summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ui/inputwidget.c117
-rw-r--r--src/ui/text.c51
-rw-r--r--src/ui/text.h7
3 files changed, 125 insertions, 50 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. */
diff --git a/src/ui/text.c b/src/ui/text.c
index aacc8d3d..6c9e23cb 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -1404,9 +1404,21 @@ iString *renderBlockChars_Text(const iBlock *fontData, int height, enum iTextBlo
1404 1404
1405iDefineTypeConstructionArgs(TextBuf, (int font, int color, const char *text), font, color, text) 1405iDefineTypeConstructionArgs(TextBuf, (int font, int color, const char *text), font, color, text)
1406 1406
1407void init_TextBuf(iTextBuf *d, int font, int color, const char *text) { 1407static void initWrap_TextBuf_(iTextBuf *d, int font, int color, int maxWidth, iBool doWrap, const char *text) {
1408 SDL_Renderer *render = text_.render; 1408 SDL_Renderer *render = text_.render;
1409 d->size = advance_Text(font, text); 1409 if (maxWidth == 0) {
1410 d->size = advance_Text(font, text);
1411 }
1412 else {
1413 d->size = zero_I2();
1414 iRangecc content = range_CStr(text);
1415 while (!isEmpty_Range(&content)) {
1416 const iInt2 size = (doWrap ? tryAdvance_Text(font, content, maxWidth, &content.start)
1417 : tryAdvanceNoWrap_Text(font, content, maxWidth, &content.start));
1418 d->size.x = iMax(d->size.x, size.x);
1419 d->size.y += size.y;
1420 }
1421 }
1410 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); 1422 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
1411 if (d->size.x * d->size.y) { 1423 if (d->size.x * d->size.y) {
1412 d->texture = SDL_CreateTexture(render, 1424 d->texture = SDL_CreateTexture(render,
@@ -1424,17 +1436,50 @@ void init_TextBuf(iTextBuf *d, int font, int color, const char *text) {
1424 SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */ 1436 SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */
1425 SDL_SetRenderDrawColor(text_.render, 0, 0, 0, 0); 1437 SDL_SetRenderDrawColor(text_.render, 0, 0, 0, 0);
1426 SDL_RenderClear(text_.render); 1438 SDL_RenderClear(text_.render);
1427 draw_Text_(font, zero_I2(), color | fillBackground_ColorId, range_CStr(text)); 1439 const int fg = color | fillBackground_ColorId;
1440 iRangecc range = range_CStr(text);
1441 if (maxWidth == 0) {
1442 draw_Text_(font, zero_I2(), fg, range);
1443 }
1444 else if (doWrap) {
1445 drawWrapRange_Text(font, zero_I2(), maxWidth, fg, range);
1446 }
1447 else {
1448 iInt2 pos = zero_I2();
1449 while (!isEmpty_Range(&range)) {
1450 const char *endp;
1451 tryAdvanceNoWrap_Text(font, range, maxWidth, &endp);
1452 draw_Text_(font, pos, fg, (iRangecc){ range.start, endp });
1453 range.start = endp;
1454 pos.y += lineHeight_Text(font);
1455 }
1456 }
1428 SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_BLEND); 1457 SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_BLEND);
1429 SDL_SetRenderTarget(render, oldTarget); 1458 SDL_SetRenderTarget(render, oldTarget);
1430 SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND); 1459 SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND);
1431 } 1460 }
1432} 1461}
1433 1462
1463void init_TextBuf(iTextBuf *d, int font, int color, const char *text) {
1464 initWrap_TextBuf_(d, font, color, 0, iFalse, text);
1465}
1466
1434void deinit_TextBuf(iTextBuf *d) { 1467void deinit_TextBuf(iTextBuf *d) {
1435 SDL_DestroyTexture(d->texture); 1468 SDL_DestroyTexture(d->texture);
1436} 1469}
1437 1470
1471iTextBuf *newBound_TextBuf(int font, int color, int boundWidth, const char *text) {
1472 iTextBuf *d = iMalloc(TextBuf);
1473 initWrap_TextBuf_(d, font, color, boundWidth, iFalse, text);
1474 return d;
1475}
1476
1477iTextBuf *newWrap_TextBuf(int font, int color, int wrapWidth, const char *text) {
1478 iTextBuf *d = iMalloc(TextBuf);
1479 initWrap_TextBuf_(d, font, color, wrapWidth, iTrue, text);
1480 return d;
1481}
1482
1438void draw_TextBuf(const iTextBuf *d, iInt2 pos, int color) { 1483void draw_TextBuf(const iTextBuf *d, iInt2 pos, int color) {
1439 const iColor clr = get_Color(color); 1484 const iColor clr = get_Color(color);
1440 SDL_SetTextureColorMod(d->texture, clr.r, clr.g, clr.b); 1485 SDL_SetTextureColorMod(d->texture, clr.r, clr.g, clr.b);
diff --git a/src/ui/text.h b/src/ui/text.h
index c6091599..044ddd32 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -170,10 +170,13 @@ iString * renderBlockChars_Text (const iBlock *fontData, int height, enum iT
170 170
171iDeclareType(TextBuf) 171iDeclareType(TextBuf)
172iDeclareTypeConstructionArgs(TextBuf, int font, int color, const char *text) 172iDeclareTypeConstructionArgs(TextBuf, int font, int color, const char *text)
173 173
174struct Impl_TextBuf { 174struct Impl_TextBuf {
175 SDL_Texture *texture; 175 SDL_Texture *texture;
176 iInt2 size; 176 iInt2 size;
177}; 177};
178 178
179void draw_TextBuf (const iTextBuf *, iInt2 pos, int color); 179iTextBuf * newBound_TextBuf(int font, int color, int boundWidth, const char *text); /* does not word wrap */
180iTextBuf * newWrap_TextBuf (int font, int color, int wrapWidth, const char *text);
181
182void draw_TextBuf (const iTextBuf *, iInt2 pos, int color);