diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-05 07:02:33 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-05 07:02:33 +0300 |
commit | aa50c1e0028c6cb08524dcdfb7188906c817e46f (patch) | |
tree | 1f5d91bef261612680d589e0481dad99ef189619 | |
parent | de53b815e09a1004b8fb70706199fb840f53514a (diff) |
Option to force break very long lines
Even preformatted lines may need to be wrapped so the content remains visible, since there is no horizontal scrolling. However, this is off by default so ASCII art isn't broken in narrow windows.
-rw-r--r-- | src/app.c | 14 | ||||
-rw-r--r-- | src/app.h | 1 | ||||
-rw-r--r-- | src/gmdocument.c | 16 | ||||
-rw-r--r-- | src/gmdocument.h | 4 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 23 | ||||
-rw-r--r-- | src/ui/window.c | 2 |
6 files changed, 44 insertions, 16 deletions
@@ -94,6 +94,7 @@ struct Impl_App { | |||
94 | iRect initialWindowRect; | 94 | iRect initialWindowRect; |
95 | float uiScale; | 95 | float uiScale; |
96 | int zoomPercent; | 96 | int zoomPercent; |
97 | iBool forceWrap; | ||
97 | enum iColorTheme theme; | 98 | enum iColorTheme theme; |
98 | iBool useSystemTheme; | 99 | iBool useSystemTheme; |
99 | iString gopherProxy; | 100 | iString gopherProxy; |
@@ -146,6 +147,9 @@ static iString *serializePrefs_App_(const iApp *d) { | |||
146 | if (isVisible_Widget(constAs_Widget(sidebar))) { | 147 | if (isVisible_Widget(constAs_Widget(sidebar))) { |
147 | appendCStr_String(str, "sidebar.toggle\n"); | 148 | appendCStr_String(str, "sidebar.toggle\n"); |
148 | } | 149 | } |
150 | if (d->forceWrap) { | ||
151 | appendFormat_String(str, "forcewrap.toggle\n"); | ||
152 | } | ||
149 | appendFormat_String(str, "sidebar.mode arg:%d\n", mode_SidebarWidget(sidebar)); | 153 | appendFormat_String(str, "sidebar.mode arg:%d\n", mode_SidebarWidget(sidebar)); |
150 | appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(d->window)); | 154 | appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(d->window)); |
151 | appendFormat_String(str, "zoom.set arg:%d\n", d->zoomPercent); | 155 | appendFormat_String(str, "zoom.set arg:%d\n", d->zoomPercent); |
@@ -281,6 +285,7 @@ static void init_App_(iApp *d, int argc, char **argv) { | |||
281 | d->retainWindowSize = iTrue; | 285 | d->retainWindowSize = iTrue; |
282 | d->pendingRefresh = iFalse; | 286 | d->pendingRefresh = iFalse; |
283 | d->zoomPercent = 100; | 287 | d->zoomPercent = 100; |
288 | d->forceWrap = iFalse; | ||
284 | d->certs = new_GmCerts(dataDir_App_); | 289 | d->certs = new_GmCerts(dataDir_App_); |
285 | d->visited = new_Visited(); | 290 | d->visited = new_Visited(); |
286 | d->bookmarks = new_Bookmarks(); | 291 | d->bookmarks = new_Bookmarks(); |
@@ -431,6 +436,10 @@ int zoom_App(void) { | |||
431 | return app_.zoomPercent; | 436 | return app_.zoomPercent; |
432 | } | 437 | } |
433 | 438 | ||
439 | iBool isLineWrapForced_App(void) { | ||
440 | return app_.forceWrap; | ||
441 | } | ||
442 | |||
434 | enum iColorTheme colorTheme_App(void) { | 443 | enum iColorTheme colorTheme_App(void) { |
435 | return app_.theme; | 444 | return app_.theme; |
436 | } | 445 | } |
@@ -793,6 +802,11 @@ iBool handleCommand_App(const char *cmd) { | |||
793 | postCommand_App("window.unfreeze"); | 802 | postCommand_App("window.unfreeze"); |
794 | return iTrue; | 803 | return iTrue; |
795 | } | 804 | } |
805 | else if (equal_Command(cmd, "forcewrap.toggle")) { | ||
806 | d->forceWrap = !d->forceWrap; | ||
807 | updateSize_DocumentWidget(document_App()); | ||
808 | return iTrue; | ||
809 | } | ||
796 | else if (equal_Command(cmd, "bookmark.add")) { | 810 | else if (equal_Command(cmd, "bookmark.add")) { |
797 | iDocumentWidget *doc = document_App(); | 811 | iDocumentWidget *doc = document_App(); |
798 | makeBookmarkCreation_Widget(url_DocumentWidget(doc), | 812 | makeBookmarkCreation_Widget(url_DocumentWidget(doc), |
@@ -56,6 +56,7 @@ iBool isRefreshPending_App (void); | |||
56 | uint32_t elapsedSinceLastTicker_App (void); /* milliseconds */ | 56 | uint32_t elapsedSinceLastTicker_App (void); /* milliseconds */ |
57 | 57 | ||
58 | int zoom_App (void); | 58 | int zoom_App (void); |
59 | iBool isLineWrapForced_App(void); | ||
59 | enum iColorTheme colorTheme_App (void); | 60 | enum iColorTheme colorTheme_App (void); |
60 | const iString * schemeProxy_App (iRangecc scheme); | 61 | const iString * schemeProxy_App (iRangecc scheme); |
61 | 62 | ||
diff --git a/src/gmdocument.c b/src/gmdocument.c index 924eee32..e4ae03a8 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -104,6 +104,7 @@ struct Impl_GmDocument { | |||
104 | iString source; | 104 | iString source; |
105 | iString url; /* for resolving relative links */ | 105 | iString url; /* for resolving relative links */ |
106 | iString localHost; | 106 | iString localHost; |
107 | int forceBreakWidth; /* force breaks on very long preformatted lines */ | ||
107 | iInt2 size; | 108 | iInt2 size; |
108 | iArray layout; /* contents of source, laid out in document space */ | 109 | iArray layout; /* contents of source, laid out in document space */ |
109 | iPtrArray links; | 110 | iPtrArray links; |
@@ -506,12 +507,11 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
506 | } | 507 | } |
507 | run.bounds.pos = addX_I2(pos, indent * gap_Text); | 508 | run.bounds.pos = addX_I2(pos, indent * gap_Text); |
508 | const char *contPos; | 509 | const char *contPos; |
509 | const int avail = d->size.x - run.bounds.pos.x; | 510 | const int avail = (isPreformat ? d->forceBreakWidth : d->size.x) - run.bounds.pos.x; |
510 | const iInt2 dims = | 511 | const iInt2 dims = tryAdvance_Text(run.font, runLine, avail, &contPos); |
511 | tryAdvance_Text(run.font, runLine, isPreformat ? 0 : avail, &contPos); | ||
512 | run.bounds.size.x = iMax(avail, dims.x); /* Extends to the right edge for selection. */ | 512 | run.bounds.size.x = iMax(avail, dims.x); /* Extends to the right edge for selection. */ |
513 | run.bounds.size.y = dims.y; | 513 | run.bounds.size.y = dims.y; |
514 | run.visBounds = run.bounds; | 514 | run.visBounds = run.bounds; |
515 | run.visBounds.size.x = dims.x; | 515 | run.visBounds.size.x = dims.x; |
516 | if (contPos > runLine.start) { | 516 | if (contPos > runLine.start) { |
517 | run.text = (iRangecc){ runLine.start, contPos }; | 517 | run.text = (iRangecc){ runLine.start, contPos }; |
@@ -866,7 +866,8 @@ void setFormat_GmDocument(iGmDocument *d, enum iGmDocumentFormat format) { | |||
866 | d->format = format; | 866 | d->format = format; |
867 | } | 867 | } |
868 | 868 | ||
869 | void setWidth_GmDocument(iGmDocument *d, int width) { | 869 | void setWidth_GmDocument(iGmDocument *d, int width, int forceBreakWidth) { |
870 | d->forceBreakWidth = forceBreakWidth; | ||
870 | d->size.x = width; | 871 | d->size.x = width; |
871 | doLayout_GmDocument_(d); /* TODO: just flag need-layout and do it later */ | 872 | doLayout_GmDocument_(d); /* TODO: just flag need-layout and do it later */ |
872 | } | 873 | } |
@@ -939,11 +940,10 @@ void setUrl_GmDocument(iGmDocument *d, const iString *url) { | |||
939 | setRange_String(&d->localHost, parts.host); | 940 | setRange_String(&d->localHost, parts.host); |
940 | } | 941 | } |
941 | 942 | ||
942 | void setSource_GmDocument(iGmDocument *d, const iString *source, int width) { | 943 | void setSource_GmDocument(iGmDocument *d, const iString *source, int width, int forceBreakWidth) { |
943 | set_String(&d->source, source); | 944 | set_String(&d->source, source); |
944 | normalize_GmDocument(d); | 945 | normalize_GmDocument(d); |
945 | setWidth_GmDocument(d, width); | 946 | setWidth_GmDocument(d, width, forceBreakWidth); /* re-do layout */ |
946 | /* TODO: just flag need-layout and do it later */ | ||
947 | } | 947 | } |
948 | 948 | ||
949 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data) { | 949 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data) { |
diff --git a/src/gmdocument.h b/src/gmdocument.h index b6c1c6ab..e3c21097 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -94,9 +94,9 @@ enum iGmDocumentFormat { | |||
94 | 94 | ||
95 | void setThemeSeed_GmDocument (iGmDocument *, const iBlock *seed); | 95 | void setThemeSeed_GmDocument (iGmDocument *, const iBlock *seed); |
96 | void setFormat_GmDocument (iGmDocument *, enum iGmDocumentFormat format); | 96 | void setFormat_GmDocument (iGmDocument *, enum iGmDocumentFormat format); |
97 | void setWidth_GmDocument (iGmDocument *, int width); | 97 | void setWidth_GmDocument (iGmDocument *, int width, int forceBreakWidth); |
98 | void setUrl_GmDocument (iGmDocument *, const iString *url); | 98 | void setUrl_GmDocument (iGmDocument *, const iString *url); |
99 | void setSource_GmDocument (iGmDocument *, const iString *source, int width); | 99 | void setSource_GmDocument (iGmDocument *, const iString *source, int width, int forceBreakWidth); |
100 | void setImage_GmDocument (iGmDocument *, iGmLinkId linkId, const iString *mime, const iBlock *data); | 100 | void setImage_GmDocument (iGmDocument *, iGmLinkId linkId, const iString *mime, const iBlock *data); |
101 | 101 | ||
102 | void reset_GmDocument (iGmDocument *); /* free images */ | 102 | void reset_GmDocument (iGmDocument *); /* free images */ |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 437e9468..2ccdc416 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -296,6 +296,15 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { | |||
296 | return rect; | 296 | return rect; |
297 | } | 297 | } |
298 | 298 | ||
299 | static int forceBreakWidth_DocumentWidget_(const iDocumentWidget *d) { | ||
300 | if (isLineWrapForced_App()) { | ||
301 | const iRect bounds = bounds_Widget(constAs_Widget(d)); | ||
302 | const iRect docBounds = documentBounds_DocumentWidget_(d); | ||
303 | return right_Rect(bounds) - left_Rect(docBounds) - gap_UI * d->pageMargin; | ||
304 | } | ||
305 | return 0; | ||
306 | } | ||
307 | |||
299 | iLocalDef int documentToWindowY_DocumentWidget_(const iDocumentWidget *d, int docY) { | 308 | iLocalDef int documentToWindowY_DocumentWidget_(const iDocumentWidget *d, int docY) { |
300 | return docY - d->scrollY + documentBounds_DocumentWidget_(d).pos.y; | 309 | return docY - d->scrollY + documentBounds_DocumentWidget_(d).pos.y; |
301 | } | 310 | } |
@@ -488,7 +497,8 @@ static void invalidate_DocumentWidget_(iDocumentWidget *d) { | |||
488 | 497 | ||
489 | static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { | 498 | static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { |
490 | setUrl_GmDocument(d->doc, d->mod.url); | 499 | setUrl_GmDocument(d->doc, d->mod.url); |
491 | setSource_GmDocument(d->doc, source, documentWidth_DocumentWidget_(d)); | 500 | setSource_GmDocument( |
501 | d->doc, source, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); | ||
492 | d->foundMark = iNullRange; | 502 | d->foundMark = iNullRange; |
493 | d->selectMark = iNullRange; | 503 | d->selectMark = iNullRange; |
494 | d->hoverLink = NULL; | 504 | d->hoverLink = NULL; |
@@ -1021,8 +1031,10 @@ static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) { | |||
1021 | } | 1031 | } |
1022 | 1032 | ||
1023 | void updateSize_DocumentWidget(iDocumentWidget *d) { | 1033 | void updateSize_DocumentWidget(iDocumentWidget *d) { |
1024 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); | 1034 | setWidth_GmDocument( |
1035 | d->doc, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); | ||
1025 | updateVisible_DocumentWidget_(d); | 1036 | updateVisible_DocumentWidget_(d); |
1037 | invalidate_DocumentWidget_(d); | ||
1026 | } | 1038 | } |
1027 | 1039 | ||
1028 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 1040 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
@@ -1030,9 +1042,9 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1030 | if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) { | 1042 | if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) { |
1031 | const iGmRun *mid = middleRun_DocumentWidget_(d); | 1043 | const iGmRun *mid = middleRun_DocumentWidget_(d); |
1032 | const char *midLoc = (mid ? mid->text.start : NULL); | 1044 | const char *midLoc = (mid ? mid->text.start : NULL); |
1033 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); | 1045 | setWidth_GmDocument( |
1046 | d->doc, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); | ||
1034 | scroll_DocumentWidget_(d, 0); | 1047 | scroll_DocumentWidget_(d, 0); |
1035 | updateVisible_DocumentWidget_(d); | ||
1036 | if (midLoc) { | 1048 | if (midLoc) { |
1037 | mid = findRunAtLoc_GmDocument(d->doc, midLoc); | 1049 | mid = findRunAtLoc_GmDocument(d->doc, midLoc); |
1038 | if (mid) { | 1050 | if (mid) { |
@@ -1055,8 +1067,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1055 | /* Set palette for our document. */ | 1067 | /* Set palette for our document. */ |
1056 | updateTheme_DocumentWidget_(d); | 1068 | updateTheme_DocumentWidget_(d); |
1057 | updateTrust_DocumentWidget_(d, NULL); | 1069 | updateTrust_DocumentWidget_(d, NULL); |
1058 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); | 1070 | updateSize_DocumentWidget(d); |
1059 | updateVisible_DocumentWidget_(d); | ||
1060 | } | 1071 | } |
1061 | updateWindowTitle_DocumentWidget_(d); | 1072 | updateWindowTitle_DocumentWidget_(d); |
1062 | allocVisBuffer_DocumentWidget_(d); | 1073 | allocVisBuffer_DocumentWidget_(d); |
diff --git a/src/ui/window.c b/src/ui/window.c index b7b4a8fd..66f1c513 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -141,6 +141,8 @@ static const iMenuItem viewMenuItems[] = { | |||
141 | { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, | 141 | { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, |
142 | { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, | 142 | { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, |
143 | { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, | 143 | { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, |
144 | { "---", 0, 0, NULL }, | ||
145 | { "Wrap Preformatted", 0, 0, "forcewrap.toggle" } | ||
144 | }; | 146 | }; |
145 | 147 | ||
146 | static const iMenuItem helpMenuItems[] = { | 148 | static const iMenuItem helpMenuItems[] = { |