From 709329cef2fe3cd88d6a4e27389b64431f5936f6 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 11:40:44 +0300 Subject: Dialog show/hide animations Use the animations introduced for mobile on desktop as well. Adding a preference for this might be prudent. --- src/ui/mobile.c | 51 +++++++++++++++++++++++++++++++------------------- src/ui/root.c | 3 +++ src/ui/sidebarwidget.c | 3 ++- src/ui/translation.c | 2 ++ src/ui/util.c | 7 +++++++ src/ui/widget.c | 10 +++++----- 6 files changed, 51 insertions(+), 25 deletions(-) (limited to 'src/ui') diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 6c3a0b32..d678f3e1 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c @@ -381,22 +381,22 @@ void finalizeSheet_Mobile(iWidget *sheet) { } /* TODO: In portrait, top panel and detail stack are all stacked together. - Landscape Layout    Portrait Layout -    - ┌─────────┬──────Detail─Stack─────┐    ┌─────────┬ ─ ─ ─ ─ ┐ - │ │┌───────────────────┐ │    │ │Detail - │ ││┌──────────────────┴┐ │    │ │Stack │ - │ │││┌──────────────────┴┐│    │ │┌──────┐ - │ ││││ ││    │ ││┌─────┴┐│ - │ ││││ ││    │ │││ │ - │Top Panel││││ ││    │Top Panel│││ ││ - │ ││││ Panels ││    │ │││Panels│ - │ ││││ ││    │ │││ ││ - │ │└┤│ ││    │ │││ │ - │ │ └┤ ││    │ │└┤ ││ - │ │ └───────────────────┘│    │ │ └──────┘ - └─────────┴───────────────────────┘    └─────────┴ ─ ─ ─ ─ ┘ -    offscreen + Landscape Layout Portrait Layout + + ┌─────────┬──────Detail─Stack─────┐ ┌─────────┬ ─ ─ ─ ─ ┐ + │ │┌───────────────────┐ │ │ │Detail + │ ││┌──────────────────┴┐ │ │ │Stack │ + │ │││┌──────────────────┴┐│ │ │┌──────┐ + │ ││││ ││ │ ││┌─────┴┐│ + │ ││││ ││ │ │││ │ + │Top Panel││││ ││ │Top Panel│││ ││ + │ ││││ Panels ││ │ │││Panels│ + │ ││││ ││ │ │││ ││ + │ │└┤│ ││ │ │││ │ + │ │ └┤ ││ │ │└┤ ││ + │ │ └───────────────────┘│ │ │ └──────┘ + └─────────┴───────────────────────┘ └─────────┴ ─ ─ ─ ─ ┘ + offscreen */ /* Modify the top sheet to act as a fullscreen background. */ setPadding1_Widget(sheet, 0); @@ -759,6 +759,9 @@ void finalizeSheet_Mobile(iWidget *sheet) { else { arrange_Widget(sheet); } + if (!useMobileSheetLayout_()) { + setupSheetTransition_Mobile(sheet, iTrue); + } postRefresh_App(); } @@ -784,16 +787,26 @@ void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { } void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { - if (isSideBySideLayout_()) { + if (!useMobileSheetLayout_()) { + setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); + if (isIncoming) { + setVisualOffset_Widget(sheet, -height_Widget(sheet), 0, 0); + setVisualOffset_Widget(sheet, 0, 200, easeOut_AnimFlag | softer_AnimFlag); + } + else { + setVisualOffset_Widget(sheet, -height_Widget(sheet), 200, easeIn_AnimFlag); + } + return; + } + if(isSideBySideLayout_()) { return; } + setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iTrue); if (isIncoming) { - setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iTrue); setVisualOffset_Widget(sheet, size_Root(sheet->root).x, 0, 0); setVisualOffset_Widget(sheet, 0, 200, easeOut_AnimFlag); } else { - setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iTrue); const iBool wasDragged = iAbs(value_Anim(&sheet->visualOffset)) > 0; setVisualOffset_Widget(sheet, size_Root(sheet->root).x, wasDragged ? 100 : 200, wasDragged ? 0 : easeIn_AnimFlag); diff --git a/src/ui/root.c b/src/ui/root.c index 9ed62711..6c65d18f 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -276,6 +276,9 @@ void destroyPending_Root(iRoot *d) { if (!isFinished_Anim(&widget->visualOffset)) { continue; } + if (widget->flags & keepOnTop_WidgetFlag) { + removeOne_PtrArray(onTop_Root(widget->root), widget); + } if (widget->parent) { removeChild_Widget(widget->parent, widget); } diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 86410d11..ac2d147e 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -1460,7 +1460,8 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) { const iRect bounds = bounds_Widget(w); iPaint p; init_Paint(&p); - if (flags_Widget(w) & visualOffset_WidgetFlag && isVisible_Widget(w)) { + if (flags_Widget(w) & visualOffset_WidgetFlag && + flags_Widget(w) & horizontalOffset_WidgetFlag && isVisible_Widget(w)) { fillRect_Paint(&p, boundsWithoutVisualOffset_Widget(w), tmBackground_ColorId); } draw_Widget(w); diff --git a/src/ui/translation.c b/src/ui/translation.c index 4102fcb9..ed7e5baa 100644 --- a/src/ui/translation.c +++ b/src/ui/translation.c @@ -460,6 +460,7 @@ iBool handleCommand_Translation(iTranslation *d, const char *cmd) { if (equalWidget_Command(cmd, w, "translation.finished")) { if (!isFinished_Translation(d)) { if (processResult_Translation_(d)) { + setupSheetTransition_Mobile(d->dlg, iFalse); destroy_Widget(d->dlg); d->dlg = NULL; } @@ -476,6 +477,7 @@ iBool handleCommand_Translation(iTranslation *d, const char *cmd) { cancel_TlsRequest(d->request); } else { + setupSheetTransition_Mobile(d->dlg, iFalse); destroy_Widget(d->dlg); d->dlg = NULL; } diff --git a/src/ui/util.c b/src/ui/util.c index 4b35f8f7..86478300 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1176,6 +1176,7 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) { postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); setId_Widget(dlg, ""); /* no further commands to emit */ } + setupSheetTransition_Mobile(dlg, iFalse); destroy_Widget(dlg); return iTrue; } @@ -1184,11 +1185,13 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) { else if (equal_Command(cmd, "cancel")) { postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); setId_Widget(dlg, ""); /* no further commands to emit */ + setupSheetTransition_Mobile(dlg, iFalse); destroy_Widget(dlg); return iTrue; } else if (equal_Command(cmd, "valueinput.accept")) { acceptValueInput_(dlg); + setupSheetTransition_Mobile(dlg, iFalse); destroy_Widget(dlg); return iTrue; } @@ -1324,6 +1327,7 @@ static iBool messageHandler_(iWidget *msg, const char *cmd) { equal_Command(cmd, "scrollbar.fade") || equal_Command(cmd, "widget.overflow") || startsWith_CStr(cmd, "window."))) { + setupSheetTransition_Mobile(msg, iFalse); destroy_Widget(msg); } return iFalse; @@ -1908,6 +1912,7 @@ static iBool handleBookmarkCreationCommands_SidebarWidget_(iWidget *editor, cons } postCommand_App("bookmarks.changed"); } + setupSheetTransition_Mobile(editor, iFalse); destroy_Widget(editor); return iTrue; } @@ -1937,6 +1942,7 @@ iWidget *makeBookmarkCreation_Widget(const iString *url, const iString *title, i static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) { if (equal_Command(cmd, "cancel")) { + setupSheetTransition_Mobile(dlg, iFalse); destroy_Widget(dlg); return iTrue; } @@ -1971,6 +1977,7 @@ static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) { } } postCommand_App("bookmarks.changed"); + setupSheetTransition_Mobile(dlg, iFalse); destroy_Widget(dlg); return iTrue; } diff --git a/src/ui/widget.c b/src/ui/widget.c index 64f586ce..5502cb8e 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -101,9 +101,6 @@ static void aboutToBeDestroyed_Widget_(iWidget *d) { setFocus_Widget(NULL); return; } - if (flags_Widget(d) & keepOnTop_WidgetFlag) { - removeOne_PtrArray(onTop_Root(d->root), d); - } remove_Periodic(periodic_App(), d); if (isHover_Widget(d)) { get_Window()->hover = NULL; @@ -858,6 +855,9 @@ iLocalDef iBool isMouseEvent_(const SDL_Event *ev) { } static iBool filterEvent_Widget_(const iWidget *d, const SDL_Event *ev) { + if (d->flags & destroyPending_WidgetFlag) { + return iFalse; /* no more events handled */ + } const iBool isKey = isKeyboardEvent_(ev); const iBool isMouse = isMouseEvent_(ev); if ((d->flags & disabled_WidgetFlag) || (d->flags & hidden_WidgetFlag && @@ -1103,8 +1103,8 @@ void drawBackground_Widget(const iWidget *d) { drawSoftShadow_Paint(&p, bounds_Widget(d), 12 * gap_UI, black_ColorId, 30); } const iBool isFaded = fadeBackground && - ~d->flags & noFadeBackground_WidgetFlag && - ~d->flags & destroyPending_WidgetFlag; + ~d->flags & noFadeBackground_WidgetFlag;/* && + ~d->flags & destroyPending_WidgetFlag;*/ if (isFaded) { iPaint p; init_Paint(&p); -- cgit v1.2.3 From f6a55930a900bd07d4b2028e7df82bbef1a291d0 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 11:41:42 +0300 Subject: Improved Identity management via sidebar Prevent redundant activations: the highest-level URL overrides the same identity being used on lower-level URLs. Changed the icons in the list and added the list of used URLs into the context menu as clickable items. --- src/gmcerts.c | 11 +++++- src/ui/root.c | 9 +++-- src/ui/sidebarwidget.c | 94 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 90 insertions(+), 24 deletions(-) (limited to 'src/ui') diff --git a/src/gmcerts.c b/src/gmcerts.c index 35d784f6..f86712ac 100644 --- a/src/gmcerts.c +++ b/src/gmcerts.c @@ -105,7 +105,7 @@ void deserialize_GmIdentity(iGmIdentity *d, iStream *ins) { iString url; init_String(&url); deserialize_String(&url, ins); - insert_StringSet(d->useUrls, &url); + setUse_GmIdentity(d, &url, iTrue); deinit_String(&url); } } @@ -166,6 +166,15 @@ void setUse_GmIdentity(iGmIdentity *d, const iString *url, iBool use) { return; /* Redudant. */ } if (use) { + /* Remove all use-URLs that become redundant by this newly added URL. */ + /* TODO: StringSet could have a non-const iterator. */ + iForEach(Array, i, &d->useUrls->strings.values) { + iString *used = i.value; + if (startsWithCase_String(used, cstr_String(url))) { + deinit_String(used); + remove_ArrayIterator(&i); + } + } #if !defined (NDEBUG) const iBool wasInserted = #endif diff --git a/src/ui/root.c b/src/ui/root.c index 6c65d18f..1698a5d4 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -438,11 +438,14 @@ static void updateNavBarIdentity_(iWidget *navBar) { setFlags_Widget(tool, selected_WidgetFlag, ident != NULL); /* Update menu. */ iLabelWidget *idItem = child_Widget(findChild_Widget(button, "menu"), 0); + iString *subjectName = ident ? collect_String(subject_TlsCertificate(ident->cert)) : NULL; + if (subjectName && startsWith_String(subjectName, "CN = ")) { + remove_Block(&subjectName->chars, 0, 5); + } setTextCStr_LabelWidget( idItem, - ident ? format_CStr(uiTextAction_ColorEscape "%s", - cstrCollect_String(subject_TlsCertificate(ident->cert))) - : "${menu.identity.notactive}"); + subjectName ? format_CStr(uiTextAction_ColorEscape "%s", cstr_String(subjectName)) + : "${menu.identity.notactive}"); setFlags_Widget(as_Widget(idItem), disabled_WidgetFlag, !ident); } diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index ac2d147e..55c74774 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -148,6 +148,64 @@ static iLabelWidget *addActionButton_SidebarWidget_(iSidebarWidget *d, const cha return btn; } +static iGmIdentity *menuIdentity_SidebarWidget_(const iSidebarWidget *d) { + if (d->mode == identities_SidebarMode) { + if (d->contextItem) { + return identity_GmCerts(certs_App(), d->contextItem->id); + } + } + return NULL; +} + +static void updateContextMenu_SidebarWidget_(iSidebarWidget *d) { + if (d->mode != identities_SidebarMode) { + return; + } + iArray *items = collectNew_Array(sizeof(iMenuItem)); + pushBackN_Array(items, (iMenuItem[]){ + { person_Icon " ${ident.use}", 0, 0, "ident.use arg:1" }, + { close_Icon " ${ident.stopuse}", 0, 0, "ident.use arg:0" }, + { close_Icon " ${ident.stopuse.all}", 0, 0, "ident.use arg:0 clear:1" }, + { "---", 0, 0, NULL }, + { edit_Icon " ${menu.edit.notes}", 0, 0, "ident.edit" }, + { "${ident.fingerprint}", 0, 0, "ident.fingerprint" }, + { "---", 0, 0, NULL }, + { delete_Icon " " uiTextCaution_ColorEscape "${ident.delete}", 0, 0, "ident.delete confirm:1" }, + }, 8); + /* Used URLs. */ + const iGmIdentity *ident = menuIdentity_SidebarWidget_(d); + if (ident) { + size_t insertPos = 3; + if (!isEmpty_StringSet(ident->useUrls)) { + insert_Array(items, insertPos++, &(iMenuItem){ "---", 0, 0, NULL }); + } + const iString *docUrl = url_DocumentWidget(document_App()); + iBool usedOnCurrentPage = iFalse; + iConstForEach(StringSet, i, ident->useUrls) { + const iString *url = i.value; + usedOnCurrentPage |= equalCase_String(docUrl, url); + iRangecc urlStr = range_String(url); + if (startsWith_Rangecc(urlStr, "gemini://")) { + urlStr.start += 9; /* omit the default scheme */ + } + if (endsWith_Rangecc(urlStr, "/")) { + urlStr.end--; /* looks cleaner */ + } + insert_Array(items, + insertPos++, + &(iMenuItem){ format_CStr(globe_Icon " %s", cstr_Rangecc(urlStr)), + 0, + 0, + format_CStr("!open url:%s", cstr_String(url)) }); + } + if (!usedOnCurrentPage) { + remove_Array(items, 1); + } + } + destroy_Widget(d->menu); + d->menu = makeMenu_Widget(as_Widget(d), data_Array(items), size_Array(items)); +} + static void updateItems_SidebarWidget_(iSidebarWidget *d) { clear_ListWidget(d->list); releaseChildren_Widget(d->blank); @@ -380,8 +438,11 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { const iGmIdentity *ident = i.ptr; iSidebarItem *item = new_SidebarItem(); item->id = (uint32_t) index_PtrArrayConstIterator(&i); - item->icon = ident->icon; + item->icon = 0x1f464; /* person */ set_String(&item->label, collect_String(subject_TlsCertificate(ident->cert))); + if (startsWith_String(&item->label, "CN = ")) { + remove_Block(&item->label.chars, 0, 5); + } iDate until; validUntil_TlsCertificate(ident->cert, &until); const iBool isActive = isUsedOn_GmIdentity(ident, tabUrl); @@ -697,15 +758,6 @@ static const iGmIdentity *constHoverIdentity_SidebarWidget_(const iSidebarWidget return NULL; } -static iGmIdentity *menuIdentity_SidebarWidget_(const iSidebarWidget *d) { - if (d->mode == identities_SidebarMode) { - if (d->contextItem) { - return identity_GmCerts(certs_App(), d->contextItem->id); - } - } - return NULL; -} - static iGmIdentity *hoverIdentity_SidebarWidget_(const iSidebarWidget *d) { return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d)); } @@ -848,6 +900,7 @@ iBool handleBookmarkEditorCommands_SidebarWidget_(iWidget *editor, const char *c isSelected_Widget(findChild_Widget(editor, "bmed.tag.linksplit"))); postCommand_App("bookmarks.changed"); } + setupSheetTransition_Mobile(editor, iFalse); destroy_Widget(editor); return iTrue; } @@ -1199,14 +1252,6 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) } return iTrue; } - else if (isCommand_Widget(w, ev, "ident.showuse")) { - const iGmIdentity *ident = menuIdentity_SidebarWidget_(d); - if (ident) { - makeSimpleMessage_Widget(uiHeading_ColorEscape "${heading.ident.use}", - cstrCollect_String(joinCStr_StringSet(ident->useUrls, "\n"))); - } - return iTrue; - } else if (isCommand_Widget(w, ev, "ident.edit")) { const iGmIdentity *ident = menuIdentity_SidebarWidget_(d); if (ident) { @@ -1343,13 +1388,14 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) updateMouseHover_ListWidget(d->list); } if (constHoverItem_ListWidget(d->list) || isVisible_Widget(d->menu)) { - d->contextItem = hoverItem_ListWidget(d->list); + d->contextItem = hoverItem_ListWidget(d->list); /* Context is drawn in hover state. */ if (d->contextIndex != iInvalidPos) { invalidateItem_ListWidget(d->list, d->contextIndex); } d->contextIndex = hoverItemIndex_ListWidget(d->list); /* Update menu items. */ + updateContextMenu_SidebarWidget_(d); /* TODO: Some callback-based mechanism would be nice for updating menus right before they open? */ if (d->mode == bookmarks_SidebarMode && d->contextItem) { @@ -1695,8 +1741,16 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) : uiTextDim_ColorId; + if (!d->listItem.isSelected) { + for (int off = 0; off < 4; ++off) { + drawRange_Text(font, + add_I2(cPos, init_I2(off % 2 == 0 ? -1 : 1, off / 2 == 0 ? -1 : 1)), + metaFg, + range_String(&icon)); + } + } drawRange_Text( - font, cPos, d->listItem.isSelected ? iconColor : metaFg, range_String(&icon)); + font, cPos, d->listItem.isSelected ? iconColor : uiBackgroundSidebar_ColorId /*metaFg*/, range_String(&icon)); deinit_String(&icon); drawRange_Text(d->listItem.isSelected ? sidebar->itemFonts[1] : font, add_I2(cPos, init_I2(indent, 0)), -- cgit v1.2.3 From 4b50a09a4c835c23ff0ff389e976f2539d41f61b Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 14:30:24 +0300 Subject: Added a preference variable for UI animations Not yet in the UI, though. --- src/prefs.c | 1 + src/prefs.h | 1 + src/ui/mobile.c | 16 +++++++++------- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src/ui') diff --git a/src/prefs.c b/src/prefs.c index e6eba2a6..96fa3c59 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -33,6 +33,7 @@ void init_Prefs(iPrefs *d) { d->accent = cyan_ColorAccent; d->customFrame = iFalse; /* needs some more work to be default */ d->retainWindowSize = iTrue; + d->uiAnimations = iTrue; d->uiScale = 1.0f; /* default set elsewhere */ d->zoomPercent = 100; d->sideIcon = iTrue; diff --git a/src/prefs.h b/src/prefs.h index 0f604ee2..5c01ebda 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -47,6 +47,7 @@ struct Impl_Prefs { enum iColorAccent accent; iBool customFrame; /* when LAGRANGE_ENABLE_CUSTOM_FRAME is defined */ iBool retainWindowSize; + iBool uiAnimations; float uiScale; int zoomPercent; iBool sideIcon; diff --git a/src/ui/mobile.c b/src/ui/mobile.c index d678f3e1..263fc141 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c @@ -788,13 +788,15 @@ void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { if (!useMobileSheetLayout_()) { - setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); - if (isIncoming) { - setVisualOffset_Widget(sheet, -height_Widget(sheet), 0, 0); - setVisualOffset_Widget(sheet, 0, 200, easeOut_AnimFlag | softer_AnimFlag); - } - else { - setVisualOffset_Widget(sheet, -height_Widget(sheet), 200, easeIn_AnimFlag); + if (prefs_App()->uiAnimations) { + setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); + if (isIncoming) { + setVisualOffset_Widget(sheet, -height_Widget(sheet), 0, 0); + setVisualOffset_Widget(sheet, 0, 200, easeOut_AnimFlag | softer_AnimFlag); + } + else { + setVisualOffset_Widget(sheet, -height_Widget(sheet), 200, easeIn_AnimFlag); + } } return; } -- cgit v1.2.3 From 202e2a95e8f93d520377a03d0bc2c0c44cce95ab Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 14:31:09 +0300 Subject: Identity creation user experience Revised the New Identity dialog to hide the additional fields by default. Added a new option to select where the new identity will be active (current domain/page/nowhere). When the new identity is automatically activated, reload the URL used for activation. --- po/en.po | 8 +++++- res/lang/de.bin | Bin 20305 -> 20358 bytes res/lang/en.bin | Bin 19054 -> 19106 bytes res/lang/es.bin | Bin 21021 -> 21074 bytes res/lang/fi.bin | Bin 20995 -> 21048 bytes res/lang/fr.bin | Bin 21511 -> 21564 bytes res/lang/ia.bin | Bin 21212 -> 21265 bytes res/lang/ie.bin | Bin 20383 -> 20436 bytes res/lang/pl.bin | Bin 22016 -> 22069 bytes res/lang/ru.bin | Bin 32094 -> 32147 bytes res/lang/sr.bin | Bin 30673 -> 30726 bytes res/lang/tok.bin | Bin 19417 -> 19470 bytes res/lang/zh_Hans.bin | Bin 18176 -> 18229 bytes res/lang/zh_Hant.bin | Bin 18250 -> 18303 bytes src/app.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/ui/util.c | 54 ++++++++++++++++++++++++++----------- 16 files changed, 117 insertions(+), 19 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index 60beade4..a89221d0 100644 --- a/po/en.po +++ b/po/en.po @@ -916,7 +916,7 @@ msgid "dlg.newident.until" msgstr "Valid until:" msgid "hint.newident.date" -msgstr "YYYY-MM-DD HH:MM:SS" +msgstr "YYYY or YYYY-MM-DD" msgid "hint.newident.optional" msgstr "optional" @@ -930,6 +930,9 @@ msgstr "Temporary:" msgid "dlg.newident.notsaved" msgstr "not saved to disk" +msgid "dlg.newident.scope" +msgstr "Use on:" + msgid "dlg.newident.email" msgstr "Email:" @@ -945,6 +948,9 @@ msgstr "Organization:" msgid "dlg.newident.country" msgstr "Country:" +msgid "dlg.newident.more" +msgstr "More…" + msgid "dlg.newident.create" msgstr "Create Identity" diff --git a/res/lang/de.bin b/res/lang/de.bin index 45c01abd..4c2c53ea 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index 0a9a3c0f..d6dfc691 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index 0d3e80c7..4a9b3cb5 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 00039ebd..da1eeeb7 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index 139f8e51..80ca94cf 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index e7607899..51be909b 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 79b517df..1a2223c8 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index e208f3ba..52ff43ae 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index 4e775c94..4c015ac3 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 19408d1a..4f06505d 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index 2d8017cb..f15c88fa 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 171bd2a8..f4b7ef15 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index 6518c7bf..154d991d 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/app.c b/src/app.c index 3f0ec2c4..4c4d08e9 100644 --- a/src/app.c +++ b/src/app.c @@ -1653,12 +1653,36 @@ iDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) { iApp *d = &app_; + if (equal_Command(cmd, "ident.showmore")) { + iForEach(ObjectList, i, children_Widget(findChild_Widget(dlg, "headings"))) { + if (flags_Widget(i.object) & collapse_WidgetFlag) { + setFlags_Widget(i.object, hidden_WidgetFlag, iFalse); + } + } + iForEach(ObjectList, j, children_Widget(findChild_Widget(dlg, "values"))) { + if (flags_Widget(j.object) & collapse_WidgetFlag) { + setFlags_Widget(j.object, hidden_WidgetFlag, iFalse); + } + } + setFlags_Widget(child_Widget(findChild_Widget(dlg, "dialogbuttons"), 0), disabled_WidgetFlag, + iTrue); + arrange_Widget(dlg); + refresh_Widget(dlg); + return iTrue; + } + if (equal_Command(cmd, "ident.scope")) { + iLabelWidget *scope = findChild_Widget(dlg, "ident.scope"); + setText_LabelWidget(scope, + text_LabelWidget(child_Widget( + findChild_Widget(as_Widget(scope), "menu"), arg_Command(cmd)))); + return iTrue; + } if (equal_Command(cmd, "ident.temp.changed")) { setFlags_Widget( findChild_Widget(dlg, "ident.temp.note"), hidden_WidgetFlag, !arg_Command(cmd)); return iFalse; } - if (equal_Command(cmd, "ident.accept") || equal_Command(cmd, "cancel")) { + if (equal_Command(cmd, "ident.accept") || equal_Command(cmd, "ident.cancel")) { if (equal_Command(cmd, "ident.accept")) { const iString *commonName = text_InputWidget (findChild_Widget(dlg, "ident.common")); const iString *email = text_InputWidget (findChild_Widget(dlg, "ident.email")); @@ -1706,11 +1730,55 @@ static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) { } } /* The input seems fine. */ - newIdentity_GmCerts(d->certs, isTemp ? temporary_GmIdentityFlag : 0, - until, commonName, email, userId, domain, organization, country); + iGmIdentity *ident = newIdentity_GmCerts(d->certs, + isTemp ? temporary_GmIdentityFlag : 0, + until, + commonName, + email, + userId, + domain, + organization, + country); + /* Use in the chosen scope. */ { + const iLabelWidget *scope = findChild_Widget(dlg, "ident.scope"); + const iString * selLabel = text_LabelWidget(scope); + int selScope = 0; +// printf("SelLabel: %s\n", cstr_String(selLabel)); + iConstForEach(ObjectList, + i, + children_Widget(findChild_Widget(constAs_Widget(scope), "menu"))) { + if (isInstance_Object(i.object, &Class_LabelWidget)) { + const iLabelWidget *item = i.object; +// printf("itemLabel: %s\n", cstr_String(text_LabelWidget(item))); + if (equal_String(text_LabelWidget(item), selLabel)) { + break; + } + selScope++; + } + } +// printf("selScope:%d\n", selScope); + const iString *docUrl = url_DocumentWidget(document_Root(dlg->root)); + switch (selScope) { + case 0: /* current domain */ + signIn_GmCerts(d->certs, + ident, + collectNewFormat_String( + "gemini://%s", cstr_Rangecc(urlHost_String(docUrl)))); + break; + case 1: /* current page */ + signIn_GmCerts(d->certs, ident, docUrl); + break; + default: /* not used */ + break; + } + if (selScope == 0 || selScope == 1) { + postCommand_App("navigate.reload"); + } + } postCommandf_App("sidebar.mode arg:%d show:1", identities_SidebarMode); postCommand_App("idents.changed"); } + setupSheetTransition_Mobile(dlg, iFalse); destroy_Widget(dlg); return iTrue; } diff --git a/src/ui/util.c b/src/ui/util.c index 86478300..0c71cb1f 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1551,8 +1551,8 @@ void updatePreferencesLayout_Widget(iWidget *prefs) { } } -static void addDialogInputWithHeading_(iWidget *headings, iWidget *values, const char *labelText, - const char *inputId, iInputWidget *input) { +static void addDialogInputWithHeadingAndFlags_(iWidget *headings, iWidget *values, const char *labelText, + const char *inputId, iInputWidget *input, int64_t flags) { iLabelWidget *head = addChild_Widget(headings, iClob(makeHeading_Widget(labelText))); #if defined (iPlatformMobile) /* On mobile, inputs have 2 gaps of extra padding. */ @@ -1564,6 +1564,13 @@ static void addDialogInputWithHeading_(iWidget *headings, iWidget *values, const /* Ensure that the label has the same height as the input widget. */ as_Widget(head)->sizeRef = as_Widget(input); } + setFlags_Widget(as_Widget(head), flags, iTrue); + setFlags_Widget(as_Widget(input), flags, iTrue); +} + +static void addDialogInputWithHeading_(iWidget *headings, iWidget *values, const char *labelText, + const char *inputId, iInputWidget *input) { + addDialogInputWithHeadingAndFlags_(headings, values, labelText, inputId, input, 0); } iInputWidget *addTwoColumnDialogInputField_Widget(iWidget *headings, iWidget *values, @@ -2049,7 +2056,21 @@ iWidget *makeIdentityCreation_Widget(void) { page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); iWidget *values = addChildFlags_Widget( page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); + setId_Widget(headings, "headings"); + setId_Widget(values, "values"); iInputWidget *inputs[6]; + /* Where will the new identity be active on? */ { + addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.scope}"))); + const iMenuItem items[] = { + { "Current Domain", 0, 0, "ident.scope arg:0" }, + { "Current Page", 0, 0, "ident.scope arg:1" }, + { "Not Used", 0, 0, "ident.scope arg:2" }, + }; + setId_Widget(addChild_Widget(values, + iClob(makeMenuButton_LabelWidget( + items[0].label, items, iElemCount(items)))), + "ident.scope"); + } addDialogInputWithHeading_(headings, values, "${dlg.newident.until}", @@ -2066,32 +2087,35 @@ iWidget *makeIdentityCreation_Widget(void) { setFlags_Widget(tmpGroup, arrangeSize_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue); addChild_Widget(tmpGroup, iClob(makeToggle_Widget("ident.temp"))); setId_Widget( - addChildFlags_Widget( - tmpGroup, - iClob(new_LabelWidget(uiTextCaution_ColorEscape "\u26a0 ${dlg.newident.notsaved}", NULL)), - hidden_WidgetFlag | frameless_WidgetFlag), + addChildFlags_Widget(tmpGroup, + iClob(new_LabelWidget(uiTextCaution_ColorEscape warning_Icon + " ${dlg.newident.notsaved}", + NULL)), + hidden_WidgetFlag | frameless_WidgetFlag), "ident.temp.note"); addChild_Widget(values, iClob(tmpGroup)); } - addChild_Widget(headings, iClob(makePadding_Widget(gap_UI))); - addChild_Widget(values, iClob(makePadding_Widget(gap_UI))); - addDialogInputWithHeading_(headings, values, "${dlg.newident.email}", "ident.email", iClob(inputs[1] = newHint_InputWidget(0, "${hint.newident.optional}"))); - addDialogInputWithHeading_(headings, values, "${dlg.newident.userid}", "ident.userid", iClob(inputs[2] = newHint_InputWidget(0, "${hint.newident.optional}"))); - addDialogInputWithHeading_(headings, values, "${dlg.newident.domain}", "ident.domain", iClob(inputs[3] = newHint_InputWidget(0, "${hint.newident.optional}"))); - addDialogInputWithHeading_(headings, values, "${dlg.newident.org}", "ident.org", iClob(inputs[4] = newHint_InputWidget(0, "${hint.newident.optional}"))); - addDialogInputWithHeading_(headings, values, "${dlg.newident.country}", "ident.country", iClob(inputs[5] = newHint_InputWidget(0, "${hint.newident.optional}"))); + addChildFlags_Widget(headings, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag); + addChildFlags_Widget(values, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag); + addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.email}", "ident.email", iClob(inputs[1] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); + addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.userid}", "ident.userid", iClob(inputs[2] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); + addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.domain}", "ident.domain", iClob(inputs[3] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); + addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.org}", "ident.org", iClob(inputs[4] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); + addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.country}", "ident.country", iClob(inputs[5] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); arrange_Widget(dlg); for (size_t i = 0; i < iElemCount(inputs); ++i) { as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x; } addChild_Widget(dlg, iClob(makeDialogButtons_Widget( - (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, + (iMenuItem[]){ { "${dlg.newident.more}", 0, 0, "ident.showmore" }, + { "---", 0, 0, NULL }, + { "${cancel}", SDLK_ESCAPE, 0, "ident.cancel" }, { uiTextAction_ColorEscape "${dlg.newident.create}", SDLK_RETURN, KMOD_PRIMARY, "ident.accept" } }, - 2))); + 4))); addChild_Widget(get_Root()->widget, iClob(dlg)); finalizeSheet_Mobile(dlg); return dlg; -- cgit v1.2.3 From b50e6343b962fe95150feb95cf0a5d3ed9c1bcb9 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 14:54:41 +0300 Subject: Window: Allow all mouse clicks to change active split --- src/ui/window.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/ui') diff --git a/src/ui/window.c b/src/ui/window.c index 87db2f3e..96a22fee 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -858,6 +858,19 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { const iInt2 pos = coord_Window(d, event.button.x, event.button.y); event.button.x = pos.x; event.button.y = pos.y; + if (event.type == SDL_MOUSEBUTTONDOWN) { + /* Button clicks will change keyroot. */ + if (numRoots_Window(d) > 1) { + const iInt2 click = init_I2(event.button.x, event.button.y); + iForIndices(i, d->roots) { + iRoot *root = d->roots[i]; + if (root != d->keyRoot && contains_Rect(rect_Root(root), click)) { + setKeyRoot_Window(d, root); + break; + } + } + } + } } const iWidget *oldHover = d->hover; iBool wasUsed = iFalse; @@ -889,7 +902,9 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { wasUsed = dispatchEvent_Window(d, &paste); } if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_RIGHT) { - postContextClick_Window(d, &event.button); + if (postContextClick_Window(d, &event.button)) { + wasUsed = iTrue; + } } } if (isMetricsChange_UserEvent(&event)) { -- cgit v1.2.3 From 046869954cceb49f106e3a5051517050a5515b31 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 15:21:38 +0300 Subject: SidebarWidget: Highlight identities used on current domain --- src/gmcerts.c | 10 ++++++++++ src/gmcerts.h | 5 +++-- src/ui/sidebarwidget.c | 17 ++++++++++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'src/ui') diff --git a/src/gmcerts.c b/src/gmcerts.c index f86712ac..bf0f3924 100644 --- a/src/gmcerts.c +++ b/src/gmcerts.c @@ -161,6 +161,16 @@ iBool isUsedOn_GmIdentity(const iGmIdentity *d, const iString *url) { return iFalse; } +iBool isUsedOnDomain_GmIdentity(const iGmIdentity *d, const iRangecc domain) { + iConstForEach(StringSet, i, d->useUrls) { + const iRangecc host = urlHost_String(i.value); + if (equalRangeCase_Rangecc(host, domain)) { + return iTrue; + } + } + return iFalse; +} + void setUse_GmIdentity(iGmIdentity *d, const iString *url, iBool use) { if (use && isUsedOn_GmIdentity(d, url)) { return; /* Redudant. */ diff --git a/src/gmcerts.h b/src/gmcerts.h index a9859845..a962d8b6 100644 --- a/src/gmcerts.h +++ b/src/gmcerts.h @@ -44,8 +44,9 @@ struct Impl_GmIdentity { int flags; }; -iBool isUsed_GmIdentity (const iGmIdentity *); -iBool isUsedOn_GmIdentity (const iGmIdentity *, const iString *url); +iBool isUsed_GmIdentity (const iGmIdentity *); +iBool isUsedOn_GmIdentity (const iGmIdentity *, const iString *url); +iBool isUsedOnDomain_GmIdentity (const iGmIdentity *, const iRangecc domain); void setUse_GmIdentity (iGmIdentity *, const iString *url, iBool use); void clearUse_GmIdentity (iGmIdentity *); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 55c74774..aa58eb45 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -433,6 +433,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { } case identities_SidebarMode: { const iString *tabUrl = url_DocumentWidget(document_App()); + const iRangecc tabHost = urlHost_String(tabUrl); isEmpty = iTrue; iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) { const iGmIdentity *ident = i.ptr; @@ -467,6 +468,9 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { cstr_String(&ident->notes)); } item->listItem.isSelected = isActive; + if (isUsedOnDomain_GmIdentity(ident, tabHost)) { + item->indent = 1; /* will be highlighted */ + } addItem_ListWidget(d->list, item); iRelease(item); isEmpty = iFalse; @@ -1540,6 +1544,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, const int itemHeight = height_Rect(itemRect); const int iconColor = isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) : uiIcon_ColorId; + const int altIconColor = isPressing ? uiTextPressed_ColorId : uiTextCaution_ColorId; const int font = sidebar->itemFonts[d->isBold ? 1 : 0]; int bg = uiBackgroundSidebar_ColorId; if (isHover) { @@ -1730,6 +1735,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, else if (sidebar->mode == identities_SidebarMode) { const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) : uiTextStrong_ColorId; + const iBool isUsedOnDomain = (d->indent != 0); iString icon; initUnicodeN_String(&icon, &d->icon, 1); iInt2 cPos = topLeft_Rect(itemRect); @@ -1741,7 +1747,8 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId) : uiTextDim_ColorId; - if (!d->listItem.isSelected) { + if (!d->listItem.isSelected && !isUsedOnDomain) { + /* Draw an outline of the icon. */ for (int off = 0; off < 4; ++off) { drawRange_Text(font, add_I2(cPos, init_I2(off % 2 == 0 ? -1 : 1, off / 2 == 0 ? -1 : 1)), @@ -1749,8 +1756,12 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, range_String(&icon)); } } - drawRange_Text( - font, cPos, d->listItem.isSelected ? iconColor : uiBackgroundSidebar_ColorId /*metaFg*/, range_String(&icon)); + drawRange_Text(font, + cPos, + d->listItem.isSelected ? iconColor + : isUsedOnDomain ? altIconColor + : uiBackgroundSidebar_ColorId, + range_String(&icon)); deinit_String(&icon); drawRange_Text(d->listItem.isSelected ? sidebar->itemFonts[1] : font, add_I2(cPos, init_I2(indent, 0)), -- cgit v1.2.3 From e7785a9995f2b39c8e447dbf875faae66d37cf68 Mon Sep 17 00:00:00 2001 From: Raph M Date: Thu, 20 May 2021 10:05:02 -0700 Subject: Display server-returned errormsg after the user-friendly error description. Fixes #280. --- src/ui/documentwidget.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 0906a1d4..9b29c14f 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -1058,6 +1058,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode cstr_String(meta)); break; default: + appendFormat_String(src, "\n\nServer returned error: %s", cstr_String(meta)); break; } } -- cgit v1.2.3 From 5eef316269435522111db7d1b51c8a82a6ecda0d Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 21:07:03 +0300 Subject: SidebarWidget: Identities list click behavior Avoid accidental activations by never (de)activating identities based on a single click. Now both left and right mouse clicks will open the context menu. --- src/ui/listwidget.c | 7 +++++++ src/ui/listwidget.h | 1 + src/ui/sidebarwidget.c | 26 +++++++++++++------------- 3 files changed, 21 insertions(+), 13 deletions(-) (limited to 'src/ui') diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index a3406d48..a43b11ee 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c @@ -369,6 +369,13 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { return processEvent_Widget(w, ev); } +iRect itemRect_ListWidget(const iListWidget *d, size_t index) { + const iRect bounds = innerBounds_Widget(constAs_Widget(d)); + const int scrollY = pos_SmoothScroll(&d->scrollY); + return (iRect){ addY_I2(topLeft_Rect(bounds), d->itemHeight * (int) index - scrollY), + init_I2(width_Rect(bounds), d->itemHeight) }; +} + static void draw_ListWidget_(const iListWidget *d) { const iWidget *w = constAs_Widget(d); const iRect bounds = innerBounds_Widget(w); diff --git a/src/ui/listwidget.h b/src/ui/listwidget.h index 16adf664..314c183a 100644 --- a/src/ui/listwidget.h +++ b/src/ui/listwidget.h @@ -73,6 +73,7 @@ iAnyObject * hoverItem_ListWidget (iListWidget *); size_t numItems_ListWidget (const iListWidget *); int visCount_ListWidget (const iListWidget *); size_t itemIndex_ListWidget (const iListWidget *, iInt2 pos); +iRect itemRect_ListWidget (const iListWidget *, size_t index); const iAnyObject * constItem_ListWidget (const iListWidget *, size_t index); const iAnyObject * constHoverItem_ListWidget (const iListWidget *); size_t hoverItemIndex_ListWidget (const iListWidget *); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index aa58eb45..556ae951 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -766,7 +766,7 @@ static iGmIdentity *hoverIdentity_SidebarWidget_(const iSidebarWidget *d) { return iConstCast(iGmIdentity *, constHoverIdentity_SidebarWidget_(d)); } -static void itemClicked_SidebarWidget_(iSidebarWidget *d, const iSidebarItem *item) { +static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, size_t itemIndex) { setFocus_Widget(NULL); switch (d->mode) { case documentOutline_SidebarMode: { @@ -791,17 +791,16 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, const iSidebarItem *it break; } case identities_SidebarMode: { - iGmIdentity *ident = hoverIdentity_SidebarWidget_(d); - if (ident) { - const iString *tabUrl = url_DocumentWidget(document_App()); - if (isUsedOn_GmIdentity(ident, tabUrl)) { - signOut_GmCerts(certs_App(), tabUrl); - } - else { - signIn_GmCerts(certs_App(), ident, tabUrl); - } - updateItems_SidebarWidget_(d); - updateMouseHover_ListWidget(d->list); + d->contextItem = item; + d->contextIndex = itemIndex; + if (itemIndex < numItems_ListWidget(d->list)) { + updateContextMenu_SidebarWidget_(d); + arrange_Widget(d->menu); + openMenu_Widget(d->menu, + d->side == left_SideBarSide + ? topRight_Rect(itemRect_ListWidget(d->list, itemIndex)) + : addX_I2(topLeft_Rect(itemRect_ListWidget(d->list, itemIndex)), + -width_Widget(d->menu))); } break; } @@ -1065,7 +1064,8 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) return iTrue; } else if (isCommand_Widget(w, ev, "list.clicked")) { - itemClicked_SidebarWidget_(d, pointerLabel_Command(cmd, "item")); + itemClicked_SidebarWidget_( + d, pointerLabel_Command(cmd, "item"), argU32Label_Command(cmd, "arg")); return iTrue; } else if (isCommand_Widget(w, ev, "menu.closed")) { -- cgit v1.2.3 From 548034e167bd94d21ef9bcc2e6d2d8cbfaeb3d06 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 20 May 2021 21:26:39 +0300 Subject: DocumentWidget: Updated error page localization Added a new language string and blockquote styling for displaying the server's error message. IssueID #280 --- po/en.po | 3 +++ res/lang/de.bin | Bin 20358 -> 20410 bytes res/lang/en.bin | Bin 19106 -> 19158 bytes res/lang/es.bin | Bin 21074 -> 21126 bytes res/lang/fi.bin | Bin 21048 -> 21100 bytes res/lang/fr.bin | Bin 21564 -> 21616 bytes res/lang/ia.bin | Bin 21265 -> 21317 bytes res/lang/ie.bin | Bin 20436 -> 20488 bytes res/lang/pl.bin | Bin 22069 -> 22121 bytes res/lang/ru.bin | Bin 32147 -> 32199 bytes res/lang/sr.bin | Bin 30726 -> 30778 bytes res/lang/tok.bin | Bin 19470 -> 19522 bytes res/lang/zh_Hans.bin | Bin 18229 -> 18281 bytes res/lang/zh_Hant.bin | Bin 18303 -> 18355 bytes src/ui/documentwidget.c | 4 +++- 15 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index a89221d0..ef236ba8 100644 --- a/po/en.po +++ b/po/en.po @@ -597,6 +597,9 @@ msgstr "Unsubscribe" msgid "error.unsupported.suggestsave" msgstr "You can save it as a file to your Downloads folder: press %s or select \"%s\" from the menu." +msgid "error.server.msg" +msgstr "Server responded with the message:" + msgid "heading.pageinfo" msgstr "PAGE INFORMATION" diff --git a/res/lang/de.bin b/res/lang/de.bin index 4c2c53ea..e6b0de88 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index d6dfc691..dfc4039c 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index 4a9b3cb5..e8543648 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index da1eeeb7..478c20ff 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index 80ca94cf..dbad1af7 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 51be909b..3c72164f 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 1a2223c8..b5bbe210 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index 52ff43ae..ea38c272 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index 4c015ac3..73db27d2 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 4f06505d..1333959d 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index f15c88fa..b3d94d03 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index f4b7ef15..9a470421 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index 154d991d..27f84c64 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 9b29c14f..452e5508 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -1058,7 +1058,9 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode cstr_String(meta)); break; default: - appendFormat_String(src, "\n\nServer returned error: %s", cstr_String(meta)); + if (!isEmpty_String(meta)) { + appendFormat_String(src, "\n\n${error.server.msg}\n> %s", cstr_String(meta)); + } break; } } -- cgit v1.2.3 From 911a56b56c4f9ec5d0c4f1fd15189102bc97fcdb Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 21 May 2021 08:30:39 +0300 Subject: Added identity exporting Exporting an identity will display it in a new tab in PEM encoded format, where it can be saved or copied. IssueID #236 --- po/en.po | 4 +-- res/lang/de.bin | Bin 20410 -> 20430 bytes res/lang/en.bin | Bin 19158 -> 19153 bytes res/lang/es.bin | Bin 21126 -> 21146 bytes res/lang/fi.bin | Bin 21100 -> 21120 bytes res/lang/fr.bin | Bin 21616 -> 21636 bytes res/lang/ia.bin | Bin 21317 -> 21337 bytes res/lang/ie.bin | Bin 20488 -> 20508 bytes res/lang/pl.bin | Bin 22121 -> 22141 bytes res/lang/ru.bin | Bin 32199 -> 32219 bytes res/lang/sr.bin | Bin 30778 -> 30798 bytes res/lang/tok.bin | Bin 19522 -> 19542 bytes res/lang/zh_Hans.bin | Bin 18281 -> 18301 bytes res/lang/zh_Hant.bin | Bin 18355 -> 18375 bytes src/defs.h | 1 + src/gmcerts.c | 6 +++- src/gmutil.c | 3 ++ src/history.c | 5 +-- src/ui/documentwidget.c | 81 ++++++++++++++++++++++++++++++------------------ src/ui/documentwidget.h | 1 + src/ui/root.c | 5 +-- src/ui/sidebarwidget.c | 32 ++++++++++++++----- 22 files changed, 92 insertions(+), 46 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index ef236ba8..440d074f 100644 --- a/po/en.po +++ b/po/en.po @@ -542,8 +542,8 @@ msgstr "Stop Using on This Page" msgid "ident.stopuse.all" msgstr "Stop Using Everywhere" -msgid "ident.showuse" -msgstr "Show Usage" +msgid "ident.export" +msgstr "Export" msgid "heading.ident.use" msgstr "IDENTITY USAGE" diff --git a/res/lang/de.bin b/res/lang/de.bin index e6b0de88..59bde344 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index dfc4039c..a8093411 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index e8543648..c582efdc 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 478c20ff..1e155087 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index dbad1af7..1a88c420 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 3c72164f..c5800ec2 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index b5bbe210..0b4d5414 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index ea38c272..48f16b05 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index 73db27d2..48a9c7d8 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 1333959d..111528b5 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index b3d94d03..d06b4356 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 9a470421..27c269f6 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index 27f84c64..e78942bf 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/defs.h b/src/defs.h index 71719f7a..650f7e65 100644 --- a/src/defs.h +++ b/src/defs.h @@ -56,6 +56,7 @@ enum iFileVersion { #define whiteStar_Icon "\u2606" #define person_Icon "\U0001f464" #define download_Icon "\u2ba7" +#define export_Icon "\U0001f4e4" #define hourglass_Icon "\u231b" #define timer_Icon "\u23f2" #define home_Icon "\U0001f3e0" diff --git a/src/gmcerts.c b/src/gmcerts.c index bf0f3924..8577cf2b 100644 --- a/src/gmcerts.c +++ b/src/gmcerts.c @@ -201,7 +201,11 @@ void clearUse_GmIdentity(iGmIdentity *d) { } const iString *name_GmIdentity(const iGmIdentity *d) { - return collect_String(subject_TlsCertificate(d->cert)); + iString *name = collect_String(subject_TlsCertificate(d->cert)); + if (startsWith_String(name, "CN = ")) { + remove_Block(&name->chars, 0, 5); + } + return name; } iDefineTypeConstruction(GmIdentity) diff --git a/src/gmutil.c b/src/gmutil.c index 718a0a9a..2c9ba4eb 100644 --- a/src/gmutil.c +++ b/src/gmutil.c @@ -475,6 +475,9 @@ const char *mediaType_Path(const iString *path) { endsWithCase_String(path, ".hpp")) { return "text/plain"; } + else if (endsWithCase_String(path, ".pem")) { + return "application/x-pem-file"; + } else if (endsWithCase_String(path, ".zip")) { return "application/zip"; } diff --git a/src/history.c b/src/history.c index 9f4e415b..ed8e6725 100644 --- a/src/history.c +++ b/src/history.c @@ -243,7 +243,7 @@ void add_History(iHistory *d, const iString *url ){ iBool goBack_History(iHistory *d) { lock_Mutex(d->mtx); - if (d->recentPos < size_Array(&d->recent) - 1) { + if (!isEmpty_Array(&d->recent) && d->recentPos < size_Array(&d->recent) - 1) { d->recentPos++; postCommandf_Root(get_Root(), "open history:1 scroll:%f url:%s", @@ -279,7 +279,8 @@ iBool atLatest_History(const iHistory *d) { iBool atOldest_History(const iHistory *d) { iBool isOldest; - iGuardMutex(d->mtx, isOldest = (d->recentPos == size_Array(&d->recent) - 1)); + iGuardMutex(d->mtx, isOldest = (isEmpty_Array(&d->recent) || + d->recentPos == size_Array(&d->recent) - 1)); return isOldest; } diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 452e5508..337e2a03 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -976,7 +976,7 @@ iBool isPinned_DocumentWidget_(const iDocumentWidget *d) { static void showOrHidePinningIndicator_DocumentWidget_(iDocumentWidget *d) { iWidget *w = as_Widget(d); - showCollapsed_Widget(findChild_Widget(root_Widget(as_Widget(d)), "document.pinned"), + showCollapsed_Widget(findChild_Widget(root_Widget(w), "document.pinned"), isPinned_DocumentWidget_(d)); } @@ -1214,7 +1214,9 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse setRange_String(&d->sourceMime, param); } else if (startsWith_Rangecc(param, "text/") || - equal_Rangecc(param, "application/json")) { + equal_Rangecc(param, "application/json") || + equal_Rangecc(param, "application/x-pem-file") || + equal_Rangecc(param, "application/pem-certificate-chain")) { docFormat = plainText_GmDocumentFormat; setRange_String(&d->sourceMime, param); } @@ -1383,37 +1385,42 @@ static void cacheDocumentGlyphs_DocumentWidget_(const iDocumentWidget *d) { } } +static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float normScrollY, + const iGmResponse *resp) { + setLinkNumberMode_DocumentWidget_(d, iFalse); + clear_ObjectList(d->media); + delete_Gempub(d->sourceGempub); + d->sourceGempub = NULL; + reset_GmDocument(d->doc); + resetWideRuns_DocumentWidget_(d); + d->state = fetching_RequestState; + /* Do the fetch. */ { + d->initNormScrollY = normScrollY; + /* Use the cached response data. */ + updateTrust_DocumentWidget_(d, resp); + d->sourceTime = resp->when; + d->sourceStatus = success_GmStatusCode; + format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached")); + set_Block(&d->sourceContent, &resp->body); + updateDocument_DocumentWidget_(d, resp, iTrue); + postProcessRequestContent_DocumentWidget_(d, iTrue); + } + d->state = ready_RequestState; + init_Anim(&d->altTextOpacity, 0); + reset_SmoothScroll(&d->scrollY); + init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); + updateSideOpacity_DocumentWidget_(d, iFalse); + updateVisible_DocumentWidget_(d); + moveSpan_SmoothScroll(&d->scrollY, 0, 0); /* clamp position to new max */ + cacheDocumentGlyphs_DocumentWidget_(d); + d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; + postCommandf_Root(as_Widget(d)->root, "document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); +} + static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { const iRecentUrl *recent = findUrl_History(d->mod.history, d->mod.url); if (recent && recent->cachedResponse) { - const iGmResponse *resp = recent->cachedResponse; - clear_ObjectList(d->media); - delete_Gempub(d->sourceGempub); - d->sourceGempub = NULL; - reset_GmDocument(d->doc); - resetWideRuns_DocumentWidget_(d); - d->state = fetching_RequestState; - /* Do the fetch. */ { - d->initNormScrollY = recent->normScrollY; - /* Use the cached response data. */ - updateTrust_DocumentWidget_(d, resp); - d->sourceTime = resp->when; - d->sourceStatus = success_GmStatusCode; - format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached")); - set_Block(&d->sourceContent, &resp->body); - updateDocument_DocumentWidget_(d, resp, iTrue); - postProcessRequestContent_DocumentWidget_(d, iTrue); - } - d->state = ready_RequestState; - init_Anim(&d->altTextOpacity, 0); - reset_SmoothScroll(&d->scrollY); - init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); - updateSideOpacity_DocumentWidget_(d, iFalse); - updateVisible_DocumentWidget_(d); - moveSpan_SmoothScroll(&d->scrollY, 0, 0); /* clamp position to new max */ - cacheDocumentGlyphs_DocumentWidget_(d); - d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; - postCommandf_Root(as_Widget(d)->root, "document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); + updateFromCachedResponse_DocumentWidget_(d, recent->normScrollY, recent->cachedResponse); return iTrue; } else if (!isEmpty_String(d->mod.url)) { @@ -4413,6 +4420,20 @@ void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBoo } } +void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime, + const iBlock *source) { + setLinkNumberMode_DocumentWidget_(d, iFalse); + set_String(d->mod.url, url); + parseUser_DocumentWidget_(d); + iGmResponse *resp = new_GmResponse(); + resp->statusCode = success_GmStatusCode; + initCurrent_Time(&resp->when); + set_String(&resp->meta, mime); + set_Block(&resp->body, source); + updateFromCachedResponse_DocumentWidget_(d, 0, resp); + delete_GmResponse(resp); +} + iDocumentWidget *duplicate_DocumentWidget(const iDocumentWidget *orig) { iDocumentWidget *d = new_DocumentWidget(); delete_History(d->mod.history); diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h index 12603437..c038f981 100644 --- a/src/ui/documentwidget.h +++ b/src/ui/documentwidget.h @@ -47,6 +47,7 @@ int documentWidth_DocumentWidget (const iDocumentWidget *); void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); void setUrlFromCache_DocumentWidget (iDocumentWidget *, const iString *url, iBool isFromCache); +void setUrlAndSource_DocumentWidget (iDocumentWidget *, const iString *url, const iString *mime, const iBlock *source); void setInitialScroll_DocumentWidget (iDocumentWidget *, float normScrollY); /* set after content received */ void setRedirectCount_DocumentWidget (iDocumentWidget *, int count); void setSource_DocumentWidget (iDocumentWidget *, const iString *sourceText); diff --git a/src/ui/root.c b/src/ui/root.c index 1698a5d4..9a089992 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -438,10 +438,7 @@ static void updateNavBarIdentity_(iWidget *navBar) { setFlags_Widget(tool, selected_WidgetFlag, ident != NULL); /* Update menu. */ iLabelWidget *idItem = child_Widget(findChild_Widget(button, "menu"), 0); - iString *subjectName = ident ? collect_String(subject_TlsCertificate(ident->cert)) : NULL; - if (subjectName && startsWith_String(subjectName, "CN = ")) { - remove_Block(&subjectName->chars, 0, 5); - } + const iString *subjectName = ident ? name_GmIdentity(ident) : NULL; setTextCStr_LabelWidget( idItem, subjectName ? format_CStr(uiTextAction_ColorEscape "%s", cstr_String(subjectName)) diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 556ae951..f9bdbf67 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -169,9 +169,10 @@ static void updateContextMenu_SidebarWidget_(iSidebarWidget *d) { { "---", 0, 0, NULL }, { edit_Icon " ${menu.edit.notes}", 0, 0, "ident.edit" }, { "${ident.fingerprint}", 0, 0, "ident.fingerprint" }, + { export_Icon " ${ident.export}", 0, 0, "ident.export" }, { "---", 0, 0, NULL }, { delete_Icon " " uiTextCaution_ColorEscape "${ident.delete}", 0, 0, "ident.delete confirm:1" }, - }, 8); + }, 9); /* Used URLs. */ const iGmIdentity *ident = menuIdentity_SidebarWidget_(d); if (ident) { @@ -440,10 +441,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { iSidebarItem *item = new_SidebarItem(); item->id = (uint32_t) index_PtrArrayConstIterator(&i); item->icon = 0x1f464; /* person */ - set_String(&item->label, collect_String(subject_TlsCertificate(ident->cert))); - if (startsWith_String(&item->label, "CN = ")) { - remove_Block(&item->label.chars, 0, 5); - } + set_String(&item->label, name_GmIdentity(ident)); iDate until; validUntil_TlsCertificate(ident->cert, &until); const iBool isActive = isUsedOn_GmIdentity(ident, tabUrl); @@ -480,11 +478,11 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { addActionButton_SidebarWidget_(d, add_Icon " ${sidebar.action.ident.new}", "ident.new", 0); addActionButton_SidebarWidget_(d, "${sidebar.action.ident.import}", "ident.import", 0); } + /* const iMenuItem menuItems[] = { { person_Icon " ${ident.use}", 0, 0, "ident.use arg:1" }, { close_Icon " ${ident.stopuse}", 0, 0, "ident.use arg:0" }, { close_Icon " ${ident.stopuse.all}", 0, 0, "ident.use arg:0 clear:1" }, - { "${ident.showuse}", 0, 0, "ident.showuse" }, { "---", 0, 0, NULL }, { edit_Icon " ${menu.edit.notes}", 0, 0, "ident.edit" }, { "${ident.fingerprint}", 0, 0, "ident.fingerprint" }, @@ -494,6 +492,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { { delete_Icon " " uiTextCaution_ColorEscape "${ident.delete}", 0, 0, "ident.delete confirm:1" }, }; d->menu = makeMenu_Widget(as_Widget(d), menuItems, iElemCount(menuItems)); + */ break; } default: @@ -792,6 +791,9 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si } case identities_SidebarMode: { d->contextItem = item; + if (d->contextIndex != iInvalidPos) { + invalidateItem_ListWidget(d->list, d->contextIndex); + } d->contextIndex = itemIndex; if (itemIndex < numItems_ListWidget(d->list)) { updateContextMenu_SidebarWidget_(d); @@ -1277,6 +1279,20 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) } return iTrue; } + else if (isCommand_Widget(w, ev, "ident.export")) { + const iGmIdentity *ident = menuIdentity_SidebarWidget_(d); + if (ident) { + iString *pem = collect_String(pem_TlsCertificate(ident->cert)); + append_String(pem, collect_String(privateKeyPem_TlsCertificate(ident->cert))); + iDocumentWidget *expTab = newTab_App(NULL, iTrue); + setUrlAndSource_DocumentWidget( + expTab, + collectNewFormat_String("file:%s.pem", cstr_String(name_GmIdentity(ident))), + collectNewCStr_String("text/plain"), + utf8_String(pem)); + } + return iTrue; + } else if (isCommand_Widget(w, ev, "ident.setnotes")) { iGmIdentity *ident = pointerLabel_Command(cmd, "ident"); if (ident) { @@ -1385,7 +1401,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) d->contextIndex = iInvalidPos; } } - if (d->menu && ev->type == SDL_MOUSEBUTTONDOWN) { + if ((d->menu || d->mode == identities_SidebarMode )&& ev->type == SDL_MOUSEBUTTONDOWN) { if (ev->button.button == SDL_BUTTON_RIGHT) { d->contextItem = NULL; if (!isVisible_Widget(d->menu)) { @@ -1457,11 +1473,13 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) (!cmdClear && cmdUse && isUsedOn_GmIdentity(ident, docUrl)) || (!cmdClear && !cmdUse && !isUsedOn_GmIdentity(ident, docUrl))); } + /* else if (equal_Command(cmdItem, "ident.showuse")) { setFlags_Widget(as_Widget(menuItem), disabled_WidgetFlag, !isUsed_GmIdentity(ident)); } + */ } } } -- cgit v1.2.3 From 38d1b4a51e56c1125b6fb1a832a09c9201fd3edf Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 21 May 2021 10:51:44 +0300 Subject: CertImportWidget: Fixed layout issue --- src/ui/certimportwidget.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/ui') diff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c index fdc189db..e121b4d0 100644 --- a/src/ui/certimportwidget.c +++ b/src/ui/certimportwidget.c @@ -114,6 +114,7 @@ void init_CertImportWidget(iCertImportWidget *d) { setFlags_Widget(w, mouseModal_WidgetFlag | keepOnTop_WidgetFlag | arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag | centerHorizontal_WidgetFlag | + parentCannotResize_WidgetFlag | overflowScrollable_WidgetFlag, iTrue); } @@ -219,6 +220,7 @@ static iBool processEvent_CertImportWidget_(iCertImportWidget *d, const SDL_Even return iTrue; } if (isCommand_Widget(w, ev, "cancel")) { + setupSheetTransition_Mobile(w, iFalse); destroy_Widget(w); return iTrue; } @@ -226,6 +228,7 @@ static iBool processEvent_CertImportWidget_(iCertImportWidget *d, const SDL_Even if (d->cert && !isEmpty_TlsCertificate(d->cert) && hasPrivateKey_TlsCertificate(d->cert)) { importIdentity_GmCerts(certs_App(), d->cert, text_InputWidget(d->notes)); d->cert = NULL; /* taken */ + setupSheetTransition_Mobile(w, iFalse); destroy_Widget(w); postCommand_App("idents.changed"); } -- cgit v1.2.3 From 8c1ccfed06a4b986d1a4addd8c173ad6bb4d6691 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 21 May 2021 10:52:44 +0300 Subject: DocumentWidget: Scroll position vs. reload/navigating to new page --- src/ui/documentwidget.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 337e2a03..40b3d7a4 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -222,6 +222,7 @@ enum iDocumentWidgetFlag { movingSelectMarkStart_DocumentWidgetFlag = iBit(10), movingSelectMarkEnd_DocumentWidgetFlag = iBit(11), otherRootByDefault_DocumentWidgetFlag = iBit(12), /* links open to other root by default */ + urlChanged_DocumentWidgetFlag = iBit(13), }; enum iDocumentLinkOrdinalMode { @@ -1414,6 +1415,7 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n moveSpan_SmoothScroll(&d->scrollY, 0, 0); /* clamp position to new max */ cacheDocumentGlyphs_DocumentWidget_(d); d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; + d->flags &= ~urlChanged_DocumentWidgetFlag; postCommandf_Root(as_Widget(d)->root, "document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); } @@ -1662,7 +1664,10 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { break; } case categorySuccess_GmStatusCode: - //reset_SmoothScroll(&d->scrollY); + if (d->flags & urlChanged_DocumentWidgetFlag) { + /* Keep scroll position when reloading the same page. */ + reset_SmoothScroll(&d->scrollY); + } reset_GmDocument(d->doc); /* new content incoming */ delete_Gempub(d->sourceGempub); d->sourceGempub = NULL; @@ -2321,6 +2326,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) if (category_GmStatusCode(status_GmRequest(d->request)) == categorySuccess_GmStatusCode) { init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); /* TODO: unless user already scrolled! */ } + d->flags &= ~urlChanged_DocumentWidgetFlag; d->state = ready_RequestState; postProcessRequestContent_DocumentWidget_(d, iFalse); /* The response may be cached. */ @@ -4410,9 +4416,16 @@ void deserializeState_DocumentWidget(iDocumentWidget *d, iStream *ins) { updateFromHistory_DocumentWidget_(d); } +static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) { + if (!equal_String(d->mod.url, url)) { + d->flags |= urlChanged_DocumentWidgetFlag; + set_String(d->mod.url, url); + } +} + void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBool isFromCache) { setLinkNumberMode_DocumentWidget_(d, iFalse); - set_String(d->mod.url, urlFragmentStripped_String(url)); + setUrl_DocumentWidget_(d, urlFragmentStripped_String(url)); /* See if there a username in the URL. */ parseUser_DocumentWidget_(d); if (!isFromCache || !updateFromHistory_DocumentWidget_(d)) { @@ -4423,7 +4436,7 @@ void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBoo void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime, const iBlock *source) { setLinkNumberMode_DocumentWidget_(d, iFalse); - set_String(d->mod.url, url); + setUrl_DocumentWidget_(d, url); parseUser_DocumentWidget_(d); iGmResponse *resp = new_GmResponse(); resp->statusCode = success_GmStatusCode; -- cgit v1.2.3 From aa3690044d7096c20a6608a5c7fb0546d407da5a Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 21 May 2021 11:09:17 +0300 Subject: Keybindings for split view menu The split view keys now have keybindings. The default bindings for horizontal/vertical were changed to conform to Emacs (3/2). IssueID #278 --- po/en.po | 24 ++++++++++++++++++++++++ res/lang/de.bin | Bin 20430 -> 20844 bytes res/lang/en.bin | Bin 19153 -> 19567 bytes res/lang/es.bin | Bin 21146 -> 21560 bytes res/lang/fi.bin | Bin 21120 -> 21534 bytes res/lang/fr.bin | Bin 21636 -> 22050 bytes res/lang/ia.bin | Bin 21337 -> 21751 bytes res/lang/ie.bin | Bin 20508 -> 20922 bytes res/lang/pl.bin | Bin 22141 -> 22555 bytes res/lang/ru.bin | Bin 32219 -> 32633 bytes res/lang/sr.bin | Bin 30798 -> 31212 bytes res/lang/tok.bin | Bin 19542 -> 19956 bytes res/lang/zh_Hans.bin | Bin 18301 -> 18715 bytes res/lang/zh_Hant.bin | Bin 18375 -> 18789 bytes src/ui/keys.c | 12 ++++++++++++ src/ui/root.c | 4 ++-- 16 files changed, 38 insertions(+), 2 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index 440d074f..8ea38b94 100644 --- a/po/en.po +++ b/po/en.po @@ -1375,6 +1375,30 @@ msgstr "Set view split mode" msgid "keys.split.next" msgstr "Switch focus to next split" +msgid "keys.split.menu.merge" +msgstr "Split view menu: Merge tabs" + +msgid "keys.split.menu.swap" +msgstr "Split view menu: Swap sides" + +msgid "keys.split.menu.horiz" +msgstr "Split view menu: Horizontal" + +msgid "keys.split.menu.horiz12" +msgstr "Split view menu: Horizontal 1:2" + +msgid "keys.split.menu.horiz21" +msgstr "Split view menu: Horizontal 2:1" + +msgid "keys.split.menu.vert" +msgstr "Split view menu: Vertical" + +msgid "keys.split.menu.vert12" +msgstr "Split view menu: Vertical 1:2" + +msgid "keys.split.menu.vert21" +msgstr "Split view menu: Vertical 2:1" + msgid "keys.hoverurl" msgstr "Toggle show URL on hover" diff --git a/res/lang/de.bin b/res/lang/de.bin index 59bde344..d42d4cfc 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index a8093411..4b7c1af3 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index c582efdc..815cc7b0 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 1e155087..6d1eaa78 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index 1a88c420..c18cbc99 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index c5800ec2..c47e3104 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 0b4d5414..974a1310 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index 48f16b05..dd047ff9 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index 48a9c7d8..ad2ad465 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 111528b5..9c512c31 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index d06b4356..24378b1c 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 27c269f6..c1a0d4f7 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index e78942bf..adeaceeb 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/ui/keys.c b/src/ui/keys.c index 42d0d613..8af7867c 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c @@ -188,6 +188,7 @@ static void clear_Keys_(iKeys *d) { enum iBindFlag { argRepeat_BindFlag = iBit(1), argRelease_BindFlag = iBit(2), + noDirectTrigger_BindFlag = iBit(3), /* can only be triggered via LabelWidget */ }; /* TODO: This indirection could be used for localization, although all UI strings @@ -227,6 +228,14 @@ static const struct { int id; iMenuItem bind; int flags; } defaultBindings_[] = { 81, { "${keys.tab.next}", nextTab_KeyShortcut, "tabs.next" }, 0 }, { 90, { "${keys.split.menu}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" }, 0 }, { 91, { "${keys.split.next}", SDLK_TAB, KMOD_CTRL, "keyroot.next", }, 0 }, + { 92, { "${keys.split.menu.merge}", '1', 0, "ui.split arg:0", }, noDirectTrigger_BindFlag }, + { 93, { "${keys.split.menu.swap}", SDLK_x, 0, "ui.split swap:1", }, noDirectTrigger_BindFlag }, + { 94, { "${keys.split.menu.horiz}", '3', 0, "ui.split arg:3 axis:0", }, noDirectTrigger_BindFlag }, + { 95, { "${keys.split.menu.horiz12}", SDLK_d, 0, "ui.split arg:1 axis:0", }, noDirectTrigger_BindFlag }, + { 96, { "${keys.split.menu.horiz21}", SDLK_e, 0, "ui.split arg:2 axis:0", }, noDirectTrigger_BindFlag }, + { 97, { "${keys.split.menu.vert}", '2', 0, "ui.split arg:3 axis:1", }, noDirectTrigger_BindFlag }, + { 98, { "${keys.split.menu.vert12}", SDLK_f, 0, "ui.split arg:1 axis:1", }, noDirectTrigger_BindFlag }, + { 99, { "${keys.split.menu.vert21}", SDLK_r, 0, "ui.split arg:2 axis:1", }, noDirectTrigger_BindFlag }, { 100,{ "${keys.hoverurl}", '/', KMOD_PRIMARY, "prefs.hoverlink.toggle" }, 0 }, /* The following cannot currently be changed (built-in duplicates). */ #if defined (iPlatformApple) @@ -432,6 +441,9 @@ iBool processEvent_Keys(const SDL_Event *ev) { if (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) { const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod)); if (bind) { + if (bind->flags & noDirectTrigger_BindFlag) { + return iFalse; + } if (ev->type == SDL_KEYUP) { if (bind->flags & argRelease_BindFlag) { postCommandf_Root(root, "%s release:1", cstr_String(&bind->command)); diff --git a/src/ui/root.c b/src/ui/root.c index 9a089992..2a2130d8 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -1308,11 +1308,11 @@ void createUserInterface_Root(iRoot *d) { { "${menu.split.merge}", '1', 0, "ui.split arg:0" }, { "${menu.split.swap}", SDLK_x, 0, "ui.split swap:1" }, { "---", 0, 0, NULL }, - { "${menu.split.horizontal}", '2', 0, "ui.split arg:3 axis:0" }, + { "${menu.split.horizontal}", '3', 0, "ui.split arg:3 axis:0" }, { "${menu.split.horizontal} 1:2", SDLK_d, 0, "ui.split arg:1 axis:0" }, { "${menu.split.horizontal} 2:1", SDLK_e, 0, "ui.split arg:2 axis:0" }, { "---", 0, 0, NULL }, - { "${menu.split.vertical}", '3', 0, "ui.split arg:3 axis:1" }, + { "${menu.split.vertical}", '2', 0, "ui.split arg:3 axis:1" }, { "${menu.split.vertical} 1:2", SDLK_f, 0, "ui.split arg:1 axis:1" }, { "${menu.split.vertical} 2:1", SDLK_r, 0, "ui.split arg:2 axis:1" }, }, 10); -- cgit v1.2.3 From a54cdf5acad6e7081418b8fb839e89fdb5710510 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 21 May 2021 14:31:29 +0300 Subject: DocumentWidget: Cleanup Group the member variables for clarity. --- src/ui/documentwidget.c | 87 ++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 38 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 40b3d7a4..e7b412a9 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -232,15 +232,41 @@ enum iDocumentLinkOrdinalMode { struct Impl_DocumentWidget { iWidget widget; - enum iRequestState state; - iPersistentDocumentState mod; int flags; + + /* User interface: */ enum iDocumentLinkOrdinalMode ordinalMode; size_t ordinalBase; - iString * titleUser; + iRangecc selectMark; + iRangecc initialSelectMark; /* for word/line selection */ + iRangecc foundMark; + const iGmRun * grabbedPlayer; /* currently adjusting volume in a player */ + float grabbedStartVolume; + int mediaTimer; + const iGmRun * hoverPre; /* for clicking */ + const iGmRun * hoverAltPre; /* for drawing alt text */ + const iGmRun * hoverLink; + const iGmRun * contextLink; + iClick click; + iInt2 contextPos; /* coordinates of latest right click */ + int pinchZoomInitial; + int pinchZoomPosted; + iString pendingGotoHeading; + + /* Network request: */ + enum iRequestState state; iGmRequest * request; iAtomicInt isRequestUpdated; /* request has new content, need to parse it */ - iObjectList * media; + int certFlags; + iBlock * certFingerprint; + iDate certExpiry; + iString * certSubject; + int redirectCount; + iObjectList * media; /* inline media requests */ + + /* Document: */ + iPersistentDocumentState mod; + iString * titleUser; enum iGmStatusCode sourceStatus; iString sourceHeader; iString sourceMime; @@ -248,53 +274,36 @@ struct Impl_DocumentWidget { iTime sourceTime; iGempub * sourceGempub; /* NULL unless the page is Gempub content */ iGmDocument * doc; - int certFlags; - iBlock * certFingerprint; - iDate certExpiry; - iString * certSubject; - int redirectCount; - iRangecc selectMark; - iRangecc initialSelectMark; /* for word/line selection */ - iRangecc foundMark; + + /* Rendering: */ int pageMargin; + float initNormScrollY; + iSmoothScroll scrollY; + iAnim sideOpacity; + iAnim altTextOpacity; + iGmRunRange visibleRuns; iPtrArray visibleLinks; iPtrArray visiblePre; + iPtrArray visibleMedia; /* currently playing audio / ongoing downloads */ iPtrArray visibleWideRuns; /* scrollable blocks; TODO: merge into `visiblePre` */ iArray wideRunOffsets; iAnim animWideRunOffset; uint16_t animWideRunId; iGmRunRange animWideRunRange; - iPtrArray visibleMedia; /* currently playing audio / ongoing downloads */ - const iGmRun * grabbedPlayer; /* currently adjusting volume in a player */ - float grabbedStartVolume; - int mediaTimer; - const iGmRun * hoverPre; /* for clicking */ - const iGmRun * hoverAltPre; /* for drawing alt text */ - const iGmRun * hoverLink; - const iGmRun * contextLink; - iGmRunRange visibleRuns; + iDrawBufs * drawBufs; /* dynamic state for drawing */ + iVisBuf * visBuf; + iVisBufMeta * visBufMeta; iGmRunRange renderRuns; - iClick click; - iInt2 contextPos; /* coordinates of latest right click */ - iString pendingGotoHeading; - float initNormScrollY; -// iAnim scrollY; -// int overscroll; - iSmoothScroll scrollY; - iAnim sideOpacity; - iAnim altTextOpacity; + iPtrSet * invalidRuns; + + /* Widget structure: */ iScrollWidget *scroll; + iWidget * footerButtons; iWidget * menu; iWidget * playerMenu; iWidget * copyMenu; - iVisBuf * visBuf; - iVisBufMeta * visBufMeta; - iPtrSet * invalidRuns; - iDrawBufs * drawBufs; /* dynamic state for drawing */ iTranslation * translation; iWidget * phoneToolbar; - int pinchZoomInitial; - int pinchZoomPosted; }; iDefineObjectConstruction(DocumentWidget) @@ -3667,6 +3676,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { /* Preformatted runs can be scrolled. */ runOffset_DocumentWidget_(d->widget, run)); const iRect visRect = { visPos, run->visBounds.size }; +#if 0 if (run->flags & footer_GmRunFlag) { iRect footerBack = (iRect){ visPos, init_I2(width_Rect(d->widgetBounds), run->visBounds.size.y) }; @@ -3674,15 +3684,16 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { fillRect_Paint(&d->paint, footerBack, tmBackground_ColorId); return; } +#endif /* Fill the background. */ { if (run->linkId && linkFlags & isOpen_GmLinkFlag) { /* Open links get a highlighted background. */ int bg = tmBackgroundOpenLink_ColorId; const int frame = tmFrameOpenLink_ColorId; iRect wideRect = { init_I2(left_Rect(d->widgetBounds), visPos.y), - init_I2(width_Rect(d->widgetBounds) + + init_I2(width_Rect(d->widgetBounds) + width_Widget(d->widget->scroll), - height_Rect(run->visBounds)) }; + height_Rect(run->visBounds)) }; /* The first line is composed of two runs that may be drawn in either order, so only draw half of the background. */ if (run->flags & decoration_GmRunFlag) { -- cgit v1.2.3 From 55168d6431d070353d6c6d127fa9702af6442c1f Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 21 May 2021 14:47:55 +0300 Subject: DocumentWidget: Working on buttons related to page content --- src/ui/documentwidget.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index e7b412a9..e13f8da9 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -318,6 +318,7 @@ void init_DocumentWidget(iDocumentWidget *d) { init_PersistentDocumentState(&d->mod); d->flags = 0; d->phoneToolbar = NULL; + d->footerButtons = NULL; iZap(d->certExpiry); d->certFingerprint = new_Block(0); d->certFlags = 0; @@ -331,7 +332,6 @@ void init_DocumentWidget(iDocumentWidget *d) { d->redirectCount = 0; d->ordinalBase = 0; d->initNormScrollY = 0; - //init_Anim(&d->scrollY, 0); init_SmoothScroll(&d->scrollY, w, scrollBegan_DocumentWidget_); d->animWideRunId = 0; init_Anim(&d->animWideRunOffset, 0); @@ -1032,6 +1032,37 @@ static enum iGmDocumentBanner bannerType_DocumentWidget_(const iDocumentWidget * return siteDomain_GmDocumentBanner; } +static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuItem *items, size_t count) { + iWidget *w = as_Widget(d); + destroy_Widget(d->footerButtons); + d->footerButtons = NULL; + if (count == 0) { + return; + } + d->footerButtons = new_Widget(); + setFlags_Widget(d->footerButtons, + unhittable_WidgetFlag | arrangeVertical_WidgetFlag | + resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | + fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag, + iTrue); + setBackgroundColor_Widget(d->footerButtons, tmBannerBackground_ColorId); + const iRect bounds = bounds_Widget(w); + const iRect docBounds = documentBounds_DocumentWidget_(d); + const int hPad = (width_Rect(bounds) - width_Rect(docBounds)) / 2; + const int vPad = 3 * gap_UI; + setPadding_Widget(d->footerButtons, hPad, vPad, hPad, vPad); + for (size_t i = 0; i < count; ++i) { + iLabelWidget *button = + addChild_Widget(d->footerButtons, + iClob(newKeyMods_LabelWidget( + items[i].label, items[i].key, items[i].kmods, items[i].command))); + checkIcon_LabelWidget(button); + setFont_LabelWidget(button, uiContent_FontId); + } + addChild_Widget(as_Widget(d), iClob(d->footerButtons)); + arrange_Widget(d->footerButtons); +} + static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, const iString *meta) { iString *src = collectNewCStr_String("# "); @@ -1061,6 +1092,13 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode cstr_Lang("error.unsupported.suggestsave"), cstr_String(key), saveToDownloads_Label); + makeFooterButtons_DocumentWidget_( + d, + (iMenuItem[]){ { translateCStr_Lang(download_Icon " " saveToDownloads_Label), + 0, + 0, + "document.save" } }, + 1); break; } case slowDown_GmStatusCode: -- cgit v1.2.3 From 4108d5b0154775e2bf2c3af5003cf840675d789a Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 22 May 2021 08:19:00 +0300 Subject: DocumentWidget: Working on footer button positioning --- src/ui/documentwidget.c | 14 +++++++++++--- src/ui/widget.c | 4 ++++ src/ui/widget.h | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index e13f8da9..b6f9298c 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -503,7 +503,7 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { rect.size.y -= margin; } if (d->flags & centerVertically_DocumentWidgetFlag) { - const iInt2 docSize = size_GmDocument(d->doc); + const iInt2 docSize = addY_I2(size_GmDocument(d->doc), height_Widget(d->footerButtons)); if (docSize.y < rect.size.y) { /* Center vertically if short. There is one empty paragraph line's worth of margin between the banner and the page contents. */ @@ -583,7 +583,8 @@ static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) { static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { const iWidget *w = constAs_Widget(d); int sm = size_GmDocument(d->doc).y - height_Rect(bounds_Widget(w)) + - (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI; + (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI + + height_Widget(d->footerButtons); if (d->phoneToolbar) { sm += size_Root(w->root).y - top_Rect(boundsWithoutVisualOffset_Widget(d->phoneToolbar)); @@ -1040,10 +1041,12 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte return; } d->footerButtons = new_Widget(); + d->footerButtons->animOffsetRef = &d->scrollY.pos; setFlags_Widget(d->footerButtons, unhittable_WidgetFlag | arrangeVertical_WidgetFlag | resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | - fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag, + fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag | + moveToParentBottomEdge_WidgetFlag, iTrue); setBackgroundColor_Widget(d->footerButtons, tmBannerBackground_ColorId); const iRect bounds = bounds_Widget(w); @@ -1061,6 +1064,7 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte } addChild_Widget(as_Widget(d), iClob(d->footerButtons)); arrange_Widget(d->footerButtons); + arrange_Widget(w); } static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, @@ -1440,6 +1444,8 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n delete_Gempub(d->sourceGempub); d->sourceGempub = NULL; reset_GmDocument(d->doc); + destroy_Widget(d->footerButtons); + d->footerButtons = NULL; resetWideRuns_DocumentWidget_(d); d->state = fetching_RequestState; /* Do the fetch. */ { @@ -1718,6 +1724,8 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { reset_GmDocument(d->doc); /* new content incoming */ delete_Gempub(d->sourceGempub); d->sourceGempub = NULL; + destroy_Widget(d->footerButtons); + d->footerButtons = NULL; resetWideRuns_DocumentWidget_(d); updateDocument_DocumentWidget_(d, resp, iTrue); break; diff --git a/src/ui/widget.c b/src/ui/widget.c index 5502cb8e..8d9c6f3b 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -59,6 +59,7 @@ void init_Widget(iWidget *d) { d->minSize = zero_I2(); d->sizeRef = NULL; d->offsetRef = NULL; + d->animOffsetRef = NULL; d->bgColor = none_ColorId; d->frameColor = none_ColorId; init_Anim(&d->visualOffset, 0.0f); @@ -769,6 +770,9 @@ static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { pos->y += off; } } + if (d->animOffsetRef) { + pos->y -= value_Anim(d->animOffsetRef); + } if (d->flags & refChildrenOffset_WidgetFlag) { iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { const iWidget *child = i.object; diff --git a/src/ui/widget.h b/src/ui/widget.h index 79d45f23..8de62b7a 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -139,6 +139,7 @@ struct Impl_Widget { iInt2 minSize; iWidget * sizeRef; iWidget * offsetRef; + const iAnim *animOffsetRef; int padding[4]; /* left, top, right, bottom */ iAnim visualOffset; int bgColor; -- cgit v1.2.3 From fd94d906676b0dcef2b783c992f75254a61ae025 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 22 May 2021 22:24:13 +0300 Subject: Document footer buttons In some situations, e.g., when a client certificate is required but not active, make available action buttons that offer related shortcuts. Selecting or deselecting an identity for use will automatically reload the current page for convenience. Animate closing sidebars with Escape key. --- src/ui/documentwidget.c | 72 +++++++++++++++++++++++++++++++++---------------- src/ui/keys.c | 1 + src/ui/keys.h | 2 ++ src/ui/root.c | 4 +-- src/ui/sidebarwidget.c | 7 +++-- src/ui/widget.c | 6 +++++ 6 files changed, 63 insertions(+), 29 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index b6f9298c..74a101ad 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -503,7 +503,7 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { rect.size.y -= margin; } if (d->flags & centerVertically_DocumentWidgetFlag) { - const iInt2 docSize = addY_I2(size_GmDocument(d->doc), height_Widget(d->footerButtons)); + const iInt2 docSize = size_GmDocument(d->doc); if (docSize.y < rect.size.y) { /* Center vertically if short. There is one empty paragraph line's worth of margin between the banner and the page contents. */ @@ -828,6 +828,26 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { const iRangei visRange = visibleRange_DocumentWidget_(d); const iRect bounds = bounds_Widget(as_Widget(d)); const int scrollMax = scrollMax_DocumentWidget_(d); + /* Reposition the footer buttons as appropriate. */ + /* TODO: You can just position `footerButtons` here completely without having to get + `Widget` involved with the offset in any way. */ + if (d->footerButtons) { + const iRect bounds = bounds_Widget(as_Widget(d)); + const iRect docBounds = documentBounds_DocumentWidget_(d); + const int hPad = (width_Rect(bounds) - iMin(120 * gap_UI, width_Rect(docBounds))) / 2; + const int vPad = 3 * gap_UI; + setPadding_Widget(d->footerButtons, hPad, vPad, hPad, vPad); + arrange_Widget(d->footerButtons); + d->footerButtons->animOffsetRef = (scrollMax > 0 ? &d->scrollY.pos : NULL); + if (scrollMax <= 0) { + d->footerButtons->animOffsetRef = NULL; + d->footerButtons->rect.pos.y = height_Rect(bounds) - height_Widget(d->footerButtons); + } + else { + d->footerButtons->animOffsetRef = &d->scrollY.pos; + d->footerButtons->rect.pos.y = size_GmDocument(d->doc).y + 2 * gap_UI * d->pageMargin; + } + } setMax_SmoothScroll(&d->scrollY, scrollMax); setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax }); const int docSize = size_GmDocument(d->doc).y; @@ -1041,24 +1061,18 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte return; } d->footerButtons = new_Widget(); - d->footerButtons->animOffsetRef = &d->scrollY.pos; setFlags_Widget(d->footerButtons, unhittable_WidgetFlag | arrangeVertical_WidgetFlag | resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | - fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag | - moveToParentBottomEdge_WidgetFlag, + fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag, iTrue); - setBackgroundColor_Widget(d->footerButtons, tmBannerBackground_ColorId); - const iRect bounds = bounds_Widget(w); - const iRect docBounds = documentBounds_DocumentWidget_(d); - const int hPad = (width_Rect(bounds) - width_Rect(docBounds)) / 2; - const int vPad = 3 * gap_UI; - setPadding_Widget(d->footerButtons, hPad, vPad, hPad, vPad); + setBackgroundColor_Widget(d->footerButtons, tmBackground_ColorId); for (size_t i = 0; i < count; ++i) { - iLabelWidget *button = - addChild_Widget(d->footerButtons, - iClob(newKeyMods_LabelWidget( - items[i].label, items[i].key, items[i].kmods, items[i].command))); + iLabelWidget *button = addChildFlags_Widget( + d->footerButtons, + iClob(newKeyMods_LabelWidget( + items[i].label, items[i].key, items[i].kmods, items[i].command)), + alignLeft_WidgetFlag | drawKey_WidgetFlag); checkIcon_LabelWidget(button); setFont_LabelWidget(button, uiContent_FontId); } @@ -1092,10 +1106,10 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode iString *key = collectNew_String(); toString_Sym(SDLK_s, KMOD_PRIMARY, key); appendFormat_String(src, "\n```\n%s\n```\n", cstr_String(meta)); - appendFormat_String(src, - cstr_Lang("error.unsupported.suggestsave"), - cstr_String(key), - saveToDownloads_Label); +// appendFormat_String(src, +// cstr_Lang("error.unsupported.suggestsave"), +// cstr_String(key), +// saveToDownloads_Label); makeFooterButtons_DocumentWidget_( d, (iMenuItem[]){ { translateCStr_Lang(download_Icon " " saveToDownloads_Label), @@ -1116,6 +1130,13 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode break; } } + if (category_GmStatusCode(code) == categoryClientCertificate_GmStatus) { + makeFooterButtons_DocumentWidget_( + d, + (iMenuItem[]){ { leftHalf_Icon " ${menu.show.identities}", '4', KMOD_PRIMARY, "sidebar.mode arg:3 show:1" }, + { person_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" } }, + 2); + } setBanner_GmDocument(d->doc, useBanner ? bannerType_DocumentWidget_(d) : none_GmDocumentBanner); setFormat_GmDocument(d->doc, gemini_GmDocumentFormat); translate_Lang(src); @@ -1200,11 +1221,15 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool } } if (d->sourceGempub) { - if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub)) && - preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { - redoLayout_GmDocument(d->doc); - updateVisible_DocumentWidget_(d); - invalidate_DocumentWidget_(d); + if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { + makeFooterButtons_DocumentWidget_(d, (iMenuItem[]){ + { "Gempub Cover Page", 0, 0, NULL } + }, 1); + if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { + redoLayout_GmDocument(d->doc); + updateVisible_DocumentWidget_(d); + invalidate_DocumentWidget_(d); + } } if (!isCached && prefs_App()->pinSplit && equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { @@ -2108,6 +2133,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) const iBool keepCenter = equal_Command(cmd, "font.changed"); updateDocumentWidthRetainingScrollPosition_DocumentWidget_(d, keepCenter); d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; + updateVisible_DocumentWidget_(d); invalidate_DocumentWidget_(d); dealloc_VisBuf(d->visBuf); updateWindowTitle_DocumentWidget_(d); diff --git a/src/ui/keys.c b/src/ui/keys.c index 8af7867c..87a5fb88 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c @@ -237,6 +237,7 @@ static const struct { int id; iMenuItem bind; int flags; } defaultBindings_[] = { 98, { "${keys.split.menu.vert12}", SDLK_f, 0, "ui.split arg:1 axis:1", }, noDirectTrigger_BindFlag }, { 99, { "${keys.split.menu.vert21}", SDLK_r, 0, "ui.split arg:2 axis:1", }, noDirectTrigger_BindFlag }, { 100,{ "${keys.hoverurl}", '/', KMOD_PRIMARY, "prefs.hoverlink.toggle" }, 0 }, + { 110,{ "${menu.save.downloads}", SDLK_s, KMOD_PRIMARY, "document.save" }, 0 }, /* The following cannot currently be changed (built-in duplicates). */ #if defined (iPlatformApple) { 1002, { NULL, SDLK_LEFTBRACKET, KMOD_PRIMARY, "navigate.back" }, 0 }, diff --git a/src/ui/keys.h b/src/ui/keys.h index 4cbca3b7..6273027a 100644 --- a/src/ui/keys.h +++ b/src/ui/keys.h @@ -26,6 +26,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include +#define newIdentity_KeyShortcut SDLK_n, KMOD_PRIMARY | KMOD_SHIFT + #if defined (iPlatformApple) # define reload_KeyShortcut SDLK_r, KMOD_PRIMARY # define newTab_KeyShortcut SDLK_t, KMOD_PRIMARY diff --git a/src/ui/root.c b/src/ui/root.c index 2a2130d8..7a409a75 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -128,7 +128,7 @@ static const iMenuItem phoneNavMenuItems_[] = { static const iMenuItem identityButtonMenuItems_[] = { { "${menu.identity.notactive}", 0, 0, "ident.showactive" }, { "---", 0, 0, NULL }, - { add_Icon " ${menu.identity.new}", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" }, + { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" }, { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" }, { "---", 0, 0, NULL }, { person_Icon " ${menu.show.identities}", 0, 0, "toolbar.showident" }, @@ -138,7 +138,7 @@ static const iMenuItem identityButtonMenuItems_[] = { { "${menu.identity.notactive}", 0, 0, "ident.showactive" }, { "---", 0, 0, NULL }, # if !defined (iPlatformAppleDesktop) - { add_Icon " ${menu.identity.new}", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" }, + { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" }, { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" }, { "---", 0, 0, NULL }, { person_Icon " ${menu.show.identities}", '4', KMOD_PRIMARY, "sidebar.mode arg:3 show:1" }, diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index f9bdbf67..950db596 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -1249,9 +1249,11 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) } else if (arg_Command(cmd)) { signIn_GmCerts(certs_App(), ident, tabUrl); + postCommand_App("navigate.reload"); } else { signOut_GmCerts(certs_App(), tabUrl); + postCommand_App("navigate.reload"); } saveIdentities_GmCerts(certs_App()); updateItems_SidebarWidget_(d); @@ -1491,10 +1493,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) const int kmods = keyMods_Sym(ev->key.keysym.mod); /* Hide the sidebar when Escape is pressed. */ if (kmods == 0 && key == SDLK_ESCAPE && isVisible_Widget(d)) { - setFlags_Widget(w, hidden_WidgetFlag, iTrue); - arrange_Widget(w->parent); - updateSize_DocumentWidget(document_App()); - refresh_Widget(w->parent); + postCommand_Widget(d, "%s.toggle", cstr_String(id_Widget(w))); return iTrue; } } diff --git a/src/ui/widget.c b/src/ui/widget.c index 8d9c6f3b..543b8bc9 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -845,6 +845,12 @@ iBool containsExpanded_Widget(const iWidget *d, iInt2 windowCoord, int expand) { addY_I2(d->rect.size, d->flags & drawBackgroundToBottom_WidgetFlag ? size_Root(d->root).y : 0) }; + /* Apply the animated offset. (Visual offsets don't affect interaction.) */ + for (const iWidget *w = d; w; w = w->parent) { + if (w->animOffsetRef) { + windowCoord.y += value_Anim(w->animOffsetRef); + } + } return contains_Rect(expand ? expanded_Rect(bounds, init1_I2(expand)) : bounds, windowToInner_Widget(d, windowCoord)); } -- cgit v1.2.3 From 11348869069ad106d371113d4520cbd6ad2f9b03 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 25 May 2021 17:12:48 +0300 Subject: Preferences: "Close" instead of "Dismiss" IssueID #285 --- po/en.po | 4 ++-- src/ui/util.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index 8ea38b94..7e9477ab 100644 --- a/po/en.po +++ b/po/en.po @@ -108,8 +108,8 @@ msgstr "Powered by SDL 2, OpenSSL, and ☕️" msgid "cancel" msgstr "Cancel" -msgid "dismiss" -msgstr "Dismiss" +msgid "close" +msgstr "Close" msgid "dlg.message.ok" msgstr "Continue" diff --git a/src/ui/util.c b/src/ui/util.c index 0c71cb1f..6c87ba26 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1845,7 +1845,7 @@ iWidget *makePreferences_Widget(void) { updatePreferencesLayout_Widget(dlg); addChild_Widget(dlg, iClob(makeDialogButtons_Widget( - (iMenuItem[]){ { "${dismiss}", SDLK_ESCAPE, 0, "prefs.dismiss" } }, 1))); + (iMenuItem[]){ { "${close}", SDLK_ESCAPE, 0, "prefs.dismiss" } }, 1))); addChild_Widget(dlg->root->widget, iClob(dlg)); finalizeSheet_Mobile(dlg); setupSheetTransition_Mobile(dlg, iTrue); -- cgit v1.2.3 From 54d38100bb49a34f9ad11570e0144dc1ec006858 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 25 May 2021 18:21:47 +0300 Subject: Use "Close" instead of "Dismiss" IssueID #285 --- src/ui/documentwidget.c | 2 +- src/ui/translation.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 74a101ad..f7ef6d79 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -2287,7 +2287,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) if (!isEmpty_Array(items)) { pushBack_Array(items, &(iMenuItem){ "---", 0, 0, 0 }); } - pushBack_Array(items, &(iMenuItem){ "${dismiss}", 0, 0, "message.ok" }); + pushBack_Array(items, &(iMenuItem){ "${close}", 0, 0, "message.ok" }); iWidget *dlg = makeQuestion_Widget(uiHeading_ColorEscape "${heading.pageinfo}", cstr_String(msg), data_Array(items), diff --git a/src/ui/translation.c b/src/ui/translation.c index ed7e5baa..88edc48b 100644 --- a/src/ui/translation.c +++ b/src/ui/translation.c @@ -473,7 +473,7 @@ iBool handleCommand_Translation(iTranslation *d, const char *cmd) { updateTextCStr_LabelWidget( findMenuItem_Widget(findChild_Widget(d->dlg, "dialogbuttons"), "translation.cancel"), - "${dismiss}"); + "${close}"); cancel_TlsRequest(d->request); } else { -- cgit v1.2.3 From f53e6d34fbb8d2f2fb54aff8b746b1c5d06fe497 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 25 May 2021 18:25:40 +0300 Subject: Removed Symbola, replaced with other/new fonts Symbola's license is not permissive enough, so it has been removed. Added "Smol Emoji" with face emoticons and other UI characters for Lagrange. More symbols provided by Noto Sans Symbols and Noto Sans Symbols 2. The fallback fonts are now Iosevka, which has a pretty good coverage (although monospace), and the user's chosen TrueType font (which could still be a local copy of Symbola). Still a work in progress: some characters are missing. IssueID #283 --- CMakeLists.txt | 4 +- po/en.po | 3 + res/fonts/NotoSansSymbols-Regular.ttf | Bin 0 -> 168520 bytes res/fonts/NotoSansSymbols2-Regular.ttf | Bin 0 -> 583072 bytes res/fonts/SmolEmoji-Regular.ttf | Bin 0 -> 40384 bytes res/fonts/Symbola.ttf | Bin 3310696 -> 0 bytes res/lang/de.bin | Bin 20844 -> 20884 bytes res/lang/en.bin | Bin 19567 -> 19591 bytes res/lang/es.bin | Bin 21560 -> 21600 bytes res/lang/fi.bin | Bin 21534 -> 21574 bytes res/lang/fr.bin | Bin 22050 -> 22090 bytes res/lang/ia.bin | Bin 21751 -> 21791 bytes res/lang/ie.bin | Bin 20922 -> 20962 bytes res/lang/pl.bin | Bin 22555 -> 22595 bytes res/lang/ru.bin | Bin 32633 -> 32673 bytes res/lang/sr.bin | Bin 31212 -> 31252 bytes res/lang/tok.bin | Bin 19956 -> 19996 bytes res/lang/zh_Hans.bin | Bin 18715 -> 18755 bytes res/lang/zh_Hant.bin | Bin 18789 -> 18829 bytes src/app.c | 37 +++++++--- src/defs.h | 2 +- src/gmrequest.c | 4 +- src/prefs.c | 5 ++ src/prefs.h | 1 + src/ui/inputwidget.h | 5 ++ src/ui/keys.c | 8 +-- src/ui/root.c | 8 +-- src/ui/text.c | 127 +++++++++++++++++++++------------ src/ui/text.h | 16 +++-- src/ui/util.c | 2 + 30 files changed, 153 insertions(+), 69 deletions(-) create mode 100644 res/fonts/NotoSansSymbols-Regular.ttf create mode 100644 res/fonts/NotoSansSymbols2-Regular.ttf create mode 100644 res/fonts/SmolEmoji-Regular.ttf delete mode 100644 res/fonts/Symbola.ttf (limited to 'src/ui') diff --git a/CMakeLists.txt b/CMakeLists.txt index 8429193a..f48d6fdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,17 +72,19 @@ set (EMBED_RESOURCES res/fonts/NotoSansArabicUI-Regular.ttf res/fonts/NotoSansJP-Regular.ttf res/fonts/NotoSansSC-Regular.ttf + res/fonts/NotoSansSymbols-Regular.ttf + res/fonts/NotoSansSymbols2-Regular.ttf res/fonts/Nunito-Bold.ttf res/fonts/Nunito-ExtraBold.ttf res/fonts/Nunito-ExtraLight.ttf res/fonts/Nunito-LightItalic.ttf res/fonts/Nunito-Regular.ttf + res/fonts/SmolEmoji-Regular.ttf res/fonts/SourceSans3-Bold.ttf res/fonts/SourceSans3-ExtraLight.ttf res/fonts/SourceSans3-It.ttf res/fonts/SourceSans3-Regular.ttf res/fonts/SourceSans3-Semibold.ttf - res/fonts/Symbola.ttf res/lang/de.bin res/lang/en.bin res/lang/es.bin diff --git a/po/en.po b/po/en.po index 7e9477ab..96f894d1 100644 --- a/po/en.po +++ b/po/en.po @@ -1210,6 +1210,9 @@ msgstr "On Dark" msgid "prefs.boldlink.light" msgstr "On Light" +msgid "prefs.userfont" +msgstr "Symbol font:" + msgid "prefs.linewidth" msgstr "Line width:" diff --git a/res/fonts/NotoSansSymbols-Regular.ttf b/res/fonts/NotoSansSymbols-Regular.ttf new file mode 100644 index 00000000..68847551 Binary files /dev/null and b/res/fonts/NotoSansSymbols-Regular.ttf differ diff --git a/res/fonts/NotoSansSymbols2-Regular.ttf b/res/fonts/NotoSansSymbols2-Regular.ttf new file mode 100644 index 00000000..79706435 Binary files /dev/null and b/res/fonts/NotoSansSymbols2-Regular.ttf differ diff --git a/res/fonts/SmolEmoji-Regular.ttf b/res/fonts/SmolEmoji-Regular.ttf new file mode 100644 index 00000000..de7cf07f Binary files /dev/null and b/res/fonts/SmolEmoji-Regular.ttf differ diff --git a/res/fonts/Symbola.ttf b/res/fonts/Symbola.ttf deleted file mode 100644 index f4bb1b7b..00000000 Binary files a/res/fonts/Symbola.ttf and /dev/null differ diff --git a/res/lang/de.bin b/res/lang/de.bin index d42d4cfc..41e5d121 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index 4b7c1af3..c3ede7c0 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index 815cc7b0..cdf6f4fe 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 6d1eaa78..83711d2f 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index c18cbc99..0dc78464 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index c47e3104..52af09ed 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 974a1310..ccf95b6e 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index dd047ff9..3f37675f 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index ad2ad465..124a0a88 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 9c512c31..062d8c2f 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index 24378b1c..ef0f2962 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index c1a0d4f7..95be4c4f 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index adeaceeb..f53edccc 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/app.c b/src/app.c index e22ee494..bb3afea6 100644 --- a/src/app.c +++ b/src/app.c @@ -204,6 +204,7 @@ static iString *serializePrefs_App_(const iApp *d) { appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(d->window)); appendFormat_String(str, "prefs.dialogtab arg:%d\n", d->prefs.dialogTab); appendFormat_String(str, "font.set arg:%d\n", d->prefs.font); + appendFormat_String(str, "font.user path:%s\n", cstr_String(&d->prefs.symbolFontPath)); appendFormat_String(str, "headingfont.set arg:%d\n", d->prefs.headingFont); appendFormat_String(str, "zoom.set arg:%d\n", d->prefs.zoomPercent); appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); @@ -1555,24 +1556,25 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { isSelected_Widget(findChild_Widget(d, "prefs.imageloadscroll"))); postCommandf_App("hidetoolbarscroll arg:%d", isSelected_Widget(findChild_Widget(d, "prefs.hidetoolbarscroll"))); - postCommandf_App("ostheme arg:%d", - isSelected_Widget(findChild_Widget(d, "prefs.ostheme"))); + postCommandf_App("ostheme arg:%d", isSelected_Widget(findChild_Widget(d, "prefs.ostheme"))); + postCommandf_App("font.user path:%s", + cstrText_InputWidget(findChild_Widget(d, "prefs.userfont"))); postCommandf_App("decodeurls arg:%d", isSelected_Widget(findChild_Widget(d, "prefs.decodeurls"))); postCommandf_App("searchurl address:%s", - cstr_String(text_InputWidget(findChild_Widget(d, "prefs.searchurl")))); + cstrText_InputWidget(findChild_Widget(d, "prefs.searchurl"))); postCommandf_App("cachesize.set arg:%d", - toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize")))); + toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize")))); postCommandf_App("ca.file path:%s", - cstr_String(text_InputWidget(findChild_Widget(d, "prefs.ca.file")))); + cstrText_InputWidget(findChild_Widget(d, "prefs.ca.file"))); postCommandf_App("ca.path path:%s", - cstr_String(text_InputWidget(findChild_Widget(d, "prefs.ca.path")))); + cstrText_InputWidget(findChild_Widget(d, "prefs.ca.path"))); postCommandf_App("proxy.gemini address:%s", - cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.gemini")))); + cstrText_InputWidget(findChild_Widget(d, "prefs.proxy.gemini"))); postCommandf_App("proxy.gopher address:%s", - cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.gopher")))); + cstrText_InputWidget(findChild_Widget(d, "prefs.proxy.gopher"))); postCommandf_App("proxy.http address:%s", - cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.http")))); + cstrText_InputWidget(findChild_Widget(d, "prefs.proxy.http"))); const iWidget *tabs = findChild_Widget(d, "prefs.tabs"); if (tabs) { postCommandf_App("prefs.dialogtab arg:%u", @@ -1892,6 +1894,22 @@ iBool handleCommand_App(const char *cmd) { resetFonts_Text(); return iTrue; } + else if (equal_Command(cmd, "font.user")) { + const char *path = suffixPtr_Command(cmd, "path"); + if (cmp_String(&d->prefs.symbolFontPath, path)) { + if (!isFrozen) { + setFreezeDraw_Window(get_Window(), iTrue); + } + setCStr_String(&d->prefs.symbolFontPath, path); + loadUserFonts_Text(); + resetFonts_Text(); + if (!isFrozen) { + postCommand_App("font.changed"); + postCommand_App("window.unfreeze"); + } + } + return iTrue; + } else if (equal_Command(cmd, "font.set")) { if (!isFrozen) { setFreezeDraw_Window(get_Window(), iTrue); @@ -2332,6 +2350,7 @@ iBool handleCommand_App(const char *cmd) { setToggle_Widget(findChild_Widget(dlg, "prefs.archive.openindex"), d->prefs.openArchiveIndexPages); setToggle_Widget(findChild_Widget(dlg, "prefs.ostheme"), d->prefs.useSystemTheme); setToggle_Widget(findChild_Widget(dlg, "prefs.customframe"), d->prefs.customFrame); + setText_InputWidget(findChild_Widget(dlg, "prefs.userfont"), &d->prefs.symbolFontPath); updatePrefsPinSplitButtons_(dlg, d->prefs.pinSplit); updateDropdownSelection_(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.uiLanguage)); setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize); diff --git a/src/defs.h b/src/defs.h index 650f7e65..c19dd50e 100644 --- a/src/defs.h +++ b/src/defs.h @@ -62,7 +62,7 @@ enum iFileVersion { #define home_Icon "\U0001f3e0" #define edit_Icon "\u270e" #define delete_Icon "\u232b" -#define copy_Icon "\u2bba" +#define copy_Icon "\u2398" //"\u2bba" #define check_Icon "\u2714" #define ballotCheck_Icon "\U0001f5f9" #define inbox_Icon "\U0001f4e5" diff --git a/src/gmrequest.c b/src/gmrequest.c index 3dd92eec..1325c025 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c @@ -346,6 +346,7 @@ static const iBlock *replaceVariables_(const iBlock *block) { if (equal_Rangecc(name, "APP_VERSION")) { repl = range_CStr(LAGRANGE_APP_VERSION); } +#if 0 else if (startsWith_Rangecc(name, "BT:")) { /* block text */ repl = range_String(collect_String(renderBlockChars_Text( &fontFiraSansRegular_Embedded, @@ -356,12 +357,13 @@ static const iBlock *replaceVariables_(const iBlock *block) { } else if (startsWith_Rangecc(name, "ST:")) { /* shaded text */ repl = range_String(collect_String(renderBlockChars_Text( - &fontSymbola_Embedded, + &fontSmolEmojiRegular_Embedded, 20, shading_TextBlockMode, &(iString){ iBlockLiteral( name.start + 3, size_Range(&name) - 3, size_Range(&name) - 3) }))); } +#endif else if (equal_Rangecc(name, "ALT")) { #if defined (iPlatformApple) repl = range_CStr("\u2325"); diff --git a/src/prefs.c b/src/prefs.c index 96fa3c59..b29b33b5 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -68,6 +68,7 @@ void init_Prefs(iPrefs *d) { init_String(&d->httpProxy); init_String(&d->downloadDir); init_String(&d->searchUrl); + init_String(&d->symbolFontPath); /* TODO: Add some platform-specific common locations? */ if (fileExistsCStr_FileInfo("/etc/ssl/cert.pem")) { /* macOS */ setCStr_String(&d->caFile, "/etc/ssl/cert.pem"); @@ -75,9 +76,13 @@ void init_Prefs(iPrefs *d) { if (fileExistsCStr_FileInfo("/etc/ssl/certs")) { setCStr_String(&d->caPath, "/etc/ssl/certs"); } +#if defined (iPlatformAppleDesktop) + setCStr_String(&d->symbolFontPath, "/System/Library/Fonts/Apple Symbols.ttf"); +#endif } void deinit_Prefs(iPrefs *d) { + deinit_String(&d->symbolFontPath); deinit_String(&d->searchUrl); deinit_String(&d->geminiProxy); deinit_String(&d->gopherProxy); diff --git a/src/prefs.h b/src/prefs.h index 5c01ebda..7185c8f9 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -70,6 +70,7 @@ struct Impl_Prefs { iString gopherProxy; iString httpProxy; /* Style */ + iString symbolFontPath; enum iTextFont font; enum iTextFont headingFont; iBool monospaceGemini; diff --git a/src/ui/inputwidget.h b/src/ui/inputwidget.h index cb32a29c..5c39aae0 100644 --- a/src/ui/inputwidget.h +++ b/src/ui/inputwidget.h @@ -63,6 +63,11 @@ void setNotifyEdits_InputWidget (iInputWidget *, iBool notifyEdits); void setEatEscape_InputWidget (iInputWidget *, iBool eatEscape); const iString * text_InputWidget (const iInputWidget *); + +iLocalDef const char *cstrText_InputWidget(const iInputWidget *d) { + return cstr_String(text_InputWidget(d)); +} + iInputWidgetContentPadding contentPadding_InputWidget (const iInputWidget *); diff --git a/src/ui/keys.c b/src/ui/keys.c index 87a5fb88..17cc0e72 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c @@ -311,7 +311,10 @@ static iBinding *findCommand_Keys_(iKeys *d, const char *command) { static void updateLookup_Keys_(iKeys *d) { clear_PtrSet(&d->lookup); iConstForEach(Array, i, &d->bindings) { - insert_PtrSet(&d->lookup, i.value); + const iBinding *bind = i.value; + if (~bind->flags & noDirectTrigger_BindFlag) { + insert_PtrSet(&d->lookup, i.value); + } } } @@ -442,9 +445,6 @@ iBool processEvent_Keys(const SDL_Event *ev) { if (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) { const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod)); if (bind) { - if (bind->flags & noDirectTrigger_BindFlag) { - return iFalse; - } if (ev->type == SDL_KEYUP) { if (bind->flags & argRelease_BindFlag) { postCommandf_Root(root, "%s release:1", cstr_String(&bind->command)); diff --git a/src/ui/root.c b/src/ui/root.c index 7a409a75..49925856 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -156,10 +156,10 @@ static const char *pageMenuCStr_ = midEllipsis_Icon; /* TODO: A preference for these, maybe? */ static const char *stopSeqCStr_[] = { /* Corners */ - uiTextCaution_ColorEscape "\U0000230c", - uiTextCaution_ColorEscape "\U0000230d", - uiTextCaution_ColorEscape "\U0000230f", - uiTextCaution_ColorEscape "\U0000230e", + uiTextCaution_ColorEscape "\U0000231c", + uiTextCaution_ColorEscape "\U0000231d", + uiTextCaution_ColorEscape "\U0000231f", + uiTextCaution_ColorEscape "\U0000231e", #if 0 /* Rotating arrow */ uiTextCaution_ColorEscape "\U00002b62", diff --git a/src/ui/text.c b/src/ui/text.c index b0c4f557..0e6a6d32 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include +#include #include #include #include @@ -124,10 +125,6 @@ struct Impl_Font { iBool isMonospaced; iBool manualKernOnly; enum iFontSize sizeId; /* used to look up different fonts of matching size */ -// enum iFontId -// enum iFontId japaneseFont; /* font to use for Japanese glyphs */ -// enum iFontId chineseFont; /* font to use for Simplified Chinese glyphs */ -// enum iFontId koreanFont; /* font to use for Korean glyphs */ uint32_t indexTable[128 - 32]; /* quick ASCII lookup */ }; @@ -155,13 +152,12 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, d->xScale *= floorf(advance) / advance; } } - d->vertOffset = height * (1.0f - scale) / 2; - d->baseline = ascent * d->yScale; - d->sizeId = sizeId; -// d->symbolsFont = symbolsFont; -// d->japaneseFont = regularJapanese_FontId; -// d->chineseFont = regularChinese_FontId; -// d->koreanFont = regularKorean_FontId; + d->baseline = ascent * d->yScale; + d->vertOffset = height * (1.0f - scale) / 2; + if (scale > 1.0f) { + d->vertOffset /= 2; /* Tweak for Noto Sans Symbols */ + } + d->sizeId = sizeId; memset(d->indexTable, 0xff, sizeof(d->indexTable)); } @@ -215,7 +211,8 @@ struct Impl_Text { iRegExp * ansiEscape; }; -static iText text_; +static iText text_; +static iBlock *userFont_; static void initFonts_Text_(iText *d) { const float textSize = fontSize_UI * d->contentFontSize; @@ -321,27 +318,31 @@ static void initFonts_Text_(iText *d) { { &fontIosevkaTermExtended_Embedded, smallMonoSize, 1.0f, contentMonoSmall_FontSize }, { &fontIosevkaTermExtended_Embedded, monoSize, 1.0f, contentMono_FontSize }, /* extra content fonts */ - { &fontSourceSans3Regular_Embedded, textSize, scaling, contentRegular_FontSize }, - { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, contentRegular_FontSize }, + { &fontSourceSans3Regular_Embedded, textSize, scaling, contentRegular_FontSize }, +// { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, contentRegular_FontSize }, /* symbols and scripts */ -#define DEFINE_FONT_SET(data) \ - { &data, uiSize, 1.0f, uiNormal_FontSize }, \ - { &data, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, \ - { &data, uiSize * 1.333f, 1.0f, uiBig_FontSize }, \ - { &data, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, \ - { &data, textSize, 1.0f, contentRegular_FontSize }, \ - { &data, textSize * 1.200f, 1.0f, contentMedium_FontSize }, \ - { &data, textSize * 1.333f, 1.0f, contentBig_FontSize }, \ - { &data, textSize * 1.666f, 1.0f, contentLarge_FontSize }, \ - { &data, textSize * 2.000f, 1.0f, contentHuge_FontSize }, \ - { &data, smallMonoSize, 1.0f, contentMonoSmall_FontSize }, \ - { &data, monoSize, 1.0f, contentMono_FontSize } - DEFINE_FONT_SET(fontSymbola_Embedded), - DEFINE_FONT_SET(fontNotoEmojiRegular_Embedded), - DEFINE_FONT_SET(fontNotoSansJPRegular_Embedded), - DEFINE_FONT_SET(fontNotoSansSCRegular_Embedded), - DEFINE_FONT_SET(fontNanumGothicRegular_Embedded), /* TODO: should use Noto Sans here, too */ - DEFINE_FONT_SET(fontNotoSansArabicUIRegular_Embedded), +#define DEFINE_FONT_SET(data, glyphScale) \ + { (data), uiSize, glyphScale, uiNormal_FontSize }, \ + { (data), uiSize * 1.125f, glyphScale, uiMedium_FontSize }, \ + { (data), uiSize * 1.333f, glyphScale, uiBig_FontSize }, \ + { (data), uiSize * 1.666f, glyphScale, uiLarge_FontSize }, \ + { (data), textSize, glyphScale, contentRegular_FontSize }, \ + { (data), textSize * 1.200f, glyphScale, contentMedium_FontSize }, \ + { (data), textSize * 1.333f, glyphScale, contentBig_FontSize }, \ + { (data), textSize * 1.666f, glyphScale, contentLarge_FontSize }, \ + { (data), textSize * 2.000f, glyphScale, contentHuge_FontSize }, \ + { (data), smallMonoSize, glyphScale, contentMonoSmall_FontSize }, \ + { (data), monoSize, glyphScale, contentMono_FontSize } + DEFINE_FONT_SET(userFont_ ? userFont_ : &fontIosevkaTermExtended_Embedded, 1.0f), + DEFINE_FONT_SET(&fontIosevkaTermExtended_Embedded, 0.866f), + DEFINE_FONT_SET(&fontNotoSansSymbolsRegular_Embedded, 1.45f), + DEFINE_FONT_SET(&fontNotoSansSymbols2Regular_Embedded, 1.45f), + DEFINE_FONT_SET(&fontSmolEmojiRegular_Embedded, 1.0f), + DEFINE_FONT_SET(&fontNotoEmojiRegular_Embedded, 1.0f), + DEFINE_FONT_SET(&fontNotoSansJPRegular_Embedded, 1.0f), + DEFINE_FONT_SET(&fontNotoSansSCRegular_Embedded, 1.0f), + DEFINE_FONT_SET(&fontNanumGothicRegular_Embedded, 1.0f), /* TODO: should use Noto Sans here, too */ + DEFINE_FONT_SET(&fontNotoSansArabicUIRegular_Embedded, 1.0f), }; iForIndices(i, fontData) { iFont *font = &d->fonts[i]; @@ -401,8 +402,28 @@ static void deinitCache_Text_(iText *d) { SDL_DestroyTexture(d->cache); } +void loadUserFonts_Text(void) { + if (userFont_) { + delete_Block(userFont_); + userFont_ = NULL; + } + /* Load the system font. */ + const iPrefs *prefs = prefs_App(); + if (!isEmpty_String(&prefs->symbolFontPath)) { + iFile *f = new_File(&prefs->symbolFontPath); + if (open_File(f, readOnly_FileMode)) { + userFont_ = readAll_File(f); + } + else { + fprintf(stderr, "[Text] failed to open: %s\n", cstr_String(&prefs->symbolFontPath)); + } + iRelease(f); + } +} + void init_Text(SDL_Renderer *render) { iText *d = &text_; + loadUserFonts_Text(); d->contentFont = nunito_TextFont; d->headingFont = nunito_TextFont; d->contentFontSize = contentScale_Text_; @@ -542,14 +563,27 @@ static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) { } iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { + /* Smol Emoji overrides all other fonts. */ + if (ch != 0x20) { + iFont *smol = font_Text_(smolEmoji_FontId + d->sizeId); + if (smol != d && (*glyphIndex = glyphIndex_Font_(smol, ch)) != 0) { + return smol; + } + } if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { return d; } - /* Not defined in current font, try Noto Emoji (for selected characters). */ - if ((ch >= 0x1f300 && ch < 0x1f600) || (ch >= 0x1f680 && ch <= 0x1f6c5)) { - iFont *emoji = font_Text_(emoji_FontId + d->sizeId); - if (emoji != d && (*glyphIndex = glyphIndex_Font_(emoji, ch)) != 0) { - return emoji; + const int fallbacks[] = { + smolEmoji_FontId, + notoEmoji_FontId, + symbols2_FontId, + symbols_FontId + }; + /* First fallback is Smol Emoji. */ + iForIndices(i, fallbacks) { + iFont *fallback = font_Text_(fallbacks[i] + d->sizeId); + if (fallback != d && (*glyphIndex = glyphIndex_Font_(fallback, ch)) != 0) { + return fallback; } } /* Try Simplified Chinese. */ @@ -588,13 +622,18 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { return d; } #endif - /* Fall back to Symbola for anything else. */ - iFont *font = font_Text_(symbols_FontId + d->sizeId); - *glyphIndex = glyphIndex_Font_(font, ch); -// if (!*glyphIndex) { -// fprintf(stderr, "failed to find %08x (%lc)\n", ch, ch); fflush(stderr); -// } - return font; + /* User's symbols font. */ { + iFont *sys = font_Text_(userSymbols_FontId + d->sizeId); + if (sys != d && (*glyphIndex = glyphIndex_Font_(sys, ch)) != 0) { + return sys; + } + } +// iFont *font = font_Text_(iosevka_FontId + d->sizeId); +// *glyphIndex = glyphIndex_Font_(font, ch); + if (!*glyphIndex) { + fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); + } + return d; } static iGlyph *glyph_Font_(iFont *d, iChar ch) { diff --git a/src/ui/text.h b/src/ui/text.h index 044ddd32..1bb60e8b 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -68,11 +68,14 @@ enum iFontId { monospace_FontId, /* extra content fonts */ defaultContentSized_FontId, /* UI font but sized to regular_FontId */ - regularMonospace_FontId, /* symbols and scripts */ - symbols_FontId, - emoji_FontId = symbols_FontId + max_FontSize, - japanese_FontId = emoji_FontId + max_FontSize, + userSymbols_FontId, + iosevka_FontId = userSymbols_FontId + max_FontSize, + symbols_FontId = iosevka_FontId + max_FontSize, + symbols2_FontId = symbols_FontId + max_FontSize, + smolEmoji_FontId = symbols2_FontId + max_FontSize, + notoEmoji_FontId = smolEmoji_FontId + max_FontSize, + japanese_FontId = notoEmoji_FontId + max_FontSize, chineseSimplified_FontId = japanese_FontId + max_FontSize, korean_FontId = chineseSimplified_FontId + max_FontSize, arabic_FontId = korean_FontId + max_FontSize, @@ -91,7 +94,7 @@ enum iFontId { uiInput_FontId = defaultMedium_FontId, uiContent_FontId = defaultMedium_FontId, uiContentBold_FontId = defaultMediumBold_FontId, - uiContentSymbols_FontId = symbols_FontId + uiMedium_FontSize, + uiContentSymbols_FontId = symbols_FontId + uiMedium_FontSize, /* Document fonts: */ paragraph_FontId = regular_FontId, firstParagraph_FontId = medium_FontId, @@ -102,6 +105,7 @@ enum iFontId { heading2_FontId = largeBold_FontId, heading3_FontId = big_FontId, banner_FontId = largeLight_FontId, + regularMonospace_FontId = iosevka_FontId + contentRegular_FontSize }; iLocalDef iBool isJapanese_FontId(enum iFontId id) { @@ -124,6 +128,8 @@ extern int gap_Text; /* affected by content font size */ void init_Text (SDL_Renderer *); void deinit_Text (void); +void loadUserFonts_Text (void); /* based on Prefs */ + void setContentFont_Text (enum iTextFont font); void setHeadingFont_Text (enum iTextFont font); void setContentFontSize_Text (float fontSizeFactor); /* affects all except `default*` fonts */ diff --git a/src/ui/util.c b/src/ui/util.c index 6c87ba26..977eba9d 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1525,6 +1525,7 @@ void updatePreferencesLayout_Widget(iWidget *prefs) { static const char *inputIds[] = { "prefs.searchurl", "prefs.downloads", + "prefs.userfont", "prefs.ca.file", "prefs.ca.path", "prefs.proxy.gemini", @@ -1786,6 +1787,7 @@ iWidget *makePreferences_Widget(void) { updateSize_LabelWidget((iLabelWidget *) tog); } addChildFlags_Widget(values, iClob(boldLink), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); + addPrefsInputWithHeading_(headings, values, "prefs.userfont", iClob(new_InputWidget(0))); } makeTwoColumnHeading_("${heading.prefs.paragraph}", headings, values); addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.linewidth}"))); -- cgit v1.2.3 From 247b2c6cdea3e57f4d22d375b43927bc9f39efc8 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Wed, 26 May 2021 11:58:29 +0300 Subject: Fonts: Added more Smol Emoji symbols --- res/fonts/SmolEmoji-Regular.ttf | Bin 40384 -> 43704 bytes src/defs.h | 2 +- src/ui/root.c | 2 +- src/ui/text.c | 14 +++++++++++--- 4 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src/ui') diff --git a/res/fonts/SmolEmoji-Regular.ttf b/res/fonts/SmolEmoji-Regular.ttf index de7cf07f..86125852 100644 Binary files a/res/fonts/SmolEmoji-Regular.ttf and b/res/fonts/SmolEmoji-Regular.ttf differ diff --git a/src/defs.h b/src/defs.h index c19dd50e..d592abb2 100644 --- a/src/defs.h +++ b/src/defs.h @@ -92,7 +92,7 @@ enum iFileVersion { #define globe_Icon "\U0001f310" #define magnifyingGlass_Icon "\U0001f50d" #define midEllipsis_Icon "\u00b7\u00b7\u00b7" -#define return_Icon "\u21a9" +#define return_Icon "\u23ce" #if defined (iPlatformApple) # define shift_Icon "\u21e7" diff --git a/src/ui/root.c b/src/ui/root.c index 49925856..15548e74 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -1049,7 +1049,7 @@ void createUserInterface_Root(iRoot *d) { moveToParentRightEdge_WidgetFlag); /* Feeds refresh indicator is inside the input field. */ { iLabelWidget *queryInd = - new_LabelWidget(uiTextAction_ColorEscape "${status.query} \u21a9", NULL); + new_LabelWidget(uiTextAction_ColorEscape "${status.query} " return_Icon, NULL); setId_Widget(as_Widget(queryInd), "input.indicator.search"); setBackgroundColor_Widget(as_Widget(queryInd), uiBackground_ColorId); setFrameColor_Widget(as_Widget(queryInd), uiTextAction_ColorId); diff --git a/src/ui/text.c b/src/ui/text.c index 0e6a6d32..d35b470c 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -154,8 +154,13 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, } d->baseline = ascent * d->yScale; d->vertOffset = height * (1.0f - scale) / 2; - if (scale > 1.0f) { - d->vertOffset /= 2; /* Tweak for Noto Sans Symbols */ + /* Custom tweaks. */ + if (data == &fontNotoSansSymbolsRegular_Embedded || + data == &fontNotoSansSymbols2Regular_Embedded) { + d->vertOffset /= 2; + } + else if (data == &fontNotoEmojiRegular_Embedded) { + //d->vertOffset -= height / 30; } d->sizeId = sizeId; memset(d->indexTable, 0xff, sizeof(d->indexTable)); @@ -338,7 +343,7 @@ static void initFonts_Text_(iText *d) { DEFINE_FONT_SET(&fontNotoSansSymbolsRegular_Embedded, 1.45f), DEFINE_FONT_SET(&fontNotoSansSymbols2Regular_Embedded, 1.45f), DEFINE_FONT_SET(&fontSmolEmojiRegular_Embedded, 1.0f), - DEFINE_FONT_SET(&fontNotoEmojiRegular_Embedded, 1.0f), + DEFINE_FONT_SET(&fontNotoEmojiRegular_Embedded, 1.10f), DEFINE_FONT_SET(&fontNotoSansJPRegular_Embedded, 1.0f), DEFINE_FONT_SET(&fontNotoSansSCRegular_Embedded, 1.0f), DEFINE_FONT_SET(&fontNanumGothicRegular_Embedded, 1.0f), /* TODO: should use Noto Sans here, too */ @@ -563,6 +568,9 @@ static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) { } iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { + if (isVariationSelector_Char(ch)) { + return d; + } /* Smol Emoji overrides all other fonts. */ if (ch != 0x20) { iFont *smol = font_Text_(smolEmoji_FontId + d->sizeId); -- cgit v1.2.3 From 4fd7e26798fd7fe8097977ee6cbdd4614ca9fe1f Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 27 May 2021 12:23:22 +0300 Subject: Slightly larger font for audio player times The seven segment digits are coming from a different font. --- src/ui/mediaui.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/ui') diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c index 24b29cb0..bc417fc3 100644 --- a/src/ui/mediaui.c +++ b/src/ui/mediaui.c @@ -86,7 +86,7 @@ static int drawSevenSegmentTime_(iInt2 pos, int color, int align, int seconds) { const int hours = seconds / 3600; const int mins = (seconds / 60) % 60; const int secs = seconds % 60; - const int font = uiLabel_FontId; + const int font = defaultBig_FontId; iString num; init_String(&num); if (hours) { @@ -102,7 +102,7 @@ static int drawSevenSegmentTime_(iInt2 pos, int color, int align, int seconds) { if (align == right_Alignment) { pos.x -= size.x; } - drawRange_Text(font, pos, color, range_String(&num)); + drawRange_Text(font, addY_I2(pos, -gap_UI / 8), color, range_String(&num)); deinit_String(&num); return size.x; } @@ -123,7 +123,7 @@ void draw_PlayerUI(iPlayerUI *d, iPaint *p) { drawPlayerButton_( p, d->volumeRect, volumeChar_(volume_Player(d->player)), uiContentSymbols_FontId); } - const int hgt = lineHeight_Text(uiLabel_FontId); + const int hgt = lineHeight_Text(defaultBig_FontId); const int yMid = mid_Rect(d->scrubberRect).y; const float playTime = time_Player(d->player); const float totalTime = duration_Player(d->player); @@ -153,7 +153,8 @@ void draw_PlayerUI(iPlayerUI *d, iPaint *p) { const char *dot = "\u23fa"; const int dotWidth = advance_Text(uiLabel_FontId, dot).x; draw_Text(uiLabel_FontId, - init_I2(s1 * (1.0f - normPos) + s2 * normPos - dotWidth / 2, yMid - hgt / 2), + init_I2(s1 * (1.0f - normPos) + s2 * normPos - dotWidth / 2, + yMid - lineHeight_Text(uiLabel_FontId) / 2), isPaused_Player(d->player) ? dim : bright, dot); /* Volume adjustment. */ @@ -186,7 +187,8 @@ void draw_PlayerUI(iPlayerUI *d, iPaint *p) { width_Rect(d->volumeSlider) - volPart, dim); draw_Text(uiLabel_FontId, - init_I2(left_Rect(d->volumeSlider) + volPart - dotWidth / 2, yMid - hgt / 2), + init_I2(left_Rect(d->volumeSlider) + volPart - dotWidth / 2, + yMid - lineHeight_Text(uiLabel_FontId) / 2), volColor, dot); } -- cgit v1.2.3 From b924ad8d8180306f18434882ab922f8c54da4f98 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 27 May 2021 13:39:25 +0300 Subject: Fixed icon alignments Some of the icons in the Bookmarks list and lookup results were misaligned. --- src/ui/lookupwidget.c | 15 +++++++++++---- src/ui/sidebarwidget.c | 30 +++++++++++++++++++++++------- src/ui/text.c | 11 ++++++++++- src/ui/text.h | 1 + 4 files changed, 45 insertions(+), 12 deletions(-) (limited to 'src/ui') diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index 3eafd4bd..254aad93 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c @@ -127,10 +127,11 @@ static void draw_LookupItem_(iLookupItem *d, iPaint *p, iRect rect, const iListW pos.y = bottom_Rect(rect) - lineHeight_Text(d->font); } if (!isEmpty_String(&d->icon)) { - const iRect iconRect = { pos, init_I2(gap_UI * 5, height_Rect(rect)) }; - const iInt2 iconSize = measureRange_Text(d->font, range_String(&d->icon)); + const iRect iconRect = { init_I2(pos.x, top_Rect(rect)), + init_I2(gap_UI * 5, height_Rect(rect)) }; + const iRect iconVis = visualBounds_Text(d->font, range_String(&d->icon)); drawRange_Text(d->font, - addX_I2(pos, width_Rect(iconRect) / 2 - iconSize.x / 2), + sub_I2(mid_Rect(iconRect), mid_Rect(iconVis)), fg, range_String(&d->icon)); pos.x += width_Rect(iconRect) + gap_UI * 3 / 2; @@ -301,7 +302,7 @@ static void searchIdentities_LookupJob_(iLookupJob *d) { iLookupResult *res = new_LookupResult(); res->type = identity_LookupResultType; res->relevance = identityRelevance_LookupJob_(d, identity); - res->icon = identity->icon; + res->icon = 0x1f464; /* identity->icon; */ iString *cn = subject_TlsCertificate(identity->cert); set_String(&res->label, cn); delete_String(cn); @@ -701,6 +702,12 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { } return iTrue; } + if (ev->type == SDL_MOUSEMOTION) { + if (contains_Widget(w, init_I2(ev->motion.x, ev->motion.y))) { + setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_HAND); + } + return iFalse; + } if (ev->type == SDL_KEYDOWN) { const int mods = keyMods_Sym(ev->key.keysym.mod); const int key = ev->key.keysym.sym; diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 950db596..395138bb 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -1680,7 +1680,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, : uiText_ColorId; iString str; init_String(&str); - appendChar_String(&str, d->icon ? d->icon : 0x1f588); + appendChar_String(&str, d->icon ? d->icon : 0x1f588); const iRect iconArea = { addX_I2(pos, gap_UI), init_I2(1.75f * lineHeight_Text(font), itemHeight) }; drawCentered_Text(font, @@ -1694,9 +1694,13 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, deinit_String(&str); const iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2); drawRange_Text(font, textPos, fg, range_String(&d->label)); + const int metaFont = default_FontId; + const int metaIconWidth = 4.5f * gap_UI; const iInt2 metaPos = - init_I2(right_Rect(itemRect) - advanceRange_Text(font, range_String(&d->meta)).x - - 2 * gap_UI - (scrollBarWidth ? scrollBarWidth - gap_UI : 0), + init_I2(right_Rect(itemRect) - + length_String(&d->meta) * + metaIconWidth + - 2 * gap_UI - (blankWidth ? blankWidth - 1.5f * gap_UI : (gap_UI / 2)), textPos.y); fillRect_Paint(p, init_Rect(metaPos.x, @@ -1704,10 +1708,22 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, right_Rect(itemRect) - metaPos.x, height_Rect(itemRect)), bg); - drawRange_Text(font, - metaPos, - isHover && isPressing ? fg : uiTextCaution_ColorId, - range_String(&d->meta)); + iInt2 mpos = metaPos; + iStringConstIterator iter; + init_StringConstIterator(&iter, &d->meta); + iRangecc range = { cstr_String(&d->meta), iter.pos }; + while (iter.value) { + next_StringConstIterator(&iter); + range.end = iter.pos; + iRect iconArea = { mpos, init_I2(metaIconWidth, lineHeight_Text(metaFont)) }; + iRect visBounds = visualBounds_Text(metaFont, range); + drawRange_Text(metaFont, + sub_I2(mid_Rect(iconArea), mid_Rect(visBounds)), + isHover && isPressing ? fg : uiTextCaution_ColorId, + range); + mpos.x += metaIconWidth; + range.start = range.end; + } } else if (sidebar->mode == history_SidebarMode) { iBeginCollect(); diff --git a/src/ui/text.c b/src/ui/text.c index d35b470c..54b0a9da 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -1237,7 +1237,7 @@ iInt2 advanceN_Text(int fontId, const char *text, size_t n) { return init_I2(advance, lineHeight_Text(fontId)); } -static void drawBounded_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text) { +static void drawBoundedN_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text, size_t maxLen) { iText *d = &text_; iFont *font = font_Text_(fontId); const iColor clr = get_Color(color & mask_ColorId); @@ -1248,11 +1248,16 @@ static void drawBounded_Text_(int fontId, iInt2 pos, int xposBound, int color, i (color & fillBackground_ColorId ? fillBackground_RunMode : 0) | runFlagsFromId_(fontId), .text = text, + .maxLen = maxLen, .pos = pos, .xposLayoutBound = xposBound, .color = color & mask_ColorId }); } +static void drawBounded_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text) { + drawBoundedN_Text_(fontId, pos, xposBound, color, text, 0); +} + static void draw_Text_(int fontId, iInt2 pos, int color, iRangecc text) { drawBounded_Text_(fontId, pos, 0, color, text); } @@ -1295,6 +1300,10 @@ void drawRange_Text(int fontId, iInt2 pos, int color, iRangecc text) { draw_Text_(fontId, pos, color, text); } +void drawRangeN_Text(int fontId, iInt2 pos, int color, iRangecc text, size_t maxChars) { + drawBoundedN_Text_(fontId, pos, 0, color, text, maxChars); +} + iInt2 advanceWrapRange_Text(int fontId, int maxWidth, iRangecc text) { iInt2 size = zero_I2(); const char *endp; diff --git a/src/ui/text.h b/src/ui/text.h index 1bb60e8b..3dc38238 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -162,6 +162,7 @@ void drawAlign_Text (int fontId, iInt2 pos, int color, enum iAlignment a void drawCentered_Text (int fontId, iRect rect, iBool alignVisual, int color, const char *text, ...); void drawString_Text (int fontId, iInt2 pos, int color, const iString *text); void drawRange_Text (int fontId, iInt2 pos, int color, iRangecc text); +void drawRangeN_Text (int fontId, iInt2 pos, int color, iRangecc text, size_t maxLen); void drawBoundRange_Text (int fontId, iInt2 pos, int boundWidth, int color, iRangecc text); /* bound does not wrap */ int drawWrapRange_Text (int fontId, iInt2 pos, int maxWidth, int color, iRangecc text); /* returns new Y */ -- cgit v1.2.3 From d247f8b13d2bc69ed1996d247de9ca7643acdb76 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 27 May 2021 14:18:43 +0300 Subject: Fixed disappearing scrollbars Scrollbar visibility depends on it having a non-zero area. --- src/ui/listwidget.c | 9 +++++++-- src/ui/scrollwidget.c | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/ui') diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index a43b11ee..f7c43a93 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c @@ -148,11 +148,16 @@ void updateVisible_ListWidget(iListWidget *d) { const int contentSize = size_PtrArray(&d->items) * d->itemHeight; const iRect bounds = innerBounds_Widget(as_Widget(d)); const iBool wasVisible = isVisible_Widget(d->scroll); - if (area_Rect(bounds) == 0) { + if (width_Rect(bounds) <= 0 || height_Rect(bounds) <= 0) { return; } + /* The scroll widget's visibility depends on it having a valid non-zero size. + However, this may be called during arrangement (sizeChanged_ListWidget_), + which means the child hasn't been arranged yet. The child cannot update + its visibility unless it knows its correct size. */ + arrange_Widget(as_Widget(d->scroll)); setMax_SmoothScroll(&d->scrollY, scrollMax_ListWidget_(d)); - setRange_ScrollWidget(d->scroll, (iRangei){ 0, d->scrollY.max }); + setRange_ScrollWidget(d->scroll, (iRangei){ 0, d->scrollY.max }); setThumb_ScrollWidget(d->scroll, pos_SmoothScroll(&d->scrollY), contentSize > 0 ? height_Rect(bounds_Widget(as_Widget(d->scroll))) * diff --git a/src/ui/scrollwidget.c b/src/ui/scrollwidget.c index ff5144b2..0bab601a 100644 --- a/src/ui/scrollwidget.c +++ b/src/ui/scrollwidget.c @@ -54,7 +54,8 @@ struct Impl_ScrollWidget { }; static void updateMetrics_ScrollWidget_(iScrollWidget *d) { - as_Widget(d)->rect.size.x = gap_UI * 3; + iWidget *w = as_Widget(d); + w->rect.size.x = gap_UI * 3; } static void animateOpacity_ScrollWidget_(void *ptr) { -- cgit v1.2.3 From 3d25f624d92668377eac1f206a77267563db7edc Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 27 May 2021 15:02:53 +0300 Subject: DocumentWidget: Composited link numbers/letters Draw the circle and the number/letter separately since we don't have a font with all the glyphs. --- src/ui/documentwidget.c | 18 ++++++++++-------- src/ui/text.c | 9 ++++++--- src/ui/text.h | 17 +++++++++-------- 3 files changed, 25 insertions(+), 19 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index f7ef6d79..ac283a21 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -2908,7 +2908,7 @@ static size_t linkOrdinalFromKey_DocumentWidget_(const iDocumentWidget *d, int k static iChar linkOrdinalChar_DocumentWidget_(const iDocumentWidget *d, size_t ord) { if (d->ordinalMode == numbersAndAlphabet_DocumentLinkOrdinalMode) { if (ord < 9) { - return 0x278a + ord; + return '1' + ord; } #if defined (iPlatformApple) if (ord < 9 + 22) { @@ -2917,17 +2917,17 @@ static iChar linkOrdinalChar_DocumentWidget_(const iDocumentWidget *d, size_t or if (key >= 'm') key++; if (key >= 'q') key++; if (key >= 'w') key++; - return 0x24b6 + key - 'a'; + return 'A' + key - 'a'; } #else if (ord < 9 + 26) { - return 0x24b6 + ord - 9; + return 'A' + ord - 9; } #endif } else { if (ord < iElemCount(homeRowKeys_)) { - return 0x24b6 + homeRowKeys_[ord] - 'a'; + return 'A' + homeRowKeys_[ord] - 'a'; } } return 0; @@ -3818,10 +3818,12 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { const iChar ordChar = linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); if (ordChar) { - drawString_Text(run->font, - init_I2(d->viewPos.x - gap_UI / 3, visPos.y), - tmQuote_ColorId, - collect_String(newUnicodeN_String(&ordChar, 1))); + const char *circle = "\u25ef"; /* Large Circle */ + iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), + init_I2(4 * gap_UI, lineHeight_Text(run->font)) }; + drawRange_Text(run->font, topLeft_Rect(nbArea), tmQuote_ColorId, + range_CStr(circle)); + drawCentered_Text(run->font, nbArea, iTrue, tmQuote_ColorId, "%lc", (int) ordChar); goto runDrawn; } } diff --git a/src/ui/text.c b/src/ui/text.c index 54b0a9da..980f15bd 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -1341,13 +1341,16 @@ void drawCentered_Text(int fontId, iRect rect, iBool alignVisual, int color, con vprintf_Block(&chars, format, args); va_end(args); } - const iRangecc text = range_Block(&chars); - iRect textBounds = alignVisual ? visualBounds_Text(fontId, text) + drawCenteredRange_Text(fontId, rect, alignVisual, color, range_Block(&chars)); + deinit_Block(&chars); +} + +void drawCenteredRange_Text(int fontId, iRect rect, iBool alignVisual, int color, iRangecc text) { + iRect textBounds = alignVisual ? visualBounds_Text(fontId, text) : (iRect){ zero_I2(), advanceRange_Text(fontId, text) }; textBounds.pos = sub_I2(mid_Rect(rect), mid_Rect(textBounds)); textBounds.pos.x = iMax(textBounds.pos.x, left_Rect(rect)); /* keep left edge visible */ draw_Text_(fontId, textBounds.pos, color, text); - deinit_Block(&chars); } SDL_Texture *glyphCache_Text(void) { diff --git a/src/ui/text.h b/src/ui/text.h index 3dc38238..0007b264 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -157,14 +157,15 @@ void setOpacity_Text (float opacity); void cache_Text (int fontId, iRangecc text); /* pre-render glyphs */ -void draw_Text (int fontId, iInt2 pos, int color, const char *text, ...); -void drawAlign_Text (int fontId, iInt2 pos, int color, enum iAlignment align, const char *text, ...); -void drawCentered_Text (int fontId, iRect rect, iBool alignVisual, int color, const char *text, ...); -void drawString_Text (int fontId, iInt2 pos, int color, const iString *text); -void drawRange_Text (int fontId, iInt2 pos, int color, iRangecc text); -void drawRangeN_Text (int fontId, iInt2 pos, int color, iRangecc text, size_t maxLen); -void drawBoundRange_Text (int fontId, iInt2 pos, int boundWidth, int color, iRangecc text); /* bound does not wrap */ -int drawWrapRange_Text (int fontId, iInt2 pos, int maxWidth, int color, iRangecc text); /* returns new Y */ +void draw_Text (int fontId, iInt2 pos, int color, const char *text, ...); +void drawAlign_Text (int fontId, iInt2 pos, int color, enum iAlignment align, const char *text, ...); +void drawCentered_Text (int fontId, iRect rect, iBool alignVisual, int color, const char *text, ...); +void drawCenteredRange_Text (int fontId, iRect rect, iBool alignVisual, int color, iRangecc text); +void drawString_Text (int fontId, iInt2 pos, int color, const iString *text); +void drawRange_Text (int fontId, iInt2 pos, int color, iRangecc text); +void drawRangeN_Text (int fontId, iInt2 pos, int color, iRangecc text, size_t maxLen); +void drawBoundRange_Text (int fontId, iInt2 pos, int boundWidth, int color, iRangecc text); /* bound does not wrap */ +int drawWrapRange_Text (int fontId, iInt2 pos, int maxWidth, int color, iRangecc text); /* returns new Y */ SDL_Texture * glyphCache_Text (void); -- cgit v1.2.3 From a45a7dd965d0345edffd37c04c4f264a6a368f91 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 28 May 2021 06:21:46 +0300 Subject: DocumentWidget: Improved drawing of link key shortcuts --- src/ui/documentwidget.c | 15 +++++++++++---- src/ui/text.c | 4 ++-- src/ui/text.h | 3 ++- 3 files changed, 15 insertions(+), 7 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index ac283a21..f354623e 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -3820,10 +3820,17 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { if (ordChar) { const char *circle = "\u25ef"; /* Large Circle */ iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), - init_I2(4 * gap_UI, lineHeight_Text(run->font)) }; - drawRange_Text(run->font, topLeft_Rect(nbArea), tmQuote_ColorId, - range_CStr(circle)); - drawCentered_Text(run->font, nbArea, iTrue, tmQuote_ColorId, "%lc", (int) ordChar); + init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(run->font)) }; + drawRange_Text( + run->font, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); + iRect circleArea = visualBounds_Text(run->font, range_CStr(circle)); + addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); + drawCentered_Text(defaultContentSmall_FontId, + circleArea, + iTrue, + tmQuote_ColorId, + "%lc", + (int) ordChar); goto runDrawn; } } diff --git a/src/ui/text.c b/src/ui/text.c index 980f15bd..ae952df9 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -324,7 +324,7 @@ static void initFonts_Text_(iText *d) { { &fontIosevkaTermExtended_Embedded, monoSize, 1.0f, contentMono_FontSize }, /* extra content fonts */ { &fontSourceSans3Regular_Embedded, textSize, scaling, contentRegular_FontSize }, -// { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, contentRegular_FontSize }, + { &fontSourceSans3Regular_Embedded, textSize * 0.80f, scaling, contentRegular_FontSize }, /* symbols and scripts */ #define DEFINE_FONT_SET(data, glyphScale) \ { (data), uiSize, glyphScale, uiNormal_FontSize }, \ @@ -626,7 +626,7 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { /* White up arrow is used for the Shift key on macOS. Symbola's glyph is not a great match to the other text, so use the UI font instead. */ if ((ch == 0x2318 || ch == 0x21e7) && d == font_Text_(regular_FontId)) { - *glyphIndex = glyphIndex_Font_(d = font_Text_(defaultContentSized_FontId), ch); + *glyphIndex = glyphIndex_Font_(d = font_Text_(defaultContentRegular_FontId), ch); return d; } #endif diff --git a/src/ui/text.h b/src/ui/text.h index 0007b264..2f2bcf3a 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -67,7 +67,8 @@ enum iFontId { monospaceSmall_FontId, monospace_FontId, /* extra content fonts */ - defaultContentSized_FontId, /* UI font but sized to regular_FontId */ + defaultContentRegular_FontId, /* UI font but sized to regular_FontId */ + defaultContentSmall_FontId, /* UI font but sized smaller */ /* symbols and scripts */ userSymbols_FontId, iosevka_FontId = userSymbols_FontId + max_FontSize, -- cgit v1.2.3 From 3f06ba4868c974e86d616dc3049c2e5f5402e83f Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 28 May 2021 08:40:56 +0300 Subject: Lang: Translations for New Identity scopes --- po/en.po | 9 +++++++++ res/lang/de.bin | Bin 20884 -> 20997 bytes res/lang/en.bin | Bin 19591 -> 19702 bytes res/lang/es.bin | Bin 21600 -> 22044 bytes res/lang/fi.bin | Bin 21574 -> 21685 bytes res/lang/fr.bin | Bin 22090 -> 22609 bytes res/lang/ia.bin | Bin 21791 -> 21907 bytes res/lang/ie.bin | Bin 20962 -> 21075 bytes res/lang/pl.bin | Bin 22595 -> 22713 bytes res/lang/ru.bin | Bin 32673 -> 32794 bytes res/lang/sr.bin | Bin 31252 -> 31369 bytes res/lang/tok.bin | Bin 19996 -> 20112 bytes res/lang/zh_Hans.bin | Bin 18755 -> 18866 bytes res/lang/zh_Hant.bin | Bin 18829 -> 19051 bytes src/ui/util.c | 6 +++--- 15 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index 96f894d1..e32ba5c1 100644 --- a/po/en.po +++ b/po/en.po @@ -936,6 +936,15 @@ msgstr "not saved to disk" msgid "dlg.newident.scope" msgstr "Use on:" +msgid "dlg.newident.scope.domain" +msgstr "Current Domain" + +msgid "dlg.newident.scope.page" +msgstr "Current Page" + +msgid "dlg.newident.scope.none" +msgstr "Not Used" + msgid "dlg.newident.email" msgstr "Email:" diff --git a/res/lang/de.bin b/res/lang/de.bin index 41e5d121..a70f5f62 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index c3ede7c0..19650c34 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index cdf6f4fe..e4d45e79 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 83711d2f..06c815fa 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index 0dc78464..e39abdfa 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 52af09ed..0c0797eb 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index ccf95b6e..9aa66449 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index 3f37675f..6df22643 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index 124a0a88..c6ea9e0a 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 062d8c2f..a770ac48 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index ef0f2962..6335c836 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 95be4c4f..8490d0d6 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index f53edccc..b39feba1 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/ui/util.c b/src/ui/util.c index 977eba9d..edac214f 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -2064,9 +2064,9 @@ iWidget *makeIdentityCreation_Widget(void) { /* Where will the new identity be active on? */ { addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.scope}"))); const iMenuItem items[] = { - { "Current Domain", 0, 0, "ident.scope arg:0" }, - { "Current Page", 0, 0, "ident.scope arg:1" }, - { "Not Used", 0, 0, "ident.scope arg:2" }, + { "${dlg.newident.scope.domain}", 0, 0, "ident.scope arg:0" }, + { "${dlg.newident.scope.page}", 0, 0, "ident.scope arg:1" }, + { "${dlg.newident.scope.none}", 0, 0, "ident.scope arg:2" }, }; setId_Widget(addChild_Widget(values, iClob(makeMenuButton_LabelWidget( -- cgit v1.2.3 From 47024a3bd5f9b9173319a0c345e546bb573daf56 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 28 May 2021 15:03:47 +0300 Subject: Gempub: Linear navigation with left/right arrow keys --- src/defs.h | 2 ++ src/gempub.c | 37 +++++++++++++++++++++++ src/gempub.h | 4 +++ src/gmdocument.c | 3 +- src/ui/documentwidget.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 122 insertions(+), 4 deletions(-) (limited to 'src/ui') diff --git a/src/defs.h b/src/defs.h index d592abb2..d16c56f5 100644 --- a/src/defs.h +++ b/src/defs.h @@ -36,6 +36,8 @@ enum iFileVersion { /* Icons */ +#define rightArrowhead_Icon "\u27a4" +#define leftArrowhead_Icon "\u27a4" #define warning_Icon "\u26a0" #define openLock_Icon "\U0001f513" #define closedLock_Icon "\U0001f512" diff --git a/src/gempub.c b/src/gempub.c index aa03d835..f3021add 100644 --- a/src/gempub.c +++ b/src/gempub.c @@ -213,6 +213,10 @@ iBool isOpen_Gempub(const iGempub *d) { return d->arch != NULL; } +const iString *property_Gempub(const iGempub *d, enum iGempubProperty prop) { + return &d->props[prop]; +} + const iString *coverPageUrl_Gempub(const iGempub *d) { return &d->baseUrl; } @@ -232,6 +236,39 @@ const iString *navStartLinkUrl_Gempub(const iGempub *d) { return &((const iGempubNavLink *) constFront_Array(d->navLinks))->url; } +size_t navSize_Gempub(const iGempub *d) { + parseNavigationLinks_Gempub_(d); + return size_Array(d->navLinks); +} + +size_t navIndex_Gempub(const iGempub *d, const iString *url) { + parseNavigationLinks_Gempub_(d); + const iString *normUrl = withSpacesEncoded_String(url); + iConstForEach(Array, i, d->navLinks) { + const iGempubNavLink *nav = i.value; + if (equalCase_String(&nav->url, normUrl)) { + return index_ArrayConstIterator(&i); + } + } + return iInvalidPos; +} + +const iString *navLinkUrl_Gempub(const iGempub *d, size_t index) { + parseNavigationLinks_Gempub_(d); + if (index < size_Array(d->navLinks)) { + return &constValue_Array(d->navLinks, index, iGempubNavLink).url; + } + return NULL; +} + +const iString *navLinkLabel_Gempub(const iGempub *d, size_t index) { + parseNavigationLinks_Gempub_(d); + if (index < size_Array(d->navLinks)) { + return &constValue_Array(d->navLinks, index, iGempubNavLink).label; + } + return NULL; +} + static iBool hasProperty_Gempub_(const iGempub *d, enum iGempubProperty prop) { return !isEmpty_String(&d->props[prop]); } diff --git a/src/gempub.h b/src/gempub.h index 6912bcc9..c03cabe6 100644 --- a/src/gempub.h +++ b/src/gempub.h @@ -60,5 +60,9 @@ const iString * property_Gempub (const iGempub *, enum iGempubProperty); const iString * coverPageUrl_Gempub (const iGempub *); const iString * indexPageUrl_Gempub (const iGempub *); const iString * navStartLinkUrl_Gempub (const iGempub *); /* for convenience */ +size_t navSize_Gempub (const iGempub *); +size_t navIndex_Gempub (const iGempub *, const iString *url); +const iString * navLinkUrl_Gempub (const iGempub *, size_t index); +const iString * navLinkLabel_Gempub (const iGempub *, size_t index); extern const char *mimeType_Gempub; diff --git a/src/gmdocument.c b/src/gmdocument.c index ec406a63..ad8616a3 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "visited.h" #include "bookmarks.h" #include "app.h" +#include "defs.h" #include #include @@ -400,7 +401,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { static const float bottomMargin[max_GmLineType] = { 0.0f, 0.333f, 1.0f, 0.5f, 0.5f, 0.5f, 0.5f, 0.25f }; - static const char *arrow = "\u27a4"; + static const char *arrow = rightArrowhead_Icon; static const char *envelope = "\U0001f4e7"; static const char *bullet = "\u2022"; static const char *folder = "\U0001f4c1"; diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index f354623e..c8aad02b 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -1222,15 +1222,89 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool } if (d->sourceGempub) { if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { - makeFooterButtons_DocumentWidget_(d, (iMenuItem[]){ - { "Gempub Cover Page", 0, 0, NULL } - }, 1); + if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { + iArray *items = collectNew_Array(sizeof(iMenuItem)); + pushBack_Array( + items, + &(iMenuItem){ book_Icon " ${gempub.cover.view}", + 0, + 0, + format_CStr("!open url:%s", + cstr_String(indexPageUrl_Gempub(d->sourceGempub))) }); + if (navSize_Gempub(d->sourceGempub) > 0) { + pushBack_Array( + items, + &(iMenuItem){ + format_CStr(forwardArrow_Icon " %s", + cstr_String(navLinkLabel_Gempub(d->sourceGempub, 0))), + SDLK_RIGHT, + 0, + format_CStr("!open url:%s", + cstr_String(navLinkUrl_Gempub(d->sourceGempub, 0))) }); + } + makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); + } if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { redoLayout_GmDocument(d->doc); updateVisible_DocumentWidget_(d); invalidate_DocumentWidget_(d); } } + else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { + makeFooterButtons_DocumentWidget_( + d, + (iMenuItem[]){ { format_CStr(book_Icon " %s", + cstr_String(property_Gempub(d->sourceGempub, + title_GempubProperty))), + SDLK_LEFT, + 0, + format_CStr("!open url:%s", + cstr_String(coverPageUrl_Gempub(d->sourceGempub))) } }, + 1); + } + else { + /* Navigation buttons. */ + iArray *items = collectNew_Array(sizeof(iMenuItem)); + const size_t navIndex = navIndex_Gempub(d->sourceGempub, d->mod.url); + if (navIndex != iInvalidPos) { + if (navIndex < navSize_Gempub(d->sourceGempub) - 1) { + pushBack_Array( + items, + &(iMenuItem){ + format_CStr(forwardArrow_Icon " %s", + cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex + 1))), + SDLK_RIGHT, + 0, + format_CStr("!open url:%s", + cstr_String(navLinkUrl_Gempub(d->sourceGempub, navIndex + 1))) }); + } + if (navIndex > 0) { + pushBack_Array( + items, + &(iMenuItem){ + format_CStr(backArrow_Icon " %s", + cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex - 1))), + SDLK_LEFT, + 0, + format_CStr("!open url:%s", + cstr_String(navLinkUrl_Gempub(d->sourceGempub, navIndex - 1))) }); + } + else if (!equalCase_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { + pushBack_Array( + items, + &(iMenuItem){ + format_CStr(book_Icon " %s", + cstr_String(property_Gempub(d->sourceGempub, title_GempubProperty))), + SDLK_LEFT, + 0, + format_CStr("!open url:%s", + cstr_String(coverPageUrl_Gempub(d->sourceGempub))) }); + } + } + if (!isEmpty_Array(items)) { + makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); + } + } if (!isCached && prefs_App()->pinSplit && equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { const iString *navStart = navStartLinkUrl_Gempub(d->sourceGempub); -- cgit v1.2.3 From 18e590f1fd50397004113804bf1218656119d41f Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 07:14:18 +0300 Subject: Text: Use Iosevka as final fallback font --- src/ui/text.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/ui') diff --git a/src/ui/text.c b/src/ui/text.c index ae952df9..082899b0 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -582,7 +582,6 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { return d; } const int fallbacks[] = { - smolEmoji_FontId, notoEmoji_FontId, symbols2_FontId, symbols_FontId @@ -636,8 +635,11 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { return sys; } } -// iFont *font = font_Text_(iosevka_FontId + d->sizeId); -// *glyphIndex = glyphIndex_Font_(font, ch); + /* Final fallback. */ + iFont *font = font_Text_(iosevka_FontId + d->sizeId); + if (d != font) { + *glyphIndex = glyphIndex_Font_(font, ch); + } if (!*glyphIndex) { fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); } -- cgit v1.2.3 From 23e31410556e9b4e22c3742b2b137bd5d96abac8 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 07:17:45 +0300 Subject: Gempub: Fixed glitches in DocumentWidget --- po/en.po | 3 +++ res/lang/de.bin | Bin 20997 -> 21054 bytes res/lang/en.bin | Bin 19702 -> 19759 bytes res/lang/es.bin | Bin 22044 -> 22101 bytes res/lang/fi.bin | Bin 21685 -> 21742 bytes res/lang/fr.bin | Bin 22609 -> 22666 bytes res/lang/ia.bin | Bin 21907 -> 21964 bytes res/lang/ie.bin | Bin 21075 -> 21132 bytes res/lang/pl.bin | Bin 22713 -> 22770 bytes res/lang/ru.bin | Bin 32794 -> 32851 bytes res/lang/sr.bin | Bin 31369 -> 31426 bytes res/lang/tok.bin | Bin 20112 -> 20169 bytes res/lang/zh_Hans.bin | Bin 18866 -> 18923 bytes res/lang/zh_Hant.bin | Bin 19051 -> 19108 bytes src/gempub.c | 19 +++++++------ src/gempub.h | 1 + src/ui/documentwidget.c | 70 +++++++++++++++++++++++++++++++++++------------- 17 files changed, 67 insertions(+), 26 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index e32ba5c1..bbca83e5 100644 --- a/po/en.po +++ b/po/en.po @@ -191,6 +191,9 @@ msgstr "Save to Files" msgid "menu.save.downloads" msgstr "Save to Downloads" +msgid "menu.save.downloads.open" +msgstr "Save to Downloads and Open File" + msgid "menu.sidebar" msgstr "Toggle Sidebar" diff --git a/res/lang/de.bin b/res/lang/de.bin index a70f5f62..45260c31 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index 19650c34..728c7ff8 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index e4d45e79..d6cdd974 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 06c815fa..b66badcb 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index e39abdfa..232338c9 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 0c0797eb..e460faf7 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 9aa66449..87e3c0e5 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index 6df22643..0c021408 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index c6ea9e0a..17df17a8 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index a770ac48..74f897cb 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index 6335c836..4d8259b3 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 8490d0d6..c5b6cede 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index b39feba1..56d7643d 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/gempub.c b/src/gempub.c index f3021add..1f5d58ce 100644 --- a/src/gempub.c +++ b/src/gempub.c @@ -94,6 +94,9 @@ static void parseNavigationLinks_Gempub_(const iGempub *d) { set_String(&link.url, absoluteUrl_String(url_GmRequest(index), collectNewRange_String(url))); setRange_String(&link.label, capturedRange_RegExpMatch(&m, 2)); trim_String(&link.label); + if (isEmpty_String(&link.label)) { + setRange_String(&link.label, url); + } pushBack_Array(d->navLinks, &link); } iEndCollect(); @@ -280,7 +283,7 @@ static void appendProperty_Gempub_(const iGempub *d, const char *label, } } -static iBool isRemote_Gempub_(const iGempub *d) { +iBool isRemote_Gempub(const iGempub *d) { return !equalCase_Rangecc(urlScheme_String(&d->baseUrl), "file"); } @@ -295,7 +298,7 @@ iString *coverPageSource_Gempub(const iGempub *d) { } appendCStr_String(out, "\n"); appendProperty_Gempub_(d, "${gempub.meta.author}:", author_GempubProperty, out); - if (!isRemote_Gempub_(d)) { + if (!isRemote_Gempub(d)) { appendFormat_String(out, "\n=> %s " book_Icon " ${gempub.cover.view}\n", cstr_String(indexPageUrl_Gempub(d))); if (hasProperty_Gempub_(d, cover_GempubProperty)) { @@ -306,12 +309,12 @@ iString *coverPageSource_Gempub(const iGempub *d) { else { iString *key = collectNew_String(); /* TODO: add a helper for this */ toString_Sym(SDLK_s, KMOD_PRIMARY, key); - appendCStr_String(out, "\n${gempub.cover.viewlocal} "); - appendFormat_String(out, - cstr_Lang("error.unsupported.suggestsave"), - cstr_String(key), - saveToDownloads_Label); - appendCStr_String(out, "\n"); + appendCStr_String(out, "\n${gempub.cover.viewlocal}\n"); +// appendFormat_String(out, +// cstr_Lang("error.unsupported.suggestsave"), +// cstr_String(key), +// saveToDownloads_Label); +// appendCStr_String(out, "\n"); } appendCStr_String(out, "\n## ${gempub.cover.aboutbook}\n"); appendProperty_Gempub_(d, "${gempub.meta.version}:", version_GempubProperty, out); diff --git a/src/gempub.h b/src/gempub.h index c03cabe6..e5f1b8eb 100644 --- a/src/gempub.h +++ b/src/gempub.h @@ -53,6 +53,7 @@ void close_Gempub (iGempub *); void setBaseUrl_Gempub (iGempub *, const iString *baseUrl); iBool isOpen_Gempub (const iGempub *); +iBool isRemote_Gempub (const iGempub *); iString * coverPageSource_Gempub (const iGempub *); iBool preloadCoverImage_Gempub(const iGempub *, iGmDocument *doc); diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index c8aad02b..a02e0bca 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -820,6 +820,13 @@ static iRangecc currentHeading_DocumentWidget_(const iDocumentWidget *d) { return heading; } +static int updateScrollMax_DocumentWidget_(iDocumentWidget *d) { + arrange_Widget(d->footerButtons); /* scrollMax depends on footer height */ + const int scrollMax = scrollMax_DocumentWidget_(d); + setMax_SmoothScroll(&d->scrollY, scrollMax); + return scrollMax; +} + static void updateVisible_DocumentWidget_(iDocumentWidget *d) { iChangeFlags(d->flags, centerVertically_DocumentWidgetFlag, @@ -827,7 +834,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { !isSuccess_GmStatusCode(d->sourceStatus)); const iRangei visRange = visibleRange_DocumentWidget_(d); const iRect bounds = bounds_Widget(as_Widget(d)); - const int scrollMax = scrollMax_DocumentWidget_(d); + const int scrollMax = updateScrollMax_DocumentWidget_(d); /* Reposition the footer buttons as appropriate. */ /* TODO: You can just position `footerButtons` here completely without having to get `Widget` involved with the offset in any way. */ @@ -837,7 +844,6 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { const int hPad = (width_Rect(bounds) - iMin(120 * gap_UI, width_Rect(docBounds))) / 2; const int vPad = 3 * gap_UI; setPadding_Widget(d->footerButtons, hPad, vPad, hPad, vPad); - arrange_Widget(d->footerButtons); d->footerButtons->animOffsetRef = (scrollMax > 0 ? &d->scrollY.pos : NULL); if (scrollMax <= 0) { d->footerButtons->animOffsetRef = NULL; @@ -848,7 +854,6 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { d->footerButtons->rect.pos.y = size_GmDocument(d->doc).y + 2 * gap_UI * d->pageMargin; } } - setMax_SmoothScroll(&d->scrollY, scrollMax); setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax }); const int docSize = size_GmDocument(d->doc).y; setThumb_ScrollWidget(d->scroll, @@ -1066,7 +1071,7 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag, iTrue); - setBackgroundColor_Widget(d->footerButtons, tmBackground_ColorId); + //setBackgroundColor_Widget(d->footerButtons, tmBackground_ColorId); for (size_t i = 0; i < count; ++i) { iLabelWidget *button = addChildFlags_Widget( d->footerButtons, @@ -1079,6 +1084,7 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte addChild_Widget(as_Widget(d), iClob(d->footerButtons)); arrange_Widget(d->footerButtons); arrange_Widget(w); + updateVisible_DocumentWidget_(d); /* final placement for the buttons */ } static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, @@ -1222,7 +1228,7 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool } if (d->sourceGempub) { if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { - if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { + if (!isRemote_Gempub(d->sourceGempub)) { iArray *items = collectNew_Array(sizeof(iMenuItem)); pushBack_Array( items, @@ -1244,6 +1250,19 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool } makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); } + else { + makeFooterButtons_DocumentWidget_( + d, + (iMenuItem[]){ { book_Icon " ${menu.save.downloads.open}", + SDLK_s, + KMOD_PRIMARY | KMOD_SHIFT, + "document.save open:1" }, + { download_Icon " " saveToDownloads_Label, + SDLK_s, + KMOD_PRIMARY, + "document.save" } }, + 2); + } if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { redoLayout_GmDocument(d->doc); updateVisible_DocumentWidget_(d); @@ -2048,7 +2067,8 @@ static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { return iFalse; } -static void saveToDownloads_(const iString *url, const iString *mime, const iBlock *content) { +static const iString *saveToDownloads_(const iString *url, const iString *mime, const iBlock *content, + iBool showDialog) { const iString *savePath = downloadPathForUrl_App(url, mime); /* Write the file. */ { iFile *f = new_File(savePath); @@ -2060,17 +2080,22 @@ static void saveToDownloads_(const iString *url, const iString *mime, const iBlo #if defined (iPlatformAppleMobile) exportDownloadedFile_iOS(savePath); #else - const iMenuItem items[2] = { - { "${dlg.save.opendownload}", 0, 0, - format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) }, - { "${dlg.message.ok}", 0, 0, "message.ok" }, - }; - makeMessage_Widget(uiHeading_ColorEscape "${heading.save}", - format_CStr("%s\n${dlg.save.size} %.3f %s", cstr_String(path_File(f)), - isMega ? size / 1.0e6f : (size / 1.0e3f), - isMega ? "${mb}" : "${kb}"), - items, iElemCount(items)); + if (showDialog) { + const iMenuItem items[2] = { + { "${dlg.save.opendownload}", 0, 0, + format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) }, + { "${dlg.message.ok}", 0, 0, "message.ok" }, + }; + makeMessage_Widget(uiHeading_ColorEscape "${heading.save}", + format_CStr("%s\n${dlg.save.size} %.3f %s", + cstr_String(path_File(f)), + isMega ? size / 1.0e6f : (size / 1.0e3f), + isMega ? "${mb}" : "${kb}"), + items, + iElemCount(items)); + } #endif + return savePath; } else { makeSimpleMessage_Widget(uiTextCaution_ColorEscape "${heading.save.error}", @@ -2078,6 +2103,7 @@ static void saveToDownloads_(const iString *url, const iString *mime, const iBlo } iRelease(f); } + return collectNew_String(); } static void addAllLinks_(void *context, const iGmRun *run) { @@ -2556,7 +2582,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) const iMediaRequest *media = findMediaRequest_DocumentWidget_(d, linkId); if (media) { saveToDownloads_(url_GmRequest(media->req), meta_GmRequest(media->req), - body_GmRequest(media->req)); + body_GmRequest(media->req), iTrue); } } else if (equal_Command(cmd, "document.save") && document_App() == d) { @@ -2565,7 +2591,13 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) "${dlg.save.incomplete}"); } else if (!isEmpty_Block(&d->sourceContent)) { - saveToDownloads_(d->mod.url, &d->sourceMime, &d->sourceContent); + const iBool doOpen = argLabel_Command(cmd, "open"); + const iString *savePath = saveToDownloads_(d->mod.url, &d->sourceMime, + &d->sourceContent, !doOpen); + if (!isEmpty_String(savePath) && doOpen) { + postCommandf_Root( + w->root, "!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))); + } } return iTrue; } @@ -2675,6 +2707,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) return iTrue; } else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) { + updateScrollMax_DocumentWidget_(d); /* scrollY.max might not be fully updated */ init_Anim(&d->scrollY.pos, d->scrollY.max); invalidate_VisBuf(d->visBuf); clampScroll_DocumentWidget_(d); @@ -3188,6 +3221,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e iArray items; init_Array(&items, sizeof(iMenuItem)); if (d->contextLink) { + /* Context menu for a link. */ const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId); // const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId); const iRangecc scheme = urlScheme_String(linkUrl); -- cgit v1.2.3 From 53a3381dc9ccf9ca50b99b16bcc82919e9f31e4d Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 07:30:13 +0300 Subject: Text: Use arrows from Iosevka --- src/ui/text.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/ui') diff --git a/src/ui/text.c b/src/ui/text.c index 082899b0..55fd4254 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -578,6 +578,13 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { return smol; } } + /* Manual exceptions. */ { + if (ch >= 0x2190 && ch <= 0x2193 /* arrows */) { + d = font_Text_(iosevka_FontId + d->sizeId); + *glyphIndex = glyphIndex_Font_(d, ch); + return d; + } + } if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { return d; } -- cgit v1.2.3 From 55e0f439cc4c32df2d280487031f789b63a9e287 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 08:06:19 +0300 Subject: Preferences: Added toggle for UI animations --- po/en.po | 3 +++ res/about/version.gmi | 3 ++- res/lang/de.bin | Bin 21054 -> 21080 bytes res/lang/en.bin | Bin 19759 -> 19785 bytes res/lang/es.bin | Bin 22101 -> 22127 bytes res/lang/fi.bin | Bin 21742 -> 21768 bytes res/lang/fr.bin | Bin 22666 -> 22692 bytes res/lang/ia.bin | Bin 21964 -> 21990 bytes res/lang/ie.bin | Bin 21132 -> 21158 bytes res/lang/pl.bin | Bin 22770 -> 22796 bytes res/lang/ru.bin | Bin 32851 -> 32877 bytes res/lang/sr.bin | Bin 31426 -> 31452 bytes res/lang/tok.bin | Bin 20169 -> 20195 bytes res/lang/zh_Hans.bin | Bin 18923 -> 18949 bytes res/lang/zh_Hant.bin | Bin 19108 -> 19134 bytes src/app.c | 6 ++++++ src/ui/sidebarwidget.c | 3 ++- src/ui/util.c | 2 ++ 18 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index bbca83e5..9744f761 100644 --- a/po/en.po +++ b/po/en.po @@ -1160,6 +1160,9 @@ msgstr "UI scale factor:" msgid "prefs.customframe" msgstr "Custom window frame:" +msgid "prefs.animate" +msgstr "Animations:" + msgid "prefs.retainwindow" msgstr "Retain placement:" diff --git a/res/about/version.gmi b/res/about/version.gmi index a3a7c43d..e1b62835 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi @@ -13,7 +13,8 @@ * Disallow sending query responses that are too long (1024 bytes maximum). * Shift-click to select a range of text in input widgets (i.e, without dragging). * Footer buttons: on certain pages (e.g., error messages) show relevant actions in the bottom of the page. For example, if a certificate is required for viewing a page, show buttons for creating a new identity and showing the Identities sidebar. -* Link navigation shortcut icons are drawn with a consistent appearance. +* Gempub: Linear navigation through the book with Left/Right arrow keys and via footer buttons. The navigation order is determined by links on the Gempub index page. +* Link navigation shortcut icons (home row and numbered) are drawn with a consistent appearance. * Animate showing and hiding of sidebars and dialogs. * macOS: Workaround for a Metal rendering issue. * Added "Smol Emoji" and "Noto Sans Symbols" fonts, removed Symbola. Note: Many Emoji and pictographs added in recent years are still missing. diff --git a/res/lang/de.bin b/res/lang/de.bin index 45260c31..a5f3c427 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index 728c7ff8..3fe8fc26 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index d6cdd974..8a8c314f 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index b66badcb..361f3fce 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index 232338c9..d6875a05 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index e460faf7..1ebd2fea 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 87e3c0e5..4738fd3e 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index 0c021408..877ffaf7 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index 17df17a8..8301f8d4 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 74f897cb..75fe0b99 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index 4d8259b3..d5419504 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index c5b6cede..66c62937 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index 56d7643d..57e310e2 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/app.c b/src/app.c index bb3afea6..663fa2e8 100644 --- a/src/app.c +++ b/src/app.c @@ -213,6 +213,7 @@ static iString *serializePrefs_App_(const iApp *d) { appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); /* TODO: Set up an array of booleans in Prefs and do these in a loop. */ + appendFormat_String(str, "prefs.animate.changed arg:%d\n", d->prefs.uiAnimations); appendFormat_String(str, "prefs.mono.gemini.changed arg:%d\n", d->prefs.monospaceGemini); appendFormat_String(str, "prefs.mono.gopher.changed arg:%d\n", d->prefs.monospaceGopher); appendFormat_String(str, "prefs.boldlink.dark.changed arg:%d\n", d->prefs.boldLinkDark); @@ -2108,6 +2109,10 @@ iBool handleCommand_App(const char *cmd) { d->prefs.openArchiveIndexPages = arg_Command(cmd) != 0; return iTrue; } + else if (equal_Command(cmd, "prefs.animate.changed")) { + d->prefs.uiAnimations = arg_Command(cmd) != 0; + return iTrue; + } else if (equal_Command(cmd, "saturation.set")) { d->prefs.saturation = (float) arg_Command(cmd) / 100.0f; if (!isFrozen) { @@ -2350,6 +2355,7 @@ iBool handleCommand_App(const char *cmd) { setToggle_Widget(findChild_Widget(dlg, "prefs.archive.openindex"), d->prefs.openArchiveIndexPages); setToggle_Widget(findChild_Widget(dlg, "prefs.ostheme"), d->prefs.useSystemTheme); setToggle_Widget(findChild_Widget(dlg, "prefs.customframe"), d->prefs.customFrame); + setToggle_Widget(findChild_Widget(dlg, "prefs.animate"), d->prefs.uiAnimations); setText_InputWidget(findChild_Widget(dlg, "prefs.userfont"), &d->prefs.symbolFontPath); updatePrefsPinSplitButtons_(dlg, d->prefs.pinSplit); updateDropdownSelection_(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.uiLanguage)); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 395138bb..27646b22 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -936,7 +936,8 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char * if (arg_Command(cmd) && isVisible_Widget(w)) { return iTrue; } - const iBool isAnimated = argLabel_Command(cmd, "noanim") == 0 && + const iBool isAnimated = prefs_App()->uiAnimations && + argLabel_Command(cmd, "noanim") == 0 && (deviceType_App() != phone_AppDeviceType); int visX = 0; if (isVisible_Widget(w)) { diff --git a/src/ui/util.c b/src/ui/util.c index edac214f..c4fb8886 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1698,6 +1698,8 @@ iWidget *makePreferences_Widget(void) { addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.customframe}"))); addChild_Widget(values, iClob(makeToggle_Widget("prefs.customframe"))); #endif + addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.animate}"))); + addChild_Widget(values, iClob(makeToggle_Widget("prefs.animate"))); makeTwoColumnHeading_("${heading.prefs.scrolling}", headings, values); addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.smoothscroll}"))); addChild_Widget(values, iClob(makeToggle_Widget("prefs.smoothscroll"))); -- cgit v1.2.3 From 1777c26a44daa5b87c7b88dd611008aaa59576eb Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 14:55:24 +0300 Subject: DocumentWidget: Retain scroll position Use scroll position from history when the page content wasn't in the cache. --- src/ui/documentwidget.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index a02e0bca..f37b2b6d 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -1599,6 +1599,10 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { else if (!isEmpty_String(d->mod.url)) { fetch_DocumentWidget_(d); } + if (recent) { + /* Retain scroll position in refetched content as well. */ + d->initNormScrollY = recent->normScrollY; + } return iFalse; } -- cgit v1.2.3 From 0bee8772e3bb7e29a78cf98a1ca84926b93df77f Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 15:12:21 +0300 Subject: DocumentWidget: Looking up URLs from history URLs in the history are in decoded and NFC normalized form, except for spaces which are stored as %20. --- src/ui/documentwidget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index f37b2b6d..6184a75a 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -1591,7 +1591,7 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n } static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { - const iRecentUrl *recent = findUrl_History(d->mod.history, d->mod.url); + const iRecentUrl *recent = findUrl_History(d->mod.history, withSpacesEncoded_String(d->mod.url)); if (recent && recent->cachedResponse) { updateFromCachedResponse_DocumentWidget_(d, recent->normScrollY, recent->cachedResponse); return iTrue; -- cgit v1.2.3 From 05e2ce8b07e8332af887f608831c36d4f7bde664 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 15:26:13 +0300 Subject: Keys: Redundant split menu language strings --- po/en.po | 25 ++----------------------- res/lang/de.bin | Bin 21080 -> 20699 bytes res/lang/en.bin | Bin 19785 -> 19404 bytes res/lang/es.bin | Bin 22127 -> 21746 bytes res/lang/fi.bin | Bin 21768 -> 21892 bytes res/lang/fr.bin | Bin 22692 -> 22311 bytes res/lang/ia.bin | Bin 21990 -> 21609 bytes res/lang/ie.bin | Bin 21158 -> 21153 bytes res/lang/pl.bin | Bin 22796 -> 22415 bytes res/lang/ru.bin | Bin 32877 -> 32496 bytes res/lang/sr.bin | Bin 31452 -> 31969 bytes res/lang/tok.bin | Bin 20195 -> 19814 bytes res/lang/zh_Hans.bin | Bin 18949 -> 18568 bytes res/lang/zh_Hant.bin | Bin 19134 -> 18753 bytes src/ui/keys.c | 16 ++++++++-------- 15 files changed, 10 insertions(+), 31 deletions(-) (limited to 'src/ui') diff --git a/po/en.po b/po/en.po index 9744f761..8fe6b96d 100644 --- a/po/en.po +++ b/po/en.po @@ -1393,29 +1393,8 @@ msgstr "Set view split mode" msgid "keys.split.next" msgstr "Switch focus to next split" -msgid "keys.split.menu.merge" -msgstr "Split view menu: Merge tabs" - -msgid "keys.split.menu.swap" -msgstr "Split view menu: Swap sides" - -msgid "keys.split.menu.horiz" -msgstr "Split view menu: Horizontal" - -msgid "keys.split.menu.horiz12" -msgstr "Split view menu: Horizontal 1:2" - -msgid "keys.split.menu.horiz21" -msgstr "Split view menu: Horizontal 2:1" - -msgid "keys.split.menu.vert" -msgstr "Split view menu: Vertical" - -msgid "keys.split.menu.vert12" -msgstr "Split view menu: Vertical 1:2" - -msgid "keys.split.menu.vert21" -msgstr "Split view menu: Vertical 2:1" +msgid "keys.split.item" +msgstr "Split view menu:" msgid "keys.hoverurl" msgstr "Toggle show URL on hover" diff --git a/res/lang/de.bin b/res/lang/de.bin index a5f3c427..b89c8b0f 100644 Binary files a/res/lang/de.bin and b/res/lang/de.bin differ diff --git a/res/lang/en.bin b/res/lang/en.bin index 3fe8fc26..0ac42d88 100644 Binary files a/res/lang/en.bin and b/res/lang/en.bin differ diff --git a/res/lang/es.bin b/res/lang/es.bin index 8a8c314f..01d86e3f 100644 Binary files a/res/lang/es.bin and b/res/lang/es.bin differ diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 361f3fce..7034468b 100644 Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ diff --git a/res/lang/fr.bin b/res/lang/fr.bin index d6875a05..0b78f3b7 100644 Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 1ebd2fea..e6590afc 100644 Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 4738fd3e..dcf6a70d 100644 Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ diff --git a/res/lang/pl.bin b/res/lang/pl.bin index 877ffaf7..9f42024c 100644 Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ diff --git a/res/lang/ru.bin b/res/lang/ru.bin index 8301f8d4..3cacac36 100644 Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 75fe0b99..af0acbf9 100644 Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ diff --git a/res/lang/tok.bin b/res/lang/tok.bin index d5419504..8f10e051 100644 Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 66c62937..b155036d 100644 Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index 57e310e2..57ce2d83 100644 Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ diff --git a/src/ui/keys.c b/src/ui/keys.c index 17cc0e72..b15fe04b 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c @@ -228,14 +228,14 @@ static const struct { int id; iMenuItem bind; int flags; } defaultBindings_[] = { 81, { "${keys.tab.next}", nextTab_KeyShortcut, "tabs.next" }, 0 }, { 90, { "${keys.split.menu}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" }, 0 }, { 91, { "${keys.split.next}", SDLK_TAB, KMOD_CTRL, "keyroot.next", }, 0 }, - { 92, { "${keys.split.menu.merge}", '1', 0, "ui.split arg:0", }, noDirectTrigger_BindFlag }, - { 93, { "${keys.split.menu.swap}", SDLK_x, 0, "ui.split swap:1", }, noDirectTrigger_BindFlag }, - { 94, { "${keys.split.menu.horiz}", '3', 0, "ui.split arg:3 axis:0", }, noDirectTrigger_BindFlag }, - { 95, { "${keys.split.menu.horiz12}", SDLK_d, 0, "ui.split arg:1 axis:0", }, noDirectTrigger_BindFlag }, - { 96, { "${keys.split.menu.horiz21}", SDLK_e, 0, "ui.split arg:2 axis:0", }, noDirectTrigger_BindFlag }, - { 97, { "${keys.split.menu.vert}", '2', 0, "ui.split arg:3 axis:1", }, noDirectTrigger_BindFlag }, - { 98, { "${keys.split.menu.vert12}", SDLK_f, 0, "ui.split arg:1 axis:1", }, noDirectTrigger_BindFlag }, - { 99, { "${keys.split.menu.vert21}", SDLK_r, 0, "ui.split arg:2 axis:1", }, noDirectTrigger_BindFlag }, + { 92, { "${keys.split.item} ${menu.split.merge}", '1', 0, "ui.split arg:0", }, noDirectTrigger_BindFlag }, + { 93, { "${keys.split.item} ${menu.split.swap}", SDLK_x, 0, "ui.split swap:1", }, noDirectTrigger_BindFlag }, + { 94, { "${keys.split.item} ${menu.split.horizontal}", '3', 0, "ui.split arg:3 axis:0", }, noDirectTrigger_BindFlag }, + { 95, { "${keys.split.item} ${menu.split.horizontal} 1:2", SDLK_d, 0, "ui.split arg:1 axis:0", }, noDirectTrigger_BindFlag }, + { 96, { "${keys.split.item} ${menu.split.horizontal} 2:1", SDLK_e, 0, "ui.split arg:2 axis:0", }, noDirectTrigger_BindFlag }, + { 97, { "${keys.split.item} ${menu.split.vertical}", '2', 0, "ui.split arg:3 axis:1", }, noDirectTrigger_BindFlag }, + { 98, { "${keys.split.item} ${menu.split.vertical} 1:2", SDLK_f, 0, "ui.split arg:1 axis:1", }, noDirectTrigger_BindFlag }, + { 99, { "${keys.split.item} ${menu.split.vertical} 2:1", SDLK_r, 0, "ui.split arg:2 axis:1", }, noDirectTrigger_BindFlag }, { 100,{ "${keys.hoverurl}", '/', KMOD_PRIMARY, "prefs.hoverlink.toggle" }, 0 }, { 110,{ "${menu.save.downloads}", SDLK_s, KMOD_PRIMARY, "document.save" }, 0 }, /* The following cannot currently be changed (built-in duplicates). */ -- cgit v1.2.3 From 9264e1969c88c86f3f3ec8012b973d43febb4e2c Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 May 2021 16:09:44 +0300 Subject: Cleanup --- src/ui/keys.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/ui') diff --git a/src/ui/keys.c b/src/ui/keys.c index b15fe04b..9df505e0 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c @@ -228,14 +228,14 @@ static const struct { int id; iMenuItem bind; int flags; } defaultBindings_[] = { 81, { "${keys.tab.next}", nextTab_KeyShortcut, "tabs.next" }, 0 }, { 90, { "${keys.split.menu}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" }, 0 }, { 91, { "${keys.split.next}", SDLK_TAB, KMOD_CTRL, "keyroot.next", }, 0 }, - { 92, { "${keys.split.item} ${menu.split.merge}", '1', 0, "ui.split arg:0", }, noDirectTrigger_BindFlag }, - { 93, { "${keys.split.item} ${menu.split.swap}", SDLK_x, 0, "ui.split swap:1", }, noDirectTrigger_BindFlag }, - { 94, { "${keys.split.item} ${menu.split.horizontal}", '3', 0, "ui.split arg:3 axis:0", }, noDirectTrigger_BindFlag }, - { 95, { "${keys.split.item} ${menu.split.horizontal} 1:2", SDLK_d, 0, "ui.split arg:1 axis:0", }, noDirectTrigger_BindFlag }, - { 96, { "${keys.split.item} ${menu.split.horizontal} 2:1", SDLK_e, 0, "ui.split arg:2 axis:0", }, noDirectTrigger_BindFlag }, - { 97, { "${keys.split.item} ${menu.split.vertical}", '2', 0, "ui.split arg:3 axis:1", }, noDirectTrigger_BindFlag }, - { 98, { "${keys.split.item} ${menu.split.vertical} 1:2", SDLK_f, 0, "ui.split arg:1 axis:1", }, noDirectTrigger_BindFlag }, - { 99, { "${keys.split.item} ${menu.split.vertical} 2:1", SDLK_r, 0, "ui.split arg:2 axis:1", }, noDirectTrigger_BindFlag }, + { 92, { "${keys.split.item} ${menu.split.merge}", '1', 0, "ui.split arg:0", }, noDirectTrigger_BindFlag }, + { 93, { "${keys.split.item} ${menu.split.swap}", SDLK_x, 0, "ui.split swap:1", }, noDirectTrigger_BindFlag }, + { 94, { "${keys.split.item} ${menu.split.horizontal}", '3', 0, "ui.split arg:3 axis:0", }, noDirectTrigger_BindFlag }, + { 95, { "${keys.split.item} ${menu.split.horizontal} 1:2", SDLK_d, 0, "ui.split arg:1 axis:0", }, noDirectTrigger_BindFlag }, + { 96, { "${keys.split.item} ${menu.split.horizontal} 2:1", SDLK_e, 0, "ui.split arg:2 axis:0", }, noDirectTrigger_BindFlag }, + { 97, { "${keys.split.item} ${menu.split.vertical}", '2', 0, "ui.split arg:3 axis:1", }, noDirectTrigger_BindFlag }, + { 98, { "${keys.split.item} ${menu.split.vertical} 1:2", SDLK_f, 0, "ui.split arg:1 axis:1", }, noDirectTrigger_BindFlag }, + { 99, { "${keys.split.item} ${menu.split.vertical} 2:1", SDLK_r, 0, "ui.split arg:2 axis:1", }, noDirectTrigger_BindFlag }, { 100,{ "${keys.hoverurl}", '/', KMOD_PRIMARY, "prefs.hoverlink.toggle" }, 0 }, { 110,{ "${menu.save.downloads}", SDLK_s, KMOD_PRIMARY, "document.save" }, 0 }, /* The following cannot currently be changed (built-in duplicates). */ -- cgit v1.2.3 From 0153e4dc294edcb52ef6579e38fdc5f6ae713b2d Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Tue, 8 Jun 2021 18:13:18 +0300 Subject: Normalize (NFC) document/input field content The text renderer has problems with composites so normalizing the text (using Unicode normalization form C) yields better results for now. --- src/gmdocument.c | 1 + src/ui/inputwidget.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/ui') diff --git a/src/gmdocument.c b/src/gmdocument.c index ad8616a3..b95f85e7 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c @@ -1488,6 +1488,7 @@ static void normalize_GmDocument(iGmDocument *d) { appendCStr_String(normalized, "\n"); } set_String(&d->source, collect_String(normalized)); + normalize_String(&d->source); /* NFC */ } void setUrl_GmDocument(iGmDocument *d, const iString *url) { diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 0dc5ffcb..32fb5ccb 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c @@ -547,7 +547,9 @@ void setText_InputWidget(iInputWidget *d, const iString *text) { } clearUndo_InputWidget_(d); clear_Array(&d->text); - iConstForEach(String, i, text) { + iString *nfcText = collect_String(copy_String(text)); + normalize_String(nfcText); + iConstForEach(String, i, nfcText) { pushBack_Array(&d->text, &i.value); } if (isFocused_Widget(d)) { -- cgit v1.2.3 From d03b4bb3b567de4501915f4236280b33dc385103 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Wed, 9 Jun 2021 17:45:10 +0300 Subject: CertImportWidget: Respond to "input.paste" The "input.paste" command is triggered via menus before CertImportWidget gets the key. --- res/about/version.gmi | 1 + src/ui/certimportwidget.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'src/ui') diff --git a/res/about/version.gmi b/res/about/version.gmi index c48a16d0..0a51df34 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi @@ -7,6 +7,7 @@ # Release notes ## 1.5.2 +* Fixed pasting a PEM-formatted certificate and/or private key via clipboard in Import Identity. * Normalize page contents (NFC) to avoid most common issues with diacritics. ## 1.5.1 diff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c index e121b4d0..6e818137 100644 --- a/src/ui/certimportwidget.c +++ b/src/ui/certimportwidget.c @@ -215,6 +215,14 @@ static iBool processEvent_CertImportWidget_(iCertImportWidget *d, const SDL_Even return iTrue; } } + if (isCommand_UserEvent(ev, "input.paste")) { + if (!tryImportFromClipboard_CertImportWidget_(d)) { + makeSimpleMessage_Widget(uiTextCaution_ColorEscape "${heading.certimport.pasted}", + "${dlg.certimport.notfound}"); + } + postRefresh_App(); + return iTrue; + } if (isCommand_UserEvent(ev, "certimport.paste")) { tryImportFromClipboard_CertImportWidget_(d); return iTrue; -- cgit v1.2.3