diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 2 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 2 | ||||
-rw-r--r-- | src/ui/root.c | 10 | ||||
-rw-r--r-- | src/ui/root.h | 2 | ||||
-rw-r--r-- | src/ui/text.c | 93 | ||||
-rw-r--r-- | src/ui/text.h | 17 | ||||
-rw-r--r-- | src/ui/text_simple.c | 16 | ||||
-rw-r--r-- | src/ui/util.c | 42 | ||||
-rw-r--r-- | src/ui/widget.c | 38 | ||||
-rw-r--r-- | src/ui/widget.h | 4 | ||||
-rw-r--r-- | src/ui/window.c | 257 | ||||
-rw-r--r-- | src/ui/window.h | 34 |
12 files changed, 361 insertions, 156 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index ed9e41d6..6f9824de 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -750,7 +750,7 @@ static uint32_t mediaUpdateInterval_DocumentWidget_(const iDocumentWidget *d) { | |||
750 | if (document_App() != d) { | 750 | if (document_App() != d) { |
751 | return 0; | 751 | return 0; |
752 | } | 752 | } |
753 | if (get_Window()->isDrawFrozen) { | 753 | if (as_MainWindow(window_Widget(d))->isDrawFrozen) { |
754 | return 0; | 754 | return 0; |
755 | } | 755 | } |
756 | static const uint32_t invalidInterval_ = ~0u; | 756 | static const uint32_t invalidInterval_ = ~0u; |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index a561d5bd..f02bf408 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -2352,7 +2352,7 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
2352 | } | 2352 | } |
2353 | /* Draw the insertion point. */ | 2353 | /* Draw the insertion point. */ |
2354 | if (isFocused && d->cursorVis && contains_Range(&visLines, d->cursor.y) && | 2354 | if (isFocused && d->cursorVis && contains_Range(&visLines, d->cursor.y) && |
2355 | isEmpty_Range(&d->mark)) { | 2355 | (deviceType_App() == desktop_AppDeviceType || isEmpty_Range(&d->mark))) { |
2356 | iInt2 curSize; | 2356 | iInt2 curSize; |
2357 | iRangecc cursorChar = iNullRange; | 2357 | iRangecc cursorChar = iNullRange; |
2358 | int visWrapsAbove = 0; | 2358 | int visWrapsAbove = 0; |
diff --git a/src/ui/root.c b/src/ui/root.c index 52a08eca..9e290b05 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -298,16 +298,6 @@ void destroyPending_Root(iRoot *d) { | |||
298 | setCurrent_Root(oldRoot); | 298 | setCurrent_Root(oldRoot); |
299 | } | 299 | } |
300 | 300 | ||
301 | void postArrange_Root(iRoot *d) { | ||
302 | if (!d->pendingArrange) { | ||
303 | d->pendingArrange = iTrue; | ||
304 | SDL_Event ev = { .type = SDL_USEREVENT }; | ||
305 | ev.user.code = arrange_UserEventCode; | ||
306 | ev.user.data2 = d; | ||
307 | SDL_PushEvent(&ev); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | iPtrArray *onTop_Root(iRoot *d) { | 301 | iPtrArray *onTop_Root(iRoot *d) { |
312 | if (!d->onTop) { | 302 | if (!d->onTop) { |
313 | d->onTop = new_PtrArray(); | 303 | d->onTop = new_PtrArray(); |
diff --git a/src/ui/root.h b/src/ui/root.h index 740e97c9..04dd5e16 100644 --- a/src/ui/root.h +++ b/src/ui/root.h | |||
@@ -9,6 +9,7 @@ iDeclareType(Root) | |||
9 | 9 | ||
10 | struct Impl_Root { | 10 | struct Impl_Root { |
11 | iWidget * widget; | 11 | iWidget * widget; |
12 | iWindow * window; | ||
12 | iPtrArray *onTop; /* order is important; last one is topmost */ | 13 | iPtrArray *onTop; /* order is important; last one is topmost */ |
13 | iPtrSet * pendingDestruction; | 14 | iPtrSet * pendingDestruction; |
14 | iBool pendingArrange; | 15 | iBool pendingArrange; |
@@ -29,7 +30,6 @@ iAnyObject *findWidget_Root (const char *id); /* under curre | |||
29 | 30 | ||
30 | iPtrArray * onTop_Root (iRoot *); | 31 | iPtrArray * onTop_Root (iRoot *); |
31 | void destroyPending_Root (iRoot *); | 32 | void destroyPending_Root (iRoot *); |
32 | void postArrange_Root (iRoot *); | ||
33 | 33 | ||
34 | void updateMetrics_Root (iRoot *); | 34 | void updateMetrics_Root (iRoot *); |
35 | void updatePadding_Root (iRoot *); /* TODO: is part of metrics? */ | 35 | void updatePadding_Root (iRoot *); /* TODO: is part of metrics? */ |
diff --git a/src/ui/text.c b/src/ui/text.c index f7fff4bc..bf71b0e9 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -290,7 +290,9 @@ struct Impl_Text { | |||
290 | iRegExp * ansiEscape; | 290 | iRegExp * ansiEscape; |
291 | }; | 291 | }; |
292 | 292 | ||
293 | static iText text_; | 293 | iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render) |
294 | |||
295 | static iText *activeText_; | ||
294 | static iBlock *userFont_; | 296 | static iBlock *userFont_; |
295 | 297 | ||
296 | static void initFonts_Text_(iText *d) { | 298 | static void initFonts_Text_(iText *d) { |
@@ -501,8 +503,7 @@ void loadUserFonts_Text(void) { | |||
501 | } | 503 | } |
502 | } | 504 | } |
503 | 505 | ||
504 | void init_Text(SDL_Renderer *render) { | 506 | void init_Text(iText *d, SDL_Renderer *render) { |
505 | iText *d = &text_; | ||
506 | loadUserFonts_Text(); | 507 | loadUserFonts_Text(); |
507 | d->contentFont = nunito_TextFont; | 508 | d->contentFont = nunito_TextFont; |
508 | d->headingFont = nunito_TextFont; | 509 | d->headingFont = nunito_TextFont; |
@@ -521,8 +522,7 @@ void init_Text(SDL_Renderer *render) { | |||
521 | initFonts_Text_(d); | 522 | initFonts_Text_(d); |
522 | } | 523 | } |
523 | 524 | ||
524 | void deinit_Text(void) { | 525 | void deinit_Text(iText *d) { |
525 | iText *d = &text_; | ||
526 | SDL_FreePalette(d->grayscale); | 526 | SDL_FreePalette(d->grayscale); |
527 | deinitFonts_Text_(d); | 527 | deinitFonts_Text_(d); |
528 | deinitCache_Text_(d); | 528 | deinitCache_Text_(d); |
@@ -530,30 +530,34 @@ void deinit_Text(void) { | |||
530 | iRelease(d->ansiEscape); | 530 | iRelease(d->ansiEscape); |
531 | } | 531 | } |
532 | 532 | ||
533 | void setCurrent_Text(iText *d) { | ||
534 | activeText_ = d; | ||
535 | } | ||
536 | |||
533 | void setOpacity_Text(float opacity) { | 537 | void setOpacity_Text(float opacity) { |
534 | SDL_SetTextureAlphaMod(text_.cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); | 538 | SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); |
535 | } | 539 | } |
536 | 540 | ||
537 | void setContentFont_Text(enum iTextFont font) { | 541 | void setContentFont_Text(iText *d, enum iTextFont font) { |
538 | if (text_.contentFont != font) { | 542 | if (d->contentFont != font) { |
539 | text_.contentFont = font; | 543 | d->contentFont = font; |
540 | resetFonts_Text(); | 544 | resetFonts_Text(d); |
541 | } | 545 | } |
542 | } | 546 | } |
543 | 547 | ||
544 | void setHeadingFont_Text(enum iTextFont font) { | 548 | void setHeadingFont_Text(iText *d, enum iTextFont font) { |
545 | if (text_.headingFont != font) { | 549 | if (d->headingFont != font) { |
546 | text_.headingFont = font; | 550 | d->headingFont = font; |
547 | resetFonts_Text(); | 551 | resetFonts_Text(d); |
548 | } | 552 | } |
549 | } | 553 | } |
550 | 554 | ||
551 | void setContentFontSize_Text(float fontSizeFactor) { | 555 | void setContentFontSize_Text(iText *d, float fontSizeFactor) { |
552 | fontSizeFactor *= contentScale_Text_; | 556 | fontSizeFactor *= contentScale_Text_; |
553 | iAssert(fontSizeFactor > 0); | 557 | iAssert(fontSizeFactor > 0); |
554 | if (iAbs(text_.contentFontSize - fontSizeFactor) > 0.001f) { | 558 | if (iAbs(d->contentFontSize - fontSizeFactor) > 0.001f) { |
555 | text_.contentFontSize = fontSizeFactor; | 559 | d->contentFontSize = fontSizeFactor; |
556 | resetFonts_Text(); | 560 | resetFonts_Text(d); |
557 | } | 561 | } |
558 | } | 562 | } |
559 | 563 | ||
@@ -565,8 +569,7 @@ static void resetCache_Text_(iText *d) { | |||
565 | initCache_Text_(d); | 569 | initCache_Text_(d); |
566 | } | 570 | } |
567 | 571 | ||
568 | void resetFonts_Text(void) { | 572 | void resetFonts_Text(iText *d) { |
569 | iText *d = &text_; | ||
570 | deinitFonts_Text_(d); | 573 | deinitFonts_Text_(d); |
571 | deinitCache_Text_(d); | 574 | deinitCache_Text_(d); |
572 | initCache_Text_(d); | 575 | initCache_Text_(d); |
@@ -574,7 +577,7 @@ void resetFonts_Text(void) { | |||
574 | } | 577 | } |
575 | 578 | ||
576 | iLocalDef iFont *font_Text_(enum iFontId id) { | 579 | iLocalDef iFont *font_Text_(enum iFontId id) { |
577 | return &text_.fonts[id & mask_FontId]; | 580 | return &activeText_->fonts[id & mask_FontId]; |
578 | } | 581 | } |
579 | 582 | ||
580 | static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) { | 583 | static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) { |
@@ -584,7 +587,7 @@ static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, fl | |||
584 | SDL_Surface *surface8 = | 587 | SDL_Surface *surface8 = |
585 | SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8); | 588 | SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8); |
586 | SDL_SetSurfaceBlendMode(surface8, SDL_BLENDMODE_NONE); | 589 | SDL_SetSurfaceBlendMode(surface8, SDL_BLENDMODE_NONE); |
587 | SDL_SetSurfacePalette(surface8, text_.grayscale); | 590 | SDL_SetSurfacePalette(surface8, activeText_->grayscale); |
588 | #if LAGRANGE_RASTER_DEPTH != 8 | 591 | #if LAGRANGE_RASTER_DEPTH != 8 |
589 | /* Convert to the cache format. */ | 592 | /* Convert to the cache format. */ |
590 | SDL_Surface *surf = SDL_ConvertSurfaceFormat(surface8, LAGRANGE_RASTER_FORMAT, 0); | 593 | SDL_Surface *surf = SDL_ConvertSurfaceFormat(surface8, LAGRANGE_RASTER_FORMAT, 0); |
@@ -631,7 +634,7 @@ static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) { | |||
631 | &d->font, index_Glyph_(glyph), d->xScale, d->yScale, hoff * 0.5f, 0.0f, &x0, &y0, &x1, &y1); | 634 | &d->font, index_Glyph_(glyph), d->xScale, d->yScale, hoff * 0.5f, 0.0f, &x0, &y0, &x1, &y1); |
632 | glRect->size = init_I2(x1 - x0, y1 - y0); | 635 | glRect->size = init_I2(x1 - x0, y1 - y0); |
633 | /* Determine placement in the glyph cache texture, advancing in rows. */ | 636 | /* Determine placement in the glyph cache texture, advancing in rows. */ |
634 | glRect->pos = assignCachePos_Text_(&text_, glRect->size); | 637 | glRect->pos = assignCachePos_Text_(activeText_, glRect->size); |
635 | glyph->d[hoff] = init_I2(x0, y0); | 638 | glyph->d[hoff] = init_I2(x0, y0); |
636 | glyph->d[hoff].y += d->vertOffset; | 639 | glyph->d[hoff].y += d->vertOffset; |
637 | if (hoff == 0) { /* hoff==1 uses same metrics as `glyph` */ | 640 | if (hoff == 0) { /* hoff==1 uses same metrics as `glyph` */ |
@@ -737,11 +740,11 @@ static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) { | |||
737 | } | 740 | } |
738 | else { | 741 | else { |
739 | /* If the cache is running out of space, clear it and we'll recache what's needed currently. */ | 742 | /* If the cache is running out of space, clear it and we'll recache what's needed currently. */ |
740 | if (text_.cacheBottom > text_.cacheSize.y - maxGlyphHeight_Text_(&text_)) { | 743 | if (activeText_->cacheBottom > activeText_->cacheSize.y - maxGlyphHeight_Text_(activeText_)) { |
741 | #if !defined (NDEBUG) | 744 | #if !defined (NDEBUG) |
742 | printf("[Text] glyph cache is full, clearing!\n"); fflush(stdout); | 745 | printf("[Text] glyph cache is full, clearing!\n"); fflush(stdout); |
743 | #endif | 746 | #endif |
744 | resetCache_Text_(&text_); | 747 | resetCache_Text_(activeText_); |
745 | } | 748 | } |
746 | glyph = new_Glyph(glyphIndex); | 749 | glyph = new_Glyph(glyphIndex); |
747 | glyph->font = d; | 750 | glyph->font = d; |
@@ -858,7 +861,7 @@ static void finishRun_AttributedText_(iAttributedText *d, iAttributedRun *run, i | |||
858 | } | 861 | } |
859 | 862 | ||
860 | static enum iFontId fontId_Text_(const iFont *font) { | 863 | static enum iFontId fontId_Text_(const iFont *font) { |
861 | return (enum iFontId) (font - text_.fonts); | 864 | return (enum iFontId) (font - activeText_->fonts); |
862 | } | 865 | } |
863 | 866 | ||
864 | static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iChar overrideChar) { | 867 | static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iChar overrideChar) { |
@@ -949,7 +952,7 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh | |||
949 | /* Do a regexp match in the source text. */ | 952 | /* Do a regexp match in the source text. */ |
950 | iRegExpMatch m; | 953 | iRegExpMatch m; |
951 | init_RegExpMatch(&m); | 954 | init_RegExpMatch(&m); |
952 | if (match_RegExp(text_.ansiEscape, srcPos, d->source.end - srcPos, &m)) { | 955 | if (match_RegExp(activeText_->ansiEscape, srcPos, d->source.end - srcPos, &m)) { |
953 | finishRun_AttributedText_(d, &run, pos - 1); | 956 | finishRun_AttributedText_(d, &run, pos - 1); |
954 | run.fgColor = ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), | 957 | run.fgColor = ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), |
955 | tmParagraph_ColorId); | 958 | tmParagraph_ColorId); |
@@ -1082,9 +1085,9 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { | |||
1082 | while (index < size_Array(glyphIndices)) { | 1085 | while (index < size_Array(glyphIndices)) { |
1083 | for (; index < size_Array(glyphIndices); index++) { | 1086 | for (; index < size_Array(glyphIndices); index++) { |
1084 | const uint32_t glyphIndex = constValue_Array(glyphIndices, index, uint32_t); | 1087 | const uint32_t glyphIndex = constValue_Array(glyphIndices, index, uint32_t); |
1085 | const int lastCacheBottom = text_.cacheBottom; | 1088 | const int lastCacheBottom = activeText_->cacheBottom; |
1086 | iGlyph *glyph = glyphByIndex_Font_(d, glyphIndex); | 1089 | iGlyph *glyph = glyphByIndex_Font_(d, glyphIndex); |
1087 | if (text_.cacheBottom < lastCacheBottom) { | 1090 | if (activeText_->cacheBottom < lastCacheBottom) { |
1088 | /* The cache was reset due to running out of space. We need to restart from | 1091 | /* The cache was reset due to running out of space. We need to restart from |
1089 | the beginning! */ | 1092 | the beginning! */ |
1090 | bufX = 0; | 1093 | bufX = 0; |
@@ -1103,7 +1106,7 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { | |||
1103 | LAGRANGE_RASTER_DEPTH, | 1106 | LAGRANGE_RASTER_DEPTH, |
1104 | LAGRANGE_RASTER_FORMAT); | 1107 | LAGRANGE_RASTER_FORMAT); |
1105 | SDL_SetSurfaceBlendMode(buf, SDL_BLENDMODE_NONE); | 1108 | SDL_SetSurfaceBlendMode(buf, SDL_BLENDMODE_NONE); |
1106 | SDL_SetSurfacePalette(buf, text_.grayscale); | 1109 | SDL_SetSurfacePalette(buf, activeText_->grayscale); |
1107 | } | 1110 | } |
1108 | SDL_Surface *surfaces[2] = { | 1111 | SDL_Surface *surfaces[2] = { |
1109 | !isRasterized_Glyph_(glyph, 0) ? | 1112 | !isRasterized_Glyph_(glyph, 0) ? |
@@ -1147,19 +1150,19 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { | |||
1147 | } | 1150 | } |
1148 | /* Finished or the buffer is full, copy the glyphs to the cache texture. */ | 1151 | /* Finished or the buffer is full, copy the glyphs to the cache texture. */ |
1149 | if (!isEmpty_Array(rasters)) { | 1152 | if (!isEmpty_Array(rasters)) { |
1150 | SDL_Texture *bufTex = SDL_CreateTextureFromSurface(text_.render, buf); | 1153 | SDL_Texture *bufTex = SDL_CreateTextureFromSurface(activeText_->render, buf); |
1151 | SDL_SetTextureBlendMode(bufTex, SDL_BLENDMODE_NONE); | 1154 | SDL_SetTextureBlendMode(bufTex, SDL_BLENDMODE_NONE); |
1152 | if (!isTargetChanged) { | 1155 | if (!isTargetChanged) { |
1153 | isTargetChanged = iTrue; | 1156 | isTargetChanged = iTrue; |
1154 | oldTarget = SDL_GetRenderTarget(text_.render); | 1157 | oldTarget = SDL_GetRenderTarget(activeText_->render); |
1155 | SDL_SetRenderTarget(text_.render, text_.cache); | 1158 | SDL_SetRenderTarget(activeText_->render, activeText_->cache); |
1156 | } | 1159 | } |
1157 | // printf("copying %zu rasters from %p\n", size_Array(rasters), bufTex); fflush(stdout); | 1160 | // printf("copying %zu rasters from %p\n", size_Array(rasters), bufTex); fflush(stdout); |
1158 | iConstForEach(Array, i, rasters) { | 1161 | iConstForEach(Array, i, rasters) { |
1159 | const iRasterGlyph *rg = i.value; | 1162 | const iRasterGlyph *rg = i.value; |
1160 | // iAssert(isEqual_I2(rg->rect.size, rg->glyph->rect[rg->hoff].size)); | 1163 | // iAssert(isEqual_I2(rg->rect.size, rg->glyph->rect[rg->hoff].size)); |
1161 | const iRect *glRect = &rg->glyph->rect[rg->hoff]; | 1164 | const iRect *glRect = &rg->glyph->rect[rg->hoff]; |
1162 | SDL_RenderCopy(text_.render, | 1165 | SDL_RenderCopy(activeText_->render, |
1163 | bufTex, | 1166 | bufTex, |
1164 | (const SDL_Rect *) &rg->rect, | 1167 | (const SDL_Rect *) &rg->rect, |
1165 | (const SDL_Rect *) glRect); | 1168 | (const SDL_Rect *) glRect); |
@@ -1179,7 +1182,7 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) { | |||
1179 | SDL_FreeSurface(buf); | 1182 | SDL_FreeSurface(buf); |
1180 | } | 1183 | } |
1181 | if (isTargetChanged) { | 1184 | if (isTargetChanged) { |
1182 | SDL_SetRenderTarget(text_.render, oldTarget); | 1185 | SDL_SetRenderTarget(activeText_->render, oldTarget); |
1183 | } | 1186 | } |
1184 | } | 1187 | } |
1185 | 1188 | ||
@@ -1706,9 +1709,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1706 | } | 1709 | } |
1707 | if (~mode & permanentColorFlag_RunMode) { | 1710 | if (~mode & permanentColorFlag_RunMode) { |
1708 | const iColor clr = run->fgColor; | 1711 | const iColor clr = run->fgColor; |
1709 | SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b); | 1712 | SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b); |
1710 | if (args->mode & fillBackground_RunMode) { | 1713 | if (args->mode & fillBackground_RunMode) { |
1711 | SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0); | 1714 | SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0); |
1712 | } | 1715 | } |
1713 | } | 1716 | } |
1714 | SDL_Rect src; | 1717 | SDL_Rect src; |
@@ -1719,9 +1722,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1719 | /* Alpha blending looks much better if the RGB components don't change in | 1722 | /* Alpha blending looks much better if the RGB components don't change in |
1720 | the partially transparent pixels. */ | 1723 | the partially transparent pixels. */ |
1721 | /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */ | 1724 | /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */ |
1722 | SDL_RenderFillRect(text_.render, &dst); | 1725 | SDL_RenderFillRect(activeText_->render, &dst); |
1723 | } | 1726 | } |
1724 | SDL_RenderCopy(text_.render, text_.cache, &src, &dst); | 1727 | SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst); |
1725 | #if 0 | 1728 | #if 0 |
1726 | /* Show spaces and direction. */ | 1729 | /* Show spaces and direction. */ |
1727 | if (logicalText[logPos] == 0x20) { | 1730 | if (logicalText[logPos] == 0x20) { |
@@ -1863,7 +1866,7 @@ iTextMetrics measureN_Text(int fontId, const char *text, size_t n) { | |||
1863 | } | 1866 | } |
1864 | 1867 | ||
1865 | static void drawBoundedN_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text, size_t maxLen) { | 1868 | static void drawBoundedN_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text, size_t maxLen) { |
1866 | iText * d = &text_; | 1869 | iText * d = activeText_; |
1867 | iFont * font = font_Text_(fontId); | 1870 | iFont * font = font_Text_(fontId); |
1868 | const iColor clr = get_Color(color & mask_ColorId); | 1871 | const iColor clr = get_Color(color & mask_ColorId); |
1869 | SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b); | 1872 | SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b); |
@@ -2057,7 +2060,7 @@ iTextMetrics draw_WrapText(iWrapText *d, int fontId, iInt2 pos, int color) { | |||
2057 | } | 2060 | } |
2058 | 2061 | ||
2059 | SDL_Texture *glyphCache_Text(void) { | 2062 | SDL_Texture *glyphCache_Text(void) { |
2060 | return text_.cache; | 2063 | return activeText_->cache; |
2061 | } | 2064 | } |
2062 | 2065 | ||
2063 | static void freeBitmap_(void *ptr) { | 2066 | static void freeBitmap_(void *ptr) { |
@@ -2170,7 +2173,7 @@ iString *renderBlockChars_Text(const iBlock *fontData, int height, enum iTextBlo | |||
2170 | iDefineTypeConstructionArgs(TextBuf, (iWrapText *wrapText, int font, int color), wrapText, font, color) | 2173 | iDefineTypeConstructionArgs(TextBuf, (iWrapText *wrapText, int font, int color), wrapText, font, color) |
2171 | 2174 | ||
2172 | void init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) { | 2175 | void init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) { |
2173 | SDL_Renderer *render = text_.render; | 2176 | SDL_Renderer *render = activeText_->render; |
2174 | d->size = measure_WrapText(wrapText, font).bounds.size; | 2177 | d->size = measure_WrapText(wrapText, font).bounds.size; |
2175 | SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); | 2178 | SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); |
2176 | if (d->size.x * d->size.y) { | 2179 | if (d->size.x * d->size.y) { |
@@ -2191,9 +2194,9 @@ void init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) { | |||
2191 | SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); | 2194 | SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); |
2192 | SDL_SetRenderDrawColor(render, 255, 255, 255, 0); | 2195 | SDL_SetRenderDrawColor(render, 255, 255, 255, 0); |
2193 | SDL_RenderClear(render); | 2196 | SDL_RenderClear(render); |
2194 | SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */ | 2197 | SDL_SetTextureBlendMode(activeText_->cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */ |
2195 | draw_WrapText(wrapText, font, zero_I2(), color | fillBackground_ColorId); | 2198 | draw_WrapText(wrapText, font, zero_I2(), color | fillBackground_ColorId); |
2196 | SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_BLEND); | 2199 | SDL_SetTextureBlendMode(activeText_->cache, SDL_BLENDMODE_BLEND); |
2197 | SDL_SetRenderTarget(render, oldTarget); | 2200 | SDL_SetRenderTarget(render, oldTarget); |
2198 | origin_Paint = oldOrigin; | 2201 | origin_Paint = oldOrigin; |
2199 | SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND); | 2202 | SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND); |
@@ -2212,7 +2215,7 @@ void draw_TextBuf(const iTextBuf *d, iInt2 pos, int color) { | |||
2212 | addv_I2(&pos, origin_Paint); | 2215 | addv_I2(&pos, origin_Paint); |
2213 | const iColor clr = get_Color(color); | 2216 | const iColor clr = get_Color(color); |
2214 | SDL_SetTextureColorMod(d->texture, clr.r, clr.g, clr.b); | 2217 | SDL_SetTextureColorMod(d->texture, clr.r, clr.g, clr.b); |
2215 | SDL_RenderCopy(text_.render, | 2218 | SDL_RenderCopy(activeText_->render, |
2216 | d->texture, | 2219 | d->texture, |
2217 | &(SDL_Rect){ 0, 0, d->size.x, d->size.y }, | 2220 | &(SDL_Rect){ 0, 0, d->size.x, d->size.y }, |
2218 | &(SDL_Rect){ pos.x, pos.y, d->size.x, d->size.y }); | 2221 | &(SDL_Rect){ pos.x, pos.y, d->size.x, d->size.y }); |
diff --git a/src/ui/text.h b/src/ui/text.h index ac6cc1c1..1da43818 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -139,15 +139,20 @@ enum iTextFont { | |||
139 | 139 | ||
140 | extern int gap_Text; /* affected by content font size */ | 140 | extern int gap_Text; /* affected by content font size */ |
141 | 141 | ||
142 | void init_Text (SDL_Renderer *); | 142 | iDeclareType(Text) |
143 | void deinit_Text (void); | 143 | iDeclareTypeConstructionArgs(Text, SDL_Renderer *) |
144 | |||
145 | void init_Text (iText *, SDL_Renderer *); | ||
146 | void deinit_Text (iText *); | ||
147 | |||
148 | void setCurrent_Text (iText *); | ||
144 | 149 | ||
145 | void loadUserFonts_Text (void); /* based on Prefs */ | 150 | void loadUserFonts_Text (void); /* based on Prefs */ |
146 | 151 | ||
147 | void setContentFont_Text (enum iTextFont font); | 152 | void setContentFont_Text (iText *, enum iTextFont font); |
148 | void setHeadingFont_Text (enum iTextFont font); | 153 | void setHeadingFont_Text (iText *, enum iTextFont font); |
149 | void setContentFontSize_Text (float fontSizeFactor); /* affects all except `default*` fonts */ | 154 | void setContentFontSize_Text (iText *, float fontSizeFactor); /* affects all except `default*` fonts */ |
150 | void resetFonts_Text (void); | 155 | void resetFonts_Text (iText *); |
151 | 156 | ||
152 | int lineHeight_Text (int fontId); | 157 | int lineHeight_Text (int fontId); |
153 | iRect visualBounds_Text (int fontId, iRangecc text); | 158 | iRect visualBounds_Text (int fontId, iRangecc text); |
diff --git a/src/ui/text_simple.c b/src/ui/text_simple.c index bf33b4be..8b1de64a 100644 --- a/src/ui/text_simple.c +++ b/src/ui/text_simple.c | |||
@@ -92,7 +92,7 @@ static iRect runSimple_Font_(iFont *d, const iRunArgs *args) { | |||
92 | } | 92 | } |
93 | if (args->mode & fillBackground_RunMode) { | 93 | if (args->mode & fillBackground_RunMode) { |
94 | const iColor initial = get_Color(args->color); | 94 | const iColor initial = get_Color(args->color); |
95 | SDL_SetRenderDrawColor(text_.render, initial.r, initial.g, initial.b, 0); | 95 | SDL_SetRenderDrawColor(activeText_->render, initial.r, initial.g, initial.b, 0); |
96 | } | 96 | } |
97 | /* Text rendering is not very straightforward! Let's dive in... */ | 97 | /* Text rendering is not very straightforward! Let's dive in... */ |
98 | iChar prevCh = 0; | 98 | iChar prevCh = 0; |
@@ -114,14 +114,14 @@ static iRect runSimple_Font_(iFont *d, const iRunArgs *args) { | |||
114 | chPos++; | 114 | chPos++; |
115 | iRegExpMatch m; | 115 | iRegExpMatch m; |
116 | init_RegExpMatch(&m); | 116 | init_RegExpMatch(&m); |
117 | if (match_RegExp(text_.ansiEscape, chPos, args->text.end - chPos, &m)) { | 117 | if (match_RegExp(activeText_->ansiEscape, chPos, args->text.end - chPos, &m)) { |
118 | if (mode & draw_RunMode && ~mode & permanentColorFlag_RunMode) { | 118 | if (mode & draw_RunMode && ~mode & permanentColorFlag_RunMode) { |
119 | /* Change the color. */ | 119 | /* Change the color. */ |
120 | const iColor clr = | 120 | const iColor clr = |
121 | ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), tmParagraph_ColorId); | 121 | ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), tmParagraph_ColorId); |
122 | SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b); | 122 | SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b); |
123 | if (args->mode & fillBackground_RunMode) { | 123 | if (args->mode & fillBackground_RunMode) { |
124 | SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0); | 124 | SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0); |
125 | } | 125 | } |
126 | } | 126 | } |
127 | chPos = end_RegExpMatch(&m); | 127 | chPos = end_RegExpMatch(&m); |
@@ -205,9 +205,9 @@ static iRect runSimple_Font_(iFont *d, const iRunArgs *args) { | |||
205 | } | 205 | } |
206 | if (mode & draw_RunMode && ~mode & permanentColorFlag_RunMode) { | 206 | if (mode & draw_RunMode && ~mode & permanentColorFlag_RunMode) { |
207 | const iColor clr = get_Color(colorNum); | 207 | const iColor clr = get_Color(colorNum); |
208 | SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b); | 208 | SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b); |
209 | if (args->mode & fillBackground_RunMode) { | 209 | if (args->mode & fillBackground_RunMode) { |
210 | SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0); | 210 | SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0); |
211 | } | 211 | } |
212 | } | 212 | } |
213 | prevCh = 0; | 213 | prevCh = 0; |
@@ -311,9 +311,9 @@ static iRect runSimple_Font_(iFont *d, const iRunArgs *args) { | |||
311 | if (args->mode & fillBackground_RunMode) { | 311 | if (args->mode & fillBackground_RunMode) { |
312 | /* Alpha blending looks much better if the RGB components don't change in | 312 | /* Alpha blending looks much better if the RGB components don't change in |
313 | the partially transparent pixels. */ | 313 | the partially transparent pixels. */ |
314 | SDL_RenderFillRect(text_.render, &dst); | 314 | SDL_RenderFillRect(activeText_->render, &dst); |
315 | } | 315 | } |
316 | SDL_RenderCopy(text_.render, text_.cache, &src, &dst); | 316 | SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst); |
317 | } | 317 | } |
318 | xpos += advance; | 318 | xpos += advance; |
319 | if (!isSpace_Char(ch)) { | 319 | if (!isSpace_Char(ch)) { |
diff --git a/src/ui/util.c b/src/ui/util.c index 721aed2d..38977b96 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -613,6 +613,8 @@ iBool isAction_Widget(const iWidget *d) { | |||
613 | /*-----------------------------------------------------------------------------------------------*/ | 613 | /*-----------------------------------------------------------------------------------------------*/ |
614 | 614 | ||
615 | static iBool isCommandIgnoredByMenus_(const char *cmd) { | 615 | static iBool isCommandIgnoredByMenus_(const char *cmd) { |
616 | if (equal_Command(cmd, "window.focus.lost") || | ||
617 | equal_Command(cmd, "window.focus.gained")) return iTrue; | ||
616 | /* TODO: Perhaps a common way of indicating which commands are notifications and should not | 618 | /* TODO: Perhaps a common way of indicating which commands are notifications and should not |
617 | be reacted to by menus? */ | 619 | be reacted to by menus? */ |
618 | return equal_Command(cmd, "media.updated") || | 620 | return equal_Command(cmd, "media.updated") || |
@@ -810,6 +812,10 @@ static void updateMenuItemFonts_Widget_(iWidget *d) { | |||
810 | } | 812 | } |
811 | } | 813 | } |
812 | 814 | ||
815 | iLocalDef iBool isUsingMenuPopupWindows_(void) { | ||
816 | return deviceType_App() == desktop_AppDeviceType; | ||
817 | } | ||
818 | |||
813 | void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { | 819 | void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { |
814 | const iRect rootRect = rect_Root(d->root); | 820 | const iRect rootRect = rect_Root(d->root); |
815 | const iInt2 rootSize = rootRect.size; | 821 | const iInt2 rootSize = rootRect.size; |
@@ -822,6 +828,26 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { | |||
822 | processEvents_App(postedEventsOnly_AppEventMode); | 828 | processEvents_App(postedEventsOnly_AppEventMode); |
823 | setFlags_Widget(d, hidden_WidgetFlag, iFalse); | 829 | setFlags_Widget(d, hidden_WidgetFlag, iFalse); |
824 | setFlags_Widget(d, commandOnMouseMiss_WidgetFlag, iTrue); | 830 | setFlags_Widget(d, commandOnMouseMiss_WidgetFlag, iTrue); |
831 | if (isUsingMenuPopupWindows_()) { | ||
832 | if (postCommands) { | ||
833 | postCommand_Widget(d, "menu.opened"); | ||
834 | } | ||
835 | updateMenuItemFonts_Widget_(d); | ||
836 | iRoot *oldRoot = current_Root(); | ||
837 | setFlags_Widget(d, keepOnTop_WidgetFlag, iFalse); | ||
838 | setUserData_Object(d, parent_Widget(d)); | ||
839 | removeChild_Widget(parent_Widget(d), d); /* we'll borrow the widget for a while */ | ||
840 | iInt2 mousePos; | ||
841 | SDL_GetGlobalMouseState(&mousePos.x, &mousePos.y); | ||
842 | iWindow *win = newPopup_Window(sub_I2(mousePos, divi_I2(gap2_UI, 2)), d); | ||
843 | SDL_SetWindowTitle(win->win, "Menu"); | ||
844 | addPopup_App(win); /* window takes the widget */ | ||
845 | SDL_ShowWindow(win->win); | ||
846 | draw_Window(win); | ||
847 | setCurrent_Window(mainWindow_App()); | ||
848 | setCurrent_Root(oldRoot); | ||
849 | return; | ||
850 | } | ||
825 | raise_Widget(d); | 851 | raise_Widget(d); |
826 | setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iFalse); | 852 | setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iFalse); |
827 | if (isPortraitPhone) { | 853 | if (isPortraitPhone) { |
@@ -836,7 +862,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { | |||
836 | arrange_Widget(d); | 862 | arrange_Widget(d); |
837 | if (isPortraitPhone) { | 863 | if (isPortraitPhone) { |
838 | if (isSlidePanel) { | 864 | if (isSlidePanel) { |
839 | d->rect.pos = zero_I2(); //neg_I2(bounds_Widget(parent_Widget(d)).pos); | 865 | d->rect.pos = zero_I2(); |
840 | } | 866 | } |
841 | else { | 867 | else { |
842 | d->rect.pos = init_I2(0, rootSize.y); | 868 | d->rect.pos = init_I2(0, rootSize.y); |
@@ -856,7 +882,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { | |||
856 | float l, t, r, b; | 882 | float l, t, r, b; |
857 | safeAreaInsets_iOS(&l, &t, &r, &b); | 883 | safeAreaInsets_iOS(&l, &t, &r, &b); |
858 | topExcess += t; | 884 | topExcess += t; |
859 | bottomExcess += iMax(b, get_Window()->keyboardHeight); | 885 | bottomExcess += iMax(b, get_MainWindow()->keyboardHeight); |
860 | leftExcess += l; | 886 | leftExcess += l; |
861 | rightExcess += r; | 887 | rightExcess += r; |
862 | } | 888 | } |
@@ -884,6 +910,18 @@ void closeMenu_Widget(iWidget *d) { | |||
884 | if (d == NULL || flags_Widget(d) & hidden_WidgetFlag) { | 910 | if (d == NULL || flags_Widget(d) & hidden_WidgetFlag) { |
885 | return; /* Already closed. */ | 911 | return; /* Already closed. */ |
886 | } | 912 | } |
913 | if (isUsingMenuPopupWindows_()) { | ||
914 | iWindow *win = window_Widget(d); | ||
915 | iAssert(type_Window(win) == popup_WindowType); | ||
916 | iWidget *originalParent = userData_Object(d); | ||
917 | setUserData_Object(d, NULL); | ||
918 | win->roots[0]->widget = NULL; | ||
919 | setRoot_Widget(d, originalParent->root); | ||
920 | addChild_Widget(originalParent, d); | ||
921 | setFlags_Widget(d, keepOnTop_WidgetFlag, iTrue); | ||
922 | SDL_HideWindow(win->win); | ||
923 | collect_Garbage(win, (iDeleteFunc) delete_Window); /* get rid of it after event processing */ | ||
924 | } | ||
887 | setFlags_Widget(d, hidden_WidgetFlag, iTrue); | 925 | setFlags_Widget(d, hidden_WidgetFlag, iTrue); |
888 | setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iTrue); | 926 | setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iTrue); |
889 | postRefresh_App(); | 927 | postRefresh_App(); |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 23c19315..7b33a752 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -271,6 +271,10 @@ iWidget *root_Widget(const iWidget *d) { | |||
271 | return d ? d->root->widget : NULL; | 271 | return d ? d->root->widget : NULL; |
272 | } | 272 | } |
273 | 273 | ||
274 | iWindow *window_Widget(const iAnyObject *d) { | ||
275 | return constAs_Widget(d)->root->window; | ||
276 | } | ||
277 | |||
274 | void showCollapsed_Widget(iWidget *d, iBool show) { | 278 | void showCollapsed_Widget(iWidget *d, iBool show) { |
275 | const iBool isVisible = !(d->flags & hidden_WidgetFlag); | 279 | const iBool isVisible = !(d->flags & hidden_WidgetFlag); |
276 | if ((isVisible && !show) || (!isVisible && show)) { | 280 | if ((isVisible && !show) || (!isVisible && show)) { |
@@ -979,11 +983,10 @@ void unhover_Widget(void) { | |||
979 | } | 983 | } |
980 | 984 | ||
981 | iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | 985 | iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { |
982 | //iAssert(d->root == get_Root()); | ||
983 | if (!d->parent) { | 986 | if (!d->parent) { |
984 | if (get_Window()->focus && get_Window()->focus->root == d->root && isKeyboardEvent_(ev)) { | 987 | if (window_Widget(d)->focus && window_Widget(d)->focus->root == d->root && isKeyboardEvent_(ev)) { |
985 | /* Root dispatches keyboard events directly to the focused widget. */ | 988 | /* Root dispatches keyboard events directly to the focused widget. */ |
986 | if (dispatchEvent_Widget(get_Window()->focus, ev)) { | 989 | if (dispatchEvent_Widget(window_Widget(d)->focus, ev)) { |
987 | return iTrue; | 990 | return iTrue; |
988 | } | 991 | } |
989 | } | 992 | } |
@@ -1012,7 +1015,8 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
1012 | } | 1015 | } |
1013 | } | 1016 | } |
1014 | else if (ev->type == SDL_MOUSEMOTION && | 1017 | else if (ev->type == SDL_MOUSEMOTION && |
1015 | (!get_Window()->hover || hasParent_Widget(d, get_Window()->hover)) && | 1018 | ev->motion.windowID == SDL_GetWindowID(window_Widget(d)->win) && |
1019 | (!window_Widget(d)->hover || hasParent_Widget(d, window_Widget(d)->hover)) && | ||
1016 | flags_Widget(d) & hover_WidgetFlag && ~flags_Widget(d) & hidden_WidgetFlag && | 1020 | flags_Widget(d) & hover_WidgetFlag && ~flags_Widget(d) & hidden_WidgetFlag && |
1017 | ~flags_Widget(d) & disabled_WidgetFlag) { | 1021 | ~flags_Widget(d) & disabled_WidgetFlag) { |
1018 | if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) { | 1022 | if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) { |
@@ -1031,11 +1035,11 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
1031 | iReverseForEach(ObjectList, i, d->children) { | 1035 | iReverseForEach(ObjectList, i, d->children) { |
1032 | iWidget *child = as_Widget(i.object); | 1036 | iWidget *child = as_Widget(i.object); |
1033 | //iAssert(child->root == d->root); | 1037 | //iAssert(child->root == d->root); |
1034 | if (child == get_Window()->focus && isKeyboardEvent_(ev)) { | 1038 | if (child == window_Widget(d)->focus && isKeyboardEvent_(ev)) { |
1035 | continue; /* Already dispatched. */ | 1039 | continue; /* Already dispatched. */ |
1036 | } | 1040 | } |
1037 | if (isVisible_Widget(child) && child->flags & keepOnTop_WidgetFlag) { | 1041 | if (isVisible_Widget(child) && child->flags & keepOnTop_WidgetFlag) { |
1038 | /* Already dispatched. */ | 1042 | /* Already dispatched. */ |
1039 | continue; | 1043 | continue; |
1040 | } | 1044 | } |
1041 | if (dispatchEvent_Widget(child, ev)) { | 1045 | if (dispatchEvent_Widget(child, ev)) { |
@@ -1050,7 +1054,7 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
1050 | #endif | 1054 | #endif |
1051 | #if 0 | 1055 | #if 0 |
1052 | if (ev->type == SDL_MOUSEMOTION) { | 1056 | if (ev->type == SDL_MOUSEMOTION) { |
1053 | printf("[%p] %s:'%s' (on top) ate the motion\n", | 1057 | printf("[%p] %s:'%s' ate the motion\n", |
1054 | child, class_Widget(child)->name, | 1058 | child, class_Widget(child)->name, |
1055 | cstr_String(id_Widget(child))); | 1059 | cstr_String(id_Widget(child))); |
1056 | fflush(stdout); | 1060 | fflush(stdout); |
@@ -1246,7 +1250,7 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
1246 | ev->button.x, | 1250 | ev->button.x, |
1247 | ev->button.y); | 1251 | ev->button.y); |
1248 | } | 1252 | } |
1249 | setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); | 1253 | setCursor_Window(window_Widget(d), SDL_SYSTEM_CURSOR_ARROW); |
1250 | return iTrue; | 1254 | return iTrue; |
1251 | } | 1255 | } |
1252 | return iFalse; | 1256 | return iFalse; |
@@ -1270,6 +1274,7 @@ iLocalDef iBool isDrawn_Widget_(const iWidget *d) { | |||
1270 | void drawLayerEffects_Widget(const iWidget *d) { | 1274 | void drawLayerEffects_Widget(const iWidget *d) { |
1271 | /* Layered effects are not buffered, so they are drawn here separately. */ | 1275 | /* Layered effects are not buffered, so they are drawn here separately. */ |
1272 | iAssert(isDrawn_Widget_(d)); | 1276 | iAssert(isDrawn_Widget_(d)); |
1277 | iAssert(window_Widget(d) == get_Window()); | ||
1273 | iBool shadowBorder = (d->flags & keepOnTop_WidgetFlag && ~d->flags & mouseModal_WidgetFlag) != 0; | 1278 | iBool shadowBorder = (d->flags & keepOnTop_WidgetFlag && ~d->flags & mouseModal_WidgetFlag) != 0; |
1274 | iBool fadeBackground = (d->bgColor >= 0 || d->frameColor >= 0) && d->flags & mouseModal_WidgetFlag; | 1279 | iBool fadeBackground = (d->bgColor >= 0 || d->frameColor >= 0) && d->flags & mouseModal_WidgetFlag; |
1275 | if (deviceType_App() == phone_AppDeviceType) { | 1280 | if (deviceType_App() == phone_AppDeviceType) { |
@@ -1539,6 +1544,7 @@ static void endBufferDraw_Widget_(const iWidget *d) { | |||
1539 | } | 1544 | } |
1540 | 1545 | ||
1541 | void draw_Widget(const iWidget *d) { | 1546 | void draw_Widget(const iWidget *d) { |
1547 | iAssert(window_Widget(d) == get_Window()); | ||
1542 | if (!isDrawn_Widget_(d)) { | 1548 | if (!isDrawn_Widget_(d)) { |
1543 | if (d->drawBuf) { | 1549 | if (d->drawBuf) { |
1544 | // printf("[%p] drawBuffer released\n", d); | 1550 | // printf("[%p] drawBuffer released\n", d); |
@@ -1820,7 +1826,17 @@ iBool equalWidget_Command(const char *cmd, const iWidget *widget, const char *ch | |||
1820 | if (equal_Command(cmd, checkCommand)) { | 1826 | if (equal_Command(cmd, checkCommand)) { |
1821 | const iWidget *src = pointer_Command(cmd); | 1827 | const iWidget *src = pointer_Command(cmd); |
1822 | iAssert(!src || strstr(cmd, " ptr:")); | 1828 | iAssert(!src || strstr(cmd, " ptr:")); |
1823 | return src == widget || hasParent_Widget(src, widget); | 1829 | if (src == widget || hasParent_Widget(src, widget)) { |
1830 | return iTrue; | ||
1831 | } | ||
1832 | // if (src && type_Window(window_Widget(src)) == popup_WindowType) { | ||
1833 | // /* Special case: command was emitted from a popup widget. The popup root widget actually | ||
1834 | // belongs to someone else. */ | ||
1835 | // iWidget *realParent = userData_Object(src->root->widget); | ||
1836 | // iAssert(realParent); | ||
1837 | // iAssert(isInstance_Object(realParent, &Class_Widget)); | ||
1838 | // return realParent == widget || hasParent_Widget(realParent, widget); | ||
1839 | // } | ||
1824 | } | 1840 | } |
1825 | return iFalse; | 1841 | return iFalse; |
1826 | } | 1842 | } |
@@ -1962,6 +1978,10 @@ void postCommand_Widget(const iAnyObject *d, const char *cmd, ...) { | |||
1962 | } | 1978 | } |
1963 | if (!isGlobal) { | 1979 | if (!isGlobal) { |
1964 | iAssert(isInstance_Object(d, &Class_Widget)); | 1980 | iAssert(isInstance_Object(d, &Class_Widget)); |
1981 | if (type_Window(window_Widget(d)) == popup_WindowType) { | ||
1982 | postCommandf_Root(((const iWidget *) d)->root, "cancel popup:1 ptr:%p", d); | ||
1983 | d = userData_Object(root_Widget(d)); | ||
1984 | } | ||
1965 | appendFormat_String(&str, " ptr:%p", d); | 1985 | appendFormat_String(&str, " ptr:%p", d); |
1966 | } | 1986 | } |
1967 | postCommandString_Root(((const iWidget *) d)->root, &str); | 1987 | postCommandString_Root(((const iWidget *) d)->root, &str); |
diff --git a/src/ui/widget.h b/src/ui/widget.h index 7491cb79..0eab69c1 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h | |||
@@ -34,7 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
34 | #include <the_Foundation/string.h> | 34 | #include <the_Foundation/string.h> |
35 | #include <SDL_events.h> | 35 | #include <SDL_events.h> |
36 | 36 | ||
37 | iDeclareType(Root) /* each widget is associated with a Root */ | 37 | iDeclareType(Root) /* each widget is associated with a Root */ |
38 | iDeclareType(Window) /* each Root is inside a Window */ | ||
38 | 39 | ||
39 | #define iDeclareWidgetClass(className) \ | 40 | #define iDeclareWidgetClass(className) \ |
40 | iDeclareType(className); \ | 41 | iDeclareType(className); \ |
@@ -185,6 +186,7 @@ void releaseChildren_Widget (iWidget *); | |||
185 | - inner: 0,0 is at the top left corner of the widget */ | 186 | - inner: 0,0 is at the top left corner of the widget */ |
186 | 187 | ||
187 | iWidget * root_Widget (const iWidget *); | 188 | iWidget * root_Widget (const iWidget *); |
189 | iWindow * window_Widget (const iAnyObject *); | ||
188 | const iString * id_Widget (const iWidget *); | 190 | const iString * id_Widget (const iWidget *); |
189 | int64_t flags_Widget (const iWidget *); | 191 | int64_t flags_Widget (const iWidget *); |
190 | iRect bounds_Widget (const iWidget *); /* outer bounds */ | 192 | iRect bounds_Widget (const iWidget *); /* outer bounds */ |
diff --git a/src/ui/window.c b/src/ui/window.c index 92125d81..e9a34ace 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -57,7 +57,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
57 | #include "stb_image.h" | 57 | #include "stb_image.h" |
58 | #include "stb_image_resize.h" | 58 | #include "stb_image_resize.h" |
59 | 59 | ||
60 | static iWindow *theWindow_ = NULL; | 60 | static iWindow * theWindow_; |
61 | static iMainWindow *theMainWindow_; | ||
61 | 62 | ||
62 | #if defined (iPlatformApple) || defined (iPlatformLinux) || defined (iPlatformOther) | 63 | #if defined (iPlatformApple) || defined (iPlatformLinux) || defined (iPlatformOther) |
63 | static float initialUiScale_ = 1.0f; | 64 | static float initialUiScale_ = 1.0f; |
@@ -67,6 +68,9 @@ static float initialUiScale_ = 1.1f; | |||
67 | 68 | ||
68 | static iBool isOpenGLRenderer_; | 69 | static iBool isOpenGLRenderer_; |
69 | 70 | ||
71 | iDefineTypeConstructionArgs(Window, | ||
72 | (enum iWindowType type, iRect rect, uint32_t flags), | ||
73 | type, rect, flags) | ||
70 | iDefineTypeConstructionArgs(MainWindow, (iRect rect), rect) | 74 | iDefineTypeConstructionArgs(MainWindow, (iRect rect), rect) |
71 | 75 | ||
72 | /* TODO: Define menus per platform. */ | 76 | /* TODO: Define menus per platform. */ |
@@ -205,6 +209,7 @@ static void setupUserInterface_MainWindow(iMainWindow *d) { | |||
205 | #endif | 209 | #endif |
206 | /* One root is created by default. */ | 210 | /* One root is created by default. */ |
207 | d->base.roots[0] = new_Root(); | 211 | d->base.roots[0] = new_Root(); |
212 | d->base.roots[0]->window = as_Window(d); | ||
208 | setCurrent_Root(d->base.roots[0]); | 213 | setCurrent_Root(d->base.roots[0]); |
209 | createUserInterface_Root(d->base.roots[0]); | 214 | createUserInterface_Root(d->base.roots[0]); |
210 | setCurrent_Root(NULL); | 215 | setCurrent_Root(NULL); |
@@ -409,7 +414,6 @@ void init_Window(iWindow *d, enum iWindowType type, iRect rect, uint32_t flags) | |||
409 | d->mouseGrab = NULL; | 414 | d->mouseGrab = NULL; |
410 | d->focus = NULL; | 415 | d->focus = NULL; |
411 | d->pendingCursor = NULL; | 416 | d->pendingCursor = NULL; |
412 | d->isDrawFrozen = iTrue; | ||
413 | d->isExposed = iFalse; | 417 | d->isExposed = iFalse; |
414 | d->isMinimized = iFalse; | 418 | d->isMinimized = iFalse; |
415 | d->isInvalidated = iFalse; /* set when posting event, to avoid repeated events */ | 419 | d->isInvalidated = iFalse; /* set when posting event, to avoid repeated events */ |
@@ -441,9 +445,27 @@ void init_Window(iWindow *d, enum iWindowType type, iRect rect, uint32_t flags) | |||
441 | d->uiScale = initialUiScale_; | 445 | d->uiScale = initialUiScale_; |
442 | /* TODO: Ratios, scales, and metrics must be window-specific, not global. */ | 446 | /* TODO: Ratios, scales, and metrics must be window-specific, not global. */ |
443 | setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale); | 447 | setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale); |
448 | d->text = new_Text(d->render); | ||
449 | } | ||
450 | |||
451 | static void deinitRoots_Window_(iWindow *d) { | ||
452 | iRecycle(); | ||
453 | iForIndices(i, d->roots) { | ||
454 | if (d->roots[i]) { | ||
455 | setCurrent_Root(d->roots[i]); | ||
456 | delete_Root(d->roots[i]); | ||
457 | d->roots[i] = NULL; | ||
458 | } | ||
459 | } | ||
460 | setCurrent_Root(NULL); | ||
444 | } | 461 | } |
445 | 462 | ||
446 | void deinit_Window(iWindow *d) { | 463 | void deinit_Window(iWindow *d) { |
464 | if (d->type == popup_WindowType) { | ||
465 | removePopup_App(d); | ||
466 | } | ||
467 | deinitRoots_Window_(d); | ||
468 | delete_Text(d->text); | ||
447 | SDL_DestroyRenderer(d->render); | 469 | SDL_DestroyRenderer(d->render); |
448 | SDL_DestroyWindow(d->win); | 470 | SDL_DestroyWindow(d->win); |
449 | iForIndices(i, d->cursors) { | 471 | iForIndices(i, d->cursors) { |
@@ -455,6 +477,7 @@ void deinit_Window(iWindow *d) { | |||
455 | 477 | ||
456 | void init_MainWindow(iMainWindow *d, iRect rect) { | 478 | void init_MainWindow(iMainWindow *d, iRect rect) { |
457 | theWindow_ = &d->base; | 479 | theWindow_ = &d->base; |
480 | theMainWindow_ = d; | ||
458 | uint32_t flags = 0; | 481 | uint32_t flags = 0; |
459 | #if defined (iPlatformAppleDesktop) | 482 | #if defined (iPlatformAppleDesktop) |
460 | SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); | 483 | SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); |
@@ -465,13 +488,15 @@ void init_MainWindow(iMainWindow *d, iRect rect) { | |||
465 | #endif | 488 | #endif |
466 | SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); | 489 | SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); |
467 | init_Window(&d->base, main_WindowType, rect, flags); | 490 | init_Window(&d->base, main_WindowType, rect, flags); |
468 | d->splitMode = d->pendingSplitMode = 0; | 491 | d->isDrawFrozen = iTrue; |
469 | d->pendingSplitUrl = new_String(); | 492 | d->splitMode = 0; |
470 | d->place.initialPos = rect.pos; | 493 | d->pendingSplitMode = 0; |
471 | d->place.normalRect = rect; | 494 | d->pendingSplitUrl = new_String(); |
495 | d->place.initialPos = rect.pos; | ||
496 | d->place.normalRect = rect; | ||
472 | d->place.lastNotifiedSize = zero_I2(); | 497 | d->place.lastNotifiedSize = zero_I2(); |
473 | d->place.snap = 0; | 498 | d->place.snap = 0; |
474 | d->keyboardHeight = 0; | 499 | d->keyboardHeight = 0; |
475 | #if defined(iPlatformMobile) | 500 | #if defined(iPlatformMobile) |
476 | const iInt2 minSize = zero_I2(); /* windows aren't independently resizable */ | 501 | const iInt2 minSize = zero_I2(); /* windows aren't independently resizable */ |
477 | #else | 502 | #else |
@@ -510,9 +535,9 @@ void init_MainWindow(iMainWindow *d, iRect rect) { | |||
510 | } | 535 | } |
511 | #endif | 536 | #endif |
512 | #if defined (iPlatformAppleMobile) | 537 | #if defined (iPlatformAppleMobile) |
513 | setupWindow_iOS(d); | 538 | setupWindow_iOS(as_Window(d)); |
514 | #endif | 539 | #endif |
515 | init_Text(d->base.render); | 540 | setCurrent_Text(d->base.text); |
516 | SDL_GetRendererOutputSize(d->base.render, &d->base.size.x, &d->base.size.y); | 541 | SDL_GetRendererOutputSize(d->base.render, &d->base.size.x, &d->base.size.y); |
517 | setupUserInterface_MainWindow(d); | 542 | setupUserInterface_MainWindow(d); |
518 | postCommand_App("~bindings.changed"); /* update from bindings */ | 543 | postCommand_App("~bindings.changed"); /* update from bindings */ |
@@ -538,24 +563,15 @@ void init_MainWindow(iMainWindow *d, iRect rect) { | |||
538 | #endif | 563 | #endif |
539 | } | 564 | } |
540 | 565 | ||
541 | static void deinitRoots_Window_(iWindow *d) { | ||
542 | iRecycle(); | ||
543 | iForIndices(i, d->roots) { | ||
544 | if (d->roots[i]) { | ||
545 | setCurrent_Root(d->roots[i]); | ||
546 | deinit_Root(d->roots[i]); | ||
547 | } | ||
548 | } | ||
549 | setCurrent_Root(NULL); | ||
550 | } | ||
551 | |||
552 | void deinit_MainWindow(iMainWindow *d) { | 566 | void deinit_MainWindow(iMainWindow *d) { |
553 | deinitRoots_Window_(as_Window(d)); | 567 | deinitRoots_Window_(as_Window(d)); |
554 | if (theWindow_ == as_Window(d)) { | 568 | if (theWindow_ == as_Window(d)) { |
555 | theWindow_ = NULL; | 569 | theWindow_ = NULL; |
556 | } | 570 | } |
571 | if (theMainWindow_ == d) { | ||
572 | theMainWindow_ = NULL; | ||
573 | } | ||
557 | delete_String(d->pendingSplitUrl); | 574 | delete_String(d->pendingSplitUrl); |
558 | deinit_Text(); | ||
559 | deinit_Window(&d->base); | 575 | deinit_Window(&d->base); |
560 | } | 576 | } |
561 | 577 | ||
@@ -592,7 +608,7 @@ iRoot *otherRoot_Window(const iWindow *d, iRoot *root) { | |||
592 | static void invalidate_MainWindow_(iMainWindow *d, iBool forced) { | 608 | static void invalidate_MainWindow_(iMainWindow *d, iBool forced) { |
593 | if (d && (!d->base.isInvalidated || forced)) { | 609 | if (d && (!d->base.isInvalidated || forced)) { |
594 | d->base.isInvalidated = iTrue; | 610 | d->base.isInvalidated = iTrue; |
595 | resetFonts_Text(); | 611 | resetFonts_Text(text_Window(d)); |
596 | postCommand_App("theme.changed auto:1"); /* forces UI invalidation */ | 612 | postCommand_App("theme.changed auto:1"); /* forces UI invalidation */ |
597 | } | 613 | } |
598 | } | 614 | } |
@@ -607,7 +623,7 @@ void invalidate_Window(iAnyWindow *d) { | |||
607 | } | 623 | } |
608 | 624 | ||
609 | static iBool isNormalPlacement_MainWindow_(const iMainWindow *d) { | 625 | static iBool isNormalPlacement_MainWindow_(const iMainWindow *d) { |
610 | if (d->base.isDrawFrozen) return iFalse; | 626 | if (d->isDrawFrozen) return iFalse; |
611 | #if defined (iPlatformApple) | 627 | #if defined (iPlatformApple) |
612 | /* Maximized mode is not special on macOS. */ | 628 | /* Maximized mode is not special on macOS. */ |
613 | if (snap_MainWindow(d) == maximized_WindowSnap) { | 629 | if (snap_MainWindow(d) == maximized_WindowSnap) { |
@@ -655,7 +671,7 @@ static iBool unsnap_MainWindow_(iMainWindow *d, const iInt2 *newPos) { | |||
655 | static void notifyMetricsChange_Window_(const iWindow *d) { | 671 | static void notifyMetricsChange_Window_(const iWindow *d) { |
656 | /* Dynamic UI metrics change. Widgets need to update themselves. */ | 672 | /* Dynamic UI metrics change. Widgets need to update themselves. */ |
657 | setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale); | 673 | setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale); |
658 | resetFonts_Text(); | 674 | resetFonts_Text(d->text); |
659 | postCommand_App("metrics.changed"); | 675 | postCommand_App("metrics.changed"); |
660 | } | 676 | } |
661 | 677 | ||
@@ -676,6 +692,41 @@ static void checkPixelRatioChange_Window_(iWindow *d) { | |||
676 | } | 692 | } |
677 | } | 693 | } |
678 | 694 | ||
695 | static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { | ||
696 | if (ev->windowID != SDL_GetWindowID(d->win)) { | ||
697 | return iFalse; | ||
698 | } | ||
699 | switch (ev->event) { | ||
700 | case SDL_WINDOWEVENT_EXPOSED: | ||
701 | d->isExposed = iTrue; | ||
702 | postRefresh_App(); | ||
703 | return iTrue; | ||
704 | case SDL_WINDOWEVENT_RESTORED: | ||
705 | case SDL_WINDOWEVENT_SHOWN: | ||
706 | postRefresh_App(); | ||
707 | return iTrue; | ||
708 | case SDL_WINDOWEVENT_FOCUS_LOST: | ||
709 | /* Popup windows are currently only used for menus. */ | ||
710 | closeMenu_Widget(d->roots[0]->widget); | ||
711 | return iTrue; | ||
712 | case SDL_WINDOWEVENT_LEAVE: | ||
713 | unhover_Widget(); | ||
714 | d->isMouseInside = iFalse; | ||
715 | //postCommand_App("window.mouse.exited"); | ||
716 | // SDL_SetWindowInputFocus(mainWindow_App()->base.win); | ||
717 | printf("mouse leaves popup\n"); fflush(stdout); | ||
718 | //SDL_RaiseWindow(mainWindow_App()->base.win); | ||
719 | postRefresh_App(); | ||
720 | return iTrue; | ||
721 | case SDL_WINDOWEVENT_ENTER: | ||
722 | d->isMouseInside = iTrue; | ||
723 | //postCommand_App("window.mouse.entered"); | ||
724 | printf("mouse enters popup\n"); fflush(stdout); | ||
725 | return iTrue; | ||
726 | } | ||
727 | return iFalse; | ||
728 | } | ||
729 | |||
679 | static iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent *ev) { | 730 | static iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent *ev) { |
680 | switch (ev->event) { | 731 | switch (ev->event) { |
681 | #if defined(iPlatformDesktop) | 732 | #if defined(iPlatformDesktop) |
@@ -795,6 +846,7 @@ static iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent | |||
795 | return iTrue; | 846 | return iTrue; |
796 | case SDL_WINDOWEVENT_ENTER: | 847 | case SDL_WINDOWEVENT_ENTER: |
797 | d->base.isMouseInside = iTrue; | 848 | d->base.isMouseInside = iTrue; |
849 | SDL_SetWindowInputFocus(d->base.win); | ||
798 | postCommand_App("window.mouse.entered"); | 850 | postCommand_App("window.mouse.entered"); |
799 | return iTrue; | 851 | return iTrue; |
800 | case SDL_WINDOWEVENT_FOCUS_GAINED: | 852 | case SDL_WINDOWEVENT_FOCUS_GAINED: |
@@ -802,16 +854,16 @@ static iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent | |||
802 | setCapsLockDown_Keys(iFalse); | 854 | setCapsLockDown_Keys(iFalse); |
803 | postCommand_App("window.focus.gained"); | 855 | postCommand_App("window.focus.gained"); |
804 | d->base.isExposed = iTrue; | 856 | d->base.isExposed = iTrue; |
805 | #if !defined(iPlatformDesktop) | 857 | #if !defined (iPlatformDesktop) |
806 | /* Returned to foreground, may have lost buffered content. */ | 858 | /* Returned to foreground, may have lost buffered content. */ |
807 | invalidate_Window_(d, iTrue); | 859 | invalidate_MainWindow_(d, iTrue); |
808 | postCommand_App("window.unfreeze"); | 860 | postCommand_App("window.unfreeze"); |
809 | #endif | 861 | #endif |
810 | return iFalse; | 862 | return iFalse; |
811 | case SDL_WINDOWEVENT_FOCUS_LOST: | 863 | case SDL_WINDOWEVENT_FOCUS_LOST: |
812 | postCommand_App("window.focus.lost"); | 864 | postCommand_App("window.focus.lost"); |
813 | #if !defined(iPlatformDesktop) | 865 | #if !defined (iPlatformDesktop) |
814 | setFreezeDraw_Window(d, iTrue); | 866 | setFreezeDraw_MainWindow(d, iTrue); |
815 | #endif | 867 | #endif |
816 | return iFalse; | 868 | return iFalse; |
817 | case SDL_WINDOWEVENT_TAKE_FOCUS: | 869 | case SDL_WINDOWEVENT_TAKE_FOCUS: |
@@ -831,8 +883,8 @@ static void applyCursor_Window_(iWindow *d) { | |||
831 | } | 883 | } |
832 | } | 884 | } |
833 | 885 | ||
834 | iBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) { | 886 | iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { |
835 | iWindow *w = as_Window(d); | 887 | iMainWindow *mw = (type_Window(d) == main_WindowType ? as_MainWindow(d) : NULL); |
836 | switch (ev->type) { | 888 | switch (ev->type) { |
837 | #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) | 889 | #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) |
838 | case SDL_SYSWMEVENT: { | 890 | case SDL_SYSWMEVENT: { |
@@ -845,19 +897,26 @@ iBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) { | |||
845 | } | 897 | } |
846 | #endif | 898 | #endif |
847 | case SDL_WINDOWEVENT: { | 899 | case SDL_WINDOWEVENT: { |
848 | return handleWindowEvent_MainWindow_(d, &ev->window); | 900 | if (mw) { |
901 | return handleWindowEvent_MainWindow_(mw, &ev->window); | ||
902 | } | ||
903 | else { | ||
904 | return handleWindowEvent_Window_(d, &ev->window); | ||
905 | } | ||
849 | } | 906 | } |
850 | case SDL_RENDER_TARGETS_RESET: | 907 | case SDL_RENDER_TARGETS_RESET: |
851 | case SDL_RENDER_DEVICE_RESET: { | 908 | case SDL_RENDER_DEVICE_RESET: { |
852 | invalidate_MainWindow_(d, iTrue /* force full reset */); | 909 | if (mw) { |
910 | invalidate_MainWindow_(mw, iTrue /* force full reset */); | ||
911 | } | ||
853 | break; | 912 | break; |
854 | } | 913 | } |
855 | default: { | 914 | default: { |
856 | SDL_Event event = *ev; | 915 | SDL_Event event = *ev; |
857 | if (event.type == SDL_USEREVENT && isCommand_UserEvent(ev, "window.unfreeze")) { | 916 | if (event.type == SDL_USEREVENT && isCommand_UserEvent(ev, "window.unfreeze")) { |
858 | d->base.isDrawFrozen = iFalse; | 917 | mw->isDrawFrozen = iFalse; |
859 | if (SDL_GetWindowFlags(w->win) & SDL_WINDOW_HIDDEN) { | 918 | if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_HIDDEN) { |
860 | SDL_ShowWindow(w->win); | 919 | SDL_ShowWindow(d->win); |
861 | } | 920 | } |
862 | postRefresh_App(); | 921 | postRefresh_App(); |
863 | postCommand_App("media.player.update"); /* in case a player needs updating */ | 922 | postCommand_App("media.player.update"); /* in case a player needs updating */ |
@@ -866,35 +925,35 @@ iBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) { | |||
866 | if (processEvent_Touch(&event)) { | 925 | if (processEvent_Touch(&event)) { |
867 | return iTrue; | 926 | return iTrue; |
868 | } | 927 | } |
869 | if (event.type == SDL_KEYDOWN && SDL_GetTicks() - d->base.focusGainedAt < 10) { | 928 | if (event.type == SDL_KEYDOWN && SDL_GetTicks() - d->focusGainedAt < 10) { |
870 | /* Suspiciously close to when input focus was received. For example under openbox, | 929 | /* Suspiciously close to when input focus was received. For example under openbox, |
871 | closing xterm with Ctrl+D will cause the keydown event to "spill" over to us. | 930 | closing xterm with Ctrl+D will cause the keydown event to "spill" over to us. |
872 | As a workaround, ignore these events. */ | 931 | As a workaround, ignore these events. */ |
873 | return iTrue; /* won't go to bindings, either */ | 932 | return iTrue; /* won't go to bindings, either */ |
874 | } | 933 | } |
875 | if (event.type == SDL_MOUSEBUTTONDOWN && d->base.ignoreClick) { | 934 | if (event.type == SDL_MOUSEBUTTONDOWN && d->ignoreClick) { |
876 | d->base.ignoreClick = iFalse; | 935 | d->ignoreClick = iFalse; |
877 | return iTrue; | 936 | return iTrue; |
878 | } | 937 | } |
879 | /* Map mouse pointer coordinate to our coordinate system. */ | 938 | /* Map mouse pointer coordinate to our coordinate system. */ |
880 | if (event.type == SDL_MOUSEMOTION) { | 939 | if (event.type == SDL_MOUSEMOTION) { |
881 | setCursor_Window(w, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */ | 940 | setCursor_Window(d, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */ |
882 | const iInt2 pos = coord_Window(w, event.motion.x, event.motion.y); | 941 | const iInt2 pos = coord_Window(d, event.motion.x, event.motion.y); |
883 | event.motion.x = pos.x; | 942 | event.motion.x = pos.x; |
884 | event.motion.y = pos.y; | 943 | event.motion.y = pos.y; |
885 | } | 944 | } |
886 | else if (event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) { | 945 | else if (event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) { |
887 | const iInt2 pos = coord_Window(w, event.button.x, event.button.y); | 946 | const iInt2 pos = coord_Window(d, event.button.x, event.button.y); |
888 | event.button.x = pos.x; | 947 | event.button.x = pos.x; |
889 | event.button.y = pos.y; | 948 | event.button.y = pos.y; |
890 | if (event.type == SDL_MOUSEBUTTONDOWN) { | 949 | if (event.type == SDL_MOUSEBUTTONDOWN) { |
891 | /* Button clicks will change keyroot. */ | 950 | /* Button clicks will change keyroot. */ |
892 | if (numRoots_Window(w) > 1) { | 951 | if (numRoots_Window(d) > 1) { |
893 | const iInt2 click = init_I2(event.button.x, event.button.y); | 952 | const iInt2 click = init_I2(event.button.x, event.button.y); |
894 | iForIndices(i, w->roots) { | 953 | iForIndices(i, d->roots) { |
895 | iRoot *root = w->roots[i]; | 954 | iRoot *root = d->roots[i]; |
896 | if (root != w->keyRoot && contains_Rect(rect_Root(root), click)) { | 955 | if (root != d->keyRoot && contains_Rect(rect_Root(root), click)) { |
897 | setKeyRoot_Window(w, root); | 956 | setKeyRoot_Window(d, root); |
898 | break; | 957 | break; |
899 | } | 958 | } |
900 | } | 959 | } |
@@ -909,13 +968,13 @@ iBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) { | |||
909 | event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) { | 968 | event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) { |
910 | if (mouseGrab_Widget()) { | 969 | if (mouseGrab_Widget()) { |
911 | iWidget *grabbed = mouseGrab_Widget(); | 970 | iWidget *grabbed = mouseGrab_Widget(); |
912 | setCurrent_Root(findRoot_Window(w, grabbed)); | 971 | setCurrent_Root(findRoot_Window(d, grabbed)); |
913 | wasUsed = dispatchEvent_Widget(grabbed, &event); | 972 | wasUsed = dispatchEvent_Widget(grabbed, &event); |
914 | } | 973 | } |
915 | } | 974 | } |
916 | /* Dispatch the event to the tree of widgets. */ | 975 | /* Dispatch the event to the tree of widgets. */ |
917 | if (!wasUsed) { | 976 | if (!wasUsed) { |
918 | wasUsed = dispatchEvent_Window(w, &event); | 977 | wasUsed = dispatchEvent_Window(d, &event); |
919 | } | 978 | } |
920 | if (!wasUsed) { | 979 | if (!wasUsed) { |
921 | /* As a special case, clicking the middle mouse button can be used for pasting | 980 | /* As a special case, clicking the middle mouse button can be used for pasting |
@@ -928,35 +987,35 @@ iBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) { | |||
928 | paste.key.keysym.mod = KMOD_PRIMARY; | 987 | paste.key.keysym.mod = KMOD_PRIMARY; |
929 | paste.key.state = SDL_PRESSED; | 988 | paste.key.state = SDL_PRESSED; |
930 | paste.key.timestamp = SDL_GetTicks(); | 989 | paste.key.timestamp = SDL_GetTicks(); |
931 | wasUsed = dispatchEvent_Window(w, &paste); | 990 | wasUsed = dispatchEvent_Window(d, &paste); |
932 | } | 991 | } |
933 | if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_RIGHT) { | 992 | if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_RIGHT) { |
934 | if (postContextClick_Window(w, &event.button)) { | 993 | if (postContextClick_Window(d, &event.button)) { |
935 | wasUsed = iTrue; | 994 | wasUsed = iTrue; |
936 | } | 995 | } |
937 | } | 996 | } |
938 | } | 997 | } |
939 | if (isMetricsChange_UserEvent(&event)) { | 998 | if (isMetricsChange_UserEvent(&event)) { |
940 | iForIndices(i, w->roots) { | 999 | iForIndices(i, d->roots) { |
941 | updateMetrics_Root(w->roots[i]); | 1000 | updateMetrics_Root(d->roots[i]); |
942 | } | 1001 | } |
943 | } | 1002 | } |
944 | if (isCommand_UserEvent(&event, "lang.changed")) { | 1003 | if (isCommand_UserEvent(&event, "lang.changed") && mw) { |
945 | #if defined (iHaveNativeMenus) | 1004 | #if defined (iHaveNativeMenus) |
946 | /* Retranslate the menus. */ | 1005 | /* Retranslate the menus. */ |
947 | removeMacMenus_(); | 1006 | removeMacMenus_(); |
948 | insertMacMenus_(); | 1007 | insertMacMenus_(); |
949 | #endif | 1008 | #endif |
950 | invalidate_Window(w); | 1009 | invalidate_Window(d); |
951 | iForIndices(i, w->roots) { | 1010 | iForIndices(i, d->roots) { |
952 | if (w->roots[i]) { | 1011 | if (d->roots[i]) { |
953 | updatePreferencesLayout_Widget(findChild_Widget(w->roots[i]->widget, "prefs")); | 1012 | updatePreferencesLayout_Widget(findChild_Widget(d->roots[i]->widget, "prefs")); |
954 | arrange_Widget(w->roots[i]->widget); | 1013 | arrange_Widget(d->roots[i]->widget); |
955 | } | 1014 | } |
956 | } | 1015 | } |
957 | } | 1016 | } |
958 | if (event.type == SDL_MOUSEMOTION) { | 1017 | if (event.type == SDL_MOUSEMOTION) { |
959 | applyCursor_Window_(w); | 1018 | applyCursor_Window_(d); |
960 | } | 1019 | } |
961 | return wasUsed; | 1020 | return wasUsed; |
962 | } | 1021 | } |
@@ -1003,6 +1062,9 @@ iBool dispatchEvent_Window(iWindow *d, const SDL_Event *ev) { | |||
1003 | coord_MouseWheelEvent(&ev->wheel))) { | 1062 | coord_MouseWheelEvent(&ev->wheel))) { |
1004 | continue; /* Only process the event in the relevant split. */ | 1063 | continue; /* Only process the event in the relevant split. */ |
1005 | } | 1064 | } |
1065 | if (!root->widget) { | ||
1066 | continue; | ||
1067 | } | ||
1006 | setCurrent_Root(root); | 1068 | setCurrent_Root(root); |
1007 | const iBool wasUsed = dispatchEvent_Widget(root->widget, ev); | 1069 | const iBool wasUsed = dispatchEvent_Widget(root->widget, ev); |
1008 | if (wasUsed) { | 1070 | if (wasUsed) { |
@@ -1044,11 +1106,40 @@ iBool postContextClick_Window(iWindow *d, const SDL_MouseButtonEvent *ev) { | |||
1044 | return iFalse; | 1106 | return iFalse; |
1045 | } | 1107 | } |
1046 | 1108 | ||
1109 | void draw_Window(iWindow *d) { | ||
1110 | if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_HIDDEN) { | ||
1111 | return; | ||
1112 | } | ||
1113 | iPaint p; | ||
1114 | init_Paint(&p); | ||
1115 | iRoot *root = d->roots[0]; | ||
1116 | setCurrent_Root(root); | ||
1117 | unsetClip_Paint(&p); /* update clip to full window */ | ||
1118 | const iColor back = get_Color(uiBackground_ColorId); | ||
1119 | SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255); | ||
1120 | SDL_RenderClear(d->render); | ||
1121 | d->frameTime = SDL_GetTicks(); | ||
1122 | if (isExposed_Window(d)) { | ||
1123 | d->isInvalidated = iFalse; | ||
1124 | extern int drawCount_; | ||
1125 | drawRoot_Widget(root->widget); | ||
1126 | #if !defined (NDEBUG) | ||
1127 | draw_Text(defaultBold_FontId, safeRect_Root(root).pos, red_ColorId, "%d", drawCount_); | ||
1128 | drawCount_ = 0; | ||
1129 | #endif | ||
1130 | } | ||
1131 | // drawRectThickness_Paint(&p, (iRect){ zero_I2(), sub_I2(d->size, one_I2()) }, gap_UI / 4, uiSeparator_ColorId); | ||
1132 | setCurrent_Root(NULL); | ||
1133 | SDL_RenderPresent(d->render); | ||
1134 | } | ||
1135 | |||
1047 | void draw_MainWindow(iMainWindow *d) { | 1136 | void draw_MainWindow(iMainWindow *d) { |
1137 | /* TODO: Try to make this a specialization of `draw_Window`? */ | ||
1048 | iWindow *w = as_Window(d); | 1138 | iWindow *w = as_Window(d); |
1049 | if (w->isDrawFrozen) { | 1139 | if (d->isDrawFrozen) { |
1050 | return; | 1140 | return; |
1051 | } | 1141 | } |
1142 | setCurrent_Text(d->base.text); | ||
1052 | /* Check if root needs resizing. */ { | 1143 | /* Check if root needs resizing. */ { |
1053 | iInt2 renderSize; | 1144 | iInt2 renderSize; |
1054 | SDL_GetRendererOutputSize(w->render, &renderSize.x, &renderSize.y); | 1145 | SDL_GetRendererOutputSize(w->render, &renderSize.x, &renderSize.y); |
@@ -1180,7 +1271,7 @@ void setUiScale_Window(iWindow *d, float uiScale) { | |||
1180 | } | 1271 | } |
1181 | } | 1272 | } |
1182 | 1273 | ||
1183 | void setFreezeDraw_Window(iWindow *d, iBool freezeDraw) { | 1274 | void setFreezeDraw_MainWindow(iMainWindow *d, iBool freezeDraw) { |
1184 | d->isDrawFrozen = freezeDraw; | 1275 | d->isDrawFrozen = freezeDraw; |
1185 | } | 1276 | } |
1186 | 1277 | ||
@@ -1231,8 +1322,23 @@ iWindow *get_Window(void) { | |||
1231 | return theWindow_; | 1322 | return theWindow_; |
1232 | } | 1323 | } |
1233 | 1324 | ||
1325 | void setCurrent_Window(iAnyWindow *d) { | ||
1326 | theWindow_ = d; | ||
1327 | if (type_Window(d) == main_WindowType) { | ||
1328 | theMainWindow_ = d; | ||
1329 | } | ||
1330 | if (d) { | ||
1331 | setCurrent_Text(theWindow_->text); | ||
1332 | setCurrent_Root(theWindow_->keyRoot); | ||
1333 | } | ||
1334 | else { | ||
1335 | setCurrent_Text(NULL); | ||
1336 | setCurrent_Root(NULL); | ||
1337 | } | ||
1338 | } | ||
1339 | |||
1234 | iMainWindow *get_MainWindow(void) { | 1340 | iMainWindow *get_MainWindow(void) { |
1235 | return as_MainWindow(theWindow_); | 1341 | return theMainWindow_; |
1236 | } | 1342 | } |
1237 | 1343 | ||
1238 | iBool isOpenGLRenderer_Window(void) { | 1344 | iBool isOpenGLRenderer_Window(void) { |
@@ -1272,7 +1378,7 @@ void setSplitMode_MainWindow(iMainWindow *d, int splitFlags) { | |||
1272 | iAssert(current_Root() == NULL); | 1378 | iAssert(current_Root() == NULL); |
1273 | if (d->splitMode != splitMode) { | 1379 | if (d->splitMode != splitMode) { |
1274 | int oldCount = numRoots_Window(w); | 1380 | int oldCount = numRoots_Window(w); |
1275 | setFreezeDraw_Window(w, iTrue); | 1381 | setFreezeDraw_MainWindow(d, iTrue); |
1276 | if (oldCount == 2 && splitMode == 0) { | 1382 | if (oldCount == 2 && splitMode == 0) { |
1277 | /* Keep references to the tabs of the second root. */ | 1383 | /* Keep references to the tabs of the second root. */ |
1278 | const iDocumentWidget *curPage = document_Root(w->keyRoot); | 1384 | const iDocumentWidget *curPage = document_Root(w->keyRoot); |
@@ -1311,6 +1417,7 @@ void setSplitMode_MainWindow(iMainWindow *d, int splitFlags) { | |||
1311 | } | 1417 | } |
1312 | w->roots[newRootIndex] = new_Root(); | 1418 | w->roots[newRootIndex] = new_Root(); |
1313 | w->keyRoot = w->roots[newRootIndex]; | 1419 | w->keyRoot = w->roots[newRootIndex]; |
1420 | w->keyRoot->window = w; | ||
1314 | setCurrent_Root(w->roots[newRootIndex]); | 1421 | setCurrent_Root(w->roots[newRootIndex]); |
1315 | createUserInterface_Root(w->roots[newRootIndex]); | 1422 | createUserInterface_Root(w->roots[newRootIndex]); |
1316 | if (!isEmpty_String(d->pendingSplitUrl)) { | 1423 | if (!isEmpty_String(d->pendingSplitUrl)) { |
@@ -1471,3 +1578,25 @@ int snap_MainWindow(const iMainWindow *d) { | |||
1471 | } | 1578 | } |
1472 | return d->place.snap; | 1579 | return d->place.snap; |
1473 | } | 1580 | } |
1581 | |||
1582 | /*----------------------------------------------------------------------------------------------*/ | ||
1583 | |||
1584 | iWindow *newPopup_Window(iInt2 screenPos, iWidget *rootWidget) { | ||
1585 | arrange_Widget(rootWidget); | ||
1586 | iWindow *win = | ||
1587 | new_Window(popup_WindowType, | ||
1588 | (iRect){ screenPos, divf_I2(rootWidget->rect.size, get_Window()->pixelRatio) }, | ||
1589 | SDL_WINDOW_ALWAYS_ON_TOP | | ||
1590 | SDL_WINDOW_POPUP_MENU | | ||
1591 | SDL_WINDOW_SKIP_TASKBAR); | ||
1592 | #if defined (iPlatformAppleDesktop) | ||
1593 | hideTitleBar_MacOS(win); /* make it a borderless window */ | ||
1594 | #endif | ||
1595 | iRoot *root = new_Root(); | ||
1596 | win->roots[0] = root; | ||
1597 | win->keyRoot = root; | ||
1598 | root->widget = rootWidget; | ||
1599 | root->window = win; | ||
1600 | setRoot_Widget(rootWidget, root); | ||
1601 | return win; | ||
1602 | } | ||
diff --git a/src/ui/window.h b/src/ui/window.h index 73e92391..f1827931 100644 --- a/src/ui/window.h +++ b/src/ui/window.h | |||
@@ -29,8 +29,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
29 | #include <SDL_render.h> | 29 | #include <SDL_render.h> |
30 | #include <SDL_video.h> | 30 | #include <SDL_video.h> |
31 | 31 | ||
32 | enum iWindowType { | ||
33 | main_WindowType, | ||
34 | popup_WindowType, | ||
35 | }; | ||
36 | |||
32 | iDeclareType(MainWindow) | 37 | iDeclareType(MainWindow) |
38 | iDeclareType(Text) | ||
33 | iDeclareType(Window) | 39 | iDeclareType(Window) |
40 | |||
41 | iDeclareTypeConstructionArgs(Window, enum iWindowType type, iRect rect, uint32_t flags) | ||
34 | iDeclareTypeConstructionArgs(MainWindow, iRect rect) | 42 | iDeclareTypeConstructionArgs(MainWindow, iRect rect) |
35 | 43 | ||
36 | typedef iAny iAnyWindow; | 44 | typedef iAny iAnyWindow; |
@@ -71,15 +79,9 @@ enum iWindowSplit { | |||
71 | noEvents_WindowSplit = iBit(11), | 79 | noEvents_WindowSplit = iBit(11), |
72 | }; | 80 | }; |
73 | 81 | ||
74 | enum iWindowType { | ||
75 | main_WindowType, | ||
76 | popup_WindowType, | ||
77 | }; | ||
78 | |||
79 | struct Impl_Window { | 82 | struct Impl_Window { |
80 | enum iWindowType type; | 83 | enum iWindowType type; |
81 | SDL_Window * win; | 84 | SDL_Window * win; |
82 | iBool isDrawFrozen; /* avoids premature draws while restoring window state */ | ||
83 | iBool isExposed; | 85 | iBool isExposed; |
84 | iBool isMinimized; | 86 | iBool isMinimized; |
85 | iBool isMouseInside; | 87 | iBool isMouseInside; |
@@ -102,11 +104,13 @@ struct Impl_Window { | |||
102 | iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ | 104 | iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ |
103 | iRoot * keyRoot; /* root that has the current keyboard input focus */ | 105 | iRoot * keyRoot; /* root that has the current keyboard input focus */ |
104 | SDL_Texture * borderShadow; | 106 | SDL_Texture * borderShadow; |
107 | iText * text; | ||
105 | }; | 108 | }; |
106 | 109 | ||
107 | struct Impl_MainWindow { | 110 | struct Impl_MainWindow { |
108 | iWindow base; | 111 | iWindow base; |
109 | iWindowPlacement place; | 112 | iWindowPlacement place; |
113 | iBool isDrawFrozen; /* avoids premature draws while restoring window state */ | ||
110 | int splitMode; | 114 | int splitMode; |
111 | int pendingSplitMode; | 115 | int pendingSplitMode; |
112 | iString * pendingSplitUrl; /* URL to open in a newly opened split */ | 116 | iString * pendingSplitUrl; /* URL to open in a newly opened split */ |
@@ -115,7 +119,10 @@ struct Impl_MainWindow { | |||
115 | }; | 119 | }; |
116 | 120 | ||
117 | iLocalDef enum iWindowType type_Window(const iAnyWindow *d) { | 121 | iLocalDef enum iWindowType type_Window(const iAnyWindow *d) { |
118 | return ((const iWindow *) d)->type; | 122 | if (d) { |
123 | return ((const iWindow *) d)->type; | ||
124 | } | ||
125 | return main_WindowType; | ||
119 | } | 126 | } |
120 | 127 | ||
121 | uint32_t id_Window (const iWindow *); | 128 | uint32_t id_Window (const iWindow *); |
@@ -131,11 +138,11 @@ int numRoots_Window (const iWindow *); | |||
131 | iRoot * findRoot_Window (const iWindow *, const iWidget *widget); | 138 | iRoot * findRoot_Window (const iWindow *, const iWidget *widget); |
132 | iRoot * otherRoot_Window (const iWindow *, iRoot *root); | 139 | iRoot * otherRoot_Window (const iWindow *, iRoot *root); |
133 | 140 | ||
141 | iBool processEvent_Window (iWindow *, const SDL_Event *); | ||
134 | iBool dispatchEvent_Window (iWindow *, const SDL_Event *); | 142 | iBool dispatchEvent_Window (iWindow *, const SDL_Event *); |
135 | void invalidate_Window (iAnyWindow *); /* discard all cached graphics */ | 143 | void invalidate_Window (iAnyWindow *); /* discard all cached graphics */ |
136 | void draw_Window (iWindow *); | 144 | void draw_Window (iWindow *); |
137 | void setUiScale_Window (iWindow *, float uiScale); | 145 | void setUiScale_Window (iWindow *, float uiScale); |
138 | void setFreezeDraw_Window (iWindow *, iBool freezeDraw); | ||
139 | void setCursor_Window (iWindow *, int cursor); | 146 | void setCursor_Window (iWindow *, int cursor); |
140 | iBool setKeyRoot_Window (iWindow *, iRoot *root); | 147 | iBool setKeyRoot_Window (iWindow *, iRoot *root); |
141 | iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); | 148 | iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); |
@@ -143,6 +150,8 @@ iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); | |||
143 | iWindow * get_Window (void); | 150 | iWindow * get_Window (void); |
144 | iBool isOpenGLRenderer_Window (void); | 151 | iBool isOpenGLRenderer_Window (void); |
145 | 152 | ||
153 | void setCurrent_Window (iAnyWindow *); | ||
154 | |||
146 | iLocalDef iBool isExposed_Window(const iWindow *d) { | 155 | iLocalDef iBool isExposed_Window(const iWindow *d) { |
147 | iAssert(d); | 156 | iAssert(d); |
148 | return d->isExposed; | 157 | return d->isExposed; |
@@ -158,6 +167,10 @@ iLocalDef const iWindow *constAs_Window(const iAnyWindow *d) { | |||
158 | return (const iWindow *) d; | 167 | return (const iWindow *) d; |
159 | } | 168 | } |
160 | 169 | ||
170 | iLocalDef iText *text_Window(const iAnyWindow *d) { | ||
171 | return constAs_Window(d)->text; | ||
172 | } | ||
173 | |||
161 | /*----------------------------------------------------------------------------------------------*/ | 174 | /*----------------------------------------------------------------------------------------------*/ |
162 | 175 | ||
163 | iLocalDef iWindow *asWindow_MainWindow(iMainWindow *d) { | 176 | iLocalDef iWindow *asWindow_MainWindow(iMainWindow *d) { |
@@ -167,6 +180,7 @@ iLocalDef iWindow *asWindow_MainWindow(iMainWindow *d) { | |||
167 | 180 | ||
168 | void setTitle_MainWindow (iMainWindow *, const iString *title); | 181 | void setTitle_MainWindow (iMainWindow *, const iString *title); |
169 | void setSnap_MainWindow (iMainWindow *, int snapMode); | 182 | void setSnap_MainWindow (iMainWindow *, int snapMode); |
183 | void setFreezeDraw_MainWindow (iMainWindow *, iBool freezeDraw); | ||
170 | void setKeyboardHeight_MainWindow (iMainWindow *, int height); | 184 | void setKeyboardHeight_MainWindow (iMainWindow *, int height); |
171 | void setSplitMode_MainWindow (iMainWindow *, int splitMode); | 185 | void setSplitMode_MainWindow (iMainWindow *, int splitMode); |
172 | void checkPendingSplit_MainWindow (iMainWindow *); | 186 | void checkPendingSplit_MainWindow (iMainWindow *); |
@@ -196,3 +210,7 @@ iLocalDef const iMainWindow *constAs_MainWindow(const iAnyWindow *d) { | |||
196 | iAssert(type_Window(d) == main_WindowType); | 210 | iAssert(type_Window(d) == main_WindowType); |
197 | return (const iMainWindow *) d; | 211 | return (const iMainWindow *) d; |
198 | } | 212 | } |
213 | |||
214 | /*----------------------------------------------------------------------------------------------*/ | ||
215 | |||
216 | iWindow * newPopup_Window (iInt2 screenPos, iWidget *rootWidget); | ||