From b28c21947e9efa28a56fe2cbaa2526894acb7769 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 18 Aug 2019 15:47:10 +0800 Subject: [PATCH] feat: add switch --- demo/app/assets/views/documentation.xml | 5 + docs/components/switch.md | 36 ++++ include/LCDesign/ui/components.h | 1 + include/LCDesign/ui/components/spinner.h | 2 +- include/LCDesign/ui/components/switch.h | 49 +++++ main.vcxproj | 4 +- main.vcxproj.filters | 4 +- src/main.c | 1 + src/scss/_switch.scss | 52 +++++ src/scss/_variables.scss | 14 ++ src/scss/lc-design.scss | 1 + src/ui/components/spinner.c | 2 +- src/ui/components/switch.c | 240 +++++++++++++++++++++++ 13 files changed, 407 insertions(+), 4 deletions(-) create mode 100644 docs/components/switch.md create mode 100644 include/LCDesign/ui/components/switch.h create mode 100644 src/scss/_switch.scss create mode 100644 src/ui/components/switch.c diff --git a/demo/app/assets/views/documentation.xml b/demo/app/assets/views/documentation.xml index 058db68..bcc8aeb 100644 --- a/demo/app/assets/views/documentation.xml +++ b/demo/app/assets/views/documentation.xml @@ -105,6 +105,11 @@ Spinners + + + Switch + + Scrollbar diff --git a/docs/components/switch.md b/docs/components/switch.md new file mode 100644 index 0000000..03c82d2 --- /dev/null +++ b/docs/components/switch.md @@ -0,0 +1,36 @@ +# Switch + +Represent the switching between two states or on-off state. + +## Basic + +``` switch-basic-demo-xml + +``` + +## Text & icon + +With text and icon. + +``` switch-text-icon-demo-xml +

+ +

+

+ +

+

+ +

+``` + +## Disabled + +``` switch-text-icon-demo-xml +

+ +

+

+ +

+``` diff --git a/include/LCDesign/ui/components.h b/include/LCDesign/ui/components.h index 6be182a..0c18ebd 100644 --- a/include/LCDesign/ui/components.h +++ b/include/LCDesign/ui/components.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/include/LCDesign/ui/components/spinner.h b/include/LCDesign/ui/components/spinner.h index 31cdc48..242f7f2 100644 --- a/include/LCDesign/ui/components/spinner.h +++ b/include/LCDesign/ui/components/spinner.h @@ -1,4 +1,4 @@ -/* +/* * spinner.h -- Spinner, used to indicate the loading state of a component * or page. * diff --git a/include/LCDesign/ui/components/switch.h b/include/LCDesign/ui/components/switch.h new file mode 100644 index 0000000..931ed69 --- /dev/null +++ b/include/LCDesign/ui/components/switch.h @@ -0,0 +1,49 @@ +/* + * switch.h -- Switch, used to represent the switching between two states or + * on-off state. + * + * Copyright (c) 2019, Liu chao All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of LCUI nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LCDESIGN_SWITCH_H_ +#define LCDESIGN_SWITCH_H_ + +LCUI_API void LCDesign_InitSwitch(void); + +LCUI_API LCUI_BOOL Switch_IsChecked(LCUI_Widget w); + +LCUI_API void Switch_SetChecked(LCUI_Widget w, LCUI_BOOL checked); + +LCUI_API void Switch_SetCheckedText(LCUI_Widget w, const char *text); + +LCUI_API void Switch_SetUncheckedText(LCUI_Widget w, const char *text); + +LCUI_API void Switch_SetCheckedIcon(LCUI_Widget w, const char *icon_name); + +LCUI_API void Switch_SetUncheckedIcon(LCUI_Widget w, const char *icon_name); + +#endif diff --git a/main.vcxproj b/main.vcxproj index 695e1bd..d750c74 100644 --- a/main.vcxproj +++ b/main.vcxproj @@ -1,4 +1,4 @@ - + @@ -170,6 +170,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/main.vcxproj.filters b/main.vcxproj.filters index 462ba0c..b7e9896 100644 --- a/main.vcxproj.filters +++ b/main.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -15,6 +15,7 @@ + @@ -32,5 +33,6 @@ + \ No newline at end of file diff --git a/src/main.c b/src/main.c index b366539..3653d9a 100644 --- a/src/main.c +++ b/src/main.c @@ -40,6 +40,7 @@ void LCDesign_Init(void) LCDesign_InitRate(); LCDesign_InitTooltip(); LCDesign_InitSpinner(); + LCDesign_InitSwitch(); LCDesign_InitPassword(); LCDesign_InitTypograhy(); LCDesign_InitModal(); diff --git a/src/scss/_switch.scss b/src/scss/_switch.scss new file mode 100644 index 0000000..36c3ffe --- /dev/null +++ b/src/scss/_switch.scss @@ -0,0 +1,52 @@ +.switch-bar { + left: -$switch-icon-width; + height: 100%; + width: $switch-bar-width; + position: relative; +} + +.switch-slider { + background-color: #fff; + width: $switch-slider-width; + height: 100%; +} + +.switch-on-block, +.switch-off-block { + width: $switch-icon-width; + color: #fff; + font-size: $switch-icon-height - 2px; + text-align: center; + line-height: $switch-icon-height; +} + +.switch-on-block, +.switch-off-block, +.switch-slider { + display: inline-block; +} + +.switch { + width: $switch-width; + height: $switch-height; + display: inline-block; + border: $switch-border-width solid $switch-color; + background-color: $switch-color; + + &.checked { + border-color: $switch-checked-color; + background-color: $switch-checked-color; + + .switch-bar { + left: 0; + } + } + &:disabled { + opacity: 0.4; + } +} + +.switch-text { + margin-left: $switch-margin-left; + line-height: $switch-height; +} diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss index fe6359d..5f3b9ac 100644 --- a/src/scss/_variables.scss +++ b/src/scss/_variables.scss @@ -562,3 +562,17 @@ $close-color: $black !default; $rate-star-size: $font-size-base * 1.5 !default; $rate-star-color: $orange !default; $rate-star-void-color: $gray-400 !default; + + +// Switch + +$switch-height: 20px; +$switch-border-width: 2px; +$switch-margin-left: $font-size-base / 2; +$switch-slider-width: $switch-height - $switch-border-width * 2; +$switch-icon-width: $switch-height + $switch-border-width * 2; +$switch-icon-height: $switch-height - $switch-border-width * 2; +$switch-bar-width: $switch-icon-width * 2 + $switch-slider-width; +$switch-width: $switch-icon-width + $switch-slider-width + $switch-border-width * 2; +$switch-checked-color: $primary; +$switch-color: $text-muted; diff --git a/src/scss/lc-design.scss b/src/scss/lc-design.scss index fe0743b..a977b78 100644 --- a/src/scss/lc-design.scss +++ b/src/scss/lc-design.scss @@ -14,6 +14,7 @@ @import "dropdown"; @import "list-group"; @import "rate"; +@import "switch"; @import "close"; @import "modal"; @import "toasts"; diff --git a/src/ui/components/spinner.c b/src/ui/components/spinner.c index ab43b6d..b499429 100644 --- a/src/ui/components/spinner.c +++ b/src/ui/components/spinner.c @@ -1,4 +1,4 @@ -/* +/* * spinner.c -- Spinner, used to indicate the loading state of a component * or page. * diff --git a/src/ui/components/switch.c b/src/ui/components/switch.c new file mode 100644 index 0000000..d171822 --- /dev/null +++ b/src/ui/components/switch.c @@ -0,0 +1,240 @@ +/* + * switch.c -- Switch, used to represent the switching between two states or + * on-off state. + * + * Copyright (c) 2019, Liu chao All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of LCUI nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +typedef struct SwitchRec_ { + char *checked_text; + char *checked_icon; + char *unchecked_text; + char *unchecked_icon; + LCUI_Widget txt_off; + LCUI_Widget txt_on; + LCUI_Widget slider; + LCUI_Widget bar; + LCUI_BOOL checked; +} SwitchRec, *Switch; + +static struct SwitchModule { + LCUI_WidgetPrototype prototype; +} self; + +static void Switch_OnClick(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCUI_WidgetEventRec ev; + Switch data = Widget_GetData(w, self.prototype); + + if (w->disabled) { + return; + } + Switch_SetChecked(w, !data->checked); + LCUI_InitWidgetEvent(&ev, "change"); + ev.cancel_bubble = TRUE; + Widget_TriggerEvent(w, &ev, NULL); +} + +static void Switch_ResetChildren(LCUI_Widget w) +{ + Switch data = Widget_GetData(w, self.prototype); + + if (data->txt_off) { + Widget_Destroy(data->txt_off); + data->txt_off = NULL; + } + if (data->txt_on) { + Widget_Destroy(data->txt_on); + data->txt_on = NULL; + } + if (data->checked_icon) { + data->txt_on = LCUIWidget_New("icon"); + Icon_SetName(data->txt_on, data->checked_icon); + } else { + data->txt_on = LCUIWidget_New("textview"); + if (data->checked_text) { + TextView_SetText(data->txt_on, data->checked_text); + } + } + if (data->unchecked_icon) { + data->txt_off = LCUIWidget_New("icon"); + Icon_SetName(data->txt_off, data->unchecked_icon); + } else { + data->txt_off = LCUIWidget_New("textview"); + if (data->unchecked_text) { + TextView_SetText(data->txt_off, data->unchecked_text); + } + } + Widget_AddClass(data->txt_on, "switch-on-block"); + Widget_AddClass(data->txt_off, "switch-off-block"); + Widget_Append(data->bar, data->txt_on); + Widget_Append(data->bar, data->slider); + Widget_Append(data->bar, data->txt_off); +} + +static void Switch_OnInit(LCUI_Widget w) +{ + const size_t data_size = sizeof(SwitchRec); + Switch data = Widget_AddData(w, self.prototype, data_size); + + data->checked = FALSE; + data->bar = LCUIWidget_New(NULL); + data->slider = LCUIWidget_New(NULL); + data->checked_text = NULL; + data->checked_icon = NULL; + data->unchecked_text = NULL; + data->unchecked_icon = NULL; + data->txt_off = NULL; + data->txt_on = NULL; + Widget_AddClass(w, "switch"); + Widget_AddClass(data->bar, "switch-bar"); + Widget_AddClass(data->slider, "switch-slider"); + Widget_Append(w, data->bar); + Widget_BindEvent(w, "click", Switch_OnClick, NULL, NULL); + Switch_ResetChildren(w); +} + +static void Switch_OnSetAttribute(LCUI_Widget w, const char *name, + const char *value) +{ + if (strcmp(name, "checked-icon") == 0) { + Switch_SetCheckedIcon(w, value); + } else if (strcmp(name, "unchecked-icon") == 0) { + Switch_SetUncheckedIcon(w, value); + } else if (strcmp(name, "checked-text") == 0) { + Switch_SetCheckedText(w, value); + } else if (strcmp(name, "unchecked-text") == 0) { + Switch_SetUncheckedText(w, value); + } else if (strcmp(name, "checked") == 0) { + Switch_SetChecked(w, strcmp(value, "checked") == 0); + } +} + +LCUI_BOOL Switch_IsChecked(LCUI_Widget w) +{ + Switch data = Widget_GetData(w, self.prototype); + + return data->checked; +} + +void Switch_SetChecked(LCUI_Widget w, LCUI_BOOL checked) +{ + Switch data = Widget_GetData(w, self.prototype); + + data->checked = checked; + if (data->checked) { + Widget_AddClass(w, "checked"); + } else { + Widget_RemoveClass(w, "checked"); + } +} + +void Switch_SetCheckedText(LCUI_Widget w, const char *text) +{ + Switch data = Widget_GetData(w, self.prototype); + + if (data->checked_text) { + free(data->checked_text); + data->checked_text = NULL; + } + if (text) { + data->checked_text = strdup2(text); + if (data->checked_icon) { + free(data->checked_icon); + data->checked_icon = NULL; + } + } + Switch_ResetChildren(w); +} + +void Switch_SetUncheckedText(LCUI_Widget w, const char *text) +{ + Switch data = Widget_GetData(w, self.prototype); + + if (data->unchecked_text) { + free(data->unchecked_text); + data->unchecked_text = NULL; + } + if (text) { + data->unchecked_text = strdup2(text); + if (data->unchecked_icon) { + free(data->unchecked_icon); + data->unchecked_icon = NULL; + } + } + Switch_ResetChildren(w); +} + +void Switch_SetCheckedIcon(LCUI_Widget w, const char *icon_name) +{ + Switch data = Widget_GetData(w, self.prototype); + + if (data->checked_icon) { + free(data->checked_icon); + data->checked_text = NULL; + } + if (icon_name) { + data->checked_icon = strdup2(icon_name); + if (data->checked_text) { + free(data->checked_text); + data->checked_text = NULL; + } + } + Switch_ResetChildren(w); +} + +void Switch_SetUncheckedIcon(LCUI_Widget w, const char *icon_name) +{ + Switch data = Widget_GetData(w, self.prototype); + + if (data->unchecked_icon) { + free(data->unchecked_icon); + data->unchecked_icon = NULL; + } + if (icon_name) { + data->unchecked_icon = strdup2(icon_name); + if (data->unchecked_text) { + free(data->unchecked_text); + data->unchecked_text = NULL; + } + } + Switch_ResetChildren(w); +} + +void LCDesign_InitSwitch(void) +{ + self.prototype = LCUIWidget_NewPrototype("switch", NULL); + self.prototype->setattr = Switch_OnSetAttribute; + self.prototype->init = Switch_OnInit; +}