Add C++ implementation of custom knob widget and example
Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
This commit is contained in:
		
							parent
							
								
									e0003dded5
								
							
						
					
					
						commit
						2da51dd7cd
					
				@ -1,19 +1,33 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.13)
 | 
			
		||||
project(nanogui_helloworld)
 | 
			
		||||
cmake_minimum_required(VERSION 3.14)
 | 
			
		||||
project(nanogui_experiments
 | 
			
		||||
    VERSION 1.0
 | 
			
		||||
    DESCRIPTION "NanoGUI experiments"
 | 
			
		||||
    LANGUAGES CXX
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_STANDARD 17)
 | 
			
		||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
 | 
			
		||||
set(NANOGUI_REPO "https://github.com/SpotlightKid/nanogui" CACHE STRING "nanoGUi repository URL or path")
 | 
			
		||||
set(NANOGUI_BUILD_EXAMPLES OFF)
 | 
			
		||||
set(NANOGUI_BUILD_PYTHON OFF)
 | 
			
		||||
set(NANOGUI_BUILD_SHARED OFF)
 | 
			
		||||
 | 
			
		||||
add_subdirectory(lib/nanogui)
 | 
			
		||||
include(FetchContent)
 | 
			
		||||
FetchContent_Declare(nanogui
 | 
			
		||||
    GIT_REPOSITORY ${NANOGUI_REPO}
 | 
			
		||||
    GIT_TAG nanogui-experiments
 | 
			
		||||
    GIT_SHALLOW true
 | 
			
		||||
    SOURCE_DIR lib/nanogui
 | 
			
		||||
)
 | 
			
		||||
FetchContent_MakeAvailable(nanogui)
 | 
			
		||||
 | 
			
		||||
include_directories(lib/nanogui/include)
 | 
			
		||||
include_directories(${NANOGUI_EXTRA_INCS})
 | 
			
		||||
add_definitions(${NANOGUI_EXTRA_DEFS})
 | 
			
		||||
 | 
			
		||||
set_property(TARGET glfw glfw_objects nanogui PROPERTY FOLDER "dependencies")
 | 
			
		||||
 | 
			
		||||
add_executable(nanogui_helloworld nanogui_helloworld.cpp)
 | 
			
		||||
target_compile_features(nanogui_helloworld PRIVATE cxx_std_17)
 | 
			
		||||
target_link_libraries(nanogui_helloworld nanogui ${NANOGUI_EXTRA_LIBS})
 | 
			
		||||
 | 
			
		||||
add_executable(nanogui_knobs nanogui_knobs.cpp fancyknob.cpp)
 | 
			
		||||
target_compile_features(nanogui_knobs PRIVATE cxx_std_17)
 | 
			
		||||
target_link_libraries(nanogui_knobs nanogui ${NANOGUI_EXTRA_LIBS})
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										47
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								README.md
									
									
									
									
									
								
							@ -2,22 +2,67 @@
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## Quickstart
 | 
			
		||||
## Building
 | 
			
		||||
 | 
			
		||||
### Python
 | 
			
		||||
 | 
			
		||||
Set up virtual environment providing nanogui Python bindings:
 | 
			
		||||
 | 
			
		||||
```con
 | 
			
		||||
python3 -m venv venv
 | 
			
		||||
source venv/bin/activate
 | 
			
		||||
(venv) pip install -r requirenments.txt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Run helloworld examples:
 | 
			
		||||
 | 
			
		||||
```con
 | 
			
		||||
(venv) python3 nanogui_helloworld.py
 | 
			
		||||
(venv) python3 nanogui_custowidget.py
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### C++
 | 
			
		||||
 | 
			
		||||
Configure build with *CMake*:
 | 
			
		||||
 | 
			
		||||
```con
 | 
			
		||||
cmake -B build -S .
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
(This will checkout the NanoGUI library from GitHub into the build directory.
 | 
			
		||||
You can use `-DNANOGUI_REPO=<repo path or URL>` to change from where Git will
 | 
			
		||||
retrieve the repository.)
 | 
			
		||||
 | 
			
		||||
Build the examples:
 | 
			
		||||
 | 
			
		||||
```con
 | 
			
		||||
cmake --build build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Run hellworld example:
 | 
			
		||||
 | 
			
		||||
```con
 | 
			
		||||
./build/nanogui_helloworld
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Knobs Example
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Python
 | 
			
		||||
 | 
			
		||||
```con
 | 
			
		||||
(venv) python3 nanogui_knobs.py
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### C++
 | 
			
		||||
 | 
			
		||||
```con
 | 
			
		||||
./build/nanogui_knobs
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Key and Mouse Bindings
 | 
			
		||||
 | 
			
		||||
|                                           |                      |                         |
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										238
									
								
								fancyknob.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								fancyknob.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,238 @@
 | 
			
		||||
#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)
 | 
			
		||||
							
								
								
									
										85
									
								
								fancyknob.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								fancyknob.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,85 @@
 | 
			
		||||
#ifndef FANCYKNOB_H
 | 
			
		||||
#define FANCYKNOB_H
 | 
			
		||||
 | 
			
		||||
#include <nanogui/widget.h>
 | 
			
		||||
 | 
			
		||||
NAMESPACE_BEGIN(nanogui)
 | 
			
		||||
 | 
			
		||||
class NANOGUI_EXPORT FancyKnob : public Widget {
 | 
			
		||||
public:
 | 
			
		||||
    FancyKnob(Widget* parent, int rad = 80);
 | 
			
		||||
 | 
			
		||||
    float value() const { return m_value; }
 | 
			
		||||
    void set_value(float value)
 | 
			
		||||
    {
 | 
			
		||||
        if (value != m_value)
 | 
			
		||||
            m_value = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float min_default() const { return m_default; }
 | 
			
		||||
    void set_default(float value) { m_default = value; }
 | 
			
		||||
 | 
			
		||||
    float min_value() const { return m_min_val; }
 | 
			
		||||
    void set_min_value(float value);
 | 
			
		||||
 | 
			
		||||
    float max_value() const { return m_max_val; }
 | 
			
		||||
    void set_max_value(float value);
 | 
			
		||||
 | 
			
		||||
    float increment() const { return m_increment; }
 | 
			
		||||
    void set_increment(float value) { m_increment = value; }
 | 
			
		||||
 | 
			
		||||
    float scroll_speed() const { return m_scroll_speed; }
 | 
			
		||||
    void set_scroll_speed(float value);
 | 
			
		||||
 | 
			
		||||
    const Color& gauge_color() const { return m_gauge_color; }
 | 
			
		||||
    void set_gauge_color(const Color& color);
 | 
			
		||||
 | 
			
		||||
    std::function<void(float)> callback() const { return m_callback; }
 | 
			
		||||
    void set_callback(const std::function<void(float)>& callback) { m_callback = callback; }
 | 
			
		||||
 | 
			
		||||
    virtual Vector2i preferred_size(NVGcontext* ctx) const override;
 | 
			
		||||
    virtual bool mouse_enter_event(const Vector2i& p, bool enter);
 | 
			
		||||
    virtual bool mouse_drag_event(const Vector2i& p, const Vector2i& rel, int button, int modifiers) override;
 | 
			
		||||
    virtual bool mouse_button_event(const Vector2i& p, int button, bool down, int modifiers) override;
 | 
			
		||||
    virtual bool scroll_event(const Vector2i& p, const Vector2f& rel) override;
 | 
			
		||||
    virtual bool keyboard_event(int key, int scancode, int action, int modifiers);
 | 
			
		||||
    virtual void draw(NVGcontext* ctx) override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    bool adjust_value(float value, float incr);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static const float m_pi;
 | 
			
		||||
 | 
			
		||||
    // colors
 | 
			
		||||
    Color
 | 
			
		||||
        m_gauge_color,
 | 
			
		||||
        m_gauge_bg_color,
 | 
			
		||||
        m_knob_color_1,
 | 
			
		||||
        m_knob_color_2,
 | 
			
		||||
        m_outline_color_1,
 | 
			
		||||
        m_outline_color_2;
 | 
			
		||||
 | 
			
		||||
    // sizes, value and range
 | 
			
		||||
    float
 | 
			
		||||
        m_value,
 | 
			
		||||
        m_min_val,
 | 
			
		||||
        m_max_val,
 | 
			
		||||
        m_default,
 | 
			
		||||
        m_increment,
 | 
			
		||||
        m_scroll_speed,
 | 
			
		||||
        m_scroll_increment,
 | 
			
		||||
        m_drag_increment,
 | 
			
		||||
        /* value gauge width as ratio of knob radius */
 | 
			
		||||
        m_gauge_width,
 | 
			
		||||
        /* value indicator line length as ratio of knob radius */
 | 
			
		||||
        m_indicator_size;
 | 
			
		||||
 | 
			
		||||
    // behaviour
 | 
			
		||||
    bool m_fine_mode = false;
 | 
			
		||||
    std::function<void(float)> m_callback;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
NAMESPACE_END(nanogui)
 | 
			
		||||
 | 
			
		||||
#endif // FANCYKNOB_H
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
../../nanogui
 | 
			
		||||
							
								
								
									
										144
									
								
								nanogui_knobs.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								nanogui_knobs.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,144 @@
 | 
			
		||||
/*
 | 
			
		||||
    src/nanogui_customwidget.cpp -- C++ version of an customwidget example application
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <nanogui/button.h>
 | 
			
		||||
#include <nanogui/label.h>
 | 
			
		||||
#include <nanogui/layout.h>
 | 
			
		||||
#include <nanogui/opengl.h>
 | 
			
		||||
#include <nanogui/screen.h>
 | 
			
		||||
#include <nanogui/textbox.h>
 | 
			
		||||
#include <nanogui/widget.h>
 | 
			
		||||
#include <nanogui/window.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "fancyknob.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace nanogui;
 | 
			
		||||
 | 
			
		||||
struct KnobSpec {
 | 
			
		||||
    std::string name;
 | 
			
		||||
    float default_value;
 | 
			
		||||
    float min_value;
 | 
			
		||||
    float max_value;
 | 
			
		||||
    float increment;
 | 
			
		||||
    std::string unit;
 | 
			
		||||
    Vector4i color;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
KnobSpec knobs[4] = {
 | 
			
		||||
    { "Attack", 0.0, 0.0, 5.0, 0.01, "s", { 224, 128, 128, 255 } },
 | 
			
		||||
    { "Decay", 0.2, 0.0, 5.0, 0.01, "s", { 128, 224, 128, 255 } },
 | 
			
		||||
    { "Sustain", 100.0, 0.0, 100.0, 0.01, "%", { 128, 128, 224, 255 } },
 | 
			
		||||
    { "Release", 0.2, 0.0, 5.0, 0.01, "s", { 224, 224, 128, 255 } },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class KnobsApplication : public Screen {
 | 
			
		||||
public:
 | 
			
		||||
    KnobsApplication()
 | 
			
		||||
        : Screen(Vector2i(452, 250), "NanoGUI Knobs")
 | 
			
		||||
    {
 | 
			
		||||
        inc_ref();
 | 
			
		||||
        set_background(Color(96, 96, 96, 255));
 | 
			
		||||
 | 
			
		||||
        window = new Window(this, "Envelope");
 | 
			
		||||
        window->set_layout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 20, 20));
 | 
			
		||||
        resize_event(size());
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < 4; i++) {
 | 
			
		||||
            Widget* box = new Widget(window);
 | 
			
		||||
            box->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Middle, 0, 10));
 | 
			
		||||
 | 
			
		||||
            KnobSpec knob = knobs[i];
 | 
			
		||||
            FancyKnob* k = new FancyKnob(box);
 | 
			
		||||
            k->set_default(knob.default_value);
 | 
			
		||||
            k->set_value(knob.default_value);
 | 
			
		||||
            k->set_min_value(knob.min_value);
 | 
			
		||||
            k->set_max_value(knob.max_value);
 | 
			
		||||
            k->set_increment(knob.increment);
 | 
			
		||||
            k->set_gauge_color(Color(knob.color));
 | 
			
		||||
 | 
			
		||||
            FloatBox<float>* entry = new FloatBox<float>(box);
 | 
			
		||||
            entry->set_fixed_size({ 88, 24 });
 | 
			
		||||
            entry->set_font_size(20);
 | 
			
		||||
            entry->set_editable(true);
 | 
			
		||||
            entry->set_spinnable(true);
 | 
			
		||||
            entry->set_value(k->value());
 | 
			
		||||
            entry->number_format("%02.2f");
 | 
			
		||||
            entry->set_min_value(k->min_value());
 | 
			
		||||
            entry->set_max_value(k->max_value());
 | 
			
		||||
            entry->set_value_increment(k->increment());
 | 
			
		||||
            entry->set_units(knob.unit);
 | 
			
		||||
            entry->set_callback([k](float f) { k->set_value(f); });
 | 
			
		||||
 | 
			
		||||
            k->set_callback([entry, knob](float f) {
 | 
			
		||||
                entry->set_value(f);
 | 
			
		||||
                std::cout << "'" << knob.name << "' value: " << f << std::endl;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            Label* l = new Label(box, knob.name, "sans", 20);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        perform_layout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual bool resize_event(const Vector2i& size)
 | 
			
		||||
    {
 | 
			
		||||
        window->set_fixed_size(size);
 | 
			
		||||
        window->set_size(size);
 | 
			
		||||
        window->center();
 | 
			
		||||
        window->perform_layout(nvg_context());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual bool keyboard_event(int key, int scancode, int action, int modifiers)
 | 
			
		||||
    {
 | 
			
		||||
        if (Screen::keyboard_event(key, scancode, action, modifiers))
 | 
			
		||||
            return true;
 | 
			
		||||
        if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
 | 
			
		||||
            set_visible(false);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void draw(NVGcontext* ctx)
 | 
			
		||||
    {
 | 
			
		||||
        /* Draw the user interface */
 | 
			
		||||
        Screen::draw(ctx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Window* window;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main(int /* argc */, char** /* argv */)
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        nanogui::init();
 | 
			
		||||
 | 
			
		||||
        /* scoped variables */ {
 | 
			
		||||
            ref<KnobsApplication> app = new KnobsApplication();
 | 
			
		||||
            app->dec_ref();
 | 
			
		||||
            app->draw_all();
 | 
			
		||||
            app->set_visible(true);
 | 
			
		||||
            nanogui::mainloop(1 / 60.f * 1000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        nanogui::shutdown();
 | 
			
		||||
    } catch (const std::exception& e) {
 | 
			
		||||
        std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
        MessageBoxA(nullptr, error_msg.c_str(), NULL, MB_ICONERROR | MB_OK);
 | 
			
		||||
#else
 | 
			
		||||
        std::cerr << error_msg << std::endl;
 | 
			
		||||
#endif
 | 
			
		||||
        return -1;
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
        std::cerr << "Caught an unknown error!" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user