summaryrefslogtreecommitdiff
path: root/src/gmdocument.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-11-28 14:23:18 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-11-28 14:23:18 +0200
commitedf1c0bb8b112879433f2e31fd9750c30e2d5144 (patch)
tree9e7e3207e8e926ae1dfe47992e9055ba21fb16ed /src/gmdocument.c
parent0ccabb2c8e0e894be520c621bca8023a6d5de2e2 (diff)
Scrolling wide preformatted blocks horizontally
Not entirely glitch-free but should be good enough for now. IssueID #44
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r--src/gmdocument.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 2f3a006f..1ff085c7 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -304,6 +304,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
304 iBool isPreformat = iFalse; 304 iBool isPreformat = iFalse;
305 iRangecc preAltText = iNullRange; 305 iRangecc preAltText = iNullRange;
306 int preFont = preformatted_FontId; 306 int preFont = preformatted_FontId;
307 uint16_t preId = 0;
307 iBool enableIndents = iFalse; 308 iBool enableIndents = iFalse;
308 iBool addSiteBanner = d->siteBannerEnabled; 309 iBool addSiteBanner = d->siteBannerEnabled;
309 enum iGmLineType prevType = text_GmLineType; 310 enum iGmLineType prevType = text_GmLineType;
@@ -313,12 +314,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
313 } 314 }
314 while (nextSplit_Rangecc(content, "\n", &contentLine)) { 315 while (nextSplit_Rangecc(content, "\n", &contentLine)) {
315 iRangecc line = contentLine; /* `line` will be trimmed later; would confuse nextSplit */ 316 iRangecc line = contentLine; /* `line` will be trimmed later; would confuse nextSplit */
316 iGmRun run; 317 iGmRun run = { .color = white_ColorId };
317 run.flags = 0;
318 run.color = white_ColorId;
319 run.linkId = 0;
320 run.imageId = 0;
321 run.audioId = 0;
322 enum iGmLineType type; 318 enum iGmLineType type;
323 int indent = 0; 319 int indent = 0;
324 /* Detect the type of the line. */ 320 /* Detect the type of the line. */
@@ -330,6 +326,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
330 indent = indents[type]; 326 indent = indents[type];
331 if (type == preformatted_GmLineType) { 327 if (type == preformatted_GmLineType) {
332 isPreformat = iTrue; 328 isPreformat = iTrue;
329 preId++;
333 preFont = preformatted_FontId; 330 preFont = preformatted_FontId;
334 /* Use a smaller font if the block contents are wide. */ 331 /* Use a smaller font if the block contents are wide. */
335 if (measurePreformattedBlock_GmDocument_(d, line.start, preFont).x > 332 if (measurePreformattedBlock_GmDocument_(d, line.start, preFont).x >
@@ -370,6 +367,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
370 addSiteBanner = iFalse; /* overrides the banner */ 367 addSiteBanner = iFalse; /* overrides the banner */
371 continue; 368 continue;
372 } 369 }
370 run.preId = preId;
373 run.font = (d->format == plainText_GmDocumentFormat ? regularMonospace_FontId : preFont); 371 run.font = (d->format == plainText_GmDocumentFormat ? regularMonospace_FontId : preFont);
374 indent = indents[type]; 372 indent = indents[type];
375 } 373 }
@@ -509,8 +507,9 @@ static void doLayout_GmDocument_(iGmDocument *d) {
509 } 507 }
510 run.bounds.pos = addX_I2(pos, indent * gap_Text); 508 run.bounds.pos = addX_I2(pos, indent * gap_Text);
511 const char *contPos; 509 const char *contPos;
512 const int avail = d->size.x - run.bounds.pos.x; 510 const int avail = isPreformat ? 0 : (d->size.x - run.bounds.pos.x);
513 const iInt2 dims = tryAdvance_Text(run.font, runLine, avail, &contPos); 511 const iInt2 dims = tryAdvance_Text(run.font, runLine, avail, &contPos);
512 iChangeFlags(run.flags, wide_GmRunFlag, (isPreformat && dims.x > d->size.x));
514 run.bounds.size.x = iMax(avail, dims.x); /* Extends to the right edge for selection. */ 513 run.bounds.size.x = iMax(avail, dims.x); /* Extends to the right edge for selection. */
515 run.bounds.size.y = dims.y; 514 run.bounds.size.y = dims.y;
516 run.visBounds = run.bounds; 515 run.visBounds = run.bounds;
@@ -596,6 +595,19 @@ static void doLayout_GmDocument_(iGmDocument *d) {
596 prevType = type; 595 prevType = type;
597 } 596 }
598 d->size.y = pos.y; 597 d->size.y = pos.y;
598 /* Go over the preformatted blocks and mark them wide if at least one run is wide. */ {
599 iForEach(Array, i, &d->layout) {
600 iGmRun *run = i.value;
601 if (run->preId && run->flags & wide_GmRunFlag) {
602 iGmRunRange block = findPreformattedRange_GmDocument(d, run);
603 for (const iGmRun *j = block.start; j != block.end; j++) {
604 iConstCast(iGmRun *, j)->flags |= wide_GmRunFlag;
605 }
606 /* Skip to the end of the block. */
607 i.pos = block.end - (const iGmRun *) constData_Array(&d->layout) - 1;
608 }
609 }
610 }
599} 611}
600 612
601void init_GmDocument(iGmDocument *d) { 613void init_GmDocument(iGmDocument *d) {
@@ -1237,6 +1249,23 @@ iRangecc findTextBefore_GmDocument(const iGmDocument *d, const iString *text, co
1237 return found; 1249 return found;
1238} 1250}
1239 1251
1252iGmRunRange findPreformattedRange_GmDocument(const iGmDocument *d, const iGmRun *run) {
1253 iAssert(run->preId);
1254 iGmRunRange range = { run, run };
1255 /* Find the beginning. */
1256 while (range.start > (const iGmRun *) constData_Array(&d->layout)) {
1257 const iGmRun *prev = range.start - 1;
1258 if (prev->preId != run->preId) break;
1259 range.start = prev;
1260 }
1261 /* Find the ending. */
1262 while (range.end < (const iGmRun *) constEnd_Array(&d->layout)) {
1263 if (range.end->preId != run->preId) break;
1264 range.end++;
1265 }
1266 return range;
1267}
1268
1240const iGmRun *findRun_GmDocument(const iGmDocument *d, iInt2 pos) { 1269const iGmRun *findRun_GmDocument(const iGmDocument *d, iInt2 pos) {
1241 /* TODO: Perf optimization likely needed; use a block map? */ 1270 /* TODO: Perf optimization likely needed; use a block map? */
1242 const iGmRun *last = NULL; 1271 const iGmRun *last = NULL;