239 lines
6.2 KiB
C++
239 lines
6.2 KiB
C++
#include <algorithm>
|
|
|
|
#include <nanogui/opengl.h>
|
|
#include <nanogui/theme.h>
|
|
|
|
#include "fancyknob.hpp"
|
|
|
|
NAMESPACE_BEGIN(nanogui)
|
|
|
|
FancyKnob::FancyKnob(Widget* parent, int rad)
|
|
: Widget(parent)
|
|
, m_value(0.0f)
|
|
, m_min_val(0.0f)
|
|
, m_max_val(100.0f)
|
|
, m_increment(0.1f)
|
|
, m_fine_mode(false)
|
|
, m_scroll_speed(2.0f)
|
|
, m_gauge_width(0.125f)
|
|
, m_indicator_size(0.35f)
|
|
{
|
|
// TBD: getters & setters for all colors
|
|
set_gauge_color(Color(255, 80, 80, 255));
|
|
m_knob_color_1 = Color(86, 92, 95, 255);
|
|
m_knob_color_2 = Color(39, 42, 43, 255);
|
|
m_outline_color_1 = Color(190, 190, 190, 0);
|
|
m_outline_color_2 = Color(23, 23, 23, 255);
|
|
m_scroll_increment = (m_max_val - m_min_val) / 100.0 * m_scroll_speed;
|
|
m_drag_increment = (m_max_val - m_min_val) / 100.0;
|
|
set_cursor(Cursor::Hand);
|
|
Widget::set_size({ rad, rad });
|
|
}
|
|
|
|
const float FancyKnob::m_pi = std::acos(-1.0f);
|
|
|
|
Vector2i FancyKnob::preferred_size(NVGcontext*) const
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
void FancyKnob::set_min_value(float value)
|
|
{
|
|
m_min_val = value;
|
|
m_scroll_increment = (m_max_val - m_min_val) / 100.0 * m_scroll_speed;
|
|
m_drag_increment = (m_max_val - m_min_val) / 100.0;
|
|
}
|
|
|
|
void FancyKnob::set_max_value(float value)
|
|
{
|
|
m_max_val = value;
|
|
m_scroll_increment = (m_max_val - m_min_val) / 100.0 * m_scroll_speed;
|
|
m_drag_increment = (m_max_val - m_min_val) / 100.0;
|
|
}
|
|
|
|
void FancyKnob::set_scroll_speed(float value)
|
|
{
|
|
m_scroll_speed = value;
|
|
m_scroll_increment = (m_max_val - m_min_val) / 100.0 * m_scroll_speed;
|
|
}
|
|
|
|
void FancyKnob::set_gauge_color(const Color& color)
|
|
{
|
|
m_gauge_color = color;
|
|
NVGcolor bg = nvgLerpRGBA(Color(40, 40, 40, 255), m_gauge_color, 0.3f);
|
|
m_gauge_bg_color = Color(bg.r, bg.g, bg.b, bg.a);
|
|
}
|
|
|
|
bool FancyKnob::adjust_value(float value, float incr)
|
|
{
|
|
if (m_fine_mode)
|
|
incr = m_increment;
|
|
|
|
float new_val = m_value + value * incr;
|
|
new_val = std::max(m_min_val, std::min(m_max_val, new_val));
|
|
|
|
if (new_val != m_value) {
|
|
m_value = new_val;
|
|
|
|
if (m_callback)
|
|
m_callback(m_value);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FancyKnob::scroll_event(const Vector2i& p, const Vector2f& rel)
|
|
{
|
|
if (!m_enabled)
|
|
return false;
|
|
|
|
adjust_value(rel[1], m_scroll_increment);
|
|
return true;
|
|
}
|
|
|
|
bool FancyKnob::mouse_enter_event(const Vector2i& p, bool enter)
|
|
{
|
|
if (enter)
|
|
request_focus();
|
|
|
|
set_focused(enter);
|
|
return true;
|
|
}
|
|
|
|
bool FancyKnob::mouse_drag_event(const Vector2i& p, const Vector2i& rel, int /* button */, int /* modifiers */)
|
|
{
|
|
if (!m_enabled)
|
|
return false;
|
|
|
|
adjust_value((float)-rel[1], m_drag_increment);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FancyKnob::mouse_button_event(const Vector2i& /* p */, int button, bool down, int modifiers)
|
|
{
|
|
if (!m_enabled)
|
|
return false;
|
|
|
|
if (button == GLFW_MOUSE_BUTTON_1 && modifiers & GLFW_MOD_CONTROL && down) {
|
|
if (m_value != m_default) {
|
|
m_value = m_default;
|
|
|
|
if (m_callback)
|
|
m_callback(m_value);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FancyKnob::keyboard_event(int key, int scancode, int action, int modifiers)
|
|
{
|
|
if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT) {
|
|
if (action == GLFW_PRESS)
|
|
m_fine_mode = true;
|
|
else if (action == GLFW_RELEASE)
|
|
m_fine_mode = false;
|
|
return true;
|
|
} else if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
|
if (key == GLFW_KEY_UP) {
|
|
adjust_value(1, m_drag_increment);
|
|
return true;
|
|
} else if (key == GLFW_KEY_DOWN) {
|
|
adjust_value(-1, m_drag_increment);
|
|
return true;
|
|
} else if (key == GLFW_KEY_PAGE_UP) {
|
|
adjust_value(10, m_drag_increment);
|
|
return true;
|
|
} else if (key == GLFW_KEY_PAGE_DOWN) {
|
|
adjust_value(-10, m_drag_increment);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FancyKnob::draw(NVGcontext* ctx)
|
|
{
|
|
float height = (float)m_size.y();
|
|
float radius = height / 2.0;
|
|
float gauge_width = radius * m_gauge_width;
|
|
float margin = gauge_width / 2.0;
|
|
float percent_filled = (m_value - m_min_val) / (m_max_val - m_min_val);
|
|
float knob_diameter = (radius - gauge_width) * 2.0 - margin;
|
|
float indicator_length = radius * m_indicator_size;
|
|
float indicator_start = radius - margin - indicator_length;
|
|
|
|
nvgSave(ctx);
|
|
nvgTranslate(ctx, m_pos.x(), m_pos.y());
|
|
|
|
// Gauge (background)
|
|
nvgBeginPath(ctx);
|
|
|
|
nvgStrokeWidth(ctx, gauge_width);
|
|
nvgStrokeColor(ctx, m_gauge_bg_color);
|
|
nvgLineCap(ctx, NVG_ROUND);
|
|
nvgArc(ctx, radius, radius, radius - margin, 0.75 * m_pi, 0.25 * m_pi, NVG_CW);
|
|
nvgStroke(ctx);
|
|
|
|
// Gauge (fill)
|
|
nvgBeginPath(ctx);
|
|
|
|
nvgStrokeWidth(ctx, gauge_width);
|
|
nvgStrokeColor(ctx, m_gauge_color);
|
|
nvgLineCap(ctx, NVG_ROUND);
|
|
nvgArc(
|
|
ctx,
|
|
radius,
|
|
radius,
|
|
radius - margin,
|
|
0.75 * m_pi,
|
|
(0.75 + 1.5 * percent_filled) * m_pi,
|
|
NVG_CW);
|
|
nvgStroke(ctx);
|
|
|
|
// Knob
|
|
nvgBeginPath(ctx);
|
|
|
|
nvgStrokeWidth(ctx, 2.0);
|
|
NVGpaint outline_paint = nvgLinearGradient(
|
|
ctx,
|
|
0,
|
|
0,
|
|
0,
|
|
height - 10,
|
|
m_outline_color_1,
|
|
m_outline_color_2);
|
|
nvgStrokePaint(ctx, outline_paint);
|
|
|
|
NVGpaint knob_paint = nvgLinearGradient(
|
|
ctx, radius, gauge_width, radius, knob_diameter, m_knob_color_1, m_knob_color_2);
|
|
nvgFillPaint(ctx, knob_paint);
|
|
|
|
nvgCircle(ctx, radius, radius, knob_diameter / 2.0);
|
|
nvgFill(ctx);
|
|
nvgStroke(ctx);
|
|
|
|
// Indicator
|
|
nvgBeginPath(ctx);
|
|
|
|
nvgTranslate(ctx, radius, radius);
|
|
nvgRotate(ctx, (2.0 + ((percent_filled - 0.5) * 1.5)) * m_pi);
|
|
|
|
nvgStrokeColor(ctx, m_gauge_color);
|
|
nvgStrokeWidth(ctx, gauge_width);
|
|
nvgLineCap(ctx, NVG_ROUND);
|
|
nvgMoveTo(ctx, 0, -indicator_start);
|
|
nvgLineTo(ctx, 0, -(indicator_start + indicator_length));
|
|
nvgStroke(ctx);
|
|
|
|
nvgRestore(ctx);
|
|
nvgClosePath(ctx);
|
|
}
|
|
|
|
NAMESPACE_END(nanogui)
|