summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-07-26 22:00:14 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-07-26 22:00:14 +0300
commit6d8d188237324fc1379859251ca66f1ba4247589 (patch)
tree1c7f95edf7ad96bf80c4586271ce0e869c989147 /src/ui/documentwidget.c
parentbe6438af11dec5ee10b68fe315b3bc74d2877f8e (diff)
Finding text in the document
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c103
1 files changed, 93 insertions, 10 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 5df2b1b9..f7bfa39f 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -32,6 +32,7 @@ struct Impl_DocumentWidget {
32 iGmRequest *request; 32 iGmRequest *request;
33 iAtomicInt isSourcePending; /* request has new content, need to parse it */ 33 iAtomicInt isSourcePending; /* request has new content, need to parse it */
34 iGmDocument *doc; 34 iGmDocument *doc;
35 iRangecc foundMark;
35 int pageMargin; 36 int pageMargin;
36 int scrollY; 37 int scrollY;
37 iPtrArray visibleLinks; 38 iPtrArray visibleLinks;
@@ -47,14 +48,15 @@ void init_DocumentWidget(iDocumentWidget *d) {
47 iWidget *w = as_Widget(d); 48 iWidget *w = as_Widget(d);
48 init_Widget(w); 49 init_Widget(w);
49 setId_Widget(w, "document"); 50 setId_Widget(w, "document");
50 d->state = blank_DocumentState; 51 d->state = blank_DocumentState;
51 d->url = new_String(); 52 d->url = new_String();
52 d->request = NULL; 53 d->request = NULL;
53 d->isSourcePending = iFalse; 54 d->isSourcePending = iFalse;
54 d->doc = new_GmDocument(); 55 d->doc = new_GmDocument();
55 d->pageMargin = 5; 56 d->foundMark = iNullRange;
56 d->scrollY = 0; 57 d->pageMargin = 5;
57 d->hoverLink = NULL; 58 d->scrollY = 0;
59 d->hoverLink = NULL;
58 init_PtrArray(&d->visibleLinks); 60 init_PtrArray(&d->visibleLinks);
59 init_Click(&d->click, d, SDL_BUTTON_LEFT); 61 init_Click(&d->click, d, SDL_BUTTON_LEFT);
60 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 62 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
@@ -150,10 +152,11 @@ static void updateSource_DocumentWidget_(iDocumentWidget *d) {
150 /* TODO: Do this in the background. However, that requires a text metrics calculator 152 /* TODO: Do this in the background. However, that requires a text metrics calculator
151 that does not try to cache the glyph bitmaps. */ 153 that does not try to cache the glyph bitmaps. */
152 if (status_GmRequest(d->request) != input_GmStatusCode && 154 if (status_GmRequest(d->request) != input_GmStatusCode &&
153 status_GmRequest(d->request) != sensitiveInput_GmStatusCode) { 155 status_GmRequest(d->request) != sensitiveInput_GmStatusCode) {
154 iString str; 156 iString str;
155 initBlock_String(&str, body_GmRequest(d->request)); 157 initBlock_String(&str, body_GmRequest(d->request));
156 setSource_GmDocument(d->doc, &str, documentWidth_DocumentWidget_(d)); 158 setSource_GmDocument(d->doc, &str, documentWidth_DocumentWidget_(d));
159 d->foundMark = iNullRange;
157 updateWindowTitle_DocumentWidget_(d); 160 updateWindowTitle_DocumentWidget_(d);
158 updateVisible_DocumentWidget_(d); 161 updateVisible_DocumentWidget_(d);
159 refresh_Widget(as_Widget(d)); 162 refresh_Widget(as_Widget(d));
@@ -211,6 +214,11 @@ static void scroll_DocumentWidget_(iDocumentWidget *d, int offset) {
211 refresh_Widget(as_Widget(d)); 214 refresh_Widget(as_Widget(d));
212} 215}
213 216
217static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY) {
218 d->scrollY = documentY - documentBounds_DocumentWidget_(d).size.y / 2;
219 scroll_DocumentWidget_(d, 0); /* clamp it */
220}
221
214static iRangecc dirPath_(iRangecc path) { 222static iRangecc dirPath_(iRangecc path) {
215 const size_t pos = lastIndexOfCStr_Rangecc(&path, "/"); 223 const size_t pos = lastIndexOfCStr_Rangecc(&path, "/");
216 if (pos == iInvalidPos) return path; 224 if (pos == iInvalidPos) return path;
@@ -285,6 +293,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
285 default: 293 default:
286 break; 294 break;
287 } 295 }
296 d->foundMark = iNullRange;
288 setSource_GmDocument(d->doc, src, documentWidth_DocumentWidget_(d)); 297 setSource_GmDocument(d->doc, src, documentWidth_DocumentWidget_(d));
289 updateWindowTitle_DocumentWidget_(d); 298 updateWindowTitle_DocumentWidget_(d);
290 updateVisible_DocumentWidget_(d); 299 updateVisible_DocumentWidget_(d);
@@ -408,6 +417,34 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
408 d, arg_Command(command_UserEvent(ev)) * height_Rect(documentBounds_DocumentWidget_(d))); 417 d, arg_Command(command_UserEvent(ev)) * height_Rect(documentBounds_DocumentWidget_(d)));
409 return iTrue; 418 return iTrue;
410 } 419 }
420 else if (isCommand_UserEvent(ev, "find.next")) {
421 iInputWidget *find = findWidget_App("find.input");
422 if (isEmpty_String(text_InputWidget(find))) {
423 d->foundMark = iNullRange;
424 }
425 else {
426 const iBool wrap = d->foundMark.start != NULL;
427 d->foundMark = findText_GmDocument(d->doc, text_InputWidget(find), d->foundMark.end);
428 if (!d->foundMark.start && wrap) {
429 d->foundMark = findText_GmDocument(d->doc, text_InputWidget(find), 0);
430 }
431 if (d->foundMark.start) {
432 iGmRun *run = findRunCStr_GmDocument(d->doc, d->foundMark.start);
433 if (run) {
434 scrollTo_DocumentWidget_(d, mid_Rect(run->bounds).y);
435 }
436 }
437 }
438 refresh_Widget(w);
439 return iTrue;
440 }
441 else if (isCommand_UserEvent(ev, "find.clearmark")) {
442 if (d->foundMark.start) {
443 d->foundMark = iNullRange;
444 refresh_Widget(w);
445 }
446 return iTrue;
447 }
411 if (ev->type == SDL_KEYDOWN) { 448 if (ev->type == SDL_KEYDOWN) {
412 const int mods = keyMods_Sym(ev->key.keysym.mod); 449 const int mods = keyMods_Sym(ev->key.keysym.mod);
413 const int key = ev->key.keysym.sym; 450 const int key = ev->key.keysym.sym;
@@ -493,6 +530,7 @@ struct Impl_DrawContext {
493 const iDocumentWidget *widget; 530 const iDocumentWidget *widget;
494 iRect bounds; 531 iRect bounds;
495 iPaint paint; 532 iPaint paint;
533 int insideMark;
496}; 534};
497 535
498static void drawRun_DrawContext_(void *context, const iGmRun *run) { 536static void drawRun_DrawContext_(void *context, const iGmRun *run) {
@@ -501,10 +539,55 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
501 /* TODO: making a copy is unnecessary; the text routines should accept Rangecc */ 539 /* TODO: making a copy is unnecessary; the text routines should accept Rangecc */
502 initRange_String(&text, run->text); 540 initRange_String(&text, run->text);
503 iInt2 origin = addY_I2(d->bounds.pos, -d->widget->scrollY); 541 iInt2 origin = addY_I2(d->bounds.pos, -d->widget->scrollY);
504 drawString_Text(run->font, add_I2(run->bounds.pos, origin), run->color, &text);
505 if (run == d->widget->hoverLink) { 542 if (run == d->widget->hoverLink) {
506 drawRect_Paint(&d->paint, moved_Rect(run->bounds, origin), orange_ColorId); 543 const char *desc = "";
544 const iString *url = linkUrl_GmDocument(d->widget->doc, d->widget->hoverLink->linkId);
545 if (indexOfCStr_String(url, "://") == iInvalidPos) {
546 url = d->widget->url;
547 }
548 iUrl parts;
549 init_Url(&parts, url);
550 desc = cstrFormat_String("\u2192 %s", cstr_String(collect_String(newRange_String(parts.protocol))));
551 int descWidth = measure_Text(default_FontId, desc).x + gap_UI;
552 iRect linkRect = expanded_Rect(moved_Rect(run->bounds, origin), init_I2(gap_UI, 0));
553 linkRect.size.x += descWidth;
554 fillRect_Paint(&d->paint,
555 linkRect,
556 teal_ColorId);
557 drawAlign_Text(default_FontId,
558 addX_I2(topRight_Rect(linkRect), -gap_UI),
559 cyan_ColorId,
560 right_Alignment,
561 "%s",
562 desc);
563 }
564 const iInt2 visPos = add_I2(run->bounds.pos, origin);
565 /* Found text marker. */
566 if ((!d->insideMark && contains_Range(&run->text, d->widget->foundMark.start)) ||
567 d->insideMark) {
568 int x = 0;
569 if (!d->insideMark) {
570 x = advanceRange_Text(run->font, (iRangecc){ run->text.start,
571 d->widget->foundMark.start }).x;
572 }
573 int w = width_Rect(run->bounds) - x;
574 if (contains_Range(&run->text, d->widget->foundMark.end) ||
575 run->text.end == d->widget->foundMark.end) {
576 w = advanceRange_Text(run->font,
577 !d->insideMark
578 ? d->widget->foundMark
579 : (iRangecc){ run->text.start, d->widget->foundMark.end })
580 .x;
581 d->insideMark = iFalse;
582 }
583 else {
584 d->insideMark = iTrue; /* at least until the next run */
585 }
586 fillRect_Paint(&d->paint,
587 (iRect){ addX_I2(visPos, x), init_I2(w, height_Rect(run->bounds)) },
588 teal_ColorId);
507 } 589 }
590 drawString_Text(run->font, visPos, run->color, &text);
508 deinit_String(&text); 591 deinit_String(&text);
509} 592}
510 593