summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 091673b8..9c6fe718 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 iBool selecting;
35 iRangecc selectMark; 36 iRangecc selectMark;
36 iRangecc foundMark; 37 iRangecc foundMark;
37 int pageMargin; 38 int pageMargin;
@@ -41,6 +42,9 @@ struct Impl_DocumentWidget {
41 iClick click; 42 iClick click;
42 iScrollWidget *scroll; 43 iScrollWidget *scroll;
43 iWidget *menu; 44 iWidget *menu;
45 SDL_Cursor *arrowCursor;
46 SDL_Cursor *beamCursor;
47 SDL_Cursor *handCursor;
44}; 48};
45 49
46iDefineObjectConstruction(DocumentWidget) 50iDefineObjectConstruction(DocumentWidget)
@@ -54,11 +58,15 @@ void init_DocumentWidget(iDocumentWidget *d) {
54 d->request = NULL; 58 d->request = NULL;
55 d->isSourcePending = iFalse; 59 d->isSourcePending = iFalse;
56 d->doc = new_GmDocument(); 60 d->doc = new_GmDocument();
61 d->selecting = iFalse;
57 d->selectMark = iNullRange; 62 d->selectMark = iNullRange;
58 d->foundMark = iNullRange; 63 d->foundMark = iNullRange;
59 d->pageMargin = 5; 64 d->pageMargin = 5;
60 d->scrollY = 0; 65 d->scrollY = 0;
61 d->hoverLink = NULL; 66 d->hoverLink = NULL;
67 d->arrowCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
68 d->beamCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
69 d->handCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
62 init_PtrArray(&d->visibleLinks); 70 init_PtrArray(&d->visibleLinks);
63 init_Click(&d->click, d, SDL_BUTTON_LEFT); 71 init_Click(&d->click, d, SDL_BUTTON_LEFT);
64 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 72 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
@@ -76,6 +84,9 @@ void deinit_DocumentWidget(iDocumentWidget *d) {
76 delete_String(d->url); 84 delete_String(d->url);
77 iRelease(d->request); 85 iRelease(d->request);
78 iRelease(d->doc); 86 iRelease(d->doc);
87 SDL_FreeCursor(d->arrowCursor);
88 SDL_FreeCursor(d->beamCursor);
89 SDL_FreeCursor(d->handCursor);
79} 90}
80 91
81static int documentWidth_DocumentWidget_(const iDocumentWidget *d) { 92static int documentWidth_DocumentWidget_(const iDocumentWidget *d) {
@@ -150,6 +161,16 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
150 : collectNewCStr_String("Lagrange")); 161 : collectNewCStr_String("Lagrange"));
151} 162}
152 163
164static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) {
165 setSource_GmDocument(d->doc, source, documentWidth_DocumentWidget_(d));
166 d->foundMark = iNullRange;
167 d->selectMark = iNullRange;
168 d->hoverLink = NULL;
169 updateWindowTitle_DocumentWidget_(d);
170 updateVisible_DocumentWidget_(d);
171 refresh_Widget(as_Widget(d));
172}
173
153static void updateSource_DocumentWidget_(iDocumentWidget *d) { 174static void updateSource_DocumentWidget_(iDocumentWidget *d) {
154 /* TODO: Do this in the background. However, that requires a text metrics calculator 175 /* TODO: Do this in the background. However, that requires a text metrics calculator
155 that does not try to cache the glyph bitmaps. */ 176 that does not try to cache the glyph bitmaps. */
@@ -157,11 +178,7 @@ static void updateSource_DocumentWidget_(iDocumentWidget *d) {
157 status_GmRequest(d->request) != sensitiveInput_GmStatusCode) { 178 status_GmRequest(d->request) != sensitiveInput_GmStatusCode) {
158 iString str; 179 iString str;
159 initBlock_String(&str, body_GmRequest(d->request)); 180 initBlock_String(&str, body_GmRequest(d->request));
160 setSource_GmDocument(d->doc, &str, documentWidth_DocumentWidget_(d)); 181 setSource_DocumentWidget_(d, &str);
161 d->foundMark = iNullRange;
162 updateWindowTitle_DocumentWidget_(d);
163 updateVisible_DocumentWidget_(d);
164 refresh_Widget(as_Widget(d));
165 deinit_String(&str); 182 deinit_String(&str);
166 } 183 }
167} 184}
@@ -275,7 +292,6 @@ static const iString *absoluteUrl_DocumentWidget_(const iDocumentWidget *d, cons
275} 292}
276 293
277static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code) { 294static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code) {
278 iWidget *w = as_Widget(d);
279 iString *src = collectNew_String(); 295 iString *src = collectNew_String();
280 const iGmError *msg = get_GmError(code); 296 const iGmError *msg = get_GmError(code);
281 format_String(src, 297 format_String(src,
@@ -295,11 +311,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
295 default: 311 default:
296 break; 312 break;
297 } 313 }
298 d->foundMark = iNullRange; 314 setSource_DocumentWidget_(d, src);
299 setSource_GmDocument(d->doc, src, documentWidth_DocumentWidget_(d));
300 updateWindowTitle_DocumentWidget_(d);
301 updateVisible_DocumentWidget_(d);
302 refresh_Widget(w);
303} 315}
304 316
305static void checkResponseCode_DocumentWidget_(iDocumentWidget *d) { 317static void checkResponseCode_DocumentWidget_(iDocumentWidget *d) {
@@ -494,11 +506,11 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
494 return iTrue; 506 return iTrue;
495 } 507 }
496 else if (ev->type == SDL_MOUSEMOTION) { 508 else if (ev->type == SDL_MOUSEMOTION) {
509 const iRect docBounds = documentBounds_DocumentWidget_(d);
510 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y);
497 const iGmRun *oldHoverLink = d->hoverLink; 511 const iGmRun *oldHoverLink = d->hoverLink;
498 d->hoverLink = NULL; 512 d->hoverLink = NULL;
499 const iRect docBounds = documentBounds_DocumentWidget_(d); 513 const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), d->scrollY);
500 const iInt2 hoverPos = addY_I2(
501 sub_I2(init_I2(ev->motion.x, ev->motion.y), topLeft_Rect(docBounds)), d->scrollY);
502 iConstForEach(PtrArray, i, &d->visibleLinks) { 514 iConstForEach(PtrArray, i, &d->visibleLinks) {
503 const iGmRun *run = i.ptr; 515 const iGmRun *run = i.ptr;
504 if (contains_Rect(run->bounds, hoverPos)) { 516 if (contains_Rect(run->bounds, hoverPos)) {
@@ -509,6 +521,12 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
509 if (d->hoverLink != oldHoverLink) { 521 if (d->hoverLink != oldHoverLink) {
510 refresh_Widget(w); 522 refresh_Widget(w);
511 } 523 }
524 if (!contains_Widget(w, mouse) || contains_Widget(constAs_Widget(d->scroll), mouse)) {
525 SDL_SetCursor(d->arrowCursor);
526 }
527 else {
528 SDL_SetCursor(d->hoverLink ? d->handCursor : d->beamCursor);
529 }
512 } 530 }
513 processContextMenuEvent_Widget(d->menu, ev); 531 processContextMenuEvent_Widget(d->menu, ev);
514 switch (processEvent_Click(&d->click, ev)) { 532 switch (processEvent_Click(&d->click, ev)) {
@@ -521,8 +539,15 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
521 } 539 }
522 return iTrue; 540 return iTrue;
523 case started_ClickResult: 541 case started_ClickResult:
542 d->selecting = iFalse;
543 return iTrue;
524 case double_ClickResult: 544 case double_ClickResult:
525 case drag_ClickResult: 545 case drag_ClickResult:
546 /* Begin selecting a range of text. */
547 d->selectMark = iNullRange;
548 d->selecting = iTrue;
549 refresh_Widget(w);
550 return iTrue;
526 case aborted_ClickResult: 551 case aborted_ClickResult:
527 return iTrue; 552 return iTrue;
528 default: 553 default: