mirror of
https://github.com/obsqrbtz/clrsync.git
synced 2026-04-09 12:37:41 +03:00
chore: refactor
This commit is contained in:
93
src/gui/widgets/action_buttons.cpp
Normal file
93
src/gui/widgets/action_buttons.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "action_buttons.hpp"
|
||||
#include "colors.hpp"
|
||||
#include "imgui.h"
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
action_buttons::action_buttons() = default;
|
||||
|
||||
void action_buttons::add_button(const action_button &button)
|
||||
{
|
||||
m_buttons.push_back(button);
|
||||
}
|
||||
|
||||
void action_buttons::clear()
|
||||
{
|
||||
m_buttons.clear();
|
||||
}
|
||||
|
||||
void action_buttons::render(const core::palette &theme_palette)
|
||||
{
|
||||
if (m_buttons.empty())
|
||||
return;
|
||||
|
||||
if (m_use_separator)
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(m_spacing, 8));
|
||||
|
||||
bool first = true;
|
||||
for (const auto &button : m_buttons)
|
||||
{
|
||||
if (!first)
|
||||
ImGui::SameLine();
|
||||
first = false;
|
||||
|
||||
int style_colors_pushed = 0;
|
||||
if (button.use_error_style)
|
||||
{
|
||||
auto error = palette_color(theme_palette, "error");
|
||||
auto error_hover = ImVec4(error.x * 1.1f, error.y * 1.1f, error.z * 1.1f, error.w);
|
||||
auto error_active = ImVec4(error.x * 0.8f, error.y * 0.8f, error.z * 0.8f, error.w);
|
||||
auto on_error = palette_color(theme_palette, "on_error");
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, error);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, error_hover);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, error_active);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, on_error);
|
||||
style_colors_pushed = 4;
|
||||
}
|
||||
else if (button.use_success_style)
|
||||
{
|
||||
auto success = palette_color(theme_palette, "success", "accent");
|
||||
auto success_hover = ImVec4(success.x * 1.1f, success.y * 1.1f, success.z * 1.1f, success.w);
|
||||
auto success_active = ImVec4(success.x * 0.8f, success.y * 0.8f, success.z * 0.8f, success.w);
|
||||
auto on_success = palette_color(theme_palette, "on_success", "on_surface");
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, success);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, success_hover);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, success_active);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, on_success);
|
||||
style_colors_pushed = 4;
|
||||
}
|
||||
|
||||
bool disabled = !button.enabled;
|
||||
if (disabled)
|
||||
ImGui::BeginDisabled();
|
||||
|
||||
if (ImGui::Button(button.label.c_str()))
|
||||
{
|
||||
if (button.on_click)
|
||||
{
|
||||
button.on_click();
|
||||
}
|
||||
}
|
||||
|
||||
if (disabled)
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (style_colors_pushed > 0)
|
||||
ImGui::PopStyleColor(style_colors_pushed);
|
||||
|
||||
if (!button.tooltip.empty() && ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("%s", button.tooltip.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
46
src/gui/widgets/action_buttons.hpp
Normal file
46
src/gui/widgets/action_buttons.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_ACTION_BUTTONS_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_ACTION_BUTTONS_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
struct action_button
|
||||
{
|
||||
std::string label;
|
||||
std::string tooltip;
|
||||
std::function<void()> on_click;
|
||||
bool enabled = true;
|
||||
|
||||
bool use_error_style = false;
|
||||
bool use_success_style = false;
|
||||
};
|
||||
|
||||
class action_buttons
|
||||
{
|
||||
public:
|
||||
action_buttons();
|
||||
|
||||
void add_button(const action_button &button);
|
||||
|
||||
void clear();
|
||||
|
||||
void render(const core::palette &theme_palette);
|
||||
|
||||
void set_spacing(float spacing) { m_spacing = spacing; }
|
||||
|
||||
void set_use_separator(bool use) { m_use_separator = use; }
|
||||
|
||||
private:
|
||||
std::vector<action_button> m_buttons;
|
||||
float m_spacing = 8.0f;
|
||||
bool m_use_separator = false;
|
||||
};
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_ACTION_BUTTONS_HPP
|
||||
287
src/gui/widgets/autocomplete.cpp
Normal file
287
src/gui/widgets/autocomplete.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
#include "autocomplete.hpp"
|
||||
#include "colors.hpp"
|
||||
#include "imgui.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
autocomplete_widget::autocomplete_widget()
|
||||
: m_selected_index(0), m_show_autocomplete(false), m_dismissed(false), m_dismiss_brace_pos(-1)
|
||||
{
|
||||
m_bg_color = ImVec4(0.12f, 0.12f, 0.15f, 0.98f);
|
||||
m_border_color = ImVec4(0.4f, 0.4f, 0.45f, 1.0f);
|
||||
m_selected_color = ImVec4(0.25f, 0.45f, 0.75f, 0.9f);
|
||||
m_text_color = ImVec4(0.85f, 0.85f, 0.9f, 1.0f);
|
||||
m_selected_text_color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
m_dim_text_color = ImVec4(0.6f, 0.6f, 0.7f, 1.0f);
|
||||
}
|
||||
|
||||
void autocomplete_widget::update_suggestions(const TextEditor& editor,
|
||||
const std::vector<std::string>& available_keys,
|
||||
const std::vector<std::string>& available_formats)
|
||||
{
|
||||
m_suggestions.clear();
|
||||
|
||||
auto cursor = editor.GetCursorPosition();
|
||||
std::string line = editor.GetCurrentLineText();
|
||||
int col = cursor.mColumn;
|
||||
|
||||
// Check if inside '{'
|
||||
int brace_pos = -1;
|
||||
for (int i = col - 1; i >= 0; --i)
|
||||
{
|
||||
if (i < (int)line.length())
|
||||
{
|
||||
if (line[i] == '{')
|
||||
{
|
||||
brace_pos = i;
|
||||
break;
|
||||
}
|
||||
else if (line[i] == '}' || line[i] == ' ' || line[i] == '\t')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (brace_pos < 0)
|
||||
{
|
||||
m_show_autocomplete = false;
|
||||
m_dismissed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dismissed)
|
||||
{
|
||||
bool should_reset_dismissal = false;
|
||||
|
||||
if (cursor.mLine != m_dismiss_position.mLine || brace_pos != m_dismiss_brace_pos ||
|
||||
abs(cursor.mColumn - m_dismiss_position.mColumn) > 3)
|
||||
{
|
||||
should_reset_dismissal = true;
|
||||
}
|
||||
|
||||
if (should_reset_dismissal)
|
||||
{
|
||||
m_dismissed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_show_autocomplete = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_prefix = line.substr(brace_pos + 1, col - brace_pos - 1);
|
||||
m_start_pos = TextEditor::Coordinates(cursor.mLine, brace_pos + 1);
|
||||
|
||||
size_t dot_pos = m_prefix.find('.');
|
||||
|
||||
if (dot_pos != std::string::npos)
|
||||
{
|
||||
std::string color_key = m_prefix.substr(0, dot_pos);
|
||||
std::string format_prefix = m_prefix.substr(dot_pos + 1);
|
||||
|
||||
bool valid_key = std::find(available_keys.begin(), available_keys.end(), color_key) != available_keys.end();
|
||||
|
||||
if (valid_key)
|
||||
{
|
||||
for (const auto &fmt : available_formats)
|
||||
{
|
||||
if (format_prefix.empty() || fmt.find(format_prefix) == 0 ||
|
||||
fmt.find(format_prefix) != std::string::npos)
|
||||
{
|
||||
m_suggestions.push_back(color_key + "." + fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& key : available_keys)
|
||||
{
|
||||
if (m_prefix.empty() || key.find(m_prefix) == 0 ||
|
||||
key.find(m_prefix) != std::string::npos)
|
||||
{
|
||||
m_suggestions.push_back(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(m_suggestions.begin(), m_suggestions.end(),
|
||||
[this](const std::string &a, const std::string &b) {
|
||||
bool a_prefix = a.find(m_prefix) == 0;
|
||||
bool b_prefix = b.find(m_prefix) == 0;
|
||||
if (a_prefix != b_prefix)
|
||||
return a_prefix;
|
||||
return a < b;
|
||||
});
|
||||
|
||||
m_show_autocomplete = !m_suggestions.empty();
|
||||
if (m_show_autocomplete && m_selected_index >= (int)m_suggestions.size())
|
||||
{
|
||||
m_selected_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void autocomplete_widget::render(const ImVec2& editor_pos, TextEditor& editor)
|
||||
{
|
||||
if (!m_show_autocomplete || m_suggestions.empty())
|
||||
return;
|
||||
|
||||
float line_height = ImGui::GetTextLineHeightWithSpacing();
|
||||
float char_width = ImGui::GetFontSize() * 0.5f;
|
||||
auto cursor = editor.GetCursorPosition();
|
||||
|
||||
const float line_number_width = 50.0f;
|
||||
|
||||
ImVec2 popup_pos;
|
||||
popup_pos.x = editor_pos.x + line_number_width + (m_start_pos.mColumn * char_width);
|
||||
popup_pos.y = editor_pos.y + ((cursor.mLine + 1) * line_height);
|
||||
|
||||
ImGui::SetNextWindowPos(popup_pos, ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(300, 0));
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
|
||||
ImGuiWindowFlags_NoFocusOnAppearing |
|
||||
ImGuiWindowFlags_AlwaysAutoResize;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(6, 6));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 6.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 2));
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, m_bg_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, m_border_color);
|
||||
|
||||
if (ImGui::Begin("##autocomplete", nullptr, flags))
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_dim_text_color);
|
||||
if (m_prefix.find('.') != std::string::npos)
|
||||
ImGui::Text("Formats");
|
||||
else
|
||||
ImGui::Text("Color Keys");
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Separator();
|
||||
|
||||
int max_items = std::min((int)m_suggestions.size(), 8);
|
||||
|
||||
for (int i = 0; i < max_items; ++i)
|
||||
{
|
||||
const auto &suggestion = m_suggestions[i];
|
||||
bool is_selected = (i == m_selected_index);
|
||||
|
||||
if (is_selected)
|
||||
{
|
||||
ImVec4 selected_hover = m_selected_color;
|
||||
selected_hover.w = std::min(selected_hover.w + 0.1f, 1.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, m_selected_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, selected_hover);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_selected_text_color);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImVec4 normal_bg = m_bg_color;
|
||||
normal_bg.w = 0.5f;
|
||||
ImVec4 hover_bg = m_selected_color;
|
||||
hover_bg.w = 0.3f;
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, normal_bg);
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, hover_bg);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_text_color);
|
||||
}
|
||||
|
||||
std::string display_text = " " + suggestion;
|
||||
|
||||
if (ImGui::Selectable(display_text.c_str(), is_selected, ImGuiSelectableFlags_None, ImVec2(0, 0)))
|
||||
{
|
||||
auto start = m_start_pos;
|
||||
auto end = editor.GetCursorPosition();
|
||||
editor.SetSelection(start, end);
|
||||
editor.Delete();
|
||||
editor.InsertText(suggestion + "}");
|
||||
m_show_autocomplete = false;
|
||||
m_dismissed = false;
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
if (is_selected && ImGui::IsWindowAppearing())
|
||||
{
|
||||
ImGui::SetScrollHereY();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_suggestions.size() > 8)
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_dim_text_color);
|
||||
ImGui::Text(" +%d more", (int)m_suggestions.size() - 8);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, m_dim_text_color);
|
||||
ImGui::Text(" Tab/Enter: accept | Esc: dismiss");
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleVar(3);
|
||||
}
|
||||
|
||||
void autocomplete_widget::apply_palette(const core::palette& palette)
|
||||
{
|
||||
m_bg_color = palette_color(palette, "surface", "background");
|
||||
m_bg_color.w = 0.98f;
|
||||
m_border_color = palette_color(palette, "border", "surface_variant");
|
||||
m_selected_color = palette_color(palette, "accent", "surface_variant");
|
||||
m_text_color = palette_color(palette, "on_surface", "foreground");
|
||||
m_selected_text_color = palette_color(palette, "on_surface", "foreground");
|
||||
m_dim_text_color = palette_color(palette, "on_surface_variant", "editor_inactive");
|
||||
}
|
||||
|
||||
bool autocomplete_widget::handle_input(TextEditor& editor)
|
||||
{
|
||||
if (!m_show_autocomplete || m_suggestions.empty())
|
||||
return false;
|
||||
|
||||
bool handled = false;
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow))
|
||||
{
|
||||
m_selected_index = (m_selected_index + 1) % (int)m_suggestions.size();
|
||||
handled = true;
|
||||
}
|
||||
else if (ImGui::IsKeyPressed(ImGuiKey_UpArrow))
|
||||
{
|
||||
m_selected_index = (m_selected_index - 1 + (int)m_suggestions.size()) % (int)m_suggestions.size();
|
||||
handled = true;
|
||||
}
|
||||
else if (ImGui::IsKeyPressed(ImGuiKey_Tab) || ImGui::IsKeyPressed(ImGuiKey_Enter))
|
||||
{
|
||||
if (m_selected_index >= 0 && m_selected_index < (int)m_suggestions.size())
|
||||
{
|
||||
auto start = m_start_pos;
|
||||
auto end = editor.GetCursorPosition();
|
||||
editor.SetSelection(start, end);
|
||||
editor.Delete();
|
||||
editor.InsertText(m_suggestions[m_selected_index] + "}");
|
||||
m_show_autocomplete = false;
|
||||
m_dismissed = false;
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
else if (ImGui::IsKeyPressed(ImGuiKey_Escape))
|
||||
{
|
||||
m_dismissed = true;
|
||||
m_dismiss_position = editor.GetCursorPosition();
|
||||
m_dismiss_brace_pos = -1;
|
||||
m_show_autocomplete = false;
|
||||
handled = true;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
53
src/gui/widgets/autocomplete.hpp
Normal file
53
src/gui/widgets/autocomplete.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_AUTOCOMPLETE_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_AUTOCOMPLETE_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include "color_text_edit/TextEditor.h"
|
||||
#include "imgui.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
class autocomplete_widget
|
||||
{
|
||||
public:
|
||||
autocomplete_widget();
|
||||
|
||||
void update_suggestions(const TextEditor& editor,
|
||||
const std::vector<std::string>& available_keys,
|
||||
const std::vector<std::string>& available_formats);
|
||||
|
||||
void render(const ImVec2& editor_pos, TextEditor& editor);
|
||||
|
||||
void apply_palette(const core::palette& palette);
|
||||
|
||||
bool handle_input(TextEditor& editor);
|
||||
|
||||
bool is_visible() const { return m_show_autocomplete; }
|
||||
|
||||
void dismiss() { m_dismissed = true; m_show_autocomplete = false; }
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_suggestions;
|
||||
std::string m_prefix;
|
||||
TextEditor::Coordinates m_start_pos;
|
||||
int m_selected_index;
|
||||
bool m_show_autocomplete;
|
||||
bool m_dismissed;
|
||||
|
||||
TextEditor::Coordinates m_dismiss_position;
|
||||
int m_dismiss_brace_pos;
|
||||
|
||||
ImVec4 m_bg_color;
|
||||
ImVec4 m_border_color;
|
||||
ImVec4 m_selected_color;
|
||||
ImVec4 m_text_color;
|
||||
ImVec4 m_selected_text_color;
|
||||
ImVec4 m_dim_text_color;
|
||||
};
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_AUTOCOMPLETE_HPP
|
||||
58
src/gui/widgets/colors.cpp
Normal file
58
src/gui/widgets/colors.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "colors.hpp"
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
ImVec4 palette_color(const core::palette &pal, const std::string &key,
|
||||
const std::string &fallback)
|
||||
{
|
||||
auto colors = pal.colors();
|
||||
if (colors.empty())
|
||||
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
auto it = colors.find(key);
|
||||
if (it == colors.end() && !fallback.empty())
|
||||
{
|
||||
it = colors.find(fallback);
|
||||
}
|
||||
|
||||
if (it != colors.end())
|
||||
{
|
||||
const auto &col = it->second;
|
||||
const uint32_t hex = col.hex();
|
||||
const float r = ((hex >> 24) & 0xFF) / 255.0f;
|
||||
const float g = ((hex >> 16) & 0xFF) / 255.0f;
|
||||
const float b = ((hex >> 8) & 0xFF) / 255.0f;
|
||||
const float a = (hex & 0xFF) / 255.0f;
|
||||
return ImVec4(r, g, b, a);
|
||||
}
|
||||
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
uint32_t palette_color_u32(const core::palette &pal, const std::string &key,
|
||||
const std::string &fallback)
|
||||
{
|
||||
auto colors = pal.colors();
|
||||
if (colors.empty())
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
auto it = colors.find(key);
|
||||
if (it == colors.end() && !fallback.empty())
|
||||
{
|
||||
it = colors.find(fallback);
|
||||
}
|
||||
|
||||
if (it != colors.end())
|
||||
{
|
||||
const auto &col = it->second;
|
||||
const uint32_t hex = col.hex();
|
||||
const uint32_t r = (hex >> 24) & 0xFF;
|
||||
const uint32_t g = (hex >> 16) & 0xFF;
|
||||
const uint32_t b = (hex >> 8) & 0xFF;
|
||||
const uint32_t a = hex & 0xFF;
|
||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
19
src/gui/widgets/colors.hpp
Normal file
19
src/gui/widgets/colors.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_COLORS_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_COLORS_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include "imgui.h"
|
||||
#include <string>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
ImVec4 palette_color(const core::palette &pal, const std::string &key,
|
||||
const std::string &fallback = "");
|
||||
|
||||
uint32_t palette_color_u32(const core::palette &pal, const std::string &key,
|
||||
const std::string &fallback = "");
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_COLORS_HPP
|
||||
46
src/gui/widgets/dialogs.cpp
Normal file
46
src/gui/widgets/dialogs.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "dialogs.hpp"
|
||||
#include "colors.hpp"
|
||||
#include "imgui.h"
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
bool delete_confirmation_dialog(const std::string &popup_title, const std::string &item_name,
|
||||
const std::string &item_type, const core::palette &theme_palette,
|
||||
const std::function<void()> &on_delete)
|
||||
{
|
||||
bool result = false;
|
||||
if (ImGui::BeginPopupModal(popup_title.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImVec4 warning_color = palette_color(theme_palette, "warning", "accent");
|
||||
ImGui::TextColored(warning_color, "Are you sure you want to delete '%s'?",
|
||||
item_name.c_str());
|
||||
ImGui::Text("This action cannot be undone.");
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
float button_width = 120.0f;
|
||||
float total_width = 2.0f * button_width + ImGui::GetStyle().ItemSpacing.x;
|
||||
float window_width = ImGui::GetContentRegionAvail().x;
|
||||
ImGui::SetCursorPosX((window_width - total_width) * 0.5f);
|
||||
|
||||
if (ImGui::Button("Delete", ImVec2(button_width, 0)))
|
||||
{
|
||||
on_delete();
|
||||
result = true;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", ImVec2(button_width, 0)))
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
17
src/gui/widgets/dialogs.hpp
Normal file
17
src/gui/widgets/dialogs.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_DIALOGS_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_DIALOGS_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
bool delete_confirmation_dialog(const std::string &popup_title, const std::string &item_name,
|
||||
const std::string &item_type, const core::palette &theme_palette,
|
||||
const std::function<void()> &on_delete);
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_DIALOGS_HPP
|
||||
184
src/gui/widgets/form_field.cpp
Normal file
184
src/gui/widgets/form_field.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "form_field.hpp"
|
||||
#include "imgui.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
form_field::form_field() = default;
|
||||
|
||||
void form_field::render_label(const form_field_config& config)
|
||||
{
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("%s:", config.label.c_str());
|
||||
if (config.label_width > 0)
|
||||
{
|
||||
ImGui::SameLine(config.label_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
|
||||
void form_field::render_tooltip(const form_field_config& config)
|
||||
{
|
||||
if (!config.tooltip.empty() && ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("%s", config.tooltip.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool form_field::render_text(const form_field_config& config, std::string& value)
|
||||
{
|
||||
render_label(config);
|
||||
|
||||
if (config.field_width > 0)
|
||||
{
|
||||
ImGui::SetNextItemWidth(config.field_width);
|
||||
}
|
||||
else if (config.field_width < 0)
|
||||
{
|
||||
ImGui::SetNextItemWidth(config.field_width);
|
||||
}
|
||||
|
||||
char buffer[512] = {0};
|
||||
strncpy(buffer, value.c_str(), sizeof(buffer) - 1);
|
||||
|
||||
bool changed = false;
|
||||
std::string id = "##" + config.label;
|
||||
|
||||
if (config.type == field_type::text_with_hint)
|
||||
{
|
||||
changed = ImGui::InputTextWithHint(id.c_str(), config.hint.c_str(), buffer, sizeof(buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
changed = ImGui::InputText(id.c_str(), buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
value = buffer;
|
||||
}
|
||||
|
||||
render_tooltip(config);
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool form_field::render_number(const form_field_config& config, int& value)
|
||||
{
|
||||
render_label(config);
|
||||
|
||||
if (config.field_width > 0)
|
||||
{
|
||||
ImGui::SetNextItemWidth(config.field_width);
|
||||
}
|
||||
else if (config.field_width < 0)
|
||||
{
|
||||
ImGui::SetNextItemWidth(config.field_width);
|
||||
}
|
||||
|
||||
std::string id = "##" + config.label;
|
||||
bool changed = ImGui::InputInt(id.c_str(), &value);
|
||||
|
||||
if (value < (int)config.min_value) value = (int)config.min_value;
|
||||
if (value > (int)config.max_value) value = (int)config.max_value;
|
||||
|
||||
render_tooltip(config);
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool form_field::render_number(const form_field_config& config, float& value)
|
||||
{
|
||||
render_label(config);
|
||||
|
||||
if (config.field_width > 0)
|
||||
{
|
||||
ImGui::SetNextItemWidth(config.field_width);
|
||||
}
|
||||
else if (config.field_width < 0)
|
||||
{
|
||||
ImGui::SetNextItemWidth(config.field_width);
|
||||
}
|
||||
|
||||
std::string id = "##" + config.label;
|
||||
bool changed = ImGui::InputFloat(id.c_str(), &value);
|
||||
|
||||
if (value < config.min_value) value = config.min_value;
|
||||
if (value > config.max_value) value = config.max_value;
|
||||
|
||||
render_tooltip(config);
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool form_field::render_path(const form_field_config& config, std::string& value)
|
||||
{
|
||||
render_label(config);
|
||||
|
||||
float browse_button_width = 80.0f;
|
||||
float available_width = ImGui::GetContentRegionAvail().x;
|
||||
float input_width = available_width - browse_button_width - ImGui::GetStyle().ItemSpacing.x;
|
||||
|
||||
if (config.field_width > 0)
|
||||
{
|
||||
input_width = config.field_width - browse_button_width - ImGui::GetStyle().ItemSpacing.x;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(input_width);
|
||||
|
||||
char buffer[512] = {0};
|
||||
strncpy(buffer, value.c_str(), sizeof(buffer) - 1);
|
||||
|
||||
std::string input_id = "##" + config.label + "_input";
|
||||
bool changed = false;
|
||||
|
||||
if (config.type == field_type::text_with_hint)
|
||||
{
|
||||
changed = ImGui::InputTextWithHint(input_id.c_str(), config.hint.c_str(), buffer, sizeof(buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
changed = ImGui::InputText(input_id.c_str(), buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
value = buffer;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
std::string button_id = "Browse##" + config.label;
|
||||
if (ImGui::Button(button_id.c_str()))
|
||||
{
|
||||
if (m_path_browse_callback)
|
||||
{
|
||||
std::string selected_path = m_path_browse_callback(value);
|
||||
if (!selected_path.empty())
|
||||
{
|
||||
value = selected_path;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render_tooltip(config);
|
||||
return changed;
|
||||
}
|
||||
|
||||
void form_field::render_readonly(const form_field_config& config, const std::string& value)
|
||||
{
|
||||
render_label(config);
|
||||
|
||||
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "%s", value.c_str());
|
||||
|
||||
render_tooltip(config);
|
||||
}
|
||||
|
||||
void form_field::set_path_browse_callback(const std::function<std::string(const std::string&)>& callback)
|
||||
{
|
||||
m_path_browse_callback = callback;
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
62
src/gui/widgets/form_field.hpp
Normal file
62
src/gui/widgets/form_field.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_FORM_FIELD_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_FORM_FIELD_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
enum class field_type
|
||||
{
|
||||
text,
|
||||
text_with_hint,
|
||||
number,
|
||||
path,
|
||||
readonly_text
|
||||
};
|
||||
|
||||
struct form_field_config
|
||||
{
|
||||
std::string label;
|
||||
std::string tooltip;
|
||||
float label_width = 80.0f;
|
||||
float field_width = -1.0f;
|
||||
bool required = false;
|
||||
field_type type = field_type::text;
|
||||
std::string hint;
|
||||
float min_value = 0.0f;
|
||||
float max_value = 100.0f;
|
||||
};
|
||||
|
||||
class form_field
|
||||
{
|
||||
public:
|
||||
form_field();
|
||||
|
||||
// Render a text input field
|
||||
bool render_text(const form_field_config& config, std::string& value);
|
||||
|
||||
// Render a number input field
|
||||
bool render_number(const form_field_config& config, int& value);
|
||||
bool render_number(const form_field_config& config, float& value);
|
||||
|
||||
// Render a path input field with browse button
|
||||
bool render_path(const form_field_config& config, std::string& value);
|
||||
|
||||
// Render readonly text
|
||||
void render_readonly(const form_field_config& config, const std::string& value);
|
||||
|
||||
// Set callback for path browsing
|
||||
void set_path_browse_callback(const std::function<std::string(const std::string&)>& callback);
|
||||
|
||||
private:
|
||||
std::function<std::string(const std::string&)> m_path_browse_callback;
|
||||
|
||||
void render_label(const form_field_config& config);
|
||||
void render_tooltip(const form_field_config& config);
|
||||
};
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_FORM_FIELD_HPP
|
||||
111
src/gui/widgets/input_dialog.cpp
Normal file
111
src/gui/widgets/input_dialog.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "input_dialog.hpp"
|
||||
#include "imgui.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
input_dialog::input_dialog() : m_input_buffer{0}, m_is_open(false), m_focus_input(false) {}
|
||||
|
||||
void input_dialog::open(const std::string &title, const std::string &prompt, const std::string &hint)
|
||||
{
|
||||
m_title = title;
|
||||
m_prompt = prompt;
|
||||
m_hint = hint;
|
||||
m_input_buffer[0] = 0;
|
||||
m_is_open = true;
|
||||
m_focus_input = true;
|
||||
ImGui::OpenPopup(m_title.c_str());
|
||||
}
|
||||
|
||||
bool input_dialog::render()
|
||||
{
|
||||
bool submitted = false;
|
||||
|
||||
if (!m_is_open)
|
||||
return false;
|
||||
|
||||
if (ImGui::BeginPopupModal(m_title.c_str(), &m_is_open, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::Text("%s", m_prompt.c_str());
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::SetNextItemWidth(250);
|
||||
if (m_focus_input)
|
||||
{
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
m_focus_input = false;
|
||||
}
|
||||
|
||||
bool enter_pressed = ImGui::InputTextWithHint("##input", m_hint.c_str(), m_input_buffer,
|
||||
IM_ARRAYSIZE(m_input_buffer),
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
bool can_submit = strlen(m_input_buffer) > 0;
|
||||
bool submit_clicked = false;
|
||||
|
||||
if (!can_submit)
|
||||
ImGui::BeginDisabled();
|
||||
|
||||
if (ImGui::Button("OK", ImVec2(120, 0)) || (enter_pressed && can_submit))
|
||||
{
|
||||
if (m_on_submit)
|
||||
{
|
||||
m_on_submit(m_input_buffer);
|
||||
}
|
||||
submitted = true;
|
||||
submit_clicked = true;
|
||||
m_is_open = false;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (!can_submit)
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
||||
{
|
||||
if (m_on_cancel)
|
||||
{
|
||||
m_on_cancel();
|
||||
}
|
||||
m_is_open = false;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
|
||||
{
|
||||
if (m_on_cancel)
|
||||
{
|
||||
m_on_cancel();
|
||||
}
|
||||
m_is_open = false;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_is_open = false;
|
||||
}
|
||||
|
||||
return submitted;
|
||||
}
|
||||
|
||||
void input_dialog::set_on_submit(const std::function<void(const std::string &)> &callback)
|
||||
{
|
||||
m_on_submit = callback;
|
||||
}
|
||||
|
||||
void input_dialog::set_on_cancel(const std::function<void()> &callback)
|
||||
{
|
||||
m_on_cancel = callback;
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
38
src/gui/widgets/input_dialog.hpp
Normal file
38
src/gui/widgets/input_dialog.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_INPUT_DIALOG_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_INPUT_DIALOG_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
class input_dialog
|
||||
{
|
||||
public:
|
||||
input_dialog();
|
||||
|
||||
void open(const std::string &title, const std::string &prompt, const std::string &hint = "");
|
||||
|
||||
bool render();
|
||||
|
||||
void set_on_submit(const std::function<void(const std::string &)> &callback);
|
||||
void set_on_cancel(const std::function<void()> &callback);
|
||||
|
||||
bool is_open() const { return m_is_open; }
|
||||
|
||||
private:
|
||||
std::string m_title;
|
||||
std::string m_prompt;
|
||||
std::string m_hint;
|
||||
char m_input_buffer[256];
|
||||
bool m_is_open;
|
||||
bool m_focus_input;
|
||||
|
||||
std::function<void(const std::string &)> m_on_submit;
|
||||
std::function<void()> m_on_cancel;
|
||||
};
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_INPUT_DIALOG_HPP
|
||||
46
src/gui/widgets/palette_selector.cpp
Normal file
46
src/gui/widgets/palette_selector.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "palette_selector.hpp"
|
||||
#include "imgui.h"
|
||||
#include <ranges>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
palette_selector::palette_selector() = default;
|
||||
|
||||
bool palette_selector::render(const palette_controller &controller, float width)
|
||||
{
|
||||
const auto ¤t = controller.current_palette();
|
||||
const auto &palettes = controller.palettes();
|
||||
bool selection_changed = false;
|
||||
|
||||
ImGui::SetNextItemWidth(width);
|
||||
if (ImGui::BeginCombo("##palette", current.name().c_str()))
|
||||
{
|
||||
for (const auto &name : palettes | std::views::keys)
|
||||
{
|
||||
const bool selected = current.name() == name;
|
||||
if (ImGui::Selectable(name.c_str(), selected))
|
||||
{
|
||||
if (m_on_selection_changed)
|
||||
{
|
||||
m_on_selection_changed(name);
|
||||
}
|
||||
selection_changed = true;
|
||||
}
|
||||
if (selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Select a color palette to edit");
|
||||
|
||||
return selection_changed;
|
||||
}
|
||||
|
||||
void palette_selector::set_on_selection_changed(const std::function<void(const std::string &)> &callback)
|
||||
{
|
||||
m_on_selection_changed = callback;
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
26
src/gui/widgets/palette_selector.hpp
Normal file
26
src/gui/widgets/palette_selector.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_PALETTE_SELECTOR_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_PALETTE_SELECTOR_HPP
|
||||
|
||||
#include "gui/controllers/palette_controller.hpp"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
class palette_selector
|
||||
{
|
||||
public:
|
||||
palette_selector();
|
||||
|
||||
bool render(const palette_controller &controller, float width = 200.0f);
|
||||
|
||||
void set_on_selection_changed(const std::function<void(const std::string &)> &callback);
|
||||
|
||||
private:
|
||||
std::function<void(const std::string &)> m_on_selection_changed;
|
||||
};
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_PALETTE_SELECTOR_HPP
|
||||
95
src/gui/widgets/styled_checkbox.cpp
Normal file
95
src/gui/widgets/styled_checkbox.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "styled_checkbox.hpp"
|
||||
#include "colors.hpp"
|
||||
#include "imgui.h"
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
styled_checkbox::styled_checkbox() = default;
|
||||
|
||||
bool styled_checkbox::render(const std::string &label, bool *value, const core::palette &theme_palette,
|
||||
checkbox_style style)
|
||||
{
|
||||
ImVec4 bg_color, hover_color, check_color;
|
||||
|
||||
switch (style)
|
||||
{
|
||||
case checkbox_style::success:
|
||||
if (*value)
|
||||
{
|
||||
bg_color = palette_color(theme_palette, "success", "accent");
|
||||
bg_color.w = 0.5f;
|
||||
hover_color = ImVec4(bg_color.x * 1.2f, bg_color.y * 1.2f, bg_color.z * 1.2f, 0.6f);
|
||||
check_color = palette_color(theme_palette, "on_success", "on_surface");
|
||||
}
|
||||
else
|
||||
{
|
||||
bg_color = palette_color(theme_palette, "surface", "background");
|
||||
hover_color = palette_color(theme_palette, "surface_variant", "surface");
|
||||
check_color = palette_color(theme_palette, "on_surface", "foreground");
|
||||
}
|
||||
break;
|
||||
|
||||
case checkbox_style::error:
|
||||
if (*value)
|
||||
{
|
||||
bg_color = palette_color(theme_palette, "error", "accent");
|
||||
bg_color.w = 0.5f;
|
||||
hover_color = ImVec4(bg_color.x * 1.2f, bg_color.y * 1.2f, bg_color.z * 1.2f, 0.6f);
|
||||
check_color = palette_color(theme_palette, "on_error", "on_surface");
|
||||
}
|
||||
else
|
||||
{
|
||||
bg_color = palette_color(theme_palette, "error", "accent");
|
||||
bg_color.w = 0.2f;
|
||||
hover_color = ImVec4(bg_color.x, bg_color.y, bg_color.z, 0.3f);
|
||||
check_color = palette_color(theme_palette, "on_error", "on_surface");
|
||||
}
|
||||
break;
|
||||
|
||||
case checkbox_style::warning:
|
||||
if (*value)
|
||||
{
|
||||
bg_color = palette_color(theme_palette, "warning", "accent");
|
||||
bg_color.w = 0.5f;
|
||||
hover_color = ImVec4(bg_color.x * 1.2f, bg_color.y * 1.2f, bg_color.z * 1.2f, 0.6f);
|
||||
check_color = palette_color(theme_palette, "on_warning", "on_surface");
|
||||
}
|
||||
else
|
||||
{
|
||||
bg_color = palette_color(theme_palette, "surface", "background");
|
||||
hover_color = palette_color(theme_palette, "surface_variant", "surface");
|
||||
check_color = palette_color(theme_palette, "on_surface", "foreground");
|
||||
}
|
||||
break;
|
||||
|
||||
case checkbox_style::normal:
|
||||
default:
|
||||
bg_color = palette_color(theme_palette, "surface", "background");
|
||||
hover_color = palette_color(theme_palette, "surface_variant", "surface");
|
||||
check_color = palette_color(theme_palette, "accent", "foreground");
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, bg_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, hover_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_CheckMark, check_color);
|
||||
|
||||
bool changed = ImGui::Checkbox(label.c_str(), value);
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
if (changed && m_on_changed)
|
||||
{
|
||||
m_on_changed(*value);
|
||||
}
|
||||
|
||||
if (!m_tooltip.empty() && ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("%s", m_tooltip.c_str());
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
38
src/gui/widgets/styled_checkbox.hpp
Normal file
38
src/gui/widgets/styled_checkbox.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef CLRSYNC_GUI_WIDGETS_STYLED_CHECKBOX_HPP
|
||||
#define CLRSYNC_GUI_WIDGETS_STYLED_CHECKBOX_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace clrsync::gui::widgets
|
||||
{
|
||||
|
||||
enum class checkbox_style
|
||||
{
|
||||
normal,
|
||||
success,
|
||||
error,
|
||||
warning
|
||||
};
|
||||
|
||||
class styled_checkbox
|
||||
{
|
||||
public:
|
||||
styled_checkbox();
|
||||
|
||||
bool render(const std::string &label, bool *value, const core::palette &theme_palette,
|
||||
checkbox_style style = checkbox_style::normal);
|
||||
|
||||
void set_tooltip(const std::string &tooltip) { m_tooltip = tooltip; }
|
||||
|
||||
void set_on_changed(const std::function<void(bool)> &callback) { m_on_changed = callback; }
|
||||
|
||||
private:
|
||||
std::string m_tooltip;
|
||||
std::function<void(bool)> m_on_changed;
|
||||
};
|
||||
|
||||
} // namespace clrsync::gui::widgets
|
||||
|
||||
#endif // CLRSYNC_GUI_WIDGETS_STYLED_CHECKBOX_HPP
|
||||
Reference in New Issue
Block a user