From ff746a4c5fcd9de2fd63a80a7bf463d01348f176 Mon Sep 17 00:00:00 2001 From: terencehill Date: Tue, 5 Jan 2021 00:03:15 +0100 Subject: [PATCH] Menu, player name editing: make changing an existing color much easier by detecting a color code even if the cursor is in the middle of it --- qcsrc/common/util.qc | 8 ----- qcsrc/lib/string.qh | 60 +++++++++++++++++++++++++++++++ qcsrc/menu/xonotic/colorpicker.qc | 52 +++++++-------------------- 3 files changed, 72 insertions(+), 48 deletions(-) diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index d823eeec2..8f37802ae 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -770,14 +770,6 @@ int cvar_settemp_restore() return j; } -bool isCaretEscaped(string theText, float pos) -{ - int i = 0; - while(pos - i >= 1 && substring(theText, pos - i - 1, 1) == "^") - ++i; - return (i & 1); -} - int skipIncompleteTag(string theText, float pos, int len) { int tag_start = -1; diff --git a/qcsrc/lib/string.qh b/qcsrc/lib/string.qh index 946438ca5..69ecc7b4a 100644 --- a/qcsrc/lib/string.qh +++ b/qcsrc/lib/string.qh @@ -436,3 +436,63 @@ const string HEXDIGITS = "0123456789ABCDEF0123456789abcdef"; const string DIGITS = "0123456789"; #define IS_DIGIT(d) (strstrofs(DIGITS, (d), 0) >= 0) + +// returns true if the caret at position pos is escaped +ERASEABLE +bool isCaretEscaped(string theText, float pos) +{ + // count all the previous carets + int carets = 0; + while(pos - carets >= 1 && substring(theText, pos - carets - 1, 1) == "^") + ++carets; + // if number of previous carets is odd then this carets is escaped + return (carets & 1); +} + +ERASEABLE +bool isValidColorCodeValue(string theText, int cc_len, int tag_start) +{ + if (cc_len == 2) + return IS_DIGIT(substring(theText, tag_start + 1, 1)); + if (cc_len == 5) + return (IS_HEXDIGIT(substring(theText, tag_start + 2, 1)) + && IS_HEXDIGIT(substring(theText, tag_start + 3, 1)) + && IS_HEXDIGIT(substring(theText, tag_start + 4, 1))); + return false; +} + +// it returns 0 if pos is NOT in the middle or at the end of a color code +// otherwise it returns a 2-digit number with cc_len as the first digit +// and the offset from '^' position to pos as the second digit +// e.g.: +// "a^2xy" | returns 0 if pos == 0 or 1 or 4 +// ^^ | returns 21 or 22 if pos == 2 or 3 +ERASEABLE +int checkColorCode(string theText, int pos) +{ + int text_len = strlen(theText); + string tag_type = "^"; + int cc_len = 2; + int tag_len = 1; + + LABEL(check_color_tag) + + for (int ofs = cc_len; ofs >= 1; ofs--) + { + if (!(pos >= ofs && text_len >= pos + (cc_len - ofs))) + continue; + if(substring(theText, pos - ofs, tag_len) == tag_type) + { + if (!isCaretEscaped(theText, pos - ofs) && isValidColorCodeValue(theText, cc_len, pos - ofs)) + return cc_len * 10 + ofs; + } + } + if (cc_len == 2) + { + tag_type = "^x"; + cc_len = 5; + tag_len = 2; + goto check_color_tag; + } + return 0; +} diff --git a/qcsrc/menu/xonotic/colorpicker.qc b/qcsrc/menu/xonotic/colorpicker.qc index d8aedf695..c4dfa2b6b 100644 --- a/qcsrc/menu/xonotic/colorpicker.qc +++ b/qcsrc/menu/xonotic/colorpicker.qc @@ -58,57 +58,29 @@ vector color_hslimage(vector v, vector margin) float XonoticColorpicker_mouseDrag(entity me, vector coords) { - float i, carets; + int i; for (;;) { i = me.controlledTextbox.cursorPos; - if(i >= 2) - { - if(substring(me.controlledTextbox.text, i-2, 1) == "^") - { - carets = 1; - while (i - 2 - carets >= 0 && substring(me.controlledTextbox.text, i - 2 - carets, 1) == "^") - ++carets; - if (carets & 1) - if(IS_DIGIT(substring(me.controlledTextbox.text, i-1, 1))) - { - me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); - me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); - continue; - } - } - } - if(i >= 5) + int res = checkColorCode(me.controlledTextbox.text, i); + if (res) { - if(substring(me.controlledTextbox.text, i-5, 2) == "^x") - { - carets = 1; - while (i - 5 - carets >= 0 && substring(me.controlledTextbox.text, i - 5 - carets, 1) == "^") - ++carets; - if (carets & 1) - if(IS_HEXDIGIT(substring(me.controlledTextbox.text, i - 3, 1))) - if(IS_HEXDIGIT(substring(me.controlledTextbox.text, i - 2, 1))) - if(IS_HEXDIGIT(substring(me.controlledTextbox.text, i - 1, 1))) - { - me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); - me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); - me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); - me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); - me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); - continue; - } - } + int tag_length = floor(res / 10); + int ofs = res % 10; + for (int j = tag_length - ofs; j > 0; j--) + me.controlledTextbox.keyDown(me.controlledTextbox, K_RIGHTARROW, 8, 0); + for (int j = tag_length; j > 0; j--) + me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0); + continue; } + break; } if(substring(me.controlledTextbox.text, i-1, 1) == "^") { - carets = 1; - while (i - 1 - carets >= 0 && substring(me.controlledTextbox.text, i - 1 - carets, 1) == "^") - ++carets; - if (carets & 1) + if(!isCaretEscaped(me.controlledTextbox.text, i-1)) me.controlledTextbox.enterText(me.controlledTextbox, "^"); // escape previous caret } -- 2.39.2