Added example of a calculator app with custom input box (#310)
Turned my previous pull request into an example, as you suggested.
This commit is contained in:
parent
050249b2e5
commit
c8260e22de
@ -348,6 +348,7 @@ endif
|
||||
EXAMPLES = \
|
||||
controls_test_suite/controls_test_suite \
|
||||
custom_file_dialog/custom_file_dialog \
|
||||
custom_input_box/custom_input_box\
|
||||
image_exporter/image_exporter \
|
||||
image_importer_raw/image_importer_raw \
|
||||
property_list/property_list \
|
||||
|
260
examples/custom_input_box/custom_input_box.c
Normal file
260
examples/custom_input_box/custom_input_box.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*******************************************************************************************
|
||||
*
|
||||
* raygui - basic calculator app with custom input box for float values
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* raylib 4.5 - Windowing/input management and drawing.
|
||||
* raygui 3.5 - Immediate-mode GUI controls.
|
||||
*
|
||||
* COMPILATION (Windows - MinGW):
|
||||
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
#include <raygui.h>
|
||||
|
||||
int guiFloatingPointIndex = 0; // Global variable shared by all GuiFLoatBox()
|
||||
|
||||
float TextToFloat(const char* text); // Helper function that converts text to float
|
||||
int GuiFloatBox(Rectangle bounds, const char* text, float* value, int minValue, int maxValue, bool editMode); // Custom input box that works with float values. Basicly GuiValueBox(), but with some changes
|
||||
|
||||
int main()
|
||||
{
|
||||
InitWindow(250, 100, "Basic calculator");
|
||||
|
||||
// General variables
|
||||
SetTargetFPS(60);
|
||||
|
||||
float variableA = 0.0f;
|
||||
float variableB = 0.0f;
|
||||
float result = 0.0f;
|
||||
char operation[2];
|
||||
operation[0] = '+';
|
||||
operation[1] = '\0';
|
||||
|
||||
bool variableAMode = false;
|
||||
bool variableBMode = false;
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
if (GuiFloatBox((Rectangle){ 10, 10, 100, 20 }, NULL, &variableA, -1000000.0, 1000000.0, variableAMode)) variableAMode = !variableAMode;
|
||||
if (GuiFloatBox((Rectangle){ 140, 10, 100, 20 }, NULL, &variableB, -1000000.0, 1000000.0, variableBMode)) variableBMode = !variableBMode;
|
||||
|
||||
if (GuiButton((Rectangle){ 10, 70, 50, 20 }, "+"))
|
||||
{
|
||||
result = variableA + variableB;
|
||||
operation[0] = '+';
|
||||
}
|
||||
if (GuiButton((Rectangle){ 70, 70, 50, 20 }, "-"))
|
||||
{
|
||||
result = variableA - variableB;
|
||||
operation[0] = '-';
|
||||
}
|
||||
if (GuiButton((Rectangle){ 130, 70, 50, 20 }, "*"))
|
||||
{
|
||||
result = variableA * variableB;
|
||||
operation[0] = '*';
|
||||
}
|
||||
if (GuiButton((Rectangle){ 190, 70, 50, 20 }, "/"))
|
||||
{
|
||||
result = variableA / variableB;
|
||||
operation[0] = '/';
|
||||
}
|
||||
|
||||
DrawText(operation, 123, 15, 10, DARKGRAY);
|
||||
|
||||
GuiFloatBox((Rectangle){ 55, 40, 135, 20 }, "= ", &result, -2000000.0, 2000000.0, false);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
// Get float value from text
|
||||
float TextToFloat(const char* text)
|
||||
{
|
||||
float value = 0.0f;
|
||||
float floatingPoint = 0.0f;
|
||||
int sign = 1;
|
||||
|
||||
// deal with the sign
|
||||
if ((text[0] == '+') || (text[0] == '-'))
|
||||
{
|
||||
if (text[0] == '-') sign = -1;
|
||||
text++;
|
||||
}
|
||||
|
||||
// convert text to float
|
||||
for (int i = 0; (((text[i] >= '0') && (text[i] <= '9')) || text[i] == '.'); i++)
|
||||
{
|
||||
if (text[i] == '.')
|
||||
{
|
||||
if (floatingPoint > 0.0f) break;
|
||||
|
||||
floatingPoint = 10.0f;
|
||||
continue;
|
||||
}
|
||||
if (floatingPoint > 0.0f) // after encountering decimal separator
|
||||
{
|
||||
value += (float)(text[i] - '0') / floatingPoint;
|
||||
floatingPoint *= 10.0f;
|
||||
}
|
||||
else // before decimal separator
|
||||
value = value * 10.0f + (float)(text[i] - '0');
|
||||
}
|
||||
|
||||
return value * sign;
|
||||
}
|
||||
|
||||
// Float Box control, updates input text with numbers
|
||||
int GuiFloatBox(Rectangle bounds, const char* text, float* value, int minValue, int maxValue, bool editMode)
|
||||
{
|
||||
#if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
|
||||
#define RAYGUI_VALUEBOX_MAX_CHARS 32
|
||||
#endif
|
||||
|
||||
int result = 0;
|
||||
GuiState state = guiState;
|
||||
|
||||
char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
|
||||
|
||||
Rectangle textBounds = { 0 };
|
||||
if (text != NULL)
|
||||
{
|
||||
textBounds.width = (float)GetTextWidth(text) + 2;
|
||||
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
|
||||
textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
|
||||
textBounds.y = bounds.y + bounds.height / 2 - GuiGetStyle(DEFAULT, TEXT_SIZE) / 2;
|
||||
if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
|
||||
}
|
||||
|
||||
// Update control
|
||||
//--------------------------------------------------------------------
|
||||
if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
|
||||
{
|
||||
Vector2 mousePoint = GetMousePosition();
|
||||
|
||||
if (*value >= 0) sprintf(textValue, "+%.3f", *value);
|
||||
else sprintf(textValue, "%.3f", *value);
|
||||
|
||||
bool valueHasChanged = false;
|
||||
|
||||
int keyCount = (int)strlen(textValue) - guiFloatingPointIndex;
|
||||
|
||||
if (editMode)
|
||||
{
|
||||
state = STATE_PRESSED;
|
||||
|
||||
// Only allow keys in range [48..57]
|
||||
if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
|
||||
{
|
||||
if (GetTextWidth(textValue) < bounds.width)
|
||||
{
|
||||
int key = GetCharPressed();
|
||||
if ((key >= 48) && (key <= 57) && guiFloatingPointIndex)
|
||||
{
|
||||
if (guiFloatingPointIndex && guiFloatingPointIndex != 4) guiFloatingPointIndex--;
|
||||
|
||||
textValue[keyCount] = (char)key;
|
||||
textValue[++keyCount] = '\0';
|
||||
valueHasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete text
|
||||
if (keyCount > 0)
|
||||
{
|
||||
if (IsKeyPressed(KEY_BACKSPACE))
|
||||
{
|
||||
if (guiFloatingPointIndex < 4) guiFloatingPointIndex++;
|
||||
|
||||
keyCount--;
|
||||
textValue[keyCount] = '\0';
|
||||
valueHasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Change sign
|
||||
if (IsKeyPressed(KEY_MINUS))
|
||||
{
|
||||
if (textValue[0] == '+') textValue[0] = '-';
|
||||
else if (textValue[0] == '-') textValue[0] = '+';
|
||||
valueHasChanged = true;
|
||||
}
|
||||
|
||||
// Add decimal separator
|
||||
if ((IsKeyPressed(KEY_COMMA) || IsKeyPressed(KEY_PERIOD)) && guiFloatingPointIndex == 4)
|
||||
{
|
||||
guiFloatingPointIndex--;
|
||||
valueHasChanged = true;
|
||||
}
|
||||
|
||||
if (valueHasChanged)
|
||||
{
|
||||
*value = TextToFloat(textValue);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
|
||||
{
|
||||
guiFloatingPointIndex = 0;
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*value > maxValue) *value = maxValue;
|
||||
else if (*value < minValue) *value = minValue;
|
||||
|
||||
if (CheckCollisionPointRec(mousePoint, bounds))
|
||||
{
|
||||
state = STATE_FOCUSED;
|
||||
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Draw control
|
||||
//--------------------------------------------------------------------
|
||||
Color baseColor = BLANK;
|
||||
sprintf(textValue, "%.3f", *value);
|
||||
|
||||
if (state == STATE_PRESSED)
|
||||
{
|
||||
baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
|
||||
textValue[(int)strlen(textValue) - guiFloatingPointIndex] = '\0';
|
||||
}
|
||||
else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
|
||||
|
||||
// WARNING: BLANK color does not work properly with Fade()
|
||||
GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state * 3))), guiAlpha), baseColor);
|
||||
GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state * 3))), guiAlpha));
|
||||
|
||||
// Draw cursor
|
||||
if (editMode)
|
||||
{
|
||||
// NOTE: ValueBox internal text is always centered
|
||||
Rectangle cursor = { bounds.x + GetTextWidth(textValue) / 2 + bounds.width / 2 + 1, bounds.y + 2 * GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4 * GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
|
||||
GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
|
||||
}
|
||||
|
||||
// Draw text label if provided
|
||||
GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) ? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state * 3))), guiAlpha));
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
return result;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user