From b259bad18b4d6a477cc74245e25224ed72e7270c Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 8 Sep 2019 18:07:17 +0800 Subject: [PATCH] feat: add radio --- demo/app/assets/views/documentation.xml | 5 + demo/app/assets/views/home.xml | 8 +- docs/components/radio.md | 27 ++++ include/LCDesign/ui/components.h | 2 + include/LCDesign/ui/components/radio-group.h | 42 ++++++ include/LCDesign/ui/components/radio.h | 38 ++++++ main.vcxproj | 4 + main.vcxproj.filters | 4 + src/main.c | 2 + src/scss/_checkbox.scss | 3 +- src/scss/_radio.scss | 51 ++++++++ src/scss/_switch.scss | 2 + src/scss/_variables.scss | 15 ++- src/scss/lc-design.scss | 1 + src/ui/components/checkbox.c | 2 +- src/ui/components/radio-group.c | 107 ++++++++++++++++ src/ui/components/radio.c | 128 +++++++++++++++++++ 17 files changed, 434 insertions(+), 7 deletions(-) create mode 100644 docs/components/radio.md create mode 100644 include/LCDesign/ui/components/radio-group.h create mode 100644 include/LCDesign/ui/components/radio.h create mode 100644 src/scss/_radio.scss create mode 100644 src/ui/components/radio-group.c create mode 100644 src/ui/components/radio.c diff --git a/demo/app/assets/views/documentation.xml b/demo/app/assets/views/documentation.xml index 806e35c..e82eabf 100644 --- a/demo/app/assets/views/documentation.xml +++ b/demo/app/assets/views/documentation.xml @@ -90,6 +90,11 @@ Rate + + + Radio + + Modal diff --git a/demo/app/assets/views/home.xml b/demo/app/assets/views/home.xml index 4356fde..7f166f0 100644 --- a/demo/app/assets/views/home.xml +++ b/demo/app/assets/views/home.xml @@ -3,19 +3,19 @@ - LCUI.css + LC Design A UI component framework for building LCUI application. - LCUI.css is an open source toolkit for developing with XML, CSS, and C. Quickly prototype your ideas or build your entire app with our Sass variables and mixins, simple grid system, common prebuilt components. + LC Design is an open source toolkit for developing with XML, CSS, and C. Quickly prototype your ideas or build your entire app with our Sass variables and mixins, simple grid system, common prebuilt components. - + Get started Download - Currently v.0.1.2 + Currently v.1.0.0 diff --git a/docs/components/radio.md b/docs/components/radio.md new file mode 100644 index 0000000..eaa6590 --- /dev/null +++ b/docs/components/radio.md @@ -0,0 +1,27 @@ +# Radio + +Select one of a set of options. + +## Basic + +``` radio-basic-demo-xml +Radio +``` + +## Disabled + +``` radio-disabled-demo-xml +Disabled +Disabled +``` + +## Group + +``` radio-group-demo-xml + + A + B + C + D + +``` diff --git a/include/LCDesign/ui/components.h b/include/LCDesign/ui/components.h index d53ffe8..7585912 100644 --- a/include/LCDesign/ui/components.h +++ b/include/LCDesign/ui/components.h @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/LCDesign/ui/components/radio-group.h b/include/LCDesign/ui/components/radio-group.h new file mode 100644 index 0000000..3deb1d6 --- /dev/null +++ b/include/LCDesign/ui/components/radio-group.h @@ -0,0 +1,42 @@ +/* + * radio-group.h -- Radio group + * + * 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_RADIO_GROUP_H_ +#define LCDESIGN_RADIO_GROUP_H_ + +int RadioGroup_SetCheckedRadio(LCUI_Widget w, LCUI_Widget radio); + +int RadioGroup_SetValue(LCUI_Widget w, const char *value); + +const char *RadioGroup_GetValue(LCUI_Widget w); + +void LCDesign_InitRadioGroup(void); + +#endif diff --git a/include/LCDesign/ui/components/radio.h b/include/LCDesign/ui/components/radio.h new file mode 100644 index 0000000..af3fbdb --- /dev/null +++ b/include/LCDesign/ui/components/radio.h @@ -0,0 +1,38 @@ +/* + * radio.h -- Radio, used to select one of a set of options. + * + * 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_RADIO_H_ +#define LCDESIGN_RADIO_H_ + +void Radio_SetChecked(LCUI_Widget w, LCUI_BOOL checked); + +void LCDesign_InitRadio(void); + +#endif diff --git a/main.vcxproj b/main.vcxproj index f86c431..16caa23 100644 --- a/main.vcxproj +++ b/main.vcxproj @@ -169,6 +169,8 @@ + + @@ -188,6 +190,8 @@ + + diff --git a/main.vcxproj.filters b/main.vcxproj.filters index e62a264..de66dd5 100644 --- a/main.vcxproj.filters +++ b/main.vcxproj.filters @@ -17,6 +17,8 @@ + + @@ -36,5 +38,7 @@ + + \ No newline at end of file diff --git a/src/main.c b/src/main.c index 115654a..a5f199f 100644 --- a/src/main.c +++ b/src/main.c @@ -35,6 +35,8 @@ void LCDesign_Init(void) { LCDesign_InitAlert(); LCDesign_InitCheckBox(); + LCDesign_InitRadio(); + LCDesign_InitRadioGroup(); LCDesign_InitLabel(); LCDesign_InitIcon(); LCDesign_InitImg(); diff --git a/src/scss/_checkbox.scss b/src/scss/_checkbox.scss index 88bfcdb..569f6b4 100644 --- a/src/scss/_checkbox.scss +++ b/src/scss/_checkbox.scss @@ -15,11 +15,12 @@ } .checkbox-text { - margin-left: map-get($spacers, 2); + padding: 0 map-get($spacers, 2); } checkbox { display: inline-block; + margin-right: map-get($spacers, 2); &:hover .checkbox-inner { border-color: $checkbox-checked-color; diff --git a/src/scss/_radio.scss b/src/scss/_radio.scss new file mode 100644 index 0000000..3f7aaab --- /dev/null +++ b/src/scss/_radio.scss @@ -0,0 +1,51 @@ +.radio-inner { + width: $radio-size; + height: $radio-size; + border: $radio-border-width solid $radio-border-color; + border-radius: $radio-size / 2; + display: inline-block; + vertical-align: middle; +} + +.radio-inner-icon { + background-color: $radio-checked-color; + width: $radio-inner-icon-size; + height: $radio-inner-icon-size; + border-radius: $radio-inner-icon-size / 2; + margin: $radio-inner-icon-margin; + display: none; +} + +.radio-text { + padding: 0 map-get($spacers, 2); +} + +radio { + display: inline-block; + margin-right: map-get($spacers, 2); + + &:hover .radio-inner { + border-color: $radio-checked-color; + } + + &.checked { + .radio-inner { + border-color: $radio-checked-color; + } + .radio-inner-icon { + display: block; + } + } + &:disabled { + .radio-inner { + border-color: $radio-border-color; + background-color: $radio-disabled-bg; + } + .radio-inner-icon { + background-color: $radio-disabled-color; + } + .radio-text { + color: $radio-disabled-color; + } + } +} diff --git a/src/scss/_switch.scss b/src/scss/_switch.scss index 36c3ffe..6ffb7ea 100644 --- a/src/scss/_switch.scss +++ b/src/scss/_switch.scss @@ -8,6 +8,7 @@ .switch-slider { background-color: #fff; width: $switch-slider-width; + border-radius: $switch-border-radius; height: 100%; } @@ -31,6 +32,7 @@ height: $switch-height; display: inline-block; border: $switch-border-width solid $switch-color; + border-radius: $switch-border-radius; background-color: $switch-color; &.checked { diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss index 56e7207..b67b34a 100644 --- a/src/scss/_variables.scss +++ b/src/scss/_variables.scss @@ -568,9 +568,10 @@ $rate-star-void-color: $gray-400 !default; $switch-height: 20px; $switch-border-width: 2px; +$switch-border-radius: $switch-height / 2; $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-width: $switch-height; $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; @@ -586,3 +587,15 @@ $checkbox-border-color: $border-color; $checkbox-checked-color: $primary; $checkbox-disabled-bg: $gray-100; $checkbox-disabled-color: $gray-600; + + +// Radio + +$radio-size: $font-size-base + 2px; +$radio-border-width: 1px; +$radio-border-color: $border-color; +$radio-inner-icon-margin: 3px; +$radio-inner-icon-size: $radio-size - $radio-border-width * 2 - $radio-inner-icon-margin * 2; +$radio-checked-color: $primary; +$radio-disabled-bg: $gray-100; +$radio-disabled-color: $gray-600; diff --git a/src/scss/lc-design.scss b/src/scss/lc-design.scss index 8bfce9b..fd295ec 100644 --- a/src/scss/lc-design.scss +++ b/src/scss/lc-design.scss @@ -12,6 +12,7 @@ @import "navbar"; @import "buttons"; @import "checkbox"; +@import "radio"; @import "dropdown"; @import "list-group"; @import "rate"; diff --git a/src/ui/components/checkbox.c b/src/ui/components/checkbox.c index 205b227..ea1151f 100644 --- a/src/ui/components/checkbox.c +++ b/src/ui/components/checkbox.c @@ -78,7 +78,7 @@ static void CheckBox_OnInit(LCUI_Widget w) Widget_BindEvent(w, "click", CheckBox_OnClick, NULL, NULL); } -static CheckBox_OnSetText(LCUI_Widget w, const char *text) +static void CheckBox_OnSetText(LCUI_Widget w, const char *text) { CheckBox data = Widget_GetData(w, self.prototype); diff --git a/src/ui/components/radio-group.c b/src/ui/components/radio-group.c new file mode 100644 index 0000000..b76169b --- /dev/null +++ b/src/ui/components/radio-group.c @@ -0,0 +1,107 @@ +/* + * radio-group.c -- Radio group + * + * 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 + +typedef struct RadioGroupRec_ { + LCUI_Widget checked_radio; +} RadioGroupRec, *RadioGroup; + +static struct RadioGroupModule { + LCUI_WidgetPrototype prototype; +} self; + +static void RadioGroup_OnInit(LCUI_Widget w) +{ + RadioGroup data = + Widget_AddData(w, self.prototype, sizeof(RadioGroupRec)); + + data->checked_radio = NULL; +} + +int RadioGroup_SetCheckedRadio(LCUI_Widget w, LCUI_Widget radio) +{ + LCUI_Widget parent; + RadioGroup data = Widget_GetData(w, self.prototype); + + for (parent = radio->parent; parent; parent = parent->parent) { + if (parent == w) { + break; + } + } + if (parent != w) { + return -1; + } + data->checked_radio = radio; + return 0; +} + +int RadioGroup_SetValue(LCUI_Widget w, const char *value) +{ + int found = -1; + LCUI_Widget child; + LinkedListNode *node; + RadioGroup data = Widget_GetData(w, self.prototype); + + data->checked_radio = NULL; + for (LinkedList_Each(node, &w->children)) { + child = node->data; + if (!Widget_CheckType(child, "radio")) { + continue; + } + if (strcmp(value, Widget_GetAttribute(child, "value")) == 0) { + Radio_SetChecked(child, TRUE); + data->checked_radio = child; + found = 0; + } else { + Radio_SetChecked(child, FALSE); + } + } + return found; +} + +const char *RadioGroup_GetValue(LCUI_Widget w) +{ + RadioGroup data = Widget_GetData(w, self.prototype); + + if (data->checked_radio) { + return Widget_GetAttribute(data->checked_radio, "value"); + } + return NULL; +} + +void LCDesign_InitRadioGroup(void) +{ + self.prototype = LCUIWidget_NewPrototype("radio-group", NULL); + self.prototype->init = RadioGroup_OnInit; +} diff --git a/src/ui/components/radio.c b/src/ui/components/radio.c new file mode 100644 index 0000000..b5c7ed4 --- /dev/null +++ b/src/ui/components/radio.c @@ -0,0 +1,128 @@ +/* + * radio.c -- Radio, used to select one of a set of options. + * + * 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 RadioRec_ { + LCUI_Widget inner; + LCUI_Widget content; + LCUI_BOOL checked; +} RadioRec, *Radio; + +static struct RadioModule { + LCUI_WidgetPrototype prototype; +} self; + +static void Radio_OnClick(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCUI_WidgetEventRec ev; + Radio data = Widget_GetData(w, self.prototype); + + if (w->disabled || data->checked) { + return; + } + if (w->parent && Widget_CheckType(w->parent, "radio-group")) { + RadioGroup_SetValue(w->parent, Widget_GetAttribute(w, "value")); + } else { + Radio_SetChecked(w, TRUE); + } + LCUI_InitWidgetEvent(&ev, "change"); + ev.cancel_bubble = TRUE; + Widget_TriggerEvent(w, &ev, NULL); +} + +static void Radio_OnInit(LCUI_Widget w) +{ + LCUI_Widget icon; + Radio data = Widget_AddData(w, self.prototype, sizeof(RadioRec)); + + data->checked = FALSE; + data->content = NULL; + data->inner = LCUIWidget_New(NULL); + icon = LCUIWidget_New(NULL); + Widget_AddClass(w, "radio"); + Widget_AddClass(icon, "radio-inner-icon"); + Widget_AddClass(data->inner, "radio-inner"); + Widget_Append(data->inner, icon); + Widget_Append(w, data->inner); + Widget_BindEvent(w, "click", Radio_OnClick, NULL, NULL); +} + +static void Radio_OnSetText(LCUI_Widget w, const char *text) +{ + Radio data = Widget_GetData(w, self.prototype); + + if (!data->content) { + data->content = LCUIWidget_New("span"); + Widget_AddClass(data->content, "radio-text"); + Widget_Append(w, data->content); + } + TextView_SetText(data->content, text); +} + +static void Radio_OnSetAttribute(LCUI_Widget w, const char *name, + const char *value) +{ + if (strcmp(name, "checked") == 0) { + Radio_SetChecked(w, strcmp(value, "checked") == 0); + } +} + +LCUI_BOOL Radio_IsChecked(LCUI_Widget w) +{ + Radio data = Widget_GetData(w, self.prototype); + + return data->checked; +} + +void Radio_SetChecked(LCUI_Widget w, LCUI_BOOL checked) +{ + Radio data = Widget_GetData(w, self.prototype); + + data->checked = checked; + if (data->checked) { + Widget_AddClass(w, "checked"); + } else { + Widget_RemoveClass(w, "checked"); + } +} + +void LCDesign_InitRadio(void) +{ + self.prototype = LCUIWidget_NewPrototype("radio", NULL); + self.prototype->init = Radio_OnInit; + self.prototype->settext = Radio_OnSetText; + self.prototype->setattr = Radio_OnSetAttribute; +}