summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app.c5
-rw-r--r--src/ios.h5
-rw-r--r--src/ios.m47
-rw-r--r--src/ui/documentwidget.c11
-rw-r--r--src/ui/inputwidget.c3
-rw-r--r--src/ui/labelwidget.c21
-rw-r--r--src/ui/lookupwidget.c11
-rw-r--r--src/ui/sidebarwidget.c3
-rw-r--r--src/ui/text.c33
-rw-r--r--src/ui/touch.c34
-rw-r--r--src/ui/util.c15
-rw-r--r--src/ui/widget.c16
-rw-r--r--src/ui/window.c18
13 files changed, 184 insertions, 38 deletions
diff --git a/src/app.c b/src/app.c
index ae0633e5..3307d8dd 100644
--- a/src/app.c
+++ b/src/app.c
@@ -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;
diff --git a/src/ios.h b/src/ios.h
index 09c514b0..90570e20 100644
--- a/src/ios.h
+++ b/src/ios.h
@@ -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
27void setupApplication_iOS (void); 27iDeclareType(Window)
28 28
29void setupApplication_iOS (void);
30void setupWindow_iOS (iWindow *window);
31iBool processEvent_iOS (const SDL_Event *);
diff --git a/src/ios.m b/src/ios.m
index 37f62b09..aca3bf0a 100644
--- a/src/ios.m
+++ b/src/ios.m
@@ -21,8 +21,14 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 21SOFTWARE, 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
31static iBool isSystemDarkMode_ = iFalse;
26 32
27static void enableMouse_(iBool yes) { 33static 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) {
33void setupApplication_iOS(void) { 39void setupApplication_iOS(void) {
34 enableMouse_(iFalse); 40 enableMouse_(iFalse);
35} 41}
42
43static 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
53static 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
64void setupWindow_iOS(iWindow *window) {
65 isSystemDarkMode_ = isDarkMode_(window);
66 postCommandf_App("~os.theme.changed dark:%d contrast:1", isSystemDarkMode_ ? 1 : 0);
67}
68
69iBool 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
766static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { 766static 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
775static 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
31iLocalDef iInt2 padding_(int flags) { 31iLocalDef 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
35struct Impl_LabelWidget { 39struct 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
261void updateSize_LabelWidget(iLabelWidget *d) { 278void 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
190static 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
190iBool processEvent_Touch(const SDL_Event *ev) { 203iBool 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 }