=> 7834830d05f785abd56282af6865d69e2a651165
[1mdiff --git a/Depends.cmake b/Depends.cmake[m [1mindex 7408cfb4..d74ce89d 100644[m [1m--- a/Depends.cmake[m [1m+++ b/Depends.cmake[m [36m@@ -192,6 +192,10 @@[m [mif (ENABLE_WINSPARKLE)[m endif ()[m [m find_package (PkgConfig REQUIRED)[m [31m-pkg_check_modules (SDL2 REQUIRED sdl2)[m [32m+[m[32mif (ENABLE_TUI)[m [32m+[m[32m pkg_check_modules (SDL2 REQUIRED sealcurses)[m [32m+[m[32melse ()[m [32m+[m[32m pkg_check_modules (SDL2 REQUIRED sdl2)[m [32m+[m[32mendif ()[m pkg_check_modules (MPG123 IMPORTED_TARGET libmpg123)[m pkg_check_modules (WEBP IMPORTED_TARGET libwebp)[m [1mdiff --git a/src/app.c b/src/app.c[m [1mindex 8977914e..caf9d32d 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -61,6 +61,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m #include[m #include [m #include [m [32m+[m[32m#include [m #include [m #include [m [m [36m@@ -1646,8 +1647,46 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m }[m #endif[m iBool wasUsed = iFalse;[m [32m+[m[32m /* Focus navigation events take prioritity. */[m [32m+[m[32m if (!wasUsed) {[m [32m+[m[32m /* Keyboard focus navigation with arrow keys. */[m [32m+[m[32m iWidget *menubar = NULL;[m [32m+[m[32m if (ev.type == SDL_KEYDOWN && ev.key.keysym.mod == 0 && focus_Widget() &&[m [32m+[m[32m !cmp_String(id_Widget(parent_Widget(focus_Widget())), "menu")) {[m [32m+[m[32m setCurrent_Window(window_Widget(focus_Widget()));[m [32m+[m[32m const int key = ev.key.keysym.sym;[m [32m+[m[32m if (key == SDLK_DOWN || key == SDLK_UP) {[m [32m+[m[32m iWidget *nextFocus = findFocusable_Widget(focus_Widget(),[m [32m+[m[32m key == SDLK_UP[m [32m+[m[32m ? backward_WidgetFocusDir[m [32m+[m[32m : forward_WidgetFocusDir);[m [32m+[m[32m if (nextFocus && parent_Widget(nextFocus) == parent_Widget(focus_Widget())) {[m [32m+[m[32m setFocus_Widget(nextFocus);[m [32m+[m[32m }[m [32m+[m[32m wasUsed = iTrue;[m [32m+[m[32m }[m [32m+[m[32m else if ((key == SDLK_LEFT || key == SDLK_RIGHT) &&[m [32m+[m[32m (menubar = findParent_Widget(focus_Widget(), "menubar")) != NULL) {[m [32m+[m[32m iWidget *button = parent_Widget(parent_Widget(focus_Widget()));[m [32m+[m[32m size_t index = indexOfChild_Widget(menubar, button);[m [32m+[m[32m const size_t curIndex = index;[m [32m+[m[32m //printf("index:%zu\n", index); SDL_Delay(1000);[m [32m+[m[32m if (key == SDLK_LEFT && index > 0) {[m [32m+[m[32m index--;[m [32m+[m[32m }[m [32m+[m[32m else if (key == SDLK_RIGHT && index < childCount_Widget(menubar) - 1) {[m [32m+[m[32m index++;[m [32m+[m[32m }[m [32m+[m[32m if (curIndex != index) {[m [32m+[m[32m setFocus_Widget(child_Widget(menubar, index));[m[41m [m [32m+[m[32m postCommand_Widget(child_Widget(menubar, index), "trigger");[m [32m+[m[32m }[m [32m+[m[32m wasUsed = iTrue;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m /* Per-window processing. */[m [31m- if (!isEmpty_PtrArray(&d->mainWindows)) {[m [32m+[m[32m if (!wasUsed && !isEmpty_PtrArray(&d->mainWindows)) {[m listWindows_App_(d, &windows);[m iConstForEach(PtrArray, iter, &windows) {[m iWindow *window = iter.ptr;[m [36m@@ -1861,6 +1900,9 @@[m [mvoid refresh_App(void) {[m break;[m }[m win->frameCount++;[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m sleep_Thread(1.0 / 60.0);[m [32m+[m[32m#endif[m }[m }[m if (d->warmupFrames > 0) {[m [1mdiff --git a/src/defs.h b/src/defs.h[m [1mindex 9e967217..764060b8 100644[m [1m--- a/src/defs.h[m [1m+++ b/src/defs.h[m [36m@@ -64,15 +64,6 @@[m [menum iScrollType {[m max_ScrollType[m };[m [m [31m-enum iReturnKeyFlag {[m [31m- return_ReturnKeyFlag = 0,[m [31m- shiftReturn_ReturnKeyFlag = 1,[m [31m- controlReturn_ReturnKeyFlag = 2,[m [31m- guiReturn_ReturnKeyFlag = 3,[m [31m- mask_ReturnKeyFlag = 0xf,[m [31m- accept_ReturnKeyFlag = 4, /* shift */[m [31m-};[m [31m-[m enum iToolbarAction {[m back_ToolbarAction = 0,[m forward_ToolbarAction = 1,[m [36m@@ -91,23 +82,37 @@[m [menum iToolbarAction {[m max_ToolbarAction[m };[m [m [32m+[m[32menum iReturnKeyFlag {[m [32m+[m[32m noMod_ReturnKeyFlag = 0,[m [32m+[m[32m shift_ReturnKeyFlag = 1,[m [32m+[m[32m control_ReturnKeyFlag = 2,[m [32m+[m[32m gui_ReturnKeyFlag = 3,[m [32m+[m[32m mask_ReturnKeyFlag = 0xf,[m [32m+[m[32m accept_ReturnKeyFlag = 4, /* shift */[m [32m+[m[32m};[m [32m+[m [32m+[m[32m#define RETURN_KEY_BEHAVIOR(newlineFlag, acceptFlag) \[m [32m+[m[32m ((newlineFlag) & 3 | ((acceptFlag) << accept_ReturnKeyFlag))[m [32m+[m /* Return key behavior is not handled via normal bindings because only certain combinations[m are valid. */[m enum iReturnKeyBehavior {[m [31m- acceptWithoutMod_ReturnKeyBehavior =[m [31m- shiftReturn_ReturnKeyFlag | (return_ReturnKeyFlag << accept_ReturnKeyFlag),[m [31m- acceptWithShift_ReturnKeyBehavior =[m [31m- return_ReturnKeyFlag | (shiftReturn_ReturnKeyFlag << accept_ReturnKeyFlag),[m [32m+[m[32m// acceptWithoutMod_ReturnKeyBehavior =[m [32m+[m[32m// shiftReturn_ReturnKeyFlag | (return_ReturnKeyFlag << accept_ReturnKeyFlag),[m[41m [m [32m+[m[32m// acceptWithShift_ReturnKeyBehavior =[m [32m+[m[32m// return_ReturnKeyFlag | (shiftReturn_ReturnKeyFlag << accept_ReturnKeyFlag),[m acceptWithPrimaryMod_ReturnKeyBehavior =[m #if defined (iPlatformApple)[m [31m- return_ReturnKeyFlag | (guiReturn_ReturnKeyFlag << accept_ReturnKeyFlag),[m [32m+[m[32m RETURN_KEY_BEHAVIOR(0, gui_ReturnKeyFlag),[m #else[m [31m- return_ReturnKeyFlag | (controlReturn_ReturnKeyFlag << accept_ReturnKeyFlag),[m [32m+[m[32m RETURN_KEY_BEHAVIOR(control_ReturnKeyFlag, 0),[m #endif[m [31m-#if defined (iPlatformAndroidMobile)[m [31m- default_ReturnKeyBehavior = acceptWithShift_ReturnKeyBehavior,[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m default_ReturnKeyBehavior = RETURN_KEY_BEHAVIOR(0, gui_ReturnKeyFlag),[m [32m+[m[32m#elif defined (iPlatformAndroidMobile)[m [32m+[m[32m default_ReturnKeyBehavior = RETURN_KEY_BEHAVIOR(0, shift_ReturnKeyFlag),[m #else[m [31m- default_ReturnKeyBehavior = acceptWithoutMod_ReturnKeyBehavior,[m [32m+[m[32m default_ReturnKeyBehavior = RETURN_KEY_BEHAVIOR(shift_ReturnKeyFlag, 0),[m #endif[m };[m [m [36m@@ -202,7 +207,10 @@[m [miLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) {[m #define toggleYes_Icon check_Icon[m #define toggleNo_Icon bullet_Icon[m [m [31m-#if defined (iPlatformApple)[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m# define shift_Icon "Sh"[m [32m+[m[32m# define shiftReturn_Icon "Sh-" return_Icon[m [32m+[m[32m#elif defined (iPlatformApple)[m # define shift_Icon "\u21e7"[m # define shiftReturn_Icon shift_Icon return_Icon[m #else[m [1mdiff --git a/src/gmdocument.c b/src/gmdocument.c[m [1mindex 6e0d14d4..bfd477ba 100644[m [1m--- a/src/gmdocument.c[m [1m+++ b/src/gmdocument.c[m [36m@@ -640,10 +640,10 @@[m [mstatic void doLayout_GmDocument_(iGmDocument *d) {[m const iPrefs *prefs = prefs_App();[m const iBool isMono = isForcedMonospace_GmDocument_(d);[m const iBool isGopher = isGopher_GmDocument_(d);[m [31m- const iBool isNarrow = d->size.x < 90 * gap_Text;[m [31m- const iBool isVeryNarrow = d->size.x <= 70 * gap_Text;[m [31m- const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text;[m [31m- const iBool isFullWidthImages = (d->outsideMargin < 5 * gap_UI);[m [32m+[m[32m const iBool isNarrow = d->size.x < 90 * gap_Text * aspect_UI;[m [32m+[m[32m const iBool isVeryNarrow = d->size.x <= 70 * gap_Text * aspect_UI;[m [32m+[m[32m const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text * aspect_UI;[m [32m+[m[32m const iBool isFullWidthImages = (d->outsideMargin < 5 * gap_UI * aspect_UI);[m [m initTheme_GmDocument_(d);[m d->isLayoutInvalidated = iFalse;[m [36m@@ -873,15 +873,12 @@[m [mstatic void doLayout_GmDocument_(iGmDocument *d) {[m if (type == bullet_GmLineType) {[m /* TODO: Literata bullet is broken? */[m iGmRun bulRun = run;[m [31m-#if 0[m [31m- if (prefs->font == literata_TextFont) {[m [31m- /* Something wrong this the glyph in Literata, looks cropped. */[m [31m- bulRun.font = FONT_ID(default_FontId, regular_FontStyle,[m [31m- contentRegular_FontSize);[m [31m- }[m [31m-#endif[m bulRun.color = tmQuote_ColorId;[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m bulRun.visBounds.pos = addX_I2(pos, indents[text_GmLineType] * gap_Text);[m [32m+[m[32m#else[m bulRun.visBounds.pos = addX_I2(pos, (indents[text_GmLineType] - 0.55f) * gap_Text);[m [32m+[m[32m#endif[m bulRun.visBounds.size =[m init_I2((indents[bullet_GmLineType] - indents[text_GmLineType]) * gap_Text,[m lineHeight_Text(bulRun.font));[m [36m@@ -903,8 +900,8 @@[m [mstatic void doLayout_GmDocument_(iGmDocument *d) {[m quoteRun.visBounds.size = measure_Text(quoteRun.font, quote).bounds.size;[m quoteRun.visBounds.pos =[m add_I2(pos,[m [31m- init_I2((indents[quote_GmLineType] - 5) * gap_Text,[m [31m- lineHeight_Text(quote_FontId) / 2 - bottom_Rect(vis)));[m [32m+[m[32m init_I2((indents[quote_GmLineType] - 5 * aspect_UI) * gap_Text,[m [32m+[m[32m (lineHeight_Text(quote_FontId) / 2 - bottom_Rect(vis)) * aspect_UI));[m quoteRun.bounds = zero_Rect(); /* just visual */[m quoteRun.flags |= decoration_GmRunFlag;[m pushBack_Array(&d->layout, "eRun);[m [1mdiff --git a/src/prefs.c b/src/prefs.c[m [1mindex fa7af089..f304da11 100644[m [1m--- a/src/prefs.c[m [1m+++ b/src/prefs.c[m [36m@@ -67,6 +67,9 @@[m [mvoid init_Prefs(iPrefs *d) {[m d->bottomNavBar = iFalse;[m d->bottomTabBar = iFalse; [m }[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m d->bottomNavBar = iTrue;[m [32m+[m[32m#endif[m d->menuBar = (deviceType_App() == desktop_AppDeviceType);[m d->pinSplit = 1;[m d->time24h = iTrue;[m [1mdiff --git a/src/ui/banner.c b/src/ui/banner.c[m [1mindex 9ff3e524..e9f9457c 100644[m [1m--- a/src/ui/banner.c[m [1m+++ b/src/ui/banner.c[m [36m@@ -63,15 +63,22 @@[m [mstruct Impl_Banner {[m [m iDefineTypeConstruction(Banner)[m [m [31m-#define itemGap_Banner_ (3 * gap_UI)[m [31m-#define itemVPad_Banner_ (2 * gap_UI)[m [31m-#define itemHPad_Banner_ (3 * gap_UI)[m [31m-#define bottomPad_Banner_ (4 * gap_UI)[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m# define itemGap_Banner_ (1 * gap_UI)[m [32m+[m[32m# define itemVPad_Banner_ (1 * gap_UI)[m [32m+[m[32m# define itemHPad_Banner_ (2 * gap_UI)[m [32m+[m[32m# define bottomPad_Banner_ (1 * gap_UI)[m [32m+[m[32m#else[m [32m+[m[32m# define itemGap_Banner_ (3 * gap_UI)[m [32m+[m[32m# define itemVPad_Banner_ (2 * gap_UI)[m [32m+[m[32m# define itemHPad_Banner_ (3 * gap_UI)[m [32m+[m[32m# define bottomPad_Banner_ (4 * gap_UI)[m [32m+[m[32m#endif[m [m static void updateHeight_Banner_(iBanner *d) {[m d->rect.size.y = 0;[m if (!isEmpty_String(&d->site)) {[m [31m- d->siteHeight = lineHeight_Text(banner_FontId) * 2;[m [32m+[m[32m d->siteHeight = iMax(3, lineHeight_Text(banner_FontId) * 2);[m d->rect.size.y += d->siteHeight;[m }[m const size_t numItems = size_Array(&d->items);[m [36m@@ -204,7 +211,7 @@[m [mvoid draw_Banner(const iBanner *d) {[m }[m iRect bounds = d->rect;[m /* TODO: use d->siteHeight */[m [31m- iInt2 pos = addY_I2(topLeft_Rect(bounds), lineHeight_Text(banner_FontId) / 2);[m [32m+[m[32m iInt2 pos = addY_I2(topLeft_Rect(bounds), iMax(1, lineHeight_Text(banner_FontId) / 2));[m iPaint p;[m init_Paint(&p);[m // drawRect_Paint(&p, bounds, red_ColorId);[m [1mdiff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c[m [1mindex b7a1a5a6..7d8e7999 100644[m [1m--- a/src/ui/certimportwidget.c[m [1m+++ b/src/ui/certimportwidget.c[m [36m@@ -125,7 +125,7 @@[m [mvoid init_CertImportWidget(iCertImportWidget *d) {[m #endif[m { "${cancel}" },[m { uiTextAction_ColorEscape "${dlg.certimport.import}",[m [31m- SDLK_RETURN, KMOD_PRIMARY,[m [32m+[m[32m SDLK_RETURN, KMOD_ACCEPT,[m "certimport.accept" }[m };[m init_Widget(w);[m [1mdiff --git a/src/ui/certlistwidget.c b/src/ui/certlistwidget.c[m [1mindex 61851d22..e514f974 100644[m [1m--- a/src/ui/certlistwidget.c[m [1m+++ b/src/ui/certlistwidget.c[m [36m@@ -372,9 +372,12 @@[m [mstatic void draw_CertItem_(const iCertItem *d, iPaint *p, iRect itemRect,[m iString icon;[m initUnicodeN_String(&icon, &d->icon, 1);[m iInt2 cPos = topLeft_Rect(itemRect);[m [31m- const int indent = 1.4f * lineHeight_Text(font);[m [32m+[m[32m int indent = 1.4f * lineHeight_Text(font);[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m indent += 2 * gap_UI;[m [32m+[m[32m#endif[m addv_I2(&cPos,[m [31m- init_I2(3 * gap_UI,[m [32m+[m[32m init_I2(3 * gap_UI * aspect_UI,[m (itemHeight - lineHeight_Text(uiLabel_FontId) * 2 - lineHeight_Text(font)) /[m 2));[m const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId[m [36m@@ -420,7 +423,12 @@[m [mvoid init_CertListWidget(iCertListWidget *d) {[m }[m [m void updateItemHeight_CertListWidget(iCertListWidget *d) {[m [31m- setItemHeight_ListWidget(&d->list, 3.5f * lineHeight_Text(d->itemFonts[0]));[m [32m+[m[32m#if !defined (iPlatformTerminal)[m [32m+[m[32m const float height = 3.5f;[m [32m+[m[32m#else[m [32m+[m[32m const int height = 4;[m [32m+[m[32m#endif[m[41m [m [32m+[m[32m setItemHeight_ListWidget(&d->list, height * lineHeight_Text(d->itemFonts[0]));[m }[m [m iBool updateItems_CertListWidget(iCertListWidget *d) {[m [1mdiff --git a/src/ui/color.h b/src/ui/color.h[m [1mindex 0d94f0c2..356831d2 100644[m [1m--- a/src/ui/color.h[m [1m+++ b/src/ui/color.h[m [36m@@ -195,6 +195,7 @@[m [miLocalDef iBool isRegularText_ColorId(enum iColorId d) {[m #define permanent_ColorId 0x80 /* cannot be changed via escapes */[m #define fillBackground_ColorId 0x100 /* fill background with same color, but alpha 0 */[m #define opaque_ColorId 0x200[m [32m+[m[32m#define underline_ColorId 0x400[m [m #define asciiBase_ColorEscape 33[m #define asciiExtended_ColorEscape (128 - asciiBase_ColorEscape)[m [1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m [1mindex 53e63414..478e2a26 100644[m [1m--- a/src/ui/documentwidget.c[m [1m+++ b/src/ui/documentwidget.c[m [36m@@ -547,13 +547,13 @@[m [mstatic int documentWidth_DocumentView_(const iDocumentView *d) {[m const iWidget *w = constAs_Widget(d->owner);[m const iRect bounds = bounds_Widget(w);[m const iPrefs * prefs = prefs_App();[m [31m- const int minWidth = 50 * gap_UI; /* lines must fit a word at least */[m [32m+[m[32m const int minWidth = 50 * gap_UI * aspect_UI; /* lines must fit a word at least */[m const float adjust = iClamp((float) bounds.size.x / gap_UI / 11 - 12,[m -1.0f, 10.0f); /* adapt to width */[m //printf("%f\n", adjust); fflush(stdout);[m int prefsWidth = prefs->lineWidth;[m #if defined (iPlatformTerminal)[m [31m- prefsWidth /= aspect_UI;[m [32m+[m[32m prefsWidth /= aspect_UI * 0.8f;[m #endif[m return iMini(iMax(minWidth, bounds.size.x - gap_UI * (d->pageMargin + adjust) * 2),[m fontSize_UI * prefsWidth * prefs->zoomPercent / 100);[m [36m@@ -1919,7 +1919,7 @@[m [mstatic void draw_DocumentView_(const iDocumentView *d) {[m init_I2(bounds.size.x, documentTopPad_DocumentView_(d)) },[m docBgColor);[m setPos_Banner(banner, addY_I2(topLeft_Rect(docBounds),[m [31m- -pos_SmoothScroll(&d->scrollY)));[m [32m+[m[32m floorf(-pos_SmoothScroll(&d->scrollY))));[m draw_Banner(banner);[m }[m const int yBottom = yTop + size_GmDocument(d->doc).y;[m [1mdiff --git a/src/ui/font.h b/src/ui/font.h[m [1mindex 34b399bf..6b429a55 100644[m [1m--- a/src/ui/font.h[m [1m+++ b/src/ui/font.h[m [36m@@ -83,6 +83,10 @@[m [miLocalDef enum iFontStyle style_FontId(enum iFontId id) {[m return (id / max_FontSize) % max_FontStyle;[m }[m [m [32m+[m[32miLocalDef enum iFontSize size_FontId(enum iFontId id) {[m [32m+[m[32m return id % max_FontSize;[m [32m+[m[32m}[m [32m+[m iLocalDef iBool isControl_Char(iChar c) {[m return isDefaultIgnorable_Char(c) || isVariationSelector_Char(c) || isFitzpatrickType_Char(c);[m }[m [36m@@ -240,6 +244,7 @@[m [menum iRunMode {[m permanentColorFlag_RunMode = iBit(11),[m alwaysVariableWidthFlag_RunMode = iBit(12),[m fillBackground_RunMode = iBit(13),[m [32m+[m[32m underline_RunMode = iBit(14),[m };[m [m int runFlags_FontId (enum iFontId fontId);[m [1mdiff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c[m [1mindex d843eb20..950558de 100644[m [1m--- a/src/ui/inputwidget.c[m [1m+++ b/src/ui/inputwidget.c[m [36m@@ -39,6 +39,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m #include [m #include [m #include [m [32m+[m[32m#include [m [m #if defined (iPlatformAppleDesktop)[m # include "macos.h"[m [36m@@ -732,8 +733,16 @@[m [mstatic uint32_t cursorTimer_(uint32_t interval, void *w) {[m return interval;[m }[m [m [32m+[m[32miLocalDef iBool isBlinkingCursor_(void) {[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m return iFalse; /* terminal will do it */[m [32m+[m[32m#else[m [32m+[m[32m return prefs_App()->blinkingCursor;[m [32m+[m[32m#endif[m [32m+[m[32m}[m [32m+[m static void startOrStopCursorTimer_InputWidget_(iInputWidget *d, int doStart) {[m [31m- if (!prefs_App()->blinkingCursor && doStart == 1) {[m [32m+[m[32m if (!isBlinkingCursor_() && doStart == 1) {[m doStart = iFalse;[m }[m if (doStart && !d->timer) {[m [36m@@ -785,7 +794,7 @@[m [mstatic void updateTextInputRect_InputWidget_(const iInputWidget *d) {[m setRect_SystemTextInput(d->sysCtrl, contentBounds_InputWidget_(d));[m }[m #endif[m [31m-#if !defined (iPlatformAppleMobile) && !defined (iPlatformAndroidMobile)[m [32m+[m[32m#if !defined (iPlatformAppleMobile) && !defined (iPlatformAndroidMobile) && !defined (SDL_SEAL_CURSES)[m const iRect bounds = bounds_Widget(constAs_Widget(d));[m SDL_SetTextInputRect(&(SDL_Rect){ bounds.pos.x, bounds.pos.y, bounds.size.x, bounds.size.y });[m #endif[m [36m@@ -2696,11 +2705,13 @@[m [mstatic void draw_InputWidget_(const iInputWidget *d) {[m /* `lines` is already up to date and ready for drawing. */[m fillRect_Paint([m &p, bounds, isFocused ? uiInputBackgroundFocused_ColorId : uiInputBackground_ColorId);[m [32m+[m[32m#if !defined (iPlatformTerminal)[m drawRectThickness_Paint(&p,[m adjusted_Rect(bounds, neg_I2(one_I2()), zero_I2()),[m isFocused ? gap_UI / 4 : 1,[m isFocused ? uiInputFrameFocused_ColorId[m [31m- : isHover ? uiInputFrameHover_ColorId : uiInputFrame_ColorId);[m [32m+[m[32m : isHover ? uiInputFrameHover_ColorId : uiInputFrame_ColorId);[m [32m+[m[32m#endif[m if (d->sysCtrl) {[m /* The system-provided control is drawing the text. */[m drawChildren_Widget(w);[m [36m@@ -2779,7 +2790,7 @@[m [mstatic void draw_InputWidget_(const iInputWidget *d) {[m wrapText.context = NULL;[m }[m /* Draw the insertion point. */[m [31m- if (isFocused && (d->cursorVis || !prefs_App()->blinkingCursor) &&[m [32m+[m[32m if (isFocused && (d->cursorVis || !isBlinkingCursor_()) &&[m contains_Range(&visLines, d->cursor.y) &&[m (deviceType_App() == desktop_AppDeviceType || isEmpty_Range(&d->mark))) {[m iInt2 curSize;[m [36m@@ -2818,6 +2829,10 @@[m [mstatic void draw_InputWidget_(const iInputWidget *d) {[m addX_I2(advance,[m (d->mode == insert_InputMode ? -curSize.x / 2 : 0)));[m const iRect curRect = { curPos, curSize };[m [32m+[m[32m#if defined (SDL_SEAL_CURSES)[m [32m+[m[32m /* Tell where to place the terminal cursor. */[m [32m+[m[32m SDL_SetTextInputRect((const SDL_Rect *) &curRect);[m[41m [m [32m+[m[32m#endif[m fillRect_Paint(&p, curRect, uiInputCursor_ColorId);[m if (d->mode == overwrite_InputMode) {[m /* The `gap_UI` offset below is a hack. They are used because for some reason the[m [1mdiff --git a/src/ui/keys.h b/src/ui/keys.h[m [1mindex b4ea3e5d..751af068 100644[m [1m--- a/src/ui/keys.h[m [1m+++ b/src/ui/keys.h[m [36m@@ -33,7 +33,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m # define preferences_KeyShortcut SDLK_COMMA, 0[m # define reload_KeyShortcut SDLK_r, 0[m # define newTab_KeyShortcut SDLK_t, 0[m [31m-# define closeTab_KeyShortcut SDLK_w, KMOD_SHIFT[m [32m+[m[32m# define closeTab_KeyShortcut SDLK_w, KMOD_PRIMARY[m # define prevTab_KeyShortcut SDLK_LEFTBRACKET, 0[m # define nextTab_KeyShortcut SDLK_RIGHTBRACKET, 0[m # define navigateBack_KeyShortcut SDLK_LEFT, 0[m [36m@@ -42,10 +42,11 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m # define navigateRoot_KeyShortcut SDLK_r, KMOD_PRIMARY[m # define subscribeToPage_KeyShortcut SDLK_d, 0[m # define leftSidebar_KeyShortcut SDLK_l, KMOD_SHIFT[m [32m+[m[32m# define rightSidebar_KeyShortcut SDLK_p, KMOD_SHIFT[m # define leftSidebarTab_KeyModifier 0[m # define byWord_KeyModifier KMOD_ALT[m # define byLine_KeyModifier KMOD_PRIMARY[m [31m-# define rightSidebarTab_KeyModifier KMOD_CTRL[m [32m+[m[32m# define rightSidebarTab_KeyModifier KMOD_ALT[m #elif defined (iPlatformApple)[m # define pageInfo_KeyShortcut SDLK_i, KMOD_PRIMARY[m # define preferences_KeyShortcut SDLK_COMMA, KMOD_PRIMARY[m [36m@@ -60,6 +61,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m # define navigateRoot_KeyShortcut SDLK_UP, KMOD_SHIFT | KMOD_PRIMARY[m # define subscribeToPage_KeyShortcut SDLK_d, KMOD_SHIFT | KMOD_PRIMARY[m # define leftSidebar_KeyShortcut SDLK_l, KMOD_PRIMARY | KMOD_SHIFT[m [32m+[m[32m# define rightSidebar_KeyShortcut SDLK_p, KMOD_PRIMARY | KMOD_SHIFT[m # define leftSidebarTab_KeyModifier KMOD_PRIMARY[m # define byWord_KeyModifier KMOD_ALT[m # define byLine_KeyModifier KMOD_PRIMARY[m [36m@@ -78,6 +80,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m # define navigateRoot_KeyShortcut SDLK_UP, KMOD_SHIFT | KMOD_ALT[m # define subscribeToPage_KeyShortcut SDLK_d, KMOD_SHIFT | KMOD_PRIMARY[m # define leftSidebar_KeyShortcut SDLK_l, KMOD_PRIMARY | KMOD_SHIFT[m [32m+[m[32m# define rightSidebar_KeyShortcut SDLK_p, KMOD_PRIMARY | KMOD_SHIFT[m # define leftSidebarTab_KeyModifier KMOD_PRIMARY[m # define byWord_KeyModifier KMOD_CTRL[m # define byLine_KeyModifier 0[m [1mdiff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c[m [1mindex 926cfecd..074e5309 100644[m [1m--- a/src/ui/labelwidget.c[m [1m+++ b/src/ui/labelwidget.c[m [36m@@ -368,6 +368,12 @@[m [mstatic void draw_LabelWidget_(const iLabelWidget *d) {[m init_Paint(&p);[m int bg, fg, frame, frame2, iconColor, metaColor;[m getColors_LabelWidget_(d, &bg, &fg, &frame, &frame2, &iconColor, &metaColor);[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m /* Indicate focused label with an underline attribute. */[m [32m+[m[32m if (isFocused_Widget(w)) {[m [32m+[m[32m fg |= underline_ColorId;[m [32m+[m[32m }[m [32m+[m[32m#endif[m setBaseAttributes_Text(d->font, fg);[m const enum iColorId colorEscape = parseEscape_Color(cstr_String(&d->label), NULL);[m const iBool isCaution = (colorEscape == uiTextCaution_ColorId);[m [36m@@ -376,7 +382,7 @@[m [mstatic void draw_LabelWidget_(const iLabelWidget *d) {[m }[m if (isFocused_Widget(w)) {[m iRect frameRect = adjusted_Rect(rect, zero_I2(), init1_I2(-1));[m [31m- drawRectThickness_Paint(&p, frameRect, gap_UI / 4, frame); [m [32m+[m[32m drawRectThickness_Paint(&p, frameRect, gap_UI / 4, uiTextAction_ColorId /*frame*/);[m[41m [m }[m else if (~flags & frameless_WidgetFlag) {[m iRect frameRect = adjusted_Rect(rect, zero_I2(), init1_I2(-1));[m [1mdiff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c[m [1mindex e14b43a9..3339ce14 100644[m [1m--- a/src/ui/lookupwidget.c[m [1m+++ b/src/ui/lookupwidget.c[m [36m@@ -397,6 +397,9 @@[m [mvoid init_LookupWidget(iLookupWidget *d) {[m d->list = addChildFlags_Widget(w, iClob(new_ListWidget()),[m resizeToParentWidth_WidgetFlag |[m resizeToParentHeight_WidgetFlag);[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m setPadding_Widget(as_Widget(d->list), 2, 2, 2, 2);[m [32m+[m[32m#endif[m d->cursor = iInvalidPos;[m d->work = new_Thread(worker_LookupWidget_);[m setUserData_Thread(d->work, d);[m [36m@@ -683,7 +686,7 @@[m [mstatic iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) {[m : bottomLeft_Rect(bounds_Widget(url));[m setPos_Widget([m w, windowToLocal_Widget(w, max_I2(zero_I2(), addX_I2(topLeft, -extraWidth / 2))));[m [31m-#if defined(iPlatformMobile)[m [32m+[m[32m#if defined (iPlatformMobile)[m /* TODO: Check this again. */[m /* Adjust height based on keyboard size. */ {[m if (!atBottom) {[m [1mdiff --git a/src/ui/metrics.c b/src/ui/metrics.c[m [1mindex 1379207a..c3b7f339 100644[m [1m--- a/src/ui/metrics.c[m [1m+++ b/src/ui/metrics.c[m [36m@@ -28,7 +28,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m #if defined (iPlatformTerminal)[m # define defaultFontSize_Metrics 1[m # define defaultGap_Metrics 1[m [31m-const float aspect_UI = 0.4f;[m [32m+[m[32mconst float aspect_UI = 0.5f;[m #else[m # define defaultFontSize_Metrics 18[m # define defaultGap_Metrics 4[m [1mdiff --git a/src/ui/paint.c b/src/ui/paint.c[m [1mindex 5f19ec3e..ba9fbdab 100644[m [1m--- a/src/ui/paint.c[m [1m+++ b/src/ui/paint.c[m [36m@@ -125,6 +125,11 @@[m [mvoid drawRect_Paint(const iPaint *d, iRect rect, int color) {[m }[m [m void drawRectThickness_Paint(const iPaint *d, iRect rect, int thickness, int color) {[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m if (thickness == 0) {[m [32m+[m[32m addv_I2(&rect.size, one_I2());[m [32m+[m[32m }[m [32m+[m[32m#endif[m thickness = iClamp(thickness, 1, 4);[m while (thickness--) {[m drawRect_Paint(d, rect, color);[m [1mdiff --git a/src/ui/root.c b/src/ui/root.c[m [1mindex b0bffd58..0f3c831c 100644[m [1m--- a/src/ui/root.c[m [1m+++ b/src/ui/root.c[m [36m@@ -63,7 +63,7 @@[m [mstatic const iMenuItem desktopNavMenuItems_[] = {[m { "${menu.page.copysource}", SDLK_c, KMOD_PRIMARY, "copy" },[m { "---" },[m { leftHalf_Icon " ${menu.sidebar.left}", leftSidebar_KeyShortcut, "sidebar.toggle" },[m [31m- { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },[m [32m+[m[32m { rightHalf_Icon " ${menu.sidebar.right}", rightSidebar_KeyShortcut, "sidebar2.toggle" },[m { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },[m { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },[m { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },[m [36m@@ -90,7 +90,7 @@[m [mstatic const iMenuItem tabletNavMenuItems_[] = {[m { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" },[m { "---" },[m { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" },[m [31m- { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },[m [32m+[m[32m { rightHalf_Icon " ${menu.sidebar.right}", rightSidebar_KeyShortcut, "sidebar2.toggle" },[m { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },[m { "---" },[m { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },[m [1mdiff --git a/src/ui/scrollwidget.c b/src/ui/scrollwidget.c[m [1mindex 1ea8d3ba..3e06ee90 100644[m [1m--- a/src/ui/scrollwidget.c[m [1m+++ b/src/ui/scrollwidget.c[m [36m@@ -30,6 +30,14 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m [m iDefineObjectConstruction(ScrollWidget)[m [m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32mconst int fadeTime_ScrollWidget_ = 10;[m [32m+[m[32mconst int unfadeTime_ScrollWidget_ = 10;[m [32m+[m[32m#else[m [32m+[m[32mconst int fadeTime_ScrollWidget_ = 200;[m [32m+[m[32mconst int unfadeTime_ScrollWidget_ = 66;[m [32m+[m[32m#endif[m [32m+[m static float minOpacity_(void) {[m #if !defined (iPlatformApple)[m if (deviceType_App() == desktop_AppDeviceType) {[m [36m@@ -125,7 +133,7 @@[m [mstatic iRect thumbRect_ScrollWidget_(const iScrollWidget *d) {[m static void unfade_ScrollWidget_(iScrollWidget *d, float opacity) {[m d->fadeStart = SDL_GetTicks() + 1000;[m if (targetValue_Anim(&d->opacity) < opacity) {[m [31m- setValue_Anim(&d->opacity, opacity, 66);[m [32m+[m[32m setValue_Anim(&d->opacity, opacity, unfadeTime_ScrollWidget_);[m addTickerRoot_App(animateOpacity_ScrollWidget_, as_Widget(d)->root, d);[m }[m if (!d->willCheckFade && d->fadeEnabled) {[m [36m@@ -180,7 +188,7 @@[m [mstatic iBool processEvent_ScrollWidget_(iScrollWidget *d, const SDL_Event *ev) {[m }[m if (isCommand_UserEvent(ev, "scrollbar.fade")) {[m if (d->fadeEnabled && d->willCheckFade && SDL_GetTicks() > d->fadeStart) {[m [31m- setValue_Anim(&d->opacity, minOpacity_(), 200);[m [32m+[m[32m setValue_Anim(&d->opacity, minOpacity_(), fadeTime_ScrollWidget_);[m remove_Periodic(periodic_App(), d);[m d->willCheckFade = iFalse;[m if (!isFinished_Anim(&d->opacity)) {[m [1mdiff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c[m [1mindex ccf9c8a4..bd5e2109 100644[m [1m--- a/src/ui/sidebarwidget.c[m [1m+++ b/src/ui/sidebarwidget.c[m [36m@@ -698,7 +698,12 @@[m [mstatic size_t findItem_SidebarWidget_(const iSidebarWidget *d, int id) {[m }[m [m static void updateItemHeight_SidebarWidget_(iSidebarWidget *d) {[m [31m- const float heights[max_SidebarMode] = { 1.333f, 2.333f, 1.333f, 3.5f, 1.2f };[m [32m+[m[32m /* Note: identity item height is defined by CertListWidget */[m [32m+[m[32m#if !defined (iPlatformTerminal)[m [32m+[m[32m const float heights[max_SidebarMode] = { 1.333f, 2.333f, 1.333f, 0, 1.2f };[m [32m+[m[32m#else[m [32m+[m[32m const float heights[max_SidebarMode] = { 1, 3, 1, 0, 1 };[m [32m+[m[32m#endif[m if (d->list) {[m setItemHeight_ListWidget(d->list, heights[d->mode] * lineHeight_Text(d->itemFonts[0]));[m }[m [36m@@ -2050,7 +2055,7 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)[m : (tmHeading1_ColorId + d->indent / (4 * gap_UI));[m drawRange_Text(font,[m [31m- init_I2(pos.x + 3 * gap_UI + d->indent,[m [32m+[m[32m init_I2(pos.x + (3 * gap_UI + d->indent) * aspect_UI,[m mid_Rect(itemRect).y - lineHeight_Text(font) / 2),[m fg,[m range_String(&d->label));[m [36m@@ -2069,7 +2074,7 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m drawRange_Text([m uiLabelLargeBold_FontId,[m add_I2(pos,[m [31m- init_I2(3 * gap_UI,[m [32m+[m[32m init_I2(3 * gap_UI * aspect_UI,[m itemHeight - lineHeight_Text(uiLabelLargeBold_FontId) - 1 * gap_UI)),[m uiIcon_ColorId,[m range_String(&d->meta));[m [36m@@ -2079,14 +2084,7 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m const int titleFont = sidebar->itemFonts[isUnread ? 1 : 0];[m const int h1 = lineHeight_Text(uiLabel_FontId);[m const int h2 = lineHeight_Text(titleFont);[m [31m- iRect iconArea = { addY_I2(pos, 0), init_I2(iconPad, itemHeight) };[m [31m- /*[m [31m- if (isUnread) {[m [31m- fillRect_Paint([m [31m- p,[m [31m- (iRect){ topLeft_Rect(iconArea), init_I2(gap_UI / 2, height_Rect(iconArea)) },[m [31m- iconColor);[m [31m- }*/[m [32m+[m[32m iRect iconArea = { addY_I2(pos, 0), init_I2(iconPad * aspect_UI, itemHeight) };[m /* Icon. */ {[m /* TODO: Use the primary hue from the theme of this site. */[m iString str;[m [36m@@ -2111,7 +2109,7 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m int metaFg = isPressing ? fg : uiSubheading_ColorId;[m iInt2 titleSize = measureRange_Text(titleFont, range_String(&d->label)).bounds.size;[m const iInt2 metaSize = measureRange_Text(uiLabel_FontId, range_String(&d->meta)).bounds.size;[m [31m- pos.x += iconPad;[m [32m+[m[32m pos.x += iconPad * aspect_UI;[m const int avail = width_Rect(itemRect) - iconPad - 3 * gap_UI;[m const int labelFg = isPressing ? fg : (isUnread ? uiTextStrong_ColorId : uiText_ColorId);[m if (titleSize.x > avail && metaSize.x < avail * 0.75f) {[m [36m@@ -2150,7 +2148,7 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m appendChar_String(&str, d->icon ? d->icon : 0x1f588);[m const int leftIndent = d->indent * gap_UI * 4;[m const iRect iconArea = { addX_I2(pos, gap_UI + leftIndent),[m [31m- init_I2(1.75f * lineHeight_Text(font), itemHeight) };[m [32m+[m[32m init_I2(1.75f * lineHeight_Text(font) / aspect_UI, itemHeight) };[m drawCentered_Text(font,[m iconArea,[m iTrue,[m [36m@@ -2217,7 +2215,8 @@[m [mstatic void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,[m drawRange_Text([m uiLabelLargeBold_FontId,[m add_I2(drawPos,[m [31m- init_I2(3 * gap_UI, (itemHeight - lineHeight_Text(uiLabelLargeBold_FontId)) / 2)),[m [32m+[m[32m init_I2(3 * gap_UI * aspect_UI,[m [32m+[m[32m (itemHeight - lineHeight_Text(uiLabelLargeBold_FontId)) / 2)),[m uiIcon_ColorId,[m range_String(&d->meta));[m }[m [1mdiff --git a/src/ui/text.c b/src/ui/text.c[m [1mindex bf3ddf6e..ccb15151 100644[m [1m--- a/src/ui/text.c[m [1m+++ b/src/ui/text.c[m [36m@@ -180,6 +180,7 @@[m [mstatic void drawBoundedN_Text_(int fontId, iInt2 pos, int boundWidth, iBool just[m &(iRunArgs){ .mode = draw_RunMode |[m (color & permanent_ColorId ? permanentColorFlag_RunMode : 0) |[m (color & fillBackground_ColorId ? fillBackground_RunMode : 0) |[m [32m+[m[32m (color & underline_ColorId ? underline_RunMode : 0) |[m runFlags_FontId(fontId),[m .text = text,[m .maxLen = maxLen,[m [36m@@ -241,6 +242,7 @@[m [mvoid drawRangeN_Text(int fontId, iInt2 pos, int color, iRangecc text, size_t max[m }[m [m void drawOutline_Text(int fontId, iInt2 pos, int outlineColor, int fillColor, iRangecc text) {[m [32m+[m[32m#if !defined (iPlatformTerminal)[m for (int off = 0; off < 4; ++off) {[m drawRange_Text(fontId,[m add_I2(pos, init_I2(off % 2 == 0 ? -1 : 1, off / 2 == 0 ? -1 : 1)),[m [36m@@ -250,6 +252,9 @@[m [mvoid drawOutline_Text(int fontId, iInt2 pos, int outlineColor, int fillColor, iR[m if (fillColor != none_ColorId) {[m drawRange_Text(fontId, pos, fillColor, text);[m }[m [32m+[m[32m#else[m [32m+[m[32m drawRange_Text(fontId, pos, fillColor | fillBackground_ColorId, text);[m [32m+[m[32m#endif[m[41m [m }[m [m iTextMetrics measureWrapRange_Text(int fontId, int maxWidth, iRangecc text) {[m [1mdiff --git a/src/ui/text_simple.c b/src/ui/text_simple.c[m [1mindex fceb7a66..04e2ee74 100644[m [1m--- a/src/ui/text_simple.c[m [1m+++ b/src/ui/text_simple.c[m [36m@@ -108,12 +108,16 @@[m [mstatic iRect runSimple_Font_(iFont *d, const iRunArgs *args) {[m SDL_SetRenderTextAttributes([m render,[m (style == bold_FontStyle || style == semiBold_FontStyle ? SDL_TEXT_ATTRIBUTE_BOLD : 0) |[m [31m- (style == italic_FontStyle ? SDL_TEXT_ATTRIBUTE_ITALIC : 0));[m [32m+[m[32m (style == italic_FontStyle ? SDL_TEXT_ATTRIBUTE_ITALIC : 0) |[m [32m+[m[32m (mode & underline_RunMode ? SDL_TEXT_ATTRIBUTE_BOLD | SDL_TEXT_ATTRIBUTE_UNDERLINE : 0));[m #endif[m [31m- }[m [31m- if (args->mode & fillBackground_RunMode) {[m [31m- const iColor initial = get_Color(args->color);[m [31m- SDL_SetRenderDrawColor(render, initial.r, initial.g, initial.b, 0);[m [32m+[m[32m if (args->mode & fillBackground_RunMode) {[m [32m+[m[32m const iColor initial = get_Color(args->color);[m [32m+[m[32m SDL_SetRenderDrawColor(render, initial.r, initial.g, initial.b, 0);[m [32m+[m[32m//#if defined (SDL_SEAL_CURSES)[m [32m+[m[32m// SDL_SetRenderTextFillColor(render, initial.r, initial.g, initial.b, 255);[m [32m+[m[32m//#endif[m [32m+[m[32m }[m }[m /* Text rendering is not very straightforward! Let's dive in... */[m iChar prevCh = 0;[m [36m@@ -409,6 +413,11 @@[m [mstatic iRect runSimple_Font_(iFont *d, const iRunArgs *args) {[m if (args->runAdvance_out) {[m *args->runAdvance_out = xposMax - orig.x;[m }[m [32m+[m[32m#if defined (SDL_SEAL_CURSES)[m [32m+[m[32m if (mode & draw_RunMode) {[m [32m+[m[32m SDL_SetRenderTextFillColor(render, 0, 0, 0, 0);[m [32m+[m[32m }[m [32m+[m[32m#endif[m return bounds;[m }[m [m [1mdiff --git a/src/ui/text_terminal.c b/src/ui/text_terminal.c[m [1mindex 9f9a0a66..4f94d07e 100644[m [1m--- a/src/ui/text_terminal.c[m [1m+++ b/src/ui/text_terminal.c[m [36m@@ -49,12 +49,6 @@[m [mstruct Impl_Font {[m static const iGlyph *glyph_Font_(iFont *d, iChar ch) {[m int w = width_Char(ch);[m w = iMin(2, w);[m [31m-// if (ch == 0x200b) { /* zero-width code points */[m [31m-// w = 0; [m [31m-// }[m [31m-// else if (isEmoji_Char(ch) || ch == 0x2014 /* em dash */) {[m [31m-// w = 2;[m [31m-// }[m return &d->glyphs[w]; [m }[m [m [36m@@ -67,19 +61,19 @@[m [mstatic iBool isRasterized_Glyph_(const iGlyph *d, int hoff) {[m return iTrue;[m }[m [m [31m-static void init_Font(iFont *d) {[m [32m+[m[32mstatic void init_Font(iFont *d, int height) {[m d->spec = new_FontSpec(); [m d->font.file = NULL;[m d->font.spec = d->spec;[m [31m- d->font.height = 1;[m [32m+[m[32m d->font.height = height;[m d->baseline = 0;[m for (int i = 0; i < 3; i++) {[m iGlyph *glyph = &d->glyphs[i];[m glyph->font = d;[m glyph->advance = i;[m for (size_t j = 0; j < iElemCount(glyph->d); j++) {[m [31m- glyph->d[j] = zero_I2();[m [31m- glyph->rect[j] = init_Rect(0, 0, i, 1);[m [32m+[m[32m glyph->d[j] = init_I2(0, height / 2);[m [32m+[m[32m glyph->rect[j] = init_Rect(0, 0, i, height);[m }[m }[m }[m [36m@@ -96,7 +90,7 @@[m [miDeclareType(TuiText)[m [m struct Impl_TuiText {[m iText base;[m [31m- iFont fonts[3]; /* regular, bold, italic */[m [32m+[m[32m iFont fonts[2][3]; /* height / regular, bold, italic */[m };[m [m iLocalDef iTuiText *current_TuiText_(void) {[m [36m@@ -104,19 +98,28 @@[m [miLocalDef iTuiText *current_TuiText_(void) {[m }[m [m iBaseFont *font_Text(enum iFontId id) {[m [31m- const enum iFontStyle style = style_FontId(id); [m [31m- size_t index = (style == bold_FontStyle || style == semiBold_FontStyle ? 1 :[m [31m- style == italic_FontStyle ? 2 : 0);[m [31m- return ¤t_TuiText_()->fonts[index].font;[m [32m+[m[32m const enum iFontStyle style = style_FontId(id);[m [32m+[m[32m const enum iFontSize size = size_FontId(id);[m[41m [m [32m+[m[32m size_t sizeIndex = (size == contentHuge_FontSize ? 1 : 0);[m [32m+[m[32m size_t index = (style == bold_FontStyle || style == semiBold_FontStyle ? 1[m [32m+[m[32m : style == italic_FontStyle ? 2[m [32m+[m[32m : 0);[m [32m+[m[32m return ¤t_TuiText_()->fonts[sizeIndex][index].font;[m }[m [m enum iFontId fontId_Text(const iAnyFont *font) {[m [31m- const iTuiText *d = current_TuiText_();[m [31m- if (font == &d->fonts[2]) {[m [31m- return FONT_ID(default_FontId, italic_FontStyle, 0);[m [31m- }[m [31m- if (font == &d->fonts[1]) {[m [31m- return FONT_ID(default_FontId, bold_FontStyle, 0);[m [32m+[m[32m for (size_t sizeIndex = 0; sizeIndex < 2; sizeIndex++) {[m [32m+[m[32m const iTuiText *d = current_TuiText_();[m [32m+[m[32m const enum iFontSize size = (sizeIndex == 1 ? contentHuge_FontSize : 0);[m [32m+[m[32m if (font == &d->fonts[sizeIndex][2]) {[m [32m+[m[32m return FONT_ID(default_FontId, italic_FontStyle, size);[m [32m+[m[32m }[m [32m+[m[32m if (font == &d->fonts[sizeIndex][1]) {[m [32m+[m[32m return FONT_ID(default_FontId, bold_FontStyle, size);[m [32m+[m[32m }[m [32m+[m[32m if (font == &d->fonts[sizeIndex][0]) {[m [32m+[m[32m return FONT_ID(default_FontId, regular_FontStyle, size);[m [32m+[m[32m }[m }[m return default_FontId;[m }[m [36m@@ -128,15 +131,19 @@[m [miBaseFont *characterFont_BaseFont(iBaseFont *d, iChar ch) {[m [m static void init_TuiText(iTuiText *d, SDL_Renderer *render) {[m init_Text(&d->base, render);[m [31m- iForIndices(i, d->fonts) {[m [31m- init_Font(d->fonts + i);[m [32m+[m[32m iForIndices(s, d->fonts) {[m [32m+[m[32m iForIndices(i, d->fonts[s]) {[m [32m+[m[32m init_Font(d->fonts[s] + i, s == 1 ? 2 : 1);[m [32m+[m[32m }[m[41m [m }[m gap_Text = gap_UI;[m }[m [m static void deinit_TuiText(iTuiText *d) {[m [31m- iForIndices(i, d->fonts) {[m [31m- deinit_Font(d->fonts + i);[m [32m+[m[32m iForIndices(s, d->fonts) {[m [32m+[m[32m iForIndices(i, d->fonts[s]) {[m [32m+[m[32m deinit_Font(d->fonts[s] + i);[m [32m+[m[32m }[m }[m deinit_Text(&d->base);[m }[m [1mdiff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c[m [1mindex 16622cab..8ed38a99 100644[m [1m--- a/src/ui/uploadwidget.c[m [1m+++ b/src/ui/uploadwidget.c[m [36m@@ -177,7 +177,7 @@[m [mvoid init_UploadWidget(iUploadWidget *d) {[m { "${upload.port}", 0, 0, "upload.setport" },[m { "---" },[m { "${close}", SDLK_ESCAPE, 0, "upload.cancel" },[m [31m- { uiTextAction_ColorEscape "${dlg.upload.send}", SDLK_RETURN, KMOD_PRIMARY, "upload.accept" }[m [32m+[m[32m { uiTextAction_ColorEscape "${dlg.upload.send}", SDLK_RETURN, KMOD_ACCEPT, "upload.accept" }[m };[m if (isUsingPanelLayout_Mobile()) {[m const int infoFont = (deviceType_App() == phone_AppDeviceType ? uiLabelBig_FontId[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex e71a7483..a46d6117 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -82,7 +82,41 @@[m [mstatic void removePlus_(iString *str) {[m }[m [m void toString_Sym(int key, int kmods, iString *str) {[m [31m-#if defined (iPlatformApple)[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m if (kmods & KMOD_CTRL) {[m [32m+[m[32m appendCStr_String(str, "^");[m [32m+[m[32m }[m [32m+[m[32m if (kmods & (KMOD_ALT | KMOD_GUI)) {[m [32m+[m[32m appendCStr_String(str, "M-");[m [32m+[m[32m }[m [32m+[m[32m if (kmods & KMOD_SHIFT) {[m [32m+[m[32m appendCStr_String(str, "Sh-");[m [32m+[m[32m }[m [32m+[m[32m if (key == SDLK_BACKSPACE) {[m [32m+[m[32m removePlus_(str);[m [32m+[m[32m appendCStr_String(str, "BSP"); /* Erase to the Left */[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m else if (key == 0x20) {[m [32m+[m[32m appendCStr_String(str, "SPC");[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m else if (key == SDLK_ESCAPE) {[m [32m+[m[32m removePlus_(str);[m [32m+[m[32m appendCStr_String(str, "ESC"); /* Erase to the Right */[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m else if (key == SDLK_DELETE) {[m [32m+[m[32m removePlus_(str);[m [32m+[m[32m appendCStr_String(str, "DEL"); /* Erase to the Right */[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m else if (key == SDLK_RETURN) {[m [32m+[m[32m removePlus_(str);[m [32m+[m[32m appendCStr_String(str, "RET"); /* Leftwards arrow with a hook */[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m#elif defined (iPlatformApple)[m if (kmods & KMOD_CTRL) {[m appendChar_String(str, 0x2303);[m }[m [36m@@ -683,6 +717,7 @@[m [mstatic iBool isCommandIgnoredByMenus_(const char *cmd) {[m equal_Command(cmd, "window.mouse.entered") ||[m equal_Command(cmd, "input.backup") ||[m equal_Command(cmd, "input.ended") ||[m [32m+[m[32m equal_Command(cmd, "focus.gained") ||[m equal_Command(cmd, "focus.lost") ||[m (equal_Command(cmd, "mouse.clicked") && !arg_Command(cmd)); /* button released */[m }[m [36m@@ -741,6 +776,7 @@[m [mstatic iWidget *makeMenuSeparator_(void) {[m if (deviceType_App() != desktop_AppDeviceType) {[m sep->rect.size.y = gap_UI / 2;[m }[m [32m+[m[32m sep->rect.size.y = iMax(1, sep->rect.size.y);[m setFlags_Widget(sep, hover_WidgetFlag | fixedHeight_WidgetFlag, iTrue);[m return sep;[m }[m [36m@@ -919,6 +955,9 @@[m [miWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {[m else {[m setPadding1_Widget(menu, gap_UI / 2);[m }[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m setPadding1_Widget(menu, 3);[m [32m+[m[32m#endif[m setFlags_Widget(menu,[m keepOnTop_WidgetFlag | collapse_WidgetFlag | hidden_WidgetFlag |[m arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag |[m [36m@@ -1073,7 +1112,8 @@[m [miLocalDef iBool isUsingMenuPopupWindows_(void) {[m }[m [m void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m [31m- const iBool postCommands = (menuOpenFlags & postCommands_MenuOpenFlags) != 0;[m [32m+[m[32m const iBool postCommands = (menuOpenFlags & postCommands_MenuOpenFlags) != 0;[m [32m+[m[32m const iBool isMenuFocused = (focus_Widget() == parent_Widget(d));[m #if defined (LAGRANGE_MAC_CONTEXTMENU)[m const iArray *items = userData_Object(d);[m iAssert(flags_Widget(d) & nativeMenu_WidgetFlag);[m [36m@@ -1242,7 +1282,10 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m postCommand_Widget(d, "menu.opened");[m }[m setupMenuTransition_Mobile(d, iTrue);[m [31m-#endif [m [32m+[m[32m#endif[m [32m+[m[32m if (isMenuFocused) {[m [32m+[m[32m setFocus_Widget(child_Widget(d, 0));[m [32m+[m[32m }[m }[m [m void closeMenu_Widget(iWidget *d) {[m [36m@@ -2096,6 +2139,8 @@[m [mstatic iBool messageHandler_(iWidget *msg, const char *cmd) {[m equal_Command(cmd, "edgeswipe.ended") ||[m equal_Command(cmd, "layout.changed") ||[m equal_Command(cmd, "theme.changed") ||[m [32m+[m[32m equal_Command(cmd, "focus.lost") ||[m [32m+[m[32m equal_Command(cmd, "focus.gained") ||[m[41m [m startsWith_CStr(cmd, "feeds.update.") ||[m startsWith_CStr(cmd, "window."))) {[m setupSheetTransition_Mobile(msg, dialogTransitionDir_Widget(msg));[m [36m@@ -2500,6 +2545,18 @@[m [miWidget *makeDialog_Widget(const char *id,[m return dlg;[m }[m [m [32m+[m[32mstatic const char *returnKeyBehaviorStr_(int behavior) {[m [32m+[m[32m iString *nl = collectNew_String();[m [32m+[m[32m iString *ac = collectNew_String();[m [32m+[m[32m toString_Sym(SDLK_RETURN, lineBreakKeyMod_ReturnKeyBehavior(behavior), nl);[m [32m+[m[32m toString_Sym(SDLK_RETURN, acceptKeyMod_ReturnKeyBehavior(behavior), ac);[m [32m+[m[32m return format_CStr("${prefs.returnkey.linebreak} " uiTextAction_ColorEscape[m [32m+[m[32m "%s" restore_ColorEscape[m [32m+[m[32m " ${prefs.returnkey.accept} " uiTextAction_ColorEscape "%s",[m [32m+[m[32m cstr_String(nl),[m [32m+[m[32m cstr_String(ac));[m [32m+[m[32m}[m [32m+[m iWidget *makePreferences_Widget(void) {[m /* Common items. */[m const iMenuItem langItems[] = { { u8"Čeština - cs", 0, 0, "uilang id:cs" },[m [36m@@ -2528,27 +2585,25 @@[m [miWidget *makePreferences_Widget(void) {[m { u8"繁體/正體中文 - zh", 0, 0, "uilang id:zh_Hant" },[m { NULL } };[m const iMenuItem returnKeyBehaviors[] = {[m [31m- { "${prefs.returnkey.linebreak} " uiTextAction_ColorEscape shift_Icon return_Icon[m [31m- restore_ColorEscape[m [31m- " ${prefs.returnkey.accept} " uiTextAction_ColorEscape return_Icon,[m [32m+[m[32m { returnKeyBehaviorStr_(default_ReturnKeyBehavior),[m 0,[m 0,[m format_CStr("returnkey.set arg:%d", default_ReturnKeyBehavior) },[m [31m- { "${prefs.returnkey.linebreak} " uiTextAction_ColorEscape return_Icon restore_ColorEscape[m [31m- " ${prefs.returnkey.accept} " uiTextAction_ColorEscape shift_Icon return_Icon,[m [32m+[m[32m#if !defined (iPlatformTerminal)[m [32m+[m[32m { returnKeyBehaviorStr_(RETURN_KEY_BEHAVIOR(0, shift_ReturnKeyFlag)),[m 0,[m 0,[m [31m- format_CStr("returnkey.set arg:%d", acceptWithShift_ReturnKeyBehavior) },[m [31m- { "${prefs.returnkey.linebreak} " uiTextAction_ColorEscape return_Icon restore_ColorEscape[m [31m- " ${prefs.returnkey.accept} " uiTextAction_ColorEscape[m [31m-#if defined (iPlatformApple)[m [31m- "\u2318" return_Icon,[m [31m-#else[m [31m- "Ctrl" return_Icon,[m [31m-#endif[m [32m+[m[32m format_CStr("returnkey.set arg:%d", RETURN_KEY_BEHAVIOR(0, shift_ReturnKeyFlag)) },[m [32m+[m[32m { returnKeyBehaviorStr_(acceptWithPrimaryMod_ReturnKeyBehavior),[m 0,[m 0,[m format_CStr("returnkey.set arg:%d", acceptWithPrimaryMod_ReturnKeyBehavior) },[m [32m+[m[32m#else[m [32m+[m[32m { returnKeyBehaviorStr_(RETURN_KEY_BEHAVIOR(gui_ReturnKeyFlag, 0)),[m [32m+[m[32m 0,[m [32m+[m[32m 0,[m [32m+[m[32m format_CStr("returnkey.set arg:%d", RETURN_KEY_BEHAVIOR(gui_ReturnKeyFlag, 0)) },[m[41m [m [32m+[m[32m#endif[m { NULL }[m };[m iMenuItem toolbarActionItems[2][max_ToolbarAction];[m [36m@@ -3140,7 +3195,7 @@[m [mstatic const iArray *makeBookmarkFolderItems_(iBool withNullTerminator) {[m iWidget *makeBookmarkEditor_Widget(iBool isFolder) {[m const iMenuItem actions[] = {[m { "${cancel}", 0, 0, "bmed.cancel" },[m [31m- { uiTextAction_ColorEscape "${dlg.bookmark.save}", SDLK_RETURN, KMOD_PRIMARY, "bmed.accept" }[m [32m+[m[32m { uiTextAction_ColorEscape "${dlg.bookmark.save}", SDLK_RETURN, KMOD_ACCEPT, "bmed.accept" }[m };[m iWidget *dlg = NULL;[m if (isUsingPanelLayout_Mobile()) {[m [36m@@ -3344,7 +3399,7 @@[m [miWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {[m { bookmarkId ? uiTextAction_ColorEscape "${dlg.feed.save}"[m : uiTextAction_ColorEscape "${dlg.feed.sub}",[m SDLK_RETURN,[m [31m- KMOD_PRIMARY,[m [32m+[m[32m KMOD_ACCEPT,[m format_CStr("feedcfg.accept bmid:%d", bookmarkId) } };[m if (isUsingPanelLayout_Mobile()) {[m const iMenuItem typeItems[] = {[m [36m@@ -3471,7 +3526,7 @@[m [miWidget *makeSiteSpecificSettings_Widget(const iString *url) {[m const char *sheetId = format_CStr("sitespec site:%s", cstr_Rangecc(urlRoot_String(url)));[m const iMenuItem actions[] = {[m { "${cancel}" },[m [31m- { uiTextAction_ColorEscape "${sitespec.accept}", SDLK_RETURN, KMOD_PRIMARY, "sitespec.accept" }[m [32m+[m[32m { uiTextAction_ColorEscape "${sitespec.accept}", SDLK_RETURN, KMOD_ACCEPT, "sitespec.accept" }[m };[m if (isUsingPanelLayout_Mobile()) {[m dlg = makePanels_Mobile(sheetId, (iMenuItem[]){[m [36m@@ -3529,7 +3584,7 @@[m [miWidget *makeIdentityCreation_Widget(void) {[m { "${cancel}", SDLK_ESCAPE, 0, "ident.cancel" },[m { uiTextAction_ColorEscape "${dlg.newident.create}",[m SDLK_RETURN,[m [31m- KMOD_PRIMARY,[m [32m+[m[32m KMOD_ACCEPT,[m "ident.accept" } };[m iUrl url;[m init_Url(&url, url_DocumentWidget(document_App()));[m [36m@@ -3847,7 +3902,7 @@[m [miWidget *makeUserDataImporter_Dialog(const iString *archivePath) {[m { "---" },[m { "${cancel}", SDLK_ESCAPE, 0, "importer.cancel" },[m { uiTextAction_ColorEscape "${import.userdata}",[m [31m- SDLK_RETURN, KMOD_PRIMARY,[m [32m+[m[32m SDLK_RETURN, KMOD_ACCEPT,[m format_CStr("importer.accept path:%s", cstr_String(archivePath)) },[m };[m if (isUsingPanelLayout_Mobile()) {[m [1mdiff --git a/src/ui/util.h b/src/ui/util.h[m [1mindex c7c7d542..44f1a7c4 100644[m [1m--- a/src/ui/util.h[m [1m+++ b/src/ui/util.h[m [36m@@ -75,12 +75,18 @@[m [miLocalDef iBool isScrollFinished_MouseWheelEvent(const SDL_MouseWheelEvent *ev)[m [m iInt2 coord_MouseWheelEvent (const SDL_MouseWheelEvent *);[m [m [31m-#if defined (iPlatformApple) && !defined (iPlatformTerminal)[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m# define KMOD_PRIMARY KMOD_CTRL[m [32m+[m[32m# define KMOD_SECONDARY KMOD_SHIFT[m [32m+[m[32m# define KMOD_ACCEPT KMOD_GUI[m [32m+[m[32m#elif defined (iPlatformApple)[m # define KMOD_PRIMARY KMOD_GUI[m # define KMOD_SECONDARY KMOD_CTRL[m [32m+[m[32m# define KMOD_ACCEPT KMOD_PRIMARY[m #else[m # define KMOD_PRIMARY KMOD_CTRL[m # define KMOD_SECONDARY KMOD_GUI[m [32m+[m[32m# define KMOD_ACCEPT KMOD_PRIMARY[m #endif[m [m enum iOpenTabFlag {[m [1mdiff --git a/src/ui/widget.c b/src/ui/widget.c[m [1mindex 938946c8..db08eed5 100644[m [1m--- a/src/ui/widget.c[m [1m+++ b/src/ui/widget.c[m [36m@@ -302,9 +302,9 @@[m [mvoid setMinSize_Widget(iWidget *d, iInt2 minSize) {[m [m void setPadding_Widget(iWidget *d, int left, int top, int right, int bottom) {[m if (d) {[m [31m- d->padding[0] = left;[m [32m+[m[32m d->padding[0] = left * aspect_UI;[m d->padding[1] = top * aspect_UI;[m [31m- d->padding[2] = right;[m [32m+[m[32m d->padding[2] = right * aspect_UI;[m d->padding[3] = bottom * aspect_UI;[m }[m }[m [36m@@ -1595,6 +1595,13 @@[m [mvoid drawBackground_Widget(const iWidget *d) {[m iPaint p;[m init_Paint(&p);[m if (d->bgColor >= 0) {[m [32m+[m[32m#if defined (iPlatformTerminal)[m [32m+[m[32m if (d->bgColor == uiSeparator_ColorId && rect.size.y == 1) {[m [32m+[m[32m fillRect_Paint(&p, adjusted_Rect(rect, zero_I2(), init_I2(0, -1)),[m [32m+[m[32m d->bgColor);[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m#endif[m fillRect_Paint(&p, rect, d->bgColor);[m }[m if (d->frameColor >= 0 && ~d->flags & frameless_WidgetFlag) {[m [1mdiff --git a/src/ui/window.c b/src/ui/window.c[m [1mindex 41488ca4..b64edc15 100644[m [1m--- a/src/ui/window.c[m [1m+++ b/src/ui/window.c[m [36m@@ -111,7 +111,7 @@[m [mstatic const iMenuItem viewMenuItems_[] = {[m { "${menu.show.outline}", '5', leftSidebarTab_KeyModifier, "sidebar.mode arg:4 toggle:1" },[m { "---" },[m { "${menu.sidebar.left}", leftSidebar_KeyShortcut, "sidebar.toggle" },[m [31m- { "${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },[m [32m+[m[32m { "${menu.sidebar.right}", rightSidebar_KeyShortcut, "sidebar2.toggle" },[m { "---" },[m { "${menu.back}", SDLK_LEFTBRACKET, KMOD_PRIMARY, "navigate.back" },[m { "${menu.forward}", SDLK_RIGHTBRACKET, KMOD_PRIMARY, "navigate.forward" },[m [36m@@ -1788,6 +1788,12 @@[m [mvoid setSplitMode_MainWindow(iMainWindow *d, int splitFlags) {[m }[m setCurrent_Root(NULL);[m }[m [32m+[m[32m /* Add some room for the active root indicator. */[m [32m+[m[32m for (int i = 0; i < 2; i++) {[m [32m+[m[32m if (w->roots[i]) {[m [32m+[m[32m w->roots[i]->widget->padding[1] = (splitMode ? 1 : 0);[m [32m+[m[32m }[m [32m+[m[32m }[m[41m [m d->splitMode = splitMode;[m postCommand_App("window.resized");[m #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME)[m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).