diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-20 08:33:15 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-20 08:33:15 +0200 |
commit | 0c4fc5d9189510ff88369709f018afc550aa0b54 (patch) | |
tree | 88f743ca8e6ab22e8eea781d116cdfc34c8b91d0 | |
parent | c1cc59ee6a6d8b88d6f49eb59ffa871d75c75866 (diff) |
iOS: Tweaks and changes for phone mode
Phone mode uses a modified user interface. Work in progress...
-rw-r--r-- | res/LaunchScreen.storyboard | 7 | ||||
-rw-r--r-- | src/app.c | 14 | ||||
-rw-r--r-- | src/app.h | 9 | ||||
-rw-r--r-- | src/ios.h | 2 | ||||
-rw-r--r-- | src/ios.m | 25 | ||||
-rw-r--r-- | src/prefs.c | 3 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 14 | ||||
-rw-r--r-- | src/ui/listwidget.c | 10 | ||||
-rw-r--r-- | src/ui/lookupwidget.c | 17 | ||||
-rw-r--r-- | src/ui/touch.c | 85 | ||||
-rw-r--r-- | src/ui/util.c | 20 | ||||
-rw-r--r-- | src/ui/widget.c | 8 | ||||
-rw-r--r-- | src/ui/window.c | 63 |
13 files changed, 197 insertions, 80 deletions
diff --git a/res/LaunchScreen.storyboard b/res/LaunchScreen.storyboard new file mode 100644 index 00000000..f9a048ed --- /dev/null +++ b/res/LaunchScreen.storyboard | |||
@@ -0,0 +1,7 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | ||
3 | <dependencies> | ||
4 | <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/> | ||
5 | </dependencies> | ||
6 | <scenes/> | ||
7 | </document> | ||
@@ -941,6 +941,20 @@ iMimeHooks *mimeHooks_App(void) { | |||
941 | return app_.mimehooks; | 941 | return app_.mimehooks; |
942 | } | 942 | } |
943 | 943 | ||
944 | iBool isLandscape_App(void) { | ||
945 | const iApp *d = &app_; | ||
946 | const iInt2 size = rootSize_Window(d->window); | ||
947 | return size.x > size.y; | ||
948 | } | ||
949 | |||
950 | enum iAppDeviceType deviceType_App(void) { | ||
951 | #if defined (iPlatformAppleMobile) | ||
952 | return isPhone_iOS() ? phone_AppDeviceType : tablet_AppDeviceType; | ||
953 | #else | ||
954 | return desktop_AppDeviceType; | ||
955 | #endif | ||
956 | } | ||
957 | |||
944 | iGmCerts *certs_App(void) { | 958 | iGmCerts *certs_App(void) { |
945 | return app_.certs; | 959 | return app_.certs; |
946 | } | 960 | } |
@@ -38,6 +38,12 @@ iDeclareType(MimeHooks) | |||
38 | iDeclareType(Visited) | 38 | iDeclareType(Visited) |
39 | iDeclareType(Window) | 39 | iDeclareType(Window) |
40 | 40 | ||
41 | enum iAppDeviceType { | ||
42 | desktop_AppDeviceType, | ||
43 | tablet_AppDeviceType, | ||
44 | phone_AppDeviceType, | ||
45 | }; | ||
46 | |||
41 | enum iAppEventMode { | 47 | enum iAppEventMode { |
42 | waitForNewEvents_AppEventMode, | 48 | waitForNewEvents_AppEventMode, |
43 | postedEventsOnly_AppEventMode, | 49 | postedEventsOnly_AppEventMode, |
@@ -61,6 +67,9 @@ void refresh_App (void); | |||
61 | iBool isRefreshPending_App (void); | 67 | iBool isRefreshPending_App (void); |
62 | uint32_t elapsedSinceLastTicker_App (void); /* milliseconds */ | 68 | uint32_t elapsedSinceLastTicker_App (void); /* milliseconds */ |
63 | 69 | ||
70 | iBool isLandscape_App (void); | ||
71 | iLocalDef iBool isPortrait_App (void) { return !isLandscape_App(); } | ||
72 | enum iAppDeviceType deviceType_App (void); | ||
64 | iGmCerts * certs_App (void); | 73 | iGmCerts * certs_App (void); |
65 | iVisited * visited_App (void); | 74 | iVisited * visited_App (void); |
66 | iBookmarks * bookmarks_App (void); | 75 | iBookmarks * bookmarks_App (void); |
@@ -28,4 +28,6 @@ iDeclareType(Window) | |||
28 | 28 | ||
29 | void setupApplication_iOS (void); | 29 | void setupApplication_iOS (void); |
30 | void setupWindow_iOS (iWindow *window); | 30 | void setupWindow_iOS (iWindow *window); |
31 | iBool isPhone_iOS (void); | ||
32 | void safeAreaInsets_iOS (float *left, float *top, float *right, float *bottom); | ||
31 | iBool processEvent_iOS (const SDL_Event *); | 33 | iBool processEvent_iOS (const SDL_Event *); |
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
29 | #import <UIKit/UIKit.h> | 29 | #import <UIKit/UIKit.h> |
30 | 30 | ||
31 | static iBool isSystemDarkMode_ = iFalse; | 31 | static iBool isSystemDarkMode_ = iFalse; |
32 | static iBool isPhone_ = iFalse; | ||
32 | 33 | ||
33 | static void enableMouse_(iBool yes) { | 34 | static void enableMouse_(iBool yes) { |
34 | SDL_EventState(SDL_MOUSEBUTTONDOWN, yes); | 35 | SDL_EventState(SDL_MOUSEBUTTONDOWN, yes); |
@@ -38,6 +39,10 @@ static void enableMouse_(iBool yes) { | |||
38 | 39 | ||
39 | void setupApplication_iOS(void) { | 40 | void setupApplication_iOS(void) { |
40 | enableMouse_(iFalse); | 41 | enableMouse_(iFalse); |
42 | NSString *deviceModel = [[UIDevice currentDevice] model]; | ||
43 | if ([deviceModel isEqualToString:@"iPhone"]) { | ||
44 | isPhone_ = iTrue; | ||
45 | } | ||
41 | } | 46 | } |
42 | 47 | ||
43 | static UIViewController *viewController_(iWindow *window) { | 48 | static UIViewController *viewController_(iWindow *window) { |
@@ -61,7 +66,27 @@ static iBool isDarkMode_(iWindow *window) { | |||
61 | return iFalse; | 66 | return iFalse; |
62 | } | 67 | } |
63 | 68 | ||
69 | void safeAreaInsets_iOS(float *left, float *top, float *right, float *bottom) { | ||
70 | iWindow *window = get_Window(); | ||
71 | UIViewController *ctl = viewController_(window); | ||
72 | if (@available(iOS 11.0, *)) { | ||
73 | const UIEdgeInsets safe = ctl.view.safeAreaInsets; | ||
74 | *left = safe.left * window->pixelRatio; | ||
75 | *top = safe.top * window->pixelRatio; | ||
76 | *right = safe.right * window->pixelRatio; | ||
77 | *bottom = safe.bottom * window->pixelRatio; | ||
78 | } else { | ||
79 | // Fallback on earlier versions | ||
80 | *left = *top = *right = *bottom = 0.0f; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | iBool isPhone_iOS(void) { | ||
85 | return isPhone_; | ||
86 | } | ||
87 | |||
64 | void setupWindow_iOS(iWindow *window) { | 88 | void setupWindow_iOS(iWindow *window) { |
89 | UIViewController *ctl = viewController_(window); | ||
65 | isSystemDarkMode_ = isDarkMode_(window); | 90 | isSystemDarkMode_ = isDarkMode_(window); |
66 | postCommandf_App("~os.theme.changed dark:%d contrast:1", isSystemDarkMode_ ? 1 : 0); | 91 | postCommandf_App("~os.theme.changed dark:%d contrast:1", isSystemDarkMode_ ? 1 : 0); |
67 | } | 92 | } |
diff --git a/src/prefs.c b/src/prefs.c index 9d89f2f5..056ae267 100644 --- a/src/prefs.c +++ b/src/prefs.c | |||
@@ -52,6 +52,9 @@ void init_Prefs(iPrefs *d) { | |||
52 | init_String(&d->httpProxy); | 52 | init_String(&d->httpProxy); |
53 | init_String(&d->downloadDir); | 53 | init_String(&d->downloadDir); |
54 | init_String(&d->searchUrl); | 54 | init_String(&d->searchUrl); |
55 | #if defined (iPlatformAppleMobile) | ||
56 | d->hoverLink = iFalse; | ||
57 | #endif | ||
55 | } | 58 | } |
56 | 59 | ||
57 | void deinit_Prefs(iPrefs *d) { | 60 | void deinit_Prefs(iPrefs *d) { |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 40d83cec..cb075c49 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1701,6 +1701,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1701 | iWidget *sizer = new_Widget(); | 1701 | iWidget *sizer = new_Widget(); |
1702 | setSize_Widget(sizer, init_I2(gap_UI * 90, 1)); | 1702 | setSize_Widget(sizer, init_I2(gap_UI * 90, 1)); |
1703 | addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag); | 1703 | addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag); |
1704 | setFlags_Widget(dlg, centerHorizontal_WidgetFlag, iFalse); | ||
1705 | setPos_Widget(dlg, bottomLeft_Rect(bounds_Widget(findWidget_App("navbar.lock")))); | ||
1704 | arrange_Widget(dlg); | 1706 | arrange_Widget(dlg); |
1705 | addAction_Widget(dlg, SDLK_ESCAPE, 0, "message.ok"); | 1707 | addAction_Widget(dlg, SDLK_ESCAPE, 0, "message.ok"); |
1706 | addAction_Widget(dlg, SDLK_SPACE, 0, "message.ok"); | 1708 | addAction_Widget(dlg, SDLK_SPACE, 0, "message.ok"); |
@@ -2350,16 +2352,20 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2350 | } | 2352 | } |
2351 | } | 2353 | } |
2352 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 2354 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
2355 | /* TODO: Maybe clean this up a bit? Wheel events are used for scrolling | ||
2356 | but they are calculated differently based on device/mouse/trackpad. */ | ||
2353 | const iInt2 mouseCoord = mouseCoord_Window(get_Window()); | 2357 | const iInt2 mouseCoord = mouseCoord_Window(get_Window()); |
2354 | #if defined (iPlatformApple) | 2358 | #if defined (iPlatformApple) |
2355 | /* On macOS, we handle both trackpad and mouse events. We expect SDL to identify | 2359 | /* On macOS, we handle both trackpad and mouse events. We expect SDL to identify |
2356 | which device is sending the event. */ | 2360 | which device is sending the event. */ |
2357 | if (ev->wheel.which == 0) { /* Trackpad with precise scrolling w/inertia. */ | 2361 | if (ev->wheel.which == 0) { /* Trackpad with precise scrolling w/inertia. */ |
2358 | stop_Anim(&d->scrollY); | 2362 | stop_Anim(&d->scrollY); |
2359 | iInt2 wheel = mulf_I2(init_I2(ev->wheel.x, ev->wheel.y), get_Window()->pixelRatio); | 2363 | iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); |
2360 | #if defined (iPlatformAppleMobile) | 2364 | # if defined (iPlatformAppleMobile) |
2361 | wheel.x = -wheel.x; | 2365 | wheel.x = -wheel.x; |
2362 | #else | 2366 | # else |
2367 | /* Wheel mounts are in points. */ | ||
2368 | mulfv_I2(&wheel, get_Window()->pixelRatio); | ||
2363 | /* Only scroll on one axis at a time. */ | 2369 | /* Only scroll on one axis at a time. */ |
2364 | if (iAbs(wheel.x) > iAbs(wheel.y)) { | 2370 | if (iAbs(wheel.x) > iAbs(wheel.y)) { |
2365 | wheel.y = 0; | 2371 | wheel.y = 0; |
@@ -2367,7 +2373,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2367 | else { | 2373 | else { |
2368 | wheel.x = 0; | 2374 | wheel.x = 0; |
2369 | } | 2375 | } |
2370 | #endif | 2376 | # endif |
2371 | scroll_DocumentWidget_(d, -wheel.y); | 2377 | scroll_DocumentWidget_(d, -wheel.y); |
2372 | scrollWideBlock_DocumentWidget_(d, mouseCoord, wheel.x, 0); | 2378 | scrollWideBlock_DocumentWidget_(d, mouseCoord, wheel.x, 0); |
2373 | } | 2379 | } |
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index b27107df..2130400c 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c | |||
@@ -292,12 +292,16 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) { | |||
292 | setHoverItem_ListWidget_(d, hover); | 292 | setHoverItem_ListWidget_(d, hover); |
293 | } | 293 | } |
294 | if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 294 | if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
295 | int amount = -ev->wheel.y; | ||
295 | #if defined (iPlatformApple) | 296 | #if defined (iPlatformApple) |
296 | /* Momentum scrolling. */ | 297 | # if defined (iPlatformAppleDesktop) |
297 | scrollOffset_ListWidget(d, -ev->wheel.y * get_Window()->pixelRatio); | 298 | /* Momentum scrolling (in points). */ |
299 | amount *= get_Window()->pixelRatio; | ||
300 | # endif | ||
298 | #else | 301 | #else |
299 | scrollOffset_ListWidget(d, -ev->wheel.y * 3 * d->itemHeight); | 302 | amount *= 3 * d->itemHeight; |
300 | #endif | 303 | #endif |
304 | scrollOffset_ListWidget(d, amount); | ||
301 | return iTrue; | 305 | return iTrue; |
302 | } | 306 | } |
303 | switch (processEvent_Click(&d->click, ev)) { | 307 | switch (processEvent_Click(&d->click, ev)) { |
diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index ab0a009a..7d6052e2 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c | |||
@@ -629,9 +629,6 @@ static iBool moveCursor_LookupWidget_(iLookupWidget *d, int delta) { | |||
629 | static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { | 629 | static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { |
630 | iWidget *w = as_Widget(d); | 630 | iWidget *w = as_Widget(d); |
631 | const char *cmd = command_UserEvent(ev); | 631 | const char *cmd = command_UserEvent(ev); |
632 | // if (ev->type == SDL_MOUSEMOTION && contains_Widget(w, init_I2(ev->motion.x, ev->motion.y))) { | ||
633 | // setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); | ||
634 | // } | ||
635 | if (isCommand_Widget(w, ev, "lookup.ready")) { | 632 | if (isCommand_Widget(w, ev, "lookup.ready")) { |
636 | /* Take the results and present them in the list. */ | 633 | /* Take the results and present them in the list. */ |
637 | presentResults_LookupWidget_(d); | 634 | presentResults_LookupWidget_(d); |
@@ -640,17 +637,23 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { | |||
640 | if (isResize_UserEvent(ev) || (equal_Command(cmd, "layout.changed") && | 637 | if (isResize_UserEvent(ev) || (equal_Command(cmd, "layout.changed") && |
641 | equal_Rangecc(range_Command(cmd, "id"), "navbar"))) { | 638 | equal_Rangecc(range_Command(cmd, "id"), "navbar"))) { |
642 | /* Position the lookup popup under the URL bar. */ { | 639 | /* Position the lookup popup under the URL bar. */ { |
640 | const iWindow *window = get_Window(); | ||
641 | const iInt2 rootSize = rootSize_Window(window); | ||
642 | const iRect navBarBounds = bounds_Widget(findWidget_App("navbar")); | ||
643 | setSize_Widget(w, init_I2(width_Widget(findWidget_App("url")), | 643 | setSize_Widget(w, init_I2(width_Widget(findWidget_App("url")), |
644 | get_Window()->root->rect.size.y / 2)); | 644 | (rootSize.y - bottom_Rect(navBarBounds)) / 2)); |
645 | setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url")))); | ||
645 | #if defined (iPlatformAppleMobile) | 646 | #if defined (iPlatformAppleMobile) |
646 | /* TODO: Ask the system how tall the keyboard is. */ { | 647 | /* TODO: Ask the system how tall the keyboard is. */ { |
647 | const iInt2 rootSize = rootSize_Window(get_Window()); | 648 | if (isLandscape_App()) { |
648 | if (rootSize.x > rootSize.y) { | ||
649 | w->rect.size.y = rootSize.y * 4 / 10; | 649 | w->rect.size.y = rootSize.y * 4 / 10; |
650 | } | 650 | } |
651 | else if (deviceType_App() == phone_AppDeviceType) { | ||
652 | w->rect.size.x = rootSize.x; | ||
653 | w->rect.pos.x = 0; | ||
654 | } | ||
651 | } | 655 | } |
652 | #endif | 656 | #endif |
653 | setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url")))); | ||
654 | arrange_Widget(w); | 657 | arrange_Widget(w); |
655 | } | 658 | } |
656 | updateVisible_ListWidget(d->list); | 659 | updateVisible_ListWidget(d->list); |
diff --git a/src/ui/touch.c b/src/ui/touch.c index d7d2bca1..8c39793e 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -50,7 +50,7 @@ struct Impl_Touch { | |||
50 | iFloat3 startPos; | 50 | iFloat3 startPos; |
51 | uint32_t posTime[numHistory_Touch_]; | 51 | uint32_t posTime[numHistory_Touch_]; |
52 | iFloat3 pos[numHistory_Touch_]; | 52 | iFloat3 pos[numHistory_Touch_]; |
53 | iFloat3 remainder; | 53 | iFloat3 accum; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | iLocalDef void pushPos_Touch_(iTouch *d, const iFloat3 pos, uint32_t time) { | 56 | iLocalDef void pushPos_Touch_(iTouch *d, const iFloat3 pos, uint32_t time) { |
@@ -103,7 +103,7 @@ static iBool isStationary_Touch_(const iTouch *d) { | |||
103 | } | 103 | } |
104 | 104 | ||
105 | static void dispatchClick_Touch_(const iTouch *d, int button) { | 105 | static void dispatchClick_Touch_(const iTouch *d, int button) { |
106 | const iFloat3 tapPos = d->pos[0]; //divf_F3(add_F3(d->pos[0], d->startPos), 2); | 106 | const iFloat3 tapPos = d->pos[0]; |
107 | SDL_MouseButtonEvent btn = { | 107 | SDL_MouseButtonEvent btn = { |
108 | .type = SDL_MOUSEBUTTONDOWN, | 108 | .type = SDL_MOUSEBUTTONDOWN, |
109 | .button = button, | 109 | .button = button, |
@@ -151,13 +151,14 @@ static void update_TouchState_(void *ptr) { | |||
151 | } | 151 | } |
152 | /* Update/cancel momentum scrolling. */ { | 152 | /* Update/cancel momentum scrolling. */ { |
153 | const float minSpeed = 15.0f; | 153 | const float minSpeed = 15.0f; |
154 | const float momFriction = 0.98f; /* per step */ | 154 | const float momFriction = 0.985f; /* per step */ |
155 | const float stepDurationMs = 1000.0f / 120.0f; | 155 | const float stepDurationMs = 1000.0f / 120.0f; |
156 | double momAvailMs = nowTime - d->lastMomTime; | 156 | double momAvailMs = nowTime - d->lastMomTime; |
157 | int numSteps = (int) (momAvailMs / stepDurationMs); | 157 | int numSteps = (int) (momAvailMs / stepDurationMs); |
158 | d->lastMomTime += numSteps * stepDurationMs; | 158 | d->lastMomTime += numSteps * stepDurationMs; |
159 | numSteps = iMin(numSteps, 10); /* don't spend too much time here */ | 159 | numSteps = iMin(numSteps, 10); /* don't spend too much time here */ |
160 | // printf("mom steps:%d\n", numSteps); | 160 | // printf("mom steps:%d\n", numSteps); |
161 | iWindow *window = get_Window(); | ||
161 | iForEach(Array, m, d->moms) { | 162 | iForEach(Array, m, d->moms) { |
162 | if (numSteps == 0) break; | 163 | if (numSteps == 0) break; |
163 | iMomentum *mom = m.value; | 164 | iMomentum *mom = m.value; |
@@ -165,15 +166,15 @@ static void update_TouchState_(void *ptr) { | |||
165 | mulvf_F3(&mom->velocity, momFriction); | 166 | mulvf_F3(&mom->velocity, momFriction); |
166 | addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f)); | 167 | addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f)); |
167 | } | 168 | } |
168 | const iInt2 pixels = initF3_I2(mom->accum); | 169 | const iInt2 points = initF3_I2(mom->accum); |
169 | if (pixels.x || pixels.y) { | 170 | if (points.x || points.y) { |
170 | subv_F3(&mom->accum, initI2_F3(pixels)); | 171 | subv_F3(&mom->accum, initI2_F3(points)); |
171 | dispatchEvent_Widget(mom->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ | 172 | dispatchEvent_Widget(mom->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ |
172 | .type = SDL_MOUSEWHEEL, | 173 | .type = SDL_MOUSEWHEEL, |
173 | .timestamp = nowTime, | 174 | .timestamp = nowTime, |
174 | .which = 0, /* means "precise scrolling" in DocumentWidget */ | 175 | .which = 0, /* means "precise scrolling" in DocumentWidget */ |
175 | .x = pixels.x, | 176 | .x = points.x, |
176 | .y = pixels.y | 177 | .y = points.y |
177 | }); | 178 | }); |
178 | } | 179 | } |
179 | if (length_F3(mom->velocity) < minSpeed) { | 180 | if (length_F3(mom->velocity) < minSpeed) { |
@@ -187,6 +188,17 @@ static void update_TouchState_(void *ptr) { | |||
187 | } | 188 | } |
188 | } | 189 | } |
189 | 190 | ||
191 | static void dispatchMotion_Touch_(iFloat3 pos, int buttonState) { | ||
192 | dispatchEvent_Widget(get_Window()->root, (SDL_Event *) &(SDL_MouseMotionEvent){ | ||
193 | .type = SDL_MOUSEMOTION, | ||
194 | .timestamp = SDL_GetTicks(), | ||
195 | .which = SDL_TOUCH_MOUSEID, | ||
196 | .state = buttonState, | ||
197 | .x = x_F3(pos), | ||
198 | .y = y_F3(pos) | ||
199 | }); | ||
200 | } | ||
201 | |||
190 | static void dispatchButtonUp_Touch_(iFloat3 pos) { | 202 | static void dispatchButtonUp_Touch_(iFloat3 pos) { |
191 | dispatchEvent_Widget(get_Window()->root, (SDL_Event *) &(SDL_MouseButtonEvent){ | 203 | dispatchEvent_Widget(get_Window()->root, (SDL_Event *) &(SDL_MouseButtonEvent){ |
192 | .type = SDL_MOUSEBUTTONUP, | 204 | .type = SDL_MOUSEBUTTONUP, |
@@ -206,12 +218,10 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
206 | return iFalse; | 218 | return iFalse; |
207 | } | 219 | } |
208 | iTouchState *d = touchState_(); | 220 | iTouchState *d = touchState_(); |
209 | const SDL_TouchFingerEvent *fing = &ev->tfinger; | ||
210 | iWindow *window = get_Window(); | 221 | iWindow *window = get_Window(); |
211 | const iInt2 rootSize = rootSize_Window(window); | 222 | const iInt2 rootSize = rootSize_Window(window); |
212 | const iFloat3 pos = init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0); | 223 | const SDL_TouchFingerEvent *fing = &ev->tfinger; |
213 | //printf("%2d: %f: touch %f, %f\n", ev->type, z_F3(pos), x_F3(pos), y_F3(pos)); | 224 | const iFloat3 pos = init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0); /* pixels */ |
214 | //fflush(stdout); | ||
215 | const uint32_t nowTime = SDL_GetTicks(); | 225 | const uint32_t nowTime = SDL_GetTicks(); |
216 | if (ev->type == SDL_FINGERDOWN) { | 226 | if (ev->type == SDL_FINGERDOWN) { |
217 | /* Register the new touch. */ | 227 | /* Register the new touch. */ |
@@ -225,6 +235,9 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
225 | edge = right_TouchEdge; | 235 | edge = right_TouchEdge; |
226 | } | 236 | } |
227 | iWidget *aff = hitChild_Widget(window->root, init_I2(iRound(x), iRound(y_F3(pos)))); | 237 | iWidget *aff = hitChild_Widget(window->root, init_I2(iRound(x), iRound(y_F3(pos)))); |
238 | /* TODO: We must retain a reference to the affinity widget, or otherwise it might | ||
239 | be destroyed during the gesture. */ | ||
240 | // printf("aff:%p (%s)\n", aff, aff ? class_Widget(aff)->name : "-"); | ||
228 | if (flags_Widget(aff) & touchDrag_WidgetFlag) { | 241 | if (flags_Widget(aff) & touchDrag_WidgetFlag) { |
229 | dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseButtonEvent){ | 242 | dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseButtonEvent){ |
230 | .type = SDL_MOUSEBUTTONDOWN, | 243 | .type = SDL_MOUSEBUTTONDOWN, |
@@ -248,46 +261,24 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
248 | .pos = pos | 261 | .pos = pos |
249 | }); | 262 | }); |
250 | /* Some widgets rely on hover state. */ | 263 | /* Some widgets rely on hover state. */ |
251 | dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseMotionEvent){ | 264 | dispatchMotion_Touch_(pos, 0); |
252 | .type = SDL_MOUSEMOTION, | ||
253 | .timestamp = fing->timestamp, | ||
254 | .which = SDL_TOUCH_MOUSEID, | ||
255 | .x = x_F3(pos), | ||
256 | .y = y_F3(pos) | ||
257 | }); | ||
258 | addTicker_App(update_TouchState_, d); | 265 | addTicker_App(update_TouchState_, d); |
259 | } | 266 | } |
260 | else if (ev->type == SDL_FINGERMOTION) { | 267 | else if (ev->type == SDL_FINGERMOTION) { |
261 | iTouch *touch = find_TouchState_(d, fing->fingerId); | 268 | iTouch *touch = find_TouchState_(d, fing->fingerId); |
262 | if (touch && touch->affinity) { | 269 | if (touch && touch->affinity) { |
263 | if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { | 270 | if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { |
264 | dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseMotionEvent){ | 271 | dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK); |
265 | .type = SDL_MOUSEMOTION, | ||
266 | .timestamp = fing->timestamp, | ||
267 | .which = SDL_TOUCH_MOUSEID, | ||
268 | .state = SDL_BUTTON_LMASK, | ||
269 | .x = x_F3(pos), | ||
270 | .y = y_F3(pos) | ||
271 | }); | ||
272 | return iTrue; | 272 | return iTrue; |
273 | } | 273 | } |
274 | /*dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseMotionEvent){ | ||
275 | .type = SDL_MOUSEMOTION, | ||
276 | .timestamp = fing->timestamp, | ||
277 | .which = SDL_TOUCH_MOUSEID, | ||
278 | .x = x_F3(pos), | ||
279 | .y = y_F3(pos) | ||
280 | });*/ | ||
281 | /* Update touch position. */ | 274 | /* Update touch position. */ |
282 | pushPos_Touch_(touch, pos, nowTime); | 275 | pushPos_Touch_(touch, pos, nowTime); |
283 | const iFloat3 amount = add_F3(touch->remainder, | 276 | const iFloat3 amount = mul_F3(init_F3(fing->dx, fing->dy, 0), |
284 | divf_F3(mul_F3(init_F3(fing->dx, fing->dy, 0), | 277 | init_F3(rootSize.x, rootSize.y, 0)); |
285 | init_F3(rootSize.x, rootSize.y, 0)), | 278 | addv_F3(&touch->accum, amount); |
286 | window->pixelRatio)); | 279 | iInt2 pixels = initF3_I2(touch->accum); |
287 | iInt2 pixels = init_I2(iRound(x_F3(amount)), iRound(y_F3(amount))); | ||
288 | /* We're reporting scrolling as full points, so keep track of the precise distance. */ | 280 | /* We're reporting scrolling as full points, so keep track of the precise distance. */ |
289 | iFloat3 remainder = sub_F3(amount, initI2_F3(pixels)); | 281 | subv_F3(&touch->accum, initI2_F3(pixels)); |
290 | touch->remainder = remainder; | ||
291 | if (!touch->hasMoved && !isStationary_Touch_(touch)) { | 282 | if (!touch->hasMoved && !isStationary_Touch_(touch)) { |
292 | touch->hasMoved = iTrue; | 283 | touch->hasMoved = iTrue; |
293 | } | 284 | } |
@@ -301,15 +292,17 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
301 | if (touch->edge) { | 292 | if (touch->edge) { |
302 | pixels.y = 0; | 293 | pixels.y = 0; |
303 | } | 294 | } |
295 | // printf("%p (%s) py: %i wy: %f acc: %f\n", | ||
296 | // touch->affinity, | ||
297 | // class_Widget(touch->affinity)->name, | ||
298 | // pixels.y, y_F3(amount), y_F3(touch->accum)); | ||
304 | if (pixels.x || pixels.y) { | 299 | if (pixels.x || pixels.y) { |
305 | // printf("%p (%s) wy: %f\n", touch->affinity, class_Widget(touch->affinity)->name, | ||
306 | // fing->dy * rootSize.y / window->pixelRatio); | ||
307 | dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ | 300 | dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ |
308 | .type = SDL_MOUSEWHEEL, | 301 | .type = SDL_MOUSEWHEEL, |
309 | .timestamp = SDL_GetTicks(), | 302 | .timestamp = SDL_GetTicks(), |
310 | .which = 0, /* means "precise scrolling" in DocumentWidget */ | 303 | .which = 0, /* means "precise scrolling" in DocumentWidget */ |
311 | .x = pixels.x, | 304 | .x = pixels.x, |
312 | .y = pixels.y | 305 | .y = pixels.y, |
313 | }); | 306 | }); |
314 | /* TODO: Keep increasing movement if the direction is the same. */ | 307 | /* TODO: Keep increasing movement if the direction is the same. */ |
315 | clearWidgetMomentum_TouchState_(d, touch->affinity); | 308 | clearWidgetMomentum_TouchState_(d, touch->affinity); |
@@ -340,7 +333,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
340 | else { | 333 | else { |
341 | const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex_Touch_]; | 334 | const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex_Touch_]; |
342 | const float minVelocity = 400.0f; | 335 | const float minVelocity = 400.0f; |
343 | if (elapsed < 40) { | 336 | if (elapsed < 75) { |
344 | velocity = divf_F3(sub_F3(pos, touch->pos[lastIndex_Touch_]), | 337 | velocity = divf_F3(sub_F3(pos, touch->pos[lastIndex_Touch_]), |
345 | (float) elapsed / 1000.0f); | 338 | (float) elapsed / 1000.0f); |
346 | if (fabsf(x_F3(velocity)) < minVelocity) { | 339 | if (fabsf(x_F3(velocity)) < minVelocity) { |
@@ -350,9 +343,11 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
350 | setY_F3(&velocity, 0.0f); | 343 | setY_F3(&velocity, 0.0f); |
351 | } | 344 | } |
352 | } | 345 | } |
346 | // printf("elap:%ums vel:%f\n", elapsed, length_F3(velocity)); | ||
353 | pushPos_Touch_(touch, pos, nowTime); | 347 | pushPos_Touch_(touch, pos, nowTime); |
354 | /* If short and didn't move far, do a tap (left click). */ | 348 | /* If short and didn't move far, do a tap (left click). */ |
355 | if (duration < longPressSpanMs_ && isStationary_Touch_(touch)) { | 349 | if (duration < longPressSpanMs_ && isStationary_Touch_(touch)) { |
350 | dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK); | ||
356 | dispatchClick_Touch_(touch, SDL_BUTTON_LEFT); | 351 | dispatchClick_Touch_(touch, SDL_BUTTON_LEFT); |
357 | } | 352 | } |
358 | else if (length_F3(velocity) > 0.0f) { | 353 | else if (length_F3(velocity) > 0.0f) { |
diff --git a/src/ui/util.c b/src/ui/util.c index 850ca818..1ff1b7f7 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -37,6 +37,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
37 | #include "text.h" | 37 | #include "text.h" |
38 | #include "window.h" | 38 | #include "window.h" |
39 | 39 | ||
40 | #if defined (iPlatformAppleMobile) | ||
41 | # include "../ios.h" | ||
42 | #endif | ||
43 | |||
40 | #include <the_Foundation/math.h> | 44 | #include <the_Foundation/math.h> |
41 | #include <the_Foundation/path.h> | 45 | #include <the_Foundation/path.h> |
42 | #include <SDL_timer.h> | 46 | #include <SDL_timer.h> |
@@ -472,13 +476,19 @@ void openMenu_Widget(iWidget *d, iInt2 coord) { | |||
472 | } | 476 | } |
473 | #endif | 477 | #endif |
474 | const iRect bounds = bounds_Widget(d); | 478 | const iRect bounds = bounds_Widget(d); |
475 | const int leftExcess = -left_Rect(bounds); | 479 | int leftExcess = -left_Rect(bounds); |
476 | const int rightExcess = right_Rect(bounds) - rootSize.x; | 480 | int rightExcess = right_Rect(bounds) - rootSize.x; |
477 | int topExcess = -top_Rect(bounds); | 481 | int topExcess = -top_Rect(bounds); |
478 | const int bottomExcess = bottom_Rect(bounds) - rootSize.y; | 482 | int bottomExcess = bottom_Rect(bounds) - rootSize.y; |
479 | #if defined (iPlatformAppleMobile) | 483 | #if defined (iPlatformAppleMobile) |
480 | /* Reserve space for the system status bar. */ | 484 | /* Reserve space for the system status bar. */ { |
481 | topExcess += 4.5 * gap_UI; | 485 | float l, t, r, b; |
486 | safeAreaInsets_iOS(&l, &t, &r, &b); | ||
487 | topExcess += t; | ||
488 | bottomExcess += b; | ||
489 | leftExcess += l; | ||
490 | rightExcess += r; | ||
491 | } | ||
482 | #endif | 492 | #endif |
483 | if (bottomExcess > 0) { | 493 | if (bottomExcess > 0) { |
484 | d->rect.pos.y -= bottomExcess; | 494 | d->rect.pos.y -= bottomExcess; |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 331192f9..128aa39c 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -126,11 +126,15 @@ const iString *id_Widget(const iWidget *d) { | |||
126 | } | 126 | } |
127 | 127 | ||
128 | int64_t flags_Widget(const iWidget *d) { | 128 | int64_t flags_Widget(const iWidget *d) { |
129 | return d->flags; | 129 | return d ? d->flags : 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | void setFlags_Widget(iWidget *d, int64_t flags, iBool set) { | 132 | void setFlags_Widget(iWidget *d, int64_t flags, iBool set) { |
133 | if (d) { | 133 | if (d) { |
134 | if (deviceType_App() == phone_AppDeviceType) { | ||
135 | /* Phones rarely have keyboards attached so don't bother with the shortcuts. */ | ||
136 | flags &= ~drawKey_WidgetFlag; | ||
137 | } | ||
134 | iChangeFlags(d->flags, flags, set); | 138 | iChangeFlags(d->flags, flags, set); |
135 | if (flags & keepOnTop_WidgetFlag) { | 139 | if (flags & keepOnTop_WidgetFlag) { |
136 | if (set) { | 140 | if (set) { |
@@ -731,7 +735,7 @@ size_t childIndex_Widget(const iWidget *d, const iAnyObject *child) { | |||
731 | } | 735 | } |
732 | 736 | ||
733 | iAny *hitChild_Widget(const iWidget *d, iInt2 coord) { | 737 | iAny *hitChild_Widget(const iWidget *d, iInt2 coord) { |
734 | if (d->flags & unhittable_WidgetFlag) { | 738 | if (d->flags & (unhittable_WidgetFlag | hidden_WidgetFlag)) { |
735 | return NULL; | 739 | return NULL; |
736 | } | 740 | } |
737 | /* Check for on-top widgets first. */ | 741 | /* Check for on-top widgets first. */ |
diff --git a/src/ui/window.c b/src/ui/window.c index 38df8682..251eb5c4 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -398,9 +398,21 @@ static void checkLoadAnimation_Window_(iWindow *d) { | |||
398 | setReloadLabel_Window_(d, isOngoing); | 398 | setReloadLabel_Window_(d, isOngoing); |
399 | } | 399 | } |
400 | 400 | ||
401 | static void updatePadding_Window_(iWindow *d) { | ||
402 | #if defined (iPlatformAppleMobile) | ||
403 | /* Respect the safe area insets. */ { | ||
404 | float left, top, right, bottom; | ||
405 | safeAreaInsets_iOS(&left, &top, &right, &bottom); | ||
406 | setPadding_Widget(findChild_Widget(d->root, "navdiv"), left, top, right, 0); | ||
407 | setPadding_Widget(findChild_Widget(d->root, "toolbar"), left, 0, right, bottom); | ||
408 | } | ||
409 | #endif | ||
410 | } | ||
411 | |||
401 | static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | 412 | static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { |
402 | if (equal_Command(cmd, "window.resized")) { | 413 | if (equal_Command(cmd, "window.resized")) { |
403 | const iBool isNarrow = width_Rect(bounds_Widget(navBar)) / gap_UI < 140; | 414 | const iBool isPhone = deviceType_App() == phone_AppDeviceType; |
415 | const iBool isNarrow = !isPhone && width_Rect(bounds_Widget(navBar)) / gap_UI < 140; | ||
404 | if (isNarrow ^ ((flags_Widget(navBar) & tight_WidgetFlag) != 0)) { | 416 | if (isNarrow ^ ((flags_Widget(navBar) & tight_WidgetFlag) != 0)) { |
405 | setFlags_Widget(navBar, tight_WidgetFlag, isNarrow); | 417 | setFlags_Widget(navBar, tight_WidgetFlag, isNarrow); |
406 | iForEach(ObjectList, i, navBar->children) { | 418 | iForEach(ObjectList, i, navBar->children) { |
@@ -413,6 +425,14 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | |||
413 | } | 425 | } |
414 | } | 426 | } |
415 | } | 427 | } |
428 | if (isPhone) { | ||
429 | setFlags_Widget(findWidget_App("toolbar"), hidden_WidgetFlag, isLandscape_App()); | ||
430 | setFlags_Widget(findWidget_App("navbar.back"), hidden_WidgetFlag, isPortrait_App()); | ||
431 | setFlags_Widget(findWidget_App("navbar.forward"), hidden_WidgetFlag, isPortrait_App()); | ||
432 | setFlags_Widget(findWidget_App("navbar.ident"), hidden_WidgetFlag, isPortrait_App()); | ||
433 | setFlags_Widget(findWidget_App("navbar.home"), hidden_WidgetFlag, isPortrait_App()); | ||
434 | setFlags_Widget(findWidget_App("navbar.menu"), hidden_WidgetFlag, isPortrait_App()); | ||
435 | } | ||
416 | arrange_Widget(navBar); | 436 | arrange_Widget(navBar); |
417 | refresh_Widget(navBar); | 437 | refresh_Widget(navBar); |
418 | postCommand_Widget(navBar, "layout.changed id:navbar"); | 438 | postCommand_Widget(navBar, "layout.changed id:navbar"); |
@@ -592,11 +612,6 @@ static void setupUserInterface_Window(iWindow *d) { | |||
592 | setId_Widget(div, "navdiv"); | 612 | setId_Widget(div, "navdiv"); |
593 | addChild_Widget(d->root, iClob(div)); | 613 | addChild_Widget(d->root, iClob(div)); |
594 | 614 | ||
595 | #if defined (iPlatformAppleMobile) | ||
596 | /* System status bar needs space. */ | ||
597 | setPadding_Widget(div, 0, 4 * gap_UI, 0, 0); | ||
598 | #endif | ||
599 | |||
600 | #if defined (LAGRANGE_CUSTOM_FRAME) | 615 | #if defined (LAGRANGE_CUSTOM_FRAME) |
601 | /* Window title bar. */ | 616 | /* Window title bar. */ |
602 | if (prefs_App()->customFrame) { | 617 | if (prefs_App()->customFrame) { |
@@ -662,13 +677,12 @@ static void setupUserInterface_Window(iWindow *d) { | |||
662 | addChild_Widget(div, iClob(navBar)); | 677 | addChild_Widget(div, iClob(navBar)); |
663 | setBackgroundColor_Widget(navBar, uiBackground_ColorId); | 678 | setBackgroundColor_Widget(navBar, uiBackground_ColorId); |
664 | setCommandHandler_Widget(navBar, handleNavBarCommands_); | 679 | setCommandHandler_Widget(navBar, handleNavBarCommands_); |
665 | addChild_Widget(navBar, iClob(newIcon_LabelWidget("\U0001f870", 0, 0, "navigate.back"))); | 680 | setId_Widget(addChildFlags_Widget(navBar, iClob(newIcon_LabelWidget("\U0001f870", 0, 0, "navigate.back")), collapse_WidgetFlag), "navbar.back"); |
666 | addChild_Widget(navBar, iClob(newIcon_LabelWidget("\U0001f872", 0, 0, "navigate.forward"))); | 681 | setId_Widget(addChildFlags_Widget(navBar, iClob(newIcon_LabelWidget("\U0001f872", 0, 0, "navigate.forward")), collapse_WidgetFlag), "navbar.forward"); |
667 | iLabelWidget *idMenu = makeMenuButton_LabelWidget( | 682 | iLabelWidget *idMenu = makeMenuButton_LabelWidget( |
668 | "\U0001f464", identityButtonMenuItems_, iElemCount(identityButtonMenuItems_)); | 683 | "\U0001f464", identityButtonMenuItems_, iElemCount(identityButtonMenuItems_)); |
669 | setAlignVisually_LabelWidget(idMenu, iTrue); | 684 | setAlignVisually_LabelWidget(idMenu, iTrue); |
670 | addChild_Widget(navBar, iClob(idMenu)); | 685 | setId_Widget(addChildFlags_Widget(navBar, iClob(idMenu), collapse_WidgetFlag), "navbar.ident"); |
671 | setId_Widget(as_Widget(idMenu), "navbar.ident"); | ||
672 | iLabelWidget *lock = | 686 | iLabelWidget *lock = |
673 | addChildFlags_Widget(navBar, | 687 | addChildFlags_Widget(navBar, |
674 | iClob(newIcon_LabelWidget("\U0001f513", SDLK_i, KMOD_PRIMARY, "document.info")), | 688 | iClob(newIcon_LabelWidget("\U0001f513", SDLK_i, KMOD_PRIMARY, "document.info")), |
@@ -711,14 +725,16 @@ static void setupUserInterface_Window(iWindow *d) { | |||
711 | setId_Widget(addChild_Widget( | 725 | setId_Widget(addChild_Widget( |
712 | navBar, iClob(newIcon_LabelWidget(reloadCStr_, 0, 0, "navigate.reload"))), | 726 | navBar, iClob(newIcon_LabelWidget(reloadCStr_, 0, 0, "navigate.reload"))), |
713 | "reload"); | 727 | "reload"); |
714 | addChild_Widget(navBar, | 728 | setId_Widget(addChildFlags_Widget(navBar, |
715 | iClob(newIcon_LabelWidget( | 729 | iClob(newIcon_LabelWidget( |
716 | "\U0001f3e0", SDLK_h, KMOD_PRIMARY | KMOD_SHIFT, "navigate.home"))); | 730 | "\U0001f3e0", SDLK_h, KMOD_PRIMARY | KMOD_SHIFT, "navigate.home")), |
731 | collapse_WidgetFlag), | ||
732 | "navbar.home"); | ||
717 | #if !defined (iHaveNativeMenus) | 733 | #if !defined (iHaveNativeMenus) |
718 | iLabelWidget *navMenu = | 734 | iLabelWidget *navMenu = |
719 | makeMenuButton_LabelWidget("\U0001d362", navMenuItems_, iElemCount(navMenuItems_)); | 735 | makeMenuButton_LabelWidget("\U0001d362", navMenuItems_, iElemCount(navMenuItems_)); |
720 | setAlignVisually_LabelWidget(navMenu, iTrue); | 736 | setAlignVisually_LabelWidget(navMenu, iTrue); |
721 | addChild_Widget(navBar, iClob(navMenu)); | 737 | setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu"); |
722 | #else | 738 | #else |
723 | insertMenuItems_MacOS("File", 1, fileMenuItems_, iElemCount(fileMenuItems_)); | 739 | insertMenuItems_MacOS("File", 1, fileMenuItems_, iElemCount(fileMenuItems_)); |
724 | insertMenuItems_MacOS("Edit", 2, editMenuItems_, iElemCount(editMenuItems_)); | 740 | insertMenuItems_MacOS("Edit", 2, editMenuItems_, iElemCount(editMenuItems_)); |
@@ -773,6 +789,24 @@ static void setupUserInterface_Window(iWindow *d) { | |||
773 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9d ", 'g', KMOD_PRIMARY | KMOD_SHIFT, "find.prev"))); | 789 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9d ", 'g', KMOD_PRIMARY | KMOD_SHIFT, "find.prev"))); |
774 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget("\u2a2f", SDLK_ESCAPE, 0, "find.close"))); | 790 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget("\u2a2f", SDLK_ESCAPE, 0, "find.close"))); |
775 | } | 791 | } |
792 | #if defined (iPlatformAppleMobile) | ||
793 | /* Bottom toolbar. */ | ||
794 | if (isPhone_iOS()) { | ||
795 | iWidget *toolBar = new_Widget(); | ||
796 | addChild_Widget(div, iClob(toolBar)); | ||
797 | setId_Widget(toolBar, "toolbar"); | ||
798 | setFlags_Widget(toolBar, collapse_WidgetFlag | resizeWidthOfChildren_WidgetFlag | | ||
799 | arrangeHeight_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue); | ||
800 | setBackgroundColor_Widget(toolBar, uiBackground_ColorId); | ||
801 | addChildFlags_Widget(toolBar, iClob(newLargeIcon_LabelWidget("\U0001f870", "navigate.back")), frameless_WidgetFlag); | ||
802 | addChildFlags_Widget(toolBar, iClob(newLargeIcon_LabelWidget("\U0001f872", "navigate.forward")), frameless_WidgetFlag); | ||
803 | addChildFlags_Widget(toolBar, iClob(newLargeIcon_LabelWidget("\U0001f464", "sidebar.mode arg:3 show:1")), frameless_WidgetFlag); | ||
804 | iLabelWidget *menuButton = makeMenuButton_LabelWidget("\U0001d362", navMenuItems_, iElemCount(navMenuItems_)); | ||
805 | setFont_LabelWidget(menuButton, uiLabelLarge_FontId); | ||
806 | addChildFlags_Widget(toolBar, iClob(menuButton), frameless_WidgetFlag); | ||
807 | } | ||
808 | #endif | ||
809 | updatePadding_Window_(d); | ||
776 | iWidget *tabsMenu = makeMenu_Widget(d->root, | 810 | iWidget *tabsMenu = makeMenu_Widget(d->root, |
777 | (iMenuItem[]){ | 811 | (iMenuItem[]){ |
778 | { "Close Tab", 0, 0, "tabs.close" }, | 812 | { "Close Tab", 0, 0, "tabs.close" }, |
@@ -1195,6 +1229,7 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { | |||
1195 | return iTrue; | 1229 | return iTrue; |
1196 | } | 1230 | } |
1197 | case SDL_WINDOWEVENT_RESIZED: | 1231 | case SDL_WINDOWEVENT_RESIZED: |
1232 | updatePadding_Window_(d); | ||
1198 | if (d->isMinimized) { | 1233 | if (d->isMinimized) { |
1199 | updateRootSize_Window_(d, iTrue); | 1234 | updateRootSize_Window_(d, iTrue); |
1200 | return iTrue; | 1235 | return iTrue; |
@@ -1353,7 +1388,7 @@ void draw_Window(iWindow *d) { | |||
1353 | /* Clear the window. The clear color is visible as a border around the window | 1388 | /* Clear the window. The clear color is visible as a border around the window |
1354 | when the custom frame is being used. */ { | 1389 | when the custom frame is being used. */ { |
1355 | #if defined (iPlatformAppleMobile) | 1390 | #if defined (iPlatformAppleMobile) |
1356 | const iColor back = get_Color(uiBackground_ColorId); | 1391 | const iColor back = get_Color(tmBackground_ColorId); |
1357 | #else | 1392 | #else |
1358 | const iColor back = get_Color(gotFocus && d->place.snap != maximized_WindowSnap && | 1393 | const iColor back = get_Color(gotFocus && d->place.snap != maximized_WindowSnap && |
1359 | ~winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP | 1394 | ~winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP |