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)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
project(nanogui_helloworld)
|
project(nanogui_experiments
|
||||||
|
VERSION 1.0
|
||||||
|
DESCRIPTION "NanoGUI experiments"
|
||||||
|
LANGUAGES CXX
|
||||||
|
)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(NANOGUI_REPO "https://github.com/SpotlightKid/nanogui" CACHE STRING "nanoGUi repository URL or path")
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
|
||||||
set(NANOGUI_BUILD_EXAMPLES OFF)
|
set(NANOGUI_BUILD_EXAMPLES OFF)
|
||||||
set(NANOGUI_BUILD_PYTHON OFF)
|
set(NANOGUI_BUILD_PYTHON OFF)
|
||||||
set(NANOGUI_BUILD_SHARED 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(lib/nanogui/include)
|
||||||
include_directories(${NANOGUI_EXTRA_INCS})
|
include_directories(${NANOGUI_EXTRA_INCS})
|
||||||
add_definitions(${NANOGUI_EXTRA_DEFS})
|
add_definitions(${NANOGUI_EXTRA_DEFS})
|
||||||
|
|
||||||
set_property(TARGET glfw glfw_objects nanogui PROPERTY FOLDER "dependencies")
|
set_property(TARGET glfw glfw_objects nanogui PROPERTY FOLDER "dependencies")
|
||||||
|
|
||||||
add_executable(nanogui_helloworld nanogui_helloworld.cpp)
|
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})
|
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 @@
|
||||||
|
|
||||||
![NanoGUI Knobs example app](nanogui_knobs.png)
|
![NanoGUI Knobs example app](nanogui_knobs.png)
|
||||||
|
|
||||||
## Quickstart
|
## Building
|
||||||
|
|
||||||
|
### Python
|
||||||
|
|
||||||
|
Set up virtual environment providing nanogui Python bindings:
|
||||||
|
|
||||||
```con
|
```con
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
(venv) pip install -r requirenments.txt
|
(venv) pip install -r requirenments.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Run helloworld examples:
|
||||||
|
|
||||||
|
```con
|
||||||
(venv) python3 nanogui_helloworld.py
|
(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
|
## Knobs Example
|
||||||
|
|
||||||
|
|
||||||
|
### Python
|
||||||
|
|
||||||
```con
|
```con
|
||||||
(venv) python3 nanogui_knobs.py
|
(venv) python3 nanogui_knobs.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### C++
|
||||||
|
|
||||||
|
```con
|
||||||
|
./build/nanogui_knobs
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Key and Mouse Bindings
|
### Key and Mouse Bindings
|
||||||
|
|
||||||
| | | |
|
| | | |
|
||||||
|
|
|
@ -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)
|
|
@ -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
|
|
|
@ -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…
Reference in New Issue