From f86b7cc85837eaff652d81da94d33a1307bb039d Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Jan 2018 11:18:03 +1100 Subject: [PATCH] Mostly port menu input validators to C. --- src/Client/PackedCol.c | 35 ++++++++ src/Client/PackedCol.h | 10 +-- src/Client/Widgets.c | 181 ++++++++++++++++++++++++++++++++++++++++- src/Client/Widgets.h | 20 ++++- 4 files changed, 231 insertions(+), 15 deletions(-) diff --git a/src/Client/PackedCol.c b/src/Client/PackedCol.c index 9905ba57b..57e32e3c6 100644 --- a/src/Client/PackedCol.c +++ b/src/Client/PackedCol.c @@ -35,4 +35,39 @@ void PackedCol_GetShaded(PackedCol normal, PackedCol* xSide, PackedCol* zSide, P *xSide = PackedCol_Scale(normal, PACKEDCOL_SHADE_X); *zSide = PackedCol_Scale(normal, PACKEDCOL_SHADE_Z); *yMin = PackedCol_Scale(normal, PACKEDCOL_SHADE_YMIN); +} + +bool PackedCol_Unhex(UInt8 hex, Int32* value) { + *value = 0; + if (hex >= '0' && hex <= '9') { + *value = (Int32)(hex - '0'); + } else if (hex >= 'a' && hex <= 'f') { + *value = (Int32)(hex - 'a') + 10; + } else if (hex >= 'A' && hex <= 'F') { + *value = (Int32)(hex - 'A') + 10; + } else { + return false; + } + return true; +} + +bool PackedCol_TryParseHex(STRING_PURE String* str, PackedCol* value) { + PackedCol empty = PACKEDCOL_CONST(0, 0, 0, 0); *value = empty; + /* accept XXYYZZ or #XXYYZZ forms */ + if (str->length < 6) return false; + if (str->length > 6 && (str->buffer[0] != '#' || str->length > 7)) return false; + + Int32 rH, rL, gH, gL, bH, bL; + UInt8* buffer = str->buffer; + if (buffer[0] == '#') buffer++; + + if (!PackedCol_Unhex(buffer[0], &rH) || !PackedCol_Unhex(buffer[1], &rL)) return false; + if (!PackedCol_Unhex(buffer[2], &gH) || !PackedCol_Unhex(buffer[3], &gL)) return false; + if (!PackedCol_Unhex(buffer[4], &bH) || !PackedCol_Unhex(buffer[5], &bL)) return false; + + value->R = (UInt8)(rH * 16 + rL); + value->G = (UInt8)(gH * 16 + gL); + value->B = (UInt8)(bH * 16 + bL); + value->A = UInt8_MaxValue; + return true; } \ No newline at end of file diff --git a/src/Client/PackedCol.h b/src/Client/PackedCol.h index 7999116ec..f6e0c395b 100644 --- a/src/Client/PackedCol.h +++ b/src/Client/PackedCol.h @@ -1,6 +1,7 @@ #ifndef CC_PACKEDCOL_H #define CC_PACKEDCOL_H #include "Typedefs.h" +#include "String.h" /* Manipulates an ARGB colour, in a format suitable for the native 3d graphics api. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ @@ -23,21 +24,14 @@ typedef struct PackedCol_ { #define PACKEDCOL_CONST(r, g, b, a) { r, g, b, a }; #endif - -/* Constructs a new ARGB colour. */ PackedCol PackedCol_Create4(UInt8 r, UInt8 g, UInt8 b, UInt8 a); -/* Constructs a new ARGB colour. */ PackedCol PackedCol_Create3(UInt8 r, UInt8 g, UInt8 b); -/* Returns whether two packed colours are equal. */ #define PackedCol_Equals(a, b) ((a).Packed == (b).Packed) -/* Converts a colour to ARGB form. */ #define PackedCol_ARGB(r, g, b, a) (((UInt32)(r) << 16) | ((UInt32)(g) << 8) | ((UInt32)(b)) | ((UInt32)(a) << 24)) -/* Converts a colour to ARGB form. */ UInt32 PackedCol_ToARGB(PackedCol col); -/* Multiplies the RGB components by t, where t is in [0, 1] */ PackedCol PackedCol_Scale(PackedCol value, Real32 t); -/* Linearly interpolates the RGB components of both colours by t, where t is in [0, 1] */ PackedCol PackedCol_Lerp(PackedCol a, PackedCol b, Real32 t); +bool PackedCol_TryParseHex(STRING_PURE String* str, PackedCol* value); #define PACKEDCOL_SHADE_X 0.6f #define PACKEDCOL_SHADE_Z 0.8f diff --git a/src/Client/Widgets.c b/src/Client/Widgets.c index 822d449a6..930ea7993 100644 --- a/src/Client/Widgets.c +++ b/src/Client/Widgets.c @@ -1538,6 +1538,179 @@ void InputWidget_Create(InputWidget* widget, FontDesc* font, STRING_REF String* widget->PrefixHeight = (UInt16)size.Height; widget->Base.Height = size.Height; } + +bool MenuInputValidator_AlwaysValidChar(MenuInputValidator* validator, UInt8 c) { return true; } +bool MenuInputValidator_AlwaysValidString(MenuInputValidator* validator, STRING_PURE String* s) { return true; } + +void HexColourValidator_GetRange(MenuInputValidator* validator, STRING_TRANSIENT String* range) { + String_AppendConst(range, "&7(#000000 - #FFFFFF)"); +} + +bool HexColourValidator_IsValidChar(MenuInputValidator* validator, UInt8 c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +bool HexColourValidator_IsValidString(MenuInputValidator* validator, STRING_PURE String* s) { + return s->length <= 6; +} + +bool HexColourValidator_IsValidValue(MenuInputValidator* validator, STRING_PURE String* s) { + PackedCol col; + return PackedCol_TryParseHex(s, &col); +} + +MenuInputValidator MenuInputValidator_Hex(void) { + MenuInputValidator validator; + validator.GetRange = HexColourValidator_GetRange; + validator.IsValidChar = HexColourValidator_IsValidChar; + validator.IsValidString = HexColourValidator_IsValidString; + validator.IsValidValue = HexColourValidator_IsValidValue; + return validator; +} + +void IntegerValidator_GetRange(MenuInputValidator* validator, STRING_TRANSIENT String* range) { + String_AppendConst(range, "&7("); + String_AppendInt32(range, (Int32)validator->Meta1); + String_AppendConst(range, " - "); + String_AppendInt32(range, (Int32)validator->Meta2); + String_AppendConst(range, ")"); +} + +bool IntegerValidator_IsValidChar(MenuInputValidator* validator, UInt8 c) { + return (c >= '0' && c <= '9') || c == '-'; +} + +bool IntegerValidator_IsValidString(MenuInputValidator* validator, STRING_PURE String* s) { + Int32 value; + if (s->length == 1 && s->buffer[0] == '-') return true; /* input is just a minus sign */ + return Convert_TryParseInt32(s, &value); +} + +bool IntegerValidator_IsValidValue(MenuInputValidator* validator, STRING_PURE String* s) { + Int32 value; + if (!Convert_TryParseInt32(s, &value)) return false; + + Int32 min = (Int32)validator->Meta1, max = (Int32)validator->Meta2; + return min <= value && value <= max; +} + +MenuInputValidator MenuInputValidator_Integer(Int32 min, Int32 max) { + MenuInputValidator validator; + validator.GetRange = IntegerValidator_GetRange; + validator.IsValidChar = IntegerValidator_IsValidChar; + validator.IsValidString = IntegerValidator_IsValidString; + validator.IsValidValue = IntegerValidator_IsValidValue; + validator.Meta1 = (void*)min; + validator.Meta2 = (void*)max; + return validator; +} + +void SeedValidator_GetRange(MenuInputValidator* validator, STRING_TRANSIENT String* range) { + String_AppendConst(range, "&7(an integer)"); +} + +MenuInputValidator MenuInputValidator_Seed(void) { + MenuInputValidator validator = MenuInputValidator_Integer(Int32_MinValue, Int32_MaxValue); + validator.GetRange = SeedValidator_GetRange; + return validator; +} + +void RealValidator_GetRange(MenuInputValidator* validator, STRING_TRANSIENT String* range) { + String_AppendConst(range, "&7("); + String_AppendReal32(range, (Real32)validator->Meta1); + String_AppendConst(range, " - "); + String_AppendReal32(range, (Real32)validator->Meta2); + String_AppendConst(range, ")"); +} + +bool RealValidator_IsValidChar(MenuInputValidator* validator, UInt8 c) { + return (c >= '0' && c <= '9') || c == '-' || c == '.' || c == ','; +} + +bool RealValidator_IsValidString(MenuInputValidator* validator, STRING_PURE String* s) { + Real32 value; + if (s->length == 1 && RealValidator_IsValidChar(validator, s->buffer[0])) return true; + return Convert_TryParseReal32(s, &value); +} + +bool RealValidator_IsValidValue(MenuInputValidator* validator, STRING_PURE String* s) { + Real32 value; + if (!Convert_TryParseReal32(s, &value)) return false; + Real32 min = (Real32)validator->Meta1, max = (Real32)validator->Meta2; + return min <= value && value <= max; +} + +MenuInputValidator MenuInputValidator_Real(Real32 min, Real32 max) { + MenuInputValidator validator; + validator.GetRange = RealValidator_GetRange; + validator.IsValidChar = RealValidator_IsValidChar; + validator.IsValidString = RealValidator_IsValidString; + validator.IsValidValue = RealValidator_IsValidValue; + validator.Meta1 = (void*)min; + validator.Meta2 = (void*)max; + return validator; +} + +void PathValidator_GetRange(MenuInputValidator* validator, STRING_TRANSIENT String* range) { + String_AppendConst(range, "&7(Enter name)"); +} + +bool PathValidator_IsValidChar(MenuInputValidator* validator, UInt8 c) { + return !(c == '/' || c == '\\' || c == '?' || c == '*' || c == ':' + || c == '<' || c == '>' || c == '|' || c == '"' || c == '.'); +} + +MenuInputValidator MenuInputValidator_Path(void) { + MenuInputValidator validator; + validator.GetRange = PathValidator_GetRange; + validator.IsValidChar = PathValidator_IsValidChar; + validator.IsValidString = MenuInputValidator_AlwaysValidString; + validator.IsValidValue = MenuInputValidator_AlwaysValidString; + return validator; +} + +void BooleanInputValidator_GetRange(MenuInputValidator* validator, STRING_TRANSIENT String* range) { + String_AppendConst(range, "&7(yes or no)"); +} + +MenuInputValidator MenuInputValidator_Boolean(void) { + MenuInputValidator validator; + validator.GetRange = BooleanInputValidator_GetRange; + validator.IsValidChar = MenuInputValidator_AlwaysValidChar; + validator.IsValidString = MenuInputValidator_AlwaysValidString; + validator.IsValidValue = MenuInputValidator_AlwaysValidString; + return validator; +} + +MenuInputValidator MenuInputValidator_Enum(const UInt8** names, UInt32 namesCount) { + MenuInputValidator validator = MenuInputValidator_Boolean(); + validator.Meta1 = names; + validator.Meta2 = (void*)namesCount; + return validator; +} + +void StringValidator_GetRange(MenuInputValidator* validator, STRING_TRANSIENT String* range) { + String_AppendConst(range, "&7(Enter text)"); +} + +bool StringValidator_IsValidChar(MenuInputValidator* validator, UInt8 c) { + return c != '&' && Utils_IsValidInputChar(c, true); +} + +bool StringValidator_IsValidString(MenuInputValidator* validator, STRING_PURE String* s) { + return s->length <= STRING_SIZE; +} + +MenuInputValidator MenuInputValidator_String(void) { + MenuInputValidator validator; + validator.GetRange = StringValidator_GetRange; + validator.IsValidChar = StringValidator_IsValidChar; + validator.IsValidString = StringValidator_IsValidString; + validator.IsValidValue = StringValidator_IsValidString; + return validator; +} + + void MenuInputWidget_Render(GuiElement* elem, Real64 delta) { Widget* elemW = (Widget*)elem; PackedCol backCol = PACKEDCOL_CONST(30, 30, 30, 200); @@ -1561,7 +1734,8 @@ void MenuInputWidget_RemakeTexture(GuiElement* elem) { UInt8 rangeBuffer[String_BufferSize(STRING_SIZE)]; String range = String_InitAndClearArray(rangeBuffer); - widget->Validator.GetRange(&range); + MenuInputValidator* validator = &widget->Validator; + validator->GetRange(validator, &range); /* Ensure we don't have 0 text height */ if (size.Height == 0) { @@ -1600,14 +1774,15 @@ bool MenuInputWidget_AllowedChar(GuiElement* elem, UInt8 c) { if (c == '&' || !Utils_IsValidInputChar(c, true)) return false; MenuInputWidget* widget = (MenuInputWidget*)elem; InputWidget* elemW = (InputWidget*)elem; + MenuInputValidator* validator = &widget->Validator; - if (!widget->Validator.IsValidChar(c)) return false; + if (!validator->IsValidChar(validator, c)) return false; Int32 maxChars = elemW->GetMaxLines() * elemW->MaxCharsPerLine; if (elemW->Text.length == maxChars) return false; /* See if the new string is in valid format */ InputWidget_AppendChar(elemW, c); - bool valid = widget->Validator.IsValidString(&elemW->Text); + bool valid = validator->IsValidString(validator, &elemW->Text); InputWidget_DeleteChar(elemW); return valid; } diff --git a/src/Client/Widgets.h b/src/Client/Widgets.h index 3b860963f..c91d41df4 100644 --- a/src/Client/Widgets.h +++ b/src/Client/Widgets.h @@ -162,11 +162,23 @@ void InputWidget_Append(InputWidget* widget, UInt8 c); typedef struct MenuInputValidator_ { - void (*GetRange)(STRING_TRANSIENT String* range); - bool (*IsValidChar)(UInt8 c); - bool (*IsValidString)(STRING_PURE String* s); - bool (*IsValidValue)(STRING_PURE String* s); + void (*GetRange)(struct MenuInputValidator_* validator, STRING_TRANSIENT String* range); + bool (*IsValidChar)(struct MenuInputValidator_* validator, UInt8 c); + bool (*IsValidString)(struct MenuInputValidator_* validator, STRING_PURE String* s); + bool (*IsValidValue)(struct MenuInputValidator_* validator, STRING_PURE String* s); + void* Meta1; /* TODO: do we need to handle when sizeof(void*) is < 32 bits? */ + void* Meta2; /* TODO: do we need to handle when sizeof(void*) is < 32 bits? */ } MenuInputValidator; + +MenuInputValidator MenuInputValidator_Hex(void); +MenuInputValidator MenuInputValidator_Integer(Int32 min, Int32 max); +MenuInputValidator MenuInputValidator_Seed(void); +MenuInputValidator MenuInputValidator_Real(Real32 min, Real32 max); +MenuInputValidator MenuInputValidator_Path(void); +MenuInputValidator MenuInputValidator_Boolean(void); +MenuInputValidator MenuInputValidator_Enum(const UInt8** names, UInt32 namesCount); +MenuInputValidator MenuInputValidator_String(void); + typedef struct MenuInputWidget_ { InputWidget Base; Int32 MinWidth, MinHeight;