diff options
Diffstat (limited to 'src/ui/window.c')
-rw-r--r-- | src/ui/window.c | 124 |
1 files changed, 88 insertions, 36 deletions
diff --git a/src/ui/window.c b/src/ui/window.c index a59aa135..ef4a6fca 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -52,7 +52,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
52 | #include <SDL_syswm.h> | 52 | #include <SDL_syswm.h> |
53 | 53 | ||
54 | #define STB_IMAGE_IMPLEMENTATION | 54 | #define STB_IMAGE_IMPLEMENTATION |
55 | #define STB_IMAGE_RESIZE_IMPLEMENTATION | ||
55 | #include "stb_image.h" | 56 | #include "stb_image.h" |
57 | #include "stb_image_resize.h" | ||
56 | 58 | ||
57 | static iWindow *theWindow_ = NULL; | 59 | static iWindow *theWindow_ = NULL; |
58 | 60 | ||
@@ -89,7 +91,7 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
89 | return iFalse; | 91 | return iFalse; |
90 | } | 92 | } |
91 | else if (equal_Command(cmd, "window.focus.gained")) { | 93 | else if (equal_Command(cmd, "window.focus.gained")) { |
92 | setTextColor_LabelWidget(findWidget_App("winbar.app"), uiTextCaution_ColorId); | 94 | setTextColor_LabelWidget(findWidget_App("winbar.app"), uiTextShortcut_ColorId); |
93 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiTextStrong_ColorId); | 95 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiTextStrong_ColorId); |
94 | return iFalse; | 96 | return iFalse; |
95 | } | 97 | } |
@@ -541,6 +543,10 @@ static iLabelWidget *newLargeIcon_LabelWidget(const char *text, const char *cmd) | |||
541 | return lab; | 543 | return lab; |
542 | } | 544 | } |
543 | 545 | ||
546 | static int appIconSize_(void) { | ||
547 | return lineHeight_Text(uiContent_FontId); | ||
548 | } | ||
549 | |||
544 | static void setupUserInterface_Window(iWindow *d) { | 550 | static void setupUserInterface_Window(iWindow *d) { |
545 | /* Children of root cover the entire window. */ | 551 | /* Children of root cover the entire window. */ |
546 | setFlags_Widget(d->root, resizeChildren_WidgetFlag, iTrue); | 552 | setFlags_Widget(d->root, resizeChildren_WidgetFlag, iTrue); |
@@ -552,8 +558,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
552 | 558 | ||
553 | #if defined (LAGRANGE_CUSTOM_FRAME) | 559 | #if defined (LAGRANGE_CUSTOM_FRAME) |
554 | /* Window title bar. */ { | 560 | /* Window title bar. */ { |
555 | const int border = gap_UI / 4; | 561 | setPadding1_Widget(div, 1); |
556 | setPadding1_Widget(div, border); /* draggable edges */ | ||
557 | iWidget *winBar = new_Widget(); | 562 | iWidget *winBar = new_Widget(); |
558 | setPadding_Widget(winBar, 0, gap_UI / 3, 0, 0); | 563 | setPadding_Widget(winBar, 0, gap_UI / 3, 0, 0); |
559 | setId_Widget(winBar, "winbar"); | 564 | setId_Widget(winBar, "winbar"); |
@@ -561,11 +566,14 @@ static void setupUserInterface_Window(iWindow *d) { | |||
561 | arrangeHeight_WidgetFlag | resizeChildren_WidgetFlag | | 566 | arrangeHeight_WidgetFlag | resizeChildren_WidgetFlag | |
562 | arrangeHorizontal_WidgetFlag | collapse_WidgetFlag, | 567 | arrangeHorizontal_WidgetFlag | collapse_WidgetFlag, |
563 | iTrue); | 568 | iTrue); |
569 | iWidget *appIcon; | ||
570 | setId_Widget( | ||
571 | addChild_Widget(winBar, iClob(appIcon = makePadding_Widget(0))), "winbar.icon"); | ||
564 | iLabelWidget *appButton = | 572 | iLabelWidget *appButton = |
565 | addChildFlags_Widget(winBar, | 573 | addChildFlags_Widget(winBar, |
566 | iClob(new_LabelWidget("Lagrange", NULL)), | 574 | iClob(new_LabelWidget("Lagrange", NULL)), |
567 | fixedHeight_WidgetFlag | frameless_WidgetFlag); | 575 | fixedHeight_WidgetFlag | frameless_WidgetFlag); |
568 | setTextColor_LabelWidget(appButton, uiTextCaution_ColorId); | 576 | setTextColor_LabelWidget(appButton, uiTextShortcut_ColorId); |
569 | setId_Widget(as_Widget(appButton), "winbar.app"); | 577 | setId_Widget(as_Widget(appButton), "winbar.app"); |
570 | iLabelWidget *appTitle; | 578 | iLabelWidget *appTitle; |
571 | setFont_LabelWidget(appButton, uiContentBold_FontId); | 579 | setFont_LabelWidget(appButton, uiContentBold_FontId); |
@@ -594,6 +602,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
594 | setFont_LabelWidget(appClose, uiContent_FontId); | 602 | setFont_LabelWidget(appClose, uiContent_FontId); |
595 | setSize_Widget(as_Widget(appMax), as_Widget(appMin)->rect.size); | 603 | setSize_Widget(as_Widget(appMax), as_Widget(appMin)->rect.size); |
596 | setSize_Widget(as_Widget(appClose), as_Widget(appMin)->rect.size); | 604 | setSize_Widget(as_Widget(appClose), as_Widget(appMin)->rect.size); |
605 | setSize_Widget(appIcon, init_I2(appIconSize_(), as_Widget(appMin)->rect.size.y)); | ||
597 | addChild_Widget(div, iClob(winBar)); | 606 | addChild_Widget(div, iClob(winBar)); |
598 | setBackgroundColor_Widget(winBar, uiBackground_ColorId); | 607 | setBackgroundColor_Widget(winBar, uiBackground_ColorId); |
599 | } | 608 | } |
@@ -817,25 +826,27 @@ static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, | |||
817 | const int captionHeight = lineHeight_Text(uiContent_FontId) + gap_UI * 2; | 826 | const int captionHeight = lineHeight_Text(uiContent_FontId) + gap_UI * 2; |
818 | const int rightEdge = left_Rect(bounds_Widget(findChild_Widget(d->root, "winbar.min"))); | 827 | const int rightEdge = left_Rect(bounds_Widget(findChild_Widget(d->root, "winbar.min"))); |
819 | d->place.lastHit = SDL_HITTEST_NORMAL; | 828 | d->place.lastHit = SDL_HITTEST_NORMAL; |
820 | if (isLeft) { | 829 | if (snap != maximized_WindowSnap) { |
821 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT | 830 | if (isLeft) { |
822 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT | 831 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT |
823 | : (d->place.lastHit = SDL_HITTEST_RESIZE_LEFT); | 832 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT |
824 | } | 833 | : (d->place.lastHit = SDL_HITTEST_RESIZE_LEFT); |
825 | if (isRight) { | 834 | } |
826 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT | 835 | if (isRight) { |
827 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT | 836 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT |
828 | : (d->place.lastHit = SDL_HITTEST_RESIZE_RIGHT); | 837 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT |
829 | } | 838 | : (d->place.lastHit = SDL_HITTEST_RESIZE_RIGHT); |
830 | if (isTop) { | 839 | } |
831 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT | 840 | if (isTop) { |
832 | : pos->x > w - captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT | 841 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT |
833 | : SDL_HITTEST_RESIZE_TOP; | 842 | : pos->x > w - captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT |
834 | } | 843 | : SDL_HITTEST_RESIZE_TOP; |
835 | if (isBottom) { | 844 | } |
836 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT | 845 | if (isBottom) { |
837 | : pos->x > w - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT | 846 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT |
838 | : SDL_HITTEST_RESIZE_BOTTOM; | 847 | : pos->x > w - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT |
848 | : SDL_HITTEST_RESIZE_BOTTOM; | ||
849 | } | ||
839 | } | 850 | } |
840 | if (pos->x < rightEdge && pos->y < captionHeight) { | 851 | if (pos->x < rightEdge && pos->y < captionHeight) { |
841 | return SDL_HITTEST_DRAGGABLE; | 852 | return SDL_HITTEST_DRAGGABLE; |
@@ -866,6 +877,24 @@ iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { | |||
866 | return iTrue; | 877 | return iTrue; |
867 | } | 878 | } |
868 | 879 | ||
880 | #if defined (iPlatformLinux) || defined (LAGRANGE_CUSTOM_FRAME) | ||
881 | static SDL_Surface *loadAppIconSurface_(int resized) { | ||
882 | const iBlock *icon = &imageLagrange64_Embedded; | ||
883 | int w, h, num; | ||
884 | stbi_uc * pixels = stbi_load_from_memory( | ||
885 | constData_Block(icon), size_Block(icon), &w, &h, &num, STBI_rgb_alpha); | ||
886 | if (resized) { | ||
887 | stbi_uc * rsPixels = malloc(num * resized * resized); | ||
888 | stbir_resize_uint8(pixels, w, h, 0, rsPixels, resized, resized, 0, num); | ||
889 | free(pixels); | ||
890 | pixels = rsPixels; | ||
891 | w = h = resized; | ||
892 | } | ||
893 | return SDL_CreateRGBSurfaceWithFormatFrom( | ||
894 | pixels, w, h, 8 * num, w * num, SDL_PIXELFORMAT_RGBA32); | ||
895 | } | ||
896 | #endif | ||
897 | |||
869 | void init_Window(iWindow *d, iRect rect) { | 898 | void init_Window(iWindow *d, iRect rect) { |
870 | theWindow_ = d; | 899 | theWindow_ = d; |
871 | iZap(d->cursors); | 900 | iZap(d->cursors); |
@@ -932,19 +961,10 @@ void init_Window(iWindow *d, iRect rect) { | |||
932 | #if defined (iPlatformLinux) | 961 | #if defined (iPlatformLinux) |
933 | SDL_SetWindowMinimumSize(d->win, minSize.x * d->pixelRatio, minSize.y * d->pixelRatio); | 962 | SDL_SetWindowMinimumSize(d->win, minSize.x * d->pixelRatio, minSize.y * d->pixelRatio); |
934 | /* Load the window icon. */ { | 963 | /* Load the window icon. */ { |
935 | int w, h, num; | 964 | SDL_Surface *surf = loadAppIconSurface_(0); |
936 | const iBlock *icon = &imageLagrange64_Embedded; | ||
937 | stbi_uc *pixels = stbi_load_from_memory(constData_Block(icon), | ||
938 | size_Block(icon), | ||
939 | &w, | ||
940 | &h, | ||
941 | &num, | ||
942 | STBI_rgb_alpha); | ||
943 | SDL_Surface *surf = | ||
944 | SDL_CreateRGBSurfaceWithFormatFrom(pixels, w, h, 32, 4 * w, SDL_PIXELFORMAT_RGBA32); | ||
945 | SDL_SetWindowIcon(d->win, surf); | 965 | SDL_SetWindowIcon(d->win, surf); |
966 | free(surf->pixels); | ||
946 | SDL_FreeSurface(surf); | 967 | SDL_FreeSurface(surf); |
947 | stbi_image_free(pixels); | ||
948 | } | 968 | } |
949 | #endif | 969 | #endif |
950 | d->root = new_Widget(); | 970 | d->root = new_Widget(); |
@@ -957,7 +977,16 @@ void init_Window(iWindow *d, iRect rect) { | |||
957 | setupUserInterface_Window(d); | 977 | setupUserInterface_Window(d); |
958 | postCommand_App("bindings.changed"); /* update from bindings */ | 978 | postCommand_App("bindings.changed"); /* update from bindings */ |
959 | updateRootSize_Window_(d, iFalse); | 979 | updateRootSize_Window_(d, iFalse); |
980 | d->appIcon = NULL; | ||
960 | #if defined (LAGRANGE_CUSTOM_FRAME) | 981 | #if defined (LAGRANGE_CUSTOM_FRAME) |
982 | /* Load the app icon for drawing in the title bar. */ { | ||
983 | SDL_Surface *surf = loadAppIconSurface_(appIconSize_()); | ||
984 | SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); | ||
985 | d->appIcon = SDL_CreateTextureFromSurface(d->render, surf); | ||
986 | free(surf->pixels); | ||
987 | SDL_FreeSurface(surf); | ||
988 | } | ||
989 | /* We need to observe non-client-area events. */ | ||
961 | SDL_EventState(SDL_SYSWMEVENT, SDL_TRUE); | 990 | SDL_EventState(SDL_SYSWMEVENT, SDL_TRUE); |
962 | #endif | 991 | #endif |
963 | } | 992 | } |
@@ -1256,12 +1285,30 @@ void draw_Window(iWindow *d) { | |||
1256 | // printf("draw %d\n", d->frameTime); fflush(stdout); | 1285 | // printf("draw %d\n", d->frameTime); fflush(stdout); |
1257 | //#endif | 1286 | //#endif |
1258 | /* Clear the window. */ | 1287 | /* Clear the window. */ |
1259 | const iColor back = get_Color(uiSeparator_ColorId); | 1288 | const int winFlags = SDL_GetWindowFlags(d->win); |
1289 | const iColor back = | ||
1290 | get_Color(winFlags & SDL_WINDOW_INPUT_FOCUS && d->place.snap != maximized_WindowSnap | ||
1291 | ? uiAnnotation_ColorId | ||
1292 | : uiSeparator_ColorId); | ||
1260 | SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255); | 1293 | SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255); |
1261 | SDL_RenderClear(d->render); | 1294 | SDL_RenderClear(d->render); |
1262 | /* Draw widgets. */ | 1295 | /* Draw widgets. */ |
1263 | d->frameTime = SDL_GetTicks(); | 1296 | d->frameTime = SDL_GetTicks(); |
1264 | draw_Widget(d->root); | 1297 | draw_Widget(d->root); |
1298 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
1299 | /* App icon. */ | ||
1300 | const iWidget *appIcon = findChild_Widget(d->root, "winbar.icon"); | ||
1301 | if (isVisible_Widget(appIcon)) { | ||
1302 | const int size = appIconSize_(); | ||
1303 | const iRect rect = bounds_Widget(appIcon); | ||
1304 | const iInt2 mid = mid_Rect(rect); | ||
1305 | SDL_RenderCopy( | ||
1306 | d->render, | ||
1307 | d->appIcon, | ||
1308 | NULL, | ||
1309 | &(SDL_Rect){ left_Rect(rect) + gap_UI * 1.25f, mid.y - size / 2, size, size }); | ||
1310 | } | ||
1311 | #endif | ||
1265 | #if 0 | 1312 | #if 0 |
1266 | /* Text cache debugging. */ { | 1313 | /* Text cache debugging. */ { |
1267 | SDL_Texture *cache = glyphCache_Text(); | 1314 | SDL_Texture *cache = glyphCache_Text(); |
@@ -1363,7 +1410,12 @@ void setSnap_Window(iWindow *d, int snapMode) { | |||
1363 | SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); | 1410 | SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); |
1364 | } | 1411 | } |
1365 | else { | 1412 | else { |
1366 | SDL_RestoreWindow(d->win); | 1413 | if (snap_Window(d) == fullscreen_WindowSnap) { |
1414 | SDL_SetWindowFullscreen(d->win, 0); | ||
1415 | } | ||
1416 | else { | ||
1417 | SDL_RestoreWindow(d->win); | ||
1418 | } | ||
1367 | } | 1419 | } |
1368 | } | 1420 | } |
1369 | 1421 | ||