summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app.c14
-rw-r--r--src/gmdocument.c17
-rw-r--r--src/prefs.c1
-rw-r--r--src/prefs.h1
-rw-r--r--src/ui/documentwidget.c11
-rw-r--r--src/ui/util.c1
6 files changed, 31 insertions, 14 deletions
diff --git a/src/app.c b/src/app.c
index 2de4c370..1f7abbc4 100644
--- a/src/app.c
+++ b/src/app.c
@@ -215,6 +215,7 @@ static iString *serializePrefs_App_(const iApp *d) {
215 appendFormat_String(str, "memorysize.set arg:%d\n", d->prefs.maxMemorySize); 215 appendFormat_String(str, "memorysize.set arg:%d\n", d->prefs.maxMemorySize);
216 appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); 216 appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs);
217 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); 217 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth);
218 appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing);
218 /* TODO: Set up an array of booleans in Prefs and do these in a loop. */ 219 /* TODO: Set up an array of booleans in Prefs and do these in a loop. */
219 appendFormat_String(str, "prefs.animate.changed arg:%d\n", d->prefs.uiAnimations); 220 appendFormat_String(str, "prefs.animate.changed arg:%d\n", d->prefs.uiAnimations);
220 appendFormat_String(str, "prefs.mono.gemini.changed arg:%d\n", d->prefs.monospaceGemini); 221 appendFormat_String(str, "prefs.mono.gemini.changed arg:%d\n", d->prefs.monospaceGemini);
@@ -1707,6 +1708,12 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1707 updateFontButton_(findChild_Widget(d, "prefs.headingfont"), arg_Command(cmd)); 1708 updateFontButton_(findChild_Widget(d, "prefs.headingfont"), arg_Command(cmd));
1708 return iFalse; 1709 return iFalse;
1709 } 1710 }
1711 else if (startsWith_CStr(cmd, "input.ended id:prefs.linespacing")) {
1712 /* Apply line spacing changes immediately. */
1713 const iInputWidget *lineSpacing = findWidget_App("prefs.linespacing");
1714 postCommandf_App("linespacing.set arg:%f", toFloat_String(text_InputWidget(lineSpacing)));
1715 return iTrue;
1716 }
1710 else if (equal_Command(cmd, "prefs.ostheme.changed")) { 1717 else if (equal_Command(cmd, "prefs.ostheme.changed")) {
1711 postCommandf_App("ostheme arg:%d", arg_Command(cmd)); 1718 postCommandf_App("ostheme arg:%d", arg_Command(cmd));
1712 } 1719 }
@@ -2118,6 +2125,11 @@ iBool handleCommand_App(const char *cmd) {
2118 postCommand_App("document.layout.changed"); 2125 postCommand_App("document.layout.changed");
2119 return iTrue; 2126 return iTrue;
2120 } 2127 }
2128 else if (equal_Command(cmd, "linespacing.set")) {
2129 d->prefs.lineSpacing = iMax(0.5f, argf_Command(cmd));
2130 postCommand_App("document.layout.changed redo:1");
2131 return iTrue;
2132 }
2121 else if (equal_Command(cmd, "quoteicon.set")) { 2133 else if (equal_Command(cmd, "quoteicon.set")) {
2122 d->prefs.quoteIcon = arg_Command(cmd) != 0; 2134 d->prefs.quoteIcon = arg_Command(cmd) != 0;
2123 postCommand_App("document.layout.changed"); 2135 postCommand_App("document.layout.changed");
@@ -2516,6 +2528,8 @@ iBool handleCommand_App(const char *cmd) {
2516 findChild_Widget(dlg, format_CStr("prefs.linewidth.%d", d->prefs.lineWidth)), 2528 findChild_Widget(dlg, format_CStr("prefs.linewidth.%d", d->prefs.lineWidth)),
2517 selected_WidgetFlag, 2529 selected_WidgetFlag,
2518 iTrue); 2530 iTrue);
2531 setText_InputWidget(findChild_Widget(dlg, "prefs.linespacing"),
2532 collectNewFormat_String("%.2f", d->prefs.lineSpacing));
2519 setFlags_Widget( 2533 setFlags_Widget(
2520 findChild_Widget(dlg, format_CStr("prefs.quoteicon.%d", d->prefs.quoteIcon)), 2534 findChild_Widget(dlg, format_CStr("prefs.quoteicon.%d", d->prefs.quoteIcon)),
2521 selected_WidgetFlag, 2535 selected_WidgetFlag,
diff --git a/src/gmdocument.c b/src/gmdocument.c
index a46e71cf..3d91fb34 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -147,7 +147,7 @@ static int lastVisibleRunBottom_GmDocument_(const iGmDocument *d) {
147 if (isEmpty_Range(&run->text)) { 147 if (isEmpty_Range(&run->text)) {
148 continue; 148 continue;
149 } 149 }
150 return bottom_Rect(run->bounds); 150 return top_Rect(run->bounds) + height_Rect(run->bounds) * prefs_App()->lineSpacing;
151 } 151 }
152 return 0; 152 return 0;
153} 153}
@@ -546,7 +546,8 @@ static void doLayout_GmDocument_(iGmDocument *d) {
546 banner.text = bannerText; 546 banner.text = bannerText;
547 banner.color = tmBannerTitle_ColorId; 547 banner.color = tmBannerTitle_ColorId;
548 pushBack_Array(&d->layout, &banner); 548 pushBack_Array(&d->layout, &banner);
549 pos.y += height_Rect(banner.visBounds) + lineHeight_Text(paragraph_FontId); 549 pos.y += height_Rect(banner.visBounds) +
550 lineHeight_Text(paragraph_FontId) * prefs->lineSpacing;
550 } 551 }
551 } 552 }
552 /* Empty lines don't produce text runs. */ 553 /* Empty lines don't produce text runs. */
@@ -560,7 +561,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
560 run.text = iNullRange; 561 run.text = iNullRange;
561 pushBack_Array(&d->layout, &run); 562 pushBack_Array(&d->layout, &run);
562 } 563 }
563 pos.y += lineHeight_Text(run.font); 564 pos.y += lineHeight_Text(run.font) * prefs->lineSpacing;
564 prevType = type; 565 prevType = type;
565 if (type != quote_GmLineType) { 566 if (type != quote_GmLineType) {
566 addQuoteIcon = prefs->quoteIcon; 567 addQuoteIcon = prefs->quoteIcon;
@@ -586,11 +587,6 @@ static void doLayout_GmDocument_(iGmDocument *d) {
586 if (type == link_GmLineType && prevNonBlankType == link_GmLineType && followsBlank) { 587 if (type == link_GmLineType && prevNonBlankType == link_GmLineType && followsBlank) {
587 required = 1.25f * lineHeight_Text(paragraph_FontId); 588 required = 1.25f * lineHeight_Text(paragraph_FontId);
588 } 589 }
589 else if (type == link_GmLineType && prevType == link_GmLineType) {
590 /* Balance space between the link icons and the labels, both vertically
591 between icons and between the icon and the label. */
592 //required *= 0.75f;
593 }
594 if (type == quote_GmLineType && prevType == quote_GmLineType) { 590 if (type == quote_GmLineType && prevType == quote_GmLineType) {
595 /* No margin between consecutive quote lines. */ 591 /* No margin between consecutive quote lines. */
596 required = 0; 592 required = 0;
@@ -598,9 +594,10 @@ static void doLayout_GmDocument_(iGmDocument *d) {
598 if (isEmpty_Array(&d->layout)) { 594 if (isEmpty_Array(&d->layout)) {
599 required = 0; /* top of document */ 595 required = 0; /* top of document */
600 } 596 }
597 required *= prefs->lineSpacing;
601 int delta = pos.y - lastVisibleRunBottom_GmDocument_(d); 598 int delta = pos.y - lastVisibleRunBottom_GmDocument_(d);
602 if (delta < required) { 599 if (delta < required) {
603 pos.y += required - delta; 600 pos.y += (required - delta);
604 } 601 }
605 } 602 }
606 /* Folded blocks are represented by a single run with the alt text. */ 603 /* Folded blocks are represented by a single run with the alt text. */
@@ -778,7 +775,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
778 run.flags &= ~startOfLine_GmRunFlag; 775 run.flags &= ~startOfLine_GmRunFlag;
779 runLine.start = contPos; 776 runLine.start = contPos;
780 trimStart_Rangecc(&runLine); 777 trimStart_Rangecc(&runLine);
781 pos.y += lineHeight_Text(run.font); 778 pos.y += lineHeight_Text(run.font) * prefs->lineSpacing;
782 if (--bigCount == 0) { 779 if (--bigCount == 0) {
783 run.font = fonts[text_GmLineType]; 780 run.font = fonts[text_GmLineType];
784 run.color = colors[text_GmLineType]; 781 run.color = colors[text_GmLineType];
diff --git a/src/prefs.c b/src/prefs.c
index f1842e9a..557c6887 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -54,6 +54,7 @@ void init_Prefs(iPrefs *d) {
54 d->boldLinkDark = iTrue; 54 d->boldLinkDark = iTrue;
55 d->boldLinkLight = iTrue; 55 d->boldLinkLight = iTrue;
56 d->lineWidth = 38; 56 d->lineWidth = 38;
57 d->lineSpacing = 1.0f;
57 d->bigFirstParagraph = iTrue; 58 d->bigFirstParagraph = iTrue;
58 d->quoteIcon = iTrue; 59 d->quoteIcon = iTrue;
59 d->centerShortDocs = iTrue; 60 d->centerShortDocs = iTrue;
diff --git a/src/prefs.h b/src/prefs.h
index 655ec949..c1519459 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -79,6 +79,7 @@ struct Impl_Prefs {
79 iBool boldLinkDark; 79 iBool boldLinkDark;
80 iBool boldLinkLight; 80 iBool boldLinkLight;
81 int lineWidth; 81 int lineWidth;
82 float lineSpacing;
82 iBool bigFirstParagraph; 83 iBool bigFirstParagraph;
83 iBool quoteIcon; 84 iBool quoteIcon;
84 iBool centerShortDocs; 85 iBool centerShortDocs;
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 5bded6c6..38f34c77 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -1298,9 +1298,9 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool
1298 2); 1298 2);
1299 } 1299 }
1300 if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { 1300 if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) {
1301 redoLayout_GmDocument(d->doc); 1301 redoLayout_GmDocument(d->doc);
1302 updateVisible_DocumentWidget_(d); 1302 updateVisible_DocumentWidget_(d);
1303 invalidate_DocumentWidget_(d); 1303 invalidate_DocumentWidget_(d);
1304 } 1304 }
1305 } 1305 }
1306 else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { 1306 else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) {
@@ -2461,7 +2461,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2461 invalidate_DocumentWidget_(d); 2461 invalidate_DocumentWidget_(d);
2462 refresh_Widget(w); 2462 refresh_Widget(w);
2463 } 2463 }
2464 else if (equal_Command(cmd, "document.layout.changed") && document_App() == d) { 2464 else if (equal_Command(cmd, "document.layout.changed") && document_Root(get_Root()) == d) {
2465 if (argLabel_Command(cmd, "redo")) {
2466 redoLayout_GmDocument(d->doc);
2467 }
2465 updateSize_DocumentWidget(d); 2468 updateSize_DocumentWidget(d);
2466 } 2469 }
2467 else if (equal_Command(cmd, "pinsplit.set")) { 2470 else if (equal_Command(cmd, "pinsplit.set")) {
diff --git a/src/ui/util.c b/src/ui/util.c
index 5aea4f11..d68274ad 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1809,6 +1809,7 @@ iWidget *makePreferences_Widget(void) {
1809 addRadioButton_(widths, "prefs.linewidth.1000", "${prefs.linewidth.fill}", "linewidth.set arg:1000"); 1809 addRadioButton_(widths, "prefs.linewidth.1000", "${prefs.linewidth.fill}", "linewidth.set arg:1000");
1810 } 1810 }
1811 addChildFlags_Widget(values, iClob(widths), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); 1811 addChildFlags_Widget(values, iClob(widths), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
1812 addPrefsInputWithHeading_(headings, values, "prefs.linespacing", iClob(new_InputWidget(5)));
1812 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.quoteicon}"))); 1813 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.quoteicon}")));
1813 iWidget *quote = new_Widget(); { 1814 iWidget *quote = new_Widget(); {
1814 addRadioButton_(quote, "prefs.quoteicon.1", "${prefs.quoteicon.icon}", "quoteicon.set arg:1"); 1815 addRadioButton_(quote, "prefs.quoteicon.1", "${prefs.quoteicon.icon}", "quoteicon.set arg:1");