summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c11
-rw-r--r--src/ui/inputwidget.c87
-rw-r--r--src/ui/text.c7
-rw-r--r--src/ui/uploadwidget.c2
-rw-r--r--src/ui/window.c34
5 files changed, 83 insertions, 58 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index a89eb0eb..3f655db5 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -1863,7 +1863,12 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
1863 updateTrust_DocumentWidget_(d, resp); 1863 updateTrust_DocumentWidget_(d, resp);
1864 init_Anim(&d->sideOpacity, 0); 1864 init_Anim(&d->sideOpacity, 0);
1865 init_Anim(&d->altTextOpacity, 0); 1865 init_Anim(&d->altTextOpacity, 0);
1866 format_String(&d->sourceHeader, "%d %s", statusCode, get_GmError(statusCode)->title); 1866 format_String(&d->sourceHeader,
1867 "%d %s",
1868 statusCode,
1869 isEmpty_String(&resp->meta) && !isSuccess_GmStatusCode(statusCode)
1870 ? get_GmError(statusCode)->title
1871 : cstr_String(&resp->meta));
1867 d->sourceStatus = statusCode; 1872 d->sourceStatus = statusCode;
1868 switch (category_GmStatusCode(statusCode)) { 1873 switch (category_GmStatusCode(statusCode)) {
1869 case categoryInput_GmStatusCode: { 1874 case categoryInput_GmStatusCode: {
@@ -2773,14 +2778,12 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2773 id_GmRequest(d->request) == argU32Label_Command(cmd, "reqid")) { 2778 id_GmRequest(d->request) == argU32Label_Command(cmd, "reqid")) {
2774 set_Block(&d->sourceContent, body_GmRequest(d->request)); 2779 set_Block(&d->sourceContent, body_GmRequest(d->request));
2775 if (!isSuccess_GmStatusCode(status_GmRequest(d->request))) { 2780 if (!isSuccess_GmStatusCode(status_GmRequest(d->request))) {
2781 /* TODO: Why is this here? Can it be removed? */
2776 format_String(&d->sourceHeader, 2782 format_String(&d->sourceHeader,
2777 "%d %s", 2783 "%d %s",
2778 status_GmRequest(d->request), 2784 status_GmRequest(d->request),
2779 cstr_String(meta_GmRequest(d->request))); 2785 cstr_String(meta_GmRequest(d->request)));
2780 } 2786 }
2781 else {
2782 clear_String(&d->sourceHeader);
2783 }
2784 updateFetchProgress_DocumentWidget_(d); 2787 updateFetchProgress_DocumentWidget_(d);
2785 checkResponse_DocumentWidget_(d); 2788 checkResponse_DocumentWidget_(d);
2786 if (category_GmStatusCode(status_GmRequest(d->request)) == categorySuccess_GmStatusCode) { 2789 if (category_GmStatusCode(status_GmRequest(d->request)) == categorySuccess_GmStatusCode) {
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index 9f233345..2f0cabbb 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -360,35 +360,64 @@ static int endX_InputWidget_(const iInputWidget *d, int y) {
360 return line->range.end - (isLastLine_InputWidget_(d, line) ? 0 : 1) - line->range.start; 360 return line->range.end - (isLastLine_InputWidget_(d, line) ? 0 : 1) - line->range.start;
361} 361}
362 362
363static iBool isCursorFocusable_Char_(iChar c) {
364 return !isDefaultIgnorable_Char(c) &&
365 !isVariationSelector_Char(c) &&
366 !isFitzpatrickType_Char(c);
367}
368
369static iChar at_InputWidget_(const iInputWidget *d, iInt2 pos) {
370 if (pos.y >= 0 && pos.y < size_Array(&d->lines) &&
371 pos.x >= 0 && pos.x <= endX_InputWidget_(d, pos.y)) {
372 iChar ch = 0;
373 decodeBytes_MultibyteChar(charPos_InputWidget_(d, pos),
374 constEnd_String(lineString_InputWidget_(d, pos.y)),
375 &ch);
376 return ch;
377 }
378 return ' ';
379}
380
363static iInt2 movedCursor_InputWidget_(const iInputWidget *d, iInt2 pos, int xDir, int yDir) { 381static iInt2 movedCursor_InputWidget_(const iInputWidget *d, iInt2 pos, int xDir, int yDir) {
364 iChar ch; 382 iChar ch = 0;
365 if (xDir < 0) { 383 int n = 0;
366 if (pos.x == 0) { 384 /* TODO: The cursor should never land on any combining codepoints either. */
367 if (pos.y > 0) { 385 for (;;) {
368 pos.x = endX_InputWidget_(d, --pos.y); 386 if (xDir < 0) {
387 if (pos.x == 0) {
388 if (pos.y > 0) {
389 pos.x = endX_InputWidget_(d, --pos.y);
390 }
369 } 391 }
370 } 392 else {
371 else { 393 iAssert(pos.x > 0);
372 iAssert(pos.x > 0); 394 n = decodePrecedingBytes_MultibyteChar(charPos_InputWidget_(d, pos),
373 int n = decodePrecedingBytes_MultibyteChar(charPos_InputWidget_(d, pos),
374 cstr_String(lineString_InputWidget_(d, pos.y)), 395 cstr_String(lineString_InputWidget_(d, pos.y)),
375 &ch); 396 &ch);
376 pos.x -= n; 397 pos.x -= n;
377 } 398 if (!isCursorFocusable_Char_(at_InputWidget_(d, pos))) {
378 } 399 continue;
379 else if (xDir > 0) { 400 }
380 if (pos.x == endX_InputWidget_(d, pos.y)) {
381 if (pos.y < size_Array(&d->lines) - 1) {
382 pos.y++;
383 pos.x = 0;
384 } 401 }
385 } 402 }
386 else { 403 else if (xDir > 0) {
387 int n = decodeBytes_MultibyteChar(charPos_InputWidget_(d, pos), 404 if (pos.x == endX_InputWidget_(d, pos.y)) {
405 if (pos.y < size_Array(&d->lines) - 1) {
406 pos.y++;
407 pos.x = 0;
408 }
409 }
410 else {
411 n = decodeBytes_MultibyteChar(charPos_InputWidget_(d, pos),
388 constEnd_String(lineString_InputWidget_(d, pos.y)), 412 constEnd_String(lineString_InputWidget_(d, pos.y)),
389 &ch); 413 &ch);
390 pos.x += n; 414 pos.x += n;
415 if (!isCursorFocusable_Char_(at_InputWidget_(d, pos))) {
416 continue;
417 }
418 }
391 } 419 }
420 break;
392 } 421 }
393 return pos; 422 return pos;
394} 423}
@@ -1026,7 +1055,9 @@ static void insertRange_InputWidget_(iInputWidget *d, iRangecc range) {
1026 cstr_String(&line->text) + d->cursor.x, constEnd_String(&line->text) 1055 cstr_String(&line->text) + d->cursor.x, constEnd_String(&line->text)
1027 }); 1056 });
1028 truncate_String(&line->text, d->cursor.x); 1057 truncate_String(&line->text, d->cursor.x);
1029 appendCStr_String(&line->text, "\n"); 1058 if (!endsWith_String(&line->text, "\n")) {
1059 appendCStr_String(&line->text, "\n");
1060 }
1030 insert_Array(&d->lines, ++d->cursor.y, &split); 1061 insert_Array(&d->lines, ++d->cursor.y, &split);
1031 d->cursor.x = 0; 1062 d->cursor.x = 0;
1032 } 1063 }
@@ -1059,6 +1090,8 @@ void setCursor_InputWidget(iInputWidget *d, iInt2 pos) {
1059 iAssert(!isEmpty_Array(&d->lines)); 1090 iAssert(!isEmpty_Array(&d->lines));
1060 pos.x = iClamp(pos.x, 0, endX_InputWidget_(d, pos.y)); 1091 pos.x = iClamp(pos.x, 0, endX_InputWidget_(d, pos.y));
1061 d->cursor = pos; 1092 d->cursor = pos;
1093 iChar ch = at_InputWidget_(d, pos);
1094 printf("cursor x:%d ch:%08x (%lc)\n", pos.x, ch, (int)ch);
1062 /* Update selection. */ 1095 /* Update selection. */
1063 if (isMarking_()) { 1096 if (isMarking_()) {
1064 if (isEmpty_Range(&d->mark)) { 1097 if (isEmpty_Range(&d->mark)) {
@@ -1221,18 +1254,6 @@ static iBool deleteMarked_InputWidget_(iInputWidget *d) {
1221 return iFalse; 1254 return iFalse;
1222} 1255}
1223 1256
1224static iChar at_InputWidget_(const iInputWidget *d, iInt2 pos) {
1225 if (pos.y >= 0 && pos.y < size_Array(&d->lines) &&
1226 pos.x >= 0 && pos.x <= endX_InputWidget_(d, pos.y)) {
1227 iChar ch = 0;
1228 decodeBytes_MultibyteChar(charPos_InputWidget_(d, pos),
1229 constEnd_String(lineString_InputWidget_(d, pos.y)),
1230 &ch);
1231 return ch;
1232 }
1233 return ' ';
1234}
1235
1236static iBool isWordChar_InputWidget_(const iInputWidget *d, iInt2 pos) { 1257static iBool isWordChar_InputWidget_(const iInputWidget *d, iInt2 pos) {
1237 return isAlphaNumeric_Char(at_InputWidget_(d, pos)); 1258 return isAlphaNumeric_Char(at_InputWidget_(d, pos));
1238} 1259}
diff --git a/src/ui/text.c b/src/ui/text.c
index 0a8386e4..639d8f13 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -1433,6 +1433,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1433 iBool isFirst = iTrue; 1433 iBool isFirst = iTrue;
1434 const iBool checkHitPoint = wrap && !isEqual_I2(wrap->hitPoint, zero_I2()); 1434 const iBool checkHitPoint = wrap && !isEqual_I2(wrap->hitPoint, zero_I2());
1435 const iBool checkHitChar = wrap && wrap->hitChar; 1435 const iBool checkHitChar = wrap && wrap->hitChar;
1436 iBool wasCharHit = iFalse;
1436 while (!isEmpty_Range(&wrapRuns)) { 1437 while (!isEmpty_Range(&wrapRuns)) {
1437 if (isFirst) { 1438 if (isFirst) {
1438 isFirst = iFalse; 1439 isFirst = iFalse;
@@ -1452,9 +1453,10 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1452 for (size_t runIndex = wrapRuns.start; runIndex < wrapRuns.end; runIndex++) { 1453 for (size_t runIndex = wrapRuns.start; runIndex < wrapRuns.end; runIndex++) {
1453 const iAttributedRun *run = at_Array(&attrText.runs, runIndex); 1454 const iAttributedRun *run = at_Array(&attrText.runs, runIndex);
1454 if (run->flags.isLineBreak) { 1455 if (run->flags.isLineBreak) {
1455 if (checkHitChar) { 1456 if (checkHitChar && !wasCharHit) {
1456 if (wrap->hitChar == sourcePtr_AttributedText_(&attrText, run->logical.start)) { 1457 if (wrap->hitChar == sourcePtr_AttributedText_(&attrText, run->logical.start)) {
1457 wrap->hitAdvance_out = init_I2(wrapAdvance, yCursor); 1458 wrap->hitAdvance_out = init_I2(wrapAdvance, yCursor);
1459 wasCharHit = iTrue;
1458 } 1460 }
1459 } 1461 }
1460 wrapPosRange.end = run->logical.start; 1462 wrapPosRange.end = run->logical.start;
@@ -1479,9 +1481,10 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1479 if (logPos < wrapPosRange.start || logPos >= wrapPosRange.end) { 1481 if (logPos < wrapPosRange.start || logPos >= wrapPosRange.end) {
1480 continue; 1482 continue;
1481 } 1483 }
1482 if (checkHitChar) { 1484 if (checkHitChar && !wasCharHit) {
1483 if (wrap->hitChar == sourcePtr_AttributedText_(&attrText, logPos)) { 1485 if (wrap->hitChar == sourcePtr_AttributedText_(&attrText, logPos)) {
1484 wrap->hitAdvance_out = init_I2(wrapAdvance, yCursor); 1486 wrap->hitAdvance_out = init_I2(wrapAdvance, yCursor);
1487 wasCharHit = iTrue;
1485 } 1488 }
1486 } 1489 }
1487 /* Check if the hit point is on the left side of this line. */ 1490 /* Check if the hit point is on the left side of this line. */
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c
index 57b6b6b7..5e1ee493 100644
--- a/src/ui/uploadwidget.c
+++ b/src/ui/uploadwidget.c
@@ -149,7 +149,7 @@ void init_UploadWidget(iUploadWidget *d) {
149 iWidget *buttons = 149 iWidget *buttons =
150 makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" }, 150 makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" },
151 { "---", 0, 0, NULL }, 151 { "---", 0, 0, NULL },
152 { "${cancel}", SDLK_ESCAPE, 0, "upload.cancel" }, 152 { "${close}", SDLK_ESCAPE, 0, "upload.cancel" },
153 { uiTextAction_ColorEscape "${dlg.upload.send}", 153 { uiTextAction_ColorEscape "${dlg.upload.send}",
154 SDLK_RETURN, 154 SDLK_RETURN,
155 KMOD_PRIMARY, 155 KMOD_PRIMARY,
diff --git a/src/ui/window.c b/src/ui/window.c
index 86d22b1c..1727b988 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -219,25 +219,23 @@ static void updateSize_Window_(iWindow *d, iBool notifyAlways) {
219 size->y -= d->keyboardHeight; 219 size->y -= d->keyboardHeight;
220 if (notifyAlways || !isEqual_I2(oldSize, *size)) { 220 if (notifyAlways || !isEqual_I2(oldSize, *size)) {
221 windowSizeChanged_Window_(d); 221 windowSizeChanged_Window_(d);
222 const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x); 222 if (!isEqual_I2(*size, d->place.lastNotifiedSize)) {
223 const iBool isVert = (d->place.lastNotifiedSize.y != size->y); 223 const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x);
224 postCommandf_App("window.resized width:%d height:%d horiz:%d vert:%d", 224 const iBool isVert = (d->place.lastNotifiedSize.y != size->y);
225 size->x, 225 postCommandf_App("window.resized width:%d height:%d horiz:%d vert:%d",
226 size->y, 226 size->x,
227 isHoriz, 227 size->y,
228 isVert); 228 isHoriz,
229 postCommand_App("widget.overflow"); /* check bounds with updated sizes */ 229 isVert);
230 postCommand_App("widget.overflow"); /* check bounds with updated sizes */
231 }
230 postRefresh_App(); 232 postRefresh_App();
231 d->place.lastNotifiedSize = *size; 233 d->place.lastNotifiedSize = *size;
232 } 234 }
233} 235}
234 236
235void drawWhileResizing_Window(iWindow *d, int w, int h) { 237void drawWhileResizing_Window(iWindow *d, int w, int h) {
236 /* This is called while a window resize is in progress, so we can be pretty confident 238 draw_Window(d);
237 the size has actually changed. */
238 d->size = coord_Window(d, w, h);
239 windowSizeChanged_Window_(d);
240 draw_Window(d);
241} 239}
242 240
243static float pixelRatio_Window_(const iWindow *d) { 241static float pixelRatio_Window_(const iWindow *d) {
@@ -489,7 +487,7 @@ void init_Window(iWindow *d, iRect rect) {
489 SDL_GetRendererOutputSize(d->render, &d->size.x, &d->size.y); 487 SDL_GetRendererOutputSize(d->render, &d->size.x, &d->size.y);
490 setupUserInterface_Window(d); 488 setupUserInterface_Window(d);
491 postCommand_App("~bindings.changed"); /* update from bindings */ 489 postCommand_App("~bindings.changed"); /* update from bindings */
492 updateSize_Window_(d, iFalse); 490 //updateSize_Window_(d, iFalse);
493 /* Load the border shadow texture. */ { 491 /* Load the border shadow texture. */ {
494 SDL_Surface *surf = loadImage_(&imageShadow_Embedded, 0); 492 SDL_Surface *surf = loadImage_(&imageShadow_Embedded, 0);
495 d->borderShadow = SDL_CreateTextureFromSurface(d->render, surf); 493 d->borderShadow = SDL_CreateTextureFromSurface(d->render, surf);
@@ -728,7 +726,7 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) {
728 } 726 }
729 case SDL_WINDOWEVENT_RESIZED: 727 case SDL_WINDOWEVENT_RESIZED:
730 if (d->isMinimized) { 728 if (d->isMinimized) {
731 updateSize_Window_(d, iTrue); 729 //updateSize_Window_(d, iTrue);
732 return iTrue; 730 return iTrue;
733 } 731 }
734 if (unsnap_Window_(d, NULL)) { 732 if (unsnap_Window_(d, NULL)) {
@@ -739,7 +737,7 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) {
739 //printf("normal rect set (resize)\n"); fflush(stdout); 737 //printf("normal rect set (resize)\n"); fflush(stdout);
740 } 738 }
741 checkPixelRatioChange_Window_(d); 739 checkPixelRatioChange_Window_(d);
742 updateSize_Window_(d, iTrue /* we were already redrawing during the resize */); 740 //updateSize_Window_(d, iTrue /* we were already redrawing during the resize */);
743 postRefresh_App(); 741 postRefresh_App();
744 return iTrue; 742 return iTrue;
745 case SDL_WINDOWEVENT_RESTORED: 743 case SDL_WINDOWEVENT_RESTORED:
@@ -1014,7 +1012,7 @@ void draw_Window(iWindow *d) {
1014 if (d->isDrawFrozen) { 1012 if (d->isDrawFrozen) {
1015 return; 1013 return;
1016 } 1014 }
1017#if defined (iPlatformMobile) 1015//#if defined (iPlatformMobile)
1018 /* Check if root needs resizing. */ { 1016 /* Check if root needs resizing. */ {
1019 iInt2 renderSize; 1017 iInt2 renderSize;
1020 SDL_GetRendererOutputSize(d->render, &renderSize.x, &renderSize.y); 1018 SDL_GetRendererOutputSize(d->render, &renderSize.x, &renderSize.y);
@@ -1023,7 +1021,7 @@ void draw_Window(iWindow *d) {
1023 processEvents_App(postedEventsOnly_AppEventMode); 1021 processEvents_App(postedEventsOnly_AppEventMode);
1024 } 1022 }
1025 } 1023 }
1026#endif 1024//#endif
1027 const int winFlags = SDL_GetWindowFlags(d->win); 1025 const int winFlags = SDL_GetWindowFlags(d->win);
1028 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0; 1026 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0;
1029 iPaint p; 1027 iPaint p;