diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-19 13:15:08 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-19 13:15:08 +0200 |
commit | 7a0980fd58308f7333254a1276e6dd5072326d98 (patch) | |
tree | 8431dfd498762a90944bb5e595f61ea2af914a81 | |
parent | 63dc07ddbecfdf0be7c0bd98c53e492628dda98b (diff) |
iOS: Adjusting the UI for a tablet screen
-rw-r--r-- | src/app.c | 5 | ||||
-rw-r--r-- | src/ios.h | 5 | ||||
-rw-r--r-- | src/ios.m | 47 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 11 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 3 | ||||
-rw-r--r-- | src/ui/labelwidget.c | 21 | ||||
-rw-r--r-- | src/ui/lookupwidget.c | 11 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 3 | ||||
-rw-r--r-- | src/ui/text.c | 33 | ||||
-rw-r--r-- | src/ui/touch.c | 34 | ||||
-rw-r--r-- | src/ui/util.c | 15 | ||||
-rw-r--r-- | src/ui/widget.c | 16 | ||||
-rw-r--r-- | src/ui/window.c | 18 |
13 files changed, 184 insertions, 38 deletions
@@ -617,6 +617,11 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
617 | SDL_WaitEvent(&ev)) || | 617 | SDL_WaitEvent(&ev)) || |
618 | ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) && | 618 | ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) && |
619 | SDL_PollEvent(&ev))) { | 619 | SDL_PollEvent(&ev))) { |
620 | #if defined (iPlatformAppleMobile) | ||
621 | if (processEvent_iOS(&ev)) { | ||
622 | continue; | ||
623 | } | ||
624 | #endif | ||
620 | switch (ev.type) { | 625 | switch (ev.type) { |
621 | case SDL_QUIT: | 626 | case SDL_QUIT: |
622 | d->isRunning = iFalse; | 627 | d->isRunning = iFalse; |
@@ -24,5 +24,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
24 | 24 | ||
25 | #include "ui/util.h" | 25 | #include "ui/util.h" |
26 | 26 | ||
27 | void setupApplication_iOS (void); | 27 | iDeclareType(Window) |
28 | 28 | ||
29 | void setupApplication_iOS (void); | ||
30 | void setupWindow_iOS (iWindow *window); | ||
31 | iBool processEvent_iOS (const SDL_Event *); | ||
@@ -21,8 +21,14 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
22 | 22 | ||
23 | #include "ios.h" | 23 | #include "ios.h" |
24 | 24 | #include "app.h" | |
25 | #include "ui/window.h" | ||
25 | #include <SDL_events.h> | 26 | #include <SDL_events.h> |
27 | #include <SDL_syswm.h> | ||
28 | |||
29 | #import <UIKit/UIKit.h> | ||
30 | |||
31 | static iBool isSystemDarkMode_ = iFalse; | ||
26 | 32 | ||
27 | static void enableMouse_(iBool yes) { | 33 | static void enableMouse_(iBool yes) { |
28 | SDL_EventState(SDL_MOUSEBUTTONDOWN, yes); | 34 | SDL_EventState(SDL_MOUSEBUTTONDOWN, yes); |
@@ -33,3 +39,42 @@ static void enableMouse_(iBool yes) { | |||
33 | void setupApplication_iOS(void) { | 39 | void setupApplication_iOS(void) { |
34 | enableMouse_(iFalse); | 40 | enableMouse_(iFalse); |
35 | } | 41 | } |
42 | |||
43 | static UIViewController *viewController_(iWindow *window) { | ||
44 | SDL_SysWMinfo wm; | ||
45 | SDL_VERSION(&wm.version); | ||
46 | if (SDL_GetWindowWMInfo(window->win, &wm)) { | ||
47 | return wm.info.uikit.window.rootViewController; | ||
48 | } | ||
49 | iAssert(false); | ||
50 | return NULL; | ||
51 | } | ||
52 | |||
53 | static iBool isDarkMode_(iWindow *window) { | ||
54 | UIViewController *ctl = viewController_(window); | ||
55 | if (ctl) { | ||
56 | UITraitCollection *traits = ctl.traitCollection; | ||
57 | if (@available(iOS 12.0, *)) { | ||
58 | return (traits.userInterfaceStyle == UIUserInterfaceStyleDark); | ||
59 | } | ||
60 | } | ||
61 | return iFalse; | ||
62 | } | ||
63 | |||
64 | void setupWindow_iOS(iWindow *window) { | ||
65 | isSystemDarkMode_ = isDarkMode_(window); | ||
66 | postCommandf_App("~os.theme.changed dark:%d contrast:1", isSystemDarkMode_ ? 1 : 0); | ||
67 | } | ||
68 | |||
69 | iBool processEvent_iOS(const SDL_Event *ev) { | ||
70 | if (ev->type == SDL_WINDOWEVENT) { | ||
71 | if (ev->window.event == SDL_WINDOWEVENT_RESTORED) { | ||
72 | const iBool isDark = isDarkMode_(get_Window()); | ||
73 | if (isDark != isSystemDarkMode_) { | ||
74 | isSystemDarkMode_ = isDark; | ||
75 | postCommandf_App("~os.theme.changed dark:%d contrast:1", isSystemDarkMode_ ? 1 : 0); | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | return iFalse; /* allow normal processing */ | ||
80 | } | ||
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 9619c56e..40d83cec 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -763,15 +763,19 @@ static void updateOutline_DocumentWidget_(iDocumentWidget *d) { | |||
763 | } | 763 | } |
764 | } | 764 | } |
765 | 765 | ||
766 | static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { | 766 | static void documentRunsInvalidated_DocumentWidget_(iDocumentWidget *d) { |
767 | setUrl_GmDocument(d->doc, d->mod.url); | ||
768 | setSource_GmDocument(d->doc, source, documentWidth_DocumentWidget_(d)); | ||
769 | d->foundMark = iNullRange; | 767 | d->foundMark = iNullRange; |
770 | d->selectMark = iNullRange; | 768 | d->selectMark = iNullRange; |
771 | d->hoverLink = NULL; | 769 | d->hoverLink = NULL; |
772 | d->contextLink = NULL; | 770 | d->contextLink = NULL; |
773 | d->firstVisibleRun = NULL; | 771 | d->firstVisibleRun = NULL; |
774 | d->lastVisibleRun = NULL; | 772 | d->lastVisibleRun = NULL; |
773 | } | ||
774 | |||
775 | static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { | ||
776 | setUrl_GmDocument(d->doc, d->mod.url); | ||
777 | setSource_GmDocument(d->doc, source, documentWidth_DocumentWidget_(d)); | ||
778 | documentRunsInvalidated_DocumentWidget_(d); | ||
775 | setValue_Anim(&d->outlineOpacity, 0.0f, 0); | 779 | setValue_Anim(&d->outlineOpacity, 0.0f, 0); |
776 | updateWindowTitle_DocumentWidget_(d); | 780 | updateWindowTitle_DocumentWidget_(d); |
777 | updateVisible_DocumentWidget_(d); | 781 | updateVisible_DocumentWidget_(d); |
@@ -1563,6 +1567,7 @@ static void updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocument | |||
1563 | voffset = visibleRange_DocumentWidget_(d).start - top_Rect(run->visBounds); | 1567 | voffset = visibleRange_DocumentWidget_(d).start - top_Rect(run->visBounds); |
1564 | } | 1568 | } |
1565 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); | 1569 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); |
1570 | documentRunsInvalidated_DocumentWidget_(d); | ||
1566 | if (runLoc && !keepCenter) { | 1571 | if (runLoc && !keepCenter) { |
1567 | run = findRunAtLoc_GmDocument(d->doc, runLoc); | 1572 | run = findRunAtLoc_GmDocument(d->doc, runLoc); |
1568 | if (run) { | 1573 | if (run) { |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 2f0fa064..9b36b057 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -121,6 +121,9 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) { | |||
121 | setMaxLen_InputWidget(d, maxLen); | 121 | setMaxLen_InputWidget(d, maxLen); |
122 | /* Caller must arrange the width, but the height is fixed. */ | 122 | /* Caller must arrange the width, but the height is fixed. */ |
123 | w->rect.size.y = lineHeight_Text(default_FontId) + 2 * gap_UI; | 123 | w->rect.size.y = lineHeight_Text(default_FontId) + 2 * gap_UI; |
124 | #if defined (iPlatformAppleMobile) | ||
125 | w->rect.size.y += 2 * gap_UI; | ||
126 | #endif | ||
124 | setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); | 127 | setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); |
125 | init_Click(&d->click, d, SDL_BUTTON_LEFT); | 128 | init_Click(&d->click, d, SDL_BUTTON_LEFT); |
126 | d->timer = 0; | 129 | d->timer = 0; |
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index d7e6c020..a0664433 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c | |||
@@ -28,8 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
28 | #include "util.h" | 28 | #include "util.h" |
29 | #include "keys.h" | 29 | #include "keys.h" |
30 | 30 | ||
31 | iLocalDef iInt2 padding_(int flags) { | 31 | iLocalDef iInt2 padding_(int64_t flags) { |
32 | #if defined (iPlatformAppleMobile) | ||
33 | return init_I2(flags & tight_WidgetFlag ? 4 * gap_UI / 2 : (4 * gap_UI), 3 * gap_UI / 2); | ||
34 | #else | ||
32 | return init_I2(flags & tight_WidgetFlag ? 3 * gap_UI / 2 : (3 * gap_UI), gap_UI); | 35 | return init_I2(flags & tight_WidgetFlag ? 3 * gap_UI / 2 : (3 * gap_UI), gap_UI); |
36 | #endif | ||
33 | } | 37 | } |
34 | 38 | ||
35 | struct Impl_LabelWidget { | 39 | struct Impl_LabelWidget { |
@@ -83,6 +87,19 @@ static iBool processEvent_LabelWidget_(iLabelWidget *d, const SDL_Event *ev) { | |||
83 | return iFalse; | 87 | return iFalse; |
84 | } | 88 | } |
85 | if (!isEmpty_String(&d->command)) { | 89 | if (!isEmpty_String(&d->command)) { |
90 | #if 0 && defined (iPlatformAppleMobile) | ||
91 | /* Touch allows activating any button on release. */ | ||
92 | switch (ev->type) { | ||
93 | case SDL_MOUSEBUTTONUP: { | ||
94 | const iInt2 mouse = init_I2(ev->button.x, ev->button.y); | ||
95 | if (contains_Widget(w, mouse)) { | ||
96 | trigger_LabelWidget_(d); | ||
97 | refresh_Widget(w); | ||
98 | } | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | #endif | ||
86 | switch (processEvent_Click(&d->click, ev)) { | 103 | switch (processEvent_Click(&d->click, ev)) { |
87 | case started_ClickResult: | 104 | case started_ClickResult: |
88 | setFlags_Widget(w, pressed_WidgetFlag, iTrue); | 105 | setFlags_Widget(w, pressed_WidgetFlag, iTrue); |
@@ -260,7 +277,7 @@ static void sizeChanged_LabelWidget_(iLabelWidget *d) { | |||
260 | 277 | ||
261 | void updateSize_LabelWidget(iLabelWidget *d) { | 278 | void updateSize_LabelWidget(iLabelWidget *d) { |
262 | iWidget *w = as_Widget(d); | 279 | iWidget *w = as_Widget(d); |
263 | const int flags = flags_Widget(w); | 280 | const int64_t flags = flags_Widget(w); |
264 | iInt2 size = add_I2(measure_Text(d->font, cstr_String(&d->label)), muli_I2(padding_(flags), 2)); | 281 | iInt2 size = add_I2(measure_Text(d->font, cstr_String(&d->label)), muli_I2(padding_(flags), 2)); |
265 | if ((flags & drawKey_WidgetFlag) && d->key) { | 282 | if ((flags & drawKey_WidgetFlag) && d->key) { |
266 | iString str; | 283 | iString str; |
diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index 123ac6c4..ab0a009a 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c | |||
@@ -377,6 +377,9 @@ void init_LookupWidget(iLookupWidget *d) { | |||
377 | init_Widget(w); | 377 | init_Widget(w); |
378 | setId_Widget(w, "lookup"); | 378 | setId_Widget(w, "lookup"); |
379 | setFlags_Widget(w, focusable_WidgetFlag | resizeChildren_WidgetFlag, iTrue); | 379 | setFlags_Widget(w, focusable_WidgetFlag | resizeChildren_WidgetFlag, iTrue); |
380 | #if defined (iPlatformAppleMobile) | ||
381 | setFlags_Widget(w, unhittable_WidgetFlag, iTrue); | ||
382 | #endif | ||
380 | d->list = addChild_Widget(w, iClob(new_ListWidget())); | 383 | d->list = addChild_Widget(w, iClob(new_ListWidget())); |
381 | setItemHeight_ListWidget(d->list, lineHeight_Text(uiContent_FontId) * 1.25f); | 384 | setItemHeight_ListWidget(d->list, lineHeight_Text(uiContent_FontId) * 1.25f); |
382 | d->cursor = iInvalidPos; | 385 | d->cursor = iInvalidPos; |
@@ -639,6 +642,14 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { | |||
639 | /* Position the lookup popup under the URL bar. */ { | 642 | /* Position the lookup popup under the URL bar. */ { |
640 | setSize_Widget(w, init_I2(width_Widget(findWidget_App("url")), | 643 | setSize_Widget(w, init_I2(width_Widget(findWidget_App("url")), |
641 | get_Window()->root->rect.size.y / 2)); | 644 | get_Window()->root->rect.size.y / 2)); |
645 | #if defined (iPlatformAppleMobile) | ||
646 | /* TODO: Ask the system how tall the keyboard is. */ { | ||
647 | const iInt2 rootSize = rootSize_Window(get_Window()); | ||
648 | if (rootSize.x > rootSize.y) { | ||
649 | w->rect.size.y = rootSize.y * 4 / 10; | ||
650 | } | ||
651 | } | ||
652 | #endif | ||
642 | setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url")))); | 653 | setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url")))); |
643 | arrange_Widget(w); | 654 | arrange_Widget(w); |
644 | } | 655 | } |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 32727703..5c6285fb 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -466,6 +466,9 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
466 | d->side = side; | 466 | d->side = side; |
467 | d->mode = -1; | 467 | d->mode = -1; |
468 | d->width = 60 * gap_UI; | 468 | d->width = 60 * gap_UI; |
469 | #if defined (iPlatformAppleMobile) | ||
470 | d->width = 73 * gap_UI; | ||
471 | #endif | ||
469 | setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue); | 472 | setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue); |
470 | d->maxButtonLabelWidth = 0; | 473 | d->maxButtonLabelWidth = 0; |
471 | iWidget *vdiv = makeVDiv_Widget(); | 474 | iWidget *vdiv = makeVDiv_Widget(); |
diff --git a/src/ui/text.c b/src/ui/text.c index 7bb65bdc..e300e7c4 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -246,18 +246,23 @@ static void initFonts_Text_(iText *d) { | |||
246 | h12Font = &fontLiterataBoldopsz36_Embedded; | 246 | h12Font = &fontLiterataBoldopsz36_Embedded; |
247 | h3Font = &fontLiterataRegularopsz14_Embedded; | 247 | h3Font = &fontLiterataRegularopsz14_Embedded; |
248 | } | 248 | } |
249 | #if defined (iPlatformAppleMobile) | ||
250 | const float uiSize = fontSize_UI * 1.1f; | ||
251 | #else | ||
252 | const float uiSize = fontSize_UI; | ||
253 | #endif | ||
249 | const struct { | 254 | const struct { |
250 | const iBlock *ttf; | 255 | const iBlock *ttf; |
251 | int size; | 256 | int size; |
252 | float scaling; | 257 | float scaling; |
253 | int symbolsFont; | 258 | int symbolsFont; |
254 | } fontData[max_FontId] = { | 259 | } fontData[max_FontId] = { |
255 | { &fontSourceSansProRegular_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 260 | { &fontSourceSansProRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, |
256 | { &fontSourceSansProBold_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 261 | { &fontSourceSansProBold_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, |
257 | { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 262 | { &fontSourceSansProRegular_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, |
258 | { &fontSourceSansProBold_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 263 | { &fontSourceSansProBold_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, |
259 | { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 264 | { &fontSourceSansProRegular_Embedded, uiSize * 1.666f, 1.0f, defaultLargeSymbols_FontId }, |
260 | { &fontIosevkaTermExtended_Embedded, fontSize_UI * 0.866f, 1.0f, defaultSymbols_FontId }, | 265 | { &fontIosevkaTermExtended_Embedded, uiSize * 0.866f, 1.0f, defaultSymbols_FontId }, |
261 | { &fontSourceSansProRegular_Embedded, textSize, scaling, symbols_FontId }, | 266 | { &fontSourceSansProRegular_Embedded, textSize, scaling, symbols_FontId }, |
262 | /* content fonts */ | 267 | /* content fonts */ |
263 | { regularFont, textSize, scaling, symbols_FontId }, | 268 | { regularFont, textSize, scaling, symbols_FontId }, |
@@ -272,9 +277,9 @@ static void initFonts_Text_(iText *d) { | |||
272 | /* monospace content fonts */ | 277 | /* monospace content fonts */ |
273 | { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, symbols_FontId }, | 278 | { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, symbols_FontId }, |
274 | /* symbol fonts */ | 279 | /* symbol fonts */ |
275 | { &fontSymbola_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 280 | { &fontSymbola_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, |
276 | { &fontSymbola_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 281 | { &fontSymbola_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, |
277 | { &fontSymbola_Embedded, fontSize_UI * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 282 | { &fontSymbola_Embedded, uiSize * 1.666f, 1.0f, defaultLargeSymbols_FontId }, |
278 | { &fontSymbola_Embedded, textSize, 1.0f, symbols_FontId }, | 283 | { &fontSymbola_Embedded, textSize, 1.0f, symbols_FontId }, |
279 | { &fontSymbola_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, | 284 | { &fontSymbola_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, |
280 | { &fontSymbola_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, | 285 | { &fontSymbola_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, |
@@ -283,9 +288,9 @@ static void initFonts_Text_(iText *d) { | |||
283 | { &fontSymbola_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | 288 | { &fontSymbola_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, |
284 | { &fontSymbola_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | 289 | { &fontSymbola_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, |
285 | /* emoji fonts */ | 290 | /* emoji fonts */ |
286 | { &fontNotoEmojiRegular_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 291 | { &fontNotoEmojiRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, |
287 | { &fontNotoEmojiRegular_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 292 | { &fontNotoEmojiRegular_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, |
288 | { &fontNotoEmojiRegular_Embedded, fontSize_UI * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 293 | { &fontNotoEmojiRegular_Embedded, uiSize * 1.666f, 1.0f, defaultLargeSymbols_FontId }, |
289 | { &fontNotoEmojiRegular_Embedded, textSize, 1.0f, symbols_FontId }, | 294 | { &fontNotoEmojiRegular_Embedded, textSize, 1.0f, symbols_FontId }, |
290 | { &fontNotoEmojiRegular_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, | 295 | { &fontNotoEmojiRegular_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, |
291 | { &fontNotoEmojiRegular_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, | 296 | { &fontNotoEmojiRegular_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, |
@@ -294,7 +299,7 @@ static void initFonts_Text_(iText *d) { | |||
294 | { &fontNotoEmojiRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | 299 | { &fontNotoEmojiRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, |
295 | { &fontNotoEmojiRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | 300 | { &fontNotoEmojiRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, |
296 | /* japanese fonts */ | 301 | /* japanese fonts */ |
297 | { &fontNotoSansJPRegular_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 302 | { &fontNotoSansJPRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, |
298 | { &fontNotoSansJPRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | 303 | { &fontNotoSansJPRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, |
299 | { &fontNotoSansJPRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | 304 | { &fontNotoSansJPRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, |
300 | { &fontNotoSansJPRegular_Embedded, textSize, 1.0f, symbols_FontId }, | 305 | { &fontNotoSansJPRegular_Embedded, textSize, 1.0f, symbols_FontId }, |
@@ -303,7 +308,7 @@ static void initFonts_Text_(iText *d) { | |||
303 | { &fontNotoSansJPRegular_Embedded, textSize * 1.666f, 1.0f, largeSymbols_FontId }, | 308 | { &fontNotoSansJPRegular_Embedded, textSize * 1.666f, 1.0f, largeSymbols_FontId }, |
304 | { &fontNotoSansJPRegular_Embedded, textSize * 2.000f, 1.0f, hugeSymbols_FontId }, | 309 | { &fontNotoSansJPRegular_Embedded, textSize * 2.000f, 1.0f, hugeSymbols_FontId }, |
305 | /* korean fonts */ | 310 | /* korean fonts */ |
306 | { &fontNanumGothicRegular_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 311 | { &fontNanumGothicRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, |
307 | { &fontNanumGothicRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | 312 | { &fontNanumGothicRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, |
308 | { &fontNanumGothicRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | 313 | { &fontNanumGothicRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, |
309 | { &fontNanumGothicRegular_Embedded, textSize, 1.0f, symbols_FontId }, | 314 | { &fontNanumGothicRegular_Embedded, textSize, 1.0f, symbols_FontId }, |
diff --git a/src/ui/touch.c b/src/ui/touch.c index 9b47d0fe..d7d2bca1 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -187,6 +187,19 @@ static void update_TouchState_(void *ptr) { | |||
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
190 | static void dispatchButtonUp_Touch_(iFloat3 pos) { | ||
191 | dispatchEvent_Widget(get_Window()->root, (SDL_Event *) &(SDL_MouseButtonEvent){ | ||
192 | .type = SDL_MOUSEBUTTONUP, | ||
193 | .timestamp = SDL_GetTicks(), | ||
194 | .clicks = 1, | ||
195 | .state = SDL_RELEASED, | ||
196 | .which = SDL_TOUCH_MOUSEID, | ||
197 | .button = SDL_BUTTON_LEFT, | ||
198 | .x = x_F3(pos), | ||
199 | .y = y_F3(pos) | ||
200 | }); | ||
201 | } | ||
202 | |||
190 | iBool processEvent_Touch(const SDL_Event *ev) { | 203 | iBool processEvent_Touch(const SDL_Event *ev) { |
191 | /* We only handle finger events here. */ | 204 | /* We only handle finger events here. */ |
192 | if (ev->type != SDL_FINGERDOWN && ev->type != SDL_FINGERMOTION && ev->type != SDL_FINGERUP) { | 205 | if (ev->type != SDL_FINGERDOWN && ev->type != SDL_FINGERMOTION && ev->type != SDL_FINGERUP) { |
@@ -258,6 +271,13 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
258 | }); | 271 | }); |
259 | return iTrue; | 272 | return iTrue; |
260 | } | 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 | });*/ | ||
261 | /* Update touch position. */ | 281 | /* Update touch position. */ |
262 | pushPos_Touch_(touch, pos, nowTime); | 282 | pushPos_Touch_(touch, pos, nowTime); |
263 | const iFloat3 amount = add_F3(touch->remainder, | 283 | const iFloat3 amount = add_F3(touch->remainder, |
@@ -304,16 +324,7 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
304 | continue; | 324 | continue; |
305 | } | 325 | } |
306 | if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { | 326 | if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { |
307 | dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseButtonEvent){ | 327 | dispatchButtonUp_Touch_(pos); |
308 | .type = SDL_MOUSEBUTTONUP, | ||
309 | .timestamp = fing->timestamp, | ||
310 | .clicks = 1, | ||
311 | .state = SDL_RELEASED, | ||
312 | .which = SDL_TOUCH_MOUSEID, | ||
313 | .button = SDL_BUTTON_LEFT, | ||
314 | .x = x_F3(pos), | ||
315 | .y = y_F3(pos) | ||
316 | }); | ||
317 | remove_ArrayIterator(&i); | 328 | remove_ArrayIterator(&i); |
318 | continue; | 329 | continue; |
319 | } | 330 | } |
@@ -357,6 +368,9 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
357 | } | 368 | } |
358 | pushBack_Array(d->moms, &mom); | 369 | pushBack_Array(d->moms, &mom); |
359 | } | 370 | } |
371 | else { | ||
372 | dispatchButtonUp_Touch_(pos); | ||
373 | } | ||
360 | } | 374 | } |
361 | remove_ArrayIterator(&i); | 375 | remove_ArrayIterator(&i); |
362 | } | 376 | } |
diff --git a/src/ui/util.c b/src/ui/util.c index 553d9078..850ca818 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -463,12 +463,23 @@ void openMenu_Widget(iWidget *d, iInt2 coord) { | |||
463 | arrange_Widget(d); | 463 | arrange_Widget(d); |
464 | d->rect.pos = coord; | 464 | d->rect.pos = coord; |
465 | /* Ensure the full menu is visible. */ | 465 | /* Ensure the full menu is visible. */ |
466 | const iInt2 rootSize = rootSize_Window(get_Window()); | 466 | const iInt2 rootSize = rootSize_Window(get_Window()); |
467 | #if defined (iPlatformAppleMobile) | ||
468 | /* Move out from under the user's hand/finger. */ | ||
469 | if (!parentMenuButton_(d)) { | ||
470 | const float normX = (float) left_Rect(bounds_Widget(d)) / rootSize.x; | ||
471 | subv_I2(&d->rect.pos, init_I2(normX * width_Rect(d->rect), height_Rect(d->rect))); | ||
472 | } | ||
473 | #endif | ||
467 | const iRect bounds = bounds_Widget(d); | 474 | const iRect bounds = bounds_Widget(d); |
468 | const int leftExcess = -left_Rect(bounds); | 475 | const int leftExcess = -left_Rect(bounds); |
469 | const int rightExcess = right_Rect(bounds) - rootSize.x; | 476 | const int rightExcess = right_Rect(bounds) - rootSize.x; |
470 | const int topExcess = -top_Rect(bounds); | 477 | int topExcess = -top_Rect(bounds); |
471 | const int bottomExcess = bottom_Rect(bounds) - rootSize.y; | 478 | const int bottomExcess = bottom_Rect(bounds) - rootSize.y; |
479 | #if defined (iPlatformAppleMobile) | ||
480 | /* Reserve space for the system status bar. */ | ||
481 | topExcess += 4.5 * gap_UI; | ||
482 | #endif | ||
472 | if (bottomExcess > 0) { | 483 | if (bottomExcess > 0) { |
473 | d->rect.pos.y -= bottomExcess; | 484 | d->rect.pos.y -= bottomExcess; |
474 | } | 485 | } |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 5afb004f..331192f9 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -734,9 +734,19 @@ iAny *hitChild_Widget(const iWidget *d, iInt2 coord) { | |||
734 | if (d->flags & unhittable_WidgetFlag) { | 734 | if (d->flags & unhittable_WidgetFlag) { |
735 | return NULL; | 735 | return NULL; |
736 | } | 736 | } |
737 | iConstForEach(ObjectList, i, d->children) { | 737 | /* Check for on-top widgets first. */ |
738 | iAny *found = hitChild_Widget(constAs_Widget(i.object), coord); | 738 | if (!d->parent) { |
739 | if (found) return found; | 739 | iForEach(PtrArray, i, onTop_RootData_()) { |
740 | iAny *found = hitChild_Widget(constAs_Widget(i.ptr), coord); | ||
741 | if (found) return found; | ||
742 | } | ||
743 | } | ||
744 | iForEach(ObjectList, i, d->children) { | ||
745 | const iWidget *child = constAs_Widget(i.object); | ||
746 | if (~child->flags & keepOnTop_WidgetFlag) { | ||
747 | iAny *found = hitChild_Widget(child, coord); | ||
748 | if (found) return found; | ||
749 | } | ||
740 | } | 750 | } |
741 | if (contains_Widget(d, coord)) { | 751 | if (contains_Widget(d, coord)) { |
742 | return iConstCast(iWidget *, d); | 752 | return iConstCast(iWidget *, d); |
diff --git a/src/ui/window.c b/src/ui/window.c index d64e7ebf..75dffb56 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -45,6 +45,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
45 | #if defined (iPlatformAppleDesktop) | 45 | #if defined (iPlatformAppleDesktop) |
46 | # include "macos.h" | 46 | # include "macos.h" |
47 | #endif | 47 | #endif |
48 | #if defined (iPlatformAppleMobile) | ||
49 | # include "ios.h" | ||
50 | #endif | ||
48 | 51 | ||
49 | #include <the_Foundation/file.h> | 52 | #include <the_Foundation/file.h> |
50 | #include <the_Foundation/path.h> | 53 | #include <the_Foundation/path.h> |
@@ -562,6 +565,11 @@ static void setupUserInterface_Window(iWindow *d) { | |||
562 | iWidget *div = makeVDiv_Widget(); | 565 | iWidget *div = makeVDiv_Widget(); |
563 | setId_Widget(div, "navdiv"); | 566 | setId_Widget(div, "navdiv"); |
564 | addChild_Widget(d->root, iClob(div)); | 567 | addChild_Widget(d->root, iClob(div)); |
568 | |||
569 | #if defined (iPlatformAppleMobile) | ||
570 | /* System status bar needs space. */ | ||
571 | setPadding_Widget(div, 0, 4 * gap_UI, 0, 0); | ||
572 | #endif | ||
565 | 573 | ||
566 | #if defined (LAGRANGE_CUSTOM_FRAME) | 574 | #if defined (LAGRANGE_CUSTOM_FRAME) |
567 | /* Window title bar. */ | 575 | /* Window title bar. */ |
@@ -650,7 +658,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
650 | setNotifyEdits_InputWidget(url, iTrue); | 658 | setNotifyEdits_InputWidget(url, iTrue); |
651 | setTextCStr_InputWidget(url, "gemini://"); | 659 | setTextCStr_InputWidget(url, "gemini://"); |
652 | addChildFlags_Widget(navBar, iClob(url), expand_WidgetFlag); | 660 | addChildFlags_Widget(navBar, iClob(url), expand_WidgetFlag); |
653 | setPadding_Widget(as_Widget(url),0, 0, gap_UI * 1, 0); | 661 | setPadding_Widget(as_Widget(url), 0, 0, gap_UI * 1, 0); |
654 | /* Feeds refresh indicator is inside the input field. */ { | 662 | /* Feeds refresh indicator is inside the input field. */ { |
655 | iLabelWidget *fprog = new_LabelWidget(uiTextCaution_ColorEscape | 663 | iLabelWidget *fprog = new_LabelWidget(uiTextCaution_ColorEscape |
656 | "\u2605 Refreshing Feeds...", NULL); | 664 | "\u2605 Refreshing Feeds...", NULL); |
@@ -980,6 +988,9 @@ void init_Window(iWindow *d, iRect rect) { | |||
980 | SDL_FreeSurface(surf); | 988 | SDL_FreeSurface(surf); |
981 | } | 989 | } |
982 | #endif | 990 | #endif |
991 | #if defined (iPlatformAppleMobile) | ||
992 | setupWindow_iOS(d); | ||
993 | #endif | ||
983 | d->root = new_Widget(); | 994 | d->root = new_Widget(); |
984 | setFlags_Widget(d->root, focusRoot_WidgetFlag, iTrue); | 995 | setFlags_Widget(d->root, focusRoot_WidgetFlag, iTrue); |
985 | d->presentTime = 0.0; | 996 | d->presentTime = 0.0; |
@@ -1175,7 +1186,6 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { | |||
1175 | //updateRootSize_Window_(d, iTrue); | 1186 | //updateRootSize_Window_(d, iTrue); |
1176 | invalidate_Window_(d); | 1187 | invalidate_Window_(d); |
1177 | d->isMinimized = iFalse; | 1188 | d->isMinimized = iFalse; |
1178 | printf("restored %d\n", snap_Window(d)); fflush(stdout); | ||
1179 | return iTrue; | 1189 | return iTrue; |
1180 | case SDL_WINDOWEVENT_MINIMIZED: | 1190 | case SDL_WINDOWEVENT_MINIMIZED: |
1181 | d->isMinimized = iTrue; | 1191 | d->isMinimized = iTrue; |
@@ -1316,10 +1326,14 @@ void draw_Window(iWindow *d) { | |||
1316 | const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0; | 1326 | const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0; |
1317 | /* Clear the window. The clear color is visible as a border around the window | 1327 | /* Clear the window. The clear color is visible as a border around the window |
1318 | when the custom frame is being used. */ { | 1328 | when the custom frame is being used. */ { |
1329 | #if defined (iPlatformAppleMobile) | ||
1330 | const iColor back = get_Color(uiBackground_ColorId); | ||
1331 | #else | ||
1319 | const iColor back = get_Color(gotFocus && d->place.snap != maximized_WindowSnap && | 1332 | const iColor back = get_Color(gotFocus && d->place.snap != maximized_WindowSnap && |
1320 | ~winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP | 1333 | ~winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP |
1321 | ? uiAnnotation_ColorId | 1334 | ? uiAnnotation_ColorId |
1322 | : uiSeparator_ColorId); | 1335 | : uiSeparator_ColorId); |
1336 | #endif | ||
1323 | SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255); | 1337 | SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255); |
1324 | SDL_RenderClear(d->render); | 1338 | SDL_RenderClear(d->render); |
1325 | } | 1339 | } |