mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 11:35:08 -04:00
Fix caret
This commit is contained in:
parent
3e8db412fd
commit
6d3c77db5d
244
src/LBackend.c
244
src/LBackend.c
@ -382,11 +382,128 @@ void LBackend_CheckboxDraw(struct LCheckbox* w) {
|
|||||||
/*########################################################################################################################*
|
/*########################################################################################################################*
|
||||||
*------------------------------------------------------InputWidget--------------------------------------------------------*
|
*------------------------------------------------------InputWidget--------------------------------------------------------*
|
||||||
*#########################################################################################################################*/
|
*#########################################################################################################################*/
|
||||||
|
static TimeMS caretStart;
|
||||||
|
static cc_bool lastCaretShow;
|
||||||
|
static Rect2D caretRect, lastCaretRect;
|
||||||
|
#define Rect2D_Equals(a, b) a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height
|
||||||
|
|
||||||
void LBackend_InputInit(struct LInput* w, int width) {
|
void LBackend_InputInit(struct LInput* w, int width) {
|
||||||
w->width = Display_ScaleX(width);
|
w->width = Display_ScaleX(width);
|
||||||
w->height = Display_ScaleY(30);
|
w->height = Display_ScaleY(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LBackend_InputUpdate(struct LInput* w) {
|
||||||
|
cc_string text; char textBuffer[STRING_SIZE];
|
||||||
|
struct DrawTextArgs args;
|
||||||
|
int textWidth;
|
||||||
|
|
||||||
|
String_InitArray(text, textBuffer);
|
||||||
|
LInput_UNSAFE_GetText(w, &text);
|
||||||
|
LBackend_MarkDirty(w);
|
||||||
|
|
||||||
|
DrawTextArgs_Make(&args, &text, &textFont, false);
|
||||||
|
textWidth = Drawer2D_TextWidth(&args);
|
||||||
|
w->width = max(w->minWidth, textWidth + inputExpand);
|
||||||
|
w->_textHeight = Drawer2D_TextHeight(&args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Rect2D LInput_MeasureCaret(struct LInput* w, cc_string* text) {
|
||||||
|
struct DrawTextArgs args;
|
||||||
|
Rect2D r;
|
||||||
|
DrawTextArgs_Make(&args, text, &textFont, true);
|
||||||
|
|
||||||
|
r.X = w->x + xInputOffset;
|
||||||
|
r.Y = w->y + w->height - caretOffset; r.Height = caretHeight;
|
||||||
|
|
||||||
|
if (w->caretPos == -1) {
|
||||||
|
r.X += Drawer2D_TextWidth(&args);
|
||||||
|
r.Width = caretWidth;
|
||||||
|
} else {
|
||||||
|
args.text = String_UNSAFE_Substring(text, 0, w->caretPos);
|
||||||
|
r.X += Drawer2D_TextWidth(&args);
|
||||||
|
|
||||||
|
args.text = String_UNSAFE_Substring(text, w->caretPos, 1);
|
||||||
|
r.Width = Drawer2D_TextWidth(&args);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LInput_MoveCaretToCursor(struct LInput* w, int idx) {
|
||||||
|
cc_string text; char textBuffer[STRING_SIZE];
|
||||||
|
int x = Pointers[idx].x, y = Pointers[idx].y;
|
||||||
|
struct DrawTextArgs args;
|
||||||
|
int i, charX, charWidth;
|
||||||
|
|
||||||
|
/* Input widget may have been selected by pressing tab */
|
||||||
|
/* In which case cursor is completely outside, so ignore */
|
||||||
|
if (!Gui_Contains(w->x, w->y, w->width, w->height, x, y)) return;
|
||||||
|
|
||||||
|
String_InitArray(text, textBuffer);
|
||||||
|
LInput_UNSAFE_GetText(w, &text);
|
||||||
|
x -= w->x; y -= w->y;
|
||||||
|
|
||||||
|
DrawTextArgs_Make(&args, &text, &textFont, true);
|
||||||
|
if (x >= Drawer2D_TextWidth(&args)) {
|
||||||
|
w->caretPos = -1; return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < text.length; i++) {
|
||||||
|
args.text = String_UNSAFE_Substring(&text, 0, i);
|
||||||
|
charX = Drawer2D_TextWidth(&args);
|
||||||
|
|
||||||
|
args.text = String_UNSAFE_Substring(&text, i, 1);
|
||||||
|
charWidth = Drawer2D_TextWidth(&args);
|
||||||
|
if (x >= charX && x < charX + charWidth) {
|
||||||
|
w->caretPos = i; return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LBackend_InputTick(struct LInput* w) {
|
||||||
|
int elapsed;
|
||||||
|
cc_bool caretShow;
|
||||||
|
Rect2D r;
|
||||||
|
|
||||||
|
if (!caretStart) return;
|
||||||
|
elapsed = (int)(DateTime_CurrentUTC_MS() - caretStart);
|
||||||
|
|
||||||
|
caretShow = (elapsed % 1000) < 500;
|
||||||
|
if (caretShow == w->caretShow) return;
|
||||||
|
w->caretShow = caretShow;
|
||||||
|
|
||||||
|
LBackend_InputDraw(w);
|
||||||
|
r = caretRect;
|
||||||
|
|
||||||
|
if (Rect2D_Equals(r, lastCaretRect)) {
|
||||||
|
/* Fast path, caret is blinking in same spot */
|
||||||
|
MarkAreaDirty(r.X, r.Y, r.Width, r.Height);
|
||||||
|
} else {
|
||||||
|
/* Slow path (new widget, caret moved, etc) */
|
||||||
|
MarkAreaDirty(w->x, w->y, w->width, w->height);
|
||||||
|
}
|
||||||
|
lastCaretRect = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LBackend_InputSelect(struct LInput* w, int idx, cc_bool wasSelected) {
|
||||||
|
struct OpenKeyboardArgs args;
|
||||||
|
caretStart = DateTime_CurrentUTC_MS();
|
||||||
|
w->caretShow = true;
|
||||||
|
LInput_MoveCaretToCursor(w, idx);
|
||||||
|
LBackend_MarkDirty(w);
|
||||||
|
|
||||||
|
if (wasSelected) return;
|
||||||
|
OpenKeyboardArgs_Init(&args, &w->text, w->inputType);
|
||||||
|
Window_OpenKeyboard(&args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LBackend_InputUnselect(struct LInput* w) {
|
||||||
|
caretStart = 0;
|
||||||
|
w->caretShow = false;
|
||||||
|
LBackend_MarkDirty(w);
|
||||||
|
Window_CloseKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void LInput_DrawOuterBorder(struct LInput* w) {
|
static void LInput_DrawOuterBorder(struct LInput* w) {
|
||||||
struct LScreen* s = Launcher_Active;
|
struct LScreen* s = Launcher_Active;
|
||||||
struct Bitmap* bmp = &framebuffer;
|
struct Bitmap* bmp = &framebuffer;
|
||||||
@ -458,21 +575,6 @@ static void LInput_DrawText(struct LInput* w, struct DrawTextArgs* args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LBackend_InputUpdate(struct LInput* w) {
|
|
||||||
cc_string text; char textBuffer[STRING_SIZE];
|
|
||||||
struct DrawTextArgs args;
|
|
||||||
int textWidth;
|
|
||||||
|
|
||||||
String_InitArray(text, textBuffer);
|
|
||||||
LInput_UNSAFE_GetText(w, &text);
|
|
||||||
LBackend_MarkDirty(w);
|
|
||||||
|
|
||||||
DrawTextArgs_Make(&args, &text, &textFont, false);
|
|
||||||
textWidth = Drawer2D_TextWidth(&args);
|
|
||||||
w->width = max(w->minWidth, textWidth + inputExpand);
|
|
||||||
w->_textHeight = Drawer2D_TextHeight(&args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LBackend_InputDraw(struct LInput* w) {
|
void LBackend_InputDraw(struct LInput* w) {
|
||||||
cc_string text; char textBuffer[STRING_SIZE];
|
cc_string text; char textBuffer[STRING_SIZE];
|
||||||
struct DrawTextArgs args;
|
struct DrawTextArgs args;
|
||||||
@ -491,115 +593,11 @@ void LBackend_InputDraw(struct LInput* w) {
|
|||||||
Drawer2D.Colors['f'] = Drawer2D.Colors['0'];
|
Drawer2D.Colors['f'] = Drawer2D.Colors['0'];
|
||||||
LInput_DrawText(w, &args);
|
LInput_DrawText(w, &args);
|
||||||
Drawer2D.Colors['f'] = Drawer2D.Colors['F'];
|
Drawer2D.Colors['f'] = Drawer2D.Colors['F'];
|
||||||
}
|
|
||||||
|
|
||||||
|
caretRect = LInput_MeasureCaret(w, &text);
|
||||||
static TimeMS caretStart;
|
if (!w->caretShow) return;
|
||||||
static cc_bool lastCaretShow;
|
Drawer2D_Clear(&framebuffer, BITMAPCOL_BLACK,
|
||||||
static Rect2D lastCaretRec;
|
caretRect.X, caretRect.Y, caretRect.Width, caretRect.Height);
|
||||||
#define Rect2D_Equals(a, b) a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height
|
|
||||||
|
|
||||||
static Rect2D LInput_MeasureCaret(struct LInput* w) {
|
|
||||||
cc_string text; char textBuffer[STRING_SIZE];
|
|
||||||
struct DrawTextArgs args;
|
|
||||||
Rect2D r;
|
|
||||||
|
|
||||||
String_InitArray(text, textBuffer);
|
|
||||||
LInput_UNSAFE_GetText(w, &text);
|
|
||||||
DrawTextArgs_Make(&args, &text, &textFont, true);
|
|
||||||
|
|
||||||
r.X = w->x + xInputOffset;
|
|
||||||
r.Y = w->y + w->height - caretOffset; r.Height = caretHeight;
|
|
||||||
|
|
||||||
if (w->caretPos == -1) {
|
|
||||||
r.X += Drawer2D_TextWidth(&args);
|
|
||||||
r.Width = caretWidth;
|
|
||||||
} else {
|
|
||||||
args.text = String_UNSAFE_Substring(&text, 0, w->caretPos);
|
|
||||||
r.X += Drawer2D_TextWidth(&args);
|
|
||||||
|
|
||||||
args.text = String_UNSAFE_Substring(&text, w->caretPos, 1);
|
|
||||||
r.Width = Drawer2D_TextWidth(&args);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void LInput_MoveCaretToCursor(struct LInput* w, int idx) {
|
|
||||||
cc_string text; char textBuffer[STRING_SIZE];
|
|
||||||
int x = Pointers[idx].x, y = Pointers[idx].y;
|
|
||||||
struct DrawTextArgs args;
|
|
||||||
int i, charX, charWidth;
|
|
||||||
|
|
||||||
/* Input widget may have been selected by pressing tab */
|
|
||||||
/* In which case cursor is completely outside, so ignore */
|
|
||||||
if (!Gui_Contains(w->x, w->y, w->width, w->height, x, y)) return;
|
|
||||||
lastCaretShow = false;
|
|
||||||
|
|
||||||
String_InitArray(text, textBuffer);
|
|
||||||
LInput_UNSAFE_GetText(w, &text);
|
|
||||||
x -= w->x; y -= w->y;
|
|
||||||
|
|
||||||
DrawTextArgs_Make(&args, &text, &textFont, true);
|
|
||||||
if (x >= Drawer2D_TextWidth(&args)) {
|
|
||||||
w->caretPos = -1; return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < text.length; i++) {
|
|
||||||
args.text = String_UNSAFE_Substring(&text, 0, i);
|
|
||||||
charX = Drawer2D_TextWidth(&args);
|
|
||||||
|
|
||||||
args.text = String_UNSAFE_Substring(&text, i, 1);
|
|
||||||
charWidth = Drawer2D_TextWidth(&args);
|
|
||||||
if (x >= charX && x < charX + charWidth) {
|
|
||||||
w->caretPos = i; return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LBackend_InputTick(struct LInput* w) {
|
|
||||||
int elapsed;
|
|
||||||
cc_bool caretShow;
|
|
||||||
Rect2D r;
|
|
||||||
|
|
||||||
if (!caretStart) return;
|
|
||||||
elapsed = (int)(DateTime_CurrentUTC_MS() - caretStart);
|
|
||||||
|
|
||||||
caretShow = (elapsed % 1000) < 500;
|
|
||||||
if (caretShow == lastCaretShow) return;
|
|
||||||
lastCaretShow = caretShow;
|
|
||||||
|
|
||||||
LBackend_InputDraw(w);
|
|
||||||
r = LInput_MeasureCaret(w);
|
|
||||||
|
|
||||||
if (caretShow) {
|
|
||||||
Drawer2D_Clear(&framebuffer, BITMAPCOL_BLACK,
|
|
||||||
r.X, r.Y, r.Width, r.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Rect2D_Equals(r, lastCaretRec)) {
|
|
||||||
/* Fast path, caret is blinking in same spot */
|
|
||||||
MarkAreaDirty(r.X, r.Y, r.Width, r.Height);
|
|
||||||
} else {
|
|
||||||
MarkAreaDirty(w->x, w->y, w->width, w->height);
|
|
||||||
}
|
|
||||||
lastCaretRec = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LBackend_InputSelect(struct LInput* w, int idx, cc_bool wasSelected) {
|
|
||||||
struct OpenKeyboardArgs args;
|
|
||||||
caretStart = DateTime_CurrentUTC_MS();
|
|
||||||
LInput_MoveCaretToCursor(w, idx);
|
|
||||||
if (wasSelected) return;
|
|
||||||
|
|
||||||
LBackend_MarkDirty(w);
|
|
||||||
OpenKeyboardArgs_Init(&args, &w->text, w->inputType);
|
|
||||||
Window_OpenKeyboard(&args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LBackend_InputUnselect(struct LInput* w) {
|
|
||||||
caretStart = 0;
|
|
||||||
LBackend_MarkDirty(w);
|
|
||||||
Window_CloseKeyboard();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@ struct LInput {
|
|||||||
/* The type of this input (see KEYBOARD_TYPE_ enum in Window.h) */
|
/* The type of this input (see KEYBOARD_TYPE_ enum in Window.h) */
|
||||||
/* If type is KEYBOARD_TYPE_PASSWORD, all characters are drawn as *. */
|
/* If type is KEYBOARD_TYPE_PASSWORD, all characters are drawn as *. */
|
||||||
cc_uint8 inputType;
|
cc_uint8 inputType;
|
||||||
|
/* Whether caret is currently visible */
|
||||||
|
cc_bool caretShow;
|
||||||
/* Filter applied to text received from the clipboard. Can be NULL. */
|
/* Filter applied to text received from the clipboard. Can be NULL. */
|
||||||
void (*ClipboardFilter)(cc_string* str);
|
void (*ClipboardFilter)(cc_string* str);
|
||||||
/* Callback invoked when the text is changed. Can be NULL. */
|
/* Callback invoked when the text is changed. Can be NULL. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user