summaryrefslogtreecommitdiff
path: root/src/ui/labelwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/labelwidget.c')
-rw-r--r--src/ui/labelwidget.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c
new file mode 100644
index 00000000..7b64857b
--- /dev/null
+++ b/src/ui/labelwidget.c
@@ -0,0 +1,281 @@
1#include "labelwidget.h"
2#include "text.h"
3#include "color.h"
4#include "paint.h"
5#include "app.h"
6#include "util.h"
7
8iLocalDef iInt2 padding_(void) { return init_I2(3 * gap_UI, gap_UI); }
9
10struct Impl_LabelWidget {
11 iWidget widget;
12 iString label;
13 int font;
14 int key;
15 int kmods;
16 iString command;
17 iClick click;
18};
19
20iDefineObjectConstructionArgs(LabelWidget,
21 (const char *label, int key, int kmods, const char *cmd),
22 label, key, kmods, cmd)
23
24static iBool checkModifiers_(int have, int req) {
25 return keyMods_Sym(req) == keyMods_Sym(have);
26}
27
28static void trigger_LabelWidget_(const iLabelWidget *d) {
29 postCommand_Widget(&d->widget, "%s", cstr_String(&d->command));
30}
31
32static iBool processEvent_LabelWidget_(iLabelWidget *d, const SDL_Event *ev) {
33 if (isCommand_UserEvent(ev, "metrics.changed")) {
34 updateSize_LabelWidget(d);
35 }
36 if (!isEmpty_String(&d->command)) {
37 switch (processEvent_Click(&d->click, ev)) {
38 case started_ClickResult:
39 setFlags_Widget(&d->widget, pressed_WidgetFlag, iTrue);
40 return iTrue;
41 case aborted_ClickResult:
42 setFlags_Widget(&d->widget, pressed_WidgetFlag, iFalse);
43 return iTrue;
44 case finished_ClickResult:
45 setFlags_Widget(&d->widget, pressed_WidgetFlag, iFalse);
46 trigger_LabelWidget_(d);
47 return iTrue;
48 case double_ClickResult:
49 return iTrue;
50 default:
51 break;
52 }
53 switch (ev->type) {
54 case SDL_KEYDOWN: {
55 const int mods = ev->key.keysym.mod;
56 if (d->key && ev->key.keysym.sym == d->key && checkModifiers_(mods, d->kmods)) {
57 trigger_LabelWidget_(d);
58 return iTrue;
59 }
60 break;
61 }
62 }
63 }
64 return processEvent_Widget(&d->widget, ev);
65}
66
67static void keyStr_LabelWidget_(const iLabelWidget *d, iString *str) {
68#if defined (iPlatformApple)
69 if (d->kmods & KMOD_CTRL) {
70 appendChar_String(str, 0x2303);
71 }
72 if (d->kmods & KMOD_ALT) {
73 appendChar_String(str, 0x2325);
74 }
75 if (d->kmods & KMOD_SHIFT) {
76 appendChar_String(str, 0x21e7);
77 }
78 if (d->kmods & KMOD_GUI) {
79 appendChar_String(str, 0x2318);
80 }
81#else
82 if (d->kmods & KMOD_CTRL) {
83 appendCStr_String(str, "Ctrl+");
84 }
85 if (d->kmods & KMOD_ALT) {
86 appendCStr_String(str, "Alt+");
87 }
88 if (d->kmods & KMOD_SHIFT) {
89 appendCStr_String(str, "Shift+");
90 }
91 if (d->kmods & KMOD_GUI) {
92 appendCStr_String(str, "Meta+");
93 }
94#endif
95 if (d->key == 0x20) {
96 appendCStr_String(str, "Space");
97 }
98 else if (d->key == SDLK_LEFT) {
99 appendChar_String(str, 0x2190);
100 }
101 else if (d->key == SDLK_RIGHT) {
102 appendChar_String(str, 0x2192);
103 }
104 else if (d->key < 128 && (isalnum(d->key) || ispunct(d->key))) {
105 appendChar_String(str, upper_Char(d->key));
106 }
107 else if (d->key == SDLK_BACKSPACE) {
108 appendChar_String(str, 0x232b); /* Erase to the Left */
109 }
110 else if (d->key == SDLK_DELETE) {
111 appendChar_String(str, 0x2326); /* Erase to the Right */
112 }
113 else {
114 appendCStr_String(str, SDL_GetKeyName(d->key));
115 }
116}
117
118static void draw_LabelWidget_(const iLabelWidget *d) {
119 const iWidget *w = constAs_Widget(d);
120 draw_Widget(w);
121 const iBool isButton = d->click.button != 0;
122 const int flags = flags_Widget(w);
123 const iRect bounds = bounds_Widget(w);
124 iRect rect = bounds;
125 if (isButton) {
126 shrink_Rect(&rect, divi_I2(gap2_UI, 4));
127 adjustEdges_Rect(&rect, gap_UI / 8, 0, -gap_UI / 8, 0);
128 }
129 iPaint p;
130 init_Paint(&p);
131 int bg = 0;
132 int fg = gray75_ColorId;
133 int frame = isButton ? gray50_ColorId : gray25_ColorId;
134 int frame2 = isButton ? black_ColorId : frame;
135 if (flags & selected_WidgetFlag) {
136 bg = teal_ColorId;
137 fg = white_ColorId;
138 frame = isButton ? cyan_ColorId : frame;
139 }
140 if (isHover_Widget(w)) {
141 if (flags & frameless_WidgetFlag) {
142 bg = teal_ColorId;
143 fg = white_ColorId;
144 if (isButton && flags & selected_WidgetFlag) frame = white_ColorId;
145 }
146 else {
147 if (frame != cyan_ColorId) {
148 if (startsWith_String(&d->label, orange_ColorEscape)) {
149 frame = orange_ColorId;
150 frame2 = brown_ColorId;
151 }
152 else {
153 frame = cyan_ColorId;
154 frame2 = teal_ColorId;
155 }
156 }
157 else {
158 frame = white_ColorId;
159 frame2 = cyan_ColorId;
160 }
161 }
162 }
163 if (flags & pressed_WidgetFlag) {
164 bg = orange_ColorId | permanent_ColorId;
165 if (isButton) frame = bg;
166 fg = black_ColorId | permanent_ColorId;
167 }
168 if (bg) {
169 fillRect_Paint(&p, rect, bg);
170 }
171 if (~flags & frameless_WidgetFlag) {
172 iRect frameRect = adjusted_Rect(rect, zero_I2(), init1_I2(-1));
173 if (isButton) {
174 iInt2 points[] = {
175 bottomLeft_Rect(frameRect), topLeft_Rect(frameRect), topRight_Rect(frameRect),
176 bottomRight_Rect(frameRect), bottomLeft_Rect(frameRect)
177 };
178 drawLines_Paint(&p, points + 2, 3, frame2);
179 drawLines_Paint(&p, points, 3, frame);
180 }
181 else {
182 drawRect_Paint(&p, frameRect, frame);
183 }
184 }
185 setClip_Paint(&p, rect);
186 if (flags & alignLeft_WidgetFlag) {
187 draw_Text(d->font, add_I2(bounds.pos, padding_()), fg, cstr_String(&d->label));
188 if ((flags & drawKey_WidgetFlag) && d->key) {
189 iString str;
190 init_String(&str);
191 keyStr_LabelWidget_(d, &str);
192 draw_Text(uiShortcuts_FontId, negX_I2(add_I2(topRight_Rect(bounds), negX_I2(padding_()))),
193 flags & pressed_WidgetFlag ? fg : cyan_ColorId, cstr_String(&str));
194 deinit_String(&str);
195 }
196 }
197 else if (flags & alignRight_WidgetFlag) {
198 draw_Text(
199 d->font,
200 mul_I2(init_I2(-1, 1), add_I2(topRight_Rect(bounds), negX_I2(padding_()))),
201 fg,
202 cstr_String(&d->label));
203 }
204 else {
205 drawCentered_Text(d->font, bounds, fg, cstr_String(&d->label));
206 }
207 clearClip_Paint(&p);
208}
209
210void updateSize_LabelWidget(iLabelWidget *d) {
211 iWidget *w = as_Widget(d);
212 const int flags = flags_Widget(w);
213 iInt2 size = add_I2(measure_Text(d->font, cstr_String(&d->label)), muli_I2(padding_(), 2));
214 if ((flags & drawKey_WidgetFlag) && d->key) {
215 iString str;
216 init_String(&str);
217 keyStr_LabelWidget_(d, &str);
218 size.x += 2 * gap_UI + measure_Text(uiShortcuts_FontId, cstr_String(&str)).x;
219 deinit_String(&str);
220 }
221 if (~flags & fixedWidth_WidgetFlag) {
222 w->rect.size.x = size.x;
223 }
224 if (~flags & fixedHeight_WidgetFlag) {
225 w->rect.size.y = size.y;
226 }
227}
228
229void init_LabelWidget(iLabelWidget *d, const char *label, int key, int kmods, const char *cmd) {
230 init_Widget(&d->widget);
231 d->font = default_FontId;
232 initCStr_String(&d->label, label);
233 if (cmd) {
234 initCStr_String(&d->command, cmd);
235 }
236 else {
237 init_String(&d->command);
238 }
239 d->key = key;
240 d->kmods = kmods;
241 init_Click(&d->click, d, !isEmpty_String(&d->command) ? SDL_BUTTON_LEFT : 0);
242 setFlags_Widget(&d->widget, hover_WidgetFlag, d->click.button != 0);
243 updateSize_LabelWidget(d);
244}
245
246void deinit_LabelWidget(iLabelWidget *d) {
247 deinit_String(&d->label);
248 deinit_String(&d->command);
249}
250
251void setFont_LabelWidget(iLabelWidget *d, int fontId) {
252 d->font = fontId;
253 updateSize_LabelWidget(d);
254}
255
256void setText_LabelWidget(iLabelWidget *d, const iString *text) {
257 updateText_LabelWidget(d, text);
258 updateSize_LabelWidget(d);
259}
260
261void updateText_LabelWidget(iLabelWidget *d, const iString *text) {
262 set_String(&d->label, text);
263}
264
265void updateTextCStr_LabelWidget(iLabelWidget *d, const char *text) {
266 setCStr_String(&d->label, text);
267}
268
269void setTextCStr_LabelWidget(iLabelWidget *d, const char *text) {
270 setCStr_String(&d->label, text);
271 updateSize_LabelWidget(d);
272}
273
274const iString *command_LabelWidget(const iLabelWidget *d) {
275 return &d->command;
276}
277
278iBeginDefineSubclass(LabelWidget, Widget)
279 .processEvent = (iAny *) processEvent_LabelWidget_,
280 .draw = (iAny *) draw_LabelWidget_,
281iEndDefineSubclass(LabelWidget)