summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/app.c2
-rw-r--r--src/ui/documentwidget.c47
-rw-r--r--src/ui/scrollwidget.c79
-rw-r--r--src/ui/scrollwidget.h11
-rw-r--r--src/ui/widget.c6
-rw-r--r--src/ui/widget.h1
7 files changed, 130 insertions, 18 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c9b342d5..280dcdf8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -48,6 +48,8 @@ set (SOURCES
48 src/ui/metrics.h 48 src/ui/metrics.h
49 src/ui/paint.c 49 src/ui/paint.c
50 src/ui/paint.h 50 src/ui/paint.h
51 src/ui/scrollwidget.c
52 src/ui/scrollwidget.h
51 src/ui/text.c 53 src/ui/text.c
52 src/ui/text.h 54 src/ui/text.h
53 src/ui/util.c 55 src/ui/util.c
diff --git a/src/app.c b/src/app.c
index 03917f3e..16354baf 100644
--- a/src/app.c
+++ b/src/app.c
@@ -143,7 +143,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
143 clean_Path(homePath); 143 clean_Path(homePath);
144 append_Path(homePath, &iStringLiteral("home.gmi")); 144 append_Path(homePath, &iStringLiteral("home.gmi"));
145 prependCStr_String(homePath, "file://"); 145 prependCStr_String(homePath, "file://");
146 setUrl_DocumentWidget(findWidget_App("document"), homePath); 146 postCommandf_App("open url:%s", cstr_String(homePath));
147 delete_String(homePath); 147 delete_String(homePath);
148 } 148 }
149} 149}
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index a21d660d..8c707206 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -1,4 +1,5 @@
1#include "documentwidget.h" 1#include "documentwidget.h"
2#include "scrollwidget.h"
2#include "paint.h" 3#include "paint.h"
3#include "util.h" 4#include "util.h"
4#include "app.h" 5#include "app.h"
@@ -33,6 +34,7 @@ struct Impl_DocumentWidget {
33 iPtrArray visibleLinks; 34 iPtrArray visibleLinks;
34 const iGmRun *hoverLink; 35 const iGmRun *hoverLink;
35 iClick click; 36 iClick click;
37 iScrollWidget *scroll;
36}; 38};
37 39
38iDeclareType(Url) 40iDeclareType(Url)
@@ -72,7 +74,6 @@ void init_DocumentWidget(iDocumentWidget *d) {
72 iWidget *w = as_Widget(d); 74 iWidget *w = as_Widget(d);
73 init_Widget(w); 75 init_Widget(w);
74 setId_Widget(w, "document"); 76 setId_Widget(w, "document");
75 setBackgroundColor_Widget(w, gray25_ColorId);
76 d->state = blank_DocumentState; 77 d->state = blank_DocumentState;
77 d->url = new_String(); 78 d->url = new_String();
78 d->statusCode = 0; 79 d->statusCode = 0;
@@ -84,6 +85,7 @@ void init_DocumentWidget(iDocumentWidget *d) {
84 init_PtrArray(&d->visibleLinks); 85 init_PtrArray(&d->visibleLinks);
85 d->hoverLink = NULL; 86 d->hoverLink = NULL;
86 init_Click(&d->click, d, SDL_BUTTON_LEFT); 87 init_Click(&d->click, d, SDL_BUTTON_LEFT);
88 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
87} 89}
88 90
89void deinit_DocumentWidget(iDocumentWidget *d) { 91void deinit_DocumentWidget(iDocumentWidget *d) {
@@ -110,11 +112,13 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) {
110 return rect; 112 return rect;
111} 113}
112 114
115#if 0
113void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) { 116void setSource_DocumentWidget(iDocumentWidget *d, const iString *source) {
114 /* TODO: lock source during update */ 117 /* TODO: lock source during update */
115 setSource_GmDocument(d->doc, source, documentWidth_DocumentWidget_(d)); 118 setSource_GmDocument(d->doc, source, documentWidth_DocumentWidget_(d));
116 d->state = ready_DocumentState; 119 d->state = ready_DocumentState;
117} 120}
121#endif
118 122
119static iRangecc getLine_(iRangecc text) { 123static iRangecc getLine_(iRangecc text) {
120 iRangecc line = { text.start, text.start }; 124 iRangecc line = { text.start, text.start };
@@ -194,6 +198,12 @@ void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) {
194 delete_String(newUrl); 198 delete_String(newUrl);
195} 199}
196 200
201static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) {
202 const int margin = gap_UI * d->pageMargin;
203 return (iRangei){ d->scrollY - margin,
204 d->scrollY + height_Rect(bounds_Widget(constAs_Widget(d))) - margin };
205}
206
197static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) { 207static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) {
198 iDocumentWidget *d = context; 208 iDocumentWidget *d = context;
199 if (run->linkId) { 209 if (run->linkId) {
@@ -201,19 +211,21 @@ static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) {
201 } 211 }
202} 212}
203 213
204static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { 214static int scrollMax_DocumentWidget_(const iDocumentWidget *d) {
205 const int margin = gap_UI * d->pageMargin; 215 return size_GmDocument(d->doc).y - height_Rect(bounds_Widget(constAs_Widget(d))) +
206 return (iRangei){ d->scrollY - margin, 216 2 * d->pageMargin * gap_UI;
207 d->scrollY + height_Rect(bounds_Widget(constAs_Widget(d))) - margin };
208} 217}
209 218
210static void updateVisible_DocumentWidget_(iDocumentWidget *d) { 219static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
220 const iRangei visRange = visibleRange_DocumentWidget_(d);
221 const iRect bounds = bounds_Widget(as_Widget(d));
222 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) });
223 const int docSize = size_GmDocument(d->doc).y;
224 setThumb_ScrollWidget(d->scroll,
225 d->scrollY,
226 docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0);
211 clear_PtrArray(&d->visibleLinks); 227 clear_PtrArray(&d->visibleLinks);
212 render_GmDocument( 228 render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d);
213 d->doc,
214 visibleRange_DocumentWidget_(d),
215 addVisibleLink_DocumentWidget_,
216 d);
217} 229}
218 230
219static iRangecc dirPath_(iRangecc path) { 231static iRangecc dirPath_(iRangecc path) {
@@ -300,8 +312,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
300 if (d->scrollY < 0) { 312 if (d->scrollY < 0) {
301 d->scrollY = 0; 313 d->scrollY = 0;
302 } 314 }
303 const int scrollMax = 315 const int scrollMax = scrollMax_DocumentWidget_(d);
304 size_GmDocument(d->doc).y - height_Rect(bounds_Widget(w)) + 2 * d->pageMargin * gap_UI;
305 if (scrollMax > 0) { 316 if (scrollMax > 0) {
306 d->scrollY = iMin(d->scrollY, scrollMax); 317 d->scrollY = iMin(d->scrollY, scrollMax);
307 } 318 }
@@ -377,21 +388,25 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
377 draw_Widget(w); 388 draw_Widget(w);
378 /* Update the document? */ 389 /* Update the document? */
379 if (!isEmpty_String(d->newSource)) { 390 if (!isEmpty_String(d->newSource)) {
391 iDocumentWidget *m = iConstCast(iDocumentWidget *, d);
380 /* TODO: Do this in the background. However, that requires a text metrics calculator 392 /* TODO: Do this in the background. However, that requires a text metrics calculator
381 that does not try to cache the glyph bitmaps. */ 393 that does not try to cache the glyph bitmaps. */
382 setSource_GmDocument(d->doc, d->newSource, documentWidth_DocumentWidget_(d)); 394 setSource_GmDocument(m->doc, m->newSource, documentWidth_DocumentWidget_(m));
383 clear_String(d->newSource); 395 clear_String(m->newSource);
384 iConstCast(iDocumentWidget *, d)->state = ready_DocumentState; 396 m->scrollY = 0;
385 updateVisible_DocumentWidget_(iConstCast(iDocumentWidget *, d)); 397 m->state = ready_DocumentState;
398 updateVisible_DocumentWidget_(m);
386 } 399 }
387 if (d->state != ready_DocumentState) return; 400 if (d->state != ready_DocumentState) return;
388 iDrawContext ctx = { .widget = d, .bounds = documentBounds_DocumentWidget_(d) }; 401 iDrawContext ctx = { .widget = d, .bounds = documentBounds_DocumentWidget_(d) };
389 init_Paint(&ctx.paint); 402 init_Paint(&ctx.paint);
403 fillRect_Paint(&ctx.paint, bounds_Widget(w), gray25_ColorId);
390 render_GmDocument( 404 render_GmDocument(
391 d->doc, 405 d->doc,
392 visibleRange_DocumentWidget_(d), 406 visibleRange_DocumentWidget_(d),
393 drawRun_DrawContext_, 407 drawRun_DrawContext_,
394 &ctx); 408 &ctx);
409 draw_Widget(w);
395} 410}
396 411
397iBeginDefineSubclass(DocumentWidget, Widget) 412iBeginDefineSubclass(DocumentWidget, Widget)
diff --git a/src/ui/scrollwidget.c b/src/ui/scrollwidget.c
new file mode 100644
index 00000000..cbfd2e70
--- /dev/null
+++ b/src/ui/scrollwidget.c
@@ -0,0 +1,79 @@
1#include "scrollwidget.h"
2#include "paint.h"
3
4iDefineObjectConstruction(ScrollWidget)
5
6struct Impl_ScrollWidget {
7 iWidget widget;
8 iRangei range;
9 int thumb;
10 int thumbSize;
11};
12
13void init_ScrollWidget(iScrollWidget *d) {
14 iWidget *w = as_Widget(d);
15 init_Widget(w);
16 setId_Widget(w, "scroll");
17 setFlags_Widget(w,
18 fixedWidth_WidgetFlag | resizeToParentHeight_WidgetFlag |
19 moveToParentRightEdge_WidgetFlag,
20 iTrue);
21 w->rect.size.x = gap_UI * 3;
22}
23
24void deinit_ScrollWidget(iScrollWidget *d) {
25 iUnused(d);
26}
27
28static iRect thumbRect_ScrollWidget_(const iScrollWidget *d) {
29 const iRect bounds = bounds_Widget(constAs_Widget(d));
30 iRect rect = init_Rect(bounds.pos.x, bounds.pos.y, bounds.size.x, 0);
31 const int total = size_Range(&d->range);
32// printf("total: %d thumb: %d thsize: %d\n", total, d->thumb, d->thumbSize); fflush(stdout);
33 if (total > 0) {
34 const int tsize = iMax(gap_UI * 6, d->thumbSize);
35 const int tpos =
36 iClamp((float) d->thumb / (float) total, 0, 1) * (height_Rect(bounds) - tsize);
37 rect.pos.y = tpos;
38 rect.size.y = tsize;
39 }
40 return rect;
41}
42
43static void checkVisible_ScrollWidget_(iScrollWidget *d) {
44 setFlags_Widget(as_Widget(d), hidden_WidgetFlag, height_Rect(thumbRect_ScrollWidget_(d)) == 0);
45}
46
47void setRange_ScrollWidget(iScrollWidget *d, iRangei range) {
48 range.end = iMax(range.start, range.end);
49 d->range = range;
50 checkVisible_ScrollWidget_(d);
51}
52
53void setThumb_ScrollWidget(iScrollWidget *d, int thumb, int thumbSize) {
54 d->thumb = thumb;
55 d->thumbSize = thumbSize;
56 checkVisible_ScrollWidget_(d);
57}
58
59static iBool processEvent_ScrollWidget_(iScrollWidget *d, const SDL_Event *ev) {
60 iWidget *w = as_Widget(d);
61 return processEvent_Widget(w, ev);
62}
63
64static void draw_ScrollWidget_(const iScrollWidget *d) {
65 const iWidget *w = constAs_Widget(d);
66 const iRect bounds = bounds_Widget(w);
67 if (bounds.size.x > 0) {
68 iPaint p;
69 init_Paint(&p);
70 drawRect_Paint(&p, bounds, black_ColorId);
71 iRect tr = thumbRect_ScrollWidget_(d);
72 fillRect_Paint(&p, thumbRect_ScrollWidget_(d), gray50_ColorId);
73 }
74}
75
76iBeginDefineSubclass(ScrollWidget, Widget)
77 .processEvent = (iAny *) processEvent_ScrollWidget_,
78 .draw = (iAny *) draw_ScrollWidget_,
79iEndDefineSubclass(ScrollWidget)
diff --git a/src/ui/scrollwidget.h b/src/ui/scrollwidget.h
new file mode 100644
index 00000000..7b44dced
--- /dev/null
+++ b/src/ui/scrollwidget.h
@@ -0,0 +1,11 @@
1#pragma once
2
3#include "widget.h"
4#include <the_Foundation/range.h>
5
6iDeclareWidgetClass(ScrollWidget)
7iDeclareObjectConstruction(ScrollWidget)
8
9void setRange_ScrollWidget (iScrollWidget *, iRangei range);
10void setThumb_ScrollWidget (iScrollWidget *, int thumb, int thumbSize);
11
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 49fcd7c0..5c23860f 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -150,6 +150,9 @@ static void setHeight_Widget_(iWidget *d, int height) {
150} 150}
151 151
152void arrange_Widget(iWidget *d) { 152void arrange_Widget(iWidget *d) {
153 if (d->flags & moveToParentRightEdge_WidgetFlag) {
154 d->rect.pos.x = width_Rect(d->parent->rect) - width_Rect(d->rect);
155 }
153 if (d->flags & resizeToParentWidth_WidgetFlag) { 156 if (d->flags & resizeToParentWidth_WidgetFlag) {
154 setWidth_Widget_(d, d->parent->rect.size.x); 157 setWidth_Widget_(d, d->parent->rect.size.x);
155 } 158 }
@@ -250,7 +253,8 @@ void arrange_Widget(iWidget *d) {
250 /* Parent size changed, must update the children.*/ 253 /* Parent size changed, must update the children.*/
251 iForEach(ObjectList, j, d->children) { 254 iForEach(ObjectList, j, d->children) {
252 iWidget *child = as_Widget(j.object); 255 iWidget *child = as_Widget(j.object);
253 if (child->flags & resizeToParentWidth_WidgetFlag) { 256 if (child->flags &
257 (resizeToParentWidth_WidgetFlag | moveToParentRightEdge_WidgetFlag)) {
254 arrange_Widget(child); 258 arrange_Widget(child);
255 } 259 }
256 } 260 }
diff --git a/src/ui/widget.h b/src/ui/widget.h
index bf5c22f1..2d13fe78 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -46,6 +46,7 @@ enum iWidgetFlag {
46 resizeChildrenToWidestChild_WidgetFlag = iBit(25), 46 resizeChildrenToWidestChild_WidgetFlag = iBit(25),
47 resizeToParentWidth_WidgetFlag = iBit(26), 47 resizeToParentWidth_WidgetFlag = iBit(26),
48 resizeToParentHeight_WidgetFlag = iBit(27), 48 resizeToParentHeight_WidgetFlag = iBit(27),
49 moveToParentRightEdge_WidgetFlag = iBit(28),
49}; 50};
50 51
51enum iWidgetAddPos { 52enum iWidgetAddPos {