summaryrefslogtreecommitdiff
path: root/src/ui/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/util.c')
-rw-r--r--src/ui/util.c200
1 files changed, 182 insertions, 18 deletions
diff --git a/src/ui/util.c b/src/ui/util.c
index 5dd8a0bd..4f5de7f9 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
35#include "keys.h" 35#include "keys.h"
36#include "labelwidget.h" 36#include "labelwidget.h"
37#include "root.h" 37#include "root.h"
38#include "sitespec.h"
38#include "text.h" 39#include "text.h"
39#include "touch.h" 40#include "touch.h"
40#include "widget.h" 41#include "widget.h"
@@ -903,6 +904,7 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {
903#else 904#else
904 /* Non-native custom popup menu. This may still be displayed inside a separate window. */ 905 /* Non-native custom popup menu. This may still be displayed inside a separate window. */
905 setDrawBufferEnabled_Widget(menu, iTrue); 906 setDrawBufferEnabled_Widget(menu, iTrue);
907 setFrameColor_Widget(menu, uiSeparator_ColorId);
906 setBackgroundColor_Widget(menu, uiBackgroundMenu_ColorId); 908 setBackgroundColor_Widget(menu, uiBackgroundMenu_ColorId);
907 if (deviceType_App() != desktop_AppDeviceType) { 909 if (deviceType_App() != desktop_AppDeviceType) {
908 setPadding1_Widget(menu, 2 * gap_UI); 910 setPadding1_Widget(menu, 2 * gap_UI);
@@ -1084,12 +1086,12 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {
1084 setFlags_Widget(d, hidden_WidgetFlag, iFalse); 1086 setFlags_Widget(d, hidden_WidgetFlag, iFalse);
1085 setFlags_Widget(d, commandOnMouseMiss_WidgetFlag, iTrue); 1087 setFlags_Widget(d, commandOnMouseMiss_WidgetFlag, iTrue);
1086 setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iFalse); 1088 setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iFalse);
1087 if (!isPortraitPhone) { 1089// if (!isPortraitPhone) {
1088 setFrameColor_Widget(d, uiBackgroundSelected_ColorId); 1090// setFrameColor_Widget(d, uiSeparator_ColorId);
1089 } 1091// }
1090 else { 1092// else {
1091 setFrameColor_Widget(d, none_ColorId); 1093// setFrameColor_Widget(d, none_ColorId);
1092 } 1094// }
1093 arrange_Widget(d); /* need to know the height */ 1095 arrange_Widget(d); /* need to know the height */
1094 iBool allowOverflow = iFalse; 1096 iBool allowOverflow = iFalse;
1095 /* A vertical offset determined by a possible selected label in the menu. */ 1097 /* A vertical offset determined by a possible selected label in the menu. */
@@ -1327,6 +1329,7 @@ int checkContextMenu_Widget(iWidget *menu, const SDL_Event *ev) {
1327iLabelWidget *makeMenuButton_LabelWidget(const char *label, const iMenuItem *items, size_t n) { 1329iLabelWidget *makeMenuButton_LabelWidget(const char *label, const iMenuItem *items, size_t n) {
1328 iLabelWidget *button = new_LabelWidget(label, "menu.open"); 1330 iLabelWidget *button = new_LabelWidget(label, "menu.open");
1329 iWidget *menu = makeMenu_Widget(as_Widget(button), items, n); 1331 iWidget *menu = makeMenu_Widget(as_Widget(button), items, n);
1332 setFrameColor_Widget(menu, uiBackgroundSelected_ColorId);
1330 setId_Widget(menu, "menu"); 1333 setId_Widget(menu, "menu");
1331 return button; 1334 return button;
1332} 1335}
@@ -1383,6 +1386,9 @@ void updateDropdownSelection_LabelWidget(iLabelWidget *dropButton, const char *s
1383 updateText_LabelWidget(dropButton, 1386 updateText_LabelWidget(dropButton,
1384 replaceNewlinesWithDash_(text_LabelWidget(item))); 1387 replaceNewlinesWithDash_(text_LabelWidget(item)));
1385 checkIcon_LabelWidget(dropButton); 1388 checkIcon_LabelWidget(dropButton);
1389 if (!icon_LabelWidget(dropButton)) {
1390 setIcon_LabelWidget(dropButton, icon_LabelWidget(item));
1391 }
1386 } 1392 }
1387 } 1393 }
1388 } 1394 }
@@ -1709,13 +1715,14 @@ iLabelWidget *addDialogTitle_Widget(iWidget *dlg, const char *text, const char *
1709} 1715}
1710 1716
1711static void acceptValueInput_(iWidget *dlg) { 1717static void acceptValueInput_(iWidget *dlg) {
1712 const iInputWidget *input = findChild_Widget(dlg, "input"); 1718 iInputWidget *input = findChild_Widget(dlg, "input");
1713 if (!isEmpty_String(id_Widget(dlg))) { 1719 if (!isEmpty_String(id_Widget(dlg))) {
1714 const iString *val = text_InputWidget(input); 1720 const iString *val = text_InputWidget(input);
1715 postCommandf_App("%s arg:%d value:%s", 1721 postCommandf_App("%s arg:%d value:%s",
1716 cstr_String(id_Widget(dlg)), 1722 cstr_String(id_Widget(dlg)),
1717 toInt_String(val), 1723 toInt_String(val),
1718 cstr_String(val)); 1724 cstr_String(val));
1725 setBackupFileName_InputWidget(input, NULL);
1719 } 1726 }
1720} 1727}
1721 1728
@@ -1779,6 +1786,7 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) {
1779 else if (equal_Command(cmd, "valueinput.set")) { 1786 else if (equal_Command(cmd, "valueinput.set")) {
1780 iInputWidget *input = findChild_Widget(dlg, "input"); 1787 iInputWidget *input = findChild_Widget(dlg, "input");
1781 setTextUndoableCStr_InputWidget(input, suffixPtr_Command(cmd, "text"), iTrue); 1788 setTextUndoableCStr_InputWidget(input, suffixPtr_Command(cmd, "text"), iTrue);
1789 deselect_InputWidget(input);
1782 validate_InputWidget(input); 1790 validate_InputWidget(input);
1783 return iTrue; 1791 return iTrue;
1784 } 1792 }
@@ -2495,6 +2503,7 @@ iWidget *makePreferences_Widget(void) {
2495 { "input id:prefs.searchurl url:1 noheading:1" }, 2503 { "input id:prefs.searchurl url:1 noheading:1" },
2496 { "padding" }, 2504 { "padding" },
2497 { "toggle id:prefs.bookmarks.addbottom" }, 2505 { "toggle id:prefs.bookmarks.addbottom" },
2506 { "toggle id:prefs.dataurl.openimages" },
2498 { "toggle id:prefs.archive.openindex" }, 2507 { "toggle id:prefs.archive.openindex" },
2499 { "radio device:1 id:prefs.pinsplit", 0, 0, (const void *) pinSplitItems }, 2508 { "radio device:1 id:prefs.pinsplit", 0, 0, (const void *) pinSplitItems },
2500 { "padding" }, 2509 { "padding" },
@@ -2567,6 +2576,7 @@ iWidget *makePreferences_Widget(void) {
2567 const iMenuItem networkPanelItems[] = { 2576 const iMenuItem networkPanelItems[] = {
2568 { "title id:heading.prefs.network" }, 2577 { "title id:heading.prefs.network" },
2569 { "toggle id:prefs.decodeurls" }, 2578 { "toggle id:prefs.decodeurls" },
2579 { "input id:prefs.urlsize maxlen:10 selectall:1" },
2570 { "padding" }, 2580 { "padding" },
2571 { "input id:prefs.cachesize maxlen:4 selectall:1 unit:mb" }, 2581 { "input id:prefs.cachesize maxlen:4 selectall:1 unit:mb" },
2572 { "input id:prefs.memorysize maxlen:4 selectall:1 unit:mb" }, 2582 { "input id:prefs.memorysize maxlen:4 selectall:1 unit:mb" },
@@ -2640,8 +2650,9 @@ iWidget *makePreferences_Widget(void) {
2640 setUrlContent_InputWidget(searchUrl, iTrue); 2650 setUrlContent_InputWidget(searchUrl, iTrue);
2641 addDialogPadding_(headings, values); 2651 addDialogPadding_(headings, values);
2642 addDialogToggle_(headings, values, "${prefs.hoverlink}", "prefs.hoverlink"); 2652 addDialogToggle_(headings, values, "${prefs.hoverlink}", "prefs.hoverlink");
2643 addDialogToggle_(headings, values, "${prefs.bookmarks.addbottom}", "prefs.bookmarks.addbottom"); 2653 addDialogToggle_(headings, values, "${prefs.dataurl.openimages}", "prefs.dataurl.openimages");
2644 addDialogToggle_(headings, values, "${prefs.archive.openindex}", "prefs.archive.openindex"); 2654 addDialogToggle_(headings, values, "${prefs.archive.openindex}", "prefs.archive.openindex");
2655 addDialogToggle_(headings, values, "${prefs.bookmarks.addbottom}", "prefs.bookmarks.addbottom");
2645 if (deviceType_App() != phone_AppDeviceType) { 2656 if (deviceType_App() != phone_AppDeviceType) {
2646 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.pinsplit}"))); 2657 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.pinsplit}")));
2647 iWidget *pinSplit = new_Widget(); 2658 iWidget *pinSplit = new_Widget();
@@ -2900,6 +2911,7 @@ iWidget *makePreferences_Widget(void) {
2900 appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.network}", '6', &headings, &values); 2911 appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.network}", '6', &headings, &values);
2901 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.decodeurls}"))); 2912 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.decodeurls}")));
2902 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls"))); 2913 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls")));
2914 addPrefsInputWithHeading_(headings, values, "prefs.urlsize", iClob(new_InputWidget(10)));
2903 /* Cache size. */ { 2915 /* Cache size. */ {
2904 iInputWidget *cache = new_InputWidget(4); 2916 iInputWidget *cache = new_InputWidget(4);
2905 setSelectAllOnFocus_InputWidget(cache, iTrue); 2917 setSelectAllOnFocus_InputWidget(cache, iTrue);
@@ -3120,7 +3132,7 @@ iWidget *makeBookmarkCreation_Widget(const iString *url, const iString *title, i
3120 3132
3121static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) { 3133static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) {
3122 if (equal_Command(cmd, "cancel")) { 3134 if (equal_Command(cmd, "cancel")) {
3123 setupSheetTransition_Mobile(dlg, iFalse); 3135 setupSheetTransition_Mobile(dlg, 0);
3124 destroy_Widget(dlg); 3136 destroy_Widget(dlg);
3125 return iTrue; 3137 return iTrue;
3126 } 3138 }
@@ -3163,15 +3175,14 @@ static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) {
3163} 3175}
3164 3176
3165iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { 3177iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
3166 const char *headingText = bookmarkId ? uiHeading_ColorEscape "${heading.feedcfg}" 3178 iWidget *dlg;
3167 : uiHeading_ColorEscape "${heading.subscribe}"; 3179 const char *headingText = bookmarkId ? "${heading.feedcfg}" : "${heading.subscribe}";
3168 const iMenuItem actions[] = { { "${cancel}" }, 3180 const iMenuItem actions[] = { { "${cancel}" },
3169 { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}" 3181 { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}"
3170 : uiTextCaution_ColorEscape "${dlg.feed.sub}", 3182 : uiTextCaution_ColorEscape "${dlg.feed.sub}",
3171 SDLK_RETURN, 3183 SDLK_RETURN,
3172 KMOD_PRIMARY, 3184 KMOD_PRIMARY,
3173 format_CStr("feedcfg.accept bmid:%d", bookmarkId) } }; 3185 format_CStr("feedcfg.accept bmid:%d", bookmarkId) } };
3174 iWidget *dlg;
3175 if (isUsingPanelLayout_Mobile()) { 3186 if (isUsingPanelLayout_Mobile()) {
3176 const iMenuItem typeItems[] = { 3187 const iMenuItem typeItems[] = {
3177 { "button id:feedcfg.type.gemini label:dlg.feed.type.gemini", 0, 0, "feedcfg.type arg:0" }, 3188 { "button id:feedcfg.type.gemini label:dlg.feed.type.gemini", 0, 0, "feedcfg.type arg:0" },
@@ -3228,6 +3239,111 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
3228 return dlg; 3239 return dlg;
3229} 3240}
3230 3241
3242/*----------------------------------------------------------------------------------------------*/
3243
3244static void siteSpecificThemeChanged_(const iWidget *dlg) {
3245 iDocumentWidget *doc = document_App();
3246 setThemeSeed_GmDocument((iGmDocument *) document_DocumentWidget(doc),
3247 urlPaletteSeed_String(url_DocumentWidget(doc)),
3248 urlThemeSeed_String(url_DocumentWidget(doc)));
3249 postCommand_App("theme.changed");
3250}
3251
3252static const iString *siteSpecificRoot_(const iWidget *dlg) {
3253 return collect_String(suffix_Command(cstr_String(id_Widget(dlg)), "site"));
3254}
3255
3256static void updateSiteSpecificTheme_(iInputWidget *palSeed, void *context) {
3257 iWidget *dlg = context;
3258 const iString *siteRoot = siteSpecificRoot_(dlg);
3259 setValueString_SiteSpec(siteRoot, paletteSeed_SiteSpecKey, text_InputWidget(palSeed));
3260 siteSpecificThemeChanged_(dlg);
3261 /* Allow seeing the new theme. */
3262 setFlags_Widget(dlg, noFadeBackground_WidgetFlag, iTrue);
3263}
3264
3265static void closeSiteSpecific_(iWidget *dlg) {
3266 setupSheetTransition_Mobile(dlg, 0);
3267 delete_String(userData_Object(dlg)); /* saved original palette seed */
3268 destroy_Widget(dlg);
3269}
3270
3271static iBool siteSpecificSettingsHandler_(iWidget *dlg, const char *cmd) {
3272 if (equal_Command(cmd, "cancel")) {
3273 const iBool wasNoFade = (flags_Widget(dlg) & noFadeBackground_WidgetFlag) != 0;
3274 iInputWidget *palSeed = findChild_Widget(dlg, "sitespec.palette");
3275 setText_InputWidget(palSeed, userData_Object(dlg));
3276 updateSiteSpecificTheme_(palSeed, dlg);
3277 setFlags_Widget(dlg, noFadeBackground_WidgetFlag, wasNoFade);
3278 closeSiteSpecific_(dlg);
3279 return iTrue;
3280 }
3281 if (startsWith_CStr(cmd, "input.ended id:sitespec.palette")) {
3282 setFlags_Widget(dlg, noFadeBackground_WidgetFlag, iFalse);
3283 refresh_Widget(dlg);
3284 siteSpecificThemeChanged_(dlg);
3285 return iTrue;
3286 }
3287 if (equal_Command(cmd, "sitespec.accept")) {
3288 const iInputWidget *palSeed = findChild_Widget(dlg, "sitespec.palette");
3289 const iBool warnAnsi = isSelected_Widget(findChild_Widget(dlg, "sitespec.ansi"));
3290 const iString *siteRoot = siteSpecificRoot_(dlg);
3291 int dismissed = value_SiteSpec(siteRoot, dismissWarnings_SiteSpecKey);
3292 iChangeFlags(dismissed, ansiEscapes_GmDocumentWarning, !warnAnsi);
3293 setValue_SiteSpec(siteRoot, dismissWarnings_SiteSpecKey, dismissed);
3294 setValueString_SiteSpec(siteRoot, paletteSeed_SiteSpecKey, text_InputWidget(palSeed));
3295 siteSpecificThemeChanged_(dlg);
3296 /* Note: The active DocumentWidget may actually be different than when opening the dialog. */
3297 closeSiteSpecific_(dlg);
3298 return iTrue;
3299 }
3300 return iFalse;
3301}
3302
3303iWidget *makeSiteSpecificSettings_Widget(const iString *url) {
3304 iWidget *dlg;
3305 const iMenuItem actions[] = {
3306 { "${cancel}" },
3307 { "${sitespec.accept}", SDLK_RETURN, KMOD_PRIMARY, "sitespec.accept" }
3308 };
3309 if (isUsingPanelLayout_Mobile()) {
3310 iAssert(iFalse);
3311 }
3312 else {
3313 iWidget *headings, *values;
3314 dlg = makeSheet_Widget(format_CStr("sitespec site:%s", cstr_Rangecc(urlRoot_String(url))));
3315 addDialogTitle_(dlg, "${heading.sitespec}", "heading.sitespec");
3316 addChild_Widget(dlg, iClob(makeTwoColumns_Widget(&headings, &values)));
3317 iInputWidget *palSeed = new_InputWidget(0);
3318 setHint_InputWidget(palSeed, cstr_Block(urlThemeSeed_String(url)));
3319 addPrefsInputWithHeading_(headings, values, "sitespec.palette", iClob(palSeed));
3320 addDialogToggle_(headings, values, "${sitespec.ansi}", "sitespec.ansi");
3321 addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));
3322 addChild_Widget(get_Root()->widget, iClob(dlg));
3323 as_Widget(palSeed)->rect.size.x = 60 * gap_UI;
3324 arrange_Widget(dlg);
3325 }
3326 /* Initialize. */ {
3327 const iString *site = collectNewRange_String(urlRoot_String(url));
3328 setToggle_Widget(findChild_Widget(dlg, "sitespec.ansi"),
3329 ~value_SiteSpec(site, dismissWarnings_SiteSpecKey) & ansiEscapes_GmDocumentWarning);
3330 setText_InputWidget(findChild_Widget(dlg, "sitespec.palette"),
3331 valueString_SiteSpec(site, paletteSeed_SiteSpecKey));
3332 /* Keep a copy of the original palette seed for restoring on cancel. */
3333 setUserData_Object(dlg, copy_String(valueString_SiteSpec(site, paletteSeed_SiteSpecKey)));
3334 if (!isUsingPanelLayout_Mobile()) {
3335 setValidator_InputWidget(findChild_Widget(dlg, "sitespec.palette"),
3336 updateSiteSpecificTheme_, dlg);
3337 }
3338 }
3339 setCommandHandler_Widget(dlg, siteSpecificSettingsHandler_);
3340 setupSheetTransition_Mobile(dlg, incoming_TransitionFlag);
3341 setFocus_Widget(findChild_Widget(dlg, "sitespec.palette"));
3342 return dlg;
3343}
3344
3345/*----------------------------------------------------------------------------------------------*/
3346
3231iWidget *makeIdentityCreation_Widget(void) { 3347iWidget *makeIdentityCreation_Widget(void) {
3232 const iMenuItem actions[] = { { "${dlg.newident.more}", 0, 0, "ident.showmore" }, 3348 const iMenuItem actions[] = { { "${dlg.newident.more}", 0, 0, "ident.showmore" },
3233 { "---" }, 3349 { "---" },
@@ -3451,6 +3567,54 @@ iWidget *makeTranslation_Widget(iWidget *parent) {
3451 return dlg; 3567 return dlg;
3452} 3568}
3453 3569
3570iWidget *makeGlyphFinder_Widget(void) {
3571 iString msg;
3572 iString command;
3573 init_String(&msg);
3574 initCStr_String(&command, "!font.find chars:");
3575 for (size_t i = 0; ; i++) {
3576 iChar ch = missing_Text(i);
3577 if (!ch) break;
3578 appendFormat_String(&msg, " U+%04X", ch);
3579 appendChar_String(&command, ch);
3580 }
3581 iArray items;
3582 init_Array(&items, sizeof(iMenuItem));
3583 if (!isEmpty_String(&msg)) {
3584 prependCStr_String(&msg, "${dlg.glyphfinder.missing} ");
3585 appendCStr_String(&msg, "\n\n${dlg.glyphfinder.help}");
3586 pushBackN_Array(
3587 &items,
3588 (iMenuItem[]){
3589 { "${menu.fonts}", 0, 0, "!open newtab:1 url:about:fonts" },
3590 { "${dlg.glyphfinder.disable}", 0, 0, "prefs.font.warnmissing.changed arg:0" },
3591 { "---" },
3592 { uiTextCaution_ColorEscape magnifyingGlass_Icon " ${dlg.glyphfinder.search}",
3593 0,
3594 0,
3595 cstr_String(&command) },
3596 { "${close}", 0, 0, "cancel" } },
3597 5);
3598 }
3599 else {
3600 setCStr_String(&msg, "${dlg.glyphfinder.help.empty}");
3601 pushBackN_Array(&items,
3602 (iMenuItem[]){ { "${menu.reload}", 0, 0, "navigate.reload" },
3603 { "${close}", 0, 0, "cancel" } },
3604 2);
3605 }
3606 iWidget *dlg = makeQuestion_Widget("${heading.glyphfinder}", cstr_String(&msg),
3607 constData_Array(&items),
3608 size_Array(&items));
3609 arrange_Widget(dlg);
3610 deinit_Array(&items);
3611 deinit_String(&command);
3612 deinit_String(&msg);
3613 return dlg;
3614}
3615
3616/*----------------------------------------------------------------------------------------------*/
3617
3454void init_PerfTimer(iPerfTimer *d) { 3618void init_PerfTimer(iPerfTimer *d) {
3455 d->ticks = SDL_GetPerformanceCounter(); 3619 d->ticks = SDL_GetPerformanceCounter();
3456} 3620}