summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/inputwidget.c12
-rw-r--r--src/ui/lookupwidget.c23
-rw-r--r--src/ui/text.c20
-rw-r--r--src/ui/text.h1
-rw-r--r--src/ui/touch.c17
-rw-r--r--src/ui/widget.c16
-rw-r--r--src/ui/widget.h1
-rw-r--r--src/ui/window.c20
-rw-r--r--src/ui/window.h4
9 files changed, 99 insertions, 15 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index 3f178fc5..06bb9474 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -21,6 +21,7 @@ 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 "inputwidget.h" 23#include "inputwidget.h"
24#include "command.h"
24#include "paint.h" 25#include "paint.h"
25#include "util.h" 26#include "util.h"
26#include "keys.h" 27#include "keys.h"
@@ -615,6 +616,17 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
615 } 616 }
616 return iFalse; 617 return iFalse;
617 } 618 }
619 else if (isCommand_UserEvent(ev, "keyboard.changed")) {
620 if (isFocused_Widget(d) && arg_Command(command_UserEvent(ev))) {
621 iRect rect = bounds_Widget(w);
622 rect.pos.y -= value_Anim(&get_Window()->rootOffset);
623 const iInt2 visRoot = visibleRootSize_Window(get_Window());
624 if (bottom_Rect(rect) > visRoot.y) {
625 setValue_Anim(&get_Window()->rootOffset, -(bottom_Rect(rect) - visRoot.y), 250);
626 }
627 }
628 return iFalse;
629 }
618 else if (isMetricsChange_UserEvent(ev)) { 630 else if (isMetricsChange_UserEvent(ev)) {
619 updateMetrics_InputWidget_(d); 631 updateMetrics_InputWidget_(d);
620 } 632 }
diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c
index 10039e10..eabfc7d2 100644
--- a/src/ui/lookupwidget.c
+++ b/src/ui/lookupwidget.c
@@ -36,6 +36,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36#include "util.h" 36#include "util.h"
37#include "visited.h" 37#include "visited.h"
38 38
39#if defined (iPlatformAppleMobile)
40# include "../ios.h"
41#endif
42
39#include <the_Foundation/mutex.h> 43#include <the_Foundation/mutex.h>
40#include <the_Foundation/thread.h> 44#include <the_Foundation/thread.h>
41#include <the_Foundation/regexp.h> 45#include <the_Foundation/regexp.h>
@@ -641,8 +645,9 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) {
641 if (isMetricsChange_UserEvent(ev)) { 645 if (isMetricsChange_UserEvent(ev)) {
642 updateMetrics_LookupWidget_(d); 646 updateMetrics_LookupWidget_(d);
643 } 647 }
644 else if (isResize_UserEvent(ev) || (equal_Command(cmd, "layout.changed") && 648 else if (isResize_UserEvent(ev) || equal_Command(cmd, "keyboard.changed") ||
645 equal_Rangecc(range_Command(cmd, "id"), "navbar"))) { 649 (equal_Command(cmd, "layout.changed") &&
650 equal_Rangecc(range_Command(cmd, "id"), "navbar"))) {
646 /* Position the lookup popup under the URL bar. */ { 651 /* Position the lookup popup under the URL bar. */ {
647 const iWindow *window = get_Window(); 652 const iWindow *window = get_Window();
648 const iInt2 rootSize = rootSize_Window(window); 653 const iInt2 rootSize = rootSize_Window(window);
@@ -651,13 +656,13 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) {
651 (rootSize.y - bottom_Rect(navBarBounds)) / 2)); 656 (rootSize.y - bottom_Rect(navBarBounds)) / 2));
652 setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url")))); 657 setPos_Widget(w, bottomLeft_Rect(bounds_Widget(findWidget_App("url"))));
653#if defined (iPlatformAppleMobile) 658#if defined (iPlatformAppleMobile)
654 /* TODO: Ask the system how tall the keyboard is. */ { 659 /* Adjust height based on keyboard size. */ {
655 if (isLandscape_App()) { 660 w->rect.size.y = visibleRootSize_Window(window).y - top_Rect(bounds_Widget(w));
656 w->rect.size.y = rootSize.y * 4 / 10; 661 if (deviceType_App() == phone_AppDeviceType) {
657 } 662 float l, r;
658 else if (deviceType_App() == phone_AppDeviceType) { 663 safeAreaInsets_iOS(&l, NULL, &r, NULL);
659 w->rect.size.x = rootSize.x; 664 w->rect.size.x = rootSize.x - l - r;
660 w->rect.pos.x = 0; 665 w->rect.pos.x = l;
661 } 666 }
662 } 667 }
663#endif 668#endif
diff --git a/src/ui/text.c b/src/ui/text.c
index d3b8df37..b08bdc60 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -53,6 +53,7 @@ int enableHalfPixelGlyphs_Text = iTrue; /* debug setting */
53int enableKerning_Text = iTrue; /* looking up kern pairs is slow */ 53int enableKerning_Text = iTrue; /* looking up kern pairs is slow */
54 54
55static iBool enableRaster_Text_ = iTrue; 55static iBool enableRaster_Text_ = iTrue;
56static int numPendingRasterization_Text_ = 0;
56 57
57enum iGlyphFlag { 58enum iGlyphFlag {
58 rasterized0_GlyphFlag = iBit(1), /* zero offset */ 59 rasterized0_GlyphFlag = iBit(1), /* zero offset */
@@ -423,6 +424,7 @@ static void initCache_Text_(iText *d) {
423 d->cacheSize.x, 424 d->cacheSize.x,
424 d->cacheSize.y); 425 d->cacheSize.y);
425 SDL_SetTextureBlendMode(d->cache, SDL_BLENDMODE_BLEND); 426 SDL_SetTextureBlendMode(d->cache, SDL_BLENDMODE_BLEND);
427 numPendingRasterization_Text_ = 0;
426} 428}
427 429
428static void deinitCache_Text_(iText *d) { 430static void deinitCache_Text_(iText *d) {
@@ -501,6 +503,10 @@ void resetFonts_Text(void) {
501 initFonts_Text_(d); 503 initFonts_Text_(d);
502} 504}
503 505
506int numPendingGlyphs_Text(void) {
507 return numPendingRasterization_Text_;
508}
509
504iLocalDef iFont *font_Text_(enum iFontId id) { 510iLocalDef iFont *font_Text_(enum iFontId id) {
505 return &text_.fonts[id & mask_FontId]; 511 return &text_.fonts[id & mask_FontId];
506} 512}
@@ -569,7 +575,7 @@ static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) {
569 } 575 }
570} 576}
571 577
572static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) { 578static iBool cache_Font_(iFont *d, iGlyph *glyph, int hoff) {
573 iText * txt = &text_; 579 iText * txt = &text_;
574 SDL_Renderer *render = txt->render; 580 SDL_Renderer *render = txt->render;
575 SDL_Texture * tex = NULL; 581 SDL_Texture * tex = NULL;
@@ -590,6 +596,7 @@ static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) {
590 if (surface) { 596 if (surface) {
591 SDL_FreeSurface(surface); 597 SDL_FreeSurface(surface);
592 } 598 }
599 return isRasterized_Glyph_(glyph, hoff);
593} 600}
594 601
595iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { 602iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
@@ -659,15 +666,22 @@ static const iGlyph *glyph_Font_(iFont *d, iChar ch) {
659 allocate_Font_(font, glyph, 0); 666 allocate_Font_(font, glyph, 0);
660 allocate_Font_(font, glyph, 1); 667 allocate_Font_(font, glyph, 1);
661 insert_Hash(&font->glyphs, &glyph->node); 668 insert_Hash(&font->glyphs, &glyph->node);
669 numPendingRasterization_Text_ += 2;
662 } 670 }
663 if (enableRaster_Text_ && !isFullyRasterized_Glyph_(glyph)) { 671 if (enableRaster_Text_ && !isFullyRasterized_Glyph_(glyph)) {
664 SDL_Texture *oldTarget = SDL_GetRenderTarget(text_.render); 672 SDL_Texture *oldTarget = SDL_GetRenderTarget(text_.render);
665 SDL_SetRenderTarget(text_.render, text_.cache); 673 SDL_SetRenderTarget(text_.render, text_.cache);
666 if (!isRasterized_Glyph_(glyph, 0)) { 674 if (!isRasterized_Glyph_(glyph, 0)) {
667 cache_Font_(font, glyph, 0); 675 if (cache_Font_(font, glyph, 0)) {
676 numPendingRasterization_Text_--;
677 iAssert(numPendingRasterization_Text_ >= 0);
678 }
668 } 679 }
669 if (!isRasterized_Glyph_(glyph, 1)) { 680 if (!isRasterized_Glyph_(glyph, 1)) {
670 cache_Font_(font, glyph, 1); /* half-pixel offset */ 681 if (cache_Font_(font, glyph, 1)) { /* half-pixel offset */
682 numPendingRasterization_Text_--;
683 iAssert(numPendingRasterization_Text_ >= 0);
684 }
671 } 685 }
672 SDL_SetRenderTarget(text_.render, oldTarget); 686 SDL_SetRenderTarget(text_.render, oldTarget);
673 } 687 }
diff --git a/src/ui/text.h b/src/ui/text.h
index f696b2e3..1118882d 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -161,6 +161,7 @@ void setContentFont_Text (enum iTextFont font);
161void setHeadingFont_Text (enum iTextFont font); 161void setHeadingFont_Text (enum iTextFont font);
162void setContentFontSize_Text (float fontSizeFactor); /* affects all except `default*` fonts */ 162void setContentFontSize_Text (float fontSizeFactor); /* affects all except `default*` fonts */
163void resetFonts_Text (void); 163void resetFonts_Text (void);
164int numPendingGlyphs_Text (void);
164 165
165int lineHeight_Text (int fontId); 166int lineHeight_Text (int fontId);
166iInt2 measure_Text (int fontId, const char *text); 167iInt2 measure_Text (int fontId, const char *text);
diff --git a/src/ui/touch.c b/src/ui/touch.c
index 27db0073..f15eda6f 100644
--- a/src/ui/touch.c
+++ b/src/ui/touch.c
@@ -190,6 +190,10 @@ static void update_TouchState_(void *ptr) {
190 iForEach(Array, m, d->moms) { 190 iForEach(Array, m, d->moms) {
191 if (numSteps == 0) break; 191 if (numSteps == 0) break;
192 iMomentum *mom = m.value; 192 iMomentum *mom = m.value;
193 if (!mom->affinity) {
194 remove_ArrayIterator(&m);
195 continue;
196 }
193 for (int step = 0; step < numSteps; step++) { 197 for (int step = 0; step < numSteps; step++) {
194 mulvf_F3(&mom->velocity, momFriction); 198 mulvf_F3(&mom->velocity, momFriction);
195 addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f)); 199 addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f));
@@ -248,8 +252,11 @@ static void dispatchButtonUp_Touch_(iFloat3 pos) {
248static iWidget *findOverflowScrollable_Widget_(iWidget *d) { 252static iWidget *findOverflowScrollable_Widget_(iWidget *d) {
249 const iInt2 rootSize = rootSize_Window(get_Window()); 253 const iInt2 rootSize = rootSize_Window(get_Window());
250 for (iWidget *w = d; w; w = parent_Widget(w)) { 254 for (iWidget *w = d; w; w = parent_Widget(w)) {
251 if (flags_Widget(w) & overflowScrollable_WidgetFlag && height_Widget(w) > rootSize.y) { 255 if (flags_Widget(w) & overflowScrollable_WidgetFlag) {
252 return w; 256 if (height_Widget(w) > rootSize.y && !hasVisibleChildOnTop_Widget(w)) {
257 return w;
258 }
259 return NULL;
253 } 260 }
254 } 261 }
255 return NULL; 262 return NULL;
@@ -262,9 +269,13 @@ iBool processEvent_Touch(const SDL_Event *ev) {
262 } 269 }
263 iTouchState *d = touchState_(); 270 iTouchState *d = touchState_();
264 iWindow *window = get_Window(); 271 iWindow *window = get_Window();
272 if (!isFinished_Anim(&window->rootOffset)) {
273 return iFalse;
274 }
265 const iInt2 rootSize = rootSize_Window(window); 275 const iInt2 rootSize = rootSize_Window(window);
266 const SDL_TouchFingerEvent *fing = &ev->tfinger; 276 const SDL_TouchFingerEvent *fing = &ev->tfinger;
267 const iFloat3 pos = init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0); /* pixels */ 277 const iFloat3 pos = add_F3(init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0), /* pixels */
278 init_F3(0, -value_Anim(&window->rootOffset), 0));
268 const uint32_t nowTime = SDL_GetTicks(); 279 const uint32_t nowTime = SDL_GetTicks();
269 if (ev->type == SDL_FINGERDOWN) { 280 if (ev->type == SDL_FINGERDOWN) {
270 /* Register the new touch. */ 281 /* Register the new touch. */
diff --git a/src/ui/widget.c b/src/ui/widget.c
index c54ea444..2381548a 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -507,6 +507,9 @@ iRect bounds_Widget(const iWidget *d) {
507 } 507 }
508 addv_I2(&bounds.pos, pos); 508 addv_I2(&bounds.pos, pos);
509 } 509 }
510#if defined (iPlatformMobile)
511 bounds.pos.y += value_Anim(&get_Window()->rootOffset);
512#endif
510 return bounds; 513 return bounds;
511} 514}
512 515
@@ -1131,6 +1134,19 @@ static void printTree_Widget_(const iWidget *d, int indent) {
1131 } 1134 }
1132} 1135}
1133 1136
1137iBool hasVisibleChildOnTop_Widget(const iWidget *parent) {
1138 iConstForEach(ObjectList, i, parent->children) {
1139 const iWidget *child = i.object;
1140 if (~child->flags & hidden_WidgetFlag && child->flags & keepOnTop_WidgetFlag) {
1141 return iTrue;
1142 }
1143 if (hasVisibleChildOnTop_Widget(child)) {
1144 return iTrue;
1145 }
1146 }
1147 return iFalse;
1148}
1149
1134void printTree_Widget(const iWidget *d) { 1150void printTree_Widget(const iWidget *d) {
1135 printTree_Widget_(d, 0); 1151 printTree_Widget_(d, 0);
1136} 1152}
diff --git a/src/ui/widget.h b/src/ui/widget.h
index b1ee8c73..602e86cb 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -232,6 +232,7 @@ iWidget *hover_Widget (void);
232void unhover_Widget (void); 232void unhover_Widget (void);
233void setMouseGrab_Widget (iWidget *); 233void setMouseGrab_Widget (iWidget *);
234iWidget *mouseGrab_Widget (void); 234iWidget *mouseGrab_Widget (void);
235iBool hasVisibleChildOnTop_Widget(const iWidget *parent);
235void printTree_Widget (const iWidget *); 236void printTree_Widget (const iWidget *);
236 237
237iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand); 238iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand);
diff --git a/src/ui/window.c b/src/ui/window.c
index bf7214f4..9ff22d35 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -1136,6 +1136,7 @@ static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) {
1136 iInt2 *size = &d->root->rect.size; 1136 iInt2 *size = &d->root->rect.size;
1137 const iInt2 oldSize = *size; 1137 const iInt2 oldSize = *size;
1138 SDL_GetRendererOutputSize(d->render, &size->x, &size->y); 1138 SDL_GetRendererOutputSize(d->render, &size->x, &size->y);
1139 size->y -= d->keyboardHeight;
1139 if (notifyAlways || !isEqual_I2(oldSize, *size)) { 1140 if (notifyAlways || !isEqual_I2(oldSize, *size)) {
1140 const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x); 1141 const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x);
1141 const iBool isVert = (d->place.lastNotifiedSize.y != size->y); 1142 const iBool isVert = (d->place.lastNotifiedSize.y != size->y);
@@ -1287,6 +1288,8 @@ void init_Window(iWindow *d, iRect rect) {
1287 d->isMouseInside = iTrue; 1288 d->isMouseInside = iTrue;
1288 d->ignoreClick = iFalse; 1289 d->ignoreClick = iFalse;
1289 d->focusGainedAt = 0; 1290 d->focusGainedAt = 0;
1291 d->keyboardHeight = 0;
1292 init_Anim(&d->rootOffset, 0.0f);
1290 uint32_t flags = 0; 1293 uint32_t flags = 0;
1291#if defined (iPlatformAppleDesktop) 1294#if defined (iPlatformAppleDesktop)
1292 SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); 1295 SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl");
@@ -1704,6 +1707,7 @@ void draw_Window(iWindow *d) {
1704 if (d->isDrawFrozen) { 1707 if (d->isDrawFrozen) {
1705 return; 1708 return;
1706 } 1709 }
1710// printf("num pending: %d\n", numPendingGlyphs_Text());
1707 const int winFlags = SDL_GetWindowFlags(d->win); 1711 const int winFlags = SDL_GetWindowFlags(d->win);
1708 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0; 1712 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0;
1709 /* Clear the window. The clear color is visible as a border around the window 1713 /* Clear the window. The clear color is visible as a border around the window
@@ -1797,6 +1801,10 @@ iInt2 rootSize_Window(const iWindow *d) {
1797 return d ? d->root->rect.size : zero_I2(); 1801 return d ? d->root->rect.size : zero_I2();
1798} 1802}
1799 1803
1804iInt2 visibleRootSize_Window(const iWindow *d) {
1805 return addY_I2(rootSize_Window(d), -d->keyboardHeight);
1806}
1807
1800iInt2 coord_Window(const iWindow *d, int x, int y) { 1808iInt2 coord_Window(const iWindow *d, int x, int y) {
1801#if defined (iPlatformMsys) || defined (iPlatformLinux) 1809#if defined (iPlatformMsys) || defined (iPlatformLinux)
1802 /* On Windows, surface coordinates are in pixels. */ 1810 /* On Windows, surface coordinates are in pixels. */
@@ -1828,6 +1836,18 @@ iWindow *get_Window(void) {
1828 return theWindow_; 1836 return theWindow_;
1829} 1837}
1830 1838
1839void setKeyboardHeight_Window(iWindow *d, int height) {
1840 if (d->keyboardHeight != height) {
1841 d->keyboardHeight = height;
1842 if (height == 0) {
1843 setFlags_Anim(&d->rootOffset, easeBoth_AnimFlag, iTrue);
1844 setValue_Anim(&d->rootOffset, 0, 250);
1845 }
1846 postCommandf_App("keyboard.changed arg:%d", height);
1847 postRefresh_App();
1848 }
1849}
1850
1831void setSnap_Window(iWindow *d, int snapMode) { 1851void setSnap_Window(iWindow *d, int snapMode) {
1832 if (!prefs_App()->customFrame) { 1852 if (!prefs_App()->customFrame) {
1833 if (snapMode == maximized_WindowSnap) { 1853 if (snapMode == maximized_WindowSnap) {
diff --git a/src/ui/window.h b/src/ui/window.h
index 7cd29d4b..8bc9911c 100644
--- a/src/ui/window.h
+++ b/src/ui/window.h
@@ -75,6 +75,8 @@ struct Impl_Window {
75 SDL_Cursor * cursors[SDL_NUM_SYSTEM_CURSORS]; 75 SDL_Cursor * cursors[SDL_NUM_SYSTEM_CURSORS];
76 SDL_Cursor * pendingCursor; 76 SDL_Cursor * pendingCursor;
77 int loadAnimTimer; 77 int loadAnimTimer;
78 iAnim rootOffset;
79 int keyboardHeight; /* mobile software keyboards */
78}; 80};
79 81
80iBool processEvent_Window (iWindow *, const SDL_Event *); 82iBool processEvent_Window (iWindow *, const SDL_Event *);
@@ -86,9 +88,11 @@ void setUiScale_Window (iWindow *, float uiScale);
86void setFreezeDraw_Window (iWindow *, iBool freezeDraw); 88void setFreezeDraw_Window (iWindow *, iBool freezeDraw);
87void setCursor_Window (iWindow *, int cursor); 89void setCursor_Window (iWindow *, int cursor);
88void setSnap_Window (iWindow *, int snapMode); 90void setSnap_Window (iWindow *, int snapMode);
91void setKeyboardHeight_Window(iWindow *, int height);
89 92
90uint32_t id_Window (const iWindow *); 93uint32_t id_Window (const iWindow *);
91iInt2 rootSize_Window (const iWindow *); 94iInt2 rootSize_Window (const iWindow *);
95iInt2 visibleRootSize_Window (const iWindow *); /* may be obstructed by software keyboard */
92float uiScale_Window (const iWindow *); 96float uiScale_Window (const iWindow *);
93iInt2 coord_Window (const iWindow *, int x, int y); 97iInt2 coord_Window (const iWindow *, int x, int y);
94iInt2 mouseCoord_Window (const iWindow *); 98iInt2 mouseCoord_Window (const iWindow *);