diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ccedec..f863c9e 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -114,6 +114,9 @@ set(sources "src/main.cpp"
"src/GUIStuff/ClayImplement.cpp"
"src/GUIStuff/Elements/GUIStuffHelpers.cpp"
"src/GUIStuff/Elements/Element.cpp"
+ "src/GUIStuff/Elements/AlphaSlider.cpp"
+ "src/GUIStuff/Elements/HueVerticalSlider.cpp"
+ "src/GUIStuff/Elements/SaturationValueSquare.cpp"
"src/GUIStuff/Elements/ImageDisplay.cpp"
"src/GUIStuff/Elements/MutableTextLabel.cpp"
"src/GUIStuff/Elements/SVGIcon.cpp"
diff --git a/assets/data/icons/RemixIcon/more-fill.svg b/assets/data/icons/RemixIcon/more-fill.svg
new file mode 100644
index 0000000..156029a
--- /dev/null
+++ b/assets/data/icons/RemixIcon/more-fill.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/GUIStuff/Elements/AlphaSlider.cpp b/src/GUIStuff/Elements/AlphaSlider.cpp
new file mode 100644
index 0000000..9e714bf
--- /dev/null
+++ b/src/GUIStuff/Elements/AlphaSlider.cpp
@@ -0,0 +1,73 @@
+#include "AlphaSlider.hpp"
+#include "../GUIManager.hpp"
+#include "ColorPicker.hpp"
+
+namespace GUIStuff {
+
+AlphaSlider::AlphaSlider(GUIManager& gui): Element(gui) {}
+
+void AlphaSlider::layout(const Clay_ElementId& id, const AlphaSliderData& opts) {
+ o = opts;
+ update();
+
+ CLAY(id, {
+ .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}},
+ .custom = {.customData = this}
+ }) {
+ }
+}
+
+void AlphaSlider::update() {
+ if(currentG != *o.g || currentB != *o.b || currentR != *o.r || currentAlpha != *o.alpha) {
+ currentR = *o.r;
+ currentG = *o.g;
+ currentB = *o.b;
+ currentAlpha = *o.alpha;
+ gui.invalidate_draw_element(this);
+ }
+}
+
+void AlphaSlider::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
+ if(mouseHovering && button.down && button.button == InputManager::MouseButton::LEFT) {
+ if(o.onHold) o.onHold();
+ update_alpha(button.pos);
+ if(o.onChange) o.onChange();
+ isHeld = true;
+ }
+ else if(isHeld && !button.down && button.button == InputManager::MouseButton::LEFT) {
+ if(o.onRelease) o.onRelease();
+ isHeld = false;
+ }
+}
+
+void AlphaSlider::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
+ if(isHeld) {
+ update_alpha(motion.pos);
+ if(o.onChange) o.onChange();
+ }
+}
+
+void AlphaSlider::update_alpha(Vector2f p) {
+ *o.alpha = std::clamp((p.x() - boundingBox.value().min.x()) / boundingBox.value().width(), 0.0f, 1.0f);
+}
+
+void AlphaSlider::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {
+ auto& bb = boundingBox.value();
+
+ canvas->save();
+ canvas->translate(bb.min.x(), bb.min.y());
+ canvas->clipRect(SkRect::MakeXYWH(0.0f, 0.0f, bb.width(), bb.height()), skiaAA);
+
+ SkPaint alphaBarPaint;
+ alphaBarPaint.setShader(ColorPickerShaders::get_alpha_bar_shader({currentR, currentG, currentB}, bb.width()));
+ canvas->drawPaint(alphaBarPaint);
+
+ SkPaint selectionLinePaint({1.0f, 1.0f, 1.0f, 1.0f});
+ selectionLinePaint.setAntiAlias(skiaAA);
+ selectionLinePaint.setStrokeWidth(1.0f);
+ canvas->drawLine(currentAlpha * bb.width(), 0.0f, currentAlpha * bb.width(), bb.height(), selectionLinePaint);
+
+ canvas->restore();
+}
+
+}
diff --git a/src/GUIStuff/Elements/AlphaSlider.hpp b/src/GUIStuff/Elements/AlphaSlider.hpp
new file mode 100644
index 0000000..bb8eef6
--- /dev/null
+++ b/src/GUIStuff/Elements/AlphaSlider.hpp
@@ -0,0 +1,36 @@
+#pragma once
+#include "Element.hpp"
+
+namespace GUIStuff {
+
+struct AlphaSliderData {
+ float* alpha = nullptr;
+ float* r = nullptr;
+ float* g = nullptr;
+ float* b = nullptr;
+ std::function onChange;
+ std::function onHold;
+ std::function onRelease;
+};
+
+class AlphaSlider : public Element {
+ public:
+ AlphaSlider(GUIManager& gui);
+
+ void layout(const Clay_ElementId& id, const AlphaSliderData& opts);
+ virtual void update() override;
+ virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
+ virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
+ virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
+
+ private:
+ void update_alpha(Vector2f p);
+ AlphaSliderData o;
+ float currentAlpha = -1.0f;
+ float currentR = -1.0f;
+ float currentG = -1.0f;
+ float currentB = -1.0f;
+ bool isHeld = false;
+};
+
+}
diff --git a/src/GUIStuff/Elements/ColorPicker.decl.hpp b/src/GUIStuff/Elements/ColorPicker.decl.hpp
index 6f16eaa..1be99a6 100644
--- a/src/GUIStuff/Elements/ColorPicker.decl.hpp
+++ b/src/GUIStuff/Elements/ColorPicker.decl.hpp
@@ -3,7 +3,6 @@
#include
#include
#include
-#include
#include
#include
@@ -67,44 +66,17 @@ struct ColorPickerData {
template class ColorPicker : public Element {
public:
ColorPicker(GUIManager& gui);
- void layout(const Clay_ElementId& id, T* data, bool selectAlpha, const ColorPickerData& config);
- virtual void update() override;
- virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
- void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
- void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
+ void layout(const Clay_ElementId& id, T* data, bool selectAlpha, const ColorPickerData& conf = {});
private:
- void update_color_picker_pos(const Vector2f& p, bool justHeld);
- float get_sv_selection_area_size();
- Vector2f get_hue_bar_pos();
- Vector2f get_hue_bar_dim();
- Vector2f get_alpha_bar_pos();
- Vector2f get_alpha_bar_dim();
- void set_hsv(const Vector3f& hsv);
+ void set_rgb_from_hsv(const Vector3f& hsv);
static constexpr float BAR_WIDTH = 30.0;
- static constexpr float BAR_GAP = 5.0;
-
- struct DisplayData {
- Vector3f savedHsv = {0.0f, 0.0f, 0.0f};
- float savedAlpha = 0.0f;
- bool operator!=(const DisplayData&) const = default;
- bool operator==(const DisplayData&) const = default;
- };
-
- DisplayData dd;
- DisplayData oldDD;
+ static constexpr uint16_t BAR_GAP = 5;
+ Vector3f savedHsv = {0.0f, 0.0f, 0.0f};
T* data;
std::optional oldData;
ColorPickerData config;
- bool selectAlpha = false;
- enum class HeldBar {
- NONE,
- SV_HELD,
- HUE_HELD,
- ALPHA_HELD
- };
- HeldBar held = HeldBar::NONE;
};
}
diff --git a/src/GUIStuff/Elements/ColorPicker.impl.hpp b/src/GUIStuff/Elements/ColorPicker.impl.hpp
index 28b80c6..b8686c0 100644
--- a/src/GUIStuff/Elements/ColorPicker.impl.hpp
+++ b/src/GUIStuff/Elements/ColorPicker.impl.hpp
@@ -1,192 +1,116 @@
#pragma once
#include "ColorPicker.decl.hpp"
#include "../GUIManager.hpp"
+#include "Helpers/ConvertVec.hpp"
+#include "SaturationValueSquare.hpp"
+#include "HueVerticalSlider.hpp"
+#include "AlphaSlider.hpp"
namespace GUIStuff {
template ColorPicker::ColorPicker(GUIManager& gui): Element(gui) {}
-template void ColorPicker::layout(const Clay_ElementId& id, T* data, bool selectAlpha, const ColorPickerData& config) {
+template void ColorPicker::layout(const Clay_ElementId& id, T* data, bool selectAlpha, const ColorPickerData& conf) {
this->data = data;
if(!oldData.has_value() || oldData.value() != *data) {
- dd.savedHsv = rgb_to_hsv(*data);
+ savedHsv = rgb_to_hsv(*data);
oldData = *data;
}
- if(selectAlpha)
- dd.savedAlpha = (*data)[3];
- this->selectAlpha = selectAlpha;
- this->config = config;
+ config = conf;
- CLAY(id, {
- .layout = {
- .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }
- },
- .aspectRatio = {1.0f},
- .custom = { .customData = this }
- }) {}
-}
-
-template void ColorPicker::update() {
- if(dd != oldDD) {
- gui.invalidate_draw_element(this);
- oldDD = dd;
- }
-}
-
-template void ColorPicker::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {
- auto& bb = boundingBox.value();
-
- canvas->save();
- canvas->translate(bb.min.x(), bb.min.y());
- float svSelectionAreaSize = get_sv_selection_area_size();
- canvas->scale(svSelectionAreaSize, svSelectionAreaSize);
- canvas->clipRect(SkRect::MakeXYWH(0.0f, 0.0f, 1.0f, 1.0f), skiaAA);
-
- SkPaint svSelectionAreaPaint;
- svSelectionAreaPaint.setShader(ColorPickerShaders::get_sv_selection_shader(dd.savedHsv.x() / 360.0f));
- canvas->drawPaint(svSelectionAreaPaint);
-
- SkPaint selectionLinePaint({1.0f, 1.0f, 1.0f, 1.0f});
- selectionLinePaint.setAntiAlias(skiaAA);
- selectionLinePaint.setStrokeWidth(2.0f / svSelectionAreaSize);
- canvas->drawLine(0.0f, 1.0f - dd.savedHsv.z(), 1.0f, 1.0f - dd.savedHsv.z(), selectionLinePaint);
- canvas->drawLine(dd.savedHsv.y(), 0.0f, dd.savedHsv.y(), 1.0f, selectionLinePaint);
-
- canvas->restore();
-
- float normalizedHue = dd.savedHsv.x() / 360.0f;
-
- Vector2f hueBarPos = get_hue_bar_pos();
- Vector2f hueBarDim = get_hue_bar_dim();
- canvas->save();
- canvas->translate(hueBarPos.x(), hueBarPos.y());
- canvas->scale(hueBarDim.x(), hueBarDim.y());
- canvas->clipRect(SkRect::MakeXYWH(0.0f, 0.0f, 1.0f, 1.0f), skiaAA);
-
- SkPaint hueBarPaint;
- hueBarPaint.setShader(ColorPickerShaders::get_hue_shader());
- canvas->drawPaint(hueBarPaint);
- canvas->drawLine(0.0f, 1.0f - normalizedHue, 1.0f, 1.0f - normalizedHue, selectionLinePaint);
-
- canvas->restore();
-
- Vector2f alphaBarPos = get_alpha_bar_pos();
- Vector2f alphaBarDim = get_alpha_bar_dim();
- canvas->save();
- canvas->translate(alphaBarPos.x(), alphaBarPos.y());
- canvas->clipRect(SkRect::MakeXYWH(0.0f, 0.0f, alphaBarDim.x(), alphaBarDim.y()), skiaAA);
-
- SkPaint alphaBarPaint;
- if(selectAlpha)
- alphaBarPaint.setShader(ColorPickerShaders::get_alpha_bar_shader({(*data)[0], (*data)[1], (*data)[2]}, alphaBarDim.x()));
- else
- alphaBarPaint.setColor4f(SkColor4f{(*data)[0], (*data)[1], (*data)[2], 1.0f});
- canvas->drawPaint(alphaBarPaint);
+ auto onChange = [&] {
+ set_rgb_from_hsv(savedHsv);
+ if(config.onChange) config.onChange();
+ };
if(selectAlpha) {
- canvas->scale(alphaBarDim.x(), alphaBarDim.y());
- canvas->drawLine((*data)[3], 0.0f, (*data)[3], 1.0f, selectionLinePaint);
- }
-
- canvas->restore();
-}
-
-template void ColorPicker::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
- HeldBar oldHeld = held;
- held = HeldBar::NONE;
- if(mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down && boundingBox.has_value()) {
- auto& bb = boundingBox.value();
- float svSelectionAreaSize = get_sv_selection_area_size();
- if(SCollision::collide(SCollision::AABB(bb.min, bb.min + Vector2f{svSelectionAreaSize, svSelectionAreaSize}), button.pos))
- held = HeldBar::SV_HELD;
- else {
- Vector2f hueBarPos = get_hue_bar_pos();
- Vector2f hueBarDim = get_hue_bar_dim();
- if(SCollision::collide(SCollision::AABB(hueBarPos, hueBarPos + hueBarDim), button.pos))
- held = HeldBar::HUE_HELD;
- else if(selectAlpha) {
- Vector2f alphaBarPos = get_alpha_bar_pos();
- Vector2f alphaBarDim = get_alpha_bar_dim();
- if(SCollision::collide(SCollision::AABB(alphaBarPos, alphaBarPos + alphaBarDim), button.pos))
- held = HeldBar::ALPHA_HELD;
+ CLAY(id, {
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) },
+ .childGap = BAR_GAP,
+ .layoutDirection = CLAY_TOP_TO_BOTTOM
+ }
+ }) {
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
+ .childGap = BAR_GAP,
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
+ },
+ }) {
+ gui.element("sv square", SaturationValueSquareData{
+ .saturation = &savedHsv.y(),
+ .value = &savedHsv.z(),
+ .hue = &savedHsv.x(),
+ .onChange = onChange,
+ .onHold = config.onHold,
+ .onRelease = config.onRelease
+ });
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIT(BAR_WIDTH), .height = CLAY_SIZING_GROW(0)}
+ },
+ }) {
+ gui.element("hue slider", HueVerticalSliderData{
+ .hue = &savedHsv.x(),
+ .onChange = onChange,
+ .onHold = config.onHold,
+ .onRelease = config.onRelease
+ });
+ }
+ }
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(BAR_WIDTH)}
+ },
+ }) {
+ gui.element("alpha slider", AlphaSliderData{
+ .alpha = &(*data)[3],
+ .r = &(*data)[0],
+ .g = &(*data)[1],
+ .b = &(*data)[2],
+ .onChange = onChange,
+ .onHold = config.onHold,
+ .onRelease = config.onRelease
+ });
}
}
}
- if(oldHeld != HeldBar::NONE && held == HeldBar::NONE) {
- gui.set_post_callback_func([&] {
- if(config.onRelease) config.onRelease();
- });
- }
- update_color_picker_pos(button.pos, true);
-}
-
-template void ColorPicker::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
- update_color_picker_pos(motion.pos, false);
-}
-
-template void ColorPicker::update_color_picker_pos(const Vector2f& p, bool justHeld) {
- if(held != HeldBar::NONE && boundingBox.has_value()) {
- gui.set_post_callback_func([&, p, justHeld]() {
- auto& bb = boundingBox.value();
- switch(held) {
- case HeldBar::NONE:
- break;
- case HeldBar::SV_HELD: {
- float svSelectionAreaSize = bb.width() - (BAR_GAP + BAR_WIDTH);
- Vector2f newSv = cwise_vec_clamp((p - bb.min) / svSelectionAreaSize, Vector2f{0.0f, 0.0f}, Vector2f{1.0f, 1.0f});
- dd.savedHsv.y() = newSv.x();
- dd.savedHsv.z() = 1.0f - newSv.y();
- set_hsv(dd.savedHsv);
- if(justHeld && config.onHold) config.onHold();
- if(config.onChange) config.onChange();
- break;
- }
- case HeldBar::HUE_HELD: {
- Vector2f huePos = get_hue_bar_pos();
- Vector2f hueDim = get_hue_bar_dim();
- dd.savedHsv.x() = (1.0f - std::clamp((p.y() - huePos.y()) / hueDim.y(), 0.0f, 1.0f)) * 360.0f;
- set_hsv(dd.savedHsv);
- if(justHeld && config.onHold) config.onHold();
- if(config.onChange) config.onChange();
- break;
- }
- case HeldBar::ALPHA_HELD: {
- Vector2f alphaPos = get_alpha_bar_pos();
- Vector2f alphaDim = get_alpha_bar_dim();
- (*data)[3] = std::clamp((p.x() - alphaPos.x()) / alphaDim.x(), 0.0f, 1.0f);
- dd.savedAlpha = (*data)[3];
- oldData = *data;
- if(justHeld && config.onHold) config.onHold();
- if(config.onChange) config.onChange();
- break;
- }
+ else {
+ CLAY(id, {
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
+ .childGap = BAR_GAP,
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
+ },
+ }) {
+ gui.element("sv square", SaturationValueSquareData{
+ .saturation = &savedHsv.y(),
+ .value = &savedHsv.z(),
+ .hue = &savedHsv.x(),
+ .onChange = onChange,
+ .onHold = config.onHold,
+ .onRelease = config.onRelease
+ });
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIT(BAR_WIDTH), .height = CLAY_SIZING_GROW(0)},
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
+ },
+ }) {
+ gui.element("hue slider", HueVerticalSliderData{
+ .hue = &savedHsv.x(),
+ .onChange = onChange,
+ .onHold = config.onHold,
+ .onRelease = config.onRelease
+ });
}
- });
+ }
}
}
-template float ColorPicker::get_sv_selection_area_size() {
- return boundingBox.value().width() - (BAR_GAP + BAR_WIDTH);
-}
-
-template Vector2f ColorPicker::get_hue_bar_pos() {
- return {boundingBox.value().min.x() + get_sv_selection_area_size() + BAR_GAP, boundingBox.value().min.y()};
-}
-
-template Vector2f ColorPicker::get_hue_bar_dim() {
- return {BAR_WIDTH, get_sv_selection_area_size()};
-}
-
-template Vector2f ColorPicker::get_alpha_bar_pos() {
- return {boundingBox.value().min.x(), boundingBox.value().min.y() + get_sv_selection_area_size() + BAR_GAP};
-}
-
-template Vector2f ColorPicker::get_alpha_bar_dim() {
- return {boundingBox.value().width(), BAR_WIDTH};
-}
-
-template void ColorPicker::set_hsv(const Vector3f& hsv) {
+template void ColorPicker::set_rgb_from_hsv(const Vector3f& hsv) {
Vector3f a = hsv_to_rgb(hsv);
(*data)[0] = a.x();
(*data)[1] = a.y();
diff --git a/src/GUIStuff/Elements/DropDown.hpp b/src/GUIStuff/Elements/DropDown.hpp
index 23e7836..92ee38c 100644
--- a/src/GUIStuff/Elements/DropDown.hpp
+++ b/src/GUIStuff/Elements/DropDown.hpp
@@ -16,7 +16,6 @@ struct DropdownOptions {
template class DropDown : public Element {
public:
- static constexpr float ENTRY_HEIGHT = 27.0f;
static constexpr float DROPDOWN_OFFSET = 4.0f;
DropDown(GUIManager& gui): Element(gui) {}
@@ -61,6 +60,7 @@ template class DropDown : public Element {
if(isOpen && boundingBox.has_value()) {
auto& buttonBB = boundingBox.value();
+ float ENTRY_HEIGHT = buttonBB.height();
gui.set_z_index(gui.get_z_index() + 1, [&] {
gui.element("DROPDOWN", [&](LayoutElement* l, const Clay_ElementId& lId) {
float dropdownHeight = ENTRY_HEIGHT * selections.size() + DROPDOWN_OFFSET;
diff --git a/src/GUIStuff/Elements/Element.cpp b/src/GUIStuff/Elements/Element.cpp
index 8eb144a..ace042a 100644
--- a/src/GUIStuff/Elements/Element.cpp
+++ b/src/GUIStuff/Elements/Element.cpp
@@ -14,8 +14,12 @@ namespace GUIStuff {
void Element::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { }
void Element::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { }
void Element::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) { }
- void Element::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { }
- void Element::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { }
+ void Element::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) {
+ input_mouse_button_callback(InputManager::convert_finger_touch_to_mouse_button(touch));
+ }
+ void Element::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) {
+ input_mouse_motion_callback(InputManager::convert_finger_motion_to_mouse_motion(motion));
+ }
void Element::input_key_callback(const InputManager::KeyCallbackArgs& key) {}
void Element::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {}
diff --git a/src/GUIStuff/Elements/HueVerticalSlider.cpp b/src/GUIStuff/Elements/HueVerticalSlider.cpp
new file mode 100644
index 0000000..ef12e02
--- /dev/null
+++ b/src/GUIStuff/Elements/HueVerticalSlider.cpp
@@ -0,0 +1,75 @@
+#include "HueVerticalSlider.hpp"
+#include "../GUIManager.hpp"
+#include "ColorPicker.hpp"
+
+namespace GUIStuff {
+
+HueVerticalSlider::HueVerticalSlider(GUIManager& gui): Element(gui) {}
+
+void HueVerticalSlider::layout(const Clay_ElementId& id, const HueVerticalSliderData& opts) {
+ o = opts;
+ update();
+
+ CLAY(id, {
+ .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}},
+ .custom = {.customData = this}
+ }) {
+ }
+}
+
+void HueVerticalSlider::update() {
+ if(currentHue != *o.hue) {
+ currentHue = *o.hue;
+ gui.invalidate_draw_element(this);
+ }
+}
+
+void HueVerticalSlider::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
+ if(mouseHovering && button.down && button.button == InputManager::MouseButton::LEFT) {
+ if(o.onHold) o.onHold();
+ update_hue(button.pos);
+ if(o.onChange) o.onChange();
+ isHeld = true;
+ }
+ else if(isHeld && !button.down && button.button == InputManager::MouseButton::LEFT) {
+ if(o.onRelease) o.onRelease();
+ isHeld = false;
+ }
+}
+
+void HueVerticalSlider::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
+ if(isHeld) {
+ update_hue(motion.pos);
+ if(o.onChange) o.onChange();
+ }
+}
+
+void HueVerticalSlider::update_hue(Vector2f p) {
+ *o.hue = (1.0f - std::clamp((p.y() - boundingBox.value().min.y()) / boundingBox.value().height(), 0.0f, 1.0f)) * 360.0f;
+}
+
+void HueVerticalSlider::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {
+ auto& bb = boundingBox.value();
+
+ float normalizedHue = currentHue / 360.0f;
+
+ canvas->save();
+ canvas->translate(bb.min.x(), bb.min.y());
+ canvas->scale(bb.width(), bb.height());
+ canvas->clipRect(SkRect::MakeXYWH(0.0f, 0.0f, 1.0f, 1.0f), skiaAA);
+ SkPaint hueBarPaint;
+ hueBarPaint.setShader(ColorPickerShaders::get_hue_shader());
+ canvas->drawPaint(hueBarPaint);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(bb.min.x(), bb.min.y());
+ SkPaint selectionLinePaint({1.0f, 1.0f, 1.0f, 1.0f});
+ selectionLinePaint.setAntiAlias(skiaAA);
+ selectionLinePaint.setStrokeWidth(1.0f);
+ float hueY = bb.height() * (1.0f - normalizedHue);
+ canvas->drawLine(0.0f, hueY, bb.width(), hueY, selectionLinePaint);
+ canvas->restore();
+}
+
+}
diff --git a/src/GUIStuff/Elements/HueVerticalSlider.hpp b/src/GUIStuff/Elements/HueVerticalSlider.hpp
new file mode 100644
index 0000000..0458686
--- /dev/null
+++ b/src/GUIStuff/Elements/HueVerticalSlider.hpp
@@ -0,0 +1,30 @@
+#pragma once
+#include "Element.hpp"
+
+namespace GUIStuff {
+
+struct HueVerticalSliderData {
+ float* hue = nullptr;
+ std::function onChange;
+ std::function onHold;
+ std::function onRelease;
+};
+
+class HueVerticalSlider : public Element {
+ public:
+ HueVerticalSlider(GUIManager& gui);
+
+ void layout(const Clay_ElementId& id, const HueVerticalSliderData& opts);
+ virtual void update() override;
+ virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
+ virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
+ virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
+
+ private:
+ void update_hue(Vector2f p);
+ HueVerticalSliderData o;
+ float currentHue = -1.0f;
+ bool isHeld = false;
+};
+
+}
diff --git a/src/GUIStuff/Elements/SaturationValueSquare.cpp b/src/GUIStuff/Elements/SaturationValueSquare.cpp
new file mode 100644
index 0000000..e14876b
--- /dev/null
+++ b/src/GUIStuff/Elements/SaturationValueSquare.cpp
@@ -0,0 +1,82 @@
+#include "SaturationValueSquare.hpp"
+#include "../GUIManager.hpp"
+#include "ColorPicker.hpp"
+
+namespace GUIStuff {
+
+SaturationValueSquare::SaturationValueSquare(GUIManager& gui): Element(gui) {}
+
+void SaturationValueSquare::layout(const Clay_ElementId& id, const SaturationValueSquareData& opts) {
+ o = opts;
+ update();
+
+ CLAY(id, {
+ .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}},
+ .custom = {.customData = this}
+ }) {
+ }
+}
+
+void SaturationValueSquare::update() {
+ if(currentHue != *o.hue || currentSaturation != *o.saturation || currentValue != *o.value) {
+ currentHue = *o.hue;
+ currentSaturation = *o.saturation;
+ currentValue = *o.value;
+ gui.invalidate_draw_element(this);
+ }
+}
+
+void SaturationValueSquare::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
+ if(mouseHovering && button.down && button.button == InputManager::MouseButton::LEFT) {
+ if(o.onHold) o.onHold();
+ update_sv(button.pos);
+ if(o.onChange) o.onChange();
+ isHeld = true;
+ }
+ else if(isHeld && !button.down && button.button == InputManager::MouseButton::LEFT) {
+ if(o.onRelease) o.onRelease();
+ isHeld = false;
+ }
+}
+
+void SaturationValueSquare::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
+ if(isHeld) {
+ update_sv(motion.pos);
+ if(o.onChange) o.onChange();
+ }
+}
+
+void SaturationValueSquare::update_sv(Vector2f p) {
+ *o.saturation = std::clamp((p.x() - boundingBox.value().min.x()) / boundingBox.value().width(), 0.0f, 1.0f);
+ *o.value = 1.0f - std::clamp((p.y() - boundingBox.value().min.y()) / boundingBox.value().height(), 0.0f, 1.0f);
+}
+
+void SaturationValueSquare::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {
+ auto& bb = boundingBox.value();
+
+ canvas->save();
+ canvas->translate(bb.min.x(), bb.min.y());
+ canvas->scale(bb.width(), bb.height());
+ canvas->clipRect(SkRect::MakeXYWH(0.0f, 0.0f, 1.0f, 1.0f), skiaAA);
+
+ SkPaint svSelectionAreaPaint;
+ svSelectionAreaPaint.setShader(ColorPickerShaders::get_sv_selection_shader(currentHue / 360.0f));
+ canvas->drawPaint(svSelectionAreaPaint);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(bb.min.x(), bb.min.y());
+
+ SkPaint selectionLinePaint({1.0f, 1.0f, 1.0f, 1.0f});
+ selectionLinePaint.setAntiAlias(skiaAA);
+ selectionLinePaint.setStrokeWidth(1.0f);
+
+ float valueY = bb.height() * (1.0f - currentValue);
+ canvas->drawLine(0.0f, valueY, bb.width(), valueY, selectionLinePaint);
+ float saturationX = bb.width() * currentSaturation;
+ canvas->drawLine(saturationX, 0.0f, saturationX, bb.height(), selectionLinePaint);
+
+ canvas->restore();
+}
+
+}
diff --git a/src/GUIStuff/Elements/SaturationValueSquare.hpp b/src/GUIStuff/Elements/SaturationValueSquare.hpp
new file mode 100644
index 0000000..d9e0538
--- /dev/null
+++ b/src/GUIStuff/Elements/SaturationValueSquare.hpp
@@ -0,0 +1,34 @@
+#pragma once
+#include "Element.hpp"
+
+namespace GUIStuff {
+
+struct SaturationValueSquareData {
+ float* saturation = nullptr;
+ float* value = nullptr;
+ float* hue = nullptr;
+ std::function onChange;
+ std::function onHold;
+ std::function onRelease;
+};
+
+class SaturationValueSquare : public Element {
+ public:
+ SaturationValueSquare(GUIManager& gui);
+
+ void layout(const Clay_ElementId& id, const SaturationValueSquareData& opts);
+ virtual void update() override;
+ virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
+ virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
+ virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
+
+ private:
+ void update_sv(Vector2f p);
+ SaturationValueSquareData o;
+ float currentHue = -1.0f;
+ float currentSaturation = -1.0f;
+ float currentValue = -1.0f;
+ bool isHeld = false;
+};
+
+}
diff --git a/src/InputManager.cpp b/src/InputManager.cpp
index 2b004b8..8331b26 100644
--- a/src/InputManager.cpp
+++ b/src/InputManager.cpp
@@ -624,6 +624,24 @@ void InputManager::backend_pen_axis_update(const SDL_PenAxisEvent& e) {
}
}
+InputManager::MouseButtonCallbackArgs InputManager::convert_finger_touch_to_mouse_button(const FingerTouchCallbackArgs& touch) {
+ return {
+ .deviceType = InputManager::MouseDeviceType::TOUCH,
+ .button = InputManager::MouseButton::LEFT,
+ .down = touch.down,
+ .clicks = static_cast(touch.fingerTapCount),
+ .pos = touch.pos
+ };
+}
+
+InputManager::MouseMotionCallbackArgs InputManager::convert_finger_motion_to_mouse_motion(const FingerMotionCallbackArgs& motion) {
+ return {
+ .deviceType = InputManager::MouseDeviceType::TOUCH,
+ .pos = motion.pos,
+ .move = motion.move
+ };
+}
+
std::vector InputManager::get_multiple_finger_positions() {
std::vector pos;
for(const SDL_TouchFingerEvent& fingerEvent : touch.fingers)
diff --git a/src/InputManager.hpp b/src/InputManager.hpp
index b2c0490..315097f 100644
--- a/src/InputManager.hpp
+++ b/src/InputManager.hpp
@@ -395,6 +395,9 @@ struct InputManager {
size_t fingerDownCount;
};
+ static MouseButtonCallbackArgs convert_finger_touch_to_mouse_button(const FingerTouchCallbackArgs& touch);
+ static MouseMotionCallbackArgs convert_finger_motion_to_mouse_motion(const FingerMotionCallbackArgs& motion);
+
struct WindowResizeCallbackArgs {
Vector2i size;
SCollision::AABB safeArea;
diff --git a/src/Screens/PhoneDrawingProgramScreen.cpp b/src/Screens/PhoneDrawingProgramScreen.cpp
index cbfb65a..6b013c4 100644
--- a/src/Screens/PhoneDrawingProgramScreen.cpp
+++ b/src/Screens/PhoneDrawingProgramScreen.cpp
@@ -3,9 +3,12 @@
#include "DrawingProgramScreen.hpp"
#include "Helpers/ConvertVec.hpp"
#include "../GUIStuff/Elements/GridScrollArea.hpp"
+#include "../GUIStuff/Elements/DropDown.hpp"
+#include "../GUIStuff/Elements/ColorPicker.hpp"
#include "../GUIStuff/ElementHelpers/ButtonHelpers.hpp"
#include "../GUIStuff/ElementHelpers/LayoutHelpers.hpp"
#include "../GUIStuff/ElementHelpers/TextLabelHelpers.hpp"
+#include "../GUIStuff/ElementHelpers/TextBoxHelpers.hpp"
#include "FileSelectScreen.hpp"
#include
@@ -112,8 +115,10 @@ void PhoneDrawingProgramScreen::bottom_toolbar() {
}) {}
switch(settingsMenuPopup) {
case SettingsMenuPopup::NONE:
+ reset_color_picker_popup_data();
break;
case SettingsMenuPopup::SETTINGS:
+ reset_color_picker_popup_data();
tool_settings_popup();
break;
case SettingsMenuPopup::FG_COLOR:
@@ -234,24 +239,25 @@ void PhoneDrawingProgramScreen::tool_settings_popup() {
});
}
+void PhoneDrawingProgramScreen::reset_color_picker_popup_data() {
+ colorPickerPopupData.extraSettingsOpen = false;
+ colorPickerPopupData.addingPalette = false;
+ colorPickerPopupData.newPaletteStr.clear();
+}
+
void PhoneDrawingProgramScreen::color_settings_popup(Vector4f* color) {
auto& gui = main.g.gui;
- auto& palette = main.conf.palettes[paletteData.selectedPalette];
- gui.element("color settings popup", [&] (LayoutElement*, const Clay_ElementId& lId) {
- CLAY(lId, {
- .layout = {
- .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0)},
- },
- .backgroundColor = convert_vec4(gui.io.theme->backColor1),
- .cornerRadius = CLAY_CORNER_RADIUS(gui.io.theme->windowCorners1)
- }) {
- gui.element("color selector grid", GridScrollArea::Options{
- .entryWidth = BIG_BUTTON_SIZE,
- .childAlignmentX = CLAY_ALIGN_X_CENTER,
- .entryHeight = BIG_BUTTON_SIZE,
- .entryCount = palette.colors.size(),
- .scrollbar = ScrollArea::ScrollbarType::NORMAL,
- .elementContent = [&](size_t i) {
+ auto& palette = main.conf.palettes[colorPickerPopupData.selectedPalette];
+
+ auto paletteColorPickerGrid = [&] {
+ gui.element("color selector grid", GridScrollArea::Options{
+ .entryWidth = BIG_BUTTON_SIZE,
+ .childAlignmentX = CLAY_ALIGN_X_CENTER,
+ .entryHeight = BIG_BUTTON_SIZE,
+ .entryCount = palette.colors.size() + 1,
+ .scrollbar = ScrollArea::ScrollbarType::NORMAL,
+ .elementContent = [&](size_t i) {
+ if(i < palette.colors.size()) {
auto newC = std::make_shared(palette.colors[i].x(), palette.colors[i].y(), palette.colors[i].z());
color_button(gui, "c", newC.get(), {
.isSelected = newC->x() == color->x() && newC->y() == color->y() && newC->z() == color->z(),
@@ -264,7 +270,124 @@ void PhoneDrawingProgramScreen::color_settings_popup(Vector4f* color) {
}
});
}
+ else {
+ svg_icon_button(gui, "extra color settings", "data/icons/RemixIcon/more-fill.svg", {
+ .drawType = SelectableButton::DrawType::TRANSPARENT_ALL,
+ .isSelected = colorPickerPopupData.extraSettingsOpen,
+ .onClick = [&] {
+ colorPickerPopupData.extraSettingsOpen = !colorPickerPopupData.extraSettingsOpen;
+ }
+ });
+ }
+ }
+ });
+ };
+
+ auto paletteColorPickerExtras = [&] {
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIT(200), .height = CLAY_SIZING_FIT(200)},
+ .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER},
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
+ }
+ }) {
+ gui.element>("color picker element", color, true);
+ }
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0)},
+ .childGap = gui.io.theme->childGap1,
+ .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER},
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
+ }
+ }) {
+ std::vector paletteNames;
+ for(auto& p : main.conf.palettes)
+ paletteNames.emplace_back(p.name);
+ gui.element>("paletteselector", &colorPickerPopupData.selectedPalette, paletteNames);
+ svg_icon_button(gui, "paletteadd", "data/icons/plus.svg", {
+ .onClick = [&] {
+ colorPickerPopupData.addingPalette = !colorPickerPopupData.addingPalette;
+ }
});
+ svg_icon_button(gui, "paletteremove", "data/icons/close.svg", {
+ .onClick = [&] {
+ main.conf.palettes.erase(main.conf.palettes.begin() + colorPickerPopupData.selectedPalette);
+ colorPickerPopupData.selectedPalette = 0;
+ }
+ });
+ }
+ if(colorPickerPopupData.addingPalette) {
+ input_text_field(gui, "paletteinputname", "Name", &colorPickerPopupData.newPaletteStr);
+ text_button(gui, "addpalettebutton", "Create", {
+ .wide = true,
+ .onClick = [&] {
+ if(!colorPickerPopupData.newPaletteStr.empty()) {
+ main.conf.palettes.emplace_back();
+ main.conf.palettes.back().name = colorPickerPopupData.newPaletteStr;
+ colorPickerPopupData.selectedPalette = main.conf.palettes.size() - 1;
+ colorPickerPopupData.addingPalette = false;
+ }
+ }
+ });
+ }
+ if(colorPickerPopupData.selectedPalette != 0) {
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0)},
+ .childGap = gui.io.theme->childGap1,
+ .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER},
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
+ }
+ }) {
+ svg_icon_button(gui, "addcolor", "data/icons/plus.svg", {
+ .onClick = [&, color] {
+ std::erase(palette.colors, Vector3f{color->x(), color->y(), color->z()});
+ palette.colors.emplace_back(color->x(), color->y(), color->z());
+ }
+ });
+ svg_icon_button(gui, "deletecolor", "data/icons/close.svg", {
+ .onClick = [&, color] {
+ std::erase(palette.colors, Vector3f{color->x(), color->y(), color->z()});
+ }
+ });
+ }
+ }
+ };
+
+ gui.element("color settings popup", [&] (LayoutElement* l, const Clay_ElementId& lId) {
+ CLAY(lId, {
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0)},
+ .childGap = gui.io.theme->childGap1,
+ .childAlignment = { .x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER},
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
+ },
+ .backgroundColor = convert_vec4(gui.io.theme->backColor1),
+ .cornerRadius = CLAY_CORNER_RADIUS(gui.io.theme->windowCorners1)
+ }) {
+ if(colorPickerPopupData.extraSettingsOpen) {
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0)},
+ .childGap = gui.io.theme->childGap1,
+ .layoutDirection = CLAY_TOP_TO_BOTTOM
+ },
+ }) {
+ paletteColorPickerGrid();
+ }
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0)},
+ .childGap = gui.io.theme->childGap1,
+ .layoutDirection = CLAY_TOP_TO_BOTTOM
+ },
+ }) {
+ paletteColorPickerExtras();
+ }
+ }
+ else
+ paletteColorPickerGrid();
}
});
}
diff --git a/src/Screens/PhoneDrawingProgramScreen.hpp b/src/Screens/PhoneDrawingProgramScreen.hpp
index 8204012..0a2b42c 100644
--- a/src/Screens/PhoneDrawingProgramScreen.hpp
+++ b/src/Screens/PhoneDrawingProgramScreen.hpp
@@ -24,9 +24,11 @@ class PhoneDrawingProgramScreen : public DrawingProgramScreen {
FG_COLOR,
BG_COLOR
} settingsMenuPopup = SettingsMenuPopup::NONE;
- struct PaletteData {
+ struct ColorPickerPopupData {
+ bool extraSettingsOpen = false;
size_t selectedPalette = 0;
bool addingPalette = false;
std::string newPaletteStr;
- } paletteData;
+ } colorPickerPopupData;
+ void reset_color_picker_popup_data();
};