├── docs ├── _static │ ├── entypo.eot │ ├── entypo.ttf │ ├── entypo.woff │ └── entypo.woff2 ├── requirements.txt ├── release.rst ├── Makefile ├── make.bat ├── index.rst ├── usage.rst └── examples.rst ├── resources ├── screenshot.png ├── Roboto-Bold.ttf ├── icons │ ├── icon1.png │ ├── icon2.png │ ├── icon3.png │ ├── icon4.png │ ├── icon5.png │ ├── icon6.ico │ ├── icon6.png │ ├── icon7.png │ └── icon8.png ├── screenshot2.png ├── Roboto-Regular.ttf ├── FontAwesome-Solid.ttf ├── Inconsolata-Regular.ttf ├── imageview_vertex.gl ├── imageview_vertex.gles ├── nanoguiConfig.cmake.in ├── imageview_fragment.gles ├── imageview_fragment.gl ├── imageview_vertex.metal ├── imageview_fragment.metal ├── bin2c.cmake ├── check-style.sh └── fa-import.py ├── MANIFEST.in ├── src ├── opengl_check.h ├── autorelease.mm ├── python │ ├── ema.cpp │ ├── chroma.cpp │ ├── python.h │ ├── color.cpp │ ├── quad.cpp │ ├── textarea.cpp │ ├── example_icons.py │ ├── example2.py │ ├── render_test_3_quad.py │ ├── render_test_0.py │ ├── canvas.cpp │ ├── render_test_1.py │ ├── tabs.cpp │ ├── misc.cpp │ ├── example_hdr.py │ ├── textbox.cpp │ ├── glfw.cpp │ ├── CMakeLists.txt │ ├── button.cpp │ └── formhelper.cpp ├── shader_impl.h ├── shader.cpp ├── opengl.cpp ├── progressbar.cpp ├── traits.cpp ├── rtimer.cpp ├── rtimer.h ├── messagedialog.cpp ├── label.cpp ├── graph.cpp ├── popup.cpp ├── example2.cpp ├── popupbutton.cpp ├── checkbox.cpp ├── combobox.cpp ├── colorpicker.cpp ├── texture.cpp ├── theme.cpp └── imagepanel.cpp ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ └── wheels.yml ├── nanogui └── __init__.py ├── .gitmodules ├── .appveyor.yml ├── include └── nanogui │ ├── toolbutton.h │ ├── progressbar.h │ ├── nanogui.h │ ├── ema.h │ ├── messagedialog.h │ ├── popupbutton.h │ ├── chroma.h │ ├── imagepanel.h │ ├── vscrollpanel.h │ ├── label.h │ ├── graph.h │ ├── slider.h │ ├── colorpass.h │ ├── window.h │ ├── metal.h │ ├── popup.h │ ├── combobox.h │ ├── imageview.h │ ├── quad.h │ ├── traits.h │ ├── canvas.h │ ├── opengl.h │ ├── colorwheel.h │ ├── checkbox.h │ └── textarea.h ├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── CONTRIBUTING.rst └── pyproject.toml /docs/_static/entypo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/docs/_static/entypo.eot -------------------------------------------------------------------------------- /docs/_static/entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/docs/_static/entypo.ttf -------------------------------------------------------------------------------- /docs/_static/entypo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/docs/_static/entypo.woff -------------------------------------------------------------------------------- /resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/screenshot.png -------------------------------------------------------------------------------- /docs/_static/entypo.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/docs/_static/entypo.woff2 -------------------------------------------------------------------------------- /resources/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/Roboto-Bold.ttf -------------------------------------------------------------------------------- /resources/icons/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon1.png -------------------------------------------------------------------------------- /resources/icons/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon2.png -------------------------------------------------------------------------------- /resources/icons/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon3.png -------------------------------------------------------------------------------- /resources/icons/icon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon4.png -------------------------------------------------------------------------------- /resources/icons/icon5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon5.png -------------------------------------------------------------------------------- /resources/icons/icon6.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon6.ico -------------------------------------------------------------------------------- /resources/icons/icon6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon6.png -------------------------------------------------------------------------------- /resources/icons/icon7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon7.png -------------------------------------------------------------------------------- /resources/icons/icon8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/icons/icon8.png -------------------------------------------------------------------------------- /resources/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/screenshot2.png -------------------------------------------------------------------------------- /resources/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/Roboto-Regular.ttf -------------------------------------------------------------------------------- /resources/FontAwesome-Solid.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/FontAwesome-Solid.ttf -------------------------------------------------------------------------------- /resources/Inconsolata-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitsuba-renderer/nanogui/HEAD/resources/Inconsolata-Regular.ttf -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # Breathe and Sphinx 2.x are incompatible at this time 2 | Sphinx==1.8.5 3 | exhale 4 | sphinx_rtd_theme 5 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE.txt 2 | global-include CMakeLists.txt *.cmake 3 | recursive-include src *.cpp 4 | recursive-include include *.h 5 | recursive-include python *.cpp *.h 6 | recursive-include resources *.ttf 7 | recursive-include ext *.h *.c *.cpp *.pc.in *.h.in *.cmake.in 8 | -------------------------------------------------------------------------------- /src/opengl_check.h: -------------------------------------------------------------------------------- 1 | #if defined(NDEBUG) 2 | # define CHK(cmd) cmd 3 | #else 4 | # define CHK(cmd) \ 5 | do { \ 6 | cmd; \ 7 | (void) nanogui_check_glerror(#cmd); \ 8 | } while (0) 9 | #endif 10 | 11 | -------------------------------------------------------------------------------- /src/autorelease.mm: -------------------------------------------------------------------------------- 1 | #include 2 | #import 3 | 4 | NAMESPACE_BEGIN(nanogui) 5 | 6 | void *autorelease_init() { 7 | return [[NSAutoreleasePool alloc] init]; 8 | } 9 | 10 | void autorelease_release(void *pool_) { 11 | [((NSAutoreleasePool *) pool_) release]; 12 | } 13 | 14 | NAMESPACE_END(nanogui) 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | ignore: 9 | # Offical actions have moving tags like v1 10 | # that are used, so they don't need updates here 11 | - dependency-name: "actions/*" 12 | -------------------------------------------------------------------------------- /resources/imageview_vertex.gl: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | uniform mat4 matrix_image; 4 | uniform mat4 matrix_background; 5 | in vec2 position; 6 | out vec2 position_background; 7 | out vec2 uv; 8 | 9 | void main() { 10 | vec4 p = vec4(position, 0.0, 1.0); 11 | gl_Position = matrix_image * p; 12 | position_background = (matrix_background * p).xy; 13 | uv = position; 14 | } 15 | -------------------------------------------------------------------------------- /resources/imageview_vertex.gles: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform mat4 matrix_image; 4 | uniform mat4 matrix_background; 5 | attribute vec2 position; 6 | varying vec2 position_background; 7 | varying vec2 uv; 8 | 9 | void main() { 10 | vec4 p = vec4(position, 0.0, 1.0); 11 | gl_Position = matrix_image * p; 12 | position_background = (matrix_background * p).xy; 13 | uv = position; 14 | } 15 | -------------------------------------------------------------------------------- /nanogui/__init__.py: -------------------------------------------------------------------------------- 1 | from importlib import import_module as _import 2 | 3 | _import('nanogui.nanogui_ext') 4 | 5 | def cmake_dir(): 6 | from os import path 7 | file_dir = path.abspath(path.dirname(__file__)) 8 | cmake_path = path.join(file_dir, "share", "cmake", "nanogui") 9 | if not path.exists(cmake_path): 10 | raise ImportError("Cannot find NanoGUI CMake directory") 11 | return cmake_path 12 | -------------------------------------------------------------------------------- /docs/release.rst: -------------------------------------------------------------------------------- 1 | How to make a new release? 2 | -------------------------- 3 | 4 | 1. Update version in ``include/nanogui/common.h`` 5 | 6 | 2. Commit: ``git commit -am "vX.Y.Z release"`` 7 | 8 | 3. Tag: ``git tag -a vX.Y.Z -m "vX.Y.Z release"`` 9 | 10 | 4. Push: ``git push`` and ``git push --tags`` 11 | 12 | 5. Build via GitHub actions (``Wheels`` target) 13 | 14 | 6. Upload via GitHub or ``twine upload `` 15 | -------------------------------------------------------------------------------- /resources/nanoguiConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set(nanogui_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") 4 | set(nanogui_VERSION_TYPE "@ENOKI_VERSION_TYPE@") 5 | set(nanogui_LIBRARY "") 6 | 7 | check_required_components(nanogui) 8 | 9 | include("${CMAKE_CURRENT_LIST_DIR}/nanoguiTargets.cmake") 10 | 11 | if(NOT nanogui_FIND_QUIETLY) 12 | message(STATUS "Found nanogui: ${nanogui_INCLUDE_DIR} (found version \"${nanogui_VERSION}\" ${nanogui_VERSION_TYPE})") 13 | endif() 14 | 15 | -------------------------------------------------------------------------------- /src/python/ema.cpp: -------------------------------------------------------------------------------- 1 | #ifdef NANOGUI_PYTHON 2 | 3 | #include "python.h" 4 | #include 5 | 6 | void register_ema(nb::module_ &m) { 7 | nb::class_(m, "EMA", D(EMA)) 8 | .def(nb::init(), "weight"_a = 0.983f, D(EMA, EMA)) 9 | .def("reset", &EMA::reset, D(EMA, reset)) 10 | .def("put", &EMA::put, "sample"_a, D(EMA, put)) 11 | .def("value", &EMA::value, D(EMA, value)) 12 | .def("weight", &EMA::weight, D(EMA, weight)) 13 | .def("sample_count", &EMA::sample_count, D(EMA, sample_count)); 14 | } 15 | 16 | #endif -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/nanovg"] 2 | path = ext/nanovg 3 | url = https://github.com/wjakob/nanovg 4 | [submodule "ext/nanovg_metal"] 5 | path = ext/nanovg_metal 6 | url = https://github.com/wjakob/nanovg_metal 7 | [submodule "ext/glfw"] 8 | path = ext/glfw 9 | url = https://github.com/wjakob/glfw 10 | [submodule "ext/nanobind"] 11 | path = ext/nanobind 12 | url = https://github.com/wjakob/nanobind 13 | [submodule "ext/nativefiledialog-extended"] 14 | path = ext/nativefiledialog-extended 15 | url = https://github.com/mitsuba-renderer/nativefiledialog-extended 16 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | os: Visual Studio 2015 3 | test: off 4 | clone_folder: C:\projects\nanogui 5 | branches: 6 | only: 7 | - master 8 | install: 9 | - git submodule update --init --recursive 10 | - cinstall: python 11 | build_script: 12 | - echo Running cmake... 13 | - cd c:\projects\nanogui 14 | - cmake -G "Visual Studio 14 2015 Win64" -DPYTHON_EXECUTABLE:FILEPATH=C:/Python34-x64/python.exe . 15 | - set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" 16 | - set MSBuildOptions=/v:m /p:Configuration=Release /logger:%MSBuildLogger% 17 | - msbuild %MSBuildOptions% nanogui.sln 18 | -------------------------------------------------------------------------------- /resources/imageview_fragment.gles: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | varying vec2 uv; 4 | varying vec2 position_background; 5 | uniform sampler2D image; 6 | uniform vec4 background_color; 7 | 8 | void main() { 9 | vec2 frac = position_background - floor(position_background); 10 | float checkerboard = ((frac.x > .5) == (frac.y > .5)) ? 0.4 : 0.5; 11 | 12 | vec4 background = (1.0 - background_color.a) * vec4(vec3(checkerboard), 1.0) + 13 | background_color.a * vec4(background_color.rgb, 1.0); 14 | 15 | vec4 value = texture2D(image, uv); 16 | gl_FragColor = (1.0 - value.a) * background + value.a * vec4(value.rgb, 1.0); 17 | } 18 | -------------------------------------------------------------------------------- /resources/imageview_fragment.gl: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | in vec2 uv; 4 | in vec2 position_background; 5 | out vec4 frag_color; 6 | uniform sampler2D image; 7 | uniform vec4 background_color; 8 | 9 | void main() { 10 | vec2 frac = position_background - floor(position_background); 11 | float checkerboard = ((frac.x > .5) == (frac.y > .5)) ? 0.4 : 0.5; 12 | 13 | vec4 background = (1.0 - background_color.a) * vec4(vec3(checkerboard), 1.0) + 14 | background_color.a * vec4(background_color.rgb, 1.0); 15 | 16 | vec4 value = texture(image, uv); 17 | frag_color = (1.0 - value.a) * background + value.a * vec4(value.rgb, 1.0); 18 | } 19 | -------------------------------------------------------------------------------- /resources/imageview_vertex.metal: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace metal; 4 | 5 | struct VertexOut { 6 | float4 position_image [[position]]; 7 | float2 position_background; 8 | float2 uv; 9 | }; 10 | 11 | vertex VertexOut vertex_main(const device float2 *position, 12 | constant float4x4 &matrix_image, 13 | constant float4x4 &matrix_background, 14 | uint id [[vertex_id]]) { 15 | float4 p = float4(position[id], 0.f, 1.f); 16 | VertexOut vert; 17 | vert.position_image = matrix_image * p; 18 | vert.position_background = (matrix_background * p).xy; 19 | vert.uv = p.xy; 20 | return vert; 21 | } 22 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = NanoGUI 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile clean 16 | 17 | clean: 18 | rm -rf doxyoutput/ api/ 19 | @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 20 | 21 | # Catch-all target: route all unknown targets to Sphinx using the new 22 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 23 | %: Makefile 24 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 25 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python -msphinx 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=NanoGUI 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /resources/imageview_fragment.metal: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace metal; 4 | 5 | struct VertexOut { 6 | float4 position_image [[position]]; 7 | float2 position_background; 8 | float2 uv; 9 | }; 10 | 11 | fragment float4 fragment_main(VertexOut vert [[stage_in]], 12 | texture2d image, 13 | constant float4 &background_color, 14 | sampler image_sampler) { 15 | float2 frac = vert.position_background - floor(vert.position_background); 16 | float checkerboard = ((frac.x > .5f) == (frac.y > .5f)) ? .4f : .5f; 17 | 18 | float4 background = (1.f - background_color.a) * float4(float3(checkerboard), 1.f) + 19 | background_color.a * float4(background_color.rgb, 1.f); 20 | 21 | float4 value = image.sample(image_sampler, vert.uv); 22 | return (1.f - value.a) * background + value.a * float4(value.rgb, 1.f); 23 | } 24 | -------------------------------------------------------------------------------- /include/nanogui/toolbutton.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/toolbutton.h -- Simple radio+toggle button with an icon 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class ToolButton toolbutton.h nanogui/toolbutton.h 21 | * 22 | * \brief Simple radio+toggle button with an icon. 23 | */ 24 | class ToolButton : public Button { 25 | public: 26 | ToolButton(Widget *parent, int icon, 27 | std::string_view caption = "") 28 | : Button(parent, caption, icon) { 29 | set_flags(Flags::RadioButton | Flags::ToggleButton); 30 | set_fixed_size(Vector2i(25, 25)); 31 | } 32 | }; 33 | 34 | NAMESPACE_END(nanogui) 35 | -------------------------------------------------------------------------------- /include/nanogui/progressbar.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/progressbar.h -- Standard widget for visualizing progress 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class ProgressBar progressbar.h nanogui/progressbar.h 21 | * 22 | * \brief Standard widget for visualizing progress. 23 | */ 24 | class NANOGUI_EXPORT ProgressBar : public Widget { 25 | public: 26 | ProgressBar(Widget *parent); 27 | 28 | float value() { return m_value; } 29 | void set_value(float value) { m_value = value; } 30 | 31 | virtual void draw(NVGcontext* ctx) override; 32 | protected: 33 | virtual Vector2i preferred_size_impl(NVGcontext *ctx) const override; 34 | float m_value; 35 | }; 36 | 37 | NAMESPACE_END(nanogui) 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *\.exe 2 | *\.lib 3 | *\.cmake 4 | *\.pyi 5 | py\.typed 6 | .DS_Store 7 | ext_build 8 | nanogui_resources.* 9 | build 10 | CMakeCache.txt 11 | CMakeFiles 12 | \.ninja_deps 13 | \.ninja_log 14 | install_manifest\.txt 15 | build.ninja 16 | rules.ninja 17 | Makefile 18 | bin2c 19 | example[1-9] 20 | example[1-9].bc 21 | example[1-9].wasm 22 | example[1-9].js 23 | example[1-9].exe 24 | example_icons 25 | example_icons.bc 26 | example_icons.js 27 | example_icons.wasm 28 | example_icons.exe 29 | example_hdr 30 | example_hdr.bc 31 | example_hdr.js 32 | example_hdr.wasm 33 | example_hdr.exe 34 | icons 35 | *~ 36 | nanogui*.so 37 | nanogui*.pyd 38 | libnanobind-static.a 39 | libnanogui.so 40 | libnanogui.a 41 | libnanogui.bc 42 | libnanogui.dylib 43 | *.metallib 44 | .vscode/ 45 | # html documentation specific 46 | *.pyc 47 | docs/_build 48 | docs/doxyoutput 49 | docs/api 50 | 51 | # entypo update generation 52 | # this is it's own repo: https://github.com/svenevs/nanogui-entypo 53 | # should not ever be needed again unless there are new 54 | # icons added :) 55 | resources/nanogui-entypo 56 | 57 | compile_commands.json 58 | \.clangd 59 | \.cache 60 | -------------------------------------------------------------------------------- /src/python/chroma.cpp: -------------------------------------------------------------------------------- 1 | #ifdef NANOGUI_PYTHON 2 | 3 | #include "python.h" 4 | #include 5 | #include 6 | 7 | using namespace nanogui::ituth273; 8 | 9 | void register_chroma(nb::module_ &m_) { 10 | auto m = m_.def_submodule("ituth273"); 11 | 12 | nb::enum_(m, "ColorPrimaries") 13 | .value("BT709", ColorPrimaries::BT709) 14 | .value("Unspecified", ColorPrimaries::Unspecified) 15 | .value("BT470M", ColorPrimaries::BT470M) 16 | .value("BT470BG", ColorPrimaries::BT470BG) 17 | .value("SMTPE170M", ColorPrimaries::SMPTE170M) 18 | .value("SMTP240M", ColorPrimaries::SMPTE240M) 19 | .value("Film", ColorPrimaries::Film) 20 | .value("BT2020", ColorPrimaries::BT2020) 21 | .value("SMTPE428", ColorPrimaries::SMPTE428) 22 | .value("SMTPE431", ColorPrimaries::SMPTE431) 23 | .value("SMTPE432", ColorPrimaries::SMPTE432) 24 | .value("Weird", ColorPrimaries::Weird); 25 | 26 | 27 | m.def("chroma_to_rec709_matrix", &chroma_to_rec709_matrix); 28 | m.def("chroma", &chroma); 29 | m.def("from_screen", &from_screen); 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/python/python.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_MSC_VER) 4 | # pragma warning (disable:5033) // 'register' is no longer a supported storage class 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #include 18 | #include "py_doc.h" 19 | 20 | #define D(...) DOC(nanogui, __VA_ARGS__ ) 21 | 22 | #define DECLARE_LAYOUT(Name) \ 23 | class Py##Name : public Name { \ 24 | public: \ 25 | NANOGUI_LAYOUT_OVERLOADS(Name); \ 26 | } 27 | 28 | #define DECLARE_WIDGET(Name) \ 29 | class Py##Name : public Name { \ 30 | public: \ 31 | NANOGUI_WIDGET_OVERLOADS(Name); \ 32 | } 33 | 34 | #define DECLARE_SCREEN(Name) \ 35 | class Py##Name : public Name { \ 36 | public: \ 37 | NANOGUI_WIDGET_OVERLOADS(Name); \ 38 | NANOGUI_SCREEN_OVERLOADS(Name); \ 39 | } 40 | 41 | using namespace nanogui; 42 | 43 | namespace nb = nanobind; 44 | using namespace nanobind::literals; 45 | 46 | extern int widget_tp_traverse(PyObject *, visitproc, void *); 47 | extern int widget_tp_clear(PyObject *); 48 | -------------------------------------------------------------------------------- /src/python/color.cpp: -------------------------------------------------------------------------------- 1 | #ifdef NANOGUI_PYTHON 2 | 3 | #include "python.h" 4 | 5 | void register_eigen(nb::module_ &m) { 6 | nb::class_(m, "Color", D(Color)) 7 | .def(nb::init(), D(Color, Color, 7)) 8 | .def(nb::init(), D(Color, Color, 5)) 9 | .def(nb::init(), D(Color, Color, 7)) 10 | .def(nb::init(), D(Color, Color, 5)) 11 | .def("contrasting_color", &Color::contrasting_color, 12 | D(Color, contrasting_color)) 13 | .def_prop_rw("r", [](const Color &c) { return c.r(); }, 14 | [](Color &c, float v) { c.r() = v; }, D(Color, r)) 15 | .def_prop_rw("g", [](const Color &c) { return c.g(); }, 16 | [](Color &c, float v) { c.g() = v; }, D(Color, g)) 17 | .def_prop_rw("b", [](const Color &c) { return c.b(); }, 18 | [](Color &c, float v) { c.b() = v; }, D(Color, b)) 19 | .def_prop_rw("w", [](const Color &c) { return c.w(); }, 20 | [](Color &c, float v) { c.w() = v; }, "Return a reference to the alpha channel.") 21 | .def("__repr__", [](const Color &c) { 22 | std::ostringstream oss; 23 | oss << c; 24 | return oss.str(); 25 | }); 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /src/python/quad.cpp: -------------------------------------------------------------------------------- 1 | #ifdef NANOGUI_PYTHON 2 | 3 | #include "python.h" 4 | #include 5 | 6 | void register_quad(nb::module_ &m) { 7 | nb::class_(m, "TexturedQuad", D(TexturedQuad)) 8 | .def(nb::init(), 9 | D(TexturedQuad, TexturedQuad), 10 | "render_pass"_a, 11 | "blend_mode"_a = Shader::BlendMode::None) 12 | .def("set_texture", &TexturedQuad::set_texture, 13 | D(TexturedQuad, set_texture), 14 | "texture"_a) 15 | .def("set_mvp", &TexturedQuad::set_mvp, 16 | D(TexturedQuad, set_mvp), 17 | "mvp"_a) 18 | .def("set_texture_linear", &TexturedQuad::set_texture_linear, 19 | D(TexturedQuad, set_texture_linear), 20 | "linear"_a) 21 | .def("texture_linear", &TexturedQuad::texture_linear, 22 | D(TexturedQuad, texture_linear)) 23 | .def("set_texture_exposure", &TexturedQuad::set_texture_exposure, 24 | D(TexturedQuad, set_texture_exposure), 25 | "exposure"_a) 26 | .def("texture_exposure", &TexturedQuad::texture_exposure, 27 | D(TexturedQuad, texture_exposure)) 28 | .def("draw", &TexturedQuad::draw, 29 | D(TexturedQuad, draw)); 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/shader_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | NAMESPACE_BEGIN(nanogui) 8 | 9 | enum BufferType { 10 | Unknown = 0, 11 | VertexBuffer, 12 | VertexTexture, 13 | VertexSampler, 14 | FragmentBuffer, 15 | FragmentTexture, 16 | FragmentSampler, 17 | UniformBuffer, 18 | IndexBuffer, 19 | }; 20 | 21 | struct Buffer { 22 | void *buffer = nullptr; 23 | BufferType type = Unknown; 24 | VariableType dtype = VariableType::Invalid; 25 | int index = 0; 26 | size_t ndim = 0; 27 | size_t shape[3] { 0, 0, 0 }; 28 | size_t size = 0; 29 | bool dirty = false; 30 | 31 | std::string to_string() const; 32 | }; 33 | 34 | 35 | struct Shader::Impl { 36 | RenderPass* render_pass; 37 | std::string name; 38 | tsl::robin_map, std::equal_to<>> buffers; 39 | Shader::BlendMode blend_mode; 40 | 41 | #if defined(NANOGUI_USE_OPENGL) || defined(NANOGUI_USE_GLES) 42 | uint32_t shader_handle = 0; 43 | # if defined(NANOGUI_USE_OPENGL) 44 | uint32_t vertex_array_handle = 0; 45 | bool uses_point_size = false; 46 | # endif 47 | #elif defined(NANOGUI_USE_METAL) 48 | void *pipeline_state; 49 | #endif 50 | }; 51 | 52 | NAMESPACE_END(nanogui) 53 | -------------------------------------------------------------------------------- /resources/bin2c.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15...3.28) 2 | 3 | # Create header for C file 4 | file(WRITE ${OUTPUT_C} "/* Autogenerated by bin2c */\n\n") 5 | file(APPEND ${OUTPUT_C} "#include \n\n") 6 | 7 | # Create header of H file 8 | file(WRITE ${OUTPUT_H} "/* Autogenerated by bin2c */\n\n") 9 | file(APPEND ${OUTPUT_H} "#pragma once\n") 10 | file(APPEND ${OUTPUT_H} "#include \n\n") 11 | 12 | string(REPLACE "," ";" INPUT_LIST ${INPUT_FILES}) 13 | 14 | 15 | # Iterate through binary files files 16 | foreach(bin ${INPUT_LIST}) 17 | # Get short filename 18 | string(REGEX MATCH "([^/]+)$" filename ${bin}) 19 | # Replace filename spaces & extension separator for C compatibility 20 | string(REGEX REPLACE "\\.| |-" "_" filename ${filename}) 21 | # Convert to lower case 22 | string(TOLOWER ${filename} filename) 23 | # Read hex data from file 24 | file(READ ${bin} filedata HEX) 25 | # Convert hex data for C compatibility 26 | string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," filedata "${filedata}") 27 | # Append data to c file 28 | file(APPEND ${OUTPUT_C} "extern const uint8_t ${filename}[] = {${filedata}0x00};\n\nuint32_t ${filename}_size = sizeof(${filename}) - 1;\n\n") 29 | # Append extern definitions to h file 30 | file(APPEND ${OUTPUT_H} "extern const uint8_t ${filename}[];\n\nextern uint32_t ${filename}_size;\n\n") 31 | endforeach() 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | dist: trusty 3 | sudo: false 4 | 5 | # Only build master branch, other branches will have a Pull Request build. 6 | branches: 7 | only: 8 | - master 9 | 10 | matrix: 11 | include: 12 | - os: linux 13 | compiler: gcc-4.8 14 | addons: 15 | apt: 16 | sources: 17 | - ubuntu-toolchain-r-test 18 | - deadsnakes 19 | - kubuntu-backports 20 | packages: 21 | - g++-4.8 22 | - python3.5 23 | - python3.5-dev 24 | - python3.5-venv 25 | - libglu1-mesa-dev 26 | - libxxf86vm-dev 27 | - libxrandr-dev 28 | - libxinerama-dev 29 | - libxcursor-dev 30 | - libxi-dev 31 | - libx11-dev 32 | - cmake 33 | script: 34 | - cmake --version 35 | - cmake -DNANOGUI_USE_GLAD=ON -DNANOGUI_PYTHON_VERSION=3.5 -DPYTHON_INCLUDE_DIRS:PATH=/usr/include/python3.5m -DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.5m.so -DCMAKE_CXX_COMPILER=g++-4.8 -DCMAKE_C_COMPILER=gcc-4.8 36 | - make -j 2 37 | - os: osx 38 | compiler: clang 39 | script: 40 | - cmake --version 41 | - cmake -DNANOGUI_PYTHON_VERSION=2.7 42 | - make -j 2 43 | - os: linux 44 | language: docs 45 | env: STYLE 46 | script: 47 | - resources/check-style.sh 48 | -------------------------------------------------------------------------------- /include/nanogui/nanogui.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/nanogui.h -- Pull in *everything* from NanoGUI 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | -------------------------------------------------------------------------------- /src/shader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "shader_impl.h" 3 | 4 | NAMESPACE_BEGIN(nanogui) 5 | 6 | std::string Buffer::to_string() const { 7 | std::string result = "Buffer[type="; 8 | switch (type) { 9 | case VertexBuffer: result += "vertex"; break; 10 | case FragmentBuffer: result += "fragment"; break; 11 | case UniformBuffer: result += "uniform"; break; 12 | case IndexBuffer: result += "index"; break; 13 | default: result += "unknown"; break; 14 | } 15 | result += ", dtype="; 16 | result += type_name(dtype); 17 | result += ", shape=["; 18 | for (size_t i = 0; i < ndim; ++i) { 19 | result += std::to_string(shape[i]); 20 | if (i + 1 < ndim) 21 | result += ", "; 22 | } 23 | result += "]]"; 24 | return result; 25 | } 26 | 27 | // Accessor methods 28 | RenderPass *Shader::render_pass() { return p->render_pass; } 29 | std::string_view Shader::name() const { return p->name; } 30 | Shader::BlendMode Shader::blend_mode() const { return p->blend_mode; } 31 | 32 | #if defined(NANOGUI_USE_OPENGL) || defined(NANOGUI_USE_GLES) 33 | uint32_t Shader::shader_handle() const { return p->shader_handle; } 34 | #elif defined(NANOGUI_USE_METAL) 35 | void *Shader::pipeline_state() const { return p->pipeline_state; } 36 | #endif 37 | 38 | #if defined(NANOGUI_USE_OPENGL) 39 | uint32_t Shader::vertex_array_handle() const { return p->vertex_array_handle; } 40 | #endif 41 | 42 | NAMESPACE_END(nanogui) 43 | -------------------------------------------------------------------------------- /src/opengl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | NAMESPACE_BEGIN(nanogui) 4 | 5 | #if !defined(GL_STACK_OVERFLOW) 6 | # define GL_STACK_OVERFLOW 0x0503 7 | #endif 8 | 9 | #if !defined(GL_STACK_UNDERFLOW) 10 | # define GL_STACK_UNDERFLOW 0x0504 11 | #endif 12 | 13 | bool nanogui_check_glerror(const char *cmd) { 14 | GLenum err = glGetError(); 15 | const char *msg = nullptr; 16 | 17 | switch (err) { 18 | case GL_NO_ERROR: 19 | // printf("OK: %s\n", cmd); 20 | return false; 21 | 22 | case GL_INVALID_ENUM: 23 | msg = "invalid enumeration"; 24 | break; 25 | 26 | case GL_INVALID_VALUE: 27 | msg = "invalid value"; 28 | break; 29 | 30 | case GL_INVALID_OPERATION: 31 | msg = "invalid operation"; 32 | break; 33 | 34 | case GL_INVALID_FRAMEBUFFER_OPERATION: 35 | msg = "invalid framebuffer operation"; 36 | break; 37 | 38 | case GL_OUT_OF_MEMORY: 39 | msg = "out of memory"; 40 | break; 41 | 42 | case GL_STACK_UNDERFLOW: 43 | msg = "stack underflow"; 44 | break; 45 | 46 | case GL_STACK_OVERFLOW: 47 | msg = "stack overflow"; 48 | break; 49 | 50 | default: 51 | msg = "unknown error"; 52 | break; 53 | } 54 | 55 | fprintf(stderr, "OpenGL error (%s) during operation \"%s\"!\n", msg, cmd); 56 | return true; 57 | } 58 | 59 | NAMESPACE_END(nanogui) 60 | -------------------------------------------------------------------------------- /include/nanogui/ema.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | NAMESPACE_BEGIN(nanogui) 7 | 8 | /// Exponentially weighted moving average accumulator with bias correction 9 | template class EMA { 10 | public: 11 | /// Construct with given weight for old samples 12 | /// The default weight (0.983) results in a ~1 second time constant at 60 FPS 13 | EMA(Value weight = 0.983f) 14 | : m_weights{weight, 1.f-weight}, m_value(0.f), 15 | m_sample_count(0) { 16 | if (weight < 0.f || weight >= 1.f) 17 | throw std::invalid_argument("Weight must be in range [0, 1)"); 18 | } 19 | 20 | /// Reset the accumulator to initial state 21 | void reset() { m_value = 0.f; m_sample_count = 0; } 22 | 23 | /// Add a new sample to the accumulator 24 | void put(Value sample) { 25 | m_value = std::fma(m_weights[0], m_value, sample * m_weights[1]); 26 | m_sample_count++; 27 | } 28 | 29 | /// Get the bias-corrected accumulated value 30 | Value value() const { 31 | if (m_sample_count == 0) 32 | return 0.f; 33 | return m_value / (1.f - std::pow(m_weights[0], m_sample_count)); 34 | } 35 | 36 | /// Get the current weight 37 | Value weight() const { return m_weights[0]; } 38 | 39 | /// Get the number of samples accumulated 40 | size_t sample_count() const { return m_sample_count; } 41 | 42 | private: 43 | Value m_weights[2]; 44 | Value m_value; 45 | size_t m_sample_count; 46 | }; 47 | 48 | NAMESPACE_END(nanogui) 49 | -------------------------------------------------------------------------------- /src/python/textarea.cpp: -------------------------------------------------------------------------------- 1 | #ifdef NANOGUI_PYTHON 2 | 3 | #include "python.h" 4 | 5 | DECLARE_WIDGET(TextArea); 6 | 7 | void register_textarea(nb::module_ &m) { 8 | nb::class_(m, "TextArea", D(TextArea)) 9 | .def(nb::init(), D(TextArea, TextArea)) 10 | .def("set_font", &TextArea::set_font, D(TextArea, set_font)) 11 | .def("font", &TextArea::font, D(TextArea, font)) 12 | .def("set_foreground_color", &TextArea::set_foreground_color, D(TextArea, set_foreground_color)) 13 | .def("foreground_color", &TextArea::foreground_color, D(TextArea, foreground_color)) 14 | .def("set_background_color", &TextArea::set_background_color, D(TextArea, set_background_color)) 15 | .def("background_color", &TextArea::background_color, D(TextArea, background_color)) 16 | .def("set_selection_color", &TextArea::set_selection_color, D(TextArea, set_selection_color)) 17 | .def("selection_color", &TextArea::selection_color, D(TextArea, selection_color)) 18 | .def("set_padding", &TextArea::set_padding, D(TextArea, set_padding)) 19 | .def("padding", &TextArea::padding, D(TextArea, padding)) 20 | .def("set_selectable", &TextArea::set_selectable, D(TextArea, set_selectable)) 21 | .def("is_selectable", &TextArea::is_selectable, D(TextArea, is_selectable)) 22 | .def("append", &TextArea::append, D(TextArea, append)) 23 | .def("append_line", &TextArea::append_line, D(TextArea, append_line)) 24 | .def("clear", &TextArea::clear, D(TextArea, clear)); 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/progressbar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/progressbar.cpp -- Standard widget for visualizing progress 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | NAMESPACE_BEGIN(nanogui) 16 | 17 | ProgressBar::ProgressBar(Widget *parent) 18 | : Widget(parent), m_value(0.0f) {} 19 | 20 | Vector2i ProgressBar::preferred_size_impl(NVGcontext *) const { 21 | return Vector2i(70, 12); 22 | } 23 | 24 | void ProgressBar::draw(NVGcontext* ctx) { 25 | Widget::draw(ctx); 26 | 27 | NVGpaint paint = nvgBoxGradient( 28 | ctx, m_pos.x() + 1, m_pos.y() + 1, 29 | m_size.x()-2, m_size.y(), 3, 4, Color(0, 32), Color(0, 92)); 30 | nvgBeginPath(ctx); 31 | nvgRoundedRect(ctx, m_pos.x(), m_pos.y(), m_size.x(), m_size.y(), 3); 32 | nvgFillPaint(ctx, paint); 33 | nvgFill(ctx); 34 | 35 | float value = std::min(std::max(0.0f, m_value), 1.0f); 36 | int bar_pos = (int) std::round((m_size.x() - 2) * value); 37 | 38 | paint = nvgBoxGradient( 39 | ctx, m_pos.x(), m_pos.y(), 40 | bar_pos+1.5f, m_size.y()-1, 3, 4, 41 | Color(220, 100), Color(128, 100)); 42 | 43 | nvgBeginPath(ctx); 44 | nvgRoundedRect( 45 | ctx, m_pos.x()+1, m_pos.y()+1, 46 | bar_pos, m_size.y()-2, 3); 47 | nvgFillPaint(ctx, paint); 48 | nvgFill(ctx); 49 | } 50 | 51 | NAMESPACE_END(nanogui) 52 | -------------------------------------------------------------------------------- /src/traits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | NAMESPACE_BEGIN(nanogui) 5 | 6 | size_t type_size(VariableType type) { 7 | switch (type) { 8 | case VariableType::UInt8: 9 | case VariableType::Int8: 10 | case VariableType::Bool: 11 | return 1; 12 | 13 | case VariableType::UInt16: 14 | case VariableType::Int16: 15 | case VariableType::Float16: 16 | return 2; 17 | 18 | case VariableType::UInt32: 19 | case VariableType::Int32: 20 | case VariableType::Float32: 21 | return 4; 22 | 23 | case VariableType::UInt64: 24 | case VariableType::Int64: 25 | case VariableType::Float64: 26 | return 8; 27 | 28 | default: 29 | throw std::runtime_error("Unknown type!"); 30 | } 31 | } 32 | 33 | const char *type_name(VariableType type) { 34 | switch (type) { 35 | case VariableType::Bool: return "bool"; 36 | case VariableType::UInt8: return "uint8"; 37 | case VariableType::Int8: return "int8"; 38 | case VariableType::UInt16: return "uint16"; 39 | case VariableType::Int16: return "int16"; 40 | case VariableType::UInt32: return "uint32"; 41 | case VariableType::Int32: return "int32"; 42 | case VariableType::UInt64: return "uint64"; 43 | case VariableType::Int64: return "int64"; 44 | case VariableType::Float16: return "float16"; 45 | case VariableType::Float32: return "float32"; 46 | case VariableType::Float64: return "float64"; 47 | default: return "invalid"; 48 | } 49 | } 50 | 51 | NAMESPACE_END(nanogui) 52 | -------------------------------------------------------------------------------- /include/nanogui/messagedialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/messagedialog.h -- Simple "OK" or "Yes/No"-style modal dialogs 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class MessageDialog messagedialog.h nanogui/messagedialog.h 21 | * 22 | * \brief Simple "OK" or "Yes/No"-style modal dialogs. 23 | */ 24 | class NANOGUI_EXPORT MessageDialog : public Window { 25 | public: 26 | /// Classification of the type of message this MessageDialog represents. 27 | enum class Type { 28 | Information, 29 | Question, 30 | Warning 31 | }; 32 | 33 | MessageDialog(Widget *parent, Type type, std::string_view title = "Untitled", 34 | std::string_view message = "Message", 35 | std::string_view button_text = "OK", 36 | std::string_view alt_button_text = "Cancel", bool alt_button = false); 37 | 38 | Label *message_label() { return m_message_label; } 39 | const Label *message_label() const { return m_message_label; } 40 | 41 | const std::function &callback() const { return m_callback; } 42 | void set_callback(const std::function &callback) { m_callback = callback; } 43 | protected: 44 | std::function m_callback; 45 | Label *m_message_label; 46 | }; 47 | 48 | NAMESPACE_END(nanogui) 49 | -------------------------------------------------------------------------------- /include/nanogui/popupbutton.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/popupbutton.h -- Button which launches a popup widget 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | NAMESPACE_BEGIN(nanogui) 19 | 20 | /** 21 | * \class PopupButton popupbutton.h nanogui/popupbutton.h 22 | * 23 | * \brief Button which launches a popup widget. 24 | * 25 | * \remark 26 | * This class overrides \ref nanogui::Widget::mIconExtraScale to be ``0.8f``, 27 | * which affects all subclasses of this Widget. Subclasses must explicitly 28 | * set a different value if needed (e.g., in their constructor). 29 | */ 30 | class NANOGUI_EXPORT PopupButton : public Button { 31 | public: 32 | PopupButton(Widget *parent, std::string_view caption = "Untitled", 33 | int button_icon = 0); 34 | 35 | void set_chevron_icon(int icon) { m_chevron_icon = icon; } 36 | int chevron_icon() const { return m_chevron_icon; } 37 | 38 | void set_side(Popup::Side popup_side); 39 | Popup::Side side() const { return m_popup->side(); } 40 | 41 | Popup *popup() { return m_popup; } 42 | const Popup *popup() const { return m_popup; } 43 | 44 | virtual void draw(NVGcontext* ctx) override; 45 | virtual void perform_layout(NVGcontext *ctx) override; 46 | protected: 47 | Popup *m_popup; 48 | int m_chevron_icon; 49 | }; 50 | 51 | NAMESPACE_END(nanogui) 52 | -------------------------------------------------------------------------------- /include/nanogui/chroma.h: -------------------------------------------------------------------------------- 1 | /* 2 | NanoGUI was developed by Wenzel Jakob . 3 | The widget drawing code is based on the NanoVG demo application 4 | by Mikko Mononen. 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE.txt file. 8 | */ 9 | /** 10 | * \file nanogui/chroma.h 11 | * 12 | * \brief Color space conversion utilities. 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | #include 20 | 21 | NAMESPACE_BEGIN(nanogui) 22 | 23 | extern NANOGUI_EXPORT Matrix3f chroma_to_rec709_matrix(const std::array& chroma); 24 | 25 | extern NANOGUI_EXPORT std::array chroma_from_wp_primaries(int wp_primaries); 26 | extern NANOGUI_EXPORT std::string_view wp_primaries_to_string(int wp_primaties); 27 | 28 | // Partial implementation of https://www.itu.int/rec/T-REC-H.273-202407-I/en 29 | NAMESPACE_BEGIN(ituth273) 30 | 31 | enum class ColorPrimaries : uint8_t { 32 | BT709 = 1, 33 | Unspecified = 2, 34 | BT470M = 4, 35 | BT470BG = 5, 36 | SMPTE170M = 6, 37 | SMPTE240M = 7, 38 | Film = 8, 39 | BT2020 = 9, // Same as BT2100 40 | SMPTE428 = 10, 41 | SMPTE431 = 11, 42 | SMPTE432 = 12, 43 | Weird = 22, // The spec says "No corresponding industry specification identified" 44 | }; 45 | 46 | extern NANOGUI_EXPORT std::string_view to_string(const ColorPrimaries primaries); 47 | extern NANOGUI_EXPORT std::array chroma(const ColorPrimaries primaries); 48 | 49 | extern NANOGUI_EXPORT ColorPrimaries from_wp_primaries(int wp_primaries); 50 | 51 | extern NANOGUI_EXPORT ColorPrimaries from_screen(const Screen *screen); 52 | 53 | NAMESPACE_END(ituth273) 54 | 55 | NAMESPACE_END(nanogui) 56 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | build: 12 | name: ${{ matrix.build-type }} on ${{ matrix.os }} 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest, windows-latest, macos-latest] 17 | build-type: [shared, static] 18 | fail-fast: false 19 | 20 | env: 21 | BUILD_SHARED: ${{ matrix.build-type == 'shared' && 'ON' || 'OFF' }} 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | with: 26 | submodules: recursive 27 | 28 | - name: Update CMake 29 | uses: jwlawson/actions-setup-cmake@v2 30 | 31 | - uses: actions/setup-python@v5 32 | name: Install Python 33 | with: 34 | python-version: '3.12' 35 | 36 | - name: Install dependencies on Linux 37 | if: runner.os == 'Linux' 38 | run: | 39 | sudo apt-get update 40 | sudo apt-get install -y xorg-dev libglu1-mesa-dev libwayland-dev libxkbcommon-dev libdbus-1-dev 41 | 42 | - name: Configure (Windows) 43 | if: runner.os == 'Windows' 44 | run: | 45 | cmake -S . -B build -G "Visual Studio 17 2022" ` 46 | -DNANOGUI_BUILD_SHARED=${{ env.BUILD_SHARED }} ` 47 | "-DPython_EXECUTABLE=$(python -c 'import sys; print(sys.executable)')" 48 | 49 | - name: Configure (Linux/macOS) 50 | if: runner.os == 'Linux' || runner.os == 'macOS' 51 | run: | 52 | cmake -S . -B build \ 53 | -DNANOGUI_BUILD_SHARED=${{ env.BUILD_SHARED }} \ 54 | "-DPython_EXECUTABLE=$(python3 -c 'import sys; print(sys.executable)')" 55 | 56 | - name: Build C++ 57 | run: cmake --build build -j 2 --config Release -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | NanoGUI 2 | ======================================================================================== 3 | 4 | .. include:: ../README.rst 5 | :start-after: begin_brief_description 6 | :end-before: end_brief_description 7 | 8 | Example Screenshot 9 | ---------------------------------------------------------------------------------------- 10 | 11 | .. image:: ../resources/screenshot.png 12 | :alt: Screenshot of Example 1. 13 | :align: center 14 | 15 | Description 16 | ---------------------------------------------------------------------------------------- 17 | 18 | .. include:: ../README.rst 19 | :start-after: begin_long_description 20 | :end-before: end_long_description 21 | 22 | "Simple mode" 23 | ---------------------------------------------------------------------------------------- 24 | 25 | Christian Schüller contributed a convenience class that makes it possible to create 26 | AntTweakBar-style variable manipulators using just a few lines of code. Refer to 27 | :ref:`nanogui_example_2` for how to create the image below. 28 | 29 | .. image:: ../resources/screenshot2.png 30 | :alt: Screenshot of Example 2. 31 | :align: center 32 | 33 | License 34 | ---------------------------------------------------------------------------------------- 35 | 36 | .. include:: ../README.rst 37 | :start-after: begin_license 38 | :end-before: end_license 39 | 40 | .. note:: 41 | 42 | The CC BY-SA 4.0 license should not be an issue for most projects. However, you can 43 | adopt a different font for icons if you need. See :ref:`nanogui_including_custom_fonts`. 44 | 45 | Contents 46 | ======================================================================================== 47 | 48 | .. toctree:: 49 | :maxdepth: 2 50 | 51 | usage 52 | compilation 53 | examples 54 | api/library_root 55 | contributing 56 | 57 | 58 | Indices and tables 59 | ================== 60 | 61 | * :ref:`genindex` 62 | * :ref:`modindex` 63 | * :ref:`search` 64 | -------------------------------------------------------------------------------- /include/nanogui/imagepanel.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/imagepanel.h -- Image panel widget which shows a number of 3 | square-shaped icons 4 | 5 | NanoGUI was developed by Wenzel Jakob . 6 | The widget drawing code is based on the NanoVG demo application 7 | by Mikko Mononen. 8 | 9 | All rights reserved. Use of this source code is governed by a 10 | BSD-style license that can be found in the LICENSE.txt file. 11 | */ 12 | /** \file */ 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | NAMESPACE_BEGIN(nanogui) 19 | 20 | /** 21 | * \class ImagePanel imagepanel.h nanogui/imagepanel.h 22 | * 23 | * \brief Image panel widget which shows a number of square-shaped icons. 24 | */ 25 | class NANOGUI_EXPORT ImagePanel : public Widget { 26 | public: 27 | typedef std::vector> Images; 28 | public: 29 | ImagePanel(Widget *parent); 30 | 31 | void set_images(const Images &data) { m_images = data; preferred_size_changed(); } 32 | const Images& images() const { return m_images; } 33 | 34 | const std::function &callback() const { return m_callback; } 35 | void set_callback(const std::function &callback) { m_callback = callback; } 36 | 37 | virtual bool mouse_motion_event(const Vector2i &p, const Vector2i &rel, int button, 38 | int modifiers) override; 39 | virtual bool mouse_button_event(const Vector2i &p, int button, bool down, 40 | int modifiers) override; 41 | virtual void draw(NVGcontext *ctx) override; 42 | 43 | protected: 44 | virtual Vector2i preferred_size_impl(NVGcontext *ctx) const override; 45 | Vector2i grid_size() const; 46 | int index_for_position(const Vector2i &p) const; 47 | protected: 48 | Images m_images; 49 | std::function m_callback; 50 | int m_thumb_size; 51 | int m_spacing; 52 | int m_margin; 53 | int m_mouse_index; 54 | }; 55 | 56 | NAMESPACE_END(nanogui) 57 | -------------------------------------------------------------------------------- /src/rtimer.cpp: -------------------------------------------------------------------------------- 1 | #include "rtimer.h" 2 | 3 | NAMESPACE_BEGIN(nanogui) 4 | 5 | RestartableTimer::RestartableTimer(Callback callback, std::chrono::milliseconds delay) : 6 | m_callback(std::move(callback)), 7 | m_delay(delay), 8 | m_should_exit(false), 9 | m_timer_active(false) { 10 | m_worker = std::thread(&RestartableTimer::run, this); 11 | } 12 | 13 | RestartableTimer::~RestartableTimer() { 14 | { 15 | std::lock_guard lock(m_mutex); 16 | m_should_exit = true; 17 | m_timer_active = false; 18 | m_cv.notify_one(); 19 | } 20 | m_worker.join(); 21 | } 22 | 23 | void RestartableTimer::restart() { 24 | std::lock_guard lock(m_mutex); 25 | m_deadline = std::chrono::steady_clock::now() + m_delay; 26 | 27 | if (!m_timer_active) { 28 | m_timer_active = true; 29 | m_cv.notify_one(); 30 | } 31 | } 32 | 33 | void RestartableTimer::clear() { 34 | std::lock_guard lock(m_mutex); 35 | m_timer_active = false; 36 | } 37 | 38 | void RestartableTimer::run() { 39 | std::unique_lock lock(m_mutex); 40 | 41 | while (!m_should_exit) { 42 | // Wait for timer activation 43 | if (!m_timer_active) 44 | m_cv.wait(lock); 45 | 46 | if (m_should_exit) 47 | break; 48 | 49 | while (m_timer_active) { 50 | m_cv.wait_until(lock, m_deadline); 51 | 52 | // Check if we should exit or timer was cleared 53 | if (m_should_exit || !m_timer_active) 54 | break; 55 | 56 | // Check if we've actually reached the deadline (it may have been extended) 57 | if (std::chrono::steady_clock::now() >= m_deadline) { 58 | m_timer_active = false; 59 | lock.unlock(); 60 | m_callback(); 61 | lock.lock(); 62 | break; 63 | } 64 | // Otherwise the deadline was extended, loop back to wait until new deadline 65 | } 66 | } 67 | } 68 | 69 | NAMESPACE_END(nanogui) 70 | -------------------------------------------------------------------------------- /.github/workflows/wheels.yml: -------------------------------------------------------------------------------- 1 | name: Build Python wheels 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | upload: 7 | description: 'Upload wheels to PyPI? (0: no, 1: yes)' 8 | required: true 9 | default: '0' 10 | 11 | jobs: 12 | build_wheels: 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest, windows-latest, macos-13, macos-14] 16 | fail-fast: false 17 | 18 | name: Build wheels on ${{ matrix.os }} 19 | runs-on: ${{ matrix.os }} 20 | 21 | env: 22 | CIBW_ARCHS_MACOS: ${{ matrix.os == 'macos-14' && 'arm64' || matrix.os == 'macos-13' && 'x86_64' || '' }} 23 | 24 | steps: 25 | # Checkout with retry mechanism for reliability 26 | - uses: Wandalen/wretry.action@v3.8.0 27 | with: 28 | action: actions/checkout@v4 29 | with: | 30 | submodules: recursive 31 | attempt_limit: 3 32 | attempt_delay: 2000 33 | 34 | - uses: actions/setup-python@v5 35 | name: Install Python 36 | with: 37 | python-version: '3.11' 38 | 39 | - name: Prepare compiler environment for Windows 40 | if: runner.os == 'Windows' 41 | uses: ilammy/msvc-dev-cmd@v1 42 | with: 43 | arch: x64 44 | 45 | - name: Install cibuildwheel 46 | run: | 47 | python -m pip install cibuildwheel==2.20.0 48 | 49 | - name: Build wheels 50 | run: | 51 | python -m cibuildwheel --output-dir wheelhouse 52 | 53 | - uses: actions/upload-artifact@v4 54 | with: 55 | name: wheels-${{ matrix.os }} 56 | path: ./wheelhouse/*.whl 57 | 58 | upload_pypi: 59 | name: Upload wheels to PyPI 60 | runs-on: ubuntu-latest 61 | if: ${{ github.event.inputs.upload == '1'}} 62 | needs: [build_wheels] 63 | 64 | steps: 65 | - uses: actions/download-artifact@v4 66 | with: 67 | pattern: wheels-* 68 | merge-multiple: true 69 | path: dist 70 | 71 | - uses: pypa/gh-action-pypi-publish@release/v1 72 | with: 73 | user: __token__ 74 | password: ${{ secrets.PYPI_PASSWORD }} 75 | -------------------------------------------------------------------------------- /src/rtimer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | NAMESPACE_BEGIN(nanogui) 11 | 12 | /** 13 | * A thread-safe timer that executes a callback after a fixed delay. 14 | * 15 | * The timer can be restarted at any time: calling restart() while the timer 16 | * is already running cancels the pending callback and starts a new countdown. 17 | * Only the final callback executes after the delay period expires without 18 | * further restarts. 19 | * 20 | * The callback is executed asynchronously on a dedicated worker thread. 21 | * All public methods are thread-safe and can be called from any thread. 22 | */ 23 | class RestartableTimer : public Object { 24 | public: 25 | using Callback = std::function; 26 | 27 | /** 28 | * Constructs a timer with a callback and fixed delay. 29 | * 30 | * \param callback Function to call when the timer expires 31 | * \param delay Time to wait before executing the callback 32 | */ 33 | RestartableTimer(Callback callback, std::chrono::milliseconds delay); 34 | 35 | /// Destructor. Stops the timer and waits for the worker thread to finish. 36 | ~RestartableTimer(); 37 | 38 | /** 39 | * Starts or restarts the timer countdown. 40 | * If the timer is already running, cancels the pending callback and starts 41 | * a new countdown from the current time. 42 | */ 43 | void restart(); 44 | 45 | /** 46 | * Cancels any pending callback execution. 47 | * If the timer is running, it will be stopped without executing the callback. 48 | */ 49 | void clear(); 50 | 51 | private: 52 | /** 53 | * Worker thread main loop. 54 | * Waits for timer activation and executes callbacks after the specified delay. 55 | */ 56 | void run(); 57 | 58 | std::mutex m_mutex; 59 | std::condition_variable m_cv; 60 | std::thread m_worker; 61 | const Callback m_callback; 62 | const std::chrono::milliseconds m_delay; 63 | std::chrono::steady_clock::time_point m_deadline; 64 | bool m_should_exit; 65 | bool m_timer_active; 66 | }; 67 | NAMESPACE_END(nanogui) 68 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Wenzel Jakob , All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | You are under no obligation whatsoever to provide any bug fixes, patches, or 29 | upgrades to the features, functionality or performance of the source code 30 | ("Enhancements") to anyone; however, if you choose to make your Enhancements 31 | available either publicly, or directly to the author of this software, without 32 | imposing a separate written license agreement for such Enhancements, then you 33 | hereby grant the following license: a non-exclusive, royalty-free perpetual 34 | license to install, use, modify, prepare derivative works, incorporate into 35 | other computer software, distribute, and sublicense such enhancements or 36 | derivative works thereof, in binary and source code form. 37 | -------------------------------------------------------------------------------- /include/nanogui/vscrollpanel.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/vscrollpanel.h -- Adds a vertical scrollbar around a widget 3 | that is too big to fit into a certain area 4 | 5 | NanoGUI was developed by Wenzel Jakob . 6 | The widget drawing code is based on the NanoVG demo application 7 | by Mikko Mononen. 8 | 9 | All rights reserved. Use of this source code is governed by a 10 | BSD-style license that can be found in the LICENSE.txt file. 11 | */ 12 | /** \file */ 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | NAMESPACE_BEGIN(nanogui) 19 | 20 | /** 21 | * \class VScrollPanel vscrollpanel.h nanogui/vscrollpanel.h 22 | * 23 | * \brief Adds a vertical scrollbar around a widget that is too big to fit into 24 | * a certain area. 25 | */ 26 | class NANOGUI_EXPORT VScrollPanel : public Widget { 27 | public: 28 | VScrollPanel(Widget *parent); 29 | 30 | /** 31 | * Return the current scroll amount as a value between 0 and 1. 0 means 32 | * scrolled to the top and 1 to the bottom. 33 | */ 34 | float scroll() const { return m_scroll; } 35 | 36 | /** 37 | * Set the scroll amount to a value between 0 and 1. 0 means scrolled to 38 | * the top and 1 to the bottom. 39 | */ 40 | void set_scroll(float scroll) { m_scroll = scroll; } 41 | 42 | /// Scroll to an absolute pixel position 43 | void scroll_absolute(float scroll) { 44 | float target = scroll / std::max(m_child_preferred_height + 8.0f - m_size.y(), 1.f); 45 | m_scroll = clip(m_scroll + target, 0.f, 1.f); 46 | } 47 | 48 | virtual void perform_layout(NVGcontext *ctx) override; 49 | virtual bool mouse_button_event(const Vector2i &p, int button, bool down, 50 | int modifiers) override; 51 | virtual bool mouse_drag_event(const Vector2i &p, const Vector2i &rel, 52 | int button, int modifiers) override; 53 | virtual bool scroll_event(const Vector2i &p, const Vector2f &rel) override; 54 | virtual void draw(NVGcontext *ctx) override; 55 | 56 | protected: 57 | virtual Vector2i preferred_size_impl(NVGcontext *ctx) const override; 58 | int m_child_preferred_height; 59 | float m_scroll; 60 | bool m_update_layout; 61 | }; 62 | 63 | NAMESPACE_END(nanogui) 64 | -------------------------------------------------------------------------------- /src/python/example_icons.py: -------------------------------------------------------------------------------- 1 | # python/example_icons.py -- Python version of an example application that shows 2 | # all available Entypo icons as they would appear in NanoGUI itself. For a C++ 3 | # implementation, see '../src/example_icons.cpp'. 4 | # 5 | # NanoGUI was developed by Wenzel Jakob . 6 | # The widget drawing code is based on the NanoVG demo application 7 | # by Mikko Mononen. 8 | # 9 | # All rights reserved. Use of this source code is governed by a 10 | # BSD-style license that can be found in the LICENSE.txt file. 11 | 12 | # Developer note: need to make a change to this file? 13 | # Please raise an Issue on GitHub describing what needs to change. This file 14 | # was generated, so the scripts that generated it needs to update as well. 15 | 16 | import gc 17 | 18 | import nanogui 19 | from nanogui import Screen, Window, Widget, GridLayout, VScrollPanel, Button 20 | from nanogui import icons 21 | import nanogui as ng 22 | 23 | def run(): 24 | ng.init() 25 | 26 | width = 1000 27 | half_width = width // 2 28 | height = 800 29 | 30 | # create a fixed size screen with one window 31 | screen = ng.Screen((width, height), "NanoGUI Icons", False) 32 | window = ng.Window(screen, "All Icons") 33 | window.set_position((0, 0)) 34 | window.set_fixed_size((width, height)) 35 | 36 | # attach a vertical scroll panel 37 | vscroll = ng.VScrollPanel(window) 38 | vscroll.set_fixed_size((width, height)) 39 | 40 | # vscroll should only have *ONE* child. this is what `wrapper` is for 41 | wrapper = ng.Widget(vscroll) 42 | wrapper.set_fixed_size((width, height)) 43 | wrapper.set_layout(GridLayout()) # defaults: 2 columns 44 | 45 | # NOTE: don't __dict__ crawl in real code! 46 | # this is just because it's more convenient to do this for enumerating all 47 | # of the icons -- see cpp example for alternative... 48 | for key in icons.__dict__.keys(): 49 | if key.startswith("FA_"): 50 | b = ng.Button(wrapper, "icons.{0}".format(key), icons.__dict__[key]) 51 | b.set_icon_position(Button.IconPosition.Left) 52 | b.set_fixed_width(half_width) 53 | 54 | screen.perform_layout() 55 | screen.draw_all() 56 | screen.set_visible(True) 57 | 58 | ng.run() 59 | ng.shutdown() 60 | 61 | if __name__ == "__main__": 62 | run() 63 | -------------------------------------------------------------------------------- /src/messagedialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/messagedialog.cpp -- Simple "OK" or "Yes/No"-style modal dialogs 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | MessageDialog::MessageDialog(Widget *parent, Type type, std::string_view title, 20 | std::string_view message, 21 | std::string_view button_text, 22 | std::string_view alt_button_text, bool alt_button) : Window(parent, title) { 23 | set_layout(new BoxLayout(Orientation::Vertical, 24 | Alignment::Middle, 10, 10)); 25 | set_modal(true); 26 | 27 | Widget *panel1 = new Widget(this); 28 | panel1->set_layout(new BoxLayout(Orientation::Horizontal, 29 | Alignment::Middle, 10, 15)); 30 | int icon = 0; 31 | switch (type) { 32 | case Type::Information: icon = m_theme->m_message_information_icon; break; 33 | case Type::Question: icon = m_theme->m_message_question_icon; break; 34 | case Type::Warning: icon = m_theme->m_message_warning_icon; break; 35 | } 36 | Label *icon_label = new Label(panel1, std::string(utf8(icon).data()), "icons"); 37 | icon_label->set_font_size(50); 38 | m_message_label = new Label(panel1, message); 39 | m_message_label->set_fixed_width(200); 40 | Widget *panel2 = new Widget(this); 41 | panel2->set_layout(new BoxLayout(Orientation::Horizontal, 42 | Alignment::Middle, 0, 15)); 43 | 44 | if (alt_button) { 45 | Button *button = new Button(panel2, alt_button_text, m_theme->m_message_alt_button_icon); 46 | button->set_callback([&] { if (m_callback) m_callback(1); dispose(); }); 47 | } 48 | Button *button = new Button(panel2, button_text, m_theme->m_message_primary_button_icon); 49 | button->set_callback([&] { if (m_callback) m_callback(0); dispose(); }); 50 | center(); 51 | request_focus(); 52 | } 53 | 54 | NAMESPACE_END(nanogui) 55 | -------------------------------------------------------------------------------- /include/nanogui/label.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/label.h -- Text label with an arbitrary font, color, and size 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class Label label.h nanogui/label.h 21 | * 22 | * \brief Text label widget. 23 | * 24 | * The font and color can be customized. When \ref Widget::set_fixed_width() 25 | * is used, the text is wrapped when it surpasses the specified width. 26 | */ 27 | class NANOGUI_EXPORT Label : public Widget { 28 | public: 29 | Label(Widget *parent, std::string_view caption, 30 | std::string_view font = "sans", int font_size = -1); 31 | 32 | /// Get the label's text caption 33 | std::string_view caption() const { return m_caption; } 34 | /// Set the label's text caption 35 | void set_caption(std::string_view caption) { 36 | if (m_caption != caption) { 37 | m_caption = caption; 38 | preferred_size_changed(); 39 | } 40 | } 41 | 42 | /// Set the currently active font (2 are available by default: 'sans' and 'sans-bold') 43 | void set_font(std::string_view font) { 44 | if (m_font != font) { 45 | m_font = font; 46 | preferred_size_changed(); 47 | } 48 | } 49 | /// Get the currently active font 50 | std::string_view font() const { return m_font; } 51 | 52 | /// Get the label color 53 | Color color() const { return m_color; } 54 | /// Set the label color 55 | void set_color(const Color& color) { m_color = color; } 56 | 57 | /// Set the \ref Theme used to draw this widget 58 | virtual void set_theme(Theme *theme) override; 59 | 60 | protected: 61 | /// Compute the size needed to fully display the label 62 | virtual Vector2i preferred_size_impl(NVGcontext *ctx) const override; 63 | 64 | public: 65 | 66 | /// Draw the label 67 | virtual void draw(NVGcontext *ctx) override; 68 | protected: 69 | std::string m_caption; 70 | std::string m_font; 71 | Color m_color; 72 | }; 73 | 74 | NAMESPACE_END(nanogui) 75 | -------------------------------------------------------------------------------- /src/python/example2.py: -------------------------------------------------------------------------------- 1 | # python/example2.py -- Python version of an example application that shows 2 | # how to use the form helper class. For a C++ implementation, see 3 | # '../src/example2.cpp'. 4 | # 5 | # NanoGUI was developed by Wenzel Jakob . 6 | # The widget drawing code is based on the NanoVG demo application 7 | # by Mikko Mononen. 8 | # 9 | # All rights reserved. Use of this source code is governed by a 10 | # BSD-style license that can be found in the LICENSE.txt file. 11 | 12 | import nanogui 13 | import math 14 | import gc 15 | import nanogui as ng 16 | 17 | bvar = True 18 | ivar = 12345678 19 | dvar = math.pi 20 | strvar = 'A string' 21 | strvar2 = '' 22 | enumvar = 1 23 | colvar = nanogui.Color(.5, .5, .7, 1) 24 | 25 | 26 | def make_accessors(name): 27 | def setter(value): 28 | globals()[name] = value 29 | 30 | def getter(): 31 | return globals()[name] 32 | return setter, getter 33 | 34 | nanogui.init() 35 | 36 | use_gl_4_1 = False # Set to True to create an OpenGL 4.1 context. 37 | if use_gl_4_1: 38 | # NanoGUI presents many options for you to utilize at your discretion. 39 | # See include/nanogui/screen.h for what all of the options are. 40 | screen = ng.Screen((500, 700), 'NanoGUI test [GL 4.1]', gl_major=4, gl_minor=1) 41 | else: 42 | screen = ng.Screen((500, 700), 'NanoGUI test') 43 | 44 | gui = ng.FormHelper(screen) 45 | window = gui.add_window((10, 10), 'Form helper example') 46 | 47 | gui.add_group('Basic types') 48 | gui.add_bool_variable('bool', *make_accessors('bvar')) 49 | gui.add_string_variable('string', *make_accessors('strvar')) 50 | gui.add_string_variable('placeholder', *make_accessors('strvar2')).set_placeholder('placeholder') 51 | 52 | gui.add_group('Validating fields') 53 | gui.add_int_variable('int', *make_accessors('ivar')) 54 | gui.add_double_variable('double', *make_accessors('dvar')) 55 | 56 | gui.add_group('Complex types') 57 | gui.add_enum_variable('Enumeration', *make_accessors('enumvar')) \ 58 | .set_items(['Item 1', 'Item 2', 'Item 3']) 59 | gui.add_color_variable('Color', *make_accessors('colvar')) 60 | 61 | gui.add_group('Other widgets') 62 | 63 | 64 | def cb(): 65 | print('Button pressed.') 66 | gui.add_button('A button', cb) 67 | 68 | screen.set_visible(True) 69 | screen.perform_layout() 70 | window.center() 71 | 72 | ng.run(ng.RunMode.Lazy) 73 | screen = gui = window = None 74 | gc.collect() 75 | ng.shutdown() 76 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ======================================================================================== 3 | 4 | C++ 5 | ---------------------------------------------------------------------------------------- 6 | 7 | There are effectively two ways that you can use NanoGUI in C++: have NanoGUI initialize 8 | and manage the OpenGL context (and GLFW), or you do it manually. 9 | 10 | 1. If you are letting NanoGUI take over, you **must** call :ref:`function_nanogui__init` 11 | before trying to do anything else. If you are managing OpenGL / GLFW yourself, make 12 | sure you **avoid** calling this method. 13 | 14 | 2. Create an instance of :ref:`class_nanogui__Screen` (or a derivative class you have 15 | written). 16 | 17 | - NanoGUI managed OpenGL: call the explicit constructor. 18 | - Self managed OpenGL: call the empty constructor. 19 | - You must call the :func:`nanogui::Screen::initialize` method. 20 | 21 | 3. Add any Widgets, Buttons, etc. you want to the screen instance, and call the 22 | :func:`nanogui::Screen::setVisible` and :func:`nanogui::Screen::performLayout` 23 | methods of your instance. 24 | 25 | 4. Now that everything is ready, call :ref:`function_nanogui__mainloop`. 26 | 27 | 5. When all windows are closed, this function will exit, and you should follow it up 28 | with a call to :ref:`function_nanogui__shutdown`. 29 | 30 | :NanoGUI Managed OpenGL / GLFW: 31 | Refer to :ref:`nanogui_example_2` for a concise example of what that all looks like. 32 | 33 | :Self Managed OpenGL / GLFW: 34 | Refer to :ref:`nanogui_example_3` for an as concise as possible example of what you 35 | will need to do to get the :ref:`class_nanogui__Screen` to work. 36 | 37 | 38 | Python 39 | ---------------------------------------------------------------------------------------- 40 | 41 | The Python interface is very similar to the C++ API. When you build NanoGUI with CMake, 42 | a ``python`` folder is created with the library you ``import nanogui`` from. Though 43 | there are implementation details that differ greatly, the documentation and build 44 | process for the Python side is roughly the same. Refer to the 45 | :ref:`nanogui_example_programs` and compare the source code for the two. 46 | 47 | :ref:`nanogui_example_3` highlights the more notable differences between the APIs. 48 | Specifically, that managing GLFW from Python has no meaning, as well as the main loop 49 | for Python can easily be detached. 50 | -------------------------------------------------------------------------------- /include/nanogui/graph.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/graph.h -- Simple graph widget for showing a function plot 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class Graph graph.h nanogui/graph.h 21 | * 22 | * \brief Simple graph widget for showing a function plot. 23 | */ 24 | class NANOGUI_EXPORT Graph : public Widget { 25 | public: 26 | Graph(Widget *parent, std::string_view caption = "Untitled"); 27 | 28 | std::string_view caption() const { return m_caption; } 29 | void set_caption(std::string_view caption) { m_caption = caption; } 30 | 31 | std::string_view header() const { return m_header; } 32 | void set_header(std::string_view header) { m_header = header; } 33 | 34 | std::string_view footer() const { return m_footer; } 35 | void set_footer(std::string_view footer) { m_footer = footer; } 36 | 37 | const Color &background_color() const { return m_background_color; } 38 | void set_background_color(const Color &background_color) { m_background_color = background_color; } 39 | 40 | const Color &stroke_color() const { return m_stroke_color; } 41 | void set_stroke_color(const Color &stroke_color) { m_stroke_color = stroke_color; } 42 | 43 | const Color &fill_color() const { return m_fill_color; } 44 | void set_fill_color(const Color &fill_color) { m_fill_color = fill_color; } 45 | 46 | const Color &text_color() const { return m_text_color; } 47 | void set_text_color(const Color &text_color) { m_text_color = text_color; } 48 | 49 | const std::vector &values() const { return m_values; } 50 | std::vector &values() { return m_values; } 51 | void set_values(const std::vector &values) { m_values = values; } 52 | 53 | virtual void draw(NVGcontext *ctx) override; 54 | protected: 55 | virtual Vector2i preferred_size_impl(NVGcontext *ctx) const override; 56 | std::string m_caption, m_header, m_footer; 57 | Color m_background_color, m_fill_color, m_stroke_color, m_text_color; 58 | std::vector m_values; 59 | }; 60 | 61 | NAMESPACE_END(nanogui) 62 | -------------------------------------------------------------------------------- /include/nanogui/slider.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/slider.h -- Fractional slider widget with mouse control 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class Slider slider.h nanogui/slider.h 21 | * 22 | * \brief Fractional slider widget with mouse control. 23 | */ 24 | class NANOGUI_EXPORT Slider : public Widget { 25 | public: 26 | Slider(Widget *parent); 27 | 28 | float value() const { return m_value; } 29 | void set_value(float value) { m_value = value; } 30 | 31 | const Color &highlight_color() const { return m_highlight_color; } 32 | void set_highlight_color(const Color &highlight_color) { m_highlight_color = highlight_color; } 33 | 34 | std::pair range() const { return m_range; } 35 | void set_range(std::pair range) { m_range = range; } 36 | 37 | std::pair highlighted_range() const { return m_highlighted_range; } 38 | void set_highlighted_range(std::pair highlighted_range) { m_highlighted_range = highlighted_range; } 39 | 40 | const std::function &callback() const { return m_callback; } 41 | void set_callback(const std::function &callback) { m_callback = callback; } 42 | 43 | const std::function &final_callback() const { return m_final_callback; } 44 | void set_final_callback(const std::function &callback) { m_final_callback = callback; } 45 | 46 | protected: 47 | virtual Vector2i preferred_size_impl(NVGcontext *ctx) const override; 48 | 49 | public: 50 | virtual bool mouse_drag_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override; 51 | virtual bool mouse_button_event(const Vector2i &p, int button, bool down, int modifiers) override; 52 | virtual void draw(NVGcontext* ctx) override; 53 | 54 | protected: 55 | float m_value; 56 | std::function m_callback; 57 | std::function m_final_callback; 58 | std::pair m_range; 59 | std::pair m_highlighted_range; 60 | Color m_highlight_color; 61 | }; 62 | 63 | NAMESPACE_END(nanogui) 64 | -------------------------------------------------------------------------------- /src/label.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/label.cpp -- Text label with an arbitrary font, color, and size 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | NAMESPACE_BEGIN(nanogui) 17 | 18 | Label::Label(Widget *parent, std::string_view caption, std::string_view font, int font_size) 19 | : Widget(parent), m_caption(caption), m_font(font) { 20 | if (m_theme) { 21 | m_font_size = m_theme->m_standard_font_size; 22 | m_color = m_theme->m_text_color; 23 | } 24 | if (font_size >= 0) m_font_size = font_size; 25 | } 26 | 27 | void Label::set_theme(Theme *theme) { 28 | Widget::set_theme(theme); 29 | if (m_theme) { 30 | set_font_size(m_theme->m_standard_font_size); 31 | m_color = m_theme->m_text_color; 32 | } 33 | } 34 | 35 | Vector2i Label::preferred_size_impl(NVGcontext *ctx) const { 36 | if (m_caption == "") 37 | return Vector2i(0); 38 | nvgFontFace(ctx, m_font.c_str()); 39 | nvgFontSize(ctx, font_size()); 40 | if (m_fixed_size.x() > 0) { 41 | float bounds[4]; 42 | nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); 43 | nvgTextBoxBounds(ctx, m_pos.x(), m_pos.y(), m_fixed_size.x(), m_caption.c_str(), nullptr, bounds); 44 | return Vector2i(m_fixed_size.x(), bounds[3] - bounds[1]); 45 | } else { 46 | nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); 47 | return Vector2i( 48 | nvgTextBounds(ctx, 0, 0, m_caption.c_str(), nullptr, nullptr) + 2, 49 | font_size() 50 | ); 51 | } 52 | } 53 | 54 | void Label::draw(NVGcontext *ctx) { 55 | Widget::draw(ctx); 56 | nvgFontFace(ctx, m_font.c_str()); 57 | nvgFontSize(ctx, font_size()); 58 | nvgFillColor(ctx, m_color); 59 | if (m_fixed_size.x() > 0) { 60 | nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); 61 | nvgTextBox(ctx, m_pos.x(), m_pos.y(), m_fixed_size.x(), m_caption.c_str(), nullptr); 62 | } else { 63 | nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); 64 | nvgText(ctx, m_pos.x(), m_pos.y() + m_size.y() * 0.5f, m_caption.c_str(), nullptr); 65 | } 66 | } 67 | 68 | NAMESPACE_END(nanogui) 69 | -------------------------------------------------------------------------------- /resources/check-style.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to check include/test code for common pybind11 code style errors. 4 | # 5 | # This script currently checks for 6 | # 7 | # 1. use of tabs instead of spaces 8 | # 2. MSDOS-style CRLF endings 9 | # 3. trailing spaces 10 | # 4. missing space between keyword and parenthesis, e.g.: for(, if(, while( 11 | # 5. Missing space between right parenthesis and brace, e.g. 'for (...){' 12 | # 6. opening brace on its own line. It should always be on the same line as the 13 | # if/while/for/do statment. 14 | # 15 | # Invoke as: tools/check-style.sh 16 | # 17 | 18 | errors=0 19 | IFS=$'\n' 20 | found= 21 | # The mt=41 sets a red background for matched tabs: 22 | exec 3< <(GREP_COLORS='mt=41' grep $'\t' include/ src/ python/*.{h,cpp} docs/*.rst -rn --color=always) 23 | while read -u 3 f; do 24 | if [ -z "$found" ]; then 25 | echo -e '\e[31m\e[01mError: found tabs instead of spaces in the following files:\e[0m' 26 | found=1 27 | errors=1 28 | fi 29 | 30 | echo " $f" 31 | done 32 | 33 | found= 34 | # The mt=41 sets a red background for matched MS-DOS CRLF characters 35 | exec 3< <(GREP_COLORS='mt=41' grep -IUlr $'\r' include/ src/ python/*.{h,cpp} docs/*.rst --color=always) 36 | while read -u 3 f; do 37 | if [ -z "$found" ]; then 38 | echo -e '\e[31m\e[01mError: found CRLF characters in the following files:\e[0m' 39 | found=1 40 | errors=1 41 | fi 42 | 43 | echo " $f" 44 | done 45 | 46 | found= 47 | # The mt=41 sets a red background for matched trailing spaces 48 | exec 3< <(GREP_COLORS='mt=41' grep '\s\+$' include/ src/ python/*.{h,cpp} docs/*.rst -rn --color=always) 49 | while read -u 3 f; do 50 | if [ -z "$found" ]; then 51 | echo -e '\e[31m\e[01mError: found trailing spaces in the following files:\e[0m' 52 | found=1 53 | errors=1 54 | fi 55 | 56 | echo " $f" 57 | done 58 | 59 | found= 60 | exec 3< <(grep '\<\(if\|for\|while\|catch\)(\|){' include/ src/ python/*.{h,cpp} -rn --color=always) 61 | while read -u 3 line; do 62 | if [ -z "$found" ]; then 63 | echo -e '\e[31m\e[01mError: found the following coding style problems:\e[0m' 64 | found=1 65 | errors=1 66 | fi 67 | 68 | echo " $line" 69 | done 70 | 71 | found= 72 | exec 3< <(GREP_COLORS='mt=41' grep '^\s*{\s*$' include/ src/ -rn --color=always) 73 | while read -u 3 f; do 74 | if [ -z "$found" ]; then 75 | echo -e '\e[31m\e[01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files: \e[0m' 76 | found=1 77 | errors=1 78 | fi 79 | 80 | echo " $f" 81 | done 82 | 83 | exit $errors 84 | -------------------------------------------------------------------------------- /include/nanogui/colorpass.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/colorpass.h -- HDR/extended gamut color management render pass 3 | 4 | The color management pass was contributed by Thomas Müller (@tom94). 5 | 6 | NanoGUI was developed by Wenzel Jakob . 7 | The widget drawing code is based on the NanoVG demo application 8 | by Mikko Mononen. 9 | 10 | All rights reserved. Use of this source code is governed by a 11 | BSD-style license that can be found in the LICENSE.txt file. 12 | */ 13 | 14 | #pragma once 15 | 16 | #if defined(NANOGUI_USE_OPENGL) || defined(NANOGUI_USE_GLES) 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | NAMESPACE_BEGIN(nanogui) 24 | 25 | /** 26 | * \class ColorPass colorpass.h nanogui/colorpass.h 27 | * 28 | * \brief Color management pass for rendering HDR and/or extended color gamuts 29 | * on Windows or Linux/Wayland. 30 | * 31 | * NanoGUI generally expresses color information using the nonlinear sRGB gamma 32 | * encoding and color gamut. When working with HDR data or color gamuts that are 33 | * larger than sRGB, nanogui adopts the macOS convention of "extended sRGB", 34 | * which uses the the standard nonlinear encoding, except that components can 35 | * now exceed the value 1.0 or be negative. 36 | * 37 | * On Linux/Wayland and Windows, the compositor expects a different color 38 | * representation that furthermore depends on the precise setup. This class 39 | * determines at runtime what transformation is needed and then converts from 40 | * extended sRGB to this format. This is implemented by first rendering to a 41 | * texture and then blitting a full-screen quad with a fragment shader that 42 | * performs the color conversion. 43 | */ 44 | class NANOGUI_EXPORT ColorPass : public RenderPass { 45 | public: 46 | /// Create a render target for later processing 47 | ColorPass(Texture *color_texture, 48 | Texture *depth_texture, 49 | Texture *stencil_texture, 50 | uint32_t bits_per_channel, 51 | bool float_buffer); 52 | 53 | /// Destructor 54 | virtual ~ColorPass(); 55 | 56 | /// Update color management settings 57 | void configure(GLFWwindow *window, 58 | float display_sdr_white_level_override = .0f); 59 | 60 | /// Draw the color management quad 61 | void draw_quad(); 62 | 63 | protected: 64 | Texture *color_texture() { return static_cast(m_targets[2]); } 65 | 66 | protected: 67 | ref m_color_shader; 68 | ref m_dither_matrix; 69 | bool m_float_buffer; 70 | }; 71 | 72 | NAMESPACE_END(nanogui) 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing 2 | ======================================================================================== 3 | 4 | Thank you for your interest in this project! Please refer to the following sections on 5 | how to contribute code and bug reports. 6 | 7 | Reporting bugs 8 | ---------------------------------------------------------------------------------------- 9 | 10 | At the moment, this project is run in the spare time of a single person 11 | (`Wenzel Jakob `_) with very limited resources for 12 | issue tracker tickets. Thus, before submitting a question or bug report, please take a 13 | moment of your time and ensure that your issue isn't already discussed in the project 14 | documentation elsewhere on this site. 15 | 16 | Feature requests are generally closed unless they come with a pull request 17 | that implements the desired functionality. 18 | 19 | Assuming that you have identified a previously unknown problem or an important question, 20 | it's essential that you submit a self-contained and minimal piece of code that 21 | reproduces the problem. In other words: no external dependencies, isolate the 22 | function(s) that cause breakage, submit matched and complete C++ or Python snippets 23 | (depending on how you are using NanoGUI) that can be easily compiled and run on my end. 24 | 25 | Pull requests 26 | ---------------------------------------------------------------------------------------- 27 | Contributions are submitted, reviewed, and accepted using Github pull requests. Please 28 | refer to `this article `_ for 29 | details and adhere to the following rules to make the process as smooth as possible: 30 | 31 | - Make a new branch for every feature you're working on. 32 | - Make small and clean pull requests that are easy to review but make sure they do add 33 | value by themselves. 34 | - Make sure you have tested any new functionality (e.g. if you made a new Widget). 35 | - This project has a strong focus on providing general solutions using a minimal amount 36 | of code, thus small pull requests are greatly preferred. 37 | - Read the remainder of this document, adhering to the bindings and documentation 38 | requirements. 39 | - If making a purely documentation PR, please prefix the commit with ``[docs]`` 40 | 41 | - E.g. ``[docs] Adding documentation for class X.`` 42 | 43 | 44 | Specific activities for contributions 45 | ---------------------------------------------------------------------------------------- 46 | 47 | For a list of specific parts of nanogui which would benefit from outside contributions, 48 | refer to the bottom part of `this page `_. 49 | -------------------------------------------------------------------------------- /include/nanogui/window.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/window.h -- Top-level window widget 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class Window window.h nanogui/window.h 21 | * 22 | * \brief Top-level window widget. 23 | */ 24 | class NANOGUI_EXPORT Window : public Widget { 25 | friend class Popup; 26 | public: 27 | Window(Widget *parent, std::string_view title = "Untitled"); 28 | 29 | /// Return the window title 30 | std::string_view title() const { return m_title; } 31 | /// Set the window title 32 | void set_title(std::string_view title) { m_title = title; preferred_size_changed(); } 33 | 34 | /// Is this a model dialog? 35 | bool modal() const { return m_modal; } 36 | /// Set whether or not this is a modal dialog 37 | void set_modal(bool modal) { m_modal = modal; } 38 | 39 | /// Return the panel used to house window buttons 40 | Widget *button_panel(); 41 | 42 | /// Dispose the window 43 | void dispose(); 44 | 45 | /// Center the window in the current \ref Screen 46 | void center(); 47 | 48 | /// Draw the window 49 | virtual void draw(NVGcontext *ctx) override; 50 | /// Handle mouse enter/leave events 51 | virtual bool mouse_enter_event(const Vector2i &p, bool enter) override; 52 | /// Handle window drag events 53 | virtual bool mouse_drag_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override; 54 | /// Handle mouse events recursively and bring the current window to the top 55 | virtual bool mouse_button_event(const Vector2i &p, int button, bool down, int modifiers) override; 56 | /// Accept scroll events and propagate them to the widget under the mouse cursor 57 | virtual bool scroll_event(const Vector2i &p, const Vector2f &rel) override; 58 | /// Invoke the associated layout generator to properly place child widgets, if any 59 | virtual void perform_layout(NVGcontext *ctx) override; 60 | protected: 61 | /// Compute the preferred size of the widget 62 | virtual Vector2i preferred_size_impl(NVGcontext *ctx) const override; 63 | /// Internal helper function to maintain nested window position values; overridden in \ref Popup 64 | virtual void refresh_relative_placement(); 65 | protected: 66 | std::string m_title; 67 | Widget *m_button_panel; 68 | bool m_modal; 69 | bool m_drag; 70 | }; 71 | 72 | NAMESPACE_END(nanogui) 73 | -------------------------------------------------------------------------------- /src/python/render_test_3_quad.py: -------------------------------------------------------------------------------- 1 | # Simplified OpenGL/Metal rendering test using the Quad class 2 | 3 | import sys 4 | sys.path.append('python') 5 | import nanogui as ng 6 | from nanogui import glfw 7 | import numpy as np 8 | from PIL import Image 9 | import os 10 | import math 11 | 12 | 13 | class MyScreen(ng.Screen): 14 | def __init__(self): 15 | ng.Screen.__init__(self, 16 | size=[512, 512], 17 | caption="Quad Renderer Test" 18 | ) 19 | 20 | # Load texture 21 | base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 22 | image_fname = os.path.join(base_dir, "resources/icons/icon1.png") 23 | image = np.array(Image.open(image_fname)) 24 | 25 | self.texture = ng.Texture( 26 | pixel_format=ng.Texture.PixelFormat.RGBA, 27 | component_format=ng.Texture.ComponentFormat.UInt8, 28 | size=image.shape[:2] 29 | ) 30 | self.texture.upload(image) 31 | self.render_pass = ng.RenderPass(color_targets=[self]) 32 | self.quad = ng.Quad(self.render_pass) 33 | self.quad.set_texture(self.texture) 34 | 35 | def draw_contents(self): 36 | with self.render_pass: 37 | # Create transformation matrices 38 | view = ng.Matrix4f.look_at( 39 | origin=[0, -2, -10], 40 | target=[0, 0, 0], 41 | up=[0, 1, 0] 42 | ) 43 | 44 | model = ng.Matrix4f.rotate( 45 | [0, 1, 0], 46 | math.sin(glfw.GetTime()) 47 | ) 48 | 49 | fbsize = self.framebuffer_size() 50 | proj = ng.Matrix4f.perspective( 51 | fov=25 * np.pi / 180, 52 | near=0.1, 53 | far=20, 54 | aspect=fbsize[0] / float(fbsize[1]) 55 | ) 56 | 57 | # Set MVP and render 58 | mvp = proj @ view @ model 59 | self.quad.set_mvp(mvp.T) # -> col-major 60 | self.quad.draw() 61 | 62 | def keyboard_event(self, key, scancode, action, modifiers): 63 | if super(MyScreen, self).keyboard_event(key, scancode, 64 | action, modifiers): 65 | return True 66 | if key == glfw.KEY_ESCAPE and action == glfw.PRESS: 67 | self.set_visible(False) 68 | return True 69 | return False 70 | 71 | def resize_event(self, size): 72 | self.render_pass.resize(self.framebuffer_size()) 73 | super(MyScreen, self).resize_event(size) 74 | return True 75 | 76 | 77 | def run(): 78 | ng.init() 79 | s = MyScreen() 80 | s.set_visible(True) 81 | ng.run() 82 | ng.shutdown() 83 | 84 | if __name__ == '__main__': 85 | run() 86 | -------------------------------------------------------------------------------- /include/nanogui/metal.h: -------------------------------------------------------------------------------- 1 | /* 2 | NanoGUI was developed by Wenzel Jakob . 3 | The widget drawing code is based on the NanoVG demo application 4 | by Mikko Mononen. 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE.txt file. 8 | */ 9 | /** 10 | * \file nanogui/common.h 11 | * 12 | * \brief Common definitions used by NanoGUI. 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | #if defined(NANOGUI_USE_METAL) 20 | NAMESPACE_BEGIN(nanogui) 21 | 22 | /// Initialize the Metal backend 23 | extern NANOGUI_EXPORT void metal_init(); 24 | 25 | /// Shut down the Metal backend 26 | extern NANOGUI_EXPORT void metal_shutdown(); 27 | 28 | /// Return a pointer to the underlying Metal device (id) 29 | extern NANOGUI_EXPORT void *metal_device(); 30 | 31 | /// Return a pointer to the underlying Metal command queue (id) 32 | extern NANOGUI_EXPORT void *metal_command_queue(); 33 | 34 | /// Return a pointer to the a dispatch queue for asynchronous cleanup work 35 | extern NANOGUI_EXPORT void *metal_cleanup_queue(); 36 | 37 | /// Wait for pending work to finish 38 | extern void metal_sync(); 39 | 40 | /// Return a pointer to the underlying Metal command queue (CAMetalLayer *) 41 | extern NANOGUI_EXPORT void *metal_layer(void *nswin); 42 | 43 | /// Associate a metal layer with a NSWindow created by GLEW 44 | extern NANOGUI_EXPORT void metal_window_init(void *nswin, bool float_buffer); 45 | 46 | /// Set size of the drawable underlying an NSWindow 47 | extern NANOGUI_EXPORT void metal_window_set_size(void *nswin, const Vector2i &size); 48 | 49 | /// Set content scale of the drawable underlying an NSWindow 50 | extern NANOGUI_EXPORT void metal_window_set_content_scale(void *nswin, float scale); 51 | 52 | /// Wait for vertical refresh? 53 | extern NANOGUI_EXPORT void metal_window_set_vsync(void *nswin, bool vsync); 54 | 55 | /// Return the CAMetalLayer associated with a given NSWindow 56 | extern NANOGUI_EXPORT void *metal_window_layer(void *nswin); 57 | 58 | /// Acquire the next id and underlying texture from the Metal layer 59 | extern NANOGUI_EXPORT void metal_window_next_drawable(void *nswin, void **drawable, void **texture); 60 | 61 | /// Release a drawable back to the pool 62 | extern NANOGUI_EXPORT void metal_present_and_release_drawable(void *drawable); 63 | 64 | /// Check whether any connected display supports 10-bit or EDR mode 65 | extern NANOGUI_EXPORT std::pair metal_10bit_edr_support(); 66 | 67 | // Create a new autorelease pool 68 | extern NANOGUI_EXPORT void *autorelease_init(); 69 | 70 | // Drawin an autorelease pool 71 | extern NANOGUI_EXPORT void autorelease_release(void *pool_); 72 | 73 | NAMESPACE_END(nanogui) 74 | #endif 75 | -------------------------------------------------------------------------------- /src/python/render_test_0.py: -------------------------------------------------------------------------------- 1 | # OpenGL/Metal rendering test: render a red triangle to a texture 2 | # and save it to a PNG file 3 | 4 | import sys 5 | sys.path.append('python') 6 | import nanogui as ng 7 | import numpy as np 8 | from PIL import Image 9 | 10 | ng.init() 11 | 12 | if ng.api == 'opengl': 13 | s = ng.Screen([16, 16], "Unnamed") 14 | 15 | vertex_program = ''' 16 | #version 330 17 | in vec3 position; 18 | 19 | void main() { 20 | gl_Position = vec4(position, 1.0); 21 | } 22 | ''' 23 | 24 | fragment_program = ''' 25 | #version 330 26 | uniform vec4 color; 27 | out vec4 fragColor; 28 | 29 | void main() { 30 | fragColor = color; 31 | } 32 | ''' 33 | elif ng.api == 'metal': 34 | vertex_program = ''' 35 | using namespace metal; 36 | 37 | struct VertexOut { 38 | float4 position [[position]]; 39 | }; 40 | 41 | vertex VertexOut vertex_main(const device packed_float3 *position, 42 | uint id [[vertex_id]]) { 43 | VertexOut vert; 44 | vert.position = float4(position[id], 1.f); 45 | return vert; 46 | } 47 | ''' 48 | 49 | fragment_program = ''' 50 | using namespace metal; 51 | 52 | struct VertexOut { 53 | float4 position [[position]]; 54 | }; 55 | 56 | fragment float4 fragment_main(VertexOut vert [[stage_in]], 57 | const constant float4 &color) { 58 | return color; 59 | } 60 | ''' 61 | 62 | texture = ng.Texture( 63 | pixel_format=ng.Texture.PixelFormat.RGBA, 64 | component_format=ng.Texture.ComponentFormat.UInt8, 65 | size=[512, 512], 66 | flags=ng.Texture.TextureFlags.ShaderRead | ng.Texture.TextureFlags.RenderTarget 67 | ) 68 | 69 | render_pass = ng.RenderPass([texture]) 70 | render_pass.set_viewport( 71 | [10, 10], [512 - 10, 512 - 20] 72 | ) 73 | 74 | shader = ng.Shader( 75 | render_pass, 76 | "test_shader", 77 | vertex_program, 78 | fragment_program 79 | ) 80 | 81 | p = np.array([[ 0.0, 0.5, 0], 82 | [-0.5, -0.5, 0], 83 | [ 0.5, -0.5, 0]], dtype=np.float32) 84 | 85 | shader.set_buffer("position", p) 86 | shader.set_buffer("color", np.array([1, 0, 0, 1], dtype=np.float32)) 87 | shader.set_buffer("indices", np.array([0, 1, 2], dtype=np.uint32)) 88 | 89 | with render_pass: 90 | with shader: 91 | if False: 92 | shader.draw_array(ng.Shader.PrimitiveType.Triangle, 0, 3) 93 | else: 94 | shader.draw_array(ng.Shader.PrimitiveType.Triangle, 0, 3, indexed=True) 95 | 96 | result = texture.download() 97 | 98 | Image.fromarray(result).save('test_0_%s.png' % ng.api) 99 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "scikit-build-core", 4 | "nanobind==2.9.2" 5 | ] 6 | build-backend = "scikit_build_core.build" 7 | 8 | 9 | [project] 10 | name = "nanogui" 11 | dynamic = ["version"] 12 | description = "A minimalistic GUI library for OpenGL, GLES 2, and Metal" 13 | readme = "README.rst" 14 | requires-python = ">=3.8" 15 | authors = [ 16 | { name = "Wenzel Jakob", email = "wenzel.jakob@epfl.ch" } 17 | ] 18 | license = { text = "BSD" } 19 | classifiers = [ 20 | "Development Status :: 4 - Beta", 21 | "Intended Audience :: Developers", 22 | "License :: OSI Approved :: BSD License", 23 | "Programming Language :: C++", 24 | "Programming Language :: Python :: 3", 25 | "Programming Language :: Python :: 3.8", 26 | "Programming Language :: Python :: 3.9", 27 | "Programming Language :: Python :: 3.10", 28 | "Programming Language :: Python :: 3.11", 29 | "Programming Language :: Python :: 3.12", 30 | "Topic :: Software Development :: Libraries :: Python Modules", 31 | "Topic :: Software Development :: User Interfaces" 32 | ] 33 | 34 | [project.urls] 35 | Homepage = "https://github.com/mitsuba-renderer/nanogui" 36 | Repository = "https://github.com/mitsuba-renderer/nanogui" 37 | Issues = "https://github.com/mitsuba-renderer/nanogui/issues" 38 | 39 | 40 | [tool.scikit-build] 41 | minimum-version = "0.4" 42 | build-dir = "build/{wheel_tag}" 43 | cmake.verbose = true 44 | logging.level = "INFO" 45 | wheel.py-api = "cp312" 46 | 47 | cmake.args = [ 48 | "-DCMAKE_INSTALL_LIBDIR=nanogui", 49 | "-DCMAKE_INSTALL_BINDIR=nanogui", 50 | "-DCMAKE_INSTALL_INCLUDEDIR=nanogui/include", 51 | "-DCMAKE_INSTALL_DATAROOTDIR=nanogui/share", 52 | "-DNANOGUI_BUILD_EXAMPLES=OFF" 53 | ] 54 | 55 | wheel.packages = ["nanogui"] 56 | 57 | 58 | [tool.scikit-build.metadata.version] 59 | provider = "scikit_build_core.metadata.regex" 60 | input = "include/nanogui/common.h" 61 | regex = '''(?sx) 62 | \#define \s+ NANOGUI_VERSION_MAJOR \s+ (?P\d+) .*? 63 | \#define \s+ NANOGUI_VERSION_MINOR \s+ (?P\d+) .*? 64 | \#define \s+ NANOGUI_VERSION_PATCH \s+ (?P\d+) .*? 65 | ''' 66 | result = "{major}.{minor}.{patch}" 67 | 68 | 69 | [tool.cibuildwheel] 70 | build-verbosity = 1 71 | build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*"] 72 | skip = "*-musllinux* pp*" 73 | test-command = "python -c \"import nanogui\"" 74 | 75 | # Platform-specific settings 76 | [tool.cibuildwheel.linux] 77 | archs = ["auto64"] 78 | manylinux-x86_64-image = "manylinux_2_28" 79 | manylinux-aarch64-image = "manylinux_2_28" 80 | before-build = "yum install -y mesa-libGLU-devel libXi-devel libXcursor-devel libXinerama-devel libXrandr-devel xorg-x11-server-devel libxkbcommon-devel wayland-devel dbus-devel kernel-headers" 81 | environment = { CFLAGS="-D_GNU_SOURCE", CXXFLAGS="-D_GNU_SOURCE" } 82 | 83 | [tool.cibuildwheel.windows] 84 | archs = ["auto64"] 85 | 86 | [tool.cibuildwheel.macos] 87 | environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" } 88 | -------------------------------------------------------------------------------- /src/graph.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/graph.cpp -- Simple graph widget for showing a function plot 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | NAMESPACE_BEGIN(nanogui) 17 | 18 | Graph::Graph(Widget *parent, std::string_view caption) 19 | : Widget(parent), m_caption(caption) { 20 | m_background_color = Color(20, 128); 21 | m_fill_color = Color(255, 192, 0, 128); 22 | m_stroke_color = Color(100, 255); 23 | m_text_color = Color(240, 192); 24 | } 25 | 26 | Vector2i Graph::preferred_size_impl(NVGcontext *) const { 27 | return Vector2i(180, 45); 28 | } 29 | 30 | void Graph::draw(NVGcontext *ctx) { 31 | Widget::draw(ctx); 32 | 33 | nvgBeginPath(ctx); 34 | nvgRect(ctx, m_pos.x(), m_pos.y(), m_size.x(), m_size.y()); 35 | nvgFillColor(ctx, m_background_color); 36 | nvgFill(ctx); 37 | 38 | if (m_values.size() < 2) 39 | return; 40 | 41 | nvgBeginPath(ctx); 42 | nvgMoveTo(ctx, m_pos.x(), m_pos.y()+m_size.y()); 43 | for (size_t i = 0; i < (size_t) m_values.size(); i++) { 44 | float value = m_values[i]; 45 | float vx = m_pos.x() + i * m_size.x() / (float) (m_values.size() - 1); 46 | float vy = m_pos.y() + (1-value) * m_size.y(); 47 | nvgLineTo(ctx, vx, vy); 48 | } 49 | 50 | nvgLineTo(ctx, m_pos.x() + m_size.x(), m_pos.y() + m_size.y()); 51 | nvgStrokeColor(ctx, m_stroke_color); 52 | nvgStroke(ctx); 53 | if (m_fill_color.w() > 0) { 54 | nvgFillColor(ctx, m_fill_color); 55 | nvgFill(ctx); 56 | } 57 | 58 | nvgFontFace(ctx, "sans"); 59 | 60 | if (!m_caption.empty()) { 61 | nvgFontSize(ctx, 14.0f); 62 | nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); 63 | nvgFillColor(ctx, m_text_color); 64 | nvgText(ctx, m_pos.x() + 3, m_pos.y() + 1, m_caption.c_str(), NULL); 65 | } 66 | 67 | if (!m_header.empty()) { 68 | nvgFontSize(ctx, 18.0f); 69 | nvgTextAlign(ctx, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP); 70 | nvgFillColor(ctx, m_text_color); 71 | nvgText(ctx, m_pos.x() + m_size.x() - 3, m_pos.y() + 1, m_header.c_str(), NULL); 72 | } 73 | 74 | if (!m_footer.empty()) { 75 | nvgFontSize(ctx, 15.0f); 76 | nvgTextAlign(ctx, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM); 77 | nvgFillColor(ctx, m_text_color); 78 | nvgText(ctx, m_pos.x() + m_size.x() - 3, m_pos.y() + m_size.y() - 1, m_footer.c_str(), NULL); 79 | } 80 | 81 | nvgBeginPath(ctx); 82 | nvgRect(ctx, m_pos.x(), m_pos.y(), m_size.x(), m_size.y()); 83 | nvgStrokeColor(ctx, Color(100, 255)); 84 | nvgStroke(ctx); 85 | } 86 | 87 | NAMESPACE_END(nanogui) 88 | -------------------------------------------------------------------------------- /src/popup.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/popup.cpp -- Simple popup widget which is attached to another given 3 | window (can be nested) 4 | 5 | NanoGUI was developed by Wenzel Jakob . 6 | The widget drawing code is based on the NanoVG demo application 7 | by Mikko Mononen. 8 | 9 | All rights reserved. Use of this source code is governed by a 10 | BSD-style license that can be found in the LICENSE.txt file. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | Popup::Popup(Widget *parent, Window *parent_window) 20 | : Window(parent, ""), m_parent_window(parent_window), m_anchor_pos(Vector2i(0)), 21 | m_anchor_offset(30), m_anchor_size(15), m_side(Side::Right) { } 22 | 23 | void Popup::perform_layout(NVGcontext *ctx) { 24 | if (m_layout || m_children.size() != 1) { 25 | Widget::perform_layout(ctx); 26 | } else { 27 | m_children[0]->set_position(Vector2i(0)); 28 | m_children[0]->set_size(m_size); 29 | m_children[0]->perform_layout(ctx); 30 | } 31 | if (m_side == Side::Left) 32 | m_anchor_pos[0] -= size()[0]; 33 | } 34 | 35 | void Popup::refresh_relative_placement() { 36 | if (!m_parent_window) 37 | return; 38 | m_parent_window->refresh_relative_placement(); 39 | m_visible &= m_parent_window->visible_recursive(); 40 | m_pos = m_parent_window->position() + m_anchor_pos - Vector2i(0, m_anchor_offset); 41 | } 42 | 43 | void Popup::draw(NVGcontext* ctx) { 44 | refresh_relative_placement(); 45 | 46 | if (!m_visible) 47 | return; 48 | 49 | int ds = m_theme->m_window_drop_shadow_size, 50 | cr = m_theme->m_window_corner_radius; 51 | 52 | nvgSave(ctx); 53 | nvgResetScissor(ctx); 54 | 55 | /* Draw a drop shadow */ 56 | NVGpaint shadow_paint = nvgBoxGradient( 57 | ctx, m_pos.x(), m_pos.y(), m_size.x(), m_size.y(), cr*2, ds*2, 58 | m_theme->m_drop_shadow, m_theme->m_transparent); 59 | 60 | nvgBeginPath(ctx); 61 | nvgRect(ctx, m_pos.x()-ds,m_pos.y()-ds, m_size.x()+2*ds, m_size.y()+2*ds); 62 | nvgRoundedRect(ctx, m_pos.x(), m_pos.y(), m_size.x(), m_size.y(), cr); 63 | nvgPathWinding(ctx, NVG_HOLE); 64 | nvgFillPaint(ctx, shadow_paint); 65 | nvgFill(ctx); 66 | 67 | /* Draw window */ 68 | nvgBeginPath(ctx); 69 | nvgRoundedRect(ctx, m_pos.x(), m_pos.y(), m_size.x(), m_size.y(), cr); 70 | 71 | Vector2i base = m_pos + Vector2i(0, m_anchor_offset); 72 | int sign = -1; 73 | if (m_side == Side::Left) { 74 | base.x() += m_size.x(); 75 | sign = 1; 76 | } 77 | 78 | nvgMoveTo(ctx, base.x() + m_anchor_size*sign, base.y()); 79 | nvgLineTo(ctx, base.x() - 1*sign, base.y() - m_anchor_size); 80 | nvgLineTo(ctx, base.x() - 1*sign, base.y() + m_anchor_size); 81 | 82 | nvgFillColor(ctx, m_theme->m_window_popup); 83 | nvgFill(ctx); 84 | nvgRestore(ctx); 85 | 86 | Widget::draw(ctx); 87 | } 88 | 89 | NAMESPACE_END(nanogui) 90 | -------------------------------------------------------------------------------- /src/python/canvas.cpp: -------------------------------------------------------------------------------- 1 | #ifdef NANOGUI_PYTHON 2 | 3 | #include "python.h" 4 | #include 5 | #include 6 | 7 | class PyCanvas : public Canvas { 8 | public: 9 | NANOGUI_WIDGET_OVERLOADS(Canvas); 10 | 11 | void draw_contents() override { 12 | NB_OVERRIDE(draw_contents); 13 | } 14 | }; 15 | 16 | class PyImageView : public ImageView { 17 | public: 18 | NANOGUI_WIDGET_OVERLOADS(ImageView); 19 | 20 | void draw_contents() override { 21 | NB_OVERRIDE(draw_contents); 22 | } 23 | }; 24 | 25 | void register_canvas(nb::module_ &m) { 26 | nb::class_(m, "Canvas", D(Canvas)) 27 | .def(nb::init(), 28 | "parent"_a, "samples"_a = 4, "has_depth_buffer"_a = true, 29 | "has_stencil_buffer"_a = false, 30 | "clear"_a = true, D(Canvas, Canvas)) 31 | .def("render_pass", &Canvas::render_pass, D(Canvas, render_pass)) 32 | .def("draw_border", &Canvas::draw_border, D(Canvas, draw_border)) 33 | .def("set_draw_border", &Canvas::set_draw_border, D(Canvas, set_draw_border)) 34 | .def("border_color", &Canvas::border_color, D(Canvas, border_color)) 35 | .def("set_border_color", &Canvas::set_border_color, D(Canvas, set_border_color)) 36 | .def("background_color", &Canvas::background_color, D(Canvas, background_color)) 37 | .def("set_background_color", &Canvas::set_background_color, D(Canvas, set_background_color)) 38 | .def("draw_contents", &Canvas::draw_contents, D(Canvas, draw_contents)); 39 | 40 | nb::class_(m, "ImageView", D(ImageView)) 41 | .def(nb::init(), D(ImageView, ImageView)) 42 | .def("image", nb::overload_cast<>(&ImageView::image, nb::const_), D(ImageView, image)) 43 | .def("set_image", &ImageView::set_image, D(ImageView, set_image)) 44 | .def("reset", &ImageView::reset, D(ImageView, reset)) 45 | .def("center", &ImageView::center, D(ImageView, center)) 46 | .def("offset", &ImageView::offset, D(ImageView, offset)) 47 | .def("set_offset", &ImageView::set_offset, D(ImageView, set_offset)) 48 | .def("scale", &ImageView::scale, D(ImageView, scale)) 49 | .def("set_scale", &ImageView::set_scale, D(ImageView, set_scale)) 50 | .def("pos_to_pixel", &ImageView::pos_to_pixel, D(ImageView, pos_to_pixel)) 51 | .def("pixel_to_pos", &ImageView::pixel_to_pos, D(ImageView, pixel_to_pos)) 52 | .def("set_pixel_callback", 53 | [](ImageView &img, 54 | const std::function(const Vector2i &)> &func) { 55 | img.set_pixel_callback([func](const Vector2i &p, char **out, size_t size) { 56 | auto str = func(p); 57 | for (int i = 0; i < 4; ++i) 58 | strncpy(out[i], str[i].c_str(), size); 59 | }); 60 | }, 61 | D(ImageView, set_pixel_callback)); 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /include/nanogui/popup.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/popup.h -- Simple popup widget which is attached to another given 3 | window (can be nested) 4 | 5 | NanoGUI was developed by Wenzel Jakob . 6 | The widget drawing code is based on the NanoVG demo application 7 | by Mikko Mononen. 8 | 9 | All rights reserved. Use of this source code is governed by a 10 | BSD-style license that can be found in the LICENSE.txt file. 11 | */ 12 | /** \file */ 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | NAMESPACE_BEGIN(nanogui) 19 | 20 | /** 21 | * \class Popup popup.h nanogui/popup.h 22 | * 23 | * \brief Popup window for combo boxes, popup buttons, nested dialogs etc. 24 | * 25 | * Usually the Popup instance is constructed by another widget (e.g. \ref PopupButton) 26 | * and does not need to be created by hand. 27 | */ 28 | class NANOGUI_EXPORT Popup : public Window { 29 | public: 30 | enum Side { Left = 0, Right }; 31 | 32 | /// Create a new popup parented to a screen (first argument) and a parent window (if applicable) 33 | Popup(Widget *parent, Window *parent_window = nullptr); 34 | 35 | /// Return the anchor position in the parent window; the placement of the popup is relative to it 36 | void set_anchor_pos(const Vector2i &anchor_pos) { m_anchor_pos = anchor_pos; } 37 | /// Set the anchor position in the parent window; the placement of the popup is relative to it 38 | const Vector2i &anchor_pos() const { return m_anchor_pos; } 39 | 40 | /// Set the anchor height; this determines the vertical shift relative to the anchor position 41 | void set_anchor_offset(int anchor_offset) { m_anchor_offset = anchor_offset; } 42 | /// Return the anchor height; this determines the vertical shift relative to the anchor position 43 | int anchor_offset() const { return m_anchor_offset; } 44 | 45 | /// Set the anchor width 46 | void set_anchor_size(int anchor_size) { m_anchor_size = anchor_size; } 47 | /// Return the anchor width 48 | int anchor_size() const { return m_anchor_size; } 49 | 50 | /// Set the side of the parent window at which popup will appear 51 | void set_side(Side popup_side) { m_side = popup_side; } 52 | /// Return the side of the parent window at which popup will appear 53 | Side side() const { return m_side; } 54 | 55 | /// Return the parent window of the popup 56 | Window *parent_window() { return m_parent_window; } 57 | /// Return the parent window of the popup 58 | const Window *parent_window() const { return m_parent_window; } 59 | 60 | /// Invoke the associated layout generator to properly place child widgets, if any 61 | virtual void perform_layout(NVGcontext *ctx) override; 62 | 63 | /// Draw the popup window 64 | virtual void draw(NVGcontext* ctx) override; 65 | protected: 66 | /// Internal helper function to maintain nested window position values 67 | virtual void refresh_relative_placement() override; 68 | 69 | protected: 70 | Window *m_parent_window; 71 | Vector2i m_anchor_pos; 72 | int m_anchor_offset, m_anchor_size; 73 | Side m_side; 74 | }; 75 | 76 | NAMESPACE_END(nanogui) 77 | -------------------------------------------------------------------------------- /src/example2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/example2.cpp -- C++ version of an example application that shows 3 | how to use the form helper class. For a Python implementation, see 4 | '../python/example2.py'. 5 | 6 | NanoGUI was developed by Wenzel Jakob . 7 | The widget drawing code is based on the NanoVG demo application 8 | by Mikko Mononen. 9 | 10 | All rights reserved. Use of this source code is governed by a 11 | BSD-style license that can be found in the LICENSE.txt file. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | using namespace nanogui; 18 | 19 | enum test_enum { 20 | Item1 = 0, 21 | Item2, 22 | Item3 23 | }; 24 | 25 | bool bvar = true; 26 | int ivar = 12345678; 27 | double dvar = 3.1415926; 28 | float fvar = (float)dvar; 29 | std::string strval = "A string"; 30 | std::string strval2 = ""; 31 | test_enum enumval = Item2; 32 | Color colval(0.5f, 0.5f, 0.7f, 1.f); 33 | 34 | int main(int /* argc */, char ** /* argv */) { 35 | nanogui::init(); 36 | 37 | /* scoped variables */ { 38 | bool use_gl_4_1 = false;// Set to true to create an OpenGL 4.1 context. 39 | ref screen; 40 | 41 | if (use_gl_4_1) { 42 | // NanoGUI presents many options for you to utilize at your discretion. 43 | // See include/nanogui/screen.h for what all of these represent. 44 | screen = new Screen(Vector2i(500, 700), "NanoGUI test [GL 4.1]", 45 | /* resizable */ true, /* maximized */ false, 46 | /* fullscreen */ false, /* depth_buffer */ true, 47 | /* stencil_buffer */ true, /* float_buffer */ false, 48 | /* gl_major */ 4, /* gl_minor */ 1); 49 | 50 | } else { 51 | screen = new Screen(Vector2i(500, 700), "NanoGUI test"); 52 | } 53 | 54 | bool enabled = true; 55 | FormHelper *gui = new FormHelper(screen); 56 | ref window = gui->add_window(Vector2i(10, 10), "Form helper example"); 57 | gui->add_group("Basic types"); 58 | gui->add_variable("bool", bvar); 59 | gui->add_variable("string", strval); 60 | gui->add_variable("placeholder", strval2)->set_placeholder("placeholder"); 61 | 62 | gui->add_group("Validating fields"); 63 | gui->add_variable("int", ivar)->set_spinnable(true); 64 | gui->add_variable("float", fvar); 65 | gui->add_variable("double", dvar)->set_spinnable(true); 66 | 67 | gui->add_group("Complex types"); 68 | gui->add_variable("Enumeration", enumval, enabled) 69 | ->set_items({"Item 1", "Item 2", "Item 3"}); 70 | gui->add_variable("Color", colval); 71 | 72 | gui->add_group("Other widgets"); 73 | gui->add_button("A button", []() { std::cout << "Button pressed." << std::endl; }); 74 | 75 | screen->set_visible(true); 76 | screen->perform_layout(); 77 | window->center(); 78 | 79 | nanogui::run(RunMode::Lazy); 80 | delete gui; 81 | } 82 | 83 | nanogui::shutdown(); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /include/nanogui/combobox.h: -------------------------------------------------------------------------------- 1 | /* 2 | NanoGUI was developed by Wenzel Jakob . 3 | The widget drawing code is based on the NanoVG demo application 4 | by Mikko Mononen. 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE.txt file. 8 | */ 9 | /** 10 | * \file nanogui/combobox.h 11 | * 12 | * \brief Simple combo box widget based on a popup button. 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | NAMESPACE_BEGIN(nanogui) 20 | 21 | /** 22 | * \class ComboBox combobox.h nanogui/combobox.h 23 | * 24 | * \brief Simple combo box widget based on a popup button. 25 | */ 26 | class NANOGUI_EXPORT ComboBox : public PopupButton { 27 | public: 28 | /// Create an empty combo box 29 | ComboBox(Widget *parent); 30 | 31 | /// Create a new combo box with the given items 32 | ComboBox(Widget *parent, const std::vector &items); 33 | 34 | /** 35 | * \brief Create a new combo box with the given items, providing both short and 36 | * long descriptive labels for each item 37 | */ 38 | ComboBox(Widget *parent, const std::vector &items, 39 | const std::vector &items_short); 40 | 41 | /// The current index this ComboBox has selected. 42 | int selected_index() const { return m_selected_index; } 43 | 44 | /// Sets the current index this ComboBox has selected. 45 | void set_selected_index(int idx); 46 | 47 | /// The callback to execute for this ComboBox. 48 | const std::function &callback() const { return m_callback; } 49 | 50 | /// Sets the callback to execute for this ComboBox. 51 | void set_callback(const std::function &callback) { m_callback = callback; } 52 | 53 | /// Sets the items for this ComboBox, providing both short and long descriptive lables for each item. 54 | void set_items(const std::vector &items, const std::vector &items_short); 55 | /// Sets the items for this ComboBox. 56 | void set_items(const std::vector &items) { set_items(items, items); } 57 | /// The items associated with this ComboBox. 58 | const std::vector &items() const { return m_items; } 59 | /// The short descriptions associated with this ComboBox. 60 | const std::vector &items_short() const { return m_items_short; } 61 | 62 | /// Handles mouse scrolling events for this ComboBox. 63 | virtual bool scroll_event(const Vector2i &p, const Vector2f &rel) override; 64 | protected: 65 | /// Scroll panel used to store the combo box contents 66 | VScrollPanel *m_scroll = nullptr; 67 | 68 | /// Container containing the buttons 69 | Widget *m_container = nullptr; 70 | 71 | /// The items associated with this ComboBox. 72 | std::vector m_items; 73 | 74 | /// The short descriptions of items associated with this ComboBox. 75 | std::vector m_items_short; 76 | 77 | /// The callback for this ComboBox. 78 | std::function m_callback; 79 | 80 | /// The current index this ComboBox has selected. 81 | int m_selected_index; 82 | }; 83 | 84 | NAMESPACE_END(nanogui) 85 | -------------------------------------------------------------------------------- /include/nanogui/imageview.h: -------------------------------------------------------------------------------- 1 | /* 2 | nanogui/imageview.h -- Widget used to display images. 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | /** \file */ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | /** 20 | * \class ImageView imageview.h nanogui/imageview.h 21 | * 22 | * \brief A widget for displaying, panning, and zooming images. Numerical RGBA 23 | * pixel information is shown at large magnifications. 24 | */ 25 | class NANOGUI_EXPORT ImageView : public Canvas { 26 | public: 27 | using PixelCallback = std::function; 28 | 29 | /// Initialize the widget 30 | ImageView(Widget *parent); 31 | 32 | /// Return the currently active image 33 | Texture *image() { return m_image; } 34 | /// Return the currently active image (const version) 35 | const Texture *image() const { return m_image.get(); } 36 | /// Set the currently active image 37 | void set_image(Texture *image); 38 | 39 | /// Center the image on the screen 40 | void center(); 41 | 42 | /// Center the image on the screen and set the scale to 1:1 43 | void reset(); 44 | 45 | /// Set the callback that is used to acquire information about pixel components 46 | void set_pixel_callback(const PixelCallback &pixel_callback) { 47 | m_pixel_callback = pixel_callback; 48 | } 49 | /// Return the callback that is used to acquire information about pixel components 50 | const PixelCallback &pixel_callback() const { return m_pixel_callback; } 51 | 52 | /// Return the pixel offset of the zoomed image rectangle 53 | Vector2f offset() const { return m_offset; } 54 | /// Set the pixel offset of the zoomed image rectangle 55 | void set_offset(const Vector2f &offset) { m_offset = offset; } 56 | 57 | /// Return the current magnification of the image 58 | float scale() const; 59 | /// Set the current magnification of the image 60 | void set_scale(float scale); 61 | 62 | /// Convert a position within the widget to a pixel position in the image 63 | Vector2f pos_to_pixel(const Vector2f &p) const; 64 | /// Convert a pixel position in the image to a position within the widget 65 | Vector2f pixel_to_pos(const Vector2f &p) const; 66 | 67 | // Widget implementation 68 | virtual bool keyboard_event(int key, int scancode, int action, int modifiers) override; 69 | virtual bool mouse_drag_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override; 70 | virtual bool scroll_event(const Vector2i &p, const Vector2f &rel) override; 71 | virtual void draw(NVGcontext *ctx) override; 72 | virtual void draw_contents() override; 73 | 74 | protected: 75 | nanogui::ref m_image_shader; 76 | nanogui::ref m_image; 77 | float m_scale = 0; 78 | Vector2f m_offset = 0; 79 | bool m_draw_image_border; 80 | Color m_image_border_color; 81 | Color m_image_background_color; 82 | PixelCallback m_pixel_callback; 83 | }; 84 | 85 | NAMESPACE_END(nanogui) 86 | -------------------------------------------------------------------------------- /include/nanogui/quad.h: -------------------------------------------------------------------------------- 1 | /* 2 | NanoGUI was developed by Wenzel Jakob . 3 | The widget drawing code is based on the NanoVG demo application 4 | by Mikko Mononen. 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE.txt file. 8 | */ 9 | 10 | /** 11 | * \file nanogui/quad.h 12 | * 13 | * \brief Defines a simple quad renderer for displaying textures 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | NAMESPACE_BEGIN(nanogui) 23 | 24 | /** 25 | * \brief Textured quad 26 | * 27 | * This convenience class implements a shader that renders a textured quad 28 | * on the supported platforms (OpenGL, EGL, Metal) 29 | */ 30 | class NANOGUI_EXPORT TexturedQuad : public Shader { 31 | public: 32 | /** 33 | * \brief Initialize the quad renderer 34 | * 35 | * \param render_pass 36 | * RenderPass object encoding targets to which the quad will be rendered 37 | * 38 | * \param blend_mode 39 | * Alpha blending mode for rendering 40 | */ 41 | TexturedQuad(RenderPass *render_pass, BlendMode blend_mode = BlendMode::None); 42 | 43 | /** 44 | * \brief Set the texture to be rendered on the quad 45 | * 46 | * \param texture 47 | * The texture to display 48 | */ 49 | void set_texture(Texture *texture); 50 | 51 | /** 52 | * \brief Set the model-view-projection matrix 53 | * 54 | * \param mvp 55 | * The transformation matrix 56 | */ 57 | void set_mvp(const Matrix4f &mvp); 58 | 59 | /** 60 | * \brief Render the quad 61 | * 62 | * This method handles begin(), draw_array(), and end() internally 63 | */ 64 | void draw(); 65 | 66 | /** 67 | * \brief Set whether the texture is in linear space 68 | * 69 | * When true, the shader will convert from linear to sRGB space. 70 | * When false, the texture is assumed to already be in sRGB space. 71 | * Default is false. 72 | * 73 | * \param linear 74 | * True if texture is in linear space, false if in sRGB space 75 | */ 76 | void set_texture_linear(bool linear); 77 | 78 | /** 79 | * \brief Get whether the texture is treated as linear space 80 | * 81 | * \return True if texture is treated as linear space 82 | */ 83 | bool texture_linear() const { return m_texture_linear; } 84 | 85 | /** 86 | * \brief Set the exposure multiplier for the texture 87 | * 88 | * This value is multiplied onto the texture color before 89 | * linear-to-sRGB conversion. Default is 1.0. 90 | * 91 | * \param exposure 92 | * Exposure multiplier (typically 0.0 to 10.0) 93 | */ 94 | void set_texture_exposure(float exposure); 95 | 96 | /** 97 | * \brief Get the current exposure multiplier 98 | * 99 | * \return Current exposure value 100 | */ 101 | float texture_exposure() const { return m_texture_exposure; } 102 | 103 | private: 104 | bool m_texture_linear = false; 105 | float m_texture_exposure = 1.0f; 106 | }; 107 | 108 | NAMESPACE_END(nanogui) 109 | -------------------------------------------------------------------------------- /src/python/render_test_1.py: -------------------------------------------------------------------------------- 1 | # OpenGL/Metal rendering test: render a green triangle on screen 2 | 3 | import sys 4 | sys.path.append('python') 5 | import nanogui as ng 6 | import numpy as np 7 | from PIL import Image 8 | 9 | 10 | class MyScreen(ng.Screen): 11 | def __init__(self): 12 | ng.Screen.__init__(self, [512, 512], "Unnamed") 13 | 14 | if ng.api == 'opengl': 15 | vertex_program = ''' 16 | #version 330 17 | in vec3 position; 18 | 19 | void main() { 20 | gl_Position = vec4(position, 1); 21 | } 22 | ''' 23 | 24 | fragment_program = ''' 25 | #version 330 26 | uniform vec4 color; 27 | out vec4 fragColor; 28 | 29 | void main() { 30 | fragColor = color; 31 | } 32 | ''' 33 | elif ng.api == 'metal': 34 | vertex_program = ''' 35 | using namespace metal; 36 | 37 | struct VertexOut { 38 | float4 position [[position]]; 39 | }; 40 | 41 | vertex VertexOut vertex_main(const device packed_float3 *position, 42 | uint id [[vertex_id]]) { 43 | VertexOut vert; 44 | vert.position = float4(position[id], 1.f); 45 | return vert; 46 | } 47 | ''' 48 | 49 | fragment_program = ''' 50 | using namespace metal; 51 | 52 | struct VertexOut { 53 | float4 position [[position]]; 54 | }; 55 | 56 | fragment float4 fragment_main(VertexOut vert [[stage_in]], 57 | const constant float4 &color) { 58 | return color; 59 | } 60 | ''' 61 | 62 | self.render_pass = ng.RenderPass([self]) 63 | self.render_pass.set_viewport( 64 | [10, 10], self.framebuffer_size() - [10, 20] 65 | ) 66 | 67 | self.shader = ng.Shader( 68 | self.render_pass, 69 | "test_shader", 70 | vertex_program, 71 | fragment_program 72 | ) 73 | 74 | p = np.array([[ 0.0, 0.5, 0], 75 | [-0.5, -0.5, 0], 76 | [ 0.5, -0.5, 0]], dtype=np.float32) 77 | 78 | self.shader.set_buffer("position", p) 79 | self.shader.set_buffer("color", np.array([0, 1, 0, 1], dtype=np.float32)) 80 | self.shader.set_buffer("indices", np.array([0, 1, 2], dtype=np.uint32)) 81 | 82 | def draw_contents(self): 83 | print('draw_contents()') 84 | with self.render_pass: 85 | with self.shader: 86 | if False: 87 | self.shader.draw_array(ng.Shader.PrimitiveType.Triangle, 0, 3) 88 | else: 89 | self.shader.draw_array(ng.Shader.PrimitiveType.Triangle, 0, 3, indexed=True) 90 | 91 | def run(): 92 | ng.init() 93 | s = MyScreen() 94 | s.set_visible(True) 95 | ng.run() 96 | ng.shutdown() 97 | 98 | if __name__ == '__main__': 99 | run() 100 | -------------------------------------------------------------------------------- /src/popupbutton.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/popupbutton.cpp -- Button which launches a popup widget 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | NAMESPACE_BEGIN(nanogui) 18 | 19 | PopupButton::PopupButton(Widget *parent, std::string_view caption, int button_icon) 20 | : Button(parent, caption, button_icon) { 21 | 22 | m_chevron_icon = m_theme->m_popup_chevron_right_icon; 23 | 24 | set_flags(Flags::ToggleButton | Flags::PopupButton); 25 | 26 | m_popup = new Popup(screen(), window()); 27 | m_popup->set_size(Vector2i(320, 250)); 28 | m_popup->set_visible(false); 29 | 30 | m_icon_extra_scale = 0.8f; // widget override 31 | } 32 | 33 | void PopupButton::draw(NVGcontext* ctx) { 34 | if (!m_enabled && m_pushed) 35 | m_pushed = false; 36 | 37 | m_popup->set_visible(m_pushed); 38 | Button::draw(ctx); 39 | 40 | if (m_chevron_icon) { 41 | auto icon = utf8(m_chevron_icon); 42 | NVGcolor text_color = 43 | m_text_color.w() == 0 ? m_theme->m_text_color : m_text_color; 44 | 45 | nvgFontSize(ctx, (m_font_size < 0 ? m_theme->m_button_font_size : m_font_size) * icon_scale()); 46 | nvgFontFace(ctx, "icons"); 47 | nvgFillColor(ctx, m_enabled ? text_color : NVGcolor(m_theme->m_disabled_text_color)); 48 | nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); 49 | 50 | float iw = nvgTextBounds(ctx, 0, 0, icon.data(), nullptr, nullptr); 51 | Vector2f icon_pos(0, m_pos.y() + m_size.y() * 0.5f - 1); 52 | 53 | if (m_popup->side() == Popup::Right) 54 | icon_pos[0] = m_pos.x() + m_size.x() - iw - 8; 55 | else 56 | icon_pos[0] = m_pos.x() + 8; 57 | 58 | nvgText(ctx, icon_pos.x(), icon_pos.y(), icon.data(), nullptr); 59 | } 60 | } 61 | 62 | void PopupButton::perform_layout(NVGcontext *ctx) { 63 | Widget::perform_layout(ctx); 64 | 65 | const Window *parent_window = window(); 66 | 67 | int anchor_size = m_popup->anchor_size(); 68 | 69 | if (parent_window) { 70 | int pos_y = absolute_position().y() - parent_window->position().y() + m_size.y() / 2; 71 | if (m_popup->side() == Popup::Right) 72 | m_popup->set_anchor_pos(Vector2i(parent_window->width() + anchor_size, pos_y)); 73 | else 74 | m_popup->set_anchor_pos(Vector2i(-anchor_size, pos_y)); 75 | } else { 76 | m_popup->set_position(absolute_position() + Vector2i(width() + anchor_size + 1, m_size.y() / 2 - anchor_size)); 77 | } 78 | } 79 | 80 | void PopupButton::set_side(Popup::Side side) { 81 | if (m_popup->side() == Popup::Right && 82 | m_chevron_icon == m_theme->m_popup_chevron_right_icon) 83 | set_chevron_icon(m_theme->m_popup_chevron_left_icon); 84 | else if (m_popup->side() == Popup::Left && 85 | m_chevron_icon == m_theme->m_popup_chevron_left_icon) 86 | set_chevron_icon(m_theme->m_popup_chevron_right_icon); 87 | m_popup->set_side(side); 88 | } 89 | 90 | NAMESPACE_END(nanogui) 91 | -------------------------------------------------------------------------------- /src/checkbox.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | src/checkbox.cpp -- Two-state check box widget 3 | 4 | NanoGUI was developed by Wenzel Jakob . 5 | The widget drawing code is based on the NanoVG demo application 6 | by Mikko Mononen. 7 | 8 | All rights reserved. Use of this source code is governed by a 9 | BSD-style license that can be found in the LICENSE.txt file. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | NAMESPACE_BEGIN(nanogui) 17 | 18 | CheckBox::CheckBox(Widget *parent, std::string_view caption, 19 | const std::function &callback) 20 | : Widget(parent), m_caption(caption), m_pushed(false), m_checked(false), 21 | m_callback(callback) { 22 | m_icon_extra_scale = 1.2f; // widget override 23 | } 24 | 25 | bool CheckBox::mouse_button_event(const Vector2i &p, int button, bool down, 26 | int modifiers) { 27 | Widget::mouse_button_event(p, button, down, modifiers); 28 | if (!m_enabled) 29 | return false; 30 | 31 | if (button == GLFW_MOUSE_BUTTON_1) { 32 | if (down) { 33 | m_pushed = true; 34 | } else if (m_pushed) { 35 | if (contains(p)) { 36 | m_checked = !m_checked; 37 | if (m_callback) 38 | m_callback(m_checked); 39 | } 40 | m_pushed = false; 41 | } 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | Vector2i CheckBox::preferred_size_impl(NVGcontext *ctx) const { 48 | if (m_fixed_size != Vector2i(0)) 49 | return m_fixed_size; 50 | nvgFontSize(ctx, font_size()); 51 | nvgFontFace(ctx, "sans"); 52 | return Vector2i( 53 | nvgTextBounds(ctx, 0, 0, m_caption.c_str(), nullptr, nullptr) + 54 | 1.8f * font_size(), 55 | font_size() * 1.3f); 56 | } 57 | 58 | void CheckBox::draw(NVGcontext *ctx) { 59 | Widget::draw(ctx); 60 | 61 | nvgFontSize(ctx, font_size()); 62 | nvgFontFace(ctx, "sans"); 63 | nvgFillColor(ctx, 64 | m_enabled ? m_theme->m_text_color : m_theme->m_disabled_text_color); 65 | nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); 66 | nvgText(ctx, m_pos.x() + 1.6f * font_size(), m_pos.y() + m_size.y() * 0.5f, 67 | m_caption.c_str(), nullptr); 68 | 69 | NVGpaint bg = nvgBoxGradient(ctx, m_pos.x() + 1.5f, m_pos.y() + 1.5f, 70 | m_size.y() - 2.0f, m_size.y() - 2.0f, 3, 3, 71 | m_pushed ? Color(0, 100) : Color(0, 32), 72 | Color(0, 0, 0, 180)); 73 | 74 | nvgBeginPath(ctx); 75 | nvgRoundedRect(ctx, m_pos.x() + 1.0f, m_pos.y() + 1.0f, m_size.y() - 2.0f, 76 | m_size.y() - 2.0f, 3); 77 | nvgFillPaint(ctx, bg); 78 | nvgFill(ctx); 79 | 80 | if (m_checked) { 81 | nvgFontSize(ctx, icon_scale() * m_size.y()); 82 | nvgFontFace(ctx, "icons"); 83 | nvgFillColor(ctx, m_enabled ? m_theme->m_icon_color 84 | : m_theme->m_disabled_text_color); 85 | nvgTextAlign(ctx, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); 86 | nvgText(ctx, m_pos.x() + m_size.y() * 0.5f + 1, 87 | m_pos.y() + m_size.y() * 0.5f, utf8(m_theme->m_check_box_icon).data(), 88 | nullptr); 89 | } 90 | } 91 | 92 | NAMESPACE_END(nanogui) 93 | -------------------------------------------------------------------------------- /include/nanogui/traits.h: -------------------------------------------------------------------------------- 1 | /* 2 | NanoGUI was developed by Wenzel Jakob . 3 | The widget drawing code is based on the NanoVG demo application 4 | by Mikko Mononen. 5 | 6 | All rights reserved. Use of this source code is governed by a 7 | BSD-style license that can be found in the LICENSE.txt file. 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | 14 | NAMESPACE_BEGIN(nanogui) 15 | 16 | /// Listing of various field types that can be used as variables in shaders 17 | enum class VariableType { 18 | Invalid = 0, 19 | Int8, 20 | UInt8, 21 | Int16, 22 | UInt16, 23 | Int32, 24 | UInt32, 25 | Int64, 26 | UInt64, 27 | Float16, 28 | Float32, 29 | Float64, 30 | Bool 31 | }; 32 | 33 | /// Convert from a C++ type to an element of \ref VariableType 34 | template constexpr VariableType get_type() { 35 | if constexpr (std::is_same_v) 36 | return VariableType::Bool; 37 | 38 | if constexpr (std::is_integral_v) { 39 | if constexpr (sizeof(T) == 1) 40 | return std::is_signed_v ? VariableType::Int8 : VariableType::UInt8; 41 | else if constexpr (sizeof(T) == 2) 42 | return std::is_signed_v ? VariableType::Int16 : VariableType::UInt16; 43 | else if constexpr (sizeof(T) == 4) 44 | return std::is_signed_v ? VariableType::Int32 : VariableType::UInt32; 45 | else if constexpr (sizeof(T) == 8) 46 | return std::is_signed_v ? VariableType::Int64 : VariableType::UInt64; 47 | } else if constexpr (std::is_floating_point_v) { 48 | if constexpr (sizeof(T) == 2) 49 | return VariableType::Float16; 50 | else if constexpr (sizeof(T) == 4) 51 | return VariableType::Float32; 52 | else if constexpr (sizeof(T) == 8) 53 | return VariableType::Float64; 54 | } else { 55 | return VariableType::Invalid; 56 | } 57 | } 58 | 59 | /// Return the size in bytes associated with a specific variable type 60 | extern NANOGUI_EXPORT size_t type_size(VariableType type); 61 | 62 | /// Return the name (e.g. "uint8") associated with a specific variable type 63 | extern NANOGUI_EXPORT const char *type_name(VariableType type); 64 | 65 | namespace detail { 66 | /// Detector pattern that is used to drive many type traits below 67 | template typename Op, typename Arg> 68 | struct detector : std::false_type { }; 69 | 70 | template