From e036f13c333f64fb17ca60ec6eefae856b0503b8 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 3 Aug 2019 16:55:41 +0800 Subject: [PATCH] feat: add rate --- demo/app/assets/views/documentation.xml | 5 + docs/components/rate.md | 47 +++++ include/LCDesign/ui/components.h | 5 +- include/LCDesign/ui/components/rate.h | 46 +++++ main.vcxproj | 2 + main.vcxproj.filters | 6 + src/main.c | 1 + src/scss/_rate.scss | 15 ++ src/scss/_variables.scss | 7 + src/scss/lc-design.scss | 1 + src/ui/components/rate.c | 256 ++++++++++++++++++++++++ 11 files changed, 389 insertions(+), 2 deletions(-) create mode 100644 docs/components/rate.md create mode 100644 include/LCDesign/ui/components/rate.h create mode 100644 src/scss/_rate.scss create mode 100644 src/ui/components/rate.c diff --git a/demo/app/assets/views/documentation.xml b/demo/app/assets/views/documentation.xml index 98c7416..0252433 100644 --- a/demo/app/assets/views/documentation.xml +++ b/demo/app/assets/views/documentation.xml @@ -80,6 +80,11 @@ List group + + + Rate + + Modal diff --git a/docs/components/rate.md b/docs/components/rate.md new file mode 100644 index 0000000..5b2ad31 --- /dev/null +++ b/docs/components/rate.md @@ -0,0 +1,47 @@ +# Rate + +Rate component can be used to show evaluation, and it provide a quick rating operation on something. + +## Basic + +The simplest usage. + +``` rate-basic-demo-xml + +``` + +## Readonly + +Set the `disabled` attribute to disable mouse interaction. + +``` rate-readonly-demo-xml + +``` + +## Other star count + +The default number of stars is 5, you can set it with the `count` attribute. + +``` rate-count-demo-xml + +``` + +## Other icon + +Replace the default star to other iconfont. + +``` rate-icon-demo-xml + + + +``` + +## Other character + +Replace the default star to other character like alphabet, digit or even Chinese word. + +``` rate-character-demo-xml + + + +``` diff --git a/include/LCDesign/ui/components.h b/include/LCDesign/ui/components.h index aeaa531..d4574de 100644 --- a/include/LCDesign/ui/components.h +++ b/include/LCDesign/ui/components.h @@ -28,14 +28,15 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef LCUIEX_UI_COMPONETS_H -#define LCUIEX_UI_COMPONETS_H +#ifndef LCDESIGN_UI_COMPONETS_H +#define LCDESIGN_UI_COMPONETS_H #include #include #include #include #include +#include #include #include #include diff --git a/include/LCDesign/ui/components/rate.h b/include/LCDesign/ui/components/rate.h new file mode 100644 index 0000000..5584911 --- /dev/null +++ b/include/LCDesign/ui/components/rate.h @@ -0,0 +1,46 @@ +/* +* rate.h -- Rate component. +* +* 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_RATE_H_ +#define LCDESIGN_RATE_H_ + +void Rate_SetValue(LCUI_Widget w, unsigned value); + +unsigned Rate_GetValue(LCUI_Widget w); + +void Rate_SetCount(LCUI_Widget w, unsigned count); + +void Rate_SetIcon(LCUI_Widget w, const char *void_icon, const char *icon); + +void Rate_SetCharacter(LCUI_Widget w, const wchar_t ch); + +void LCDesign_InitRate(void); + +#endif diff --git a/main.vcxproj b/main.vcxproj index 36ce738..47faa37 100644 --- a/main.vcxproj +++ b/main.vcxproj @@ -168,6 +168,7 @@ + @@ -182,6 +183,7 @@ + diff --git a/main.vcxproj.filters b/main.vcxproj.filters index 53dedac..b335201 100644 --- a/main.vcxproj.filters +++ b/main.vcxproj.filters @@ -54,6 +54,9 @@ 源文件 + + 源文件 + @@ -92,5 +95,8 @@ 头文件\LCDesign\components + + 头文件\LCDesign\components + \ No newline at end of file diff --git a/src/main.c b/src/main.c index 2c290b2..0f05a83 100644 --- a/src/main.c +++ b/src/main.c @@ -37,6 +37,7 @@ void LCDesign_Init(void) LCDesign_InitLabel(); LCDesign_InitIcon(); LCDesign_InitImg(); + LCDesign_InitRate(); LCDesign_InitPassword(); LCDesign_InitTypograhy(); LCDesign_InitModal(); diff --git a/src/scss/_rate.scss b/src/scss/_rate.scss new file mode 100644 index 0000000..34f20d9 --- /dev/null +++ b/src/scss/_rate.scss @@ -0,0 +1,15 @@ +rate { + display: inline-block; + + icon, + span { + font-size: $rate-star-size; + display: inline-block; + color: $rate-star-color; + margin-right: map-get($spacers, 2); + } +} + +.rate-star-void { + color: $rate-star-void-color; +} diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss index 4bfba7a..6bf15ed 100644 --- a/src/scss/_variables.scss +++ b/src/scss/_variables.scss @@ -537,3 +537,10 @@ $list-group-action-active-bg: $gray-200 !default; $close-font-size: $font-size-base * 1.5 !default; $close-font-weight: $font-weight-bold !default; $close-color: $black !default; + + +// Rate + +$rate-star-size: $font-size-base * 1.5 !default; +$rate-star-color: $orange !default; +$rate-star-void-color: $gray-400 !default; diff --git a/src/scss/lc-design.scss b/src/scss/lc-design.scss index 5fb133f..2649358 100644 --- a/src/scss/lc-design.scss +++ b/src/scss/lc-design.scss @@ -13,6 +13,7 @@ @import "buttons"; @import "dropdown"; @import "list-group"; +@import "rate"; @import "close"; @import "modal"; @import "toasts"; diff --git a/src/ui/components/rate.c b/src/ui/components/rate.c new file mode 100644 index 0000000..88c83be --- /dev/null +++ b/src/ui/components/rate.c @@ -0,0 +1,256 @@ +/* +* rate.c -- Rate component. +* +* 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 +#include + +/* clang-format off */ + +static struct { + LCUI_WidgetPrototype proto; +} rate_module; + +typedef struct RateRec_ { + unsigned int value; + unsigned int count; + wchar_t character; + const char *icon; + const char *void_icon; +} RateRec, *Rate; + +/* clang-format on */ + +static void Rate_Update(LCUI_Widget w, unsigned value) +{ + LCUI_Widget child; + LinkedListNode *node; + Rate rate = Widget_GetData(w, rate_module.proto); + + for (LinkedList_Each(node, &w->children)) { + child = node->data; + if (child->index >= value) { + break; + } + if (!rate->character) { + Icon_SetName(child, rate->icon); + } + Widget_RemoveClass(child, "rate-star-void"); + } + for (; node; node = node->next) { + child = node->data; + if (!rate->character) { + Icon_SetName(child, rate->void_icon); + } + Widget_AddClass(child, "rate-star-void"); + } +} + +static void Rate_ResetChildren(LCUI_Widget w) +{ + unsigned i; + wchar_t text[2]; + LCUI_Widget child; + Rate rate = Widget_GetData(w, rate_module.proto); + + Widget_Empty(w); + for (i = 0; i < rate->count; ++i) { + if (rate->character) { + text[0] = rate->character; + text[1] = 0; + child = LCUIWidget_New("span"); + TextView_SetTextW(child, text); + + } else { + child = LCUIWidget_New("icon"); + Icon_SetName(child, rate->void_icon); + } + Widget_Append(w, child); + } + Rate_Update(w, rate->value); +} + +static unsigned Rate_GetValueByEvent(LCUI_Widget w, LCUI_WidgetEvent e) +{ + float x, y; + LCUI_Widget child; + LCUI_Widget target = NULL; + LinkedListNode *node; + + Widget_GetOffset(w, NULL, &x, &y); + x = 1.0f * e->motion.x - x; + y = 1.0f * e->motion.y - y; + for (LinkedList_Each(node, &w->children)) { + child = node->data; + if (child->x <= x) { + target = child; + } + } + if (!target) { + return 0; + } + return (unsigned)(target->index + 1); +} + +static void Rate_OnMouseMove(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + + if (w->disabled) { + return; + } + Rate_Update(w, min(rate->count, Rate_GetValueByEvent(w, e))); +} + +static void Rate_OnMouseDown(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + + if (w->disabled) { + return; + } + Rate_SetValue(w, Rate_GetValueByEvent(w, e)); +} + +static void Rate_OnMouseOut(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + + if (e->target != w || w->disabled) { + return; + } + Rate_Update(w, rate->value); +} + +static void Rate_OnInit(LCUI_Widget w) +{ + Rate rate = Widget_AddData(w, rate_module.proto, sizeof(RateRec)); + + rate->value = 0; + rate->count = 5; + rate->character = 0; + rate->icon = "star"; + rate->void_icon = "star-outline"; + Widget_BindEvent(w, "mousemove", Rate_OnMouseMove, NULL, NULL); + Widget_BindEvent(w, "mousedown", Rate_OnMouseDown, NULL, NULL); + Widget_BindEvent(w, "mouseout", Rate_OnMouseOut, NULL, NULL); + Rate_ResetChildren(w); + Rate_Update(w, rate->value); +} + +void Rate_SetValue(LCUI_Widget w, unsigned value) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + LCUI_WidgetEventRec e; + + rate->value = value; + Rate_Update(w, value); + LCUI_InitWidgetEvent(&e, "change"); + Widget_TriggerEvent(w, &e, NULL); +} + +unsigned Rate_GetValue(LCUI_Widget w) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + + return rate->value; +} + +void Rate_SetCount(LCUI_Widget w, unsigned count) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + + rate->count = count; + rate->value = min(rate->value, rate->count); + Rate_ResetChildren(w); +} + +void Rate_SetIcon(LCUI_Widget w, const char *void_icon, const char *icon) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + + if (!icon) { + icon = void_icon; + } + if (!void_icon) { + return; + } + rate->character = 0; + rate->icon = icon; + rate->void_icon = void_icon; + Rate_ResetChildren(w); +} + +void Rate_SetCharacter(LCUI_Widget w, const wchar_t ch) +{ + Rate rate = Widget_GetData(w, rate_module.proto); + + rate->character = ch; + Rate_ResetChildren(w); +} + +static void Rate_OnSetAttribute(LCUI_Widget w, const char *name, + const char *value) +{ + wchar_t str[4]; + unsigned count; + Rate rate = Widget_GetData(w, rate_module.proto); + + if (strcmp(name, "character") == 0) { + LCUI_DecodeUTF8String(str, value, 4); + rate->character = str[0]; + Rate_ResetChildren(w); + } else if (strcmp(name, "icon") == 0) { + rate->icon = value; + rate->character = 0; + Rate_ResetChildren(w); + } else if (strcmp(name, "void-icon") == 0) { + rate->void_icon = value; + rate->character = 0; + Rate_ResetChildren(w); + } else if (strcmp(name, "count") == 0) { + sscanf(value, "%u", &count); + Rate_SetCount(w, count); + } else if (strcmp(name, "value") == 0) { + sscanf(value, "%u", &count); + Rate_SetValue(w, count); + } +} + +void LCDesign_InitRate(void) +{ + rate_module.proto = LCUIWidget_NewPrototype("rate", NULL); + rate_module.proto->init = Rate_OnInit; + rate_module.proto->setattr = Rate_OnSetAttribute; +}