summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c144
-rw-r--r--src/ui/mobile.c2
-rw-r--r--src/ui/root.c13
-rw-r--r--src/ui/touch.c6
-rw-r--r--src/ui/widget.c15
-rw-r--r--src/ui/widget.h2
6 files changed, 170 insertions, 12 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 936c3cb7..70201d7b 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -315,6 +315,10 @@ void init_DocumentWidget(iDocumentWidget *d) {
315 init_Widget(w); 315 init_Widget(w);
316 setId_Widget(w, format_CStr("document%03d", ++docEnum_)); 316 setId_Widget(w, format_CStr("document%03d", ++docEnum_));
317 setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); 317 setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue);
318 if (deviceType_App() != desktop_AppDeviceType) {
319 setFlags_Widget(w, leftEdgeDraggable_WidgetFlag | rightEdgeDraggable_WidgetFlag |
320 horizontalOffset_WidgetFlag, iTrue);
321 }
318 init_PersistentDocumentState(&d->mod); 322 init_PersistentDocumentState(&d->mod);
319 d->flags = 0; 323 d->flags = 0;
320 d->phoneToolbar = NULL; 324 d->phoneToolbar = NULL;
@@ -977,6 +981,9 @@ static void updateTimestampBuf_DocumentWidget_(const iDocumentWidget *d) {
977} 981}
978 982
979static void invalidate_DocumentWidget_(iDocumentWidget *d) { 983static void invalidate_DocumentWidget_(iDocumentWidget *d) {
984 if (flags_Widget(as_Widget(d)) & destroyPending_WidgetFlag) {
985 return;
986 }
980 invalidate_VisBuf(d->visBuf); 987 invalidate_VisBuf(d->visBuf);
981 clear_PtrSet(d->invalidRuns); 988 clear_PtrSet(d->invalidRuns);
982} 989}
@@ -2237,6 +2244,133 @@ static iBool handlePinch_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
2237 return iTrue; 2244 return iTrue;
2238} 2245}
2239 2246
2247static void swap_DocumentWidget_(iDocumentWidget *d, iGmDocument *doc,
2248 iDocumentWidget *swapBuffersWith) {
2249 if (doc) {
2250 iAssert(isInstance_Object(doc, &Class_GmDocument));
2251 iGmDocument *copy = ref_Object(doc);
2252 iRelease(d->doc);
2253 d->doc = copy;
2254 d->scrollY = swapBuffersWith->scrollY;
2255 updateVisible_DocumentWidget_(d);
2256 iSwap(iVisBuf *, d->visBuf, swapBuffersWith->visBuf);
2257 iSwap(iVisBufMeta *, d->visBufMeta, swapBuffersWith->visBufMeta);
2258 iSwap(iDrawBufs *, d->drawBufs, swapBuffersWith->drawBufs);
2259 invalidate_DocumentWidget_(swapBuffersWith);
2260 }
2261}
2262
2263static iWidget *swipeParent_DocumentWidget_(iDocumentWidget *d) {
2264 return findChild_Widget(as_Widget(d)->root->widget, "doctabs");
2265}
2266
2267static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
2268 iWidget *w = as_Widget(d);
2269 if (equal_Command(cmd, "edgeswipe.moved")) {
2270 as_Widget(d)->offsetRef = NULL;
2271 const int side = argLabel_Command(cmd, "side");
2272 const int offset = arg_Command(cmd);
2273 if (side == 1) {
2274 if (atOldest_History(d->mod.history)) {
2275 return iTrue;
2276 }
2277 iWidget *swipeParent = swipeParent_DocumentWidget_(d);
2278 /* The temporary "swipeIn" will display the previous page until the finger is lifted. */
2279 iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein");
2280 if (!swipeIn) {
2281 swipeIn = new_DocumentWidget();
2282 setId_Widget(as_Widget(swipeIn), "swipein");
2283 setFlags_Widget(as_Widget(swipeIn),
2284 disabled_WidgetFlag | refChildrenOffset_WidgetFlag |
2285 fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue);
2286 swipeIn->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos));
2287 swipeIn->widget.rect.size = d->widget.rect.size;
2288 swipeIn->widget.offsetRef = w;
2289 iRecentUrl *recent = new_RecentUrl();
2290 preceding_History(d->mod.history, recent);
2291 if (recent->cachedDoc) {
2292 iChangeRef(swipeIn->doc, recent->cachedDoc);
2293 updateScrollMax_DocumentWidget_(d);
2294 setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0);
2295 updateVisible_DocumentWidget_(swipeIn);
2296 }
2297 delete_RecentUrl(recent);
2298 addChildPos_Widget(swipeParent, iClob(swipeIn), front_WidgetAddPos);
2299 }
2300 }
2301 if (side == 2) {
2302 if (offset < -get_Window()->pixelRatio * 10) {
2303 if (!atLatest_History(d->mod.history) &&
2304 ~flags_Widget(w) & dragged_WidgetFlag) {
2305 postCommand_Widget(d, "navigate.forward");
2306 setFlags_Widget(w, dragged_WidgetFlag, iTrue);
2307 /* Set up the swipe dummy. */
2308 iWidget *swipeParent = swipeParent_DocumentWidget_(d);
2309 iDocumentWidget *target = new_DocumentWidget();
2310 setId_Widget(as_Widget(target), "swipeout");
2311 /* The target takes the old document and jumps on top. */
2312 target->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos));
2313 target->widget.rect.size = d->widget.rect.size;
2314 setFlags_Widget(as_Widget(target), fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue);
2315 swap_DocumentWidget_(target, d->doc, d);
2316 addChildPos_Widget(swipeParent, iClob(target), front_WidgetAddPos);
2317 setFlags_Widget(as_Widget(target), refChildrenOffset_WidgetFlag, iTrue);
2318 as_Widget(target)->offsetRef = parent_Widget(w);
2319 destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */
2320 }
2321 if (flags_Widget(w) & dragged_WidgetFlag) {
2322 setVisualOffset_Widget(w, width_Widget(w) + offset, 10, 0);
2323 }
2324 else {
2325 setVisualOffset_Widget(w, offset / 4, 10, 0);
2326 }
2327 }
2328 return iTrue;
2329 }
2330 }
2331 if (equal_Command(cmd, "edgeswipe.ended") && argLabel_Command(cmd, "side") == 2) {
2332 if (argLabel_Command(cmd, "abort") && flags_Widget(w) & dragged_WidgetFlag) {
2333 postCommand_Widget(d, "navigate.back");
2334 }
2335 setFlags_Widget(w, dragged_WidgetFlag, iFalse);
2336 setVisualOffset_Widget(w, 0, 100, 0);
2337 return iTrue;
2338 }
2339 if (equal_Command(cmd, "edgeswipe.ended") && argLabel_Command(cmd, "side") == 1) {
2340 iWidget *swipeParent = swipeParent_DocumentWidget_(d);
2341 iWidget *swipeIn = findChild_Widget(swipeParent, "swipein");
2342 if (swipeIn) {
2343 swipeIn->offsetRef = NULL;
2344 destroy_Widget(swipeIn);
2345 }
2346 }
2347 if (equal_Command(cmd, "swipe.back")) {
2348 if (atOldest_History(d->mod.history)) {
2349 setVisualOffset_Widget(w, 0, 100, 0);
2350 return iTrue;
2351 }
2352 iWidget *swipeParent = swipeParent_DocumentWidget_(d);
2353 iDocumentWidget *target = new_DocumentWidget();
2354 setId_Widget(as_Widget(target), "swipeout");
2355 /* The target takes the old document and jumps on top. */
2356 target->widget.rect.pos = windowToInner_Widget(swipeParent, innerToWindow_Widget(w, zero_I2()));
2357 /* Note: `innerToWindow_Widget` does not apply visual offset. */
2358 target->widget.rect.size = w->rect.size;
2359 setFlags_Widget(as_Widget(target), fixedPosition_WidgetFlag | fixedSize_WidgetFlag, iTrue);
2360 swap_DocumentWidget_(target, d->doc, d);
2361 addChildPos_Widget(swipeParent, iClob(target), back_WidgetAddPos);
2362 setFlags_Widget(as_Widget(d), refChildrenOffset_WidgetFlag, iTrue);
2363 as_Widget(d)->offsetRef = swipeParent;
2364 setVisualOffset_Widget(as_Widget(target), value_Anim(&w->visualOffset), 0, 0);
2365 setVisualOffset_Widget(as_Widget(target), width_Widget(target), 150, 0);
2366 destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */
2367 setVisualOffset_Widget(w, 0, 0, 0);
2368 postCommand_Widget(d, "navigate.back");
2369 return iTrue;
2370 }
2371 return iFalse;
2372}
2373
2240static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { 2374static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
2241 iWidget *w = as_Widget(d); 2375 iWidget *w = as_Widget(d);
2242 if (equal_Command(cmd, "document.openurls.changed")) { 2376 if (equal_Command(cmd, "document.openurls.changed")) {
@@ -2842,7 +2976,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2842 uiHeading_ColorEscape "${heading.import.bookmarks}", 2976 uiHeading_ColorEscape "${heading.import.bookmarks}",
2843 formatCStrs_Lang("dlg.import.found.n", count), 2977 formatCStrs_Lang("dlg.import.found.n", count),
2844 (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, 2978 (iMenuItem[]){ { "${cancel}", 0, 0, NULL },
2845 { format_CStr(cstrCount_Lang("dlg.import.add.n", count), 2979 { format_CStr(cstrCount_Lang("dlg.import.add.n", (int) count),
2846 uiTextAction_ColorEscape, 2980 uiTextAction_ColorEscape,
2847 count), 2981 count),
2848 0, 2982 0,
@@ -2901,6 +3035,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2901 else if (startsWith_CStr(cmd, "pinch.") && document_Command(cmd) == d) { 3035 else if (startsWith_CStr(cmd, "pinch.") && document_Command(cmd) == d) {
2902 return handlePinch_DocumentWidget_(d, cmd); 3036 return handlePinch_DocumentWidget_(d, cmd);
2903 } 3037 }
3038 else if ((startsWith_CStr(cmd, "edgeswipe.") || startsWith_CStr(cmd, "swipe.")) &&
3039 document_App() == d) {
3040 return handleSwipe_DocumentWidget_(d, cmd);
3041 }
2904 return iFalse; 3042 return iFalse;
2905} 3043}
2906 3044
@@ -4306,7 +4444,8 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx,
4306 /* Swap buffers around to have room available both before and after the visible region. */ 4444 /* Swap buffers around to have room available both before and after the visible region. */
4307 allocVisBuffer_DocumentWidget_(d); 4445 allocVisBuffer_DocumentWidget_(d);
4308 reposition_VisBuf(visBuf, vis); 4446 reposition_VisBuf(visBuf, vis);
4309 /* Redraw the invalid ranges. */ { 4447 /* Redraw the invalid ranges. */
4448 if (~flags_Widget(constAs_Widget(d)) & destroyPending_WidgetFlag) {
4310 iPaint *p = &ctx->paint; 4449 iPaint *p = &ctx->paint;
4311 init_Paint(p); 4450 init_Paint(p);
4312 iForIndices(i, visBuf->buffers) { 4451 iForIndices(i, visBuf->buffers) {
@@ -4490,6 +4629,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4490 .vis = vis, 4629 .vis = vis,
4491 .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0, 4630 .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0,
4492 }; 4631 };
4632 init_Paint(&ctx.paint);
4493 render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); 4633 render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */);
4494 setClip_Paint(&ctx.paint, bounds); 4634 setClip_Paint(&ctx.paint, bounds);
4495 int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); 4635 int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY);
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index 1bf289a7..7c0c8b60 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -447,7 +447,7 @@ void finalizeSheet_Mobile(iWidget *sheet) {
447 } 447 }
448 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); 448 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
449 /* Slide top panel with detail panels. */ { 449 /* Slide top panel with detail panels. */ {
450 setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue); 450 setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue);
451 topPanel->offsetRef = detailStack; 451 topPanel->offsetRef = detailStack;
452 } 452 }
453 if (prefsTabs) { 453 if (prefsTabs) {
diff --git a/src/ui/root.c b/src/ui/root.c
index 2d69970d..e279a048 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -271,7 +271,8 @@ void destroyPending_Root(iRoot *d) {
271 setCurrent_Root(d); 271 setCurrent_Root(d);
272 iForEach(PtrSet, i, d->pendingDestruction) { 272 iForEach(PtrSet, i, d->pendingDestruction) {
273 iWidget *widget = *i.value; 273 iWidget *widget = *i.value;
274 if (!isFinished_Anim(&widget->visualOffset)) { 274 if (!isFinished_Anim(&widget->visualOffset) ||
275 isBeingVisuallyOffsetByReference_Widget(widget)) {
275 continue; 276 continue;
276 } 277 }
277 if (widget->flags & keepOnTop_WidgetFlag) { 278 if (widget->flags & keepOnTop_WidgetFlag) {
@@ -1169,11 +1170,11 @@ void createUserInterface_Root(iRoot *d) {
1169 setId_Widget(mainStack, "stack"); 1170 setId_Widget(mainStack, "stack");
1170 addChildFlags_Widget(div, iClob(mainStack), resizeChildren_WidgetFlag | expand_WidgetFlag | 1171 addChildFlags_Widget(div, iClob(mainStack), resizeChildren_WidgetFlag | expand_WidgetFlag |
1171 unhittable_WidgetFlag); 1172 unhittable_WidgetFlag);
1172 iWidget *tabBar = makeTabs_Widget(mainStack); 1173 iWidget *docTabs = makeTabs_Widget(mainStack);
1173 setId_Widget(tabBar, "doctabs"); 1174 setId_Widget(docTabs, "doctabs");
1174 setBackgroundColor_Widget(tabBar, uiBackground_ColorId); 1175 setBackgroundColor_Widget(docTabs, uiBackground_ColorId);
1175 appendTabPage_Widget(tabBar, iClob(new_DocumentWidget()), "Document", 0, 0); 1176 appendTabPage_Widget(docTabs, iClob(new_DocumentWidget()), "Document", 0, 0);
1176 iWidget *buttons = findChild_Widget(tabBar, "tabs.buttons"); 1177 iWidget *buttons = findChild_Widget(docTabs, "tabs.buttons");
1177 setFlags_Widget(buttons, collapse_WidgetFlag | hidden_WidgetFlag | 1178 setFlags_Widget(buttons, collapse_WidgetFlag | hidden_WidgetFlag |
1178 drawBackgroundToHorizontalSafeArea_WidgetFlag, iTrue); 1179 drawBackgroundToHorizontalSafeArea_WidgetFlag, iTrue);
1179 if (deviceType_App() == phone_AppDeviceType) { 1180 if (deviceType_App() == phone_AppDeviceType) {
diff --git a/src/ui/touch.c b/src/ui/touch.c
index 236601e8..36bac267 100644
--- a/src/ui/touch.c
+++ b/src/ui/touch.c
@@ -273,8 +273,9 @@ static void update_TouchState_(void *ptr) {
273// touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0); 273// touch->edge == right_TouchEdge && swipeDir < 0 ? SDL_BUTTON_X2 : 0);
274// setHover_Widget(NULL); 274// setHover_Widget(NULL);
275 postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", touch->edge, touch->id); 275 postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", touch->edge, touch->id);
276 touch->edge = none_TouchEdge; 276 touch->edge = none_TouchEdge;
277 remove_ArrayIterator(&i); 277 /* May be a regular drag along the edge so don't remove. */
278 //remove_ArrayIterator(&i);
278 } 279 }
279 continue; 280 continue;
280 } 281 }
@@ -516,6 +517,7 @@ iBool processEvent_Touch(const SDL_Event *ev) {
516 else if (ev->type == SDL_FINGERMOTION) { 517 else if (ev->type == SDL_FINGERMOTION) {
517 iTouch *touch = find_TouchState_(d, fing->fingerId); 518 iTouch *touch = find_TouchState_(d, fing->fingerId);
518 if (touch && touch->edge) { 519 if (touch && touch->edge) {
520 clear_Array(d->moms);
519 pushPos_Touch_(touch, pos, nowTime); 521 pushPos_Touch_(touch, pos, nowTime);
520 postCommandf_App("edgeswipe.moved arg:%d side:%d id:%llu", 522 postCommandf_App("edgeswipe.moved arg:%d side:%d id:%llu",
521 (int) (x_F3(pos) - x_F3(touch->startPos)), 523 (int) (x_F3(pos) - x_F3(touch->startPos)),
diff --git a/src/ui/widget.c b/src/ui/widget.c
index f1d1dae4..3b67684b 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -759,6 +759,19 @@ void arrange_Widget(iWidget *d) {
759 } 759 }
760} 760}
761 761
762iBool isBeingVisuallyOffsetByReference_Widget(const iWidget *d) {
763 if (d->flags & refChildrenOffset_WidgetFlag) {
764 iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) {
765 const iWidget *child = i.object;
766 if (child == d) continue;
767 if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) {
768 return iTrue;
769 }
770 }
771 }
772 return iFalse;
773}
774
762static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { 775static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) {
763 if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { 776 if (d->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) {
764 const int off = iRound(value_Anim(&d->visualOffset)); 777 const int off = iRound(value_Anim(&d->visualOffset));
@@ -1075,12 +1088,12 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) {
1075 if (d->flags & dragged_WidgetFlag && equal_Command(cmd, "edgeswipe.ended")) { 1088 if (d->flags & dragged_WidgetFlag && equal_Command(cmd, "edgeswipe.ended")) {
1076 if (argLabel_Command(cmd, "abort")) { 1089 if (argLabel_Command(cmd, "abort")) {
1077 setVisualOffset_Widget(d, 0, 200, easeOut_AnimFlag); 1090 setVisualOffset_Widget(d, 0, 200, easeOut_AnimFlag);
1078 setFlags_Widget(d, dragged_WidgetFlag, iFalse);
1079 } 1091 }
1080 else { 1092 else {
1081 postCommand_Widget( 1093 postCommand_Widget(
1082 d, argLabel_Command(cmd, "side") == 1 ? "swipe.back" : "swipe.forward"); 1094 d, argLabel_Command(cmd, "side") == 1 ? "swipe.back" : "swipe.forward");
1083 } 1095 }
1096 setFlags_Widget(d, dragged_WidgetFlag, iFalse);
1084 } 1097 }
1085 if (d->commandHandler && d->commandHandler(d, ev->user.data1)) { 1098 if (d->commandHandler && d->commandHandler(d, ev->user.data1)) {
1086 iAssert(get_Root() == d->root); 1099 iAssert(get_Root() == d->root);
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 7255b975..b2310f21 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -244,6 +244,8 @@ iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, cons
244iBool hasParent_Widget (const iWidget *d, const iWidget *someParent); 244iBool hasParent_Widget (const iWidget *d, const iWidget *someParent);
245iBool isAffectedByVisualOffset_Widget 245iBool isAffectedByVisualOffset_Widget
246 (const iWidget *); 246 (const iWidget *);
247iBool isBeingVisuallyOffsetByReference_Widget
248 (const iWidget *);
247void setId_Widget (iWidget *, const char *id); 249void setId_Widget (iWidget *, const char *id);
248void setFlags_Widget (iWidget *, int64_t flags, iBool set); 250void setFlags_Widget (iWidget *, int64_t flags, iBool set);
249void setPos_Widget (iWidget *, iInt2 pos); 251void setPos_Widget (iWidget *, iInt2 pos);