summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c86
-rw-r--r--src/ui/text.c70
-rw-r--r--src/ui/text.h28
-rw-r--r--src/ui/util.c158
-rw-r--r--src/ui/util.h1
-rw-r--r--src/ui/widget.c22
-rw-r--r--src/ui/widget.h79
7 files changed, 293 insertions, 151 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 70e66180..69dde8c7 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -60,8 +60,8 @@ struct Impl_MediaRequest {
60 60
61static void updated_MediaRequest_(iAnyObject *obj) { 61static void updated_MediaRequest_(iAnyObject *obj) {
62 iMediaRequest *d = obj; 62 iMediaRequest *d = obj;
63 postCommandf_App("media.updated link:%u request:%p", d->linkId, d); 63 postCommandf_App("media.updated link:%u request:%p", d->linkId, d);
64 } 64}
65 65
66static void finished_MediaRequest_(iAnyObject *obj) { 66static void finished_MediaRequest_(iAnyObject *obj) {
67 iMediaRequest *d = obj; 67 iMediaRequest *d = obj;
@@ -243,10 +243,11 @@ static void resetSmoothScroll_DocumentWidget_(iDocumentWidget *d) {
243} 243}
244 244
245static int documentWidth_DocumentWidget_(const iDocumentWidget *d) { 245static int documentWidth_DocumentWidget_(const iDocumentWidget *d) {
246 const iWidget *w = constAs_Widget(d); 246 const iWidget *w = constAs_Widget(d);
247 const iRect bounds = bounds_Widget(w); 247 const iRect bounds = bounds_Widget(w);
248 const iPrefs * prefs = prefs_App();
248 return iMini(bounds.size.x - gap_UI * d->pageMargin * 2, 249 return iMini(bounds.size.x - gap_UI * d->pageMargin * 2,
249 fontSize_UI * 40 * zoom_App() / 100); /* TODO: Add user preference .*/ 250 fontSize_UI * prefs->lineWidth * prefs->zoomPercent / 100);
250} 251}
251 252
252static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { 253static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) {
@@ -369,9 +370,9 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) {
369 if (d->hoverLink && 370 if (d->hoverLink &&
370 linkFlags_GmDocument(d->doc, d->hoverLink->linkId) & permanent_GmLinkFlag) { 371 linkFlags_GmDocument(d->doc, d->hoverLink->linkId) & permanent_GmLinkFlag) {
371 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); /* not dismissable */ 372 setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); /* not dismissable */
373 }
372 } 374 }
373} 375}
374}
375 376
376static void updateVisible_DocumentWidget_(iDocumentWidget *d) { 377static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
377 const iRangei visRange = visibleRange_DocumentWidget_(d); 378 const iRangei visRange = visibleRange_DocumentWidget_(d);
@@ -573,7 +574,9 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse
573 if (category_GmStatusCode(statusCode) != categoryInput_GmStatusCode) { 574 if (category_GmStatusCode(statusCode) != categoryInput_GmStatusCode) {
574 iString str; 575 iString str;
575 invalidate_DocumentWidget_(d); 576 invalidate_DocumentWidget_(d);
576 updateTheme_DocumentWidget_(d); 577 if (document_App() == d) {
578 updateTheme_DocumentWidget_(d);
579 }
577 clear_String(&d->sourceMime); 580 clear_String(&d->sourceMime);
578// set_Block(&d->sourceContent, &response->body); 581// set_Block(&d->sourceContent, &response->body);
579 initBlock_String(&str, &response->body); 582 initBlock_String(&str, &response->body);
@@ -1208,7 +1211,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1208 "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url)); 1211 "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url));
1209 iReleasePtr(&d->request); 1212 iReleasePtr(&d->request);
1210 if (d->state != ready_RequestState) { 1213 if (d->state != ready_RequestState) {
1211 d->state = ready_RequestState; 1214 d->state = ready_RequestState;
1212 postCommand_App("navigate.back"); 1215 postCommand_App("navigate.back");
1213 } 1216 }
1214 updateFetchProgress_DocumentWidget_(d); 1217 updateFetchProgress_DocumentWidget_(d);
@@ -1256,9 +1259,9 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1256 } 1259 }
1257 else if (startsWith_String(&d->sourceMime, "image/")) { 1260 else if (startsWith_String(&d->sourceMime, "image/")) {
1258 appendCStr_String(savePath, cstr_String(&d->sourceMime) + 6); 1261 appendCStr_String(savePath, cstr_String(&d->sourceMime) + 6);
1262 }
1263 }
1259 if (fileExists_FileInfo(savePath)) { 1264 if (fileExists_FileInfo(savePath)) {
1260 }
1261 }
1262 /* Make it unique. */ 1265 /* Make it unique. */
1263 iDate now; 1266 iDate now;
1264 initCurrent_Date(&now); 1267 initCurrent_Date(&now);
@@ -1550,38 +1553,39 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1550 iArray items; 1553 iArray items;
1551 init_Array(&items, sizeof(iMenuItem)); 1554 init_Array(&items, sizeof(iMenuItem));
1552 if (d->contextLink) { 1555 if (d->contextLink) {
1556 const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId);
1553 pushBackN_Array( 1557 pushBackN_Array(
1554 &items, 1558 &items,
1555 (iMenuItem[]){ { "Open Link in New Tab", 1559 (iMenuItem[]){
1560 { "Open Link in New Tab",
1556 0, 1561 0,
1557 0, 1562 0,
1558 format_CStr("!open newtab:1 url:%s", 1563 format_CStr("!open newtab:1 url:%s", cstr_String(linkUrl)) },
1559 cstr_String(linkUrl_GmDocument( 1564 { "Open Link in Background Tab",
1560 d->doc, d->contextLink->linkId))) },
1561 { "---", 0, 0, NULL },
1562 { "Copy Link",
1563 0, 1565 0,
1564 0, 1566 0,
1565 "document.copylink" }}, 1567 format_CStr("!open newtab:2 url:%s", cstr_String(linkUrl)) },
1566 3); 1568 { "---", 0, 0, NULL },
1569 { "Copy Link", 0, 0, "document.copylink" } },
1570 4);
1567 } 1571 }
1568 else { 1572 else {
1569 if (!isEmpty_Range(&d->selectMark)) { 1573 if (!isEmpty_Range(&d->selectMark)) {
1570 pushBackN_Array( 1574 pushBackN_Array(
1571 &items, 1575 &items,
1572 (iMenuItem[]){ { "Copy", 0, 0, "copy" }, { "---", 0, 0, NULL } }, 1576 (iMenuItem[]){ { "Copy", 0, 0, "copy" }, { "---", 0, 0, NULL } },
1573 2); 1577 2);
1574 } 1578 }
1575 pushBackN_Array( 1579 pushBackN_Array(
1576 &items, 1580 &items,
1577 (iMenuItem[]){ 1581 (iMenuItem[]){
1578 { "Go Back", navigateBack_KeyShortcut, "navigate.back" }, 1582 { "Go Back", navigateBack_KeyShortcut, "navigate.back" },
1579 { "Go Forward", navigateForward_KeyShortcut, "navigate.forward" }, 1583 { "Go Forward", navigateForward_KeyShortcut, "navigate.forward" },
1580 { "Reload Page", reload_KeyShortcut, "navigate.reload" }, 1584 { "Reload Page", reload_KeyShortcut, "navigate.reload" },
1581 { "---", 0, 0, NULL }, 1585 { "---", 0, 0, NULL },
1582 { "Copy Page URL", 0, 0, "document.copylink" }, 1586 { "Copy Page URL", 0, 0, "document.copylink" },
1583 { "---", 0, 0, NULL } }, 1587 { "---", 0, 0, NULL } },
1584 6); 1588 6);
1585 if (isEmpty_Range(&d->selectMark)) { 1589 if (isEmpty_Range(&d->selectMark)) {
1586 pushBackN_Array( 1590 pushBackN_Array(
1587 &items, 1591 &items,
@@ -1617,6 +1621,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1617 else if (loc) { 1621 else if (loc) {
1618 d->selectMark.end = loc; 1622 d->selectMark.end = loc;
1619 } 1623 }
1624// printf("mark %zu ... %zu\n", d->selectMark.start - cstr_String(source_GmDocument(d->doc)),
1625// d->selectMark.end - cstr_String(source_GmDocument(d->doc)));
1626// fflush(stdout);
1620 refresh_Widget(w); 1627 refresh_Widget(w);
1621 return iTrue; 1628 return iTrue;
1622 } 1629 }
@@ -1702,7 +1709,8 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol
1702 /* Selection may be done in either direction. */ 1709 /* Selection may be done in either direction. */
1703 iSwap(const char *, mark.start, mark.end); 1710 iSwap(const char *, mark.start, mark.end);
1704 } 1711 }
1705 if ((!*isInside && contains_Range(&run->text, mark.start)) || *isInside) { 1712 if ((!*isInside && (contains_Range(&run->text, mark.start) || mark.start == run->text.end)) ||
1713 *isInside) {
1706 int x = 0; 1714 int x = 0;
1707 if (!*isInside) { 1715 if (!*isInside) {
1708 x = advanceRange_Text(run->font, (iRangecc){ run->text.start, mark.start }).x; 1716 x = advanceRange_Text(run->font, (iRangecc){ run->text.start, mark.start }).x;
@@ -1873,23 +1881,23 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1873 (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) || 1881 (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) ||
1874 showHost)) { 1882 showHost)) {
1875 format_String(&str, 1883 format_String(&str,
1876 " \u2014%s%s%s\r%c%s", 1884 " \u2014%s%s%s\r%c%s",
1877 showHost ? " " : "", 1885 showHost ? " " : "",
1878 showHost ? (flags & mailto_GmLinkFlag 1886 showHost ? (flags & mailto_GmLinkFlag
1879 ? cstr_String(url) 1887 ? cstr_String(url)
1880 : ~flags & gemini_GmLinkFlag 1888 : ~flags & gemini_GmLinkFlag
1881 ? format_CStr("%s://%s", 1889 ? format_CStr("%s://%s",
1882 cstr_Rangecc(parts.scheme), 1890 cstr_Rangecc(parts.scheme),
1883 cstr_Rangecc(parts.host)) 1891 cstr_Rangecc(parts.host))
1884 : cstr_Rangecc(parts.host)) 1892 : cstr_Rangecc(parts.host))
1885 : "", 1893 : "",
1886 showHost && (showImage || showAudio) ? " \u2014" : "", 1894 showHost && (showImage || showAudio) ? " \u2014" : "",
1887 showImage || showAudio 1895 showImage || showAudio
1888 ? asciiBase_ColorEscape + fg 1896 ? asciiBase_ColorEscape + fg
1889 : (asciiBase_ColorEscape + 1897 : (asciiBase_ColorEscape +
1890 linkColor_GmDocument(doc, run->linkId, domain_GmLinkPart)), 1898 linkColor_GmDocument(doc, run->linkId, domain_GmLinkPart)),
1891 showImage ? " View Image \U0001f5bc" 1899 showImage ? " View Image \U0001f5bc"
1892 : showAudio ? " Play Audio \U0001f3b5" : ""); 1900 : showAudio ? " Play Audio \U0001f3b5" : "");
1893 } 1901 }
1894 if (run->flags & endOfLine_GmRunFlag && flags & visited_GmLinkFlag) { 1902 if (run->flags & endOfLine_GmRunFlag && flags & visited_GmLinkFlag) {
1895 iDate date; 1903 iDate date;
diff --git a/src/ui/text.c b/src/ui/text.c
index a48d0e0e..8d4661ac 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -167,33 +167,45 @@ static void initFonts_Text_(iText *d) {
167 { &fontSourceSansProRegular_Embedded, fontSize_UI, defaultSymbols_FontId }, 167 { &fontSourceSansProRegular_Embedded, fontSize_UI, defaultSymbols_FontId },
168 { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.125f, defaultMediumSymbols_FontId }, 168 { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.125f, defaultMediumSymbols_FontId },
169 { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.866f, defaultSymbols_FontId }, 169 { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.866f, defaultSymbols_FontId },
170 /* content fonts */
170 { &fontNunitoRegular_Embedded, textSize, symbols_FontId }, 171 { &fontNunitoRegular_Embedded, textSize, symbols_FontId },
171 { &fontFiraMonoRegular_Embedded, monoSize, smallSymbols_FontId }, 172 { &fontFiraMonoRegular_Embedded, monoSize, monospaceSymbols_FontId },
172 { &fontFiraMonoRegular_Embedded, monoSize * 0.750f, smallSymbols_FontId }, 173 { &fontFiraMonoRegular_Embedded, monoSize * 0.750f, monospaceSmallSymbols_FontId },
173 { &fontNunitoRegular_Embedded, textSize * 1.333f, mediumSymbols_FontId }, 174 { &fontNunitoRegular_Embedded, textSize * 1.200f, mediumSymbols_FontId },
175 { &fontNunitoRegular_Embedded, textSize * 1.333f, bigSymbols_FontId },
174 { &fontNunitoLightItalic_Embedded, textSize, symbols_FontId }, 176 { &fontNunitoLightItalic_Embedded, textSize, symbols_FontId },
175 { &fontNunitoExtraBold_Embedded, textSize, symbols_FontId }, 177 { &fontNunitoExtraBold_Embedded, textSize, symbols_FontId },
176 { &fontNunitoExtraBold_Embedded, textSize * 1.333f, mediumSymbols_FontId }, 178 { &fontNunitoExtraBold_Embedded, textSize * 1.333f, mediumSymbols_FontId },
177 { &fontNunitoExtraBold_Embedded, textSize * 1.666f, largeSymbols_FontId }, 179 { &fontNunitoExtraBold_Embedded, textSize * 1.666f, largeSymbols_FontId },
178 { &fontNunitoExtraBold_Embedded, textSize * 2.000f, hugeSymbols_FontId }, 180 { &fontNunitoExtraBold_Embedded, textSize * 2.000f, hugeSymbols_FontId },
179 { &fontNunitoExtraLight_Embedded, textSize * 1.666f, largeSymbols_FontId }, 181 { &fontNunitoExtraLight_Embedded, textSize * 1.666f, largeSymbols_FontId },
182 /* symbol fonts */
180 { &fontSymbola_Embedded, fontSize_UI, defaultSymbols_FontId }, 183 { &fontSymbola_Embedded, fontSize_UI, defaultSymbols_FontId },
181 { &fontSymbola_Embedded, fontSize_UI * 1.125f, defaultMediumSymbols_FontId }, 184 { &fontSymbola_Embedded, fontSize_UI * 1.125f, defaultMediumSymbols_FontId },
182 { &fontSymbola_Embedded, textSize, symbols_FontId }, 185 { &fontSymbola_Embedded, textSize, symbols_FontId },
183 { &fontSymbola_Embedded, textSize * 1.333f, mediumSymbols_FontId }, 186 { &fontSymbola_Embedded, textSize * 1.200f, mediumSymbols_FontId },
187 { &fontSymbola_Embedded, textSize * 1.333f, bigSymbols_FontId },
184 { &fontSymbola_Embedded, textSize * 1.666f, largeSymbols_FontId }, 188 { &fontSymbola_Embedded, textSize * 1.666f, largeSymbols_FontId },
185 { &fontSymbola_Embedded, textSize * 2.000f, hugeSymbols_FontId }, 189 { &fontSymbola_Embedded, textSize * 2.000f, hugeSymbols_FontId },
186 { &fontSymbola_Embedded, textSize * 0.866f, smallSymbols_FontId }, 190 { &fontSymbola_Embedded, monoSize, monospaceSymbols_FontId },
191 { &fontSymbola_Embedded, monoSize * 0.750f, monospaceSmallSymbols_FontId },
192 /* emoji fonts */
187 { &fontNotoEmojiRegular_Embedded, fontSize_UI, defaultSymbols_FontId }, 193 { &fontNotoEmojiRegular_Embedded, fontSize_UI, defaultSymbols_FontId },
188 { &fontNotoEmojiRegular_Embedded, fontSize_UI * 1.125f, defaultMediumSymbols_FontId }, 194 { &fontNotoEmojiRegular_Embedded, fontSize_UI * 1.125f, defaultMediumSymbols_FontId },
189 { &fontNotoEmojiRegular_Embedded, textSize, symbols_FontId }, 195 { &fontNotoEmojiRegular_Embedded, textSize, symbols_FontId },
190 { &fontNotoEmojiRegular_Embedded, textSize * 1.333f, mediumSymbols_FontId }, 196 { &fontNotoEmojiRegular_Embedded, textSize * 1.200f, mediumSymbols_FontId },
197 { &fontNotoEmojiRegular_Embedded, textSize * 1.333f, bigSymbols_FontId },
191 { &fontNotoEmojiRegular_Embedded, textSize * 1.666f, largeSymbols_FontId }, 198 { &fontNotoEmojiRegular_Embedded, textSize * 1.666f, largeSymbols_FontId },
192 { &fontNotoEmojiRegular_Embedded, textSize * 2.000f, hugeSymbols_FontId }, 199 { &fontNotoEmojiRegular_Embedded, textSize * 2.000f, hugeSymbols_FontId },
193 { &fontNotoEmojiRegular_Embedded, textSize * 0.866f, smallSymbols_FontId }, 200 { &fontNotoEmojiRegular_Embedded, monoSize, monospaceSymbols_FontId },
194 { &fontKosugiMaruRegular_Embedded, textSize * 0.666f, smallSymbols_FontId }, 201 { &fontNotoEmojiRegular_Embedded, monoSize * 0.750f, monospaceSmallSymbols_FontId },
202 /* japanese fonts */
203 { &fontKosugiMaruRegular_Embedded, fontSize_UI, defaultSymbols_FontId },
204 { &fontKosugiMaruRegular_Embedded, monoSize * 0.750, monospaceSmallSymbols_FontId },
205 { &fontKosugiMaruRegular_Embedded, monoSize, monospaceSymbols_FontId },
195 { &fontKosugiMaruRegular_Embedded, textSize, symbols_FontId }, 206 { &fontKosugiMaruRegular_Embedded, textSize, symbols_FontId },
196 { &fontKosugiMaruRegular_Embedded, textSize * 1.333f, mediumSymbols_FontId }, 207 { &fontKosugiMaruRegular_Embedded, textSize * 1.200f, mediumSymbols_FontId },
208 { &fontKosugiMaruRegular_Embedded, textSize * 1.333f, bigSymbols_FontId },
197 { &fontKosugiMaruRegular_Embedded, textSize * 1.666f, largeSymbols_FontId }, 209 { &fontKosugiMaruRegular_Embedded, textSize * 1.666f, largeSymbols_FontId },
198 { &fontKosugiMaruRegular_Embedded, textSize * 2.000f, hugeSymbols_FontId }, 210 { &fontKosugiMaruRegular_Embedded, textSize * 2.000f, hugeSymbols_FontId },
199 }; 211 };
@@ -211,13 +223,17 @@ static void initFonts_Text_(iText *d) {
211 /* Everything defaults to the regular sized japanese font, so these are just 223 /* Everything defaults to the regular sized japanese font, so these are just
212 the other sizes. */ 224 the other sizes. */
213 /* TODO: Add these to the table above... */ 225 /* TODO: Add these to the table above... */
214 font_Text_(monospace_FontId)->japaneseFont = smallJapanese_FontId; 226 font_Text_(default_FontId)->japaneseFont = defaultJapanese_FontId;
215 font_Text_(monospaceSmall_FontId)->japaneseFont = smallJapanese_FontId; 227 font_Text_(defaultMedium_FontId)->japaneseFont = defaultJapanese_FontId;
216 font_Text_(medium_FontId)->japaneseFont = mediumJapanese_FontId; 228 font_Text_(defaultMonospace_FontId)->japaneseFont = defaultJapanese_FontId;
217 font_Text_(mediumBold_FontId)->japaneseFont = mediumJapanese_FontId; 229 font_Text_(monospaceSmall_FontId)->japaneseFont = monospaceSmallJapanese_FontId;
218 font_Text_(largeBold_FontId)->japaneseFont = largeJapanese_FontId; 230 font_Text_(monospace_FontId)->japaneseFont = monospaceJapanese_FontId;
219 font_Text_(largeLight_FontId)->japaneseFont = largeJapanese_FontId; 231 font_Text_(medium_FontId)->japaneseFont = mediumJapanese_FontId;
220 font_Text_(hugeBold_FontId)->japaneseFont = hugeJapanese_FontId; 232 font_Text_(big_FontId)->japaneseFont = bigJapanese_FontId;
233 font_Text_(bigBold_FontId)->japaneseFont = bigJapanese_FontId;
234 font_Text_(largeBold_FontId)->japaneseFont = largeJapanese_FontId;
235 font_Text_(largeLight_FontId)->japaneseFont = largeJapanese_FontId;
236 font_Text_(hugeBold_FontId)->japaneseFont = hugeJapanese_FontId;
221 } 237 }
222 gap_Text = iRound(gap_UI * d->contentFontSize); 238 gap_Text = iRound(gap_UI * d->contentFontSize);
223} 239}
@@ -520,8 +536,8 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
520 } 536 }
521 } 537 }
522 iChar ch = nextChar_(&chPos, text.end); 538 iChar ch = nextChar_(&chPos, text.end);
523 if (ch == variationSelectorEmoji_Char) { 539 if (isVariationSelector_Char(ch)) {
524 /* TODO: Should peek ahead for this and prefer the Emoji font. */ 540 /* TODO: VS15: Should peek ahead for this and prefer the Emoji font. */
525 ch = nextChar_(&chPos, text.end); /* just ignore */ 541 ch = nextChar_(&chPos, text.end); /* just ignore */
526 } 542 }
527 /* Special instructions. */ { 543 /* Special instructions. */ {
@@ -555,10 +571,10 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
555 } 571 }
556 break; 572 break;
557 } 573 }
558 const SDL_Rect dst = { x1 + glyph->d[hoff].x, 574 SDL_Rect dst = { x1 + glyph->d[hoff].x,
559 pos.y + glyph->font->baseline + glyph->d[hoff].y, 575 pos.y + glyph->font->baseline + glyph->d[hoff].y,
560 glyph->rect[hoff].size.x, 576 glyph->rect[hoff].size.x,
561 glyph->rect[hoff].size.y }; 577 glyph->rect[hoff].size.y };
562 /* Update the bounding box. */ 578 /* Update the bounding box. */
563 if (mode == measureVisual_RunMode) { 579 if (mode == measureVisual_RunMode) {
564 if (isEmpty_Rect(bounds)) { 580 if (isEmpty_Rect(bounds)) {
@@ -572,13 +588,19 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
572 bounds.size.x = iMax(bounds.size.x, x2 - orig.x); 588 bounds.size.x = iMax(bounds.size.x, x2 - orig.x);
573 bounds.size.y = iMax(bounds.size.y, pos.y + glyph->font->height - orig.y); 589 bounds.size.y = iMax(bounds.size.y, pos.y + glyph->font->height - orig.y);
574 } 590 }
591 const iBool useMonoAdvance =
592 monoAdvance > 0 && !isJapanese_FontId(fontId_Text_(glyph->font));
593 const float advance = (useMonoAdvance ? monoAdvance : glyph->advance);
575 if (!isMeasuring_(mode)) { 594 if (!isMeasuring_(mode)) {
595 if (useMonoAdvance && dst.w > advance) {
596 dst.x -= (dst.w - advance) / 2;
597
598 }
576 SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect[hoff], &dst); 599 SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect[hoff], &dst);
577 } 600 }
578 /* Symbols and emojis are NOT monospaced, so must conform when the primary font 601 /* Symbols and emojis are NOT monospaced, so must conform when the primary font
579 is monospaced. Except with Japanese script, that's larger than the normal monospace. */ 602 is monospaced. Except with Japanese script, that's larger than the normal monospace. */
580 xpos += (monoAdvance > 0 && !isJapanese_FontId(fontId_Text_(glyph->font)) ? monoAdvance 603 xpos += advance;
581 : glyph->advance);
582 xposMax = iMax(xposMax, xpos); 604 xposMax = iMax(xposMax, xpos);
583 if (continueFrom_out && (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch))) { 605 if (continueFrom_out && (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch))) {
584 lastWordEnd = chPos; 606 lastWordEnd = chPos;
diff --git a/src/ui/text.h b/src/ui/text.h
index 9a22620f..7dc4aa38 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -27,17 +27,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27 27
28#include <SDL_render.h> 28#include <SDL_render.h>
29 29
30/* Size names: regular (1x) -> medium (1.2x) -> big (1.33x) -> large (1.67x) -> huge (2x) */
31
30enum iFontId { 32enum iFontId {
31 default_FontId, 33 default_FontId,
32 defaultMedium_FontId, 34 defaultMedium_FontId,
33 defaultMonospace_FontId, 35 defaultMonospace_FontId,
36 /* content fonts */
34 regular_FontId, 37 regular_FontId,
35 monospace_FontId, 38 monospace_FontId,
36 monospaceSmall_FontId, 39 monospaceSmall_FontId,
37 medium_FontId, 40 medium_FontId,
41 big_FontId,
38 italic_FontId, 42 italic_FontId,
39 bold_FontId, 43 bold_FontId,
40 mediumBold_FontId, 44 bigBold_FontId,
41 largeBold_FontId, 45 largeBold_FontId,
42 hugeBold_FontId, 46 hugeBold_FontId,
43 largeLight_FontId, 47 largeLight_FontId,
@@ -46,27 +50,34 @@ enum iFontId {
46 defaultMediumSymbols_FontId, 50 defaultMediumSymbols_FontId,
47 symbols_FontId, 51 symbols_FontId,
48 mediumSymbols_FontId, 52 mediumSymbols_FontId,
53 bigSymbols_FontId,
49 largeSymbols_FontId, 54 largeSymbols_FontId,
50 hugeSymbols_FontId, 55 hugeSymbols_FontId,
51 smallSymbols_FontId, 56 monospaceSymbols_FontId,
57 monospaceSmallSymbols_FontId,
52 /* emoji fonts */ 58 /* emoji fonts */
53 defaultEmoji_FontId, 59 defaultEmoji_FontId,
54 defaultMediumEmoji_FontId, 60 defaultMediumEmoji_FontId,
55 emoji_FontId, 61 emoji_FontId,
56 mediumEmoji_FontId, 62 mediumEmoji_FontId,
63 bigEmoji_FontId,
57 largeEmoji_FontId, 64 largeEmoji_FontId,
58 hugeEmoji_FontId, 65 hugeEmoji_FontId,
59 smallEmoji_FontId, 66 monospaceEmoji_FontId,
67 monospaceSmallEmoji_FontId,
60 /* japanese script */ 68 /* japanese script */
61 smallJapanese_FontId, 69 defaultJapanese_FontId,
70 monospaceSmallJapanese_FontId,
71 monospaceJapanese_FontId,
62 regularJapanese_FontId, 72 regularJapanese_FontId,
63 mediumJapanese_FontId, 73 mediumJapanese_FontId,
74 bigJapanese_FontId,
64 largeJapanese_FontId, 75 largeJapanese_FontId,
65 hugeJapanese_FontId, 76 hugeJapanese_FontId,
66 max_FontId, 77 max_FontId,
67 78
68 /* Meta: */ 79 /* Meta: */
69 fromSymbolsToEmojiOffset_FontId = 7, 80 fromSymbolsToEmojiOffset_FontId = 9,
70 81
71 /* UI fonts: */ 82 /* UI fonts: */
72 uiLabel_FontId = default_FontId, 83 uiLabel_FontId = default_FontId,
@@ -81,12 +92,15 @@ enum iFontId {
81 quote_FontId = italic_FontId, 92 quote_FontId = italic_FontId,
82 heading1_FontId = hugeBold_FontId, 93 heading1_FontId = hugeBold_FontId,
83 heading2_FontId = largeBold_FontId, 94 heading2_FontId = largeBold_FontId,
84 heading3_FontId = medium_FontId, 95 heading3_FontId = big_FontId,
85 banner_FontId = largeLight_FontId, 96 banner_FontId = largeLight_FontId,
86}; 97};
87 98
88iLocalDef iBool isJapanese_FontId(enum iFontId id) { 99iLocalDef iBool isJapanese_FontId(enum iFontId id) {
89 return id >= smallJapanese_FontId && id <= hugeJapanese_FontId; 100 return id >= defaultJapanese_FontId && id <= hugeJapanese_FontId;
101}
102iLocalDef iBool isVariationSelector_Char(iChar ch) {
103 return ch >= 0xfe00 && ch <= 0xfe0f;
90} 104}
91 105
92#define variationSelectorEmoji_Char ((iChar) 0xfe0f) 106#define variationSelectorEmoji_Char ((iChar) 0xfe0f)
diff --git a/src/ui/util.c b/src/ui/util.c
index ff6f8822..c341a11d 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -471,6 +471,19 @@ iWidget *removeTabPage_Widget(iWidget *tabs, size_t index) {
471 return page; 471 return page;
472} 472}
473 473
474void resizeToLargestPage_Widget(iWidget *tabs) {
475 arrange_Widget(tabs);
476 iInt2 largest = zero_I2();
477 iWidget *pages = findChild_Widget(tabs, "tabs.pages");
478 iConstForEach(ObjectList, i, children_Widget(pages)) {
479 largest = max_I2(largest, ((const iWidget *) i.object)->rect.size);
480 }
481 iForEach(ObjectList, j, children_Widget(pages)) {
482 setSize_Widget(j.object, largest);
483 }
484 setSize_Widget(tabs, addY_I2(largest, height_Widget(findChild_Widget(tabs, "tabs.buttons"))));
485}
486
474iLabelWidget *tabButtonForPage_Widget_(iWidget *tabs, const iWidget *page) { 487iLabelWidget *tabButtonForPage_Widget_(iWidget *tabs, const iWidget *page) {
475 iWidget *buttons = findChild_Widget(tabs, "tabs.buttons"); 488 iWidget *buttons = findChild_Widget(tabs, "tabs.buttons");
476 iForEach(ObjectList, i, buttons->children) { 489 iForEach(ObjectList, i, buttons->children) {
@@ -591,18 +604,18 @@ iWidget *makeSheet_Widget(const char *id) {
591 setBackgroundColor_Widget(sheet, uiBackground_ColorId); 604 setBackgroundColor_Widget(sheet, uiBackground_ColorId);
592 setFlags_Widget(sheet, 605 setFlags_Widget(sheet,
593 mouseModal_WidgetFlag | keepOnTop_WidgetFlag | arrangeVertical_WidgetFlag | 606 mouseModal_WidgetFlag | keepOnTop_WidgetFlag | arrangeVertical_WidgetFlag |
594 arrangeSize_WidgetFlag, 607 arrangeSize_WidgetFlag | centerHorizontal_WidgetFlag,
595 iTrue); 608 iTrue);
596 return sheet; 609 return sheet;
597} 610}
598 611
599void centerSheet_Widget(iWidget *sheet) { 612void centerSheet_Widget(iWidget *sheet) {
600 arrange_Widget(sheet); 613 arrange_Widget(sheet->parent);
601 const iInt2 rootSize = rootSize_Window(get_Window()); 614// const iInt2 rootSize = rootSize_Window(get_Window());
602 const iInt2 orig = localCoord_Widget( 615// const iInt2 orig = localCoord_Widget(
603 sheet->parent, 616// sheet->parent,
604 init_I2(rootSize.x / 2 - sheet->rect.size.x / 2, bounds_Widget(sheet).pos.y)); 617// init_I2(rootSize.x / 2 - sheet->rect.size.x / 2, bounds_Widget(sheet).pos.y));
605 sheet->rect.pos = orig; 618// sheet->rect.pos = orig;
606 postRefresh_App(); 619 postRefresh_App();
607} 620}
608 621
@@ -803,49 +816,110 @@ iWidget *makeToggle_Widget(const char *id) {
803 return toggle; 816 return toggle;
804} 817}
805 818
819static iWidget *appendTwoColumnPage_(iWidget *tabs, const char *title, iWidget **headings,
820 iWidget **values) {
821 iWidget *page = new_Widget();
822 setFlags_Widget(page, arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag |
823 resizeHeightOfChildren_WidgetFlag, iTrue);
824 addChildFlags_Widget(page, iClob(new_Widget()), expand_WidgetFlag);
825 iWidget *columns = new_Widget();
826 addChildFlags_Widget(page, iClob(columns), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
827 *headings = addChildFlags_Widget(
828 columns, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
829 *values = addChildFlags_Widget(
830 columns, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
831 addChildFlags_Widget(page, iClob(new_Widget()), expand_WidgetFlag);
832 appendTabPage_Widget(tabs, page, title, 0, 0);
833 return page;
834}
835
836static void makeTwoColumnHeading_(const char *title, iWidget *headings, iWidget *values) {
837 addChild_Widget(headings,
838 iClob(makeHeading_Widget(format_CStr(uiHeading_ColorEscape "%s", title))));
839 addChild_Widget(values, iClob(makeHeading_Widget("")));
840}
841
842static void expandInputFieldWidth_(iInputWidget *input) {
843 iWidget *page = as_Widget(input)->parent->parent->parent->parent; /* tabs > page > values > input */
844 as_Widget(input)->rect.size.x =
845 right_Rect(bounds_Widget(page)) - left_Rect(bounds_Widget(constAs_Widget(input)));
846}
847
806iWidget *makePreferences_Widget(void) { 848iWidget *makePreferences_Widget(void) {
807 iWidget *dlg = makeSheet_Widget("prefs"); 849 iWidget *dlg = makeSheet_Widget("prefs");
808 addChildFlags_Widget(dlg, 850 addChildFlags_Widget(dlg,
809 iClob(new_LabelWidget(uiHeading_ColorEscape "PREFERENCES", 0, 0, NULL)), 851 iClob(new_LabelWidget(uiHeading_ColorEscape "PREFERENCES", 0, 0, NULL)),
810 frameless_WidgetFlag); 852 frameless_WidgetFlag);
811 iWidget *page = new_Widget(); 853 iWidget *tabs = makeTabs_Widget(dlg);
812 addChild_Widget(dlg, iClob(page)); 854 iWidget *headings, *values;
813 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); 855 /* General preferences. */ {
814 iWidget *headings = addChildFlags_Widget( 856 appendTwoColumnPage_(tabs, "General", &headings, &values);
815 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 857 addChild_Widget(headings, iClob(makeHeading_Widget("Downloads folder:")));
816 iWidget *values = addChildFlags_Widget( 858 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.downloads");
817 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 859 makeTwoColumnHeading_("WINDOW", headings, values);
818 addChild_Widget(headings, iClob(makeHeading_Widget("Downloads folder:")));
819 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.downloads");
820#if defined (iPlatformApple) || defined (iPlatformMSys) 860#if defined (iPlatformApple) || defined (iPlatformMSys)
821 addChild_Widget(headings, iClob(makeHeading_Widget("Use system theme:"))); 861 addChild_Widget(headings, iClob(makeHeading_Widget("Use system theme:")));
822 addChild_Widget(values, iClob(makeToggle_Widget("prefs.ostheme"))); 862 addChild_Widget(values, iClob(makeToggle_Widget("prefs.ostheme")));
823#endif 863#endif
824 addChild_Widget(headings, iClob(makeHeading_Widget("Theme:"))); 864 addChild_Widget(headings, iClob(makeHeading_Widget("Theme:")));
825 iWidget *themes = new_Widget(); 865 iWidget *themes = new_Widget();
826 /* Themes. */ { 866 /* Themes. */ {
827 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Pure Black", 0, 0, "theme.set arg:0"))), "prefs.theme.0"); 867 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Pure Black", 0, 0, "theme.set arg:0"))), "prefs.theme.0");
828 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Dark", 0, 0, "theme.set arg:1"))), "prefs.theme.1"); 868 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Dark", 0, 0, "theme.set arg:1"))), "prefs.theme.1");
829 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Light", 0, 0, "theme.set arg:2"))), "prefs.theme.2"); 869 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Light", 0, 0, "theme.set arg:2"))), "prefs.theme.2");
830 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Pure White", 0, 0, "theme.set arg:3"))), "prefs.theme.3"); 870 setId_Widget(addChild_Widget(themes, iClob(new_LabelWidget("Pure White", 0, 0, "theme.set arg:3"))), "prefs.theme.3");
831 } 871 }
832 addChildFlags_Widget(values, iClob(themes), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); 872 addChildFlags_Widget(values, iClob(themes), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
833 addChild_Widget(headings, iClob(makeHeading_Widget("Retain window size:"))); 873 addChild_Widget(headings, iClob(makeHeading_Widget("Retain window size:")));
834 addChild_Widget(values, iClob(makeToggle_Widget("prefs.retainwindow"))); 874 addChild_Widget(values, iClob(makeToggle_Widget("prefs.retainwindow")));
835 addChild_Widget(headings, iClob(makeHeading_Widget("UI scale factor:"))); 875 addChild_Widget(headings, iClob(makeHeading_Widget("UI scale factor:")));
836 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(8))), "prefs.uiscale"); 876 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(8))), "prefs.uiscale");
837 addChild_Widget(headings, iClob(makeHeading_Widget(uiHeading_ColorEscape "Proxies"))); 877 }
838 addChild_Widget(values, iClob(makeHeading_Widget(""))); 878 /* Layout. */ {
839 addChild_Widget(headings, iClob(makeHeading_Widget("Gopher proxy:"))); 879 appendTwoColumnPage_(tabs, "Layout", &headings, &values);
840 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gopher"); 880 addChild_Widget(headings, iClob(makeHeading_Widget("Line width:")));
841 addChild_Widget(headings, iClob(makeHeading_Widget("HTTP proxy:"))); 881 iWidget *widths = new_Widget();
842 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.http"); 882 /* Line widths. */ {
883 addChild_Widget(widths, iClob(new_LabelWidget("\u20132", 0, 0, "linewidth.set arg:-2")));
884 addChild_Widget(widths, iClob(new_LabelWidget("\u20131", 0, 0, "linewidth.set arg:-1")));
885 addChild_Widget(widths, iClob(new_LabelWidget("Normal", 0, 0, "linewidth.set arg:0")));
886 addChild_Widget(widths, iClob(new_LabelWidget("+1", 0, 0, "linewidth.set arg:1")));
887 addChild_Widget(widths, iClob(new_LabelWidget("+2", 0, 0, "linewidth.set arg:2")));
888 addChild_Widget(widths, iClob(new_LabelWidget("Window", 0, 0, "linewidth.set arg:1000")));
889 }
890 addChildFlags_Widget(values, iClob(widths), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
891 addChild_Widget(headings, iClob(makeHeading_Widget("Big 1st paragaph:")));
892 addChild_Widget(values, iClob(makeToggle_Widget("prefs.biglede")));
893 }
894 /* Colors. */ {
895 appendTwoColumnPage_(tabs, "Colors", &headings, &values);
896 addChild_Widget(headings, iClob(makeHeading_Widget("Dark theme:")));
897 addChild_Widget(values, iClob(new_LabelWidget("Colorful", 0, 0, 0)));
898 addChild_Widget(headings, iClob(makeHeading_Widget("Light theme:")));
899 addChild_Widget(values, iClob(new_LabelWidget("White", 0, 0, 0)));
900 addChild_Widget(headings, iClob(makeHeading_Widget("Saturation:")));
901 iWidget *sats = new_Widget();
902 /* Saturation levels. */ {
903 addChild_Widget(sats, iClob(new_LabelWidget("Full", 0, 0, "saturation.set arg:100")));
904 addChild_Widget(sats, iClob(new_LabelWidget("Reduced", 0, 0, "saturation.set arg:66")));
905 addChild_Widget(sats, iClob(new_LabelWidget("Minimal", 0, 0, "saturation.set arg:33")));
906 addChild_Widget(sats, iClob(new_LabelWidget("Monochrome", 0, 0, "saturation.set arg:0")));
907 }
908 addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
909 }
910 /* Proxies. */ {
911 appendTwoColumnPage_(tabs, "Proxies", &headings, &values);
912 addChild_Widget(headings, iClob(makeHeading_Widget("Gopher proxy:")));
913 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gopher");
914 addChild_Widget(headings, iClob(makeHeading_Widget("HTTP proxy:")));
915 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.http");
916 }
917 resizeToLargestPage_Widget(tabs);
843 arrange_Widget(dlg); 918 arrange_Widget(dlg);
844 /* Set text input widths. */ { 919 /* Set input field sizes. */ {
845 const int inputWidth = width_Rect(page->rect) - width_Rect(headings->rect); 920 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.downloads"));
846 as_Widget(findChild_Widget(values, "prefs.downloads"))->rect.size.x = inputWidth; 921 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.http"));
847 as_Widget(findChild_Widget(values, "prefs.proxy.http"))->rect.size.x = inputWidth; 922 expandInputFieldWidth_(findChild_Widget(tabs, "prefs.proxy.gopher"));
848 as_Widget(findChild_Widget(values, "prefs.proxy.gopher"))->rect.size.x = inputWidth;
849 } 923 }
850 iWidget *div = new_Widget(); { 924 iWidget *div = new_Widget(); {
851 setFlags_Widget(div, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); 925 setFlags_Widget(div, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
diff --git a/src/ui/util.h b/src/ui/util.h
index 5590d008..754310ad 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -136,6 +136,7 @@ iWidget * makeTabs_Widget (iWidget *parent);
136void appendTabPage_Widget (iWidget *tabs, iWidget *page, const char *label, int key, int kmods); 136void appendTabPage_Widget (iWidget *tabs, iWidget *page, const char *label, int key, int kmods);
137void prependTabPage_Widget (iWidget *tabs, iWidget *page, const char *label, int key, int kmods); 137void prependTabPage_Widget (iWidget *tabs, iWidget *page, const char *label, int key, int kmods);
138iWidget * removeTabPage_Widget (iWidget *tabs, size_t index); /* returns the page */ 138iWidget * removeTabPage_Widget (iWidget *tabs, size_t index); /* returns the page */
139void resizeToLargestPage_Widget (iWidget *tabs);
139void showTabPage_Widget (iWidget *tabs, const iWidget *page); 140void showTabPage_Widget (iWidget *tabs, const iWidget *page);
140void setTabPageLabel_Widget (iWidget *tabs, const iAnyObject *page, const iString *label); 141void setTabPageLabel_Widget (iWidget *tabs, const iAnyObject *page, const iString *label);
141iWidget * tabPage_Widget (iWidget *tabs, size_t index); 142iWidget * tabPage_Widget (iWidget *tabs, size_t index);
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 05bb62cc..d218d7ee 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -119,11 +119,11 @@ const iString *id_Widget(const iWidget *d) {
119 return &d->id; 119 return &d->id;
120} 120}
121 121
122int flags_Widget(const iWidget *d) { 122int64_t flags_Widget(const iWidget *d) {
123 return d->flags; 123 return d->flags;
124} 124}
125 125
126void setFlags_Widget(iWidget *d, int flags, iBool set) { 126void setFlags_Widget(iWidget *d, int64_t flags, iBool set) {
127 iChangeFlags(d->flags, flags, set); 127 iChangeFlags(d->flags, flags, set);
128 if (flags & keepOnTop_WidgetFlag) { 128 if (flags & keepOnTop_WidgetFlag) {
129 if (set) { 129 if (set) {
@@ -228,6 +228,13 @@ static size_t numArrangedChildren_Widget_(const iWidget *d) {
228 return count; 228 return count;
229} 229}
230 230
231static void centerHorizontal_Widget_(iWidget *d) {
232 d->rect.pos.x = ((d->parent ? width_Rect(innerRect_Widget_(d->parent))
233 : rootSize_Window(get_Window()).x) -
234 width_Rect(d->rect)) /
235 2;
236}
237
231void arrange_Widget(iWidget *d) { 238void arrange_Widget(iWidget *d) {
232 if (isCollapsed_Widget_(d)) { 239 if (isCollapsed_Widget_(d)) {
233 setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue); 240 setFlags_Widget(d, wasCollapsed_WidgetFlag, iTrue);
@@ -236,6 +243,9 @@ void arrange_Widget(iWidget *d) {
236 if (d->flags & moveToParentRightEdge_WidgetFlag) { 243 if (d->flags & moveToParentRightEdge_WidgetFlag) {
237 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); 244 d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect);
238 } 245 }
246 if (d->flags & centerHorizontal_WidgetFlag) {
247 centerHorizontal_Widget_(d);
248 }
239 if (d->flags & resizeToParentWidth_WidgetFlag) { 249 if (d->flags & resizeToParentWidth_WidgetFlag) {
240 setWidth_Widget_(d, width_Rect(innerRect_Widget_(d->parent))); 250 setWidth_Widget_(d, width_Rect(innerRect_Widget_(d->parent)));
241 } 251 }
@@ -351,6 +361,9 @@ void arrange_Widget(iWidget *d) {
351 if (child->flags & fixedPosition_WidgetFlag) { 361 if (child->flags & fixedPosition_WidgetFlag) {
352 continue; 362 continue;
353 } 363 }
364 if (child->flags & centerHorizontal_WidgetFlag) {
365 continue;
366 }
354 if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) { 367 if (d->flags & (arrangeHorizontal_WidgetFlag | arrangeVertical_WidgetFlag)) {
355 if (child->flags & moveToParentRightEdge_WidgetFlag) { 368 if (child->flags & moveToParentRightEdge_WidgetFlag) {
356 continue; /* Not part of the sequential arrangement .*/ 369 continue; /* Not part of the sequential arrangement .*/
@@ -401,6 +414,9 @@ void arrange_Widget(iWidget *d) {
401 } 414 }
402 } 415 }
403 } 416 }
417 if (d->flags & centerHorizontal_WidgetFlag) {
418 centerHorizontal_Widget_(d);
419 }
404 } 420 }
405} 421}
406 422
@@ -616,7 +632,7 @@ iAny *addChildPos_Widget(iWidget *d, iAnyObject *child, enum iWidgetAddPos addPo
616 return child; 632 return child;
617} 633}
618 634
619iAny *addChildFlags_Widget(iWidget *d, iAnyObject *child, int childFlags) { 635iAny *addChildFlags_Widget(iWidget *d, iAnyObject *child, int64_t childFlags) {
620 setFlags_Widget(child, childFlags, iTrue); 636 setFlags_Widget(child, childFlags, iTrue);
621 return addChild_Widget(d, child); 637 return addChild_Widget(d, child);
622} 638}
diff --git a/src/ui/widget.h b/src/ui/widget.h
index fa4fbe0f..a2be30e9 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -44,44 +44,47 @@ iBeginDeclareClass(Widget)
44iEndDeclareClass(Widget) 44iEndDeclareClass(Widget)
45 45
46enum iWidgetFlag { 46enum iWidgetFlag {
47 hidden_WidgetFlag = iBit(1), 47 hidden_WidgetFlag = iBit(1),
48 disabled_WidgetFlag = iBit(2), 48 disabled_WidgetFlag = iBit(2),
49 hover_WidgetFlag = iBit(3), /* eligible for mouse hover */ 49 hover_WidgetFlag = iBit(3), /* eligible for mouse hover */
50 selected_WidgetFlag = iBit(4), 50 selected_WidgetFlag = iBit(4),
51 pressed_WidgetFlag = iBit(5), 51 pressed_WidgetFlag = iBit(5),
52 alignLeft_WidgetFlag = iBit(6), 52 alignLeft_WidgetFlag = iBit(6),
53 alignRight_WidgetFlag = iBit(7), 53 alignRight_WidgetFlag = iBit(7),
54 frameless_WidgetFlag = iBit(8), 54 frameless_WidgetFlag = iBit(8),
55 commandOnClick_WidgetFlag = iBit(9), 55 commandOnClick_WidgetFlag = iBit(9),
56 drawKey_WidgetFlag = iBit(10), 56 commandOnMouseMiss_WidgetFlag = iBit(10),
57 focusable_WidgetFlag = iBit(11), 57 drawKey_WidgetFlag = iBit(11),
58 tight_WidgetFlag = iBit(12), /* smaller padding */ 58 focusable_WidgetFlag = iBit(12),
59 keepOnTop_WidgetFlag = iBit(13), /* gets events first; drawn last */ 59 tight_WidgetFlag = iBit(13), /* smaller padding */
60 mouseModal_WidgetFlag = iBit(14), /* eats all unprocessed mouse events */ 60 keepOnTop_WidgetFlag = iBit(14), /* gets events first; drawn last */
61 commandOnMouseMiss_WidgetFlag = iBit(15), 61 mouseModal_WidgetFlag = iBit(15), /* eats all unprocessed mouse events */
62 /* arrange behavior */ 62 /* arrangement */
63 fixedPosition_WidgetFlag = iBit(16), 63 fixedPosition_WidgetFlag = iBit(17),
64 arrangeHorizontal_WidgetFlag = iBit(17), /* arrange children horizontally */ 64 arrangeHorizontal_WidgetFlag = iBit(18), /* arrange children horizontally */
65 arrangeVertical_WidgetFlag = iBit(18), /* arrange children vertically */ 65 arrangeVertical_WidgetFlag = iBit(19), /* arrange children vertically */
66 arrangeWidth_WidgetFlag = iBit(19), /* area of children becomes parent size */ 66 arrangeWidth_WidgetFlag = iBit(20), /* area of children becomes parent size */
67 arrangeHeight_WidgetFlag = iBit(20), /* area of children becomes parent size */ 67 arrangeHeight_WidgetFlag = iBit(21), /* area of children becomes parent size */
68 resizeWidthOfChildren_WidgetFlag = iBit(21), 68 resizeWidthOfChildren_WidgetFlag = iBit(22),
69 resizeHeightOfChildren_WidgetFlag = iBit(22), 69 resizeHeightOfChildren_WidgetFlag = iBit(23),
70 expand_WidgetFlag = iBit(23), 70 expand_WidgetFlag = iBit(24),
71 fixedWidth_WidgetFlag = iBit(24), 71 fixedWidth_WidgetFlag = iBit(25),
72 fixedHeight_WidgetFlag = iBit(25), 72 fixedHeight_WidgetFlag = iBit(26),
73 resizeChildrenToWidestChild_WidgetFlag = iBit(26), 73 resizeChildrenToWidestChild_WidgetFlag = iBit(27),
74 resizeToParentWidth_WidgetFlag = iBit(27), 74 resizeToParentWidth_WidgetFlag = iBit(28),
75 resizeToParentHeight_WidgetFlag = iBit(28), 75 resizeToParentHeight_WidgetFlag = iBit(29),
76 moveToParentRightEdge_WidgetFlag = iBit(29), 76 collapse_WidgetFlag = iBit(30), /* if hidden, arrange size to zero */
77 collapse_WidgetFlag = iBit(30), /* when hidden, arrange size to zero */
78 wasCollapsed_WidgetFlag = iBit(31),
79 /* combinations */ 77 /* combinations */
80 arrangeSize_WidgetFlag = arrangeWidth_WidgetFlag | arrangeHeight_WidgetFlag, 78 arrangeSize_WidgetFlag = arrangeWidth_WidgetFlag | arrangeHeight_WidgetFlag,
81 resizeChildren_WidgetFlag = resizeWidthOfChildren_WidgetFlag | resizeHeightOfChildren_WidgetFlag, 79 resizeChildren_WidgetFlag = resizeWidthOfChildren_WidgetFlag | resizeHeightOfChildren_WidgetFlag,
82 fixedSize_WidgetFlag = fixedWidth_WidgetFlag | fixedHeight_WidgetFlag, 80 fixedSize_WidgetFlag = fixedWidth_WidgetFlag | fixedHeight_WidgetFlag,
83}; 81};
84 82
83/* 64-bit extended flags */
84#define wasCollapsed_WidgetFlag iBit64(32)
85#define centerHorizontal_WidgetFlag iBit64(33)
86#define moveToParentRightEdge_WidgetFlag iBit64(34)
87
85enum iWidgetAddPos { 88enum iWidgetAddPos {
86 back_WidgetAddPos, 89 back_WidgetAddPos,
87 front_WidgetAddPos, 90 front_WidgetAddPos,
@@ -95,7 +98,7 @@ enum iWidgetFocusDir {
95struct Impl_Widget { 98struct Impl_Widget {
96 iObject object; 99 iObject object;
97 iString id; 100 iString id;
98 int flags; 101 int64_t flags;
99 iRect rect; 102 iRect rect;
100 int padding[4]; /* left, top, right, bottom */ 103 int padding[4]; /* left, top, right, bottom */
101 int bgColor; 104 int bgColor;
@@ -131,7 +134,7 @@ void destroy_Widget (iWidget *); /* widget removed and deleted later */
131void destroyPending_Widget(void); 134void destroyPending_Widget(void);
132 135
133const iString *id_Widget (const iWidget *); 136const iString *id_Widget (const iWidget *);
134int flags_Widget (const iWidget *); 137int64_t flags_Widget (const iWidget *);
135iRect bounds_Widget (const iWidget *); /* outer bounds */ 138iRect bounds_Widget (const iWidget *); /* outer bounds */
136iRect innerBounds_Widget (const iWidget *); 139iRect innerBounds_Widget (const iWidget *);
137iInt2 localCoord_Widget (const iWidget *, iInt2 coord); 140iInt2 localCoord_Widget (const iWidget *, iInt2 coord);
@@ -148,6 +151,10 @@ iLocalDef int width_Widget(const iAnyObject *d) {
148 iAssert(isInstance_Object(d, &Class_Widget)); 151 iAssert(isInstance_Object(d, &Class_Widget));
149 return ((const iWidget *) d)->rect.size.x; 152 return ((const iWidget *) d)->rect.size.x;
150} 153}
154iLocalDef int height_Widget(const iAnyObject *d) {
155 iAssert(isInstance_Object(d, &Class_Widget));
156 return ((const iWidget *) d)->rect.size.y;
157}
151iLocalDef iObjectList *children_Widget(iAnyObject *d) { 158iLocalDef iObjectList *children_Widget(iAnyObject *d) {
152 iAssert(isInstance_Object(d, &Class_Widget)); 159 iAssert(isInstance_Object(d, &Class_Widget));
153 return ((iWidget *) d)->children; 160 return ((iWidget *) d)->children;
@@ -161,7 +168,7 @@ iBool isSelected_Widget (const iAnyObject *);
161iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, const char *cmd); 168iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, const char *cmd);
162iBool hasParent_Widget (const iWidget *d, const iWidget *someParent); 169iBool hasParent_Widget (const iWidget *d, const iWidget *someParent);
163void setId_Widget (iWidget *, const char *id); 170void setId_Widget (iWidget *, const char *id);
164void setFlags_Widget (iWidget *, int flags, iBool set); 171void setFlags_Widget (iWidget *, int64_t flags, iBool set);
165void setPos_Widget (iWidget *, iInt2 pos); 172void setPos_Widget (iWidget *, iInt2 pos);
166void setSize_Widget (iWidget *, iInt2 size); 173void setSize_Widget (iWidget *, iInt2 size);
167void setPadding_Widget (iWidget *, int left, int top, int right, int bottom); 174void setPadding_Widget (iWidget *, int left, int top, int right, int bottom);
@@ -171,7 +178,7 @@ void setFrameColor_Widget (iWidget *, int frameColor);
171void setCommandHandler_Widget (iWidget *, iBool (*handler)(iWidget *, const char *)); 178void setCommandHandler_Widget (iWidget *, iBool (*handler)(iWidget *, const char *));
172iAny * addChild_Widget (iWidget *, iAnyObject *child); /* holds a ref */ 179iAny * addChild_Widget (iWidget *, iAnyObject *child); /* holds a ref */
173iAny * addChildPos_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos); 180iAny * addChildPos_Widget (iWidget *, iAnyObject *child, enum iWidgetAddPos addPos);
174iAny * addChildFlags_Widget(iWidget *, iAnyObject *child, int childFlags); /* holds a ref */ 181iAny * addChildFlags_Widget(iWidget *, iAnyObject *child, int64_t childFlags); /* holds a ref */
175iAny * removeChild_Widget (iWidget *, iAnyObject *child); /* returns a ref */ 182iAny * removeChild_Widget (iWidget *, iAnyObject *child); /* returns a ref */
176iAny * child_Widget (iWidget *, size_t index); /* O(n) */ 183iAny * child_Widget (iWidget *, size_t index); /* O(n) */
177size_t childIndex_Widget (const iWidget *, const iAnyObject *child); /* O(n) */ 184size_t childIndex_Widget (const iWidget *, const iAnyObject *child); /* O(n) */