summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--po/en.po12
-rw-r--r--res/lang/de.binbin24162 -> 24222 bytes
-rw-r--r--res/lang/en.binbin22763 -> 22823 bytes
-rw-r--r--res/lang/es.binbin25286 -> 25346 bytes
-rw-r--r--res/lang/fi.binbin25291 -> 25351 bytes
-rw-r--r--res/lang/fr.binbin26260 -> 26320 bytes
-rw-r--r--res/lang/ia.binbin24890 -> 24950 bytes
-rw-r--r--res/lang/ie.binbin24645 -> 24705 bytes
-rw-r--r--res/lang/pl.binbin25823 -> 25883 bytes
-rw-r--r--res/lang/ru.binbin37542 -> 37602 bytes
-rw-r--r--res/lang/sr.binbin37199 -> 37259 bytes
-rw-r--r--res/lang/tok.binbin23081 -> 23141 bytes
-rw-r--r--res/lang/zh_Hans.binbin21842 -> 21902 bytes
-rw-r--r--res/lang/zh_Hant.binbin22027 -> 22087 bytes
-rw-r--r--src/app.c16
-rw-r--r--src/defs.h2
-rw-r--r--src/ui/color.h1
-rw-r--r--src/ui/documentwidget.c21
-rw-r--r--src/ui/inputwidget.c563
-rw-r--r--src/ui/paint.c19
-rw-r--r--src/ui/paint.h2
-rw-r--r--src/ui/root.c33
-rw-r--r--src/ui/touch.c9
-rw-r--r--src/ui/util.c70
-rw-r--r--src/ui/widget.c40
-rw-r--r--src/ui/window.c10
-rw-r--r--src/ui/window.h2
27 files changed, 591 insertions, 209 deletions
diff --git a/po/en.po b/po/en.po
index 546a9489..96026528 100644
--- a/po/en.po
+++ b/po/en.po
@@ -273,6 +273,18 @@ msgstr "Copy"
273msgid "menu.paste" 273msgid "menu.paste"
274msgstr "Paste" 274msgstr "Paste"
275 275
276# keep this short (3x1 horiz layout)
277msgid "menu.selectall"
278msgstr "Select All"
279
280# keep this short (3x1 horiz layout)
281msgid "menu.delete"
282msgstr "Delete"
283
284# keep this short (3x1 horiz layout)
285msgid "menu.undo"
286msgstr "Undo"
287
276msgid "menu.select.clear" 288msgid "menu.select.clear"
277msgstr "Clear Selection" 289msgstr "Clear Selection"
278 290
diff --git a/res/lang/de.bin b/res/lang/de.bin
index ba87d002..f5a6b07e 100644
--- a/res/lang/de.bin
+++ b/res/lang/de.bin
Binary files differ
diff --git a/res/lang/en.bin b/res/lang/en.bin
index a7dfb866..df3c4025 100644
--- a/res/lang/en.bin
+++ b/res/lang/en.bin
Binary files differ
diff --git a/res/lang/es.bin b/res/lang/es.bin
index 7e7398d6..9f5a169f 100644
--- a/res/lang/es.bin
+++ b/res/lang/es.bin
Binary files differ
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index 607e52fd..ac3b99ef 100644
--- a/res/lang/fi.bin
+++ b/res/lang/fi.bin
Binary files differ
diff --git a/res/lang/fr.bin b/res/lang/fr.bin
index 955695ed..7d40e32c 100644
--- a/res/lang/fr.bin
+++ b/res/lang/fr.bin
Binary files differ
diff --git a/res/lang/ia.bin b/res/lang/ia.bin
index 61a18efc..d10ab85e 100644
--- a/res/lang/ia.bin
+++ b/res/lang/ia.bin
Binary files differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index 06ea7979..14349637 100644
--- a/res/lang/ie.bin
+++ b/res/lang/ie.bin
Binary files differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index 5fc5e24a..9ddd137f 100644
--- a/res/lang/pl.bin
+++ b/res/lang/pl.bin
Binary files differ
diff --git a/res/lang/ru.bin b/res/lang/ru.bin
index 1718f647..366c6ee5 100644
--- a/res/lang/ru.bin
+++ b/res/lang/ru.bin
Binary files differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index 60b7b600..870b0950 100644
--- a/res/lang/sr.bin
+++ b/res/lang/sr.bin
Binary files differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index 3298f0e8..dac5fb33 100644
--- a/res/lang/tok.bin
+++ b/res/lang/tok.bin
Binary files differ
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin
index 8c32a0c5..3407c485 100644
--- a/res/lang/zh_Hans.bin
+++ b/res/lang/zh_Hans.bin
Binary files differ
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin
index 68f7d3bc..b9001e2d 100644
--- a/res/lang/zh_Hant.bin
+++ b/res/lang/zh_Hant.bin
Binary files differ
diff --git a/src/app.c b/src/app.c
index fa601ac3..37f9c804 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1069,11 +1069,11 @@ iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
1069 return iFalse; 1069 return iFalse;
1070 } 1070 }
1071#endif 1071#endif
1072#if defined (iPlatformMobile) 1072//#if defined (iPlatformMobile)
1073 if (!isFinished_Anim(&d->window->rootOffset)) { 1073// if (!isFinished_Anim(&d->window->rootOffset)) {
1074 return iFalse; 1074// return iFalse;
1075 } 1075// }
1076#endif 1076//#endif
1077 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers); 1077 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers);
1078} 1078}
1079 1079
@@ -1318,7 +1318,7 @@ void processEvents_App(enum iAppEventMode eventMode) {
1318 } 1318 }
1319 } 1319 }
1320#if defined (LAGRANGE_ENABLE_IDLE_SLEEP) 1320#if defined (LAGRANGE_ENABLE_IDLE_SLEEP)
1321 if (d->isIdling && !gotEvents && isFinished_Anim(&d->window->rootOffset)) { 1321 if (d->isIdling && !gotEvents /*&& isFinished_Anim(&d->window->rootOffset)*/) {
1322 /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we 1322 /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we
1323 can't wait too long after the user tries to interact again with the app. In any 1323 can't wait too long after the user tries to interact again with the app. In any
1324 case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */ 1324 case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */
@@ -1411,9 +1411,9 @@ void refresh_App(void) {
1411#endif 1411#endif
1412 if (!exchange_Atomic(&d->pendingRefresh, iFalse)) { 1412 if (!exchange_Atomic(&d->pendingRefresh, iFalse)) {
1413 /* Refreshing wasn't pending. */ 1413 /* Refreshing wasn't pending. */
1414 if (isFinished_Anim(&d->window->rootOffset)) { 1414// if (isFinished_Anim(&d->window->rootOffset)) {
1415 return; 1415 return;
1416 } 1416// }
1417 } 1417 }
1418// iTime draw; 1418// iTime draw;
1419// initCurrent_Time(&draw); 1419// initCurrent_Time(&draw);
diff --git a/src/defs.h b/src/defs.h
index 6b12c86c..c3a23596 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -151,6 +151,8 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) {
151#define magnifyingGlass_Icon "\U0001f50d" 151#define magnifyingGlass_Icon "\U0001f50d"
152#define midEllipsis_Icon "\u00b7\u00b7\u00b7" 152#define midEllipsis_Icon "\u00b7\u00b7\u00b7"
153#define return_Icon "\u23ce" 153#define return_Icon "\u23ce"
154#define undo_Icon "\u23ea"
155#define select_Icon "\u2b1a"
154 156
155#if defined (iPlatformApple) 157#if defined (iPlatformApple)
156# define shift_Icon "\u21e7" 158# define shift_Icon "\u21e7"
diff --git a/src/ui/color.h b/src/ui/color.h
index 37ec49eb..a1d863dc 100644
--- a/src/ui/color.h
+++ b/src/ui/color.h
@@ -183,6 +183,7 @@ iLocalDef iBool isRegularText_ColorId(enum iColorId d) {
183#define mask_ColorId 0x7f 183#define mask_ColorId 0x7f
184#define permanent_ColorId 0x80 /* cannot be changed via escapes */ 184#define permanent_ColorId 0x80 /* cannot be changed via escapes */
185#define fillBackground_ColorId 0x100 /* fill background with same color, but alpha 0 */ 185#define fillBackground_ColorId 0x100 /* fill background with same color, but alpha 0 */
186#define opaque_ColorId 0x200
186 187
187#define asciiBase_ColorEscape 33 188#define asciiBase_ColorEscape 33
188#define asciiExtended_ColorEscape (128 - asciiBase_ColorEscape) 189#define asciiExtended_ColorEscape (128 - asciiBase_ColorEscape)
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 4b3c2db0..8ea695d5 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -4597,23 +4597,6 @@ static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) {
4597 } 4597 }
4598} 4598}
4599 4599
4600static void drawPin_(iPaint *p, iRect rangeRect, int dir) {
4601 const int pinColor = tmQuote_ColorId;
4602 const int height = height_Rect(rangeRect);
4603 iRect pin;
4604 if (dir == 0) {
4605 pin = (iRect){ add_I2(topLeft_Rect(rangeRect), init_I2(-gap_UI / 4, -gap_UI)),
4606 init_I2(gap_UI / 2, height + gap_UI) };
4607 }
4608 else {
4609 pin = (iRect){ addX_I2(topRight_Rect(rangeRect), -gap_UI / 4),
4610 init_I2(gap_UI / 2, height + gap_UI) };
4611 }
4612 fillRect_Paint(p, pin, pinColor);
4613 fillRect_Paint(p, initCentered_Rect(dir == 0 ? topMid_Rect(pin) : bottomMid_Rect(pin),
4614 init1_I2(gap_UI * 2)), pinColor);
4615}
4616
4617static void extend_GmRunRange_(iGmRunRange *runs) { 4600static void extend_GmRunRange_(iGmRunRange *runs) {
4618 if (runs->start) { 4601 if (runs->start) {
4619 runs->start--; 4602 runs->start--;
@@ -4857,8 +4840,8 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4857 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); 4840 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE);
4858 /* Selection range pins. */ 4841 /* Selection range pins. */
4859 if (isTouchSelecting) { 4842 if (isTouchSelecting) {
4860 drawPin_(&ctx.paint, ctx.firstMarkRect, 0); 4843 drawPin_Paint(&ctx.paint, ctx.firstMarkRect, 0, tmQuote_ColorId);
4861 drawPin_(&ctx.paint, ctx.lastMarkRect, 1); 4844 drawPin_Paint(&ctx.paint, ctx.lastMarkRect, 1, tmQuote_ColorId);
4862 } 4845 }
4863 } 4846 }
4864 drawMedia_DocumentWidget_(d, &ctx.paint); 4847 drawMedia_DocumentWidget_(d, &ctx.paint);
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index ad630223..12eb490d 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -179,19 +179,23 @@ static void deinit_InputUndo_(iInputUndo *d) {
179} 179}
180 180
181enum iInputWidgetFlag { 181enum iInputWidgetFlag {
182 isSensitive_InputWidgetFlag = iBit(1), 182 isSensitive_InputWidgetFlag = iBit(1),
183 isUrl_InputWidgetFlag = iBit(2), /* affected by decoding preference */ 183 isUrl_InputWidgetFlag = iBit(2), /* affected by decoding preference */
184 enterPressed_InputWidgetFlag = iBit(3), 184 enterPressed_InputWidgetFlag = iBit(3),
185 selectAllOnFocus_InputWidgetFlag = iBit(4), 185 selectAllOnFocus_InputWidgetFlag = iBit(4),
186 notifyEdits_InputWidgetFlag = iBit(5), 186 notifyEdits_InputWidgetFlag = iBit(5),
187 eatEscape_InputWidgetFlag = iBit(6), 187 eatEscape_InputWidgetFlag = iBit(6),
188 isMarking_InputWidgetFlag = iBit(7), 188 isMarking_InputWidgetFlag = iBit(7),
189 markWords_InputWidgetFlag = iBit(8), 189 markWords_InputWidgetFlag = iBit(8),
190 needUpdateBuffer_InputWidgetFlag = iBit(9), 190 needUpdateBuffer_InputWidgetFlag = iBit(9),
191 enterKeyEnabled_InputWidgetFlag = iBit(10), 191 enterKeyEnabled_InputWidgetFlag = iBit(10),
192 lineBreaksEnabled_InputWidgetFlag= iBit(11), 192 lineBreaksEnabled_InputWidgetFlag = iBit(11),
193 needBackup_InputWidgetFlag = iBit(12), 193 needBackup_InputWidgetFlag = iBit(12),
194 useReturnKeyBehavior_InputWidgetFlag = iBit(13), 194 useReturnKeyBehavior_InputWidgetFlag = iBit(13),
195 //touchBehavior_InputWidgetFlag = iBit(14), /* different behavior depending on interaction method */
196 dragCursor_InputWidgetFlag = iBit(14),
197 dragMarkerStart_InputWidgetFlag = iBit(15),
198 dragMarkerEnd_InputWidgetFlag = iBit(16),
195}; 199};
196 200
197/*----------------------------------------------------------------------------------------------*/ 201/*----------------------------------------------------------------------------------------------*/
@@ -217,6 +221,10 @@ struct Impl_InputWidget {
217 iArray undoStack; 221 iArray undoStack;
218 int font; 222 int font;
219 iClick click; 223 iClick click;
224 uint32_t tapStartTime;
225 uint32_t lastTapTime;
226 iInt2 lastTapPos;
227 int tapCount;
220 int wheelAccum; 228 int wheelAccum;
221 int cursorVis; 229 int cursorVis;
222 uint32_t timer; 230 uint32_t timer;
@@ -460,14 +468,18 @@ static iWrapText wrap_InputWidget_(const iInputWidget *d, int y) {
460 }; 468 };
461} 469}
462 470
463static iInt2 relativeCursorCoord_InputWidget_(const iInputWidget *d) { 471static iInt2 relativeCoord_InputWidget_(const iInputWidget *d, iInt2 pos) {
464 /* Relative to the start of the line on which the cursor is. */ 472 /* Relative to the start of the line on which the cursor is. */
465 iWrapText wt = wrap_InputWidget_(d, d->cursor.y); 473 iWrapText wt = wrap_InputWidget_(d, pos.y);
466 wt.hitChar = wt.text.start + d->cursor.x; 474 wt.hitChar = wt.text.start + pos.x;
467 measure_WrapText(&wt, d->font); 475 measure_WrapText(&wt, d->font);
468 return wt.hitAdvance_out; 476 return wt.hitAdvance_out;
469} 477}
470 478
479static iInt2 relativeCursorCoord_InputWidget_(const iInputWidget *d) {
480 return relativeCoord_InputWidget_(d, d->cursor);
481}
482
471static void updateVisible_InputWidget_(iInputWidget *d) { 483static void updateVisible_InputWidget_(iInputWidget *d) {
472 const int totalWraps = numWrapLines_InputWidget_(d); 484 const int totalWraps = numWrapLines_InputWidget_(d);
473 const int visWraps = iClamp(totalWraps, d->minWrapLines, d->maxWrapLines); 485 const int visWraps = iClamp(totalWraps, d->minWrapLines, d->maxWrapLines);
@@ -632,7 +644,7 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) {
632 init_Widget(w); 644 init_Widget(w);
633 d->validator = NULL; 645 d->validator = NULL;
634 d->validatorContext = NULL; 646 d->validatorContext = NULL;
635 setFlags_Widget(w, focusable_WidgetFlag | hover_WidgetFlag | touchDrag_WidgetFlag, iTrue); 647 setFlags_Widget(w, focusable_WidgetFlag | hover_WidgetFlag, iTrue);
636#if defined (iPlatformMobile) 648#if defined (iPlatformMobile)
637 setFlags_Widget(w, extraPadding_WidgetFlag, iTrue); 649 setFlags_Widget(w, extraPadding_WidgetFlag, iTrue);
638#endif 650#endif
@@ -662,6 +674,8 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) {
662 splitToLines_(&iStringLiteral(""), &d->lines); 674 splitToLines_(&iStringLiteral(""), &d->lines);
663 setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); /* resizes its own height */ 675 setFlags_Widget(w, fixedHeight_WidgetFlag, iTrue); /* resizes its own height */
664 init_Click(&d->click, d, SDL_BUTTON_LEFT); 676 init_Click(&d->click, d, SDL_BUTTON_LEFT);
677 d->lastTapTime = 0;
678 d->tapCount = 0;
665 d->wheelAccum = 0; 679 d->wheelAccum = 0;
666 d->timer = 0; 680 d->timer = 0;
667 d->cursorVis = 0; 681 d->cursorVis = 0;
@@ -993,7 +1007,7 @@ void begin_InputWidget(iInputWidget *d) {
993 d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end }; 1007 d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end };
994 d->cursor = cursorMax_InputWidget_(d); 1008 d->cursor = cursorMax_InputWidget_(d);
995 } 1009 }
996 else { 1010 else if (~d->inFlags & isMarking_InputWidgetFlag) {
997 iZap(d->mark); 1011 iZap(d->mark);
998 } 1012 }
999 enableEditorKeysInMenus_(iFalse); 1013 enableEditorKeysInMenus_(iFalse);
@@ -1013,9 +1027,10 @@ void end_InputWidget(iInputWidget *d, iBool accept) {
1013 splitToLines_(&d->oldText, &d->lines); 1027 splitToLines_(&d->oldText, &d->lines);
1014 } 1028 }
1015 d->inFlags |= needUpdateBuffer_InputWidgetFlag; 1029 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1030 d->inFlags &= ~isMarking_InputWidgetFlag;
1016 startOrStopCursorTimer_InputWidget_(d, iFalse); 1031 startOrStopCursorTimer_InputWidget_(d, iFalse);
1017 SDL_StopTextInput(); 1032 SDL_StopTextInput();
1018 setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag, iFalse); 1033 setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag | touchDrag_WidgetFlag, iFalse);
1019 const char *id = cstr_String(id_Widget(as_Widget(d))); 1034 const char *id = cstr_String(id_Widget(as_Widget(d)));
1020 if (!*id) id = "_"; 1035 if (!*id) id = "_";
1021 refresh_Widget(w); 1036 refresh_Widget(w);
@@ -1445,88 +1460,31 @@ static iBool checkAcceptMods_InputWidget_(const iInputWidget *d, int mods) {
1445 return mods == 0; 1460 return mods == 0;
1446} 1461}
1447 1462
1448static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { 1463enum iEventResult {
1449 iWidget *w = as_Widget(d); 1464 ignored_EventResult = 0, /* event was not processed */
1450 /* Resize according to width immediately. */ 1465 false_EventResult = 1, /* event was processed but other widgets can still process it, too*/
1451 if (d->lastUpdateWidth != w->rect.size.x) { 1466 true_EventResult = 2, /* event was processed and should not be passed on */
1452 d->inFlags |= needUpdateBuffer_InputWidgetFlag; 1467};
1453 if (d->inFlags & isUrl_InputWidgetFlag) { 1468
1454 /* Restore/omit the default scheme if necessary. */ 1469static void markWordAtCursor_InputWidget_(iInputWidget *d) {
1455 setText_InputWidget(d, text_InputWidget(d)); 1470 d->mark.start = d->mark.end = cursorToIndex_InputWidget_(d, d->cursor);
1456 } 1471 extendRange_InputWidget_(d, &d->mark.start, -1);
1457 updateAllLinesAndResizeHeight_InputWidget_(d); 1472 extendRange_InputWidget_(d, &d->mark.end, +1);
1458 d->lastUpdateWidth = w->rect.size.x; 1473 d->initialMark = d->mark;
1459 } 1474}
1460 if (isCommand_Widget(w, ev, "focus.gained")) { 1475
1461 begin_InputWidget(d); 1476static void showClipMenu_(iInt2 coord) {
1462 return iFalse; 1477 iWidget *clipMenu = findWidget_App("clipmenu");
1463 } 1478 if (isVisible_Widget(clipMenu)) {
1464 else if (isEditing_InputWidget_(d) && (isCommand_UserEvent(ev, "window.focus.lost") || 1479 closeMenu_Widget(clipMenu);
1465 isCommand_UserEvent(ev, "window.focus.gained"))) {
1466 startOrStopCursorTimer_InputWidget_(d, isCommand_UserEvent(ev, "window.focus.gained"));
1467 d->cursorVis = 1;
1468 refresh_Widget(d);
1469 return iFalse;
1470 }
1471 else if (isCommand_UserEvent(ev, "keyroot.changed")) {
1472 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1473 }
1474 else if (isCommand_UserEvent(ev, "lang.changed")) {
1475 set_String(&d->hint, &d->srcHint);
1476 translate_Lang(&d->hint);
1477 return iFalse;
1478 }
1479 else if (isCommand_Widget(w, ev, "focus.lost")) {
1480 end_InputWidget(d, iTrue);
1481 return iFalse;
1482 }
1483 else if ((isCommand_UserEvent(ev, "copy") || isCommand_UserEvent(ev, "input.copy")) &&
1484 isEditing_InputWidget_(d)) {
1485 copy_InputWidget_(d, argLabel_Command(command_UserEvent(ev), "cut"));
1486 return iTrue;
1487 }
1488 else if (isCommand_UserEvent(ev, "input.paste") && isEditing_InputWidget_(d)) {
1489 paste_InputWidget_(d);
1490 return iTrue;
1491 }
1492 else if (isCommand_UserEvent(ev, "theme.changed")) {
1493 if (d->buffered) {
1494 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1495 }
1496 return iFalse;
1497 }
1498 else if (isCommand_UserEvent(ev, "keyboard.changed")) {
1499 if (isFocused_Widget(d) && arg_Command(command_UserEvent(ev))) {
1500 iRect rect = bounds_Widget(w);
1501 rect.pos.y -= value_Anim(&get_Window()->rootOffset);
1502 const iInt2 visRoot = visibleSize_Root(w->root);
1503 if (bottom_Rect(rect) > visRoot.y) {
1504 setValue_Anim(&get_Window()->rootOffset, -(bottom_Rect(rect) - visRoot.y), 250);
1505 }
1506 }
1507 return iFalse;
1508 }
1509 else if (isCommand_UserEvent(ev, "text.insert")) {
1510 pushUndo_InputWidget_(d);
1511 deleteMarked_InputWidget_(d);
1512 insertChar_InputWidget_(d, arg_Command(command_UserEvent(ev)));
1513 contentsWereChanged_InputWidget_(d);
1514 return iTrue;
1515 }
1516 else if (isCommand_Widget(w, ev, "input.backup")) {
1517 if (d->inFlags & needBackup_InputWidgetFlag) {
1518 saveBackup_InputWidget_(d);
1519 }
1520 return iTrue;
1521 }
1522 else if (isMetricsChange_UserEvent(ev)) {
1523 updateMetrics_InputWidget_(d);
1524 // updateLinesAndResize_InputWidget_(d);
1525 } 1480 }
1526 else if (isFocused_Widget(d) && isCommand_UserEvent(ev, "copy")) { 1481 else {
1527 copy_InputWidget_(d, iFalse); 1482 openMenuFlags_Widget(clipMenu, coord, iFalse);
1528 return iTrue;
1529 } 1483 }
1484}
1485
1486static enum iEventResult processPointerEvents_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1487 iWidget *w = as_Widget(d);
1530 if (ev->type == SDL_MOUSEMOTION && (isHover_Widget(d) || flags_Widget(w) & keepOnTop_WidgetFlag)) { 1488 if (ev->type == SDL_MOUSEMOTION && (isHover_Widget(d) || flags_Widget(w) & keepOnTop_WidgetFlag)) {
1531 const iInt2 coord = init_I2(ev->motion.x, ev->motion.y); 1489 const iInt2 coord = init_I2(ev->motion.x, ev->motion.y);
1532 const iInt2 inner = windowToInner_Widget(w, coord); 1490 const iInt2 inner = windowToInner_Widget(w, coord);
@@ -1559,10 +1517,15 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1559 d->visWrapLines.start += lineDelta; 1517 d->visWrapLines.start += lineDelta;
1560 d->visWrapLines.end += lineDelta; 1518 d->visWrapLines.end += lineDelta;
1561 d->inFlags |= needUpdateBuffer_InputWidgetFlag; 1519 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1562 refresh_Widget(d); 1520 refresh_Widget(d);
1563 return iTrue; 1521 return true_EventResult;
1564 } 1522 }
1565 return iFalse; 1523 return false_EventResult;
1524 }
1525 if (ev->type == SDL_MOUSEBUTTONDOWN && ev->button.button == SDL_BUTTON_RIGHT &&
1526 contains_Widget(w, init_I2(ev->button.x, ev->button.y))) {
1527 showClipMenu_(mouseCoord_Window(get_Window(), ev->button.which));
1528 return iTrue;
1566 } 1529 }
1567 switch (processEvent_Click(&d->click, ev)) { 1530 switch (processEvent_Click(&d->click, ev)) {
1568 case none_ClickResult: 1531 case none_ClickResult:
@@ -1584,10 +1547,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1584 d->inFlags &= ~(isMarking_InputWidgetFlag | markWords_InputWidgetFlag); 1547 d->inFlags &= ~(isMarking_InputWidgetFlag | markWords_InputWidgetFlag);
1585 if (d->click.count == 2) { 1548 if (d->click.count == 2) {
1586 d->inFlags |= isMarking_InputWidgetFlag | markWords_InputWidgetFlag; 1549 d->inFlags |= isMarking_InputWidgetFlag | markWords_InputWidgetFlag;
1587 d->mark.start = d->mark.end = cursorToIndex_InputWidget_(d, d->cursor); 1550 markWordAtCursor_InputWidget_(d);
1588 extendRange_InputWidget_(d, &d->mark.start, -1);
1589 extendRange_InputWidget_(d, &d->mark.end, +1);
1590 d->initialMark = d->mark;
1591 refresh_Widget(w); 1551 refresh_Widget(w);
1592 } 1552 }
1593 if (d->click.count == 3) { 1553 if (d->click.count == 3) {
@@ -1595,11 +1555,11 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1595 } 1555 }
1596 } 1556 }
1597 refresh_Widget(d); 1557 refresh_Widget(d);
1598 return iTrue; 1558 return true_EventResult;
1599 } 1559 }
1600 case aborted_ClickResult: 1560 case aborted_ClickResult:
1601 d->inFlags &= ~isMarking_InputWidgetFlag; 1561 d->inFlags &= ~isMarking_InputWidgetFlag;
1602 return iTrue; 1562 return true_EventResult;
1603 case drag_ClickResult: 1563 case drag_ClickResult:
1604 d->cursor = coordCursor_InputWidget_(d, pos_Click(&d->click)); 1564 d->cursor = coordCursor_InputWidget_(d, pos_Click(&d->click));
1605 showCursor_InputWidget_(d); 1565 showCursor_InputWidget_(d);
@@ -1614,30 +1574,374 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1614 d->mark.start = isFwd ? d->initialMark.start : d->initialMark.end; 1574 d->mark.start = isFwd ? d->initialMark.start : d->initialMark.end;
1615 } 1575 }
1616 refresh_Widget(w); 1576 refresh_Widget(w);
1617 return iTrue; 1577 return true_EventResult;
1618 case finished_ClickResult: 1578 case finished_ClickResult:
1619 d->inFlags &= ~isMarking_InputWidgetFlag; 1579 d->inFlags &= ~isMarking_InputWidgetFlag;
1620 return iTrue; 1580 return true_EventResult;
1621 } 1581 }
1622 if (ev->type == SDL_MOUSEMOTION && flags_Widget(w) & keepOnTop_WidgetFlag) { 1582 if (ev->type == SDL_MOUSEMOTION && flags_Widget(w) & keepOnTop_WidgetFlag) {
1623 const iInt2 coord = init_I2(ev->motion.x, ev->motion.y); 1583 const iInt2 coord = init_I2(ev->motion.x, ev->motion.y);
1624 if (contains_Click(&d->click, coord)) { 1584 if (contains_Click(&d->click, coord)) {
1625 return iTrue; 1585 return true_EventResult;
1626 } 1586 }
1627 } 1587 }
1628 if (ev->type == SDL_MOUSEBUTTONDOWN && ev->button.button == SDL_BUTTON_RIGHT && 1588 return ignored_EventResult;
1629 contains_Widget(w, init_I2(ev->button.x, ev->button.y))) { 1589}
1630 iWidget *clipMenu = findWidget_App("clipmenu"); 1590
1631 if (isVisible_Widget(clipMenu)) { 1591static iInt2 touchCoordCursor_InputWidget_(const iInputWidget *d, iInt2 coord) {
1632 closeMenu_Widget(clipMenu); 1592 /* Clamp to the bounds so the cursor doesn't wrap at the ends. */
1593 iRect bounds = shrunk_Rect(contentBounds_InputWidget_(d), one_I2());
1594 bounds.size.y = iMini(numWrapLines_InputWidget_(d), d->maxWrapLines) * lineHeight_Text(d->font) - 2;
1595 return coordCursor_InputWidget_(d, min_I2(bottomRight_Rect(bounds),
1596 max_I2(coord, topLeft_Rect(bounds))));
1597}
1598
1599static iBool isInsideMark_InputWidget_(const iInputWidget *d, size_t pos) {
1600 const iRanges mark = mark_InputWidget_(d);
1601 return contains_Range(&mark, pos);
1602}
1603
1604static int distanceToPos_InputWidget_(const iInputWidget *d, iInt2 uiCoord, iInt2 textPos) {
1605 const iInt2 a = addY_I2(relativeCoord_InputWidget_(d, textPos), lineHeight_Text(d->font) / 2);
1606 const iInt2 b = sub_I2(uiCoord, topLeft_Rect(contentBounds_InputWidget_(d)));
1607 return dist_I2(a, b);
1608}
1609
1610static enum iEventResult processTouchEvents_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1611 iWidget *w = as_Widget(d);
1612 /*
1613 + first tap to focus & select all/place cursor
1614 + focused tap to place cursor
1615 - drag cursor to move it
1616 - double-click to select a word
1617 - drag to move selection handles
1618 - long-press for context menu: copy, paste, delete, select all, deselect
1619 - double-click and hold to select words
1620 - triple-click to select all
1621 - drag/wheel elsewhere to scroll (contents or overflow), no change in focus
1622 */
1623// if (ev->type != SDL_MOUSEBUTTONUP && ev->type != SDL_MOUSEBUTTONDOWN &&
1624// ev->type != SDL_MOUSEWHEEL && ev->type != SDL_MOUSEMOTION &&
1625// !(ev->type == SDL_USEREVENT && ev->user.code == widgetTapBegins_UserEventCode) &&
1626// !(ev->type == SDL_USEREVENT && ev->user.code == widgetTouchEnds_UserEventCode)) {
1627// return ignored_EventResult;
1628// }
1629 if (isFocused_Widget(w)) {
1630 if (ev->type == SDL_USEREVENT && ev->user.code == widgetTapBegins_UserEventCode) {
1631 d->lastTapTime = d->tapStartTime;
1632 d->tapStartTime = SDL_GetTicks();
1633 const int tapDist = dist_I2(latestPosition_Touch(), d->lastTapPos);
1634 d->lastTapPos = latestPosition_Touch();
1635 printf("[%p] tap start time: %u (%u) %d\n", w, d->tapStartTime, d->tapStartTime - d->lastTapTime, tapDist);
1636 if (d->tapStartTime - d->lastTapTime < 400 && tapDist < gap_UI * 4) {
1637 d->tapCount++;
1638 printf("[%p] >> tap count: %d\n", w, d->tapCount);
1639 }
1640 else {
1641 d->tapCount = 0;
1642 }
1643 if (!isEmpty_Range(&d->mark)) {
1644 const int dist[2] = {
1645 distanceToPos_InputWidget_(d, latestPosition_Touch(),
1646 indexToCursor_InputWidget_(d, d->mark.start)),
1647 distanceToPos_InputWidget_(d, latestPosition_Touch(),
1648 indexToCursor_InputWidget_(d, d->mark.end))
1649 };
1650 if (dist[0] < dist[1]) {
1651 printf("[%p] begin marker start drag\n", w);
1652 d->inFlags |= dragMarkerStart_InputWidgetFlag;
1653 }
1654 else {
1655 printf("[%p] begin marker end drag\n", w);
1656 d->inFlags |= dragMarkerEnd_InputWidgetFlag;
1657 }
1658 d->inFlags |= isMarking_InputWidgetFlag;
1659 setFlags_Widget(w, touchDrag_WidgetFlag, iTrue);
1660 }
1661 else {
1662 const int dist = distanceToPos_InputWidget_(d, latestPosition_Touch(), d->cursor);
1663 printf("[%p] tap dist: %d\n", w, dist);
1664 if (dist < gap_UI * 10) {
1665 printf("[%p] begin cursor drag\n", w);
1666 setFlags_Widget(w, touchDrag_WidgetFlag, iTrue);
1667 d->inFlags |= dragCursor_InputWidgetFlag;
1668// d->inFlags |= touchBehavior_InputWidgetFlag;
1669// setMouseGrab_Widget(w);
1670// return iTrue;
1671 }
1672 }
1673// if (~d->inFlags & selectAllOnFocus_InputWidgetFlag) {
1674// d->cursor = coordCursor_InputWidget_(d, pos_Click(&d->click));
1675// showCursor_InputWidget_(d);
1676// }
1677 return true_EventResult;
1678 }
1679 }
1680#if 0
1681 else if (isFocused_Widget(w)) {
1682 if (ev->type == SDL_MOUSEMOTION) {
1683 if (~d->inFlags & touchBehavior_InputWidgetFlag) {
1684 const iInt2 curPos = relativeCursorCoord_InputWidget_(d);
1685 const iInt2 relClick = sub_I2(pos_Click(&d->click),
1686 topLeft_Rect(contentBounds_InputWidget_(d)));
1687 if (dist_I2(curPos, relClick) < gap_UI * 8) {
1688 printf("tap on cursor!\n");
1689 setFlags_Widget(w, touchDrag_WidgetFlag, iTrue);
1690 d->inFlags |= touchBehavior_InputWidgetFlag;
1691 printf("[Input] begin cursor drag\n");
1692 setMouseGrab_Widget(w);
1693 return iTrue;
1694 }
1695 }
1696 else if (ev->motion.x > 0 && ev->motion.y > 0) {
1697 printf("[Input] cursor being dragged\n");
1698 iRect bounds = shrunk_Rect(contentBounds_InputWidget_(d), one_I2());
1699 bounds.size.y = iMini(numWrapLines_InputWidget_(d), d->maxWrapLines) * lineHeight_Text(d->font) - 2;
1700 iInt2 mpos = init_I2(ev->motion.x, ev->motion.y);
1701 mpos = min_I2(bottomRight_Rect(bounds), max_I2(mpos, topLeft_Rect(bounds)));
1702 d->cursor = coordCursor_InputWidget_(d, mpos);
1703 showCursor_InputWidget_(d);
1704 refresh_Widget(w);
1705 return iTrue;
1706 }
1633 } 1707 }
1634 else { 1708 if (d->inFlags & touchBehavior_InputWidgetFlag) {
1635 openMenuFlags_Widget(clipMenu, 1709 if (ev->type == SDL_MOUSEBUTTONUP ||
1636 mouseCoord_Window(get_Window(), ev->button.which), 1710 (ev->type == SDL_USEREVENT && ev->user.code == widgetTouchEnds_UserEventCode)) {
1637 iFalse); 1711 d->inFlags &= ~touchBehavior_InputWidgetFlag;
1712 setFlags_Widget(w, touchDrag_WidgetFlag, iFalse);
1713 setMouseGrab_Widget(NULL);
1714 printf("[Input] touch ends\n");
1715 return iFalse;
1716 }
1717 }
1718 }
1719#endif
1720#if 1
1721 if ((ev->type == SDL_MOUSEBUTTONDOWN || ev->type == SDL_MOUSEBUTTONUP) &&
1722 ev->button.button == SDL_BUTTON_RIGHT && contains_Widget(w, latestPosition_Touch())) {
1723 if (ev->type == SDL_MOUSEBUTTONDOWN) {
1724 /*if (isFocused_Widget(w)) {
1725 d->inFlags |= isMarking_InputWidgetFlag;
1726 d->cursor = touchCoordCursor_InputWidget_(d, latestPosition_Touch());
1727 markWordAtCursor_InputWidget_(d);
1728 refresh_Widget(d);
1729 return true_EventResult;
1730 }*/
1731 setFocus_Widget(w);
1732 d->inFlags |= isMarking_InputWidgetFlag;
1733 d->cursor = touchCoordCursor_InputWidget_(d, latestPosition_Touch());
1734 markWordAtCursor_InputWidget_(d);
1735 d->cursor = indexToCursor_InputWidget_(d, d->mark.end);
1736 refresh_Widget(d);
1737 }
1738 return true_EventResult;
1739 }
1740 switch (processEvent_Click(&d->click, ev)) {
1741 case none_ClickResult:
1742 break;
1743 case started_ClickResult: {
1744 printf("[%p] started\n", w);
1745 /*
1746 const iInt2 curPos = relativeCursorCoord_InputWidget_(d);
1747 const iInt2 relClick = sub_I2(pos_Click(&d->click),
1748 topLeft_Rect(contentBounds_InputWidget_(d)));
1749 if (dist_I2(curPos, relClick) < gap_UI * 8) {
1750 printf("tap on cursor!\n");
1751 setFlags_Widget(w, touchDrag_WidgetFlag, iTrue);
1752 }
1753 else {
1754 printf("tap elsewhere\n");
1755 }*/
1756 return true_EventResult;
1757 }
1758 case drag_ClickResult:
1759 printf("[%p] drag %d,%d\n", w, pos_Click(&d->click).x, pos_Click(&d->click).y);
1760 if (d->inFlags & dragCursor_InputWidgetFlag) {
1761 iZap(d->mark);
1762 d->cursor = touchCoordCursor_InputWidget_(d, pos_Click(&d->click));
1763 showCursor_InputWidget_(d);
1764 refresh_Widget(w);
1765 }
1766 else if (d->inFlags & dragMarkerStart_InputWidgetFlag) {
1767 d->mark.start = cursorToIndex_InputWidget_(d, touchCoordCursor_InputWidget_(d, pos_Click(&d->click)));
1768 refresh_Widget(w);
1769 }
1770 else if (d->inFlags & dragMarkerEnd_InputWidgetFlag) {
1771 d->mark.end = cursorToIndex_InputWidget_(d, touchCoordCursor_InputWidget_(d, pos_Click(&d->click)));
1772 refresh_Widget(w);
1773 }
1774 return true_EventResult;
1775 // printf("[%p] aborted\n", w);
1776// d->inFlags &= ~touchBehavior_InputWidgetFlag;
1777// setFlags_Widget(w, touchDrag_WidgetFlag, iFalse);
1778// return true_EventResult;
1779 case finished_ClickResult:
1780 case aborted_ClickResult:
1781 printf("[%p] ended\n", w);
1782 uint32_t tapElapsed = SDL_GetTicks() - d->tapStartTime;
1783 printf("tapElapsed: %u\n", tapElapsed);
1784 if (!isFocused_Widget(w)) {
1785 setFocus_Widget(w);
1786 d->lastTapPos = latestPosition_Touch();
1787 d->tapStartTime = SDL_GetTicks();
1788 d->tapCount = 0;
1789 d->cursor = touchCoordCursor_InputWidget_(d, pos_Click(&d->click));
1790 showCursor_InputWidget_(d);
1791 }
1792 else if (!isEmpty_Range(&d->mark) && !isMoved_Click(&d->click)) {
1793 if (isInsideMark_InputWidget_(d, cursorToIndex_InputWidget_(d, touchCoordCursor_InputWidget_(d, latestPosition_Touch())))) {
1794 showClipMenu_(latestPosition_Touch());
1795 }
1796 else {
1797 iZap(d->mark);
1798 d->cursor = touchCoordCursor_InputWidget_(d, pos_Click(&d->click));
1799 }
1800 }
1801 else if (SDL_GetTicks() - d->lastTapTime > 1000 &&
1802 d->tapCount == 0 && isEmpty_Range(&d->mark) && !isMoved_Click(&d->click) &&
1803 distanceToPos_InputWidget_(d, latestPosition_Touch(), d->cursor) < gap_UI * 5) {
1804 showClipMenu_(latestPosition_Touch());
1805 }
1806 else {
1807 if (~d->inFlags & isMarking_InputWidgetFlag) {
1808 iZap(d->mark);
1809 d->cursor = touchCoordCursor_InputWidget_(d, pos_Click(&d->click));
1810 }
1811 }
1812 if (d->inFlags & (dragCursor_InputWidgetFlag | dragMarkerStart_InputWidgetFlag |
1813 dragMarkerEnd_InputWidgetFlag)) {
1814 printf("[%p] finished cursor/marker drag\n", w);
1815 d->inFlags &= ~(dragCursor_InputWidgetFlag |
1816 dragMarkerStart_InputWidgetFlag |
1817 dragMarkerEnd_InputWidgetFlag);
1818 setFlags_Widget(w, touchDrag_WidgetFlag, iFalse);
1819 }
1820 d->inFlags &= ~isMarking_InputWidgetFlag;
1821 showCursor_InputWidget_(d);
1822 refresh_Widget(w);
1823#if 0
1824 d->inFlags &= ~touchBehavior_InputWidgetFlag;
1825 if (flags_Widget(w) & touchDrag_WidgetFlag) {
1826 setFlags_Widget(w, touchDrag_WidgetFlag, iFalse);
1827 return true_EventResult;
1828 }
1829 if (!isMoved_Click(&d->click)) {
1830 if (!isFocused_Widget(w)) {
1831 setFocus_Widget(w);
1832 if (~d->inFlags & selectAllOnFocus_InputWidgetFlag) {
1833 d->cursor = coordCursor_InputWidget_(d, pos_Click(&d->click));
1834 showCursor_InputWidget_(d);
1835 }
1836 }
1837 else {
1838 iZap(d->mark);
1839 d->cursor = coordCursor_InputWidget_(d, pos_Click(&d->click));
1840 showCursor_InputWidget_(d);
1841 }
1842 }
1843#endif
1844 return true_EventResult;
1845 }
1846#endif
1847// if ((ev->type == SDL_MOUSEBUTTONDOWN || ev->type == SDL_MOUSEBUTTONUP) &&
1848// contains_Widget(w, init_I2(ev->button.x, ev->button.y))) {
1849// /* Eat all mouse clicks on the widget. */
1850// return true_EventResult;
1851// }
1852 return ignored_EventResult;
1853}
1854
1855static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1856 iWidget *w = as_Widget(d);
1857 /* Resize according to width immediately. */
1858 if (d->lastUpdateWidth != w->rect.size.x) {
1859 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1860 if (d->inFlags & isUrl_InputWidgetFlag) {
1861 /* Restore/omit the default scheme if necessary. */
1862 setText_InputWidget(d, text_InputWidget(d));
1638 } 1863 }
1864 updateAllLinesAndResizeHeight_InputWidget_(d);
1865 d->lastUpdateWidth = w->rect.size.x;
1866 }
1867 if (isCommand_Widget(w, ev, "focus.gained")) {
1868 begin_InputWidget(d);
1869 return iFalse;
1870 }
1871 else if (isEditing_InputWidget_(d) && (isCommand_UserEvent(ev, "window.focus.lost") ||
1872 isCommand_UserEvent(ev, "window.focus.gained"))) {
1873 startOrStopCursorTimer_InputWidget_(d, isCommand_UserEvent(ev, "window.focus.gained"));
1874 d->cursorVis = 1;
1875 refresh_Widget(d);
1876 return iFalse;
1877 }
1878 else if (isCommand_UserEvent(ev, "keyroot.changed")) {
1879 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1880 }
1881 else if (isCommand_UserEvent(ev, "lang.changed")) {
1882 set_String(&d->hint, &d->srcHint);
1883 translate_Lang(&d->hint);
1884 return iFalse;
1885 }
1886 else if (isCommand_Widget(w, ev, "focus.lost")) {
1887 end_InputWidget(d, iTrue);
1888 return iFalse;
1889 }
1890 else if ((isCommand_UserEvent(ev, "copy") || isCommand_UserEvent(ev, "input.copy")) &&
1891 isEditing_InputWidget_(d)) {
1892 copy_InputWidget_(d, argLabel_Command(command_UserEvent(ev), "cut"));
1893 return iTrue;
1894 }
1895 else if (isCommand_UserEvent(ev, "input.paste") && isEditing_InputWidget_(d)) {
1896 paste_InputWidget_(d);
1639 return iTrue; 1897 return iTrue;
1640 } 1898 }
1899 else if (isCommand_UserEvent(ev, "theme.changed")) {
1900 if (d->buffered) {
1901 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1902 }
1903 return iFalse;
1904 }
1905// else if (isCommand_UserEvent(ev, "keyboard.changed")) {
1906// if (isFocused_Widget(d) && arg_Command(command_UserEvent(ev))) {
1907// iRect rect = bounds_Widget(w);
1908// rect.pos.y -= value_Anim(&get_Window()->rootOffset);
1909// const iInt2 visRoot = visibleSize_Root(w->root);
1910// if (bottom_Rect(rect) > visRoot.y) {
1911// setValue_Anim(&get_Window()->rootOffset, -(bottom_Rect(rect) - visRoot.y), 250);
1912// }
1913// }
1914// return iFalse;
1915// }
1916 else if (isCommand_UserEvent(ev, "text.insert")) {
1917 pushUndo_InputWidget_(d);
1918 deleteMarked_InputWidget_(d);
1919 insertChar_InputWidget_(d, arg_Command(command_UserEvent(ev)));
1920 contentsWereChanged_InputWidget_(d);
1921 return iTrue;
1922 }
1923 else if (isCommand_Widget(w, ev, "input.backup")) {
1924 if (d->inFlags & needBackup_InputWidgetFlag) {
1925 saveBackup_InputWidget_(d);
1926 }
1927 return iTrue;
1928 }
1929 else if (isMetricsChange_UserEvent(ev)) {
1930 updateMetrics_InputWidget_(d);
1931 // updateLinesAndResize_InputWidget_(d);
1932 }
1933 else if (isFocused_Widget(d) && isCommand_UserEvent(ev, "copy")) {
1934 copy_InputWidget_(d, iFalse);
1935 return iTrue;
1936 }
1937 /* Click behavior depends on device type. */ {
1938 const int mbResult = (deviceType_App() == desktop_AppDeviceType
1939 ? processPointerEvents_InputWidget_(d, ev)
1940 : processTouchEvents_InputWidget_(d, ev));
1941 if (mbResult) {
1942 return mbResult >> 1;
1943 }
1944 }
1641 if (ev->type == SDL_KEYUP && isFocused_Widget(w)) { 1945 if (ev->type == SDL_KEYUP && isFocused_Widget(w)) {
1642 return iTrue; 1946 return iTrue;
1643 } 1947 }
@@ -1884,6 +2188,8 @@ struct Impl_MarkPainter {
1884 const iInputLine * line; 2188 const iInputLine * line;
1885 iInt2 pos; 2189 iInt2 pos;
1886 iRanges mark; 2190 iRanges mark;
2191 iRect firstMarkRect;
2192 iRect lastMarkRect;
1887}; 2193};
1888 2194
1889static iBool draw_MarkPainter_(iWrapText *wrapText, iRangecc wrappedText, int origin, int advance, 2195static iBool draw_MarkPainter_(iWrapText *wrapText, iRangecc wrappedText, int origin, int advance,
@@ -1922,7 +2228,11 @@ static iBool draw_MarkPainter_(iWrapText *wrapText, iRangecc wrappedText, int or
1922 } 2228 }
1923 rect.size.x = iMax(gap_UI / 3, rect.size.x); 2229 rect.size.x = iMax(gap_UI / 3, rect.size.x);
1924 mp->pos.y += lineHeight_Text(mp->d->font); 2230 mp->pos.y += lineHeight_Text(mp->d->font);
1925 fillRect_Paint(mp->paint, rect, uiMarked_ColorId); 2231 fillRect_Paint(mp->paint, rect, uiMarked_ColorId | opaque_ColorId);
2232 if (deviceType_App() != desktop_AppDeviceType) {
2233 if (isEmpty_Rect(mp->firstMarkRect)) mp->firstMarkRect = rect;
2234 mp->lastMarkRect = rect;
2235 }
1926 return iTrue; 2236 return iTrue;
1927} 2237}
1928 2238
@@ -1962,6 +2272,7 @@ static void draw_InputWidget_(const iInputWidget *d) {
1962 }; 2272 };
1963 const iRangei visLines = visibleLineRange_InputWidget_(d); 2273 const iRangei visLines = visibleLineRange_InputWidget_(d);
1964 const int visLineOffsetY = visLineOffsetY_InputWidget_(d); 2274 const int visLineOffsetY = visLineOffsetY_InputWidget_(d);
2275 iRect markerRects[2];
1965 /* If buffered, just draw the buffered copy. */ 2276 /* If buffered, just draw the buffered copy. */
1966 if (d->buffered && !isFocused) { 2277 if (d->buffered && !isFocused) {
1967 /* Most input widgets will use this, since only one is focused at a time. */ 2278 /* Most input widgets will use this, since only one is focused at a time. */
@@ -1977,7 +2288,7 @@ static void draw_InputWidget_(const iInputWidget *d) {
1977 .paint = &p, 2288 .paint = &p,
1978 .d = d, 2289 .d = d,
1979 .contentBounds = contentBounds, 2290 .contentBounds = contentBounds,
1980 .mark = mark_InputWidget_(d) 2291 .mark = mark_InputWidget_(d),
1981 }; 2292 };
1982 wrapText.context = &marker; 2293 wrapText.context = &marker;
1983 wrapText.wrapFunc = isFocused ? draw_MarkPainter_ : NULL; /* mark is drawn under each line of text */ 2294 wrapText.wrapFunc = isFocused ? draw_MarkPainter_ : NULL; /* mark is drawn under each line of text */
@@ -1988,11 +2299,14 @@ static void draw_InputWidget_(const iInputWidget *d) {
1988 marker.pos = drawPos; 2299 marker.pos = drawPos;
1989 addv_I2(&drawPos, draw_WrapText(&wrapText, d->font, drawPos, fg).advance); /* lines end with \n */ 2300 addv_I2(&drawPos, draw_WrapText(&wrapText, d->font, drawPos, fg).advance); /* lines end with \n */
1990 } 2301 }
2302 markerRects[0] = marker.firstMarkRect;
2303 markerRects[1] = marker.lastMarkRect;
1991 wrapText.wrapFunc = NULL; 2304 wrapText.wrapFunc = NULL;
1992 wrapText.context = NULL; 2305 wrapText.context = NULL;
1993 } 2306 }
1994 /* Draw the insertion point. */ 2307 /* Draw the insertion point. */
1995 if (isFocused && d->cursorVis && contains_Range(&visLines, d->cursor.y)) { 2308 if (isFocused && d->cursorVis && contains_Range(&visLines, d->cursor.y) &&
2309 isEmpty_Range(&d->mark)) {
1996 iInt2 curSize; 2310 iInt2 curSize;
1997 iRangecc cursorChar = iNullRange; 2311 iRangecc cursorChar = iNullRange;
1998 int visWrapsAbove = 0; 2312 int visWrapsAbove = 0;
@@ -2040,6 +2354,11 @@ static void draw_InputWidget_(const iInputWidget *d) {
2040 } 2354 }
2041 } 2355 }
2042 unsetClip_Paint(&p); 2356 unsetClip_Paint(&p);
2357 if (!isEmpty_Rect(markerRects[0])) {
2358 for (int i = 0; i < 2; ++i) {
2359 drawPin_Paint(&p, markerRects[i], i, uiTextCaution_ColorId);
2360 }
2361 }
2043 drawChildren_Widget(w); 2362 drawChildren_Widget(w);
2044} 2363}
2045 2364
diff --git a/src/ui/paint.c b/src/ui/paint.c
index 71ebb81d..89de47d4 100644
--- a/src/ui/paint.c
+++ b/src/ui/paint.c
@@ -33,7 +33,8 @@ iLocalDef SDL_Renderer *renderer_Paint_(const iPaint *d) {
33 33
34static void setColor_Paint_(const iPaint *d, int color) { 34static void setColor_Paint_(const iPaint *d, int color) {
35 const iColor clr = get_Color(color & mask_ColorId); 35 const iColor clr = get_Color(color & mask_ColorId);
36 SDL_SetRenderDrawColor(renderer_Paint_(d), clr.r, clr.g, clr.b, clr.a * d->alpha / 255); 36 SDL_SetRenderDrawColor(renderer_Paint_(d), clr.r, clr.g, clr.b,
37 (color & opaque_ColorId ? 255 : clr.a) * d->alpha / 255);
37} 38}
38 39
39void init_Paint(iPaint *d) { 40void init_Paint(iPaint *d) {
@@ -186,6 +187,22 @@ void drawLines_Paint(const iPaint *d, const iInt2 *points, size_t n, int color)
186 free(offsetPoints); 187 free(offsetPoints);
187} 188}
188 189
190void drawPin_Paint(iPaint *d, iRect rangeRect, int dir, int pinColor) {
191 const int height = height_Rect(rangeRect);
192 iRect pin;
193 if (dir == 0) {
194 pin = (iRect){ add_I2(topLeft_Rect(rangeRect), init_I2(-gap_UI / 4, -gap_UI)),
195 init_I2(gap_UI / 2, height + gap_UI) };
196 }
197 else {
198 pin = (iRect){ addX_I2(topRight_Rect(rangeRect), -gap_UI / 4),
199 init_I2(gap_UI / 2, height + gap_UI) };
200 }
201 fillRect_Paint(d, pin, pinColor);
202 fillRect_Paint(d, initCentered_Rect(dir == 0 ? topMid_Rect(pin) : bottomMid_Rect(pin),
203 init1_I2(gap_UI * 2)), pinColor);
204}
205
189iInt2 size_SDLTexture(SDL_Texture *d) { 206iInt2 size_SDLTexture(SDL_Texture *d) {
190 iInt2 size; 207 iInt2 size;
191 SDL_QueryTexture(d, NULL, NULL, &size.x, &size.y); 208 SDL_QueryTexture(d, NULL, NULL, &size.x, &size.y);
diff --git a/src/ui/paint.h b/src/ui/paint.h
index e6701635..e894b62f 100644
--- a/src/ui/paint.h
+++ b/src/ui/paint.h
@@ -63,4 +63,6 @@ iLocalDef void drawVLine_Paint(const iPaint *d, iInt2 pos, int len, int color) {
63 drawLine_Paint(d, pos, addY_I2(pos, len), color); 63 drawLine_Paint(d, pos, addY_I2(pos, len), color);
64} 64}
65 65
66void drawPin_Paint (iPaint *, iRect rangeRect, int dir, int pinColor);
67
66iInt2 size_SDLTexture (SDL_Texture *); 68iInt2 size_SDLTexture (SDL_Texture *);
diff --git a/src/ui/root.c b/src/ui/root.c
index 59f98aa4..91f9fbb3 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -1401,23 +1401,38 @@ void createUserInterface_Root(iRoot *d) {
1401 { "${menu.closetab.other}", 0, 0, "tabs.close toleft:1 toright:1" }, 1401 { "${menu.closetab.other}", 0, 0, "tabs.close toleft:1 toright:1" },
1402 { barLeftArrow_Icon " ${menu.closetab.left}", 0, 0, "tabs.close toleft:1" }, 1402 { barLeftArrow_Icon " ${menu.closetab.left}", 0, 0, "tabs.close toleft:1" },
1403 { barRightArrow_Icon " ${menu.closetab.right}", 0, 0, "tabs.close toright:1" }, 1403 { barRightArrow_Icon " ${menu.closetab.right}", 0, 0, "tabs.close toright:1" },
1404 }, 1404 },
1405 6); 1405 6);
1406 iWidget *barMenu = 1406 iWidget *barMenu =
1407 makeMenu_Widget(root, 1407 makeMenu_Widget(root,
1408 (iMenuItem[]){ 1408 (iMenuItem[]){
1409 { leftHalf_Icon " ${menu.sidebar.left}", 0, 0, "sidebar.toggle" }, 1409 { leftHalf_Icon " ${menu.sidebar.left}", 0, 0, "sidebar.toggle" },
1410 { rightHalf_Icon " ${menu.sidebar.right}", 0, 0, "sidebar2.toggle" }, 1410 { rightHalf_Icon " ${menu.sidebar.right}", 0, 0, "sidebar2.toggle" },
1411 }, 1411 },
1412 deviceType_App() == phone_AppDeviceType ? 1 : 2); 1412 deviceType_App() == phone_AppDeviceType ? 1 : 2);
1413 iWidget *clipMenu = makeMenu_Widget(root, 1413 iWidget *clipMenu = makeMenu_Widget(root,
1414 (iMenuItem[]){ 1414#if defined (iPlatformMobile)
1415 { scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" }, 1415 (iMenuItem[]){
1416 { clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" }, 1416 { ">>>" scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" },
1417 { "---" }, 1417 { ">>>" clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" },
1418 { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" }, 1418 { ">>>" clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" },
1419 }, 1419 { "---" },
1420 4); 1420 { ">>>" delete_Icon " " uiTextCaution_ColorEscape "${menu.delete}", 0, 0, "input.delete" },
1421 { ">>>" select_Icon " ${menu.selectall}", 0, 0, "input.selectall" },
1422 { ">>>" undo_Icon " ${menu.undo}", 0, 0, "input.undo" },
1423 }, 7);
1424#else
1425 (iMenuItem[]){
1426 { scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" },
1427 { clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" },
1428 { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" },
1429 { "---" },
1430 { delete_Icon " " uiTextCaution_ColorEscape "${menu.delete}", 0, 0, "input.delete" },
1431 { undo_Icon " ${menu.undo}", 0, 0, "input.undo" },
1432 { "---" },
1433 { select_Icon " ${menu.selectall}", 0, 0, "input.selectall" },
1434 }, 8);
1435#endif
1421 iWidget *splitMenu = makeMenu_Widget(root, (iMenuItem[]){ 1436 iWidget *splitMenu = makeMenu_Widget(root, (iMenuItem[]){
1422 { "${menu.split.merge}", '1', 0, "ui.split arg:0" }, 1437 { "${menu.split.merge}", '1', 0, "ui.split arg:0" },
1423 { "${menu.split.swap}", SDLK_x, 0, "ui.split swap:1" }, 1438 { "${menu.split.swap}", SDLK_x, 0, "ui.split swap:1" },
diff --git a/src/ui/touch.c b/src/ui/touch.c
index 5fc8f245..61882739 100644
--- a/src/ui/touch.c
+++ b/src/ui/touch.c
@@ -293,6 +293,7 @@ static void update_TouchState_(void *ptr) {
293 } 293 }
294 if (elapsed > 50 && !touch->isTapBegun) { 294 if (elapsed > 50 && !touch->isTapBegun) {
295 /* Looks like a possible tap. */ 295 /* Looks like a possible tap. */
296 touchState_()->currentTouchPos = initF3_I2(touch->pos[0]);
296 dispatchNotification_Touch_(touch, widgetTapBegins_UserEventCode); 297 dispatchNotification_Touch_(touch, widgetTapBegins_UserEventCode);
297 dispatchMotion_Touch_(touch->pos[0], 0); 298 dispatchMotion_Touch_(touch->pos[0], 0);
298 refresh_Widget(touch->affinity); 299 refresh_Widget(touch->affinity);
@@ -471,13 +472,13 @@ iBool processEvent_Touch(const SDL_Event *ev) {
471 } 472 }
472 iTouchState *d = touchState_(); 473 iTouchState *d = touchState_();
473 iWindow *window = get_Window(); 474 iWindow *window = get_Window();
474 if (!isFinished_Anim(&window->rootOffset)) { 475// if (!isFinished_Anim(&window->rootOffset)) {
475 return iFalse; 476// return iFalse;
476 } 477// }
477 const iInt2 rootSize = size_Window(window); 478 const iInt2 rootSize = size_Window(window);
478 const SDL_TouchFingerEvent *fing = &ev->tfinger; 479 const SDL_TouchFingerEvent *fing = &ev->tfinger;
479 const iFloat3 pos = add_F3(init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0), /* pixels */ 480 const iFloat3 pos = add_F3(init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0), /* pixels */
480 init_F3(0, -value_Anim(&window->rootOffset), 0)); 481 init_F3(0, 0 /*-value_Anim(&window->rootOffset)*/, 0));
481 const uint32_t nowTime = SDL_GetTicks(); 482 const uint32_t nowTime = SDL_GetTicks();
482 if (ev->type == SDL_FINGERDOWN) { 483 if (ev->type == SDL_FINGERDOWN) {
483 /* Register the new touch. */ 484 /* Register the new touch. */
diff --git a/src/ui/util.c b/src/ui/util.c
index 48ed41a6..cfa8152c 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -706,23 +706,36 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {
706 setFrameColor_Widget(menu, uiSeparator_ColorId); 706 setFrameColor_Widget(menu, uiSeparator_ColorId);
707 } 707 }
708 iBool haveIcons = iFalse; 708 iBool haveIcons = iFalse;
709 iWidget *horizGroup = NULL;
709 for (size_t i = 0; i < n; ++i) { 710 for (size_t i = 0; i < n; ++i) {
710 const iMenuItem *item = &items[i]; 711 const iMenuItem *item = &items[i];
711 if (!item->label) { 712 if (!item->label) {
712 break; 713 break;
713 } 714 }
714 if (equal_CStr(item->label, "---")) { 715 const char *labelText = item->label;
716 if (!startsWith_CStr(labelText, ">>>")) {
717 horizGroup = NULL;
718 }
719 if (equal_CStr(labelText, "---")) {
715 addChild_Widget(menu, iClob(makeMenuSeparator_())); 720 addChild_Widget(menu, iClob(makeMenuSeparator_()));
716 } 721 }
717 else { 722 else {
718 iBool isInfo = iFalse; 723 iBool isInfo = iFalse;
719 const char *labelText = item->label; 724 if (startsWith_CStr(labelText, ">>>")) {
725 labelText += 3;
726 if (!horizGroup) {
727 horizGroup = makeHDiv_Widget();
728 setFlags_Widget(horizGroup, resizeHeightOfChildren_WidgetFlag, iFalse);
729 setFlags_Widget(horizGroup, arrangeHeight_WidgetFlag, iTrue);
730 addChild_Widget(menu, iClob(horizGroup));
731 }
732 }
720 if (startsWith_CStr(labelText, "```")) { 733 if (startsWith_CStr(labelText, "```")) {
721 labelText += 3; 734 labelText += 3;
722 isInfo = iTrue; 735 isInfo = iTrue;
723 } 736 }
724 iLabelWidget *label = addChildFlags_Widget( 737 iLabelWidget *label = addChildFlags_Widget(
725 menu, 738 horizGroup ? horizGroup : menu,
726 iClob(newKeyMods_LabelWidget(labelText, item->key, item->kmods, item->command)), 739 iClob(newKeyMods_LabelWidget(labelText, item->key, item->kmods, item->command)),
727 noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag | 740 noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag |
728 drawKey_WidgetFlag | itemFlags); 741 drawKey_WidgetFlag | itemFlags);
@@ -766,6 +779,34 @@ void openMenu_Widget(iWidget *d, iInt2 windowCoord) {
766 openMenuFlags_Widget(d, windowCoord, iTrue); 779 openMenuFlags_Widget(d, windowCoord, iTrue);
767} 780}
768 781
782static void updateMenuItemFonts_Widget_(iWidget *d) {
783 const iBool isPortraitPhone = (deviceType_App() == phone_AppDeviceType && isPortrait_App());
784 const iBool isSlidePanel = (flags_Widget(d) & horizontalOffset_WidgetFlag) != 0;
785 iForEach(ObjectList, i, children_Widget(d)) {
786 if (isInstance_Object(i.object, &Class_LabelWidget)) {
787 iLabelWidget *label = i.object;
788 const iBool isCaution = startsWith_String(text_LabelWidget(label), uiTextCaution_ColorEscape);
789 if (isWrapped_LabelWidget(label)) {
790 continue;
791 }
792 if (deviceType_App() == desktop_AppDeviceType) {
793 setFont_LabelWidget(label, isCaution ? uiLabelBold_FontId : uiLabel_FontId);
794 }
795 else if (isPortraitPhone) {
796 if (!isSlidePanel) {
797 setFont_LabelWidget(label, isCaution ? defaultBigBold_FontId : defaultBig_FontId);
798 }
799 }
800 else {
801 setFont_LabelWidget(label, isCaution ? uiContentBold_FontId : uiContent_FontId);
802 }
803 }
804 else if (childCount_Widget(i.object)) {
805 updateMenuItemFonts_Widget_(i.object);
806 }
807 }
808}
809
769void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) { 810void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) {
770 const iRect rootRect = rect_Root(d->root); 811 const iRect rootRect = rect_Root(d->root);
771 const iInt2 rootSize = rootRect.size; 812 const iInt2 rootSize = rootRect.size;
@@ -788,28 +829,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) {
788 } 829 }
789 d->rect.size.x = rootSize.x; 830 d->rect.size.x = rootSize.x;
790 } 831 }
791 /* Update item fonts. */ { 832 updateMenuItemFonts_Widget_(d);
792 iForEach(ObjectList, i, children_Widget(d)) {
793 if (isInstance_Object(i.object, &Class_LabelWidget)) {
794 iLabelWidget *label = i.object;
795 const iBool isCaution = startsWith_String(text_LabelWidget(label), uiTextCaution_ColorEscape);
796 if (isWrapped_LabelWidget(label)) {
797 continue;
798 }
799 if (deviceType_App() == desktop_AppDeviceType) {
800 setFont_LabelWidget(label, isCaution ? uiLabelBold_FontId : uiLabel_FontId);
801 }
802 else if (isPortraitPhone) {
803 if (!isSlidePanel) {
804 setFont_LabelWidget(label, isCaution ? defaultBigBold_FontId : defaultBig_FontId);
805 }
806 }
807 else {
808 setFont_LabelWidget(label, isCaution ? uiContentBold_FontId : uiContent_FontId);
809 }
810 }
811 }
812 }
813 arrange_Widget(d); 833 arrange_Widget(d);
814 if (isPortraitPhone) { 834 if (isPortraitPhone) {
815 if (isSlidePanel) { 835 if (isSlidePanel) {
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 0765bf9f..1c0fb271 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -880,9 +880,9 @@ iInt2 localToWindow_Widget(const iWidget *d, iInt2 localCoord) {
880 applyVisualOffset_Widget_(w, &pos); 880 applyVisualOffset_Widget_(w, &pos);
881 addv_I2(&window, pos); 881 addv_I2(&window, pos);
882 } 882 }
883#if defined (iPlatformMobile) 883//#if defined (iPlatformMobile)
884 window.y += value_Anim(&get_Window()->rootOffset); 884// window.y += value_Anim(&get_Window()->rootOffset);
885#endif 885//#endif
886 return window; 886 return window;
887} 887}
888 888
@@ -1072,23 +1072,33 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {
1072} 1072}
1073 1073
1074iBool scrollOverflow_Widget(iWidget *d, int delta) { 1074iBool scrollOverflow_Widget(iWidget *d, int delta) {
1075 iRect bounds = boundsWithoutVisualOffset_Widget(d); 1075 iRect bounds = boundsWithoutVisualOffset_Widget(d);
1076 const iInt2 rootSize = size_Root(d->root); 1076// const iInt2 rootSize = size_Root(d->root);
1077 const iRect winRect = safeRect_Root(d->root); 1077 const iRect winRect = adjusted_Rect(safeRect_Root(d->root),
1078 const int yTop = top_Rect(winRect); 1078 zero_I2(),
1079 const int yBottom = bottom_Rect(winRect); 1079 init_I2(0, -get_Window()->keyboardHeight));
1080 const int yTop = top_Rect(winRect);
1081 const int yBottom = bottom_Rect(winRect);
1080 if (top_Rect(bounds) >= yTop && bottom_Rect(bounds) < yBottom) { 1082 if (top_Rect(bounds) >= yTop && bottom_Rect(bounds) < yBottom) {
1081 return iFalse; /* fits inside just fine */ 1083 return iFalse; /* fits inside just fine */
1082 } 1084 }
1083 //const int safeBottom = rootSize.y - yBottom; 1085 //const int safeBottom = rootSize.y - yBottom;
1084 bounds.pos.y += delta; 1086 iRangei validPosRange = { bottom_Rect(winRect) - height_Rect(bounds), yTop };
1085 const iRangei range = { bottom_Rect(winRect) - height_Rect(bounds), yTop }; 1087 if (validPosRange.start > validPosRange.end) {
1088 validPosRange.start = validPosRange.end; /* no room to scroll */
1089 }
1090 if (delta) {
1091 if (delta < 0 && bounds.pos.y < validPosRange.start) {
1092 delta = 0;
1093 }
1094 if (delta > 0 && bounds.pos.y > validPosRange.end) {
1095 delta = 0;
1096 }
1097 bounds.pos.y += delta;
1086// printf("range: %d ... %d\n", range.start, range.end); 1098// printf("range: %d ... %d\n", range.start, range.end);
1087 if (range.start >= range.end) {
1088 bounds.pos.y = range.end;
1089 } 1099 }
1090 else { 1100 else {
1091 bounds.pos.y = iClamp(bounds.pos.y, range.start, range.end); 1101 bounds.pos.y = iClamp(bounds.pos.y, validPosRange.start, validPosRange.end);
1092 } 1102 }
1093// if (delta >= 0) { 1103// if (delta >= 0) {
1094// bounds.pos.y = iMin(bounds.pos.y, yTop); 1104// bounds.pos.y = iMin(bounds.pos.y, yTop);
@@ -1454,7 +1464,7 @@ void setDrawBufferEnabled_Widget(iWidget *d, iBool enable) {
1454 1464
1455static void beginBufferDraw_Widget_(const iWidget *d) { 1465static void beginBufferDraw_Widget_(const iWidget *d) {
1456 if (d->drawBuf) { 1466 if (d->drawBuf) {
1457 printf("[%p] drawbuffer update %d\n", d, d->drawBuf->isValid); 1467// printf("[%p] drawbuffer update %d\n", d, d->drawBuf->isValid);
1458 if (d->drawBuf->isValid) { 1468 if (d->drawBuf->isValid) {
1459 iAssert(!isEqual_I2(d->drawBuf->size, boundsForDraw_Widget_(d).size)); 1469 iAssert(!isEqual_I2(d->drawBuf->size, boundsForDraw_Widget_(d).size));
1460// printf(" drawBuf:%dx%d boundsForDraw:%dx%d\n", 1470// printf(" drawBuf:%dx%d boundsForDraw:%dx%d\n",
@@ -1503,7 +1513,7 @@ void draw_Widget(const iWidget *d) {
1503 endBufferDraw_Widget_(d); 1513 endBufferDraw_Widget_(d);
1504 } 1514 }
1505 if (d->drawBuf) { 1515 if (d->drawBuf) {
1506 iAssert(d->drawBuf->isValid); 1516 //iAssert(d->drawBuf->isValid);
1507 const iRect bounds = bounds_Widget(d); 1517 const iRect bounds = bounds_Widget(d);
1508 SDL_RenderCopy(renderer_Window(get_Window()), d->drawBuf->texture, NULL, 1518 SDL_RenderCopy(renderer_Window(get_Window()), d->drawBuf->texture, NULL,
1509 &(SDL_Rect){ bounds.pos.x, bounds.pos.y, 1519 &(SDL_Rect){ bounds.pos.x, bounds.pos.y,
diff --git a/src/ui/window.c b/src/ui/window.c
index 8034d858..ed2ec024 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -421,7 +421,7 @@ void init_Window(iWindow *d, iRect rect) {
421 d->ignoreClick = iFalse; 421 d->ignoreClick = iFalse;
422 d->focusGainedAt = 0; 422 d->focusGainedAt = 0;
423 d->keyboardHeight = 0; 423 d->keyboardHeight = 0;
424 init_Anim(&d->rootOffset, 0.0f); 424// init_Anim(&d->rootOffset, 0.0f);
425 uint32_t flags = 0; 425 uint32_t flags = 0;
426#if defined (iPlatformAppleDesktop) 426#if defined (iPlatformAppleDesktop)
427 SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); 427 SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl");
@@ -1215,10 +1215,10 @@ iBool isOpenGLRenderer_Window(void) {
1215void setKeyboardHeight_Window(iWindow *d, int height) { 1215void setKeyboardHeight_Window(iWindow *d, int height) {
1216 if (d->keyboardHeight != height) { 1216 if (d->keyboardHeight != height) {
1217 d->keyboardHeight = height; 1217 d->keyboardHeight = height;
1218 if (height == 0) { 1218// if (height == 0) {
1219 setFlags_Anim(&d->rootOffset, easeBoth_AnimFlag, iTrue); 1219// setFlags_Anim(&d->rootOffset, easeBoth_AnimFlag, iTrue);
1220 setValue_Anim(&d->rootOffset, 0, 250); 1220// setValue_Anim(&d->rootOffset, 0, 250);
1221 } 1221// }
1222 postCommandf_App("keyboard.changed arg:%d", height); 1222 postCommandf_App("keyboard.changed arg:%d", height);
1223 postRefresh_App(); 1223 postRefresh_App();
1224 } 1224 }
diff --git a/src/ui/window.h b/src/ui/window.h
index 63f7e5f2..a5b8f137 100644
--- a/src/ui/window.h
+++ b/src/ui/window.h
@@ -98,7 +98,7 @@ struct Impl_Window {
98 SDL_Cursor * cursors[SDL_NUM_SYSTEM_CURSORS]; 98 SDL_Cursor * cursors[SDL_NUM_SYSTEM_CURSORS];
99 SDL_Cursor * pendingCursor; 99 SDL_Cursor * pendingCursor;
100 int loadAnimTimer; 100 int loadAnimTimer;
101 iAnim rootOffset; 101// iAnim rootOffset;
102 int keyboardHeight; /* mobile software keyboards */ 102 int keyboardHeight; /* mobile software keyboards */
103}; 103};
104 104