diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app.c | 20 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 4 | ||||
-rw-r--r-- | src/ui/labelwidget.c | 12 | ||||
-rw-r--r-- | src/ui/labelwidget.h | 1 | ||||
-rw-r--r-- | src/ui/widget.c | 2 | ||||
-rw-r--r-- | src/ui/window.c | 142 |
6 files changed, 171 insertions, 10 deletions
@@ -1112,14 +1112,24 @@ iBool handleCommand_App(const char *cmd) { | |||
1112 | return iTrue; | 1112 | return iTrue; |
1113 | } | 1113 | } |
1114 | else if (equal_Command(cmd, "window.maximize")) { | 1114 | else if (equal_Command(cmd, "window.maximize")) { |
1115 | SDL_MaximizeWindow(d->window->win); | 1115 | if (!argLabel_Command(cmd, "toggle")) { |
1116 | SDL_MaximizeWindow(d->window->win); | ||
1117 | } | ||
1118 | else { | ||
1119 | if (SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_MAXIMIZED) { | ||
1120 | SDL_RestoreWindow(d->window->win); | ||
1121 | } | ||
1122 | else { | ||
1123 | SDL_MaximizeWindow(d->window->win); | ||
1124 | } | ||
1125 | } | ||
1116 | return iTrue; | 1126 | return iTrue; |
1117 | } | 1127 | } |
1118 | else if (equal_Command(cmd, "window.fullscreen")) { | 1128 | else if (equal_Command(cmd, "window.fullscreen")) { |
1119 | SDL_SetWindowFullscreen(d->window->win, | 1129 | const iBool wasFull = |
1120 | SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_FULLSCREEN_DESKTOP | 1130 | (SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; |
1121 | ? 0 | 1131 | SDL_SetWindowFullscreen(d->window->win, wasFull ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP); |
1122 | : SDL_WINDOW_FULLSCREEN_DESKTOP); | 1132 | postCommandf_App("window.fullscreen.changed arg:%d", !wasFull); |
1123 | return iTrue; | 1133 | return iTrue; |
1124 | } | 1134 | } |
1125 | else if (equal_Command(cmd, "font.set")) { | 1135 | else if (equal_Command(cmd, "font.set")) { |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index e35892cf..6ec76c0a 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -633,7 +633,9 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { | |||
633 | iUrl parts; | 633 | iUrl parts; |
634 | init_Url(&parts, d->mod.url); | 634 | init_Url(&parts, d->mod.url); |
635 | if (equalCase_Rangecc(parts.scheme, "about")) { | 635 | if (equalCase_Rangecc(parts.scheme, "about")) { |
636 | pushBackCStr_StringArray(title, "Lagrange"); | 636 | if (!findWidget_App("winbar")) { |
637 | pushBackCStr_StringArray(title, "Lagrange"); | ||
638 | } | ||
637 | } | 639 | } |
638 | else if (!isEmpty_Range(&parts.host)) { | 640 | else if (!isEmpty_Range(&parts.host)) { |
639 | pushBackRange_StringArray(title, parts.host); | 641 | pushBackRange_StringArray(title, parts.host); |
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index 57136509..d7e6c020 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c | |||
@@ -38,6 +38,7 @@ struct Impl_LabelWidget { | |||
38 | int font; | 38 | int font; |
39 | int key; | 39 | int key; |
40 | int kmods; | 40 | int kmods; |
41 | int forceFg; | ||
41 | iString command; | 42 | iString command; |
42 | iBool alignVisual; /* align according to visible bounds, not typography */ | 43 | iBool alignVisual; /* align according to visible bounds, not typography */ |
43 | iClick click; | 44 | iClick click; |
@@ -177,6 +178,9 @@ static void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int | |||
177 | } | 178 | } |
178 | *fg = uiTextPressed_ColorId | permanent_ColorId; | 179 | *fg = uiTextPressed_ColorId | permanent_ColorId; |
179 | } | 180 | } |
181 | if (d->forceFg >= 0) { | ||
182 | *fg = d->forceFg; | ||
183 | } | ||
180 | } | 184 | } |
181 | 185 | ||
182 | static void draw_LabelWidget_(const iLabelWidget *d) { | 186 | static void draw_LabelWidget_(const iLabelWidget *d) { |
@@ -277,6 +281,7 @@ void updateSize_LabelWidget(iLabelWidget *d) { | |||
277 | void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { | 281 | void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { |
278 | init_Widget(&d->widget); | 282 | init_Widget(&d->widget); |
279 | d->font = uiLabel_FontId; | 283 | d->font = uiLabel_FontId; |
284 | d->forceFg = none_ColorId; | ||
280 | initCStr_String(&d->label, label); | 285 | initCStr_String(&d->label, label); |
281 | if (cmd) { | 286 | if (cmd) { |
282 | initCStr_String(&d->command, cmd); | 287 | initCStr_String(&d->command, cmd); |
@@ -304,6 +309,13 @@ void setFont_LabelWidget(iLabelWidget *d, int fontId) { | |||
304 | updateSize_LabelWidget(d); | 309 | updateSize_LabelWidget(d); |
305 | } | 310 | } |
306 | 311 | ||
312 | void setTextColor_LabelWidget(iLabelWidget *d, int color) { | ||
313 | if (d && d->forceFg != color) { | ||
314 | d->forceFg = color; | ||
315 | refresh_Widget(d); | ||
316 | } | ||
317 | } | ||
318 | |||
307 | void setText_LabelWidget(iLabelWidget *d, const iString *text) { | 319 | void setText_LabelWidget(iLabelWidget *d, const iString *text) { |
308 | updateText_LabelWidget(d, text); | 320 | updateText_LabelWidget(d, text); |
309 | updateSize_LabelWidget(d); | 321 | updateSize_LabelWidget(d); |
diff --git a/src/ui/labelwidget.h b/src/ui/labelwidget.h index c91793e5..266c3b02 100644 --- a/src/ui/labelwidget.h +++ b/src/ui/labelwidget.h | |||
@@ -31,6 +31,7 @@ iDeclareObjectConstructionArgs(LabelWidget, const char *label, const char *comma | |||
31 | 31 | ||
32 | void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); | 32 | void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); |
33 | void setFont_LabelWidget (iLabelWidget *, int fontId); | 33 | void setFont_LabelWidget (iLabelWidget *, int fontId); |
34 | void setTextColor_LabelWidget (iLabelWidget *, int color); | ||
34 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ | 35 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ |
35 | void setTextCStr_LabelWidget (iLabelWidget *, const char *text); | 36 | void setTextCStr_LabelWidget (iLabelWidget *, const char *text); |
36 | void setCommand_LabelWidget (iLabelWidget *, const iString *command); | 37 | void setCommand_LabelWidget (iLabelWidget *, const iString *command); |
diff --git a/src/ui/widget.c b/src/ui/widget.c index ddb3f092..b60c67e3 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -149,6 +149,8 @@ void setPos_Widget(iWidget *d, iInt2 pos) { | |||
149 | } | 149 | } |
150 | 150 | ||
151 | void setSize_Widget(iWidget *d, iInt2 size) { | 151 | void setSize_Widget(iWidget *d, iInt2 size) { |
152 | if (size.x < 0) size.x = d->rect.size.x; | ||
153 | if (size.y < 0) size.y = d->rect.size.y; | ||
152 | d->rect.size = size; | 154 | d->rect.size = size; |
153 | setFlags_Widget(d, fixedSize_WidgetFlag, iTrue); | 155 | setFlags_Widget(d, fixedSize_WidgetFlag, iTrue); |
154 | } | 156 | } |
diff --git a/src/ui/window.c b/src/ui/window.c index 2d65a655..6356b292 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -84,8 +84,32 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
84 | } | 84 | } |
85 | else if (equal_Command(cmd, "window.focus.lost")) { | 85 | else if (equal_Command(cmd, "window.focus.lost")) { |
86 | setFocus_Widget(NULL); | 86 | setFocus_Widget(NULL); |
87 | setTextColor_LabelWidget(findWidget_App("winbar.app"), uiAnnotation_ColorId); | ||
88 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiAnnotation_ColorId); | ||
87 | return iFalse; | 89 | return iFalse; |
88 | } | 90 | } |
91 | else if (equal_Command(cmd, "window.focus.gained")) { | ||
92 | setTextColor_LabelWidget(findWidget_App("winbar.app"), uiTextCaution_ColorId); | ||
93 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiTextStrong_ColorId); | ||
94 | return iFalse; | ||
95 | } | ||
96 | else if (equal_Command(cmd, "window.fullscreen.changed")) { | ||
97 | iWidget *winBar = findWidget_App("winbar"); | ||
98 | if (winBar) { | ||
99 | setFlags_Widget(winBar, hidden_WidgetFlag, arg_Command(cmd)); | ||
100 | arrange_Widget(get_Window()->root); | ||
101 | postRefresh_App(); | ||
102 | } | ||
103 | return iFalse; | ||
104 | } | ||
105 | else if (equal_Command(cmd, "window.minimize")) { | ||
106 | SDL_MinimizeWindow(get_Window()->win); | ||
107 | return iTrue; | ||
108 | } | ||
109 | else if (equal_Command(cmd, "window.close")) { | ||
110 | SDL_PushEvent(&(SDL_Event){ .type = SDL_QUIT }); | ||
111 | return iTrue; | ||
112 | } | ||
89 | else if (handleCommand_App(cmd)) { | 113 | else if (handleCommand_App(cmd)) { |
90 | return iTrue; | 114 | return iTrue; |
91 | } | 115 | } |
@@ -503,6 +527,12 @@ static iBool handleSearchBarCommands_(iWidget *searchBar, const char *cmd) { | |||
503 | return iFalse; | 527 | return iFalse; |
504 | } | 528 | } |
505 | 529 | ||
530 | static iLabelWidget *newLargeIcon_LabelWidget(const char *text, const char *cmd) { | ||
531 | iLabelWidget *lab = newIcon_LabelWidget(text, 0, 0, cmd); | ||
532 | setFont_LabelWidget(lab, uiLabelLarge_FontId); | ||
533 | return lab; | ||
534 | } | ||
535 | |||
506 | static void setupUserInterface_Window(iWindow *d) { | 536 | static void setupUserInterface_Window(iWindow *d) { |
507 | /* Children of root cover the entire window. */ | 537 | /* Children of root cover the entire window. */ |
508 | setFlags_Widget(d->root, resizeChildren_WidgetFlag, iTrue); | 538 | setFlags_Widget(d->root, resizeChildren_WidgetFlag, iTrue); |
@@ -512,11 +542,58 @@ static void setupUserInterface_Window(iWindow *d) { | |||
512 | setId_Widget(div, "navdiv"); | 542 | setId_Widget(div, "navdiv"); |
513 | addChild_Widget(d->root, iClob(div)); | 543 | addChild_Widget(d->root, iClob(div)); |
514 | 544 | ||
545 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
546 | /* Window title bar. */ { | ||
547 | const int border = gap_UI / 4; | ||
548 | setPadding1_Widget(div, border); /* draggable edges */ | ||
549 | iWidget *winBar = new_Widget(); | ||
550 | setId_Widget(winBar, "winbar"); | ||
551 | setFlags_Widget(winBar, | ||
552 | arrangeHeight_WidgetFlag | resizeChildren_WidgetFlag | | ||
553 | arrangeHorizontal_WidgetFlag | collapse_WidgetFlag, | ||
554 | iTrue); | ||
555 | iLabelWidget *appButton = | ||
556 | addChildFlags_Widget(winBar, | ||
557 | iClob(new_LabelWidget("Lagrange", NULL)), | ||
558 | fixedHeight_WidgetFlag | frameless_WidgetFlag); | ||
559 | setTextColor_LabelWidget(appButton, uiTextCaution_ColorId); | ||
560 | setId_Widget(as_Widget(appButton), "winbar.app"); | ||
561 | iLabelWidget *appTitle; | ||
562 | setFont_LabelWidget(appButton, uiContentBold_FontId); | ||
563 | setId_Widget(addChildFlags_Widget(winBar, | ||
564 | iClob(appTitle = new_LabelWidget("", NULL)), | ||
565 | expand_WidgetFlag | alignLeft_WidgetFlag | | ||
566 | fixedHeight_WidgetFlag | frameless_WidgetFlag | | ||
567 | commandOnClick_WidgetFlag), | ||
568 | "winbar.title"); | ||
569 | setTextColor_LabelWidget(appTitle, uiTextStrong_ColorId); | ||
570 | iLabelWidget *appMin, *appMax, *appClose; | ||
571 | setId_Widget(addChildFlags_Widget( | ||
572 | winBar, | ||
573 | iClob(appMin = newLargeIcon_LabelWidget("\u2014", "window.minimize")), | ||
574 | frameless_WidgetFlag), | ||
575 | "winbar.min"); | ||
576 | setSize_Widget(as_Widget(appMin), | ||
577 | init_I2(gap_UI * 11.5f, height_Widget(appTitle))); | ||
578 | addChildFlags_Widget( | ||
579 | winBar, | ||
580 | iClob(appMax = newLargeIcon_LabelWidget("\u25a1", "window.maximize toggle:1")), | ||
581 | frameless_WidgetFlag); | ||
582 | addChildFlags_Widget(winBar, | ||
583 | iClob(appClose = newLargeIcon_LabelWidget("\u2a2f", "window.close")), | ||
584 | frameless_WidgetFlag); | ||
585 | setSize_Widget(as_Widget(appMax), as_Widget(appMin)->rect.size); | ||
586 | setSize_Widget(as_Widget(appClose), as_Widget(appMin)->rect.size); | ||
587 | addChild_Widget(div, iClob(winBar)); | ||
588 | setBackgroundColor_Widget(winBar, uiBackground_ColorId); | ||
589 | } | ||
590 | #endif | ||
591 | |||
515 | /* Navigation bar. */ { | 592 | /* Navigation bar. */ { |
516 | iWidget *navBar = new_Widget(); | 593 | iWidget *navBar = new_Widget(); |
517 | setId_Widget(navBar, "navbar"); | 594 | setId_Widget(navBar, "navbar"); |
518 | /*setPadding_Widget(navBar, gap_UI / 2, 0, gap_UI / 2, 0);*/ | 595 | int topPad = !findChild_Widget(div, "winbar") ? gap_UI / 2 : 0; |
519 | setPadding_Widget(navBar, gap_UI, gap_UI / 2, gap_UI, gap_UI / 2); | 596 | setPadding_Widget(navBar, gap_UI, topPad, gap_UI, gap_UI / 2); |
520 | setFlags_Widget(navBar, | 597 | setFlags_Widget(navBar, |
521 | arrangeHeight_WidgetFlag | resizeChildren_WidgetFlag | | 598 | arrangeHeight_WidgetFlag | resizeChildren_WidgetFlag | |
522 | arrangeHorizontal_WidgetFlag, | 599 | arrangeHorizontal_WidgetFlag, |
@@ -697,7 +774,7 @@ static float pixelRatio_Window_(const iWindow *d) { | |||
697 | SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(d->win), NULL, NULL, &vdpi); | 774 | SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(d->win), NULL, NULL, &vdpi); |
698 | const float factor = vdpi / 96.0f; | 775 | const float factor = vdpi / 96.0f; |
699 | return iMax(1.0f, factor); | 776 | return iMax(1.0f, factor); |
700 | #else | 777 | #else |
701 | int dx, x; | 778 | int dx, x; |
702 | SDL_GetRendererOutputSize(d->render, &dx, NULL); | 779 | SDL_GetRendererOutputSize(d->render, &dx, NULL); |
703 | SDL_GetWindowSize(d->win, &x, NULL); | 780 | SDL_GetWindowSize(d->win, &x, NULL); |
@@ -712,12 +789,61 @@ static void drawBlank_Window_(iWindow *d) { | |||
712 | SDL_RenderPresent(d->render); | 789 | SDL_RenderPresent(d->render); |
713 | } | 790 | } |
714 | 791 | ||
792 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
793 | static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, void *data) { | ||
794 | iWindow *d = data; | ||
795 | iAssert(d->win == win); | ||
796 | int w, h; | ||
797 | SDL_GetWindowSize(win, &w, &h); | ||
798 | /* TODO: Check if inside the caption label widget. */ | ||
799 | const iBool isLeft = pos->x < gap_UI; | ||
800 | const iBool isRight = pos->x >= w - gap_UI; | ||
801 | const iBool isTop = pos->y < gap_UI; | ||
802 | const iBool isBottom = pos->y >= h - gap_UI; | ||
803 | const int captionHeight = lineHeight_Text(uiContent_FontId) + gap_UI * 2; | ||
804 | const int rightEdge = left_Rect(bounds_Widget(findChild_Widget(d->root, "winbar.min"))); | ||
805 | if (isLeft) { | ||
806 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT | ||
807 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT | ||
808 | : SDL_HITTEST_RESIZE_LEFT; | ||
809 | } | ||
810 | if (isRight) { | ||
811 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT | ||
812 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT | ||
813 | : SDL_HITTEST_RESIZE_RIGHT; | ||
814 | } | ||
815 | if (isTop) { | ||
816 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT | ||
817 | : pos->x > w - captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT | ||
818 | : SDL_HITTEST_RESIZE_TOP; | ||
819 | } | ||
820 | if (isBottom) { | ||
821 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT | ||
822 | : pos->x > w - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT | ||
823 | : SDL_HITTEST_RESIZE_BOTTOM; | ||
824 | } | ||
825 | if (pos->x < rightEdge && pos->y < captionHeight) { | ||
826 | return SDL_HITTEST_DRAGGABLE; | ||
827 | } | ||
828 | return SDL_HITTEST_NORMAL; | ||
829 | } | ||
830 | #endif | ||
831 | |||
715 | iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { | 832 | iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { |
716 | flags |= SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN; | 833 | flags |= SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN; |
834 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
835 | /* We are drawing a custom frame so hide the default one. */ | ||
836 | flags |= SDL_WINDOW_BORDERLESS; | ||
837 | #endif | ||
717 | if (SDL_CreateWindowAndRenderer( | 838 | if (SDL_CreateWindowAndRenderer( |
718 | width_Rect(rect), height_Rect(rect), flags, &d->win, &d->render)) { | 839 | width_Rect(rect), height_Rect(rect), flags, &d->win, &d->render)) { |
719 | return iFalse; | 840 | return iFalse; |
720 | } | 841 | } |
842 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
843 | /* Register a handler for window hit testing (drag, resize). */ | ||
844 | SDL_SetWindowHitTest(d->win, hitTest_Window_, d); | ||
845 | SDL_SetWindowResizable(d->win, SDL_TRUE); | ||
846 | #endif | ||
721 | return iTrue; | 847 | return iTrue; |
722 | } | 848 | } |
723 | 849 | ||
@@ -776,6 +902,9 @@ void init_Window(iWindow *d, iRect rect) { | |||
776 | d->pixelRatio = pixelRatio_Window_(d); | 902 | d->pixelRatio = pixelRatio_Window_(d); |
777 | setPixelRatio_Metrics(d->pixelRatio * d->uiScale); | 903 | setPixelRatio_Metrics(d->pixelRatio * d->uiScale); |
778 | #if defined (iPlatformMsys) | 904 | #if defined (iPlatformMsys) |
905 | SDL_Rect usable; | ||
906 | SDL_GetDisplayUsableBounds(0, &usable); | ||
907 | SDL_SetWindowMaximumSize(d->win, usable.w, usable.h); | ||
779 | SDL_SetWindowMinimumSize(d->win, minSize.x * d->pixelRatio, minSize.y * d->pixelRatio); | 908 | SDL_SetWindowMinimumSize(d->win, minSize.x * d->pixelRatio, minSize.y * d->pixelRatio); |
780 | useExecutableIconResource_SDLWindow(d->win); | 909 | useExecutableIconResource_SDLWindow(d->win); |
781 | #endif | 910 | #endif |
@@ -1006,7 +1135,8 @@ void draw_Window(iWindow *d) { | |||
1006 | // printf("draw %d\n", d->frameTime); fflush(stdout); | 1135 | // printf("draw %d\n", d->frameTime); fflush(stdout); |
1007 | //#endif | 1136 | //#endif |
1008 | /* Clear the window. */ | 1137 | /* Clear the window. */ |
1009 | SDL_SetRenderDrawColor(d->render, 0, 0, 0, 255); | 1138 | const iColor back = get_Color(uiSeparator_ColorId); |
1139 | SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255); | ||
1010 | SDL_RenderClear(d->render); | 1140 | SDL_RenderClear(d->render); |
1011 | /* Draw widgets. */ | 1141 | /* Draw widgets. */ |
1012 | d->frameTime = SDL_GetTicks(); | 1142 | d->frameTime = SDL_GetTicks(); |
@@ -1030,6 +1160,10 @@ void resize_Window(iWindow *d, int w, int h) { | |||
1030 | 1160 | ||
1031 | void setTitle_Window(iWindow *d, const iString *title) { | 1161 | void setTitle_Window(iWindow *d, const iString *title) { |
1032 | SDL_SetWindowTitle(d->win, cstr_String(title)); | 1162 | SDL_SetWindowTitle(d->win, cstr_String(title)); |
1163 | iLabelWidget *bar = findChild_Widget(d->root, "winbar.title"); | ||
1164 | if (bar) { | ||
1165 | updateText_LabelWidget(bar, title); | ||
1166 | } | ||
1033 | } | 1167 | } |
1034 | 1168 | ||
1035 | void setUiScale_Window(iWindow *d, float uiScale) { | 1169 | void setUiScale_Window(iWindow *d, float uiScale) { |