summaryrefslogtreecommitdiff
path: root/src/ui/inputwidget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-05-13 22:28:43 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-05-13 22:28:43 +0300
commit713dcca5da21897fd8f5d7519112429273d7233e (patch)
tree1568d42480ada3f5f5b2b330df3af94ba335adcf /src/ui/inputwidget.c
parenta6f255c4f14b253f251f167d3f6bfff0dc5d168b (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.c117
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
458static 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
458static void updateBuffered_InputWidget_(iInputWidget *d) { 463static 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
708void setUrlContent_InputWidget(iInputWidget *d, iBool isUrl) { 723void 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
712void setSelectAllOnFocus_InputWidget(iInputWidget *d, iBool selectAllOnFocus) { 728void 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) {
1260static void draw_InputWidget_(const iInputWidget *d) { 1277static 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. */