diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-05-13 22:28:43 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-05-13 22:28:43 +0300 |
commit | 713dcca5da21897fd8f5d7519112429273d7233e (patch) | |
tree | 1568d42480ada3f5f5b2b330df3af94ba335adcf /src/ui/inputwidget.c | |
parent | a6f255c4f14b253f251f167d3f6bfff0dc5d168b (diff) |
InputWidget: Drawing hint and buffered text
Improved TextBuf to handle word/bound-wrapped content.
Diffstat (limited to 'src/ui/inputwidget.c')
-rw-r--r-- | src/ui/inputwidget.c | 117 |
1 files changed, 72 insertions, 45 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 5f86f5bf..51447f21 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -455,31 +455,46 @@ void setContentPadding_InputWidget(iInputWidget *d, int left, int right) { | |||
455 | refresh_Widget(d); | 455 | refresh_Widget(d); |
456 | } | 456 | } |
457 | 457 | ||
458 | static iBool isHintVisible_InputWidget_(const iInputWidget *d) { | ||
459 | return !isEmpty_String(&d->hint) && size_Array(&d->lines) == 1 && | ||
460 | isEmpty_String(&line_InputWidget_(d, 0)->text); | ||
461 | } | ||
462 | |||
458 | static void updateBuffered_InputWidget_(iInputWidget *d) { | 463 | static void updateBuffered_InputWidget_(iInputWidget *d) { |
459 | invalidateBuffered_InputWidget_(d); | 464 | invalidateBuffered_InputWidget_(d); |
460 | iString *bufText = NULL; | 465 | if (isHintVisible_InputWidget_(d)) { |
466 | d->buffered = new_TextBuf(d->font, uiAnnotation_ColorId, cstr_String(&d->hint)); | ||
467 | } | ||
468 | else { | ||
469 | iString *bufText = NULL; | ||
461 | #if 0 | 470 | #if 0 |
462 | if (d->inFlags & isUrl_InputWidgetFlag && as_Widget(d)->root == win->keyRoot) { | 471 | if (d->inFlags & isUrl_InputWidgetFlag && as_Widget(d)->root == win->keyRoot) { |
463 | /* TODO: Move this omitting to `updateLines_`? */ | 472 | /* TODO: Move this omitting to `updateLines_`? */ |
464 | /* Highlight the host name. */ | 473 | /* Highlight the host name. */ |
465 | iUrl parts; | 474 | iUrl parts; |
466 | const iString *text = collect_String(utf32toUtf8_InputWidget_(d)); | 475 | const iString *text = collect_String(utf32toUtf8_InputWidget_(d)); |
467 | init_Url(&parts, text); | 476 | init_Url(&parts, text); |
468 | if (!isEmpty_Range(&parts.host)) { | 477 | if (!isEmpty_Range(&parts.host)) { |
469 | bufText = new_String(); | 478 | bufText = new_String(); |
470 | appendRange_String(bufText, (iRangecc){ constBegin_String(text), parts.host.start }); | 479 | appendRange_String(bufText, (iRangecc){ constBegin_String(text), parts.host.start }); |
471 | appendCStr_String(bufText, uiTextStrong_ColorEscape); | 480 | appendCStr_String(bufText, uiTextStrong_ColorEscape); |
472 | appendRange_String(bufText, parts.host); | 481 | appendRange_String(bufText, parts.host); |
473 | appendCStr_String(bufText, restore_ColorEscape); | 482 | appendCStr_String(bufText, restore_ColorEscape); |
474 | appendRange_String(bufText, (iRangecc){ parts.host.end, constEnd_String(text) }); | 483 | appendRange_String(bufText, (iRangecc){ parts.host.end, constEnd_String(text) }); |
484 | } | ||
475 | } | 485 | } |
476 | } | ||
477 | #endif | 486 | #endif |
478 | if (!bufText) { | 487 | if (!bufText) { |
479 | bufText = visText_InputWidget_(d); | 488 | bufText = visText_InputWidget_(d); |
489 | } | ||
490 | const int maxWidth = contentBounds_InputWidget_(d).size.x; | ||
491 | const int fg = uiInputText_ColorId; | ||
492 | const char *text = cstr_String(bufText); | ||
493 | d->buffered = | ||
494 | (d->inFlags & isUrl_InputWidgetFlag ? newBound_TextBuf(d->font, fg, maxWidth, text) | ||
495 | : newWrap_TextBuf (d->font, fg, maxWidth, text)); | ||
496 | delete_String(bufText); | ||
480 | } | 497 | } |
481 | d->buffered = new_TextBuf(d->font, uiInputText_ColorId, cstr_String(bufText)); | ||
482 | delete_String(bufText); | ||
483 | d->inFlags &= ~needUpdateBuffer_InputWidgetFlag; | 498 | d->inFlags &= ~needUpdateBuffer_InputWidgetFlag; |
484 | } | 499 | } |
485 | 500 | ||
@@ -707,6 +722,7 @@ void setSensitiveContent_InputWidget(iInputWidget *d, iBool isSensitive) { | |||
707 | 722 | ||
708 | void setUrlContent_InputWidget(iInputWidget *d, iBool isUrl) { | 723 | void setUrlContent_InputWidget(iInputWidget *d, iBool isUrl) { |
709 | iChangeFlags(d->inFlags, isUrl_InputWidgetFlag, isUrl); | 724 | iChangeFlags(d->inFlags, isUrl_InputWidgetFlag, isUrl); |
725 | d->inFlags |= needUpdateBuffer_InputWidgetFlag; | ||
710 | } | 726 | } |
711 | 727 | ||
712 | void setSelectAllOnFocus_InputWidget(iInputWidget *d, iBool selectAllOnFocus) { | 728 | void setSelectAllOnFocus_InputWidget(iInputWidget *d, iBool selectAllOnFocus) { |
@@ -963,6 +979,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
963 | updateLinesAndResize_InputWidget_(d); | 979 | updateLinesAndResize_InputWidget_(d); |
964 | } | 980 | } |
965 | else if (isResize_UserEvent(ev)) { | 981 | else if (isResize_UserEvent(ev)) { |
982 | d->inFlags |= needUpdateBuffer_InputWidgetFlag; | ||
966 | if (d->inFlags & isUrl_InputWidgetFlag) { | 983 | if (d->inFlags & isUrl_InputWidgetFlag) { |
967 | /* Restore/omit the default scheme if necessary. */ | 984 | /* Restore/omit the default scheme if necessary. */ |
968 | setText_InputWidget(d, text_InputWidget(d)); | 985 | setText_InputWidget(d, text_InputWidget(d)); |
@@ -1260,7 +1277,7 @@ static iBool isWhite_(const iString *str) { | |||
1260 | static void draw_InputWidget_(const iInputWidget *d) { | 1277 | static void draw_InputWidget_(const iInputWidget *d) { |
1261 | const iWidget *w = constAs_Widget(d); | 1278 | const iWidget *w = constAs_Widget(d); |
1262 | iRect bounds = adjusted_Rect(bounds_InputWidget_(d), padding_(), neg_I2(padding_())); | 1279 | iRect bounds = adjusted_Rect(bounds_InputWidget_(d), padding_(), neg_I2(padding_())); |
1263 | iBool isHint = iFalse; | 1280 | iBool isHint = isHintVisible_InputWidget_(d); |
1264 | const iBool isFocused = isFocused_Widget(w); | 1281 | const iBool isFocused = isFocused_Widget(w); |
1265 | const iBool isHover = isHover_Widget(w) && | 1282 | const iBool isHover = isHover_Widget(w) && |
1266 | contains_InputWidget_(d, mouseCoord_Window(get_Window())); | 1283 | contains_InputWidget_(d, mouseCoord_Window(get_Window())); |
@@ -1290,33 +1307,43 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
1290 | const int fg = isHint ? uiAnnotation_ColorId | 1307 | const int fg = isHint ? uiAnnotation_ColorId |
1291 | : isFocused && !isEmpty_Array(&d->text) ? uiInputTextFocused_ColorId | 1308 | : isFocused && !isEmpty_Array(&d->text) ? uiInputTextFocused_ColorId |
1292 | : uiInputText_ColorId; | 1309 | : uiInputText_ColorId; |
1293 | /* TODO: If buffered, just draw the buffered copy. */ | 1310 | /* If buffered, just draw the buffered copy. */ |
1294 | iConstForEach(Array, i, &d->lines) { | 1311 | if (d->buffered && !isFocused) { //&& !isFocused/* && !isHint*/) { |
1295 | const iInputLine *line = i.value; | 1312 | /* Most input widgets will use this, since only one is focused at a time. */ |
1296 | const iBool isLast = index_ArrayConstIterator(&i) == size_Array(&d->lines) - 1; | 1313 | draw_TextBuf(d->buffered, topLeft_Rect(contentBounds), white_ColorId); |
1297 | const iInputLine *nextLine = isLast ? NULL : (line + 1); | 1314 | } |
1298 | const iRanges lineRange = { line->offset, | 1315 | else if (isHint) { |
1299 | nextLine ? nextLine->offset : size_Array(&d->text) }; | 1316 | drawRange_Text(d->font, topLeft_Rect(contentBounds), uiAnnotation_ColorId, |
1300 | if (isFocused && !isEmpty_Range(&d->mark)) { | 1317 | range_String(&d->hint)); |
1301 | /* Draw the selected range. */ | 1318 | } |
1302 | const iRanges mark = mark_InputWidget_(d); | 1319 | else { |
1303 | if (mark.start < lineRange.end && mark.end > lineRange.start) { | 1320 | iConstForEach(Array, i, &d->lines) { |
1304 | const int m1 = advanceN_Text(d->font, | 1321 | const iInputLine *line = i.value; |
1305 | cstr_String(&line->text), | 1322 | const iBool isLast = index_ArrayConstIterator(&i) == size_Array(&d->lines) - 1; |
1306 | iMax(lineRange.start, mark.start) - line->offset) | 1323 | const iInputLine *nextLine = isLast ? NULL : (line + 1); |
1307 | .x; | 1324 | const iRanges lineRange = { line->offset, |
1308 | const int m2 = advanceN_Text(d->font, | 1325 | nextLine ? nextLine->offset : size_Array(&d->text) }; |
1309 | cstr_String(&line->text), | 1326 | if (isFocused && !isEmpty_Range(&d->mark)) { |
1310 | iMin(lineRange.end, mark.end) - line->offset) | 1327 | /* Draw the selected range. */ |
1311 | .x; | 1328 | const iRanges mark = mark_InputWidget_(d); |
1312 | fillRect_Paint(&p, | 1329 | if (mark.start < lineRange.end && mark.end > lineRange.start) { |
1313 | (iRect){ addX_I2(drawPos, iMin(m1, m2)), | 1330 | const int m1 = advanceN_Text(d->font, |
1314 | init_I2(iAbs(m2 - m1), lineHeight_Text(d->font)) }, | 1331 | cstr_String(&line->text), |
1315 | uiMarked_ColorId); | 1332 | iMax(lineRange.start, mark.start) - line->offset) |
1333 | .x; | ||
1334 | const int m2 = advanceN_Text(d->font, | ||
1335 | cstr_String(&line->text), | ||
1336 | iMin(lineRange.end, mark.end) - line->offset) | ||
1337 | .x; | ||
1338 | fillRect_Paint(&p, | ||
1339 | (iRect){ addX_I2(drawPos, iMin(m1, m2)), | ||
1340 | init_I2(iAbs(m2 - m1), lineHeight_Text(d->font)) }, | ||
1341 | uiMarked_ColorId); | ||
1342 | } | ||
1316 | } | 1343 | } |
1344 | drawRange_Text(d->font, drawPos, fg, range_String(&line->text)); | ||
1345 | drawPos.y += lineHeight_Text(d->font); | ||
1317 | } | 1346 | } |
1318 | drawRange_Text(d->font, drawPos, fg, range_String(&line->text)); | ||
1319 | drawPos.y += lineHeight_Text(d->font); | ||
1320 | } | 1347 | } |
1321 | // if (d->buffered && !isFocused && !isHint) { | 1348 | // if (d->buffered && !isFocused && !isHint) { |
1322 | // /* Most input widgets will use this, since only one is focused at a time. */ | 1349 | // /* Most input widgets will use this, since only one is focused at a time. */ |