diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-15 22:12:57 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-15 22:12:57 +0200 |
commit | 71d8274d07a548decdd9065106c9a8fdf50a6f8c (patch) | |
tree | 06aa4a80b9f1f1f441f6fddb4fabb7825ad2e698 /src | |
parent | 65f47b60d521c23f16cb8cbcce6f9e9e3176279a (diff) |
Mobile: Find on page, various minor tweaks
On mobile, the search bar appears at the top of the page.
Keep the haptic engine running so there is no delay before each effect.
After a long-press, remove the "mouse" from the display area so there is no misleading hover.
Widget border top/bottom use metrics.
Diffstat (limited to 'src')
-rw-r--r-- | src/defs.h | 2 | ||||
-rw-r--r-- | src/ios.m | 10 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 11 | ||||
-rw-r--r-- | src/ui/touch.c | 7 | ||||
-rw-r--r-- | src/ui/util.c | 1 | ||||
-rw-r--r-- | src/ui/widget.c | 7 | ||||
-rw-r--r-- | src/ui/window.c | 16 |
7 files changed, 37 insertions, 17 deletions
@@ -80,3 +80,5 @@ enum iFileVersion { | |||
80 | #define clipCopy_Icon "\u2398" | 80 | #define clipCopy_Icon "\u2398" |
81 | #define clipboard_Icon "\U0001f4cb" | 81 | #define clipboard_Icon "\U0001f4cb" |
82 | #define unhappy_Icon "\U0001f641" | 82 | #define unhappy_Icon "\U0001f641" |
83 | #define globe_Icon "\U0001f310" | ||
84 | #define magnifyingGlass_Icon "\U0001f50d" | ||
@@ -106,9 +106,10 @@ API_AVAILABLE(ios(13.0)) | |||
106 | // TODO: Check the error. | 106 | // TODO: Check the error. |
107 | [self.engine startWithCompletionHandler:^(NSError *err){ | 107 | [self.engine startWithCompletionHandler:^(NSError *err){ |
108 | if (err == nil) { | 108 | if (err == nil) { |
109 | [self.engine notifyWhenPlayersFinished:^(NSError * _Nullable error) { | 109 | /* Just keep it running. */ |
110 | return CHHapticEngineFinishedActionStopEngine; | 110 | // [self.engine notifyWhenPlayersFinished:^(NSError * _Nullable error) { |
111 | }]; | 111 | // return CHHapticEngineFinishedActionStopEngine; |
112 | // }]; | ||
112 | NSError *startError = nil; | 113 | NSError *startError = nil; |
113 | [player startAtTime:0.0 error:&startError]; | 114 | [player startAtTime:0.0 error:&startError]; |
114 | } | 115 | } |
@@ -135,6 +136,9 @@ static AppState *appState_; | |||
135 | HapticState *hs = [[HapticState alloc] init]; | 136 | HapticState *hs = [[HapticState alloc] init]; |
136 | [hs setup]; | 137 | [hs setup]; |
137 | self.haptic = hs; | 138 | self.haptic = hs; |
139 | /* We start the engine and keep it running. */ | ||
140 | NSError *err; | ||
141 | [hs.engine startAndReturnError:&err]; | ||
138 | } | 142 | } |
139 | } else { | 143 | } else { |
140 | self.isHapticsAvailable = NO; | 144 | self.isHapticsAvailable = NO; |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index a468e2df..6df25433 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -2526,8 +2526,8 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2526 | &items, | 2526 | &items, |
2527 | (iMenuItem[]){ | 2527 | (iMenuItem[]){ |
2528 | { "Go Back", navigateBack_KeyShortcut, "navigate.back" }, | 2528 | { "Go Back", navigateBack_KeyShortcut, "navigate.back" }, |
2529 | { "Go Forward", navigateForward_KeyShortcut, "navigate.forward" } }, | 2529 | { "Go Forward", navigateForward_KeyShortcut, "navigate.forward" } }, |
2530 | 2); | 2530 | 2); |
2531 | } | 2531 | } |
2532 | pushBackN_Array( | 2532 | pushBackN_Array( |
2533 | &items, | 2533 | &items, |
@@ -2542,10 +2542,15 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2542 | { star_Icon " Subscribe to Page...", subscribeToPage_KeyModifier, "feeds.subscribe" }, | 2542 | { star_Icon " Subscribe to Page...", subscribeToPage_KeyModifier, "feeds.subscribe" }, |
2543 | { "---", 0, 0, NULL }, | 2543 | { "---", 0, 0, NULL }, |
2544 | { book_Icon " Import Links as Bookmarks...", 0, 0, "bookmark.links confirm:1" }, | 2544 | { book_Icon " Import Links as Bookmarks...", 0, 0, "bookmark.links confirm:1" }, |
2545 | { "Translate...", 0, 0, "document.translate" }, | 2545 | { globe_Icon " Translate...", 0, 0, "document.translate" }, |
2546 | { "---", 0, 0, NULL }, | 2546 | { "---", 0, 0, NULL }, |
2547 | { "Copy Page URL", 0, 0, "document.copylink" } }, | 2547 | { "Copy Page URL", 0, 0, "document.copylink" } }, |
2548 | 12); | 2548 | 12); |
2549 | if (deviceType_App() != desktop_AppDeviceType) { | ||
2550 | /* TODO: Perhaps not the best place for this? */ | ||
2551 | insert_Array(&items, size_Array(&items) - 3, | ||
2552 | &(iMenuItem){ magnifyingGlass_Icon " Find on page", 0, 0, "focus.set id:find.input" }); | ||
2553 | } | ||
2549 | if (isEmpty_Range(&d->selectMark)) { | 2554 | if (isEmpty_Range(&d->selectMark)) { |
2550 | pushBackN_Array( | 2555 | pushBackN_Array( |
2551 | &items, | 2556 | &items, |
diff --git a/src/ui/touch.c b/src/ui/touch.c index 8866fb43..c369c5a5 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -56,6 +56,7 @@ struct Impl_Touch { | |||
56 | iWidget *affinity; /* widget on which the touch started */ | 56 | iWidget *affinity; /* widget on which the touch started */ |
57 | iWidget *edgeDragging; | 57 | iWidget *edgeDragging; |
58 | iBool hasMoved; | 58 | iBool hasMoved; |
59 | iBool isTapBegun; | ||
59 | iBool isTouchDrag; | 60 | iBool isTouchDrag; |
60 | iBool isTapAndHold; | 61 | iBool isTapAndHold; |
61 | enum iTouchEdge edge; | 62 | enum iTouchEdge edge; |
@@ -151,7 +152,6 @@ static iBool dispatchClick_Touch_(const iTouch *d, int button) { | |||
151 | btn.state = SDL_RELEASED; | 152 | btn.state = SDL_RELEASED; |
152 | btn.timestamp = SDL_GetTicks(); | 153 | btn.timestamp = SDL_GetTicks(); |
153 | dispatchEvent_Widget(window->root, (SDL_Event *) &btn); | 154 | dispatchEvent_Widget(window->root, (SDL_Event *) &btn); |
154 | setHover_Widget(NULL); /* FIXME: this doesn't seem to do anything? */ | ||
155 | if (!wasUsed && button == SDL_BUTTON_RIGHT) { | 155 | if (!wasUsed && button == SDL_BUTTON_RIGHT) { |
156 | postContextClick_Window(window, &btn); | 156 | postContextClick_Window(window, &btn); |
157 | } | 157 | } |
@@ -180,9 +180,10 @@ static void update_TouchState_(void *ptr) { | |||
180 | if (elapsed > 25) { | 180 | if (elapsed > 25) { |
181 | clearWidgetMomentum_TouchState_(d, touch->affinity); | 181 | clearWidgetMomentum_TouchState_(d, touch->affinity); |
182 | } | 182 | } |
183 | if (elapsed > 50) { | 183 | if (elapsed > 50 && !touch->isTapBegun) { |
184 | /* Looks like a possible tap. */ | 184 | /* Looks like a possible tap. */ |
185 | dispatchMotion_Touch_(touch->pos[0], 0); | 185 | dispatchMotion_Touch_(touch->pos[0], 0); |
186 | touch->isTapBegun = iTrue; | ||
186 | } | 187 | } |
187 | if (!touch->isTapAndHold && nowTime - touch->startTime >= longPressSpanMs_ && | 188 | if (!touch->isTapAndHold && nowTime - touch->startTime >= longPressSpanMs_ && |
188 | touch->affinity) { | 189 | touch->affinity) { |
@@ -193,6 +194,7 @@ static void update_TouchState_(void *ptr) { | |||
193 | #if defined (iPlatformAppleMobile) | 194 | #if defined (iPlatformAppleMobile) |
194 | playHapticEffect_iOS(tap_HapticEffect); | 195 | playHapticEffect_iOS(tap_HapticEffect); |
195 | #endif | 196 | #endif |
197 | dispatchMotion_Touch_(init_F3(-100, -100, 0), 0); | ||
196 | } | 198 | } |
197 | } | 199 | } |
198 | } | 200 | } |
@@ -535,6 +537,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
535 | if (duration < longPressSpanMs_ && isStationary_Touch_(touch)) { | 537 | if (duration < longPressSpanMs_ && isStationary_Touch_(touch)) { |
536 | dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK); | 538 | dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK); |
537 | dispatchClick_Touch_(touch, SDL_BUTTON_LEFT); | 539 | dispatchClick_Touch_(touch, SDL_BUTTON_LEFT); |
540 | dispatchMotion_Touch_(init_F3(-100, -100, 0), 0); /* out of screen */ | ||
538 | } | 541 | } |
539 | else if (length_F3(velocity) > 0.0f) { | 542 | else if (length_F3(velocity) > 0.0f) { |
540 | // printf("vel:%f\n", length_F3(velocity)); | 543 | // printf("vel:%f\n", length_F3(velocity)); |
diff --git a/src/ui/util.c b/src/ui/util.c index 9d75129e..18ed7ba2 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -1060,7 +1060,6 @@ static iWidget *makeValuePadding_(iWidget *value) { | |||
1060 | setPadding_Widget(pad, 0, 1 * gap_UI, 0, 1 * gap_UI); | 1060 | setPadding_Widget(pad, 0, 1 * gap_UI, 0, 1 * gap_UI); |
1061 | addChild_Widget(pad, iClob(value)); | 1061 | addChild_Widget(pad, iClob(value)); |
1062 | setFlags_Widget(pad, | 1062 | setFlags_Widget(pad, |
1063 | borderTop_WidgetFlag | | ||
1064 | borderBottom_WidgetFlag | | 1063 | borderBottom_WidgetFlag | |
1065 | arrangeVertical_WidgetFlag | | 1064 | arrangeVertical_WidgetFlag | |
1066 | resizeToParentWidth_WidgetFlag | | 1065 | resizeToParentWidth_WidgetFlag | |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 6a6480e5..8641dd61 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -871,12 +871,15 @@ void drawBackground_Widget(const iWidget *d) { | |||
871 | const iRect rect = bounds_Widget(d); | 871 | const iRect rect = bounds_Widget(d); |
872 | iPaint p; | 872 | iPaint p; |
873 | init_Paint(&p); | 873 | init_Paint(&p); |
874 | const int hgt = gap_UI / 4; | ||
874 | if (d->flags & borderTop_WidgetFlag) { | 875 | if (d->flags & borderTop_WidgetFlag) { |
875 | drawHLine_Paint(&p, topLeft_Rect(rect), width_Rect(rect), | 876 | fillRect_Paint(&p, (iRect){ topLeft_Rect(rect), |
877 | init_I2(width_Rect(rect), hgt) }, | ||
876 | uiBackgroundFramelessHover_ColorId); | 878 | uiBackgroundFramelessHover_ColorId); |
877 | } | 879 | } |
878 | if (d->flags & borderBottom_WidgetFlag) { | 880 | if (d->flags & borderBottom_WidgetFlag) { |
879 | drawHLine_Paint(&p, addY_I2(bottomLeft_Rect(rect), -1), width_Rect(rect), | 881 | fillRect_Paint(&p, (iRect) { addY_I2(bottomLeft_Rect(rect), -hgt), |
882 | init_I2(width_Rect(rect), hgt) }, | ||
880 | uiBackgroundFramelessHover_ColorId); | 883 | uiBackgroundFramelessHover_ColorId); |
881 | } | 884 | } |
882 | } | 885 | } |
diff --git a/src/ui/window.c b/src/ui/window.c index 29f240c2..2ef67142 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -218,8 +218,6 @@ static const iMenuItem tabletNavMenuItems_[] = { | |||
218 | { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, | 218 | { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, |
219 | { close_Icon " Close Tab", 'w', KMOD_PRIMARY, "tabs.close" }, | 219 | { close_Icon " Close Tab", 'w', KMOD_PRIMARY, "tabs.close" }, |
220 | { "---", 0, 0, NULL }, | 220 | { "---", 0, 0, NULL }, |
221 | { download_Icon " Save to Downloads", SDLK_s, KMOD_PRIMARY, "document.save" }, | ||
222 | { "---", 0, 0, NULL }, | ||
223 | { "Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, | 221 | { "Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, |
224 | { "Toggle Right Sidebar", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" }, | 222 | { "Toggle Right Sidebar", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" }, |
225 | { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, | 223 | { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, |
@@ -240,8 +238,6 @@ static const iMenuItem phoneNavMenuItems_[] = { | |||
240 | { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, | 238 | { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, |
241 | { close_Icon " Close Tab", 'w', KMOD_PRIMARY, "tabs.close" }, | 239 | { close_Icon " Close Tab", 'w', KMOD_PRIMARY, "tabs.close" }, |
242 | { "---", 0, 0, NULL }, | 240 | { "---", 0, 0, NULL }, |
243 | { download_Icon " Save to Downloads", SDLK_s, KMOD_PRIMARY, "document.save" }, | ||
244 | { "---", 0, 0, NULL }, | ||
245 | { "Toggle Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, | 241 | { "Toggle Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, |
246 | { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, | 242 | { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, |
247 | { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, | 243 | { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, |
@@ -1093,11 +1089,19 @@ static void setupUserInterface_Window(iWindow *d) { | |||
1093 | arrangeHeight_WidgetFlag | resizeChildren_WidgetFlag | | 1089 | arrangeHeight_WidgetFlag | resizeChildren_WidgetFlag | |
1094 | arrangeHorizontal_WidgetFlag, | 1090 | arrangeHorizontal_WidgetFlag, |
1095 | iTrue); | 1091 | iTrue); |
1096 | addChild_Widget(div, iClob(searchBar)); | 1092 | if (deviceType_App() == desktop_AppDeviceType) { |
1093 | addChild_Widget(div, iClob(searchBar)); | ||
1094 | } | ||
1095 | else { | ||
1096 | /* The search bar appears at the top on mobile, because there is a virtual keyboard | ||
1097 | covering the bottom. */ | ||
1098 | insertChildAfter_Widget(div, iClob(searchBar), | ||
1099 | childIndex_Widget(div, findChild_Widget(div, "navbar"))); | ||
1100 | } | ||
1097 | setBackgroundColor_Widget(searchBar, uiBackground_ColorId); | 1101 | setBackgroundColor_Widget(searchBar, uiBackground_ColorId); |
1098 | setCommandHandler_Widget(searchBar, handleSearchBarCommands_); | 1102 | setCommandHandler_Widget(searchBar, handleSearchBarCommands_); |
1099 | addChildFlags_Widget( | 1103 | addChildFlags_Widget( |
1100 | searchBar, iClob(new_LabelWidget("\U0001f50d Text", NULL)), frameless_WidgetFlag); | 1104 | searchBar, iClob(new_LabelWidget(magnifyingGlass_Icon " Text", NULL)), frameless_WidgetFlag); |
1101 | iInputWidget *input = new_InputWidget(0); | 1105 | iInputWidget *input = new_InputWidget(0); |
1102 | setSelectAllOnFocus_InputWidget(input, iTrue); | 1106 | setSelectAllOnFocus_InputWidget(input, iTrue); |
1103 | setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ | 1107 | setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ |