diff options
-rw-r--r-- | src/ui/documentwidget.c | 55 |
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 | ||
46 | iDefineObjectConstruction(DocumentWidget) | 50 | iDefineObjectConstruction(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 | ||
81 | static int documentWidth_DocumentWidget_(const iDocumentWidget *d) { | 92 | static 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 | ||
164 | static 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 | |||
153 | static void updateSource_DocumentWidget_(iDocumentWidget *d) { | 174 | static 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 | ||
277 | static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code) { | 294 | static 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 | ||
305 | static void checkResponseCode_DocumentWidget_(iDocumentWidget *d) { | 317 | static 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: |