From 8e6dcc45e1681bc141fe97334dd06ab47d7ea5e5 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 12:16:03 -0800 Subject: [PATCH 01/19] Break raygui.go into separate files - per-control .go file, - separate file for style/property stuff, - added NumProperties enum to the list of properties for constraint checking, - should be no code changes --- raygui/button.go | 63 +++ raygui/checkbox.go | 46 ++ raygui/combobox.go | 102 ++++ raygui/label.go | 28 ++ raygui/progressbar.go | 21 + raygui/raygui.go | 1086 +--------------------------------------- raygui/slider.go | 76 +++ raygui/sliderbar.go | 76 +++ raygui/spinner.go | 176 +++++++ raygui/style.go | 414 +++++++++++++++ raygui/textbox.go | 59 +++ raygui/togglebutton.go | 61 +++ raygui/togglegroup.go | 16 + 13 files changed, 1145 insertions(+), 1079 deletions(-) create mode 100644 raygui/button.go create mode 100644 raygui/checkbox.go create mode 100644 raygui/combobox.go create mode 100644 raygui/label.go create mode 100644 raygui/progressbar.go create mode 100644 raygui/slider.go create mode 100644 raygui/sliderbar.go create mode 100644 raygui/spinner.go create mode 100644 raygui/style.go create mode 100644 raygui/textbox.go create mode 100644 raygui/togglebutton.go create mode 100644 raygui/togglegroup.go diff --git a/raygui/button.go b/raygui/button.go new file mode 100644 index 0000000..153d2c8 --- /dev/null +++ b/raygui/button.go @@ -0,0 +1,63 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// Button - Button element, returns true when clicked +func Button(bounds rl.Rectangle, text string) bool { + b := bounds.ToInt32() + state := Normal + mousePoint := rl.GetMousePosition() + clicked := false + + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(text, textHeight) + + // Update control + if b.Width < textWidth { + b.Width = textWidth + int32(style[ButtonTextPadding]) + } + + if b.Height < textHeight { + b.Height = textHeight + int32(style[ButtonTextPadding])/2 + } + + if rl.CheckCollisionPointRec(mousePoint, bounds) { + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { + clicked = true + } else { + state = Focused + } + } + + // Draw control + switch state { + case Normal: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonDefaultBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonDefaultInsideColor]))) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonDefaultTextColor]))) + break + + case Focused: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonHoverBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonHoverInsideColor]))) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonHoverTextColor]))) + break + + case Pressed: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonPressedBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonPressedInsideColor]))) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonPressedTextColor]))) + break + + default: + break + } + + if clicked { + return true + } + + return false +} diff --git a/raygui/checkbox.go b/raygui/checkbox.go new file mode 100644 index 0000000..705d8d5 --- /dev/null +++ b/raygui/checkbox.go @@ -0,0 +1,46 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// CheckBox - Check Box element, returns true when active +func CheckBox(bounds rl.Rectangle, checked bool) bool { + b := bounds.ToInt32() + state := Normal + mousePoint := rl.GetMousePosition() + + // Update control + if rl.CheckCollisionPointRec(mousePoint, bounds) { + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { + state = Normal + checked = !checked + } else { + state = Focused + } + } + + // Draw control + switch state { + case Normal: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxDefaultBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxDefaultInsideColor]))) + break + case Focused: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxHoverBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxHoverInsideColor]))) + break + case Pressed: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxClickBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxClickInsideColor]))) + break + default: + break + } + + if checked { + rl.DrawRectangle(b.X+int32(style[CheckboxInsideWidth]), b.Y+int32(style[CheckboxInsideWidth]), b.Width-(2*int32(style[CheckboxInsideWidth])), b.Height-(2*int32(style[CheckboxInsideWidth])), rl.GetColor(int32(style[CheckboxDefaultActiveColor]))) + } + + return checked +} diff --git a/raygui/combobox.go b/raygui/combobox.go new file mode 100644 index 0000000..aa3a07e --- /dev/null +++ b/raygui/combobox.go @@ -0,0 +1,102 @@ +package raygui + +import ( + "fmt" + "github.com/gen2brain/raylib-go/raylib" +) + +// ComboBox draws a simplified version of a ComboBox allowing the user to select a string +// from a list accompanied by an N/M counter. The widget does not provide a drop-down/completion +// or any input support. +func ComboBox(bounds rl.Rectangle, comboText []string, active int) int { + // Reject invalid selections and disable rendering. + comboCount := len(comboText) + if active < 0 || active >= comboCount { + rl.TraceLog(rl.LogWarning, "ComboBox active expects 0 <= active <= %d", comboCount) + return -1 + } + + activeText := comboText[active] + + // style sizing. + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(activeText, textHeight) + borderWidth := int32(style[ComboboxBorderWidth]) + textPadding := int32(style[ToggleTextPadding]) + + b := bounds.ToInt32() + if b.Width < textWidth { + b.Width = textWidth + textPadding + bounds.Width = float32(b.Width) + } + if b.Height < textHeight { + b.Height = textHeight + textPadding + bounds.Height = float32(b.Height) + } + + // Identify what the counter is going to look like with max digits so we don't resize it. + clickWidth := rl.MeasureText(fmt.Sprintf("%d/%d", comboCount, comboCount), b.Height) + + click := rl.NewRectangle(bounds.X+bounds.Width+float32(style[ComboboxPadding]), bounds.Y, float32(clickWidth), float32(b.Height)) + c := click.ToInt32() + mousePoint := rl.GetMousePosition() + state := Normal + if rl.CheckCollisionPointRec(mousePoint, bounds) || rl.CheckCollisionPointRec(mousePoint, click) { + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { + state = Pressed + } else { + state = Focused + } + } + + // Draw control + var borderColor, insideColor, listColor, textColor rl.Color + + switch state { + case Normal: + borderColor = rl.GetColor(int32(style[ComboboxDefaultBorderColor])) + insideColor = rl.GetColor(int32(style[ComboboxDefaultInsideColor])) + listColor = rl.GetColor(int32(style[ComboboxDefaultListTextColor])) + textColor = rl.GetColor(int32(style[ComboboxDefaultTextColor])) + + case Focused: + borderColor = rl.GetColor(int32(style[ComboboxHoverBorderColor])) + insideColor = rl.GetColor(int32(style[ComboboxHoverInsideColor])) + listColor = rl.GetColor(int32(style[ComboboxHoverListTextColor])) + textColor = rl.GetColor(int32(style[ComboboxHoverTextColor])) + + case Pressed: + borderColor = rl.GetColor(int32(style[ComboboxPressedBorderColor])) + insideColor = rl.GetColor(int32(style[ComboboxPressedInsideColor])) + listColor = rl.GetColor(int32(style[ComboboxPressedListTextColor])) + textColor = rl.GetColor(int32(style[ComboboxPressedTextColor])) + + default: + rl.TraceLog(rl.LogWarning, "ComboBox in unrecognized state %d", state) + return -1 + } + + // Render the box itself + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, borderColor) + rl.DrawRectangle(b.X+borderWidth, b.Y+borderWidth, b.Width-(2*borderWidth), b.Height-(2*borderWidth), insideColor) + rl.DrawText(activeText, b.X+((b.Width/2)-(rl.MeasureText(activeText, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) + + // Render the accompanying "clicks" box showing the element counter. + rl.DrawRectangle(c.X, c.Y, c.Width, c.Height, borderColor) + rl.DrawRectangle(c.X+borderWidth, c.Y+borderWidth, c.Width-(2*borderWidth), c.Height-(2*borderWidth), insideColor) + companionText := fmt.Sprintf("%d/%d", active+1, comboCount) + rl.DrawText(companionText, c.X+((c.Width/2)-(rl.MeasureText(companionText, textHeight)/2)), c.Y+((c.Height/2)-(textHeight/2)), textHeight, listColor) + + if rl.CheckCollisionPointRec(mousePoint, bounds) || rl.CheckCollisionPointRec(mousePoint, click) { + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { + active++ + if active >= comboCount { + active = 0 + } + } + } + + return active +} diff --git a/raygui/label.go b/raygui/label.go new file mode 100644 index 0000000..c59c299 --- /dev/null +++ b/raygui/label.go @@ -0,0 +1,28 @@ +package raygui + +import rl "github.com/gen2brain/raylib-go/raylib" + +// Label - Label element, show text +func Label(bounds rl.Rectangle, text string) { + LabelEx(bounds, text, rl.GetColor(int32(style[LabelTextColor])), rl.NewColor(0, 0, 0, 0), rl.NewColor(0, 0, 0, 0)) +} + +// LabelEx - Label element extended, configurable colors +func LabelEx(bounds rl.Rectangle, text string, textColor, border, inner rl.Color) { + b := bounds.ToInt32() + // Update control + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(text, textHeight) + + if b.Width < textWidth { + b.Width = textWidth + int32(style[LabelTextPadding]) + } + if b.Height < textHeight { + b.Height = textHeight + int32(style[LabelTextPadding])/2 + } + + // Draw control + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, border) + rl.DrawRectangle(b.X+int32(style[LabelBorderWidth]), b.Y+int32(style[LabelBorderWidth]), b.Width-(2*int32(style[LabelBorderWidth])), b.Height-(2*int32(style[LabelBorderWidth])), inner) + rl.DrawText(text, b.X+((b.Width/2)-(textWidth/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) +} diff --git a/raygui/progressbar.go b/raygui/progressbar.go new file mode 100644 index 0000000..4d6164c --- /dev/null +++ b/raygui/progressbar.go @@ -0,0 +1,21 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// ProgressBar - Progress Bar element, shows current progress value +func ProgressBar(bounds rl.Rectangle, value float32) { + b := bounds.ToInt32() + if value > 1.0 { + value = 1.0 + } else if value < 0.0 { + value = 0.0 + } + + progressBar := rl.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), b.Width - (int32(style[ProgressbarBorderWidth]) * 2), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} + progressValue := rl.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), int32(value * float32(b.Width-int32(style[ProgressbarBorderWidth])*2)), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} + + // Draw control + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ProgressbarBorderColor]))) + rl.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, rl.GetColor(int32(style[ProgressbarInsideColor]))) + rl.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, rl.GetColor(int32(style[ProgressbarProgressColor]))) +} diff --git a/raygui/raygui.go b/raygui/raygui.go index 2610e6f..4e6c2c8 100644 --- a/raygui/raygui.go +++ b/raygui/raygui.go @@ -1,1088 +1,16 @@ // Package raygui - Simple and easy-to-use IMGUI (immediate mode GUI API) library + package raygui -import ( - "bufio" - "fmt" - "io/ioutil" - "strconv" - "strings" - - "github.com/gen2brain/raylib-go/raylib" -) - -// Property - GUI property -type Property int32 - -// GUI properties enumeration -const ( - GlobalBaseColor Property = iota - GlobalBorderColor - GlobalTextColor - GlobalTextFontsize - GlobalBorderWidth - GlobalBackgroundColor - GlobalLinesColor - LabelBorderWidth - LabelTextColor - LabelTextPadding - ButtonBorderWidth - ButtonTextPadding - ButtonDefaultBorderColor - ButtonDefaultInsideColor - ButtonDefaultTextColor - ButtonHoverBorderColor - ButtonHoverInsideColor - ButtonHoverTextColor - ButtonPressedBorderColor - ButtonPressedInsideColor - ButtonPressedTextColor - ToggleTextPadding - ToggleBorderWidth - ToggleDefaultBorderColor - ToggleDefaultInsideColor - ToggleDefaultTextColor - ToggleHoverBorderColor - ToggleHoverInsideColor - ToggleHoverTextColor - TogglePressedBorderColor - TogglePressedInsideColor - TogglePressedTextColor - ToggleActiveBorderColor - ToggleActiveInsideColor - ToggleActiveTextColor - TogglegroupPadding - SliderBorderWidth - SliderButtonBorderWidth - SliderBorderColor - SliderInsideColor - SliderDefaultColor - SliderHoverColor - SliderActiveColor - SliderbarBorderColor - SliderbarInsideColor - SliderbarDefaultColor - SliderbarHoverColor - SliderbarActiveColor - SliderbarZeroLineColor - ProgressbarBorderColor - ProgressbarInsideColor - ProgressbarProgressColor - ProgressbarBorderWidth - SpinnerLabelBorderColor - SpinnerLabelInsideColor - SpinnerDefaultButtonBorderColor - SpinnerDefaultButtonInsideColor - SpinnerDefaultSymbolColor - SpinnerDefaultTextColor - SpinnerHoverButtonBorderColor - SpinnerHoverButtonInsideColor - SpinnerHoverSymbolColor - SpinnerHoverTextColor - SpinnerPressedButtonBorderColor - SpinnerPressedButtonInsideColor - SpinnerPressedSymbolColor - SpinnerPressedTextColor - ComboboxPadding - boundsWidth - boundsHeight - ComboboxBorderWidth - ComboboxDefaultBorderColor - ComboboxDefaultInsideColor - ComboboxDefaultTextColor - ComboboxDefaultListTextColor - ComboboxHoverBorderColor - ComboboxHoverInsideColor - ComboboxHoverTextColor - ComboboxHoverListTextColor - ComboboxPressedBorderColor - ComboboxPressedInsideColor - ComboboxPressedTextColor - ComboboxPressedListBorderColor - ComboboxPressedListInsideColor - ComboboxPressedListTextColor - CheckboxDefaultBorderColor - CheckboxDefaultInsideColor - CheckboxHoverBorderColor - CheckboxHoverInsideColor - CheckboxClickBorderColor - CheckboxClickInsideColor - CheckboxDefaultActiveColor - CheckboxInsideWidth - TextboxBorderWidth - TextboxBorderColor - TextboxInsideColor - TextboxTextColor - TextboxLineColor - TextboxTextFontsize -) - // GUI controls states +type ControlState int + const ( - Disabled = iota + Disabled ControlState = iota + // Normal is the default state for rendering GUI elements. Normal + // Focused indicates the mouse is hovering over the GUI element. Focused + // Pressed indicates the mouse is hovering over the GUI element and LMB is pressed down. Pressed ) - -// Current GUI style (default light) -var style = []int64{ - 0xf5f5f5ff, // GLOBAL_BASE_COLOR - 0xf5f5f5ff, // GLOBAL_BORDER_COLOR - 0xf5f5f5ff, // GLOBAL_TEXT_COLOR - 10, // GLOBAL_TEXT_FONTSIZE - 1, // GLOBAL_BORDER_WIDTH - 0xf5f5f5ff, // BACKGROUND_COLOR - 0x90abb5ff, // LINES_COLOR - 1, // LABEL_BORDER_WIDTH - 0x4d4d4dff, // LABEL_TEXT_COLOR - 20, // LABEL_TEXT_PADDING - 2, // BUTTON_BORDER_WIDTH - 20, // BUTTON_TEXT_PADDING - 0x828282ff, // BUTTON_DEFAULT_BORDER_COLOR - 0xc8c8c8ff, // BUTTON_DEFAULT_INSIDE_COLOR - 0x4d4d4dff, // BUTTON_DEFAULT_TEXT_COLOR - 0xc8c8c8ff, // BUTTON_HOVER_BORDER_COLOR - 0xffffffff, // BUTTON_HOVER_INSIDE_COLOR - 0x868686ff, // BUTTON_HOVER_TEXT_COLOR - 0x7bb0d6ff, // BUTTON_PRESSED_BORDER_COLOR - 0xbcecffff, // BUTTON_PRESSED_INSIDE_COLOR - 0x5f9aa7ff, // BUTTON_PRESSED_TEXT_COLOR - 20, // TOGGLE_TEXT_PADDING - 1, // TOGGLE_BORDER_WIDTH - 0x828282ff, // TOGGLE_DEFAULT_BORDER_COLOR - 0xc8c8c8ff, // TOGGLE_DEFAULT_INSIDE_COLOR - 0x828282ff, // TOGGLE_DEFAULT_TEXT_COLOR - 0xc8c8c8ff, // TOGGLE_HOVER_BORDER_COLOR - 0xffffffff, // TOGGLE_HOVER_INSIDE_COLOR - 0x828282ff, // TOGGLE_HOVER_TEXT_COLOR - 0xbdd7eaff, // TOGGLE_PRESSED_BORDER_COLOR - 0xddf5ffff, // TOGGLE_PRESSED_INSIDE_COLOR - 0xafccd3ff, // TOGGLE_PRESSED_TEXT_COLOR - 0x7bb0d6ff, // TOGGLE_ACTIVE_BORDER_COLOR - 0xbcecffff, // TOGGLE_ACTIVE_INSIDE_COLOR - 0x5f9aa7ff, // TOGGLE_ACTIVE_TEXT_COLOR - 3, // TOGGLEGROUP_PADDING - 1, // SLIDER_BORDER_WIDTH - 1, // SLIDER_BUTTON_BORDER_WIDTH - 0x828282ff, // SLIDER_BORDER_COLOR - 0xc8c8c8ff, // SLIDER_INSIDE_COLOR - 0xbcecffff, // SLIDER_DEFAULT_COLOR - 0xffffffff, // SLIDER_HOVER_COLOR - 0xddf5ffff, // SLIDER_ACTIVE_COLOR - 0x828282ff, // SLIDERBAR_BORDER_COLOR - 0xc8c8c8ff, // SLIDERBAR_INSIDE_COLOR - 0xbcecffff, // SLIDERBAR_DEFAULT_COLOR - 0xffffffff, // SLIDERBAR_HOVER_COLOR - 0xddf5ffff, // SLIDERBAR_ACTIVE_COLOR - 0x828282ff, // SLIDERBAR_ZERO_LINE_COLOR - 0x828282ff, // PROGRESSBAR_BORDER_COLOR - 0xc8c8c8ff, // PROGRESSBAR_INSIDE_COLOR - 0xbcecffff, // PROGRESSBAR_PROGRESS_COLOR - 2, // PROGRESSBAR_BORDER_WIDTH - 0x828282ff, // SPINNER_LABEL_BORDER_COLOR - 0xc8c8c8ff, // SPINNER_LABEL_INSIDE_COLOR - 0x828282ff, // SPINNER_DEFAULT_BUTTON_BORDER_COLOR - 0xc8c8c8ff, // SPINNER_DEFAULT_BUTTON_INSIDE_COLOR - 0x000000ff, // SPINNER_DEFAULT_SYMBOL_COLOR - 0x000000ff, // SPINNER_DEFAULT_TEXT_COLOR - 0xc8c8c8ff, // SPINNER_HOVER_BUTTON_BORDER_COLOR - 0xffffffff, // SPINNER_HOVER_BUTTON_INSIDE_COLOR - 0x000000ff, // SPINNER_HOVER_SYMBOL_COLOR - 0x000000ff, // SPINNER_HOVER_TEXT_COLOR - 0x7bb0d6ff, // SPINNER_PRESSED_BUTTON_BORDER_COLOR - 0xbcecffff, // SPINNER_PRESSED_BUTTON_INSIDE_COLOR - 0x5f9aa7ff, // SPINNER_PRESSED_SYMBOL_COLOR - 0x000000ff, // SPINNER_PRESSED_TEXT_COLOR - 1, // COMBOBOX_PADDING - 30, // COMBOBOX_BUTTON_WIDTH - 20, // COMBOBOX_BUTTON_HEIGHT - 1, // COMBOBOX_BORDER_WIDTH - 0x828282ff, // COMBOBOX_DEFAULT_BORDER_COLOR - 0xc8c8c8ff, // COMBOBOX_DEFAULT_INSIDE_COLOR - 0x828282ff, // COMBOBOX_DEFAULT_TEXT_COLOR - 0x828282ff, // COMBOBOX_DEFAULT_LIST_TEXT_COLOR - 0xc8c8c8ff, // COMBOBOX_HOVER_BORDER_COLOR - 0xffffffff, // COMBOBOX_HOVER_INSIDE_COLOR - 0x828282ff, // COMBOBOX_HOVER_TEXT_COLOR - 0x828282ff, // COMBOBOX_HOVER_LIST_TEXT_COLOR - 0x7bb0d6ff, // COMBOBOX_PRESSED_BORDER_COLOR - 0xbcecffff, // COMBOBOX_PRESSED_INSIDE_COLOR - 0x5f9aa7ff, // COMBOBOX_PRESSED_TEXT_COLOR - 0x0078acff, // COMBOBOX_PRESSED_LIST_BORDER_COLOR - 0x66e7ffff, // COMBOBOX_PRESSED_LIST_INSIDE_COLOR - 0x0078acff, // COMBOBOX_PRESSED_LIST_TEXT_COLOR - 0x828282ff, // CHECKBOX_DEFAULT_BORDER_COLOR - 0xffffffff, // CHECKBOX_DEFAULT_INSIDE_COLOR - 0xc8c8c8ff, // CHECKBOX_HOVER_BORDER_COLOR - 0xffffffff, // CHECKBOX_HOVER_INSIDE_COLOR - 0x66e7ffff, // CHECKBOX_CLICK_BORDER_COLOR - 0xddf5ffff, // CHECKBOX_CLICK_INSIDE_COLOR - 0xbcecffff, // CHECKBOX_STATUS_ACTIVE_COLOR - 1, // CHECKBOX_INSIDE_WIDTH - 1, // TEXTBOX_BORDER_WIDTH - 0x828282ff, // TEXTBOX_BORDER_COLOR - 0xf5f5f5ff, // TEXTBOX_INSIDE_COLOR - 0x000000ff, // TEXTBOX_TEXT_COLOR - 0x000000ff, // TEXTBOX_LINE_COLOR - 10, // TEXTBOX_TEXT_FONTSIZE -} - -// GUI property names (to read/write style text files) -var propertyName = []string{ - "GLOBAL_BASE_COLOR", - "GLOBAL_BORDER_COLOR", - "GLOBAL_TEXT_COLOR", - "GLOBAL_TEXT_FONTSIZE", - "GLOBAL_BORDER_WIDTH", - "BACKGROUND_COLOR", - "LINES_COLOR", - "LABEL_BORDER_WIDTH", - "LABEL_TEXT_COLOR", - "LABEL_TEXT_PADDING", - "BUTTON_BORDER_WIDTH", - "BUTTON_TEXT_PADDING", - "BUTTON_DEFAULT_BORDER_COLOR", - "BUTTON_DEFAULT_INSIDE_COLOR", - "BUTTON_DEFAULT_TEXT_COLOR", - "BUTTON_HOVER_BORDER_COLOR", - "BUTTON_HOVER_INSIDE_COLOR", - "BUTTON_HOVER_TEXT_COLOR", - "BUTTON_PRESSED_BORDER_COLOR", - "BUTTON_PRESSED_INSIDE_COLOR", - "BUTTON_PRESSED_TEXT_COLOR", - "TOGGLE_TEXT_PADDING", - "TOGGLE_BORDER_WIDTH", - "TOGGLE_DEFAULT_BORDER_COLOR", - "TOGGLE_DEFAULT_INSIDE_COLOR", - "TOGGLE_DEFAULT_TEXT_COLOR", - "TOGGLE_HOVER_BORDER_COLOR", - "TOGGLE_HOVER_INSIDE_COLOR", - "TOGGLE_HOVER_TEXT_COLOR", - "TOGGLE_PRESSED_BORDER_COLOR", - "TOGGLE_PRESSED_INSIDE_COLOR", - "TOGGLE_PRESSED_TEXT_COLOR", - "TOGGLE_ACTIVE_BORDER_COLOR", - "TOGGLE_ACTIVE_INSIDE_COLOR", - "TOGGLE_ACTIVE_TEXT_COLOR", - "TOGGLEGROUP_PADDING", - "SLIDER_BORDER_WIDTH", - "SLIDER_BUTTON_BORDER_WIDTH", - "SLIDER_BORDER_COLOR", - "SLIDER_INSIDE_COLOR", - "SLIDER_DEFAULT_COLOR", - "SLIDER_HOVER_COLOR", - "SLIDER_ACTIVE_COLOR", - "SLIDERBAR_BORDER_COLOR", - "SLIDERBAR_INSIDE_COLOR", - "SLIDERBAR_DEFAULT_COLOR", - "SLIDERBAR_HOVER_COLOR", - "SLIDERBAR_ACTIVE_COLOR", - "SLIDERBAR_ZERO_LINE_COLOR", - "PROGRESSBAR_BORDER_COLOR", - "PROGRESSBAR_INSIDE_COLOR", - "PROGRESSBAR_PROGRESS_COLOR", - "PROGRESSBAR_BORDER_WIDTH", - "SPINNER_LABEL_BORDER_COLOR", - "SPINNER_LABEL_INSIDE_COLOR", - "SPINNER_DEFAULT_BUTTON_BORDER_COLOR", - "SPINNER_DEFAULT_BUTTON_INSIDE_COLOR", - "SPINNER_DEFAULT_SYMBOL_COLOR", - "SPINNER_DEFAULT_TEXT_COLOR", - "SPINNER_HOVER_BUTTON_BORDER_COLOR", - "SPINNER_HOVER_BUTTON_INSIDE_COLOR", - "SPINNER_HOVER_SYMBOL_COLOR", - "SPINNER_HOVER_TEXT_COLOR", - "SPINNER_PRESSED_BUTTON_BORDER_COLOR", - "SPINNER_PRESSED_BUTTON_INSIDE_COLOR", - "SPINNER_PRESSED_SYMBOL_COLOR", - "SPINNER_PRESSED_TEXT_COLOR", - "COMBOBOX_PADDING", - "COMBOBOX_BUTTON_WIDTH", - "COMBOBOX_BUTTON_HEIGHT", - "COMBOBOX_BORDER_WIDTH", - "COMBOBOX_DEFAULT_BORDER_COLOR", - "COMBOBOX_DEFAULT_INSIDE_COLOR", - "COMBOBOX_DEFAULT_TEXT_COLOR", - "COMBOBOX_DEFAULT_LIST_TEXT_COLOR", - "COMBOBOX_HOVER_BORDER_COLOR", - "COMBOBOX_HOVER_INSIDE_COLOR", - "COMBOBOX_HOVER_TEXT_COLOR", - "COMBOBOX_HOVER_LIST_TEXT_COLOR", - "COMBOBOX_PRESSED_BORDER_COLOR", - "COMBOBOX_PRESSED_INSIDE_COLOR", - "COMBOBOX_PRESSED_TEXT_COLOR", - "COMBOBOX_PRESSED_LIST_BORDER_COLOR", - "COMBOBOX_PRESSED_LIST_INSIDE_COLOR", - "COMBOBOX_PRESSED_LIST_TEXT_COLOR", - "CHECKBOX_DEFAULT_BORDER_COLOR", - "CHECKBOX_DEFAULT_INSIDE_COLOR", - "CHECKBOX_HOVER_BORDER_COLOR", - "CHECKBOX_HOVER_INSIDE_COLOR", - "CHECKBOX_CLICK_BORDER_COLOR", - "CHECKBOX_CLICK_INSIDE_COLOR", - "CHECKBOX_STATUS_ACTIVE_COLOR", - "CHECKBOX_INSIDE_WIDTH", - "TEXTBOX_BORDER_WIDTH", - "TEXTBOX_BORDER_COLOR", - "TEXTBOX_INSIDE_COLOR", - "TEXTBOX_TEXT_COLOR", - "TEXTBOX_LINE_COLOR", - "TEXTBOX_TEXT_FONTSIZE", -} - -// For spinner -var ( - framesCounter int - framesCounter2 int - valueSpeed bool -) - -// BackgroundColor - Get background color -func BackgroundColor() rl.Color { - return rl.GetColor(int32(style[GlobalBackgroundColor])) -} - -// LinesColor - Get lines color -func LinesColor() rl.Color { - return rl.GetColor(int32(style[GlobalLinesColor])) -} - -// TextColor - Get text color for normal state -func TextColor() rl.Color { - return rl.GetColor(int32(style[GlobalTextColor])) -} - -// Label - Label element, show text -func Label(bounds rl.Rectangle, text string) { - LabelEx(bounds, text, rl.GetColor(int32(style[LabelTextColor])), rl.NewColor(0, 0, 0, 0), rl.NewColor(0, 0, 0, 0)) -} - -// LabelEx - Label element extended, configurable colors -func LabelEx(bounds rl.Rectangle, text string, textColor, border, inner rl.Color) { - b := bounds.ToInt32() - // Update control - textHeight := int32(style[GlobalTextFontsize]) - textWidth := rl.MeasureText(text, textHeight) - - if b.Width < textWidth { - b.Width = textWidth + int32(style[LabelTextPadding]) - } - if b.Height < textHeight { - b.Height = textHeight + int32(style[LabelTextPadding])/2 - } - - // Draw control - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, border) - rl.DrawRectangle(b.X+int32(style[LabelBorderWidth]), b.Y+int32(style[LabelBorderWidth]), b.Width-(2*int32(style[LabelBorderWidth])), b.Height-(2*int32(style[LabelBorderWidth])), inner) - rl.DrawText(text, b.X+((b.Width/2)-(textWidth/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) -} - -// Button - Button element, returns true when clicked -func Button(bounds rl.Rectangle, text string) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := rl.GetMousePosition() - clicked := false - - textHeight := int32(style[GlobalTextFontsize]) - textWidth := rl.MeasureText(text, textHeight) - - // Update control - if b.Width < textWidth { - b.Width = textWidth + int32(style[ButtonTextPadding]) - } - - if b.Height < textHeight { - b.Height = textHeight + int32(style[ButtonTextPadding])/2 - } - - if rl.CheckCollisionPointRec(mousePoint, bounds) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - clicked = true - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonDefaultBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonDefaultInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonDefaultTextColor]))) - break - - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonHoverBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonHoverInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonHoverTextColor]))) - break - - case Pressed: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonPressedBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonPressedInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonPressedTextColor]))) - break - - default: - break - } - - if clicked { - return true - } - - return false -} - -// ToggleButton - Toggle Button element, returns true when active -func ToggleButton(bounds rl.Rectangle, text string, active bool) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := rl.GetMousePosition() - - textHeight := int32(style[GlobalTextFontsize]) - textWidth := rl.MeasureText(text, textHeight) - - // Update control - if b.Width < textWidth { - b.Width = textWidth + int32(style[ToggleTextPadding]) - } - if b.Height < textHeight { - b.Height = textHeight + int32(style[ToggleTextPadding])/2 - } - - if rl.CheckCollisionPointRec(mousePoint, bounds) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - state = Normal - active = !active - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - if active { - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleActiveBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleActiveInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleDefaultTextColor]))) - } else { - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleDefaultBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleDefaultInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleDefaultTextColor]))) - } - break - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleHoverBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleHoverInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleHoverTextColor]))) - break - case Pressed: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[TogglePressedBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[TogglePressedInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[TogglePressedTextColor]))) - break - default: - break - } - - return active -} - -// ToggleGroup - Toggle Group element, returns toggled button index -func ToggleGroup(bounds rl.Rectangle, toggleText []string, active int) int { - for i := 0; i < len(toggleText); i++ { - if i == active { - ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true) - } else if ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) { - active = i - } - } - - return active -} - -// ComboBox draws a simplified version of a ComboBox allowing the user to select a string -// from a list accompanied by an N/M counter. The widget does not provide a drop-down/completion -// or any input support. -func ComboBox(bounds rl.Rectangle, comboText []string, active int) int { - // Reject invalid selections and disable rendering. - comboCount := len(comboText) - if active < 0 || active >= comboCount { - rl.TraceLog(rl.LogWarning, "ComboBox active expects 0 <= active <= %d", comboCount) - return -1 - } - - activeText := comboText[active] - - // style sizing. - textHeight := int32(style[GlobalTextFontsize]) - textWidth := rl.MeasureText(activeText, textHeight) - borderWidth := int32(style[ComboboxBorderWidth]) - textPadding := int32(style[ToggleTextPadding]) - - b := bounds.ToInt32() - if b.Width < textWidth { - b.Width = textWidth + textPadding - bounds.Width = float32(b.Width) - } - if b.Height < textHeight { - b.Height = textHeight + textPadding - bounds.Height = float32(b.Height) - } - - // Identify what the counter is going to look like with max digits so we don't resize it. - clickWidth := rl.MeasureText(fmt.Sprintf("%d/%d", comboCount, comboCount), b.Height) - - click := rl.NewRectangle(bounds.X+bounds.Width+float32(style[ComboboxPadding]), bounds.Y, float32(clickWidth), float32(b.Height)) - c := click.ToInt32() - mousePoint := rl.GetMousePosition() - state := Normal - if rl.CheckCollisionPointRec(mousePoint, bounds) || rl.CheckCollisionPointRec(mousePoint, click) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - state = Pressed - } else { - state = Focused - } - } - - // Draw control - var borderColor, insideColor, listColor, textColor rl.Color - - switch state { - case Normal: - borderColor = rl.GetColor(int32(style[ComboboxDefaultBorderColor])) - insideColor = rl.GetColor(int32(style[ComboboxDefaultInsideColor])) - listColor = rl.GetColor(int32(style[ComboboxDefaultListTextColor])) - textColor = rl.GetColor(int32(style[ComboboxDefaultTextColor])) - - case Focused: - borderColor = rl.GetColor(int32(style[ComboboxHoverBorderColor])) - insideColor = rl.GetColor(int32(style[ComboboxHoverInsideColor])) - listColor = rl.GetColor(int32(style[ComboboxHoverListTextColor])) - textColor = rl.GetColor(int32(style[ComboboxHoverTextColor])) - - case Pressed: - borderColor = rl.GetColor(int32(style[ComboboxPressedBorderColor])) - insideColor = rl.GetColor(int32(style[ComboboxPressedInsideColor])) - listColor = rl.GetColor(int32(style[ComboboxPressedListTextColor])) - textColor = rl.GetColor(int32(style[ComboboxPressedTextColor])) - - default: - rl.TraceLog(rl.LogWarning, "ComboBox in unrecognized state %d", state) - return -1 - } - - // Render the box itself - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, borderColor) - rl.DrawRectangle(b.X+borderWidth, b.Y+borderWidth, b.Width-(2*borderWidth), b.Height-(2*borderWidth), insideColor) - rl.DrawText(activeText, b.X+((b.Width/2)-(rl.MeasureText(activeText, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) - - // Render the accompanying "clicks" box showing the element counter. - rl.DrawRectangle(c.X, c.Y, c.Width, c.Height, borderColor) - rl.DrawRectangle(c.X+borderWidth, c.Y+borderWidth, c.Width-(2*borderWidth), c.Height-(2*borderWidth), insideColor) - companionText := fmt.Sprintf("%d/%d", active+1, comboCount) - rl.DrawText(companionText, c.X+((c.Width/2)-(rl.MeasureText(companionText, textHeight)/2)), c.Y+((c.Height/2)-(textHeight/2)), textHeight, listColor) - - if rl.CheckCollisionPointRec(mousePoint, bounds) || rl.CheckCollisionPointRec(mousePoint, click) { - if rl.IsMouseButtonPressed(rl.MouseLeftButton) { - active++ - if active >= comboCount { - active = 0 - } - } - } - - return active -} - -// CheckBox - Check Box element, returns true when active -func CheckBox(bounds rl.Rectangle, checked bool) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := rl.GetMousePosition() - - // Update control - if rl.CheckCollisionPointRec(mousePoint, bounds) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - state = Normal - checked = !checked - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxDefaultBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxDefaultInsideColor]))) - break - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxHoverBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxHoverInsideColor]))) - break - case Pressed: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxClickBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxClickInsideColor]))) - break - default: - break - } - - if checked { - rl.DrawRectangle(b.X+int32(style[CheckboxInsideWidth]), b.Y+int32(style[CheckboxInsideWidth]), b.Width-(2*int32(style[CheckboxInsideWidth])), b.Height-(2*int32(style[CheckboxInsideWidth])), rl.GetColor(int32(style[CheckboxDefaultActiveColor]))) - } - - return checked -} - -// Slider - Slider element, returns selected value -func Slider(bounds rl.Rectangle, value, minValue, maxValue float32) float32 { - b := bounds.ToInt32() - sliderPos := float32(0) - state := Normal - - buttonTravelDistance := float32(0) - mousePoint := rl.GetMousePosition() - - // Update control - if value < minValue { - value = minValue - } else if value >= maxValue { - value = maxValue - } - - sliderPos = (value - minValue) / (maxValue - minValue) - - sliderButton := rl.RectangleInt32{} - sliderButton.Width = (b.Width-(2*int32(style[SliderButtonBorderWidth])))/10 - 8 - sliderButton.Height = b.Height - (2 * int32(style[SliderBorderWidth]+2*style[SliderButtonBorderWidth])) - - sliderButtonMinPos := b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) - sliderButtonMaxPos := b.X + b.Width - (int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + sliderButton.Width) - - buttonTravelDistance = float32(sliderButtonMaxPos - sliderButtonMinPos) - - sliderButton.X = b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + int32(sliderPos*buttonTravelDistance) - sliderButton.Y = b.Y + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) - - if rl.CheckCollisionPointRec(mousePoint, bounds) { - state = Focused - - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } - - if state == Pressed && rl.IsMouseButtonDown(rl.MouseLeftButton) { - sliderButton.X = int32(mousePoint.X) - sliderButton.Width/2 - - if sliderButton.X <= sliderButtonMinPos { - sliderButton.X = sliderButtonMinPos - } else if sliderButton.X >= sliderButtonMaxPos { - sliderButton.X = sliderButtonMaxPos - } - - sliderPos = float32(sliderButton.X-sliderButtonMinPos) / buttonTravelDistance - } - } else { - state = Normal - } - - // Draw control - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[SliderBorderColor]))) - rl.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), rl.GetColor(int32(style[SliderInsideColor]))) - - switch state { - case Normal: - rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderDefaultColor]))) - break - case Focused: - rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderHoverColor]))) - break - case Pressed: - rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderActiveColor]))) - break - default: - break - } - - return minValue + (maxValue-minValue)*sliderPos -} - -// SliderBar - Slider Bar element, returns selected value -func SliderBar(bounds rl.Rectangle, value, minValue, maxValue float32) float32 { - b := bounds.ToInt32() - state := Normal - - mousePoint := rl.GetMousePosition() - - fixedValue := float32(0) - fixedMinValue := float32(0) - - fixedValue = value - minValue - maxValue = maxValue - minValue - fixedMinValue = 0 - - // Update control - if fixedValue <= fixedMinValue { - fixedValue = fixedMinValue - } else if fixedValue >= maxValue { - fixedValue = maxValue - } - - sliderBar := rl.RectangleInt32{} - - sliderBar.X = b.X + int32(style[SliderBorderWidth]) - sliderBar.Y = b.Y + int32(style[SliderBorderWidth]) - sliderBar.Width = int32((fixedValue * (float32(b.Width) - 2*float32(style[SliderBorderWidth]))) / (maxValue - fixedMinValue)) - sliderBar.Height = b.Height - 2*int32(style[SliderBorderWidth]) - - if rl.CheckCollisionPointRec(mousePoint, bounds) { - state = Focused - - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - - sliderBar.Width = (int32(mousePoint.X) - b.X - int32(style[SliderBorderWidth])) - - if int32(mousePoint.X) <= (b.X + int32(style[SliderBorderWidth])) { - sliderBar.Width = 0 - } else if int32(mousePoint.X) >= (b.X + b.Width - int32(style[SliderBorderWidth])) { - sliderBar.Width = b.Width - 2*int32(style[SliderBorderWidth]) - } - } - } else { - state = Normal - } - - fixedValue = (float32(sliderBar.Width) * (maxValue - fixedMinValue)) / (float32(b.Width) - 2*float32(style[SliderBorderWidth])) - - // Draw control - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[SliderbarBorderColor]))) - rl.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), rl.GetColor(int32(style[SliderbarInsideColor]))) - - switch state { - case Normal: - rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarDefaultColor]))) - break - case Focused: - rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarHoverColor]))) - break - case Pressed: - rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarActiveColor]))) - break - default: - break - } - - if minValue < 0 && maxValue > 0 { - rl.DrawRectangle((b.X+int32(style[SliderBorderWidth]))-int32(minValue*(float32(b.Width-(int32(style[SliderBorderWidth])*2))/maxValue)), sliderBar.Y, 1, sliderBar.Height, rl.GetColor(int32(style[SliderbarZeroLineColor]))) - } - - return fixedValue + minValue -} - -// ProgressBar - Progress Bar element, shows current progress value -func ProgressBar(bounds rl.Rectangle, value float32) { - b := bounds.ToInt32() - if value > 1.0 { - value = 1.0 - } else if value < 0.0 { - value = 0.0 - } - - progressBar := rl.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), b.Width - (int32(style[ProgressbarBorderWidth]) * 2), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} - progressValue := rl.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), int32(value * float32(b.Width-int32(style[ProgressbarBorderWidth])*2)), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} - - // Draw control - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ProgressbarBorderColor]))) - rl.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, rl.GetColor(int32(style[ProgressbarInsideColor]))) - rl.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, rl.GetColor(int32(style[ProgressbarProgressColor]))) -} - -// Spinner - Spinner element, returns selected value -func Spinner(bounds rl.Rectangle, value, minValue, maxValue int) int { - b := bounds.ToInt32() - state := Normal - - mousePoint := rl.GetMousePosition() - labelBoxBound := rl.RectangleInt32{b.X + b.Width/4 + 1, b.Y, b.Width / 2, b.Height} - leftButtonBound := rl.RectangleInt32{b.X, b.Y, b.Width / 4, b.Height} - rightButtonBound := rl.RectangleInt32{b.X + b.Width - b.Width/4 + 1, b.Y, b.Width / 4, b.Height} - - textHeight := int32(style[GlobalTextFontsize]) - textWidth := rl.MeasureText(fmt.Sprintf("%d", value), textHeight) - - buttonSide := 0 - - // Update control - if rl.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) || rl.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) || rl.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { - if rl.IsKeyDown(rl.KeyLeft) { - state = Pressed - buttonSide = 1 - - if value > minValue { - value-- - } - } else if rl.IsKeyDown(rl.KeyRight) { - state = Pressed - buttonSide = 2 - - if value < maxValue { - value++ - } - } - } - - if rl.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) { - buttonSide = 1 - state = Focused - - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - if !valueSpeed { - if value > minValue { - value-- - } - valueSpeed = true - } else { - framesCounter++ - } - - state = Pressed - - if value > minValue { - if framesCounter >= 30 { - value-- - } - } - } - } else if rl.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) { - buttonSide = 2 - state = Focused - - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - if !valueSpeed { - if value < maxValue { - value++ - } - valueSpeed = true - } else { - framesCounter++ - } - - state = Pressed - - if value < maxValue { - if framesCounter >= 30 { - value++ - } - } - } - } else if !rl.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { - buttonSide = 0 - } - - if rl.IsMouseButtonUp(rl.MouseLeftButton) { - valueSpeed = false - framesCounter = 0 - } - - // Draw control - switch state { - case Normal: - rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - - rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) - rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) - - rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultTextColor]))) - break - case Focused: - if buttonSide == 1 { - rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) - rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) - - rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverSymbolColor]))) - rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - } else if buttonSide == 2 { - rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) - rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) - - rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverSymbolColor]))) - } - - rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) - rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) - - rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverTextColor]))) - break - case Pressed: - if buttonSide == 1 { - rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) - rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) - - rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedSymbolColor]))) - rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - } else if buttonSide == 2 { - rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) - rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) - - rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedSymbolColor]))) - } - - rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) - rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) - - rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedTextColor]))) - break - default: - break - } - - return value -} - -// TextBox - Text Box element, updates input text -func TextBox(bounds rl.Rectangle, text string) string { - b := bounds.ToInt32() - state := Normal - - mousePoint := rl.GetMousePosition() - letter := int32(-1) - - // Update control - if rl.CheckCollisionPointRec(mousePoint, bounds) { - state = Focused // NOTE: PRESSED state is not used on this control - - framesCounter2++ - - letter = rl.GetKeyPressed() - if letter != -1 { - if letter >= 32 && letter < 127 { - text = fmt.Sprintf("%s%c", text, letter) - } - } - - if rl.IsKeyPressed(rl.KeyBackspace) { - if len(text) > 0 { - text = text[:len(text)-1] - } - } - } - - // Draw control - switch state { - case Normal: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[TextboxBorderColor]))) - rl.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), rl.GetColor(int32(style[TextboxInsideColor]))) - rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), rl.GetColor(int32(style[TextboxTextColor]))) - break - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleActiveBorderColor]))) - rl.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), rl.GetColor(int32(style[TextboxInsideColor]))) - rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), rl.GetColor(int32(style[TextboxTextColor]))) - - if (framesCounter2/20)%2 == 0 && rl.CheckCollisionPointRec(mousePoint, bounds) { - rl.DrawRectangle(b.X+4+rl.MeasureText(text, int32(style[GlobalTextFontsize])), b.Y+2, 1, b.Height-4, rl.GetColor(int32(style[TextboxLineColor]))) - } - break - case Pressed: - break - default: - break - } - - return text -} - -// SaveGuiStyle - Save GUI style file -func SaveGuiStyle(fileName string) { - var styleFile string - for i := 0; i < len(propertyName); i++ { - styleFile += fmt.Sprintf("%-40s0x%x\n", propertyName[i], GetStyleProperty(Property(i))) - } - - ioutil.WriteFile(fileName, []byte(styleFile), 0644) -} - -// LoadGuiStyle - Load GUI style file -func LoadGuiStyle(fileName string) { - file, err := rl.OpenAsset(fileName) - if err != nil { - rl.TraceLog(rl.LogWarning, "[%s] GUI style file could not be opened", fileName) - return - } - defer file.Close() - - var lines []string - scanner := bufio.NewScanner(file) - for scanner.Scan() { - lines = append(lines, scanner.Text()) - } - - for _, line := range lines { - fields := strings.Fields(line) - if len(fields) != 2 { - continue - } - - id := fields[0] - value := fields[1] - - for i := 0; i < len(propertyName); i++ { - if id == propertyName[i] { - if strings.HasPrefix(value, "0x") { - value = value[2:] - } - - v, err := strconv.ParseInt(value, 16, 64) - if err == nil { - style[i] = int64(v) - } - } - } - } -} - -// SetStyleProperty - Set one style property -func SetStyleProperty(guiProperty Property, value int64) { - style[guiProperty] = value -} - -// GetStyleProperty - Get one style property -func GetStyleProperty(guiProperty Property) int64 { - return style[int(guiProperty)] -} diff --git a/raygui/slider.go b/raygui/slider.go new file mode 100644 index 0000000..153b867 --- /dev/null +++ b/raygui/slider.go @@ -0,0 +1,76 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// Slider - Slider element, returns selected value +func Slider(bounds rl.Rectangle, value, minValue, maxValue float32) float32 { + b := bounds.ToInt32() + sliderPos := float32(0) + state := Normal + + buttonTravelDistance := float32(0) + mousePoint := rl.GetMousePosition() + + // Update control + if value < minValue { + value = minValue + } else if value >= maxValue { + value = maxValue + } + + sliderPos = (value - minValue) / (maxValue - minValue) + + sliderButton := rl.RectangleInt32{} + sliderButton.Width = (b.Width-(2*int32(style[SliderButtonBorderWidth])))/10 - 8 + sliderButton.Height = b.Height - (2 * int32(style[SliderBorderWidth]+2*style[SliderButtonBorderWidth])) + + sliderButtonMinPos := b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + sliderButtonMaxPos := b.X + b.Width - (int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + sliderButton.Width) + + buttonTravelDistance = float32(sliderButtonMaxPos - sliderButtonMinPos) + + sliderButton.X = b.X + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + int32(sliderPos*buttonTravelDistance) + sliderButton.Y = b.Y + int32(style[SliderBorderWidth]) + int32(style[SliderButtonBorderWidth]) + + if rl.CheckCollisionPointRec(mousePoint, bounds) { + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + } + + if state == Pressed && rl.IsMouseButtonDown(rl.MouseLeftButton) { + sliderButton.X = int32(mousePoint.X) - sliderButton.Width/2 + + if sliderButton.X <= sliderButtonMinPos { + sliderButton.X = sliderButtonMinPos + } else if sliderButton.X >= sliderButtonMaxPos { + sliderButton.X = sliderButtonMaxPos + } + + sliderPos = float32(sliderButton.X-sliderButtonMinPos) / buttonTravelDistance + } + } else { + state = Normal + } + + // Draw control + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[SliderBorderColor]))) + rl.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), rl.GetColor(int32(style[SliderInsideColor]))) + + switch state { + case Normal: + rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderDefaultColor]))) + break + case Focused: + rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderHoverColor]))) + break + case Pressed: + rl.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, rl.GetColor(int32(style[SliderActiveColor]))) + break + default: + break + } + + return minValue + (maxValue-minValue)*sliderPos +} diff --git a/raygui/sliderbar.go b/raygui/sliderbar.go new file mode 100644 index 0000000..dbce8fc --- /dev/null +++ b/raygui/sliderbar.go @@ -0,0 +1,76 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// SliderBar - Slider Bar element, returns selected value +func SliderBar(bounds rl.Rectangle, value, minValue, maxValue float32) float32 { + b := bounds.ToInt32() + state := Normal + + mousePoint := rl.GetMousePosition() + + fixedValue := float32(0) + fixedMinValue := float32(0) + + fixedValue = value - minValue + maxValue = maxValue - minValue + fixedMinValue = 0 + + // Update control + if fixedValue <= fixedMinValue { + fixedValue = fixedMinValue + } else if fixedValue >= maxValue { + fixedValue = maxValue + } + + sliderBar := rl.RectangleInt32{} + + sliderBar.X = b.X + int32(style[SliderBorderWidth]) + sliderBar.Y = b.Y + int32(style[SliderBorderWidth]) + sliderBar.Width = int32((fixedValue * (float32(b.Width) - 2*float32(style[SliderBorderWidth]))) / (maxValue - fixedMinValue)) + sliderBar.Height = b.Height - 2*int32(style[SliderBorderWidth]) + + if rl.CheckCollisionPointRec(mousePoint, bounds) { + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + + sliderBar.Width = (int32(mousePoint.X) - b.X - int32(style[SliderBorderWidth])) + + if int32(mousePoint.X) <= (b.X + int32(style[SliderBorderWidth])) { + sliderBar.Width = 0 + } else if int32(mousePoint.X) >= (b.X + b.Width - int32(style[SliderBorderWidth])) { + sliderBar.Width = b.Width - 2*int32(style[SliderBorderWidth]) + } + } + } else { + state = Normal + } + + fixedValue = (float32(sliderBar.Width) * (maxValue - fixedMinValue)) / (float32(b.Width) - 2*float32(style[SliderBorderWidth])) + + // Draw control + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[SliderbarBorderColor]))) + rl.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), rl.GetColor(int32(style[SliderbarInsideColor]))) + + switch state { + case Normal: + rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarDefaultColor]))) + break + case Focused: + rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarHoverColor]))) + break + case Pressed: + rl.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, rl.GetColor(int32(style[SliderbarActiveColor]))) + break + default: + break + } + + if minValue < 0 && maxValue > 0 { + rl.DrawRectangle((b.X+int32(style[SliderBorderWidth]))-int32(minValue*(float32(b.Width-(int32(style[SliderBorderWidth])*2))/maxValue)), sliderBar.Y, 1, sliderBar.Height, rl.GetColor(int32(style[SliderbarZeroLineColor]))) + } + + return fixedValue + minValue +} diff --git a/raygui/spinner.go b/raygui/spinner.go new file mode 100644 index 0000000..eb9a8f3 --- /dev/null +++ b/raygui/spinner.go @@ -0,0 +1,176 @@ +package raygui + +import ( + "fmt" + "github.com/gen2brain/raylib-go/raylib" +) + +// For spinner +var ( + framesCounter int + framesCounter2 int + valueSpeed bool +) + +// Spinner - Spinner element, returns selected value +func Spinner(bounds rl.Rectangle, value, minValue, maxValue int) int { + b := bounds.ToInt32() + state := Normal + + mousePoint := rl.GetMousePosition() + labelBoxBound := rl.RectangleInt32{b.X + b.Width/4 + 1, b.Y, b.Width / 2, b.Height} + leftButtonBound := rl.RectangleInt32{b.X, b.Y, b.Width / 4, b.Height} + rightButtonBound := rl.RectangleInt32{b.X + b.Width - b.Width/4 + 1, b.Y, b.Width / 4, b.Height} + + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(fmt.Sprintf("%d", value), textHeight) + + buttonSide := 0 + + // Update control + if rl.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) || rl.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) || rl.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { + if rl.IsKeyDown(rl.KeyLeft) { + state = Pressed + buttonSide = 1 + + if value > minValue { + value-- + } + } else if rl.IsKeyDown(rl.KeyRight) { + state = Pressed + buttonSide = 2 + + if value < maxValue { + value++ + } + } + } + + if rl.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) { + buttonSide = 1 + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + if !valueSpeed { + if value > minValue { + value-- + } + valueSpeed = true + } else { + framesCounter++ + } + + state = Pressed + + if value > minValue { + if framesCounter >= 30 { + value-- + } + } + } + } else if rl.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) { + buttonSide = 2 + state = Focused + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + if !valueSpeed { + if value < maxValue { + value++ + } + valueSpeed = true + } else { + framesCounter++ + } + + state = Pressed + + if value < maxValue { + if framesCounter >= 30 { + value++ + } + } + } + } else if !rl.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { + buttonSide = 0 + } + + if rl.IsMouseButtonUp(rl.MouseLeftButton) { + valueSpeed = false + framesCounter = 0 + } + + // Draw control + switch state { + case Normal: + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + + rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) + rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) + + rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultTextColor]))) + break + case Focused: + if buttonSide == 1 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + } else if buttonSide == 2 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverSymbolColor]))) + } + + rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) + rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) + + rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerHoverTextColor]))) + break + case Pressed: + if buttonSide == 1 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + } else if buttonSide == 2 { + rl.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, rl.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) + rl.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, rl.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) + + rl.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, rl.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) + rl.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, rl.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) + + rl.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(rl.MeasureText("+", textHeight))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerDefaultSymbolColor]))) + rl.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(rl.MeasureText("-", textHeight))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedSymbolColor]))) + } + + rl.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, rl.GetColor(int32(style[SpinnerLabelBorderColor]))) + rl.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, rl.GetColor(int32(style[SpinnerLabelInsideColor]))) + + rl.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(textHeight/2)), textHeight, rl.GetColor(int32(style[SpinnerPressedTextColor]))) + break + default: + break + } + + return value +} diff --git a/raygui/style.go b/raygui/style.go new file mode 100644 index 0000000..f97efe1 --- /dev/null +++ b/raygui/style.go @@ -0,0 +1,414 @@ +// GUI element appearance can be dynamically configured through Property values, the set of which +// forms a theme called the Style. +package raygui + +import ( + "bufio" + "fmt" + rl "github.com/gen2brain/raylib-go/raylib" + "io/ioutil" + "strconv" + "strings" +) + +// Property - GUI property +type Property int32 + +// GUI properties enumeration +const ( + GlobalBaseColor Property = iota + GlobalBorderColor + GlobalTextColor + GlobalTextFontsize + GlobalBorderWidth + GlobalBackgroundColor + GlobalLinesColor + LabelBorderWidth + LabelTextColor + LabelTextPadding + ButtonBorderWidth + ButtonTextPadding + ButtonDefaultBorderColor + ButtonDefaultInsideColor + ButtonDefaultTextColor + ButtonHoverBorderColor + ButtonHoverInsideColor + ButtonHoverTextColor + ButtonPressedBorderColor + ButtonPressedInsideColor + ButtonPressedTextColor + ToggleTextPadding + ToggleBorderWidth + ToggleDefaultBorderColor + ToggleDefaultInsideColor + ToggleDefaultTextColor + ToggleHoverBorderColor + ToggleHoverInsideColor + ToggleHoverTextColor + TogglePressedBorderColor + TogglePressedInsideColor + TogglePressedTextColor + ToggleActiveBorderColor + ToggleActiveInsideColor + ToggleActiveTextColor + TogglegroupPadding + SliderBorderWidth + SliderButtonBorderWidth + SliderBorderColor + SliderInsideColor + SliderDefaultColor + SliderHoverColor + SliderActiveColor + SliderbarBorderColor + SliderbarInsideColor + SliderbarDefaultColor + SliderbarHoverColor + SliderbarActiveColor + SliderbarZeroLineColor + ProgressbarBorderColor + ProgressbarInsideColor + ProgressbarProgressColor + ProgressbarBorderWidth + SpinnerLabelBorderColor + SpinnerLabelInsideColor + SpinnerDefaultButtonBorderColor + SpinnerDefaultButtonInsideColor + SpinnerDefaultSymbolColor + SpinnerDefaultTextColor + SpinnerHoverButtonBorderColor + SpinnerHoverButtonInsideColor + SpinnerHoverSymbolColor + SpinnerHoverTextColor + SpinnerPressedButtonBorderColor + SpinnerPressedButtonInsideColor + SpinnerPressedSymbolColor + SpinnerPressedTextColor + ComboboxPadding + boundsWidth + boundsHeight + ComboboxBorderWidth + ComboboxDefaultBorderColor + ComboboxDefaultInsideColor + ComboboxDefaultTextColor + ComboboxDefaultListTextColor + ComboboxHoverBorderColor + ComboboxHoverInsideColor + ComboboxHoverTextColor + ComboboxHoverListTextColor + ComboboxPressedBorderColor + ComboboxPressedInsideColor + ComboboxPressedTextColor + ComboboxPressedListBorderColor + ComboboxPressedListInsideColor + ComboboxPressedListTextColor + CheckboxDefaultBorderColor + CheckboxDefaultInsideColor + CheckboxHoverBorderColor + CheckboxHoverInsideColor + CheckboxClickBorderColor + CheckboxClickInsideColor + CheckboxDefaultActiveColor + CheckboxInsideWidth + TextboxBorderWidth + TextboxBorderColor + TextboxInsideColor + TextboxTextColor + TextboxLineColor + TextboxTextFontsize + + // Add new properties above. + NumProperties +) + +// GUI property names (to read/write style text files) +var propertyName = [NumProperties]string{ + "GLOBAL_BASE_COLOR", + "GLOBAL_BORDER_COLOR", + "GLOBAL_TEXT_COLOR", + "GLOBAL_TEXT_FONTSIZE", + "GLOBAL_BORDER_WIDTH", + "BACKGROUND_COLOR", + "LINES_COLOR", + "LABEL_BORDER_WIDTH", + "LABEL_TEXT_COLOR", + "LABEL_TEXT_PADDING", + "BUTTON_BORDER_WIDTH", + "BUTTON_TEXT_PADDING", + "BUTTON_DEFAULT_BORDER_COLOR", + "BUTTON_DEFAULT_INSIDE_COLOR", + "BUTTON_DEFAULT_TEXT_COLOR", + "BUTTON_HOVER_BORDER_COLOR", + "BUTTON_HOVER_INSIDE_COLOR", + "BUTTON_HOVER_TEXT_COLOR", + "BUTTON_PRESSED_BORDER_COLOR", + "BUTTON_PRESSED_INSIDE_COLOR", + "BUTTON_PRESSED_TEXT_COLOR", + "TOGGLE_TEXT_PADDING", + "TOGGLE_BORDER_WIDTH", + "TOGGLE_DEFAULT_BORDER_COLOR", + "TOGGLE_DEFAULT_INSIDE_COLOR", + "TOGGLE_DEFAULT_TEXT_COLOR", + "TOGGLE_HOVER_BORDER_COLOR", + "TOGGLE_HOVER_INSIDE_COLOR", + "TOGGLE_HOVER_TEXT_COLOR", + "TOGGLE_PRESSED_BORDER_COLOR", + "TOGGLE_PRESSED_INSIDE_COLOR", + "TOGGLE_PRESSED_TEXT_COLOR", + "TOGGLE_ACTIVE_BORDER_COLOR", + "TOGGLE_ACTIVE_INSIDE_COLOR", + "TOGGLE_ACTIVE_TEXT_COLOR", + "TOGGLEGROUP_PADDING", + "SLIDER_BORDER_WIDTH", + "SLIDER_BUTTON_BORDER_WIDTH", + "SLIDER_BORDER_COLOR", + "SLIDER_INSIDE_COLOR", + "SLIDER_DEFAULT_COLOR", + "SLIDER_HOVER_COLOR", + "SLIDER_ACTIVE_COLOR", + "SLIDERBAR_BORDER_COLOR", + "SLIDERBAR_INSIDE_COLOR", + "SLIDERBAR_DEFAULT_COLOR", + "SLIDERBAR_HOVER_COLOR", + "SLIDERBAR_ACTIVE_COLOR", + "SLIDERBAR_ZERO_LINE_COLOR", + "PROGRESSBAR_BORDER_COLOR", + "PROGRESSBAR_INSIDE_COLOR", + "PROGRESSBAR_PROGRESS_COLOR", + "PROGRESSBAR_BORDER_WIDTH", + "SPINNER_LABEL_BORDER_COLOR", + "SPINNER_LABEL_INSIDE_COLOR", + "SPINNER_DEFAULT_BUTTON_BORDER_COLOR", + "SPINNER_DEFAULT_BUTTON_INSIDE_COLOR", + "SPINNER_DEFAULT_SYMBOL_COLOR", + "SPINNER_DEFAULT_TEXT_COLOR", + "SPINNER_HOVER_BUTTON_BORDER_COLOR", + "SPINNER_HOVER_BUTTON_INSIDE_COLOR", + "SPINNER_HOVER_SYMBOL_COLOR", + "SPINNER_HOVER_TEXT_COLOR", + "SPINNER_PRESSED_BUTTON_BORDER_COLOR", + "SPINNER_PRESSED_BUTTON_INSIDE_COLOR", + "SPINNER_PRESSED_SYMBOL_COLOR", + "SPINNER_PRESSED_TEXT_COLOR", + "COMBOBOX_PADDING", + "COMBOBOX_BUTTON_WIDTH", + "COMBOBOX_BUTTON_HEIGHT", + "COMBOBOX_BORDER_WIDTH", + "COMBOBOX_DEFAULT_BORDER_COLOR", + "COMBOBOX_DEFAULT_INSIDE_COLOR", + "COMBOBOX_DEFAULT_TEXT_COLOR", + "COMBOBOX_DEFAULT_LIST_TEXT_COLOR", + "COMBOBOX_HOVER_BORDER_COLOR", + "COMBOBOX_HOVER_INSIDE_COLOR", + "COMBOBOX_HOVER_TEXT_COLOR", + "COMBOBOX_HOVER_LIST_TEXT_COLOR", + "COMBOBOX_PRESSED_BORDER_COLOR", + "COMBOBOX_PRESSED_INSIDE_COLOR", + "COMBOBOX_PRESSED_TEXT_COLOR", + "COMBOBOX_PRESSED_LIST_BORDER_COLOR", + "COMBOBOX_PRESSED_LIST_INSIDE_COLOR", + "COMBOBOX_PRESSED_LIST_TEXT_COLOR", + "CHECKBOX_DEFAULT_BORDER_COLOR", + "CHECKBOX_DEFAULT_INSIDE_COLOR", + "CHECKBOX_HOVER_BORDER_COLOR", + "CHECKBOX_HOVER_INSIDE_COLOR", + "CHECKBOX_CLICK_BORDER_COLOR", + "CHECKBOX_CLICK_INSIDE_COLOR", + "CHECKBOX_STATUS_ACTIVE_COLOR", + "CHECKBOX_INSIDE_WIDTH", + "TEXTBOX_BORDER_WIDTH", + "TEXTBOX_BORDER_COLOR", + "TEXTBOX_INSIDE_COLOR", + "TEXTBOX_TEXT_COLOR", + "TEXTBOX_LINE_COLOR", + "TEXTBOX_TEXT_FONTSIZE", +} + +// Current GUI style (default light). +var style = [NumProperties]int64{ + 0xf5f5f5ff, // GLOBAL_BASE_COLOR + 0xf5f5f5ff, // GLOBAL_BORDER_COLOR + 0xf5f5f5ff, // GLOBAL_TEXT_COLOR + 10, // GLOBAL_TEXT_FONTSIZE + 1, // GLOBAL_BORDER_WIDTH + 0xf5f5f5ff, // BACKGROUND_COLOR + 0x90abb5ff, // LINES_COLOR + 1, // LABEL_BORDER_WIDTH + 0x4d4d4dff, // LABEL_TEXT_COLOR + 20, // LABEL_TEXT_PADDING + 2, // BUTTON_BORDER_WIDTH + 20, // BUTTON_TEXT_PADDING + 0x828282ff, // BUTTON_DEFAULT_BORDER_COLOR + 0xc8c8c8ff, // BUTTON_DEFAULT_INSIDE_COLOR + 0x4d4d4dff, // BUTTON_DEFAULT_TEXT_COLOR + 0xc8c8c8ff, // BUTTON_HOVER_BORDER_COLOR + 0xffffffff, // BUTTON_HOVER_INSIDE_COLOR + 0x868686ff, // BUTTON_HOVER_TEXT_COLOR + 0x7bb0d6ff, // BUTTON_PRESSED_BORDER_COLOR + 0xbcecffff, // BUTTON_PRESSED_INSIDE_COLOR + 0x5f9aa7ff, // BUTTON_PRESSED_TEXT_COLOR + 20, // TOGGLE_TEXT_PADDING + 1, // TOGGLE_BORDER_WIDTH + 0x828282ff, // TOGGLE_DEFAULT_BORDER_COLOR + 0xc8c8c8ff, // TOGGLE_DEFAULT_INSIDE_COLOR + 0x828282ff, // TOGGLE_DEFAULT_TEXT_COLOR + 0xc8c8c8ff, // TOGGLE_HOVER_BORDER_COLOR + 0xffffffff, // TOGGLE_HOVER_INSIDE_COLOR + 0x828282ff, // TOGGLE_HOVER_TEXT_COLOR + 0xbdd7eaff, // TOGGLE_PRESSED_BORDER_COLOR + 0xddf5ffff, // TOGGLE_PRESSED_INSIDE_COLOR + 0xafccd3ff, // TOGGLE_PRESSED_TEXT_COLOR + 0x7bb0d6ff, // TOGGLE_ACTIVE_BORDER_COLOR + 0xbcecffff, // TOGGLE_ACTIVE_INSIDE_COLOR + 0x5f9aa7ff, // TOGGLE_ACTIVE_TEXT_COLOR + 3, // TOGGLEGROUP_PADDING + 1, // SLIDER_BORDER_WIDTH + 1, // SLIDER_BUTTON_BORDER_WIDTH + 0x828282ff, // SLIDER_BORDER_COLOR + 0xc8c8c8ff, // SLIDER_INSIDE_COLOR + 0xbcecffff, // SLIDER_DEFAULT_COLOR + 0xffffffff, // SLIDER_HOVER_COLOR + 0xddf5ffff, // SLIDER_ACTIVE_COLOR + 0x828282ff, // SLIDERBAR_BORDER_COLOR + 0xc8c8c8ff, // SLIDERBAR_INSIDE_COLOR + 0xbcecffff, // SLIDERBAR_DEFAULT_COLOR + 0xffffffff, // SLIDERBAR_HOVER_COLOR + 0xddf5ffff, // SLIDERBAR_ACTIVE_COLOR + 0x828282ff, // SLIDERBAR_ZERO_LINE_COLOR + 0x828282ff, // PROGRESSBAR_BORDER_COLOR + 0xc8c8c8ff, // PROGRESSBAR_INSIDE_COLOR + 0xbcecffff, // PROGRESSBAR_PROGRESS_COLOR + 2, // PROGRESSBAR_BORDER_WIDTH + 0x828282ff, // SPINNER_LABEL_BORDER_COLOR + 0xc8c8c8ff, // SPINNER_LABEL_INSIDE_COLOR + 0x828282ff, // SPINNER_DEFAULT_BUTTON_BORDER_COLOR + 0xc8c8c8ff, // SPINNER_DEFAULT_BUTTON_INSIDE_COLOR + 0x000000ff, // SPINNER_DEFAULT_SYMBOL_COLOR + 0x000000ff, // SPINNER_DEFAULT_TEXT_COLOR + 0xc8c8c8ff, // SPINNER_HOVER_BUTTON_BORDER_COLOR + 0xffffffff, // SPINNER_HOVER_BUTTON_INSIDE_COLOR + 0x000000ff, // SPINNER_HOVER_SYMBOL_COLOR + 0x000000ff, // SPINNER_HOVER_TEXT_COLOR + 0x7bb0d6ff, // SPINNER_PRESSED_BUTTON_BORDER_COLOR + 0xbcecffff, // SPINNER_PRESSED_BUTTON_INSIDE_COLOR + 0x5f9aa7ff, // SPINNER_PRESSED_SYMBOL_COLOR + 0x000000ff, // SPINNER_PRESSED_TEXT_COLOR + 1, // COMBOBOX_PADDING + 30, // COMBOBOX_BUTTON_WIDTH + 20, // COMBOBOX_BUTTON_HEIGHT + 1, // COMBOBOX_BORDER_WIDTH + 0x828282ff, // COMBOBOX_DEFAULT_BORDER_COLOR + 0xc8c8c8ff, // COMBOBOX_DEFAULT_INSIDE_COLOR + 0x828282ff, // COMBOBOX_DEFAULT_TEXT_COLOR + 0x828282ff, // COMBOBOX_DEFAULT_LIST_TEXT_COLOR + 0xc8c8c8ff, // COMBOBOX_HOVER_BORDER_COLOR + 0xffffffff, // COMBOBOX_HOVER_INSIDE_COLOR + 0x828282ff, // COMBOBOX_HOVER_TEXT_COLOR + 0x828282ff, // COMBOBOX_HOVER_LIST_TEXT_COLOR + 0x7bb0d6ff, // COMBOBOX_PRESSED_BORDER_COLOR + 0xbcecffff, // COMBOBOX_PRESSED_INSIDE_COLOR + 0x5f9aa7ff, // COMBOBOX_PRESSED_TEXT_COLOR + 0x0078acff, // COMBOBOX_PRESSED_LIST_BORDER_COLOR + 0x66e7ffff, // COMBOBOX_PRESSED_LIST_INSIDE_COLOR + 0x0078acff, // COMBOBOX_PRESSED_LIST_TEXT_COLOR + 0x828282ff, // CHECKBOX_DEFAULT_BORDER_COLOR + 0xffffffff, // CHECKBOX_DEFAULT_INSIDE_COLOR + 0xc8c8c8ff, // CHECKBOX_HOVER_BORDER_COLOR + 0xffffffff, // CHECKBOX_HOVER_INSIDE_COLOR + 0x66e7ffff, // CHECKBOX_CLICK_BORDER_COLOR + 0xddf5ffff, // CHECKBOX_CLICK_INSIDE_COLOR + 0xbcecffff, // CHECKBOX_STATUS_ACTIVE_COLOR + 1, // CHECKBOX_INSIDE_WIDTH + 1, // TEXTBOX_BORDER_WIDTH + 0x828282ff, // TEXTBOX_BORDER_COLOR + 0xf5f5f5ff, // TEXTBOX_INSIDE_COLOR + 0x000000ff, // TEXTBOX_TEXT_COLOR + 0x000000ff, // TEXTBOX_LINE_COLOR + 10, // TEXTBOX_TEXT_FONTSIZE +} + +// LoadGuiStyle will load a GUI style from a file. See SaveGuiStyle. +func LoadGuiStyle(fileName string) { + file, err := rl.OpenAsset(fileName) + if err != nil { + rl.TraceLog(rl.LogWarning, "[%s] GUI style file could not be opened: %w", fileName, err) + return + } + defer file.Close() + + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for _, line := range lines { + fields := strings.Fields(line) + if len(fields) != 2 { + continue + } + + id := fields[0] + value := fields[1] + + for i := 0; i < len(propertyName); i++ { + if id == propertyName[i] { + if strings.HasPrefix(value, "0x") { + value = value[2:] + } + + v, err := strconv.ParseInt(value, 16, 64) + if err == nil { + style[i] = int64(v) + } + } + } + } +} + +// SaveGuiStyle will write the current GUI style to a file in a format suitable for loading via LoadGuiStyle. +func SaveGuiStyle(fileName string) { + var styleFile string + for i := 0; i < len(propertyName); i++ { + styleFile += fmt.Sprintf("%-40s0x%x\n", propertyName[i], GetStyleProperty(Property(i))) + } + + if err := ioutil.WriteFile(fileName, []byte(styleFile), 0644); err != nil { + rl.TraceLog(rl.LogWarning, "[%s] GUI style file could not be written: %w", fileName, err) + } +} + +// SetStyleProperty - Set one style property +func SetStyleProperty(guiProperty Property, value int64) { + style[guiProperty] = value +} + +// GetStyleProperty - Get one style property +func GetStyleProperty(guiProperty Property) int64 { + return style[int(guiProperty)] +} + +// BackgroundColor will return the current background color +func BackgroundColor() rl.Color { + return rl.GetColor(int32(style[GlobalBackgroundColor])) +} + +// LinesColor will return the current color for lines +func LinesColor() rl.Color { + return rl.GetColor(int32(style[GlobalLinesColor])) +} + +// TextColor will return the current color for normal state +func TextColor() rl.Color { + return rl.GetColor(int32(style[GlobalTextColor])) +} + +// GetStyle32 will return the int32 for a given property of the current style +func GetStyle32(property Property) int32 { + return int32(style[property]) +} + +// GetPropColor will return the Color value for a given property of the current style +func GetStyleColor(property Property) rl.Color { + return rl.GetColor(int32(style[property])) +} + diff --git a/raygui/textbox.go b/raygui/textbox.go new file mode 100644 index 0000000..e0e356e --- /dev/null +++ b/raygui/textbox.go @@ -0,0 +1,59 @@ +package raygui + +import ( + "fmt" + "github.com/gen2brain/raylib-go/raylib" +) + +// TextBox - Text Box element, updates input text +func TextBox(bounds rl.Rectangle, text string) string { + b := bounds.ToInt32() + state := Normal + + mousePoint := rl.GetMousePosition() + letter := int32(-1) + + // Update control + if rl.CheckCollisionPointRec(mousePoint, bounds) { + state = Focused // NOTE: PRESSED state is not used on this control + + framesCounter2++ + + letter = rl.GetKeyPressed() + if letter != -1 { + if letter >= 32 && letter < 127 { + text = fmt.Sprintf("%s%c", text, letter) + } + } + + if rl.IsKeyPressed(rl.KeyBackspace) { + if len(text) > 0 { + text = text[:len(text)-1] + } + } + } + + // Draw control + switch state { + case Normal: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[TextboxBorderColor]))) + rl.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), rl.GetColor(int32(style[TextboxInsideColor]))) + rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), rl.GetColor(int32(style[TextboxTextColor]))) + break + case Focused: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleActiveBorderColor]))) + rl.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), rl.GetColor(int32(style[TextboxInsideColor]))) + rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), rl.GetColor(int32(style[TextboxTextColor]))) + + if (framesCounter2/20)%2 == 0 && rl.CheckCollisionPointRec(mousePoint, bounds) { + rl.DrawRectangle(b.X+4+rl.MeasureText(text, int32(style[GlobalTextFontsize])), b.Y+2, 1, b.Height-4, rl.GetColor(int32(style[TextboxLineColor]))) + } + break + case Pressed: + break + default: + break + } + + return text +} diff --git a/raygui/togglebutton.go b/raygui/togglebutton.go new file mode 100644 index 0000000..a9278c1 --- /dev/null +++ b/raygui/togglebutton.go @@ -0,0 +1,61 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// ToggleButton - Toggle Button element, returns true when active +func ToggleButton(bounds rl.Rectangle, text string, active bool) bool { + b := bounds.ToInt32() + state := Normal + mousePoint := rl.GetMousePosition() + + textHeight := int32(style[GlobalTextFontsize]) + textWidth := rl.MeasureText(text, textHeight) + + // Update control + if b.Width < textWidth { + b.Width = textWidth + int32(style[ToggleTextPadding]) + } + if b.Height < textHeight { + b.Height = textHeight + int32(style[ToggleTextPadding])/2 + } + + if rl.CheckCollisionPointRec(mousePoint, bounds) { + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + state = Pressed + } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { + state = Normal + active = !active + } else { + state = Focused + } + } + + // Draw control + switch state { + case Normal: + if active { + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleActiveBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleActiveInsideColor]))) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleDefaultTextColor]))) + } else { + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleDefaultBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleDefaultInsideColor]))) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleDefaultTextColor]))) + } + break + case Focused: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleHoverBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleHoverInsideColor]))) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleHoverTextColor]))) + break + case Pressed: + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[TogglePressedBorderColor]))) + rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[TogglePressedInsideColor]))) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[TogglePressedTextColor]))) + break + default: + break + } + + return active +} diff --git a/raygui/togglegroup.go b/raygui/togglegroup.go new file mode 100644 index 0000000..376e0c1 --- /dev/null +++ b/raygui/togglegroup.go @@ -0,0 +1,16 @@ +package raygui + +import "github.com/gen2brain/raylib-go/raylib" + +// ToggleGroup - Toggle Group element, returns toggled button index +func ToggleGroup(bounds rl.Rectangle, toggleText []string, active int) int { + for i := 0; i < len(toggleText); i++ { + if i == active { + ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true) + } else if ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) { + active = i + } + } + + return active +} From eff176bb13d58eda0444b57104229e22625b5af6 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 12:18:45 -0800 Subject: [PATCH 02/19] Added [optional] 'Clicked' state and GetInteractionState function --- raygui/raygui.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/raygui/raygui.go b/raygui/raygui.go index 4e6c2c8..9ea0b17 100644 --- a/raygui/raygui.go +++ b/raygui/raygui.go @@ -2,6 +2,10 @@ package raygui +import ( + rl "github.com/gen2brain/raylib-go/raylib" +) + // GUI controls states type ControlState int @@ -13,4 +17,31 @@ const ( Focused // Pressed indicates the mouse is hovering over the GUI element and LMB is pressed down. Pressed + // Clicked indicates the mouse is hovering over the GUI element and LMB has just been released. + Clicked ) + +// IsColliding will return true if 'point' is within any of the given rectangles. +func IsInAny(point rl.Vector2, rectangles ...rl.Rectangle) bool { + for _, rect := range rectangles { + if rl.CheckCollisionPointRec(point, rect) { + return true + } + } + return false +} + +// GetInteractionState determines the current state of a control based on mouse position and +// button states. +func GetInteractionState(rectangles ...rl.Rectangle) ControlState { + switch { + case !IsInAny(rl.GetMousePosition(), rectangles...): + return Normal + case rl.IsMouseButtonDown(rl.MouseLeftButton): + return Pressed + case rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton): + return Clicked + default: + return Focused + } +} From 0e83add8beed834e8bab3512f6638b8e3ccfdc21 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 12:19:31 -0800 Subject: [PATCH 03/19] Added bordered-rectangle helper functions (without adding users) --- raygui/raygui.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/raygui/raygui.go b/raygui/raygui.go index 9ea0b17..4470a61 100644 --- a/raygui/raygui.go +++ b/raygui/raygui.go @@ -45,3 +45,24 @@ func GetInteractionState(rectangles ...rl.Rectangle) ControlState { return Focused } } + +// InsetRectangle returns the dimensions of a rectangle inset by a margin within an outer rectangle. +func InsetRectangle(outer rl.RectangleInt32, inset int32) rl.RectangleInt32 { + return rl.RectangleInt32{ + X: outer.X + inset, Y: outer.Y + inset, + Width: outer.Width - 2*inset, Height: outer.Height - 2*inset, + } +} + +// DrawInsetRectangle is a helper to draw a box inset by a margin of an outer container. +func DrawInsetRectangle(outer rl.RectangleInt32, inset int32, color rl.Color) { + inside := InsetRectangle(outer, inset) + rl.DrawRectangle(inside.X, inside.Y, inside.Width, inside.Height, color) +} + +// DrawBorderedRectangle is a helper to draw a box with a border around it. +func DrawBorderedRectangle(bounds rl.RectangleInt32, borderWidth int32, borderColor, insideColor rl.Color) { + inside := InsetRectangle(bounds, borderWidth) + rl.DrawRectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height, borderColor) + rl.DrawRectangle(inside.X, inside.Y, inside.Width, inside.Height, insideColor) +} From c0b8c09edcf7355ff4c24f9551886738eee9c724 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 12:25:49 -0800 Subject: [PATCH 04/19] Added 'SetStyleColor' to make it simpler to set a color --- raygui/style.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/raygui/style.go b/raygui/style.go index f97efe1..93eb10e 100644 --- a/raygui/style.go +++ b/raygui/style.go @@ -382,6 +382,11 @@ func SetStyleProperty(guiProperty Property, value int64) { style[guiProperty] = value } +// SetStyleColor - Set one style property to a color value +func SetStyleColor(guiProperty Property, value rl.Color) { + style[guiProperty] = int64(rl.ColorToInt(value)) +} + // GetStyleProperty - Get one style property func GetStyleProperty(guiProperty Property) int64 { return style[int(guiProperty)] From cbecfffe04cc40d3eebac4adb3506b16b9c22451 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 12:41:18 -0800 Subject: [PATCH 05/19] Combobox cleanup - Switch to using helpers to detect state and render boxes, - Make state-coloring declarative in a simple table to reduce code footprint, separate concerns, without adding runtime overhead, - Leverage 'Clicked' state (bonus: eliminates a collision check. A CPU cycle has emerged in the wild!) No behavioral changes, --- raygui/combobox.go | 111 ++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 67 deletions(-) diff --git a/raygui/combobox.go b/raygui/combobox.go index aa3a07e..25b59a5 100644 --- a/raygui/combobox.go +++ b/raygui/combobox.go @@ -5,6 +5,22 @@ import ( "github.com/gen2brain/raylib-go/raylib" ) +// comboboxColoring describes the per-state colors for a Combobox control. +type comboboxColoring struct { + Border Property + Inside Property + List Property + Text Property +} + +// comboboxColors lists the styling for each supported state. +var comboboxColors = map[ControlState]comboboxColoring { + Normal: {ComboboxDefaultBorderColor, ComboboxDefaultInsideColor, ComboboxDefaultListTextColor, ComboboxDefaultTextColor}, + Clicked: {ComboboxDefaultBorderColor, ComboboxDefaultInsideColor, ComboboxDefaultListTextColor, ComboboxDefaultTextColor}, + Focused: {ComboboxHoverBorderColor, ComboboxHoverInsideColor, ComboboxHoverListTextColor, ComboboxHoverTextColor}, + Pressed: {ComboboxPressedBorderColor, ComboboxPressedInsideColor, ComboboxPressedListTextColor, ComboboxPressedTextColor}, +} + // ComboBox draws a simplified version of a ComboBox allowing the user to select a string // from a list accompanied by an N/M counter. The widget does not provide a drop-down/completion // or any input support. @@ -16,87 +32,48 @@ func ComboBox(bounds rl.Rectangle, comboText []string, active int) int { return -1 } + // Calculate text dimensions. + textHeight := GetStyle32(GlobalTextFontsize) activeText := comboText[active] - - // style sizing. - textHeight := int32(style[GlobalTextFontsize]) textWidth := rl.MeasureText(activeText, textHeight) - borderWidth := int32(style[ComboboxBorderWidth]) - textPadding := int32(style[ToggleTextPadding]) + // Ensure box is large enough. + if int32(bounds.Width) < textWidth { + bounds.Width = float32(textWidth + GetStyle32(ToggleTextPadding)) + } + if int32(bounds.Height) < textHeight { + bounds.Height = float32(textHeight + GetStyle32(ToggleTextPadding)) + } b := bounds.ToInt32() - if b.Width < textWidth { - b.Width = textWidth + textPadding - bounds.Width = float32(b.Width) - } - if b.Height < textHeight { - b.Height = textHeight + textPadding - bounds.Height = float32(b.Height) - } - // Identify what the counter is going to look like with max digits so we don't resize it. + // Generate the worst-case sizing of the counter so we can avoid resizing it as the numbers go up/down. clickWidth := rl.MeasureText(fmt.Sprintf("%d/%d", comboCount, comboCount), b.Height) - click := rl.NewRectangle(bounds.X+bounds.Width+float32(style[ComboboxPadding]), bounds.Y, float32(clickWidth), float32(b.Height)) - c := click.ToInt32() - mousePoint := rl.GetMousePosition() - state := Normal - if rl.CheckCollisionPointRec(mousePoint, bounds) || rl.CheckCollisionPointRec(mousePoint, click) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - state = Pressed - } else { - state = Focused - } + // Counter shows the index of the selection and the maximum number, e.g. "1/3". + counter := rl.NewRectangle(bounds.X+bounds.Width+float32(style[ComboboxPadding]), bounds.Y, float32(clickWidth), float32(b.Height)) + c := counter.ToInt32() + + // Determine if the user is interacting with the control, and if so, which state it is in. + state := GetInteractionState(bounds, counter) + colors, exists := comboboxColors[state] + if !exists { + return active } - // Draw control - var borderColor, insideColor, listColor, textColor rl.Color - - switch state { - case Normal: - borderColor = rl.GetColor(int32(style[ComboboxDefaultBorderColor])) - insideColor = rl.GetColor(int32(style[ComboboxDefaultInsideColor])) - listColor = rl.GetColor(int32(style[ComboboxDefaultListTextColor])) - textColor = rl.GetColor(int32(style[ComboboxDefaultTextColor])) - - case Focused: - borderColor = rl.GetColor(int32(style[ComboboxHoverBorderColor])) - insideColor = rl.GetColor(int32(style[ComboboxHoverInsideColor])) - listColor = rl.GetColor(int32(style[ComboboxHoverListTextColor])) - textColor = rl.GetColor(int32(style[ComboboxHoverTextColor])) - - case Pressed: - borderColor = rl.GetColor(int32(style[ComboboxPressedBorderColor])) - insideColor = rl.GetColor(int32(style[ComboboxPressedInsideColor])) - listColor = rl.GetColor(int32(style[ComboboxPressedListTextColor])) - textColor = rl.GetColor(int32(style[ComboboxPressedTextColor])) - - default: - rl.TraceLog(rl.LogWarning, "ComboBox in unrecognized state %d", state) - return -1 + // Update the control when the user releases the mouse over it. + if state == Clicked { + // increment but wrap to 0 on reaching end-of-list. + active = (active + 1) % comboCount } // Render the box itself - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, borderColor) - rl.DrawRectangle(b.X+borderWidth, b.Y+borderWidth, b.Width-(2*borderWidth), b.Height-(2*borderWidth), insideColor) - rl.DrawText(activeText, b.X+((b.Width/2)-(rl.MeasureText(activeText, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) + DrawBorderedRectangle(b, GetStyle32(ComboboxBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + rl.DrawText(activeText, b.X+((b.Width/2)-(rl.MeasureText(activeText, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.Text)) // Render the accompanying "clicks" box showing the element counter. - rl.DrawRectangle(c.X, c.Y, c.Width, c.Height, borderColor) - rl.DrawRectangle(c.X+borderWidth, c.Y+borderWidth, c.Width-(2*borderWidth), c.Height-(2*borderWidth), insideColor) - companionText := fmt.Sprintf("%d/%d", active+1, comboCount) - rl.DrawText(companionText, c.X+((c.Width/2)-(rl.MeasureText(companionText, textHeight)/2)), c.Y+((c.Height/2)-(textHeight/2)), textHeight, listColor) - - if rl.CheckCollisionPointRec(mousePoint, bounds) || rl.CheckCollisionPointRec(mousePoint, click) { - if rl.IsMouseButtonPressed(rl.MouseLeftButton) { - active++ - if active >= comboCount { - active = 0 - } - } - } + DrawBorderedRectangle(c, GetStyle32(ComboboxBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + counterText := fmt.Sprintf("%d/%d", active+1, comboCount) + rl.DrawText(counterText, c.X+((c.Width/2)-(rl.MeasureText(counterText, textHeight)/2)), c.Y+((c.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.List)) return active } From b62c5f30205739e2b999ca5be9251fd70e2010ac Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 12:47:10 -0800 Subject: [PATCH 06/19] Checkbox cleanup - Switch to using helpers to detect state and render boxes, - Make state-coloring declarative as per combobox, - Use the clicked state, No behavioral changes. --- raygui/checkbox.go | 56 +++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/raygui/checkbox.go b/raygui/checkbox.go index 705d8d5..88506c5 100644 --- a/raygui/checkbox.go +++ b/raygui/checkbox.go @@ -2,44 +2,38 @@ package raygui import "github.com/gen2brain/raylib-go/raylib" +// checkboxColoring describes the per-state properties for a CheckBox control. +type checkboxColoring struct { + Border, Inside Property +} + +// checkboxColors lists the styling for each supported state. +var checkboxColors = map[ControlState]checkboxColoring{ + Normal: {CheckboxDefaultBorderColor, CheckboxDefaultInsideColor}, + Clicked: {CheckboxDefaultBorderColor, CheckboxDefaultInsideColor}, + Pressed: {CheckboxClickBorderColor, CheckboxClickInsideColor}, + Focused: {CheckboxHoverBorderColor, CheckboxHoverInsideColor}, +} + // CheckBox - Check Box element, returns true when active func CheckBox(bounds rl.Rectangle, checked bool) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := rl.GetMousePosition() + state := GetInteractionState(bounds) + colors, exists := checkboxColors[state] + if !exists { + return checked + } // Update control - if rl.CheckCollisionPointRec(mousePoint, bounds) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - state = Normal - checked = !checked - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxDefaultBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxDefaultInsideColor]))) - break - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxHoverBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxHoverInsideColor]))) - break - case Pressed: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[CheckboxClickBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[CheckboxClickInsideColor]))) - break - default: - break + if state == Clicked { + checked = !checked } + // Render control + box := bounds.ToInt32() + DrawBorderedRectangle(box, GetStyle32(ToggleBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) if checked { - rl.DrawRectangle(b.X+int32(style[CheckboxInsideWidth]), b.Y+int32(style[CheckboxInsideWidth]), b.Width-(2*int32(style[CheckboxInsideWidth])), b.Height-(2*int32(style[CheckboxInsideWidth])), rl.GetColor(int32(style[CheckboxDefaultActiveColor]))) + // Show the inner button. + DrawInsetRectangle(box, GetStyle32(CheckboxInsideWidth), GetStyleColor(CheckboxDefaultActiveColor)) } return checked From da00f22f9c0a1e207993bc71bd78a9be0ac81fc7 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 12:59:43 -0800 Subject: [PATCH 07/19] Button cleanup - Switch to using helpers to detect state and render boxes, - Make state-coloring declarative as per combobox/checkbox, - Use the clicked state, No behavioral changes. --- raygui/button.go | 73 ++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/raygui/button.go b/raygui/button.go index 153d2c8..17b7ec1 100644 --- a/raygui/button.go +++ b/raygui/button.go @@ -2,62 +2,43 @@ package raygui import "github.com/gen2brain/raylib-go/raylib" +// buttonColoring describes the per-state properties for a Button control. +type buttonColoring struct { + Border, Inside, Text Property +} + +// buttonColors lists the styling for each supported state. +var buttonColors = map[ControlState]buttonColoring{ + Normal: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, + Clicked: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, + Focused: {ButtonHoverBorderColor, ButtonHoverInsideColor, ButtonHoverTextColor}, + Pressed: {ButtonPressedBorderColor, ButtonPressedInsideColor, ButtonPressedTextColor}, +} + // Button - Button element, returns true when clicked func Button(bounds rl.Rectangle, text string) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := rl.GetMousePosition() - clicked := false - textHeight := int32(style[GlobalTextFontsize]) textWidth := rl.MeasureText(text, textHeight) // Update control - if b.Width < textWidth { - b.Width = textWidth + int32(style[ButtonTextPadding]) + if int32(bounds.Height) < textHeight { + bounds.Height = float32(textHeight + GetStyle32(ButtonTextPadding)/2) + } + if int32(bounds.Width) < textWidth { + bounds.Width = float32(textWidth + GetStyle32(ButtonTextPadding)) } - if b.Height < textHeight { - b.Height = textHeight + int32(style[ButtonTextPadding])/2 - } - - if rl.CheckCollisionPointRec(mousePoint, bounds) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - clicked = true - } else { - state = Focused - } + // Determine what state we're in and whether its valid. + state := GetInteractionState(bounds) + colors, exist := buttonColors[state] + if !exist { + return false } // Draw control - switch state { - case Normal: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonDefaultBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonDefaultInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonDefaultTextColor]))) - break + b := bounds.ToInt32() + DrawBorderedRectangle(b, GetStyle32(ButtonBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.Text)) - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonHoverBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonHoverInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonHoverTextColor]))) - break - - case Pressed: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ButtonPressedBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), rl.GetColor(int32(style[ButtonPressedInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ButtonPressedTextColor]))) - break - - default: - break - } - - if clicked { - return true - } - - return false + return state == Clicked } From a406f4bf0311cc3bb3a2bcf0f8d22cb163eca7c9 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:13:07 -0800 Subject: [PATCH 08/19] Label cleanup --- raygui/label.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/raygui/label.go b/raygui/label.go index c59c299..f1b9a8c 100644 --- a/raygui/label.go +++ b/raygui/label.go @@ -9,20 +9,19 @@ func Label(bounds rl.Rectangle, text string) { // LabelEx - Label element extended, configurable colors func LabelEx(bounds rl.Rectangle, text string, textColor, border, inner rl.Color) { - b := bounds.ToInt32() // Update control - textHeight := int32(style[GlobalTextFontsize]) + textHeight := GetStyle32(GlobalTextFontsize) textWidth := rl.MeasureText(text, textHeight) + b := bounds.ToInt32() if b.Width < textWidth { - b.Width = textWidth + int32(style[LabelTextPadding]) + b.Width = textWidth + GetStyle32(LabelTextPadding) } if b.Height < textHeight { - b.Height = textHeight + int32(style[LabelTextPadding])/2 + b.Height = textHeight + GetStyle32(LabelTextPadding)/2 } // Draw control - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, border) - rl.DrawRectangle(b.X+int32(style[LabelBorderWidth]), b.Y+int32(style[LabelBorderWidth]), b.Width-(2*int32(style[LabelBorderWidth])), b.Height-(2*int32(style[LabelBorderWidth])), inner) + DrawBorderedRectangle(b, GetStyle32(LabelBorderWidth), border, inner) rl.DrawText(text, b.X+((b.Width/2)-(textWidth/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) } From 113982db715955b7f6f76a9e7dd53069bacad66f Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:23:09 -0800 Subject: [PATCH 09/19] ProgressBar cleanup --- raygui/progressbar.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/raygui/progressbar.go b/raygui/progressbar.go index 4d6164c..a9410b8 100644 --- a/raygui/progressbar.go +++ b/raygui/progressbar.go @@ -11,11 +11,13 @@ func ProgressBar(bounds rl.Rectangle, value float32) { value = 0.0 } - progressBar := rl.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), b.Width - (int32(style[ProgressbarBorderWidth]) * 2), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} - progressValue := rl.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), int32(value * float32(b.Width-int32(style[ProgressbarBorderWidth])*2)), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} + borderWidth := GetStyle32(ProgressbarBorderWidth) + progressBar := InsetRectangle(b, borderWidth) // backing rectangle + progressWidth := int32(value * float32(progressBar.Width)) // how much should be replaced with progress + progressValue := rl.RectangleInt32{progressBar.X, progressBar.Y, progressWidth, progressBar.Height} // Draw control - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ProgressbarBorderColor]))) - rl.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, rl.GetColor(int32(style[ProgressbarInsideColor]))) - rl.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, rl.GetColor(int32(style[ProgressbarProgressColor]))) + rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, GetStyleColor(ProgressbarBorderColor)) + rl.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, GetStyleColor(ProgressbarInsideColor)) + rl.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, GetStyleColor(ProgressbarProgressColor)) } From 69cba1203d4efc9bf3bcc6b94a193371af6bf838 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:23:26 -0800 Subject: [PATCH 10/19] Format cleanup --- raygui/button.go | 4 ++-- raygui/checkbox.go | 2 +- raygui/combobox.go | 4 ++-- raygui/label.go | 1 - raygui/style.go | 1 - 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/raygui/button.go b/raygui/button.go index 17b7ec1..628b8ad 100644 --- a/raygui/button.go +++ b/raygui/button.go @@ -9,8 +9,8 @@ type buttonColoring struct { // buttonColors lists the styling for each supported state. var buttonColors = map[ControlState]buttonColoring{ - Normal: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, - Clicked: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, + Normal: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, + Clicked: {ButtonDefaultBorderColor, ButtonDefaultInsideColor, ButtonDefaultTextColor}, Focused: {ButtonHoverBorderColor, ButtonHoverInsideColor, ButtonHoverTextColor}, Pressed: {ButtonPressedBorderColor, ButtonPressedInsideColor, ButtonPressedTextColor}, } diff --git a/raygui/checkbox.go b/raygui/checkbox.go index 88506c5..99a8c6a 100644 --- a/raygui/checkbox.go +++ b/raygui/checkbox.go @@ -9,7 +9,7 @@ type checkboxColoring struct { // checkboxColors lists the styling for each supported state. var checkboxColors = map[ControlState]checkboxColoring{ - Normal: {CheckboxDefaultBorderColor, CheckboxDefaultInsideColor}, + Normal: {CheckboxDefaultBorderColor, CheckboxDefaultInsideColor}, Clicked: {CheckboxDefaultBorderColor, CheckboxDefaultInsideColor}, Pressed: {CheckboxClickBorderColor, CheckboxClickInsideColor}, Focused: {CheckboxHoverBorderColor, CheckboxHoverInsideColor}, diff --git a/raygui/combobox.go b/raygui/combobox.go index 25b59a5..399109a 100644 --- a/raygui/combobox.go +++ b/raygui/combobox.go @@ -14,8 +14,8 @@ type comboboxColoring struct { } // comboboxColors lists the styling for each supported state. -var comboboxColors = map[ControlState]comboboxColoring { - Normal: {ComboboxDefaultBorderColor, ComboboxDefaultInsideColor, ComboboxDefaultListTextColor, ComboboxDefaultTextColor}, +var comboboxColors = map[ControlState]comboboxColoring{ + Normal: {ComboboxDefaultBorderColor, ComboboxDefaultInsideColor, ComboboxDefaultListTextColor, ComboboxDefaultTextColor}, Clicked: {ComboboxDefaultBorderColor, ComboboxDefaultInsideColor, ComboboxDefaultListTextColor, ComboboxDefaultTextColor}, Focused: {ComboboxHoverBorderColor, ComboboxHoverInsideColor, ComboboxHoverListTextColor, ComboboxHoverTextColor}, Pressed: {ComboboxPressedBorderColor, ComboboxPressedInsideColor, ComboboxPressedListTextColor, ComboboxPressedTextColor}, diff --git a/raygui/label.go b/raygui/label.go index f1b9a8c..5685fff 100644 --- a/raygui/label.go +++ b/raygui/label.go @@ -9,7 +9,6 @@ func Label(bounds rl.Rectangle, text string) { // LabelEx - Label element extended, configurable colors func LabelEx(bounds rl.Rectangle, text string, textColor, border, inner rl.Color) { - // Update control textHeight := GetStyle32(GlobalTextFontsize) textWidth := rl.MeasureText(text, textHeight) diff --git a/raygui/style.go b/raygui/style.go index 93eb10e..33a0da6 100644 --- a/raygui/style.go +++ b/raygui/style.go @@ -416,4 +416,3 @@ func GetStyle32(property Property) int32 { func GetStyleColor(property Property) rl.Color { return rl.GetColor(int32(style[property])) } - From bc456c69124fa559f10eab273fbd96f48c5b0b74 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:26:40 -0800 Subject: [PATCH 11/19] Added ConstrainRectangle helper --- raygui/raygui.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/raygui/raygui.go b/raygui/raygui.go index 4470a61..6224a8a 100644 --- a/raygui/raygui.go +++ b/raygui/raygui.go @@ -46,6 +46,17 @@ func GetInteractionState(rectangles ...rl.Rectangle) ControlState { } } +// Constrain rectangle will ensure that if width/height are below given minimums, they will +// be set to an ideal minimum. +func ConstrainRectangle(bounds *rl.Rectangle, minWidth, idealWidth, minHeight, idealHeight int32) { + if int32(bounds.Width) < minWidth { + bounds.Width = float32(idealWidth) + } + if int32(bounds.Height) < minHeight { + bounds.Height = float32(idealHeight) + } +} + // InsetRectangle returns the dimensions of a rectangle inset by a margin within an outer rectangle. func InsetRectangle(outer rl.RectangleInt32, inset int32) rl.RectangleInt32 { return rl.RectangleInt32{ From e30bdc3edcf02efcc8845d718dd89f2baef5ef7e Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:42:34 -0800 Subject: [PATCH 12/19] ToggleButton cleanup --- raygui/togglebutton.go | 75 +++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/raygui/togglebutton.go b/raygui/togglebutton.go index a9278c1..73fbc83 100644 --- a/raygui/togglebutton.go +++ b/raygui/togglebutton.go @@ -2,60 +2,47 @@ package raygui import "github.com/gen2brain/raylib-go/raylib" +// togglebuttonColoring describes the per-state colors for a ToggleBox control. +type togglebuttonColoring struct { + Border, Inside, Text Property +} + +// togglebuttonColors lists the styling for each supported state. +var togglebuttonColors = map[ControlState]togglebuttonColoring { + Normal: {ToggleDefaultBorderColor, ToggleDefaultInsideColor, ToggleDefaultTextColor}, + // Hijacking 'Clicked' for the 'active' state. + Clicked: {ToggleActiveBorderColor, ToggleActiveInsideColor, ToggleDefaultTextColor}, + Pressed: {TogglePressedBorderColor, TogglePressedInsideColor, TogglePressedTextColor}, + Focused: {ToggleHoverBorderColor, ToggleHoverInsideColor, ToggleHoverTextColor}, +} + // ToggleButton - Toggle Button element, returns true when active func ToggleButton(bounds rl.Rectangle, text string, active bool) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := rl.GetMousePosition() - textHeight := int32(style[GlobalTextFontsize]) textWidth := rl.MeasureText(text, textHeight) - // Update control - if b.Width < textWidth { - b.Width = textWidth + int32(style[ToggleTextPadding]) - } - if b.Height < textHeight { - b.Height = textHeight + int32(style[ToggleTextPadding])/2 + ConstrainRectangle(&bounds, textWidth, textWidth + GetStyle32(ToggleTextPadding), textHeight, textHeight + GetStyle32(ToggleTextPadding)) + + state := GetInteractionState(bounds) + if state == Clicked { + active = !active + state = Normal } - if rl.CheckCollisionPointRec(mousePoint, bounds) { - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - state = Pressed - } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsMouseButtonPressed(rl.MouseLeftButton) { - state = Normal - active = !active - } else { - state = Focused - } + // Hijack 'Clicked' as the 'active' state + if state == Normal && active { + state = Clicked + } + + colors, exists := togglebuttonColors[state] + if !exists { + return active } // Draw control - switch state { - case Normal: - if active { - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleActiveBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleActiveInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleDefaultTextColor]))) - } else { - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleDefaultBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleDefaultInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleDefaultTextColor]))) - } - break - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleHoverBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[ToggleHoverInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[ToggleHoverTextColor]))) - break - case Pressed: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[TogglePressedBorderColor]))) - rl.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), rl.GetColor(int32(style[TogglePressedInsideColor]))) - rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, rl.GetColor(int32(style[TogglePressedTextColor]))) - break - default: - break - } + b := bounds.ToInt32() + DrawBorderedRectangle(b, GetStyle32(ToggleBorderWidth), GetStyleColor(colors.Border), GetStyleColor(colors.Inside)) + rl.DrawText(text, b.X+((b.Width/2)-(rl.MeasureText(text, textHeight)/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, GetStyleColor(colors.Text)) return active } From a9c43af1bc31415d7c7fbe15c31fa67bc1a76799 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:49:34 -0800 Subject: [PATCH 13/19] ToggleGroup cleanup [minor] --- raygui/togglegroup.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/raygui/togglegroup.go b/raygui/togglegroup.go index 376e0c1..33ccaa1 100644 --- a/raygui/togglegroup.go +++ b/raygui/togglegroup.go @@ -4,10 +4,11 @@ import "github.com/gen2brain/raylib-go/raylib" // ToggleGroup - Toggle Group element, returns toggled button index func ToggleGroup(bounds rl.Rectangle, toggleText []string, active int) int { + padding := float32(style[TogglegroupPadding]) for i := 0; i < len(toggleText); i++ { if i == active { - ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true) - } else if ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) { + ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+padding), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true) + } else if ToggleButton(rl.NewRectangle(bounds.X+float32(i)*(bounds.Width+padding), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) { active = i } } From 7fc3fbd39bc10f4c6e6ef5bf8efaf1bbf6df9478 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:50:51 -0800 Subject: [PATCH 14/19] Use ConstrainRectangle in button.go --- raygui/button.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/raygui/button.go b/raygui/button.go index 628b8ad..741e3e9 100644 --- a/raygui/button.go +++ b/raygui/button.go @@ -20,13 +20,7 @@ func Button(bounds rl.Rectangle, text string) bool { textHeight := int32(style[GlobalTextFontsize]) textWidth := rl.MeasureText(text, textHeight) - // Update control - if int32(bounds.Height) < textHeight { - bounds.Height = float32(textHeight + GetStyle32(ButtonTextPadding)/2) - } - if int32(bounds.Width) < textWidth { - bounds.Width = float32(textWidth + GetStyle32(ButtonTextPadding)) - } + ConstrainRectangle(&bounds, textWidth, textWidth+GetStyle32(ButtonTextPadding), textHeight, textHeight+GetStyle32(ButtonTextPadding)/2) // Determine what state we're in and whether its valid. state := GetInteractionState(bounds) From 01408701f9d00f542d69b82923d4a058faf81c3d Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:51:09 -0800 Subject: [PATCH 15/19] Use ConstrainRectangle in combobox.go --- raygui/combobox.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/raygui/combobox.go b/raygui/combobox.go index 399109a..3de56e6 100644 --- a/raygui/combobox.go +++ b/raygui/combobox.go @@ -38,12 +38,7 @@ func ComboBox(bounds rl.Rectangle, comboText []string, active int) int { textWidth := rl.MeasureText(activeText, textHeight) // Ensure box is large enough. - if int32(bounds.Width) < textWidth { - bounds.Width = float32(textWidth + GetStyle32(ToggleTextPadding)) - } - if int32(bounds.Height) < textHeight { - bounds.Height = float32(textHeight + GetStyle32(ToggleTextPadding)) - } + ConstrainRectangle(&bounds, textWidth, textWidth + GetStyle32(ToggleTextPadding), textHeight, textHeight + GetStyle32(ToggleTextPadding)) b := bounds.ToInt32() // Generate the worst-case sizing of the counter so we can avoid resizing it as the numbers go up/down. From 4f047b24de4b35f083ed8f2266b21cdeb51481c6 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:51:30 -0800 Subject: [PATCH 16/19] Use ConstrainRectangle in label.go --- raygui/label.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/raygui/label.go b/raygui/label.go index 5685fff..e253a93 100644 --- a/raygui/label.go +++ b/raygui/label.go @@ -12,15 +12,10 @@ func LabelEx(bounds rl.Rectangle, text string, textColor, border, inner rl.Color textHeight := GetStyle32(GlobalTextFontsize) textWidth := rl.MeasureText(text, textHeight) - b := bounds.ToInt32() - if b.Width < textWidth { - b.Width = textWidth + GetStyle32(LabelTextPadding) - } - if b.Height < textHeight { - b.Height = textHeight + GetStyle32(LabelTextPadding)/2 - } + ConstrainRectangle(&bounds, textWidth, textWidth + GetStyle32(LabelTextPadding), textHeight, textHeight + GetStyle32(LabelTextPadding) / 2) // Draw control + b := bounds.ToInt32() DrawBorderedRectangle(b, GetStyle32(LabelBorderWidth), border, inner) rl.DrawText(text, b.X+((b.Width/2)-(textWidth/2)), b.Y+((b.Height/2)-(textHeight/2)), textHeight, textColor) } From 97c0449bbd5de46afeeb824a499f281faadc3413 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 13:53:51 -0800 Subject: [PATCH 17/19] go fmt on togglebutton.go --- raygui/togglebutton.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/raygui/togglebutton.go b/raygui/togglebutton.go index 73fbc83..3848b62 100644 --- a/raygui/togglebutton.go +++ b/raygui/togglebutton.go @@ -8,8 +8,8 @@ type togglebuttonColoring struct { } // togglebuttonColors lists the styling for each supported state. -var togglebuttonColors = map[ControlState]togglebuttonColoring { - Normal: {ToggleDefaultBorderColor, ToggleDefaultInsideColor, ToggleDefaultTextColor}, +var togglebuttonColors = map[ControlState]togglebuttonColoring{ + Normal: {ToggleDefaultBorderColor, ToggleDefaultInsideColor, ToggleDefaultTextColor}, // Hijacking 'Clicked' for the 'active' state. Clicked: {ToggleActiveBorderColor, ToggleActiveInsideColor, ToggleDefaultTextColor}, Pressed: {TogglePressedBorderColor, TogglePressedInsideColor, TogglePressedTextColor}, @@ -21,7 +21,7 @@ func ToggleButton(bounds rl.Rectangle, text string, active bool) bool { textHeight := int32(style[GlobalTextFontsize]) textWidth := rl.MeasureText(text, textHeight) - ConstrainRectangle(&bounds, textWidth, textWidth + GetStyle32(ToggleTextPadding), textHeight, textHeight + GetStyle32(ToggleTextPadding)) + ConstrainRectangle(&bounds, textWidth, textWidth+GetStyle32(ToggleTextPadding), textHeight, textHeight+GetStyle32(ToggleTextPadding)) state := GetInteractionState(bounds) if state == Clicked { From 578b342040e31c1ffe466cbfc22909d5014cfc3d Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 14:19:22 -0800 Subject: [PATCH 18/19] TextBox cleanup + backspace repeat - Switched textbox to helpers, - Added code to implement a repeat delay on backspace, default 300ms to start repeating, 60ms between repeats --- raygui/textbox.go | 53 +++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/raygui/textbox.go b/raygui/textbox.go index e0e356e..61258e2 100644 --- a/raygui/textbox.go +++ b/raygui/textbox.go @@ -3,22 +3,30 @@ package raygui import ( "fmt" "github.com/gen2brain/raylib-go/raylib" + "time" ) +var backspaceHeld = false +var nextBackspace = time.Now() + +// BackspaceRepeatDelay controls the time backspace must be held down before it will repeat. +var BackspaceRepeatDelay = 300 * time.Millisecond +// BackspaceRepeatInterval controls how frequently backspace registers after the initial delay. +var BackspaceRepeatInterval = 60 * time.Millisecond + // TextBox - Text Box element, updates input text func TextBox(bounds rl.Rectangle, text string) string { b := bounds.ToInt32() - state := Normal - mousePoint := rl.GetMousePosition() letter := int32(-1) // Update control - if rl.CheckCollisionPointRec(mousePoint, bounds) { - state = Focused // NOTE: PRESSED state is not used on this control + state := GetInteractionState(bounds) + borderColor := TextboxBorderColor + if state == Pressed || state == Focused { + borderColor = ToggleActiveBorderColor framesCounter2++ - letter = rl.GetKeyPressed() if letter != -1 { if letter >= 32 && letter < 127 { @@ -26,33 +34,28 @@ func TextBox(bounds rl.Rectangle, text string) string { } } - if rl.IsKeyPressed(rl.KeyBackspace) { - if len(text) > 0 { - text = text[:len(text)-1] + backspacing := rl.IsKeyPressed(rl.KeyBackspace) + if backspacing { + nextBackspace = time.Now().Add(BackspaceRepeatDelay) + } else if rl.IsKeyDown(rl.KeyBackspace) { + backspacing = time.Since(nextBackspace) >= 0 + if backspacing { + nextBackspace = time.Now().Add(BackspaceRepeatInterval) } } + if backspacing && len(text) > 0 { + text = text[:len(text)-1] + } } - // Draw control - switch state { - case Normal: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[TextboxBorderColor]))) - rl.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), rl.GetColor(int32(style[TextboxInsideColor]))) - rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), rl.GetColor(int32(style[TextboxTextColor]))) - break - case Focused: - rl.DrawRectangle(b.X, b.Y, b.Width, b.Height, rl.GetColor(int32(style[ToggleActiveBorderColor]))) - rl.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), rl.GetColor(int32(style[TextboxInsideColor]))) - rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), rl.GetColor(int32(style[TextboxTextColor]))) + DrawBorderedRectangle(b, GetStyle32(TextboxBorderWidth), GetStyleColor(borderColor), GetStyleColor(TextboxInsideColor)) + rl.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), GetStyleColor(TextboxTextColor)) - if (framesCounter2/20)%2 == 0 && rl.CheckCollisionPointRec(mousePoint, bounds) { + if state == Focused || state == Pressed { + // Draw a cursor, when focused. + if (framesCounter2/20)%2 == 0 { rl.DrawRectangle(b.X+4+rl.MeasureText(text, int32(style[GlobalTextFontsize])), b.Y+2, 1, b.Height-4, rl.GetColor(int32(style[TextboxLineColor]))) } - break - case Pressed: - break - default: - break } return text From 65c744d4b685a30707834c10ec664e0c831c0aa7 Mon Sep 17 00:00:00 2001 From: Oliver 'kfsone' Smith Date: Wed, 24 Feb 2021 14:57:47 -0800 Subject: [PATCH 19/19] Updated git ignores --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 485dee6..824d669 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ +# IDE folders .idea +.vsc +.vs + +# Ignore go.sum when go.mod is added. +go.sum