diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-04 22:24:26 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-04 22:24:43 +0200 |
commit | 35f60fa0da324ee79923d8a730cf4f10dbb6ccdb (patch) | |
tree | 3de80c1a65333a62e3cebedce339a9386f4ce8dc /src | |
parent | 900b449a5dbe8cbf08c7ad54662b1c3067093356 (diff) |
LabelWidget: Added an optional icon
Label icons are intended for context menus.
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/labelwidget.c | 64 | ||||
-rw-r--r-- | src/ui/labelwidget.h | 3 | ||||
-rw-r--r-- | src/ui/util.c | 46 | ||||
-rw-r--r-- | src/ui/widget.h | 1 | ||||
-rw-r--r-- | src/ui/window.c | 8 |
5 files changed, 100 insertions, 22 deletions
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index 87c33562..83deafe2 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c | |||
@@ -30,7 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
30 | 30 | ||
31 | iLocalDef iInt2 padding_(int64_t flags) { | 31 | iLocalDef iInt2 padding_(int64_t flags) { |
32 | #if defined (iPlatformAppleMobile) | 32 | #if defined (iPlatformAppleMobile) |
33 | return init_I2(flags & tight_WidgetFlag ? 4 * gap_UI / 2 : (4 * gap_UI), 3 * gap_UI / 2); | 33 | return init_I2(flags & tight_WidgetFlag ? 2 * gap_UI : (4 * gap_UI), |
34 | (flags & extraPadding_WidgetFlag ? 1.5f : 1) * 3 * gap_UI / 2); | ||
34 | #else | 35 | #else |
35 | return init_I2(flags & tight_WidgetFlag ? 3 * gap_UI / 2 : (3 * gap_UI), gap_UI); | 36 | return init_I2(flags & tight_WidgetFlag ? 3 * gap_UI / 2 : (3 * gap_UI), gap_UI); |
36 | #endif | 37 | #endif |
@@ -42,6 +43,7 @@ struct Impl_LabelWidget { | |||
42 | int font; | 43 | int font; |
43 | int key; | 44 | int key; |
44 | int kmods; | 45 | int kmods; |
46 | iChar icon; | ||
45 | int forceFg; | 47 | int forceFg; |
46 | iString command; | 48 | iString command; |
47 | iBool alignVisual; /* align according to visible bounds, not typography */ | 49 | iBool alignVisual; /* align according to visible bounds, not typography */ |
@@ -201,6 +203,10 @@ static void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int | |||
201 | } | 203 | } |
202 | } | 204 | } |
203 | 205 | ||
206 | iLocalDef int iconPadding_LabelWidget_(const iLabelWidget *d) { | ||
207 | return d->icon ? iRound(lineHeight_Text(d->font) * 1.5f) : 0; | ||
208 | } | ||
209 | |||
204 | static void draw_LabelWidget_(const iLabelWidget *d) { | 210 | static void draw_LabelWidget_(const iLabelWidget *d) { |
205 | const iWidget *w = constAs_Widget(d); | 211 | const iWidget *w = constAs_Widget(d); |
206 | draw_Widget(w); | 212 | draw_Widget(w); |
@@ -208,6 +214,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
208 | const int64_t flags = flags_Widget(w); | 214 | const int64_t flags = flags_Widget(w); |
209 | const iRect bounds = bounds_Widget(w); | 215 | const iRect bounds = bounds_Widget(w); |
210 | iRect rect = bounds; | 216 | iRect rect = bounds; |
217 | const iBool isHover = isHover_Widget(w); | ||
211 | if (isButton) { | 218 | if (isButton) { |
212 | shrink_Rect(&rect, divi_I2(gap2_UI, 4)); | 219 | shrink_Rect(&rect, divi_I2(gap2_UI, 4)); |
213 | adjustEdges_Rect(&rect, gap_UI / 8, 0, -gap_UI / 8, 0); | 220 | adjustEdges_Rect(&rect, gap_UI / 8, 0, -gap_UI / 8, 0); |
@@ -228,17 +235,32 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
228 | }; | 235 | }; |
229 | drawLines_Paint(&p, points + 2, 3, frame2); | 236 | drawLines_Paint(&p, points + 2, 3, frame2); |
230 | drawLines_Paint( | 237 | drawLines_Paint( |
231 | &p, points, !isHover_Widget(w) && flags & noTopFrame_WidgetFlag ? 2 : 3, frame); | 238 | &p, points, !isHover && flags & noTopFrame_WidgetFlag ? 2 : 3, frame); |
232 | } | 239 | } |
233 | } | 240 | } |
234 | setClip_Paint(&p, rect); | 241 | setClip_Paint(&p, rect); |
242 | const int iconPad = iconPadding_LabelWidget_(d); | ||
243 | if (d->icon && d->icon != 0x20) { /* no need to draw an empty icon */ | ||
244 | iString str; | ||
245 | initUnicodeN_String(&str, &d->icon, 1); | ||
246 | drawCentered_Text(d->font, | ||
247 | (iRect){ addX_I2(add_I2(bounds.pos, padding_(flags)), -2 * gap_UI), | ||
248 | init_I2(iconPad, lineHeight_Text(d->font)) }, | ||
249 | iTrue, | ||
250 | flags & pressed_WidgetFlag ? fg | ||
251 | : isHover ? uiIconHover_ColorId | ||
252 | : uiIcon_ColorId, | ||
253 | "%s", | ||
254 | cstr_String(&str)); | ||
255 | deinit_String(&str); | ||
256 | } | ||
235 | if (flags & wrapText_WidgetFlag) { | 257 | if (flags & wrapText_WidgetFlag) { |
236 | const iRect inner = innerBounds_Widget(w); | 258 | const iRect inner = adjusted_Rect(innerBounds_Widget(w), init_I2(iconPad, 0), zero_I2()); |
237 | const int wrap = inner.size.x; | 259 | const int wrap = inner.size.x; |
238 | drawWrapRange_Text(d->font, topLeft_Rect(inner), wrap, fg, range_String(&d->label)); | 260 | drawWrapRange_Text(d->font, topLeft_Rect(inner), wrap, fg, range_String(&d->label)); |
239 | } | 261 | } |
240 | else if (flags & alignLeft_WidgetFlag) { | 262 | else if (flags & alignLeft_WidgetFlag) { |
241 | draw_Text(d->font, add_I2(bounds.pos, padding_(flags)), fg, cstr_String(&d->label)); | 263 | draw_Text(d->font, add_I2(bounds.pos, addX_I2(padding_(flags), iconPad)), fg, cstr_String(&d->label)); |
242 | if ((flags & drawKey_WidgetFlag) && d->key) { | 264 | if ((flags & drawKey_WidgetFlag) && d->key) { |
243 | iString str; | 265 | iString str; |
244 | init_String(&str); | 266 | init_String(&str); |
@@ -260,7 +282,11 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
260 | cstr_String(&d->label)); | 282 | cstr_String(&d->label)); |
261 | } | 283 | } |
262 | else { | 284 | else { |
263 | drawCentered_Text(d->font, bounds, d->alignVisual, fg, cstr_String(&d->label)); | 285 | drawCentered_Text(d->font, |
286 | adjusted_Rect(bounds, init_I2(iconPad, 0), zero_I2()), | ||
287 | d->alignVisual, | ||
288 | fg, | ||
289 | cstr_String(&d->label)); | ||
264 | } | 290 | } |
265 | unsetClip_Paint(&p); | 291 | unsetClip_Paint(&p); |
266 | } | 292 | } |
@@ -288,6 +314,7 @@ iInt2 defaultSize_LabelWidget(const iLabelWidget *d) { | |||
288 | size.x += 2 * gap_UI + measure_Text(uiShortcuts_FontId, cstr_String(&str)).x; | 314 | size.x += 2 * gap_UI + measure_Text(uiShortcuts_FontId, cstr_String(&str)).x; |
289 | deinit_String(&str); | 315 | deinit_String(&str); |
290 | } | 316 | } |
317 | size.x += iconPadding_LabelWidget_(d); | ||
291 | return size; | 318 | return size; |
292 | } | 319 | } |
293 | 320 | ||
@@ -312,6 +339,7 @@ void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { | |||
312 | init_Widget(&d->widget); | 339 | init_Widget(&d->widget); |
313 | d->font = uiLabel_FontId; | 340 | d->font = uiLabel_FontId; |
314 | d->forceFg = none_ColorId; | 341 | d->forceFg = none_ColorId; |
342 | d->icon = 0; | ||
315 | initCStr_String(&d->label, label); | 343 | initCStr_String(&d->label, label); |
316 | if (cmd) { | 344 | if (cmd) { |
317 | initCStr_String(&d->command, cmd); | 345 | initCStr_String(&d->command, cmd); |
@@ -374,6 +402,32 @@ void setCommand_LabelWidget(iLabelWidget *d, const iString *command) { | |||
374 | set_String(&d->command, command); | 402 | set_String(&d->command, command); |
375 | } | 403 | } |
376 | 404 | ||
405 | void setIcon_LabelWidget(iLabelWidget *d, iChar icon) { | ||
406 | if (d->icon != icon) { | ||
407 | d->icon = icon; | ||
408 | updateSize_LabelWidget(d); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | iBool checkIcon_LabelWidget(iLabelWidget *d) { | ||
413 | if (!d->icon) { | ||
414 | iStringConstIterator iter; | ||
415 | init_StringConstIterator(&iter, &d->label); | ||
416 | const iChar icon = iter.value; | ||
417 | next_StringConstIterator(&iter); | ||
418 | if (iter.value == ' ' && icon >= 0x100) { | ||
419 | d->icon = icon; | ||
420 | remove_Block(&d->label.chars, 0, iter.next - constBegin_String(&d->label)); | ||
421 | return iTrue; | ||
422 | } | ||
423 | } | ||
424 | return iFalse; | ||
425 | } | ||
426 | |||
427 | iChar icon_LabelWidget(const iLabelWidget *d) { | ||
428 | return d->icon; | ||
429 | } | ||
430 | |||
377 | const iString *text_LabelWidget(const iLabelWidget *d) { | 431 | const iString *text_LabelWidget(const iLabelWidget *d) { |
378 | return &d->label; | 432 | return &d->label; |
379 | } | 433 | } |
diff --git a/src/ui/labelwidget.h b/src/ui/labelwidget.h index 83dd66e5..7a1d4de8 100644 --- a/src/ui/labelwidget.h +++ b/src/ui/labelwidget.h | |||
@@ -35,7 +35,9 @@ void setTextColor_LabelWidget (iLabelWidget *, int color); | |||
35 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ | 35 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ |
36 | void setTextCStr_LabelWidget (iLabelWidget *, const char *text); | 36 | void setTextCStr_LabelWidget (iLabelWidget *, const char *text); |
37 | void setCommand_LabelWidget (iLabelWidget *, const iString *command); | 37 | void setCommand_LabelWidget (iLabelWidget *, const iString *command); |
38 | void setIcon_LabelWidget (iLabelWidget *, iChar icon); | ||
38 | 39 | ||
40 | iBool checkIcon_LabelWidget (iLabelWidget *); | ||
39 | void updateSize_LabelWidget (iLabelWidget *); | 41 | void updateSize_LabelWidget (iLabelWidget *); |
40 | void updateText_LabelWidget (iLabelWidget *, const iString *text); /* not resized */ | 42 | void updateText_LabelWidget (iLabelWidget *, const iString *text); /* not resized */ |
41 | void updateTextCStr_LabelWidget (iLabelWidget *, const char *text); /* not resized */ | 43 | void updateTextCStr_LabelWidget (iLabelWidget *, const char *text); /* not resized */ |
@@ -44,6 +46,7 @@ iInt2 defaultSize_LabelWidget (const iLabelWidget *); | |||
44 | int font_LabelWidget (const iLabelWidget *); | 46 | int font_LabelWidget (const iLabelWidget *); |
45 | const iString * text_LabelWidget (const iLabelWidget *); | 47 | const iString * text_LabelWidget (const iLabelWidget *); |
46 | const iString * command_LabelWidget (const iLabelWidget *); | 48 | const iString * command_LabelWidget (const iLabelWidget *); |
49 | iChar icon_LabelWidget (const iLabelWidget *); | ||
47 | 50 | ||
48 | iLabelWidget *newKeyMods_LabelWidget(const char *label, int key, int kmods, const char *command); | 51 | iLabelWidget *newKeyMods_LabelWidget(const char *label, int key, int kmods, const char *command); |
49 | iLabelWidget *newColor_LabelWidget (const char *text, int color); | 52 | iLabelWidget *newColor_LabelWidget (const char *text, int color); |
diff --git a/src/ui/util.c b/src/ui/util.c index 055191c7..a36eb1a7 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -458,13 +458,17 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) { | |||
458 | setFrameColor_Widget(menu, uiSeparator_ColorId); | 458 | setFrameColor_Widget(menu, uiSeparator_ColorId); |
459 | setBackgroundColor_Widget(menu, uiBackground_ColorId); | 459 | setBackgroundColor_Widget(menu, uiBackground_ColorId); |
460 | if (deviceType_App() != desktop_AppDeviceType) { | 460 | if (deviceType_App() != desktop_AppDeviceType) { |
461 | setPadding1_Widget(menu, gap_UI); | 461 | setPadding1_Widget(menu, 2 * gap_UI); |
462 | } | 462 | } |
463 | setFlags_Widget(menu, | 463 | setFlags_Widget(menu, |
464 | keepOnTop_WidgetFlag | collapse_WidgetFlag | hidden_WidgetFlag | | 464 | keepOnTop_WidgetFlag | collapse_WidgetFlag | hidden_WidgetFlag | |
465 | arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag | | 465 | arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag | |
466 | resizeChildrenToWidestChild_WidgetFlag | overflowScrollable_WidgetFlag, | 466 | resizeChildrenToWidestChild_WidgetFlag | overflowScrollable_WidgetFlag, |
467 | iTrue); | 467 | iTrue); |
468 | const iBool isPortraitPhone = (deviceType_App() == phone_AppDeviceType && isPortrait_App()); | ||
469 | int64_t itemFlags = (deviceType_App() != desktop_AppDeviceType ? 0 : 0) | | ||
470 | (isPortraitPhone ? extraPadding_WidgetFlag : 0); | ||
471 | iBool haveIcons = iFalse; | ||
468 | for (size_t i = 0; i < n; ++i) { | 472 | for (size_t i = 0; i < n; ++i) { |
469 | const iMenuItem *item = &items[i]; | 473 | const iMenuItem *item = &items[i]; |
470 | if (equal_CStr(item->label, "---")) { | 474 | if (equal_CStr(item->label, "---")) { |
@@ -474,22 +478,27 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) { | |||
474 | iLabelWidget *label = addChildFlags_Widget( | 478 | iLabelWidget *label = addChildFlags_Widget( |
475 | menu, | 479 | menu, |
476 | iClob(newKeyMods_LabelWidget(item->label, item->key, item->kmods, item->command)), | 480 | iClob(newKeyMods_LabelWidget(item->label, item->key, item->kmods, item->command)), |
477 | frameless_WidgetFlag | alignLeft_WidgetFlag | drawKey_WidgetFlag); | 481 | frameless_WidgetFlag | alignLeft_WidgetFlag | drawKey_WidgetFlag | itemFlags); |
482 | haveIcons |= checkIcon_LabelWidget(label); | ||
478 | updateSize_LabelWidget(label); /* drawKey was set */ | 483 | updateSize_LabelWidget(label); /* drawKey was set */ |
479 | const iBool isCaution = startsWith_CStr(item->label, uiTextCaution_ColorEscape); | ||
480 | if (deviceType_App() == tablet_AppDeviceType) { | ||
481 | setFont_LabelWidget(label, isCaution ? uiContentBold_FontId : uiContent_FontId); | ||
482 | } | ||
483 | else if (deviceType_App() == desktop_AppDeviceType) { | ||
484 | setFont_LabelWidget(label, isCaution ? uiLabelBold_FontId : uiLabel_FontId); | ||
485 | } | ||
486 | } | 484 | } |
487 | } | 485 | } |
488 | if (deviceType_App() == phone_AppDeviceType) { | 486 | if (deviceType_App() == phone_AppDeviceType) { |
489 | addChild_Widget(menu, iClob(makeMenuSeparator_())); | 487 | addChild_Widget(menu, iClob(makeMenuSeparator_())); |
490 | setFont_LabelWidget(addChildFlags_Widget(menu, iClob(new_LabelWidget("Cancel", "cancel")), | 488 | addChildFlags_Widget(menu, |
491 | frameless_WidgetFlag | alignLeft_WidgetFlag), | 489 | iClob(new_LabelWidget("Cancel", "cancel")), |
492 | defaultBig_FontId); | 490 | itemFlags | frameless_WidgetFlag | alignLeft_WidgetFlag); |
491 | } | ||
492 | if (haveIcons) { | ||
493 | /* All items must have icons if at least one of them has. */ | ||
494 | iForEach(ObjectList, i, children_Widget(menu)) { | ||
495 | if (isInstance_Object(i.object, &Class_LabelWidget)) { | ||
496 | iLabelWidget *label = i.object; | ||
497 | if (icon_LabelWidget(label) == 0) { | ||
498 | setIcon_LabelWidget(label, ' '); | ||
499 | } | ||
500 | } | ||
501 | } | ||
493 | } | 502 | } |
494 | addChild_Widget(parent, iClob(menu)); | 503 | addChild_Widget(parent, iClob(menu)); |
495 | setCommandHandler_Widget(menu, menuHandler_); | 504 | setCommandHandler_Widget(menu, menuHandler_); |
@@ -512,10 +521,21 @@ void openMenu_Widget(iWidget *d, iInt2 coord) { | |||
512 | setFlags_Widget(d, arrangeWidth_WidgetFlag | resizeChildrenToWidestChild_WidgetFlag, iFalse); | 521 | setFlags_Widget(d, arrangeWidth_WidgetFlag | resizeChildrenToWidestChild_WidgetFlag, iFalse); |
513 | setFlags_Widget(d, resizeWidthOfChildren_WidgetFlag, iTrue); | 522 | setFlags_Widget(d, resizeWidthOfChildren_WidgetFlag, iTrue); |
514 | d->rect.size.x = rootSize_Window(get_Window()).x; | 523 | d->rect.size.x = rootSize_Window(get_Window()).x; |
524 | } | ||
525 | /* Update item fonts. */ { | ||
515 | iForEach(ObjectList, i, children_Widget(d)) { | 526 | iForEach(ObjectList, i, children_Widget(d)) { |
516 | if (isInstance_Object(i.object, &Class_LabelWidget)) { | 527 | if (isInstance_Object(i.object, &Class_LabelWidget)) { |
517 | iLabelWidget *label = i.object; | 528 | iLabelWidget *label = i.object; |
518 | setFont_LabelWidget(label, defaultBig_FontId); | 529 | const iBool isCaution = startsWith_String(text_LabelWidget(label), uiTextCaution_ColorEscape); |
530 | if (deviceType_App() == desktop_AppDeviceType) { | ||
531 | setFont_LabelWidget(label, isCaution ? uiLabelBold_FontId : uiLabel_FontId); | ||
532 | } | ||
533 | else if (isPortraitPhone) { | ||
534 | setFont_LabelWidget(label, isCaution ? defaultBigBold_FontId : defaultBig_FontId); | ||
535 | } | ||
536 | else { | ||
537 | setFont_LabelWidget(label, isCaution ? uiContentBold_FontId : uiContent_FontId); | ||
538 | } | ||
519 | } | 539 | } |
520 | } | 540 | } |
521 | } | 541 | } |
diff --git a/src/ui/widget.h b/src/ui/widget.h index 955abf5d..5bd82183 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h | |||
@@ -101,6 +101,7 @@ enum iWidgetFlag { | |||
101 | #define parentCannotResize_WidgetFlag iBit64(46) | 101 | #define parentCannotResize_WidgetFlag iBit64(46) |
102 | #define noTopFrame_WidgetFlag iBit64(47) | 102 | #define noTopFrame_WidgetFlag iBit64(47) |
103 | #define unpadded_WidgetFlag iBit64(48) /* ignore parent's padding */ | 103 | #define unpadded_WidgetFlag iBit64(48) /* ignore parent's padding */ |
104 | #define extraPadding_WidgetFlag iBit64(49) | ||
104 | 105 | ||
105 | enum iWidgetAddPos { | 106 | enum iWidgetAddPos { |
106 | back_WidgetAddPos, | 107 | back_WidgetAddPos, |
diff --git a/src/ui/window.c b/src/ui/window.c index 60813312..008290b9 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -1092,10 +1092,10 @@ static void setupUserInterface_Window(iWindow *d) { | |||
1092 | // setBackgroundColor_Widget(i.object, tmBannerSideTitle_ColorId); | 1092 | // setBackgroundColor_Widget(i.object, tmBannerSideTitle_ColorId); |
1093 | } | 1093 | } |
1094 | const iMenuItem items[] = { | 1094 | const iMenuItem items[] = { |
1095 | { "Bookmarks", 0, 0, "toolbar.showview arg:0" }, | 1095 | { "\U0001f588 Bookmarks", 0, 0, "toolbar.showview arg:0" }, |
1096 | { "Feeds", 0, 0, "toolbar.showview arg:1" }, | 1096 | { "\U00002605 Feeds", 0, 0, "toolbar.showview arg:1" }, |
1097 | { "History", 0, 0, "toolbar.showview arg:2" }, | 1097 | { "\U0001f553 History", 0, 0, "toolbar.showview arg:2" }, |
1098 | { "Page Outline", 0, 0, "toolbar.showview arg:4" }, | 1098 | { "\U0001f5b9 Page Outline", 0, 0, "toolbar.showview arg:4" }, |
1099 | }; | 1099 | }; |
1100 | iWidget *menu = makeMenu_Widget(findChild_Widget(toolBar, "toolbar.view"), | 1100 | iWidget *menu = makeMenu_Widget(findChild_Widget(toolBar, "toolbar.view"), |
1101 | items, iElemCount(items)); | 1101 | items, iElemCount(items)); |