Elements C++ GUI library

Elements-Logo Elements C++ GUI library

CMake Build Matrix

alt Photon Sampler

Introduction

Elements is a lightweight, fine-grained, resolution independent, modular GUI library. Elements is designed with these requirements in mind:

  1. It should be open source with a liberal, non-viral license.
  2. It should be usable in any application and should play well with other GUI libraries and frameworks.
  3. Corollary to the second requirement is that it can also be used to develop plugins. It should not own the event loop and should be able to co-exist with components within a plugin host such as VST and AU.
  4. It should be resolution independent and allow for HDPI displays.
  5. Should not rely on a “visual” GUI editor or code generator.
  6. It should have a declarative API using modern C++. Declarative C++ code tells you what rather than how (imperative). The GUI should be declared in C++ code.
  7. Keep it simple. Make it easy to use right out of the box, with a lot of examples.
  8. Porting to a new host target should be as easy as possible, requiring porting of only a few files.

Elements, is extremely lightweight… and modular. You compose very fine-grained, flyweight “elements” to form deep element hierarchies using a declarative interface with heavy emphasis on reuse.

Status

Please take note that Elements is still very much in flux as we are inching closer towards a version 1.0 release. The API and code is still undergoing continuous changes, and for that matter, Elements is not yet "production ready". But that should not prevent you from using Elements now! It is already in a very usable form, and more people using it will ultimately make it more robust when bugs are reported and fixed. API and usability matters and I very much welcome suggestions and contributions. Hey, this is an open source project! If you like the design, concepts and ideas behind Elements, I very much welcome collaboration.

News

  • 19 January 2020: Added Child Windows to develop (will merge to master in due time). See Example.
  • 25 September 2020: Added thumbwheels.
  • 12 September 2020: Linux Artist 2D Canvas Library port feature complete.
  • 10 September 2020: Windows Artist 2D Canvas Library port feature complete.
  • 7 September 2020: MacOS Artist 2D Canvas Library port feature complete.
  • 22 June 2020: Removed dependency on Boost. This requires some API changes to the app with additional arguments. See examples.
  • 26 May 2020: Introducing the Artist 2D Canvas Library. The Artist library will eventually replace Element's 2d canvas implementation.
  • 23 May 2020: Work in progress notebook gallery factory (notebook branch).
  • 8 April 2020: Simplified installation (Infra and Json are now header-only submodules)
  • 11 March 2020: Added Layout documentation.
  • 3 March 2020: Added Design Aspects documentation.
  • 23 February 2020: Setup and Installation guide updated for Windows and Linux.
  • 22 February 2020: Improved font support
  • 01 September 2019: Linux port completed
  • 12 August 2019: Windows port completed

Discord

Feel free to join the discord channel for discussion and chat with the developers.

Documentation

Documentation is work in progress. Stay tuned...

  1. Gallery
  2. Setup and Installation
  3. Design Aspects
  4. Layout

About the Author

Joel got into electronics and programming in the 80s because almost everything in music, his first love, is becoming electronic and digital. Since then, he builds his own guitars, effect boxes and synths. He enjoys playing distortion-laden rock guitar, composes and produces his own music in his home studio.

Joel de Guzman is the principal architect and engineer at Cycfi Research and a consultant at Ciere Consulting. He is a software engineer specializing in advanced C++ and an advocate of Open Source. He has authored a number of highly successful Open Source projects such as Boost.Spirit, Boost.Phoenix and Boost.Fusion. These libraries are all part of the Boost Libraries, a well respected, peer-reviewed, Open Source, collaborative development effort.


Copyright (c) 2014-2020 Joel de Guzman. All rights reserved. Distributed under the MIT License

Comments
  • tab widget

    tab widget

    I would like to implement tab (and some other widgets) but I need some guidance regarding library's code - everything is so composable that I have a feeling I will write duplicated code most of time time.

    I have read the post and checked how button is implemented (array composite of 2 elements) but I still don't get many things:

    • What is the purpose of _base types? That is, proxy vs proxy_base, composite vs composite_base etc
    • Why do various elements are class templates and inherit from typename Base? What's the benefit of doing this over just inheriting from element?
      • Are there any restrictions on the inheritance (eg Base must be element or a type derived from it)?
    • I figured out that the support directory is a collection of helpers (implementation details etc) but what is the reliation of element/* to element/gallery/*? Both directory trees contain button header and source - their reliation/dependency is unclear to me.
    • What are some very good widget example implementations that I should look at when implementing other widgets (eg if I would like to implement radio box, I should surely check check box)?
  • async task in the background

    async task in the background

    I have some options which perform longer tasks (eg downloading some data) and obviously they are taking too much time to wait for them in the callback itself.

    How would I implement such callbacks within elements? You said earlier about the view::post which works similarly to boost asio. Can you give me an example?

    I can do something like this but I have no way to check when the future is ready:

    std::future<result_t> long_task(atomic_struct&, /* ... */);
    
    user_state state; // persistent struct that holds all user stuff
    
    button.on_click = [&state](bool)
    {
        state.task_result = long_task(state.progress_info, /* ... */);
    };
    
    void report_progress(atomic_struct const&); // A
    void use_result(result_t const&); // B
    

    I need to:

    A) update the UI (eg progress bar) while the future is not yet ready (on every frame) B) trigger some code when the future is ready

  • CMake assumes MSVC compiler on Windows

    CMake assumes MSVC compiler on Windows

    The following things break using GCC on Windows:


    https://github.com/cycfi/elements/blob/9e73461a0520bd13c74969e35a3a5939dc3618d0/lib/CMakeLists.txt#L23-L34

    It's recommended to avoid touching internal CMake compiler/linker flags as they are very fragile and may prevent other (modern) CMake features from working.

    The bigger problem is that these flags are global and any project messing with them will impact and can break any other project which uses this library.

    I'd recommend to use generator expressions instead and limit their scope to the target:

    target_compile_options(libelements PRIVATE
        $<$<CXX_COMPILER_ID:GNU>:-Wno-missing-braces -Wno-comma -ftemplate-backtrace-limit=0>
        $<$<CXX_COMPILER_ID:Clang>:-Wno-missing-braces -Wno-comma -ftemplate-backtrace-limit=0>
        $<$<CXX_COMPILER_ID:MSVC>:/wd4244 /wd4305 /wd4996 /wd4267 /wd4018>
    )
    
    

    There are multiple ifs which change recipe behaviour on Windows, but they all are MSVC-specific.

    https://github.com/cycfi/elements/blob/9e73461a0520bd13c74969e35a3a5939dc3618d0/lib/CMakeLists.txt#L39-L49

    Such code fragments should use if(MSVC) at least, or go with target properties approach.


    https://github.com/cycfi/elements/blob/9e73461a0520bd13c74969e35a3a5939dc3618d0/lib/CMakeLists.txt#L178-L182

    Such lines should use preferred names instead of variables (that is, Boost::filesystem for each compiled library and/or Boost::boost for all header-only libraries)

    See https://cliutils.gitlab.io/modern-cmake/chapters/packages/Boost.html


    https://github.com/cycfi/elements/blob/9e73461a0520bd13c74969e35a3a5939dc3618d0/CMakeMain.txt#L93-L98

    This is currently my biggest offeder. It directly breaks GCC on Windows by disabling modern CMake features, resulting in g++ -03 -DNDEBUG compiler flags only, resulting in fatal error of no input files. It probably also poisons any other project (CMAKE_* are global flags) but I haven't tried including Elements in any of my projects yet.

  • minimum widget size limiter factory function

    minimum widget size limiter factory function

    The problem: I want to have a grid of labels and input boxes like the following (# means writeable area):

    +-----------------------------------------+----------------+
    | path to foo                             | ############## |
    +-----------------------------------------+----------------+
    | path to bar                             | ############## |
    +-----------------------------------------+----------------+
    | very long path description to something | ############## |
    +-----------------------------------------+----------------+
    

    There are 2 possible approaches:

    1. tile columns
    htile(
    	vtile(
    		align_middle(align_left(label("path to foo"))),
    		align_middle(align_left(label("path to bar"))),
    		align_middle(align_left(label("very long path description to something")))
    	),
    	vtile(
    		input_box().first,
    		input_box().first,
    		input_box().first
    	)
    )
    
    1. tile rows
    vtile(
    	htile(
    		align_middle(align_left(label("path to foo"))),
    		input_box().first,
    	),
    	htile(
    		align_middle(align_left(label("path to bar"))),
    		input_box().first,
    	),
    	htile(
    		align_middle(align_left(label("very long path description to something"))),
    		input_box().first,
    	)
    )
    

    1. has the problem that if I stretch the window horizontally, labels also stretch (_ means wasted space that I would like to be given to input boxes):
    +------------------------------------------------+------------------------+
    | path to foo                             ______ | ###################### |
    +------------------------------------------------+------------------------+
    | path to bar                             ______ | ###################### |
    +------------------------------------------------+------------------------+
    | very long path description to something ______ | ###################### |
    +------------------------------------------------+------------------------+
    
    1. has the problem that input boxes are not the same size which IMO looks ugly:
    +-----------------------------------------+----------------+
    | path to foo | ########################################## |
    +-----------------------------------------+----------------+
    | path to bar | ########################################## |
    +-----------------------------------------+----------------+
    | very long path description to something | ############## |
    +-----------------------------------------+----------------+
    

    I have no idea how to fix 2) but 1) could be easily fixed by changing behavior of labels so that they do not stretch and always occupy minimal required space.

    For 1) we can implement factories which will override this behavior - very similar to existing v/hmin_size but without an explicit paramater - the factory should adapt to actually minimal required size of the provided widget.

    template <typename Subject>
    auto hmin_required_size(Subject&& subject);
    
    template <typename Subject>
    auto vmin_required_size(Subject&& subject);
    
    template <typename Subject>
    auto min_required_size(Subject&& subject);
    
  • Example hello_universe, throws exception because image is missing

    Example hello_universe, throws exception because image is missing

    Seems as though the path given:

       view_.content(
          scroller(image{ "space.jpg" })
       );
    

    Is searching inside of the empty example directory, which doesn't have a space.jpg image.

  • Help using elements as a library?

    Help using elements as a library?

    I'm very excited about elements--it's exactly what I've wanted for a very long time! Unfortunately, as I'm pretty new to cmake, I'm having difficulty getting started with a project of my own that uses it.

    I've built elements and can run the examples on both Windows 10 and macos--no problem. What I'm trying to figure out is how to define a CMakeLists.txt from my project to use elements as a STATIC IMPORTED library.

    My main contains the code from the empty window example, but as of yet fails to compile. Please see output below.

    I'm sure I'm doing something silly. A gentle shove in the right direction would be greatly appreciated.

    My CMakeLists.txt:

    cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
    
    project(Multimind LANGUAGES CXX)
    
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
    
    add_library(elements STATIC IMPORTED)
    set_target_properties(elements
            PROPERTIES
                IMPORTED_LOCATION "../libs/elements/build/lib/elements.lib"
            )
    
    add_library(cairo STATIC IMPORTED)
    set_target_properties(cairo
            PROPERTIES
            IMPORTED_LOCATION "../libs/elements/lib/external/cairo/lib/x64/cairo.lib"
            )
    
    add_library(fontconfig STATIC IMPORTED)
    set_target_properties(elements
            PROPERTIES
            IMPORTED_LOCATION "../libs/elements/lib/external/fontconfig/x64/fontconfig.lib"
            )
    
    add_library(freetype STATIC IMPORTED)
    set_target_properties(elements
            PROPERTIES
            IMPORTED_LOCATION "../libs/elements/lib/external/freetype/win64/freetype.lib"
            )
    
    set(EXEC_SOURCE_FILES
                main.cpp
                Multimind.cpp
            )
    add_executable(Multimind ${EXEC_SOURCE_FILES})
    set_target_properties(Multimind
            PROPERTIES
                CXX_STANDARD 17
                CXX_EXTENSIONS OFF
                CXX_STANDARD_REQUIRED ON
            )
    
    target_link_libraries(Multimind elements)
    
    include_directories("../libs/elements/lib/include")
    include_directories("../libs/elements/lib/infra/include")
    include_directories("../libs/elements/lib/external/cairo/include")
    include_directories("../libs/elements/lib/external/fontconfig/include")
    include_directories("../libs/elements/lib/external/freetype/include")
    
    message(STATUS "Compiler is: " ${CMAKE_CXX_COMPILER_ID})
    

    Console output when trying to build:

    ====================[ Build | all | Debug ]=====================================
    "C:\Program Files\JetBrains\CLion 2019.3.5\bin\cmake\win\bin\cmake.exe" --build C:\Users\Radagan\Development\cpp\Multimind\cmake-build-debug --target all
    Scanning dependencies of target Multimind
    [ 33%] Building CXX object CMakeFiles/Multimind.dir/main.cpp.obj
    main.cpp
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/base_view.hpp(298): error C2061: syntax error: identifier 'host_window_handle'
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/base_view.hpp(318): error C3646: 'host': unknown override specifier
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/base_view.hpp(318): error C2059: syntax error: '('
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/base_view.hpp(318): error C2334: unexpected token(s) preceding '{'; skipping apparent function body
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/base_view.hpp(322): error C3646: '_view': unknown override specifier
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/base_view.hpp(322): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/window.hpp(60): error C3646: 'host': unknown override specifier
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/window.hpp(60): error C2059: syntax error: '('
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/window.hpp(60): error C2334: unexpected token(s) preceding '{'; skipping apparent function body
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/window.hpp(70): error C3646: '_window': unknown override specifier
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/window.hpp(70): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    C:\Users\Radagan\Development\cpp\libs\elements\lib\include\elements/view.hpp(17): fatal error C1083: Cannot open include file: 'boost/asio.hpp': No such file or directory
    NMAKE : fatal error U1077: 'C:\PROGRA~2\MICROS~2\2019\COMMUN~1\VC\Tools\MSVC\1425~1.286\bin\Hostx86\x86\cl.exe' : return code '0x2'
    Stop.
    NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\bin\HostX86\x86\nmake.exe"' : return code '0x2'
    Stop.
    NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\bin\HostX86\x86\nmake.exe"' : return code '0x2'
    Stop.
    
  • tidying up json and infra dependencies

    tidying up json and infra dependencies

    Right now elements depends on infra and json, which itself depends on infra.

    I have a problem with filesystem because certain range of GCC and Clang versions require an extra flag to link to it. I would like to make in an explicit CMake option because as I stated in https://github.com/cycfi/infra/issues/4 there is no good approach to it so IMO the most flexible solution would be to let user decide. Then, having such option I can downstream it to any dependants (including elements).

    There is however a different problem: elements and json does not link to infra, not in the CMake way. Currently the both CMake recipes are just providing include paths to them, which is wrong because they should link to their targets instead and expect complete definitions there. Otherwise we duplicate recipes and leak target definition to dependant projects.

    My current plan:

    • add filesystem flags options to infra
    • edit json recipe to actually depend on infra instead of adding its include paths (and during the way also modernize the recipe a bit)
    • edit elements recipe to actually depend on json instead of adding its include paths
    • remove elements/infra submodule - it is already a submodule of json on which elements depends
    • update elements documentation: when cloning the repository, clone recursively submodules too

    Then we can have a straight dependency chain (infra => json => elements) and targets depending on elements can get downstreated infra settings (eg filesystem linker options).

    Any objections?

  • flowable segfaults after clearing and pushing less elements than on previous render

    flowable segfaults after clearing and pushing less elements than on previous render

    Apply this patch and enjoy the crashes!

    diff --git a/examples/layout/main.cpp b/examples/layout/main.cpp
    index c97e5c3..0ed1c91 100644
    --- a/examples/layout/main.cpp
    +++ b/examples/layout/main.cpp
    @@ -144,28 +144,37 @@ auto make_htile_mixed()
        );
     }
    
    +auto num_elements = 400;
    +
     auto make_flow()
     {
        constexpr auto line_height = 30;
        constexpr auto min_size = 10;
        constexpr auto max_width = 100;
        constexpr auto max_height = line_height;
    -   constexpr auto num_elements = 40;
    
        static auto c = flow_composite{};
    -   for (int i = 0; i < num_elements; ++i)
    -   {
    -      auto w = min_size + ((double(std::rand()) * (max_width - min_size)) / RAND_MAX);
    -      auto h = min_size + ((double(std::rand()) * (max_height - min_size)) / RAND_MAX);
    -      auto _box = vsize(line_height, align_bottom(margin(
    -         { 5, 5, 5, 5 }, fixed_size({ float(w), float(h) }, rbox_)
    -      )));
    -      c.push_back(share(_box));
    -   }
    +
    +   auto btn = button("new tiles");
    +   btn.on_click = [&](bool) {
    +      c.clear();
    +      for (int i = 0; i < num_elements; ++i)
    +      {
    +        auto w = min_size + ((double(std::rand()) * (max_width - min_size)) / RAND_MAX);
    +        auto h = min_size + ((double(std::rand()) * (max_height - min_size)) / RAND_MAX);
    +        auto _box = vsize(line_height, align_bottom(margin(
    +          { 5, 5, 5, 5 }, fixed_size({ float(w), float(h) }, rbox_)
    +        )));
    +        c.push_back(share(_box));
    +      }
    +      num_elements -= 150;
    +   };
    +
    +   btn.on_click(false);
    
        auto flow_pane = margin(
           { 0, 50, 10, 10 },
    -      align_top(flow(c))
    +      vtile(btn, align_top(flow(c)))
        );
    
        return margin({ 10, 10, 10, 10 },
    

    Now, to the actual issue, here are my observations:

    The segfault occurs in htile::limits on line auto el = at(i).limits(ctx);. There is a broken lifetime:

    Thread 1 received signal SIGSEGV, Segmentation fault.
    0x00000000004409b6 in cycfi::elements::htile_element::limits (this=0xd209d90,
        ctx=...)
        at [...]/lib/src/element/tile.cpp:182
    182              auto el = at(i).limits(ctx);
    (gdb) print this->size()
    $1 = 2
    (gdb) print i
    $2 = 1
    (gdb) print this->at(0)
    $3 = (cycfi::elements::element &) @0xa81eeb0: {<std::enable_shared_from_this<cycfi::elements::element>> = {
        _M_weak_this = {<std::__weak_ptr<cycfi::elements::element, (__gnu_cxx::_Lock_policy)2>> = {_M_ptr = 0xa81eeb0, _M_refcount = {
              _M_pi = 0xa81eea0}}, <No data fields>}},
      _vptr.element = 0x4c7b10 <vtable for item_preview+16>}
    (gdb) print this->at(1)
    $4 = (cycfi::elements::element &) @0xa823150: {<std::enable_shared_from_this<cycfi::elements::element>> = {
        _M_weak_this = {<std::__weak_ptr<cycfi::elements::element, (__gnu_cxx::_Lock_policy)2>> = {_M_ptr = 0xfeeefeeefeeefeee, _M_refcount = {
              _M_pi = 0xfeeefeeefeeefeee}}, <No data fields>}},
      _vptr.element = 0xfeeefeeefeeefeee}
    

    The element at index 1 is already dead at this point.

    I strongly suspect this code:

    https://github.com/cycfi/elements/blob/1f5ba55f6f5222eb1585f431499b29f145916daa/lib/src/element/flow.cpp#L64-L68

    For each row, it creates an instance of range composite which only holds a reference to the container and copies of the indexes. I think this breaks when flowable container contents are changed, if there are less elements in flowable later then this causes access out of bounds because new flow has less rows.

  • refreshing issues

    refreshing issues

    So I have started to work a bit with buttons and menus (I'm a bit unsatisfied with the API but that will be a separate issue) and noticed a common problem: refreshing

    • Sometimes a button performs an action that modifies or adds other UI elements, and they do not render correctly when not refreshed, but the having to capture so many shared pointers quickly gets out of hand.
    • Sometimes refreshing does not help. Refresh a label, it's new text is rendered but if the space occupied by the text is different (eg larger) it is rendered on top of surrounding elements, which still use its old size. As if I had to refresh few levels higher in the hierarchy - resizing the window fixes the problem (which AFAIK refreshes everything).
  • linker fail after adding radio button

    linker fail after adding radio button

    104cef3cc19bf6f568b233a29679135a2c1f06ca - the commit before builds, but checkouting this gives me a linker error:

    "C:\Program Files\CMake\bin\cmake.exe" -E remove -f CMakeFiles\EmptyStarter.dir/objects.a
    C:\mingw64\mingw64\bin\gcc-ar.exe cr CMakeFiles\EmptyStarter.dir/objects.a @CMakeFiles\EmptyStarter.dir\objects1.rsp
    C:\mingw64\mingw64\bin\g++.exe -O3 -DNDEBUG -flto -fno-fat-lto-objects  -mwindows -Wl,--whole-archive CMakeFiles\EmptyStarter.dir/objects.a -Wl,--no-whole-archive  -o D:\Files\C++\workspace_windows\filter_spirit\build\release\bin\EmptyStarter.exe -Wl,--out-implib,D:\Files\C++\workspace_windows\filter_spirit\build\release\bin\libEmptyStarter.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles\EmptyStarter.dir\linklibs.rsp
    C:/mingw64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.1/../../../../x86_64-w64-mingw32/bin/ld.exe: radio_button.cpp.obj (symbol from plugin):(.gnu.linkonce.t._ZN5cycfi8elements18basic_radio_buttonD1Ev[_ZThn208_N5cycfi8elements18basic_radio_buttonD1Ev]+0x0): multiple definition of `cycfi::elements::basic_radio_button::~basic_radio_button()'; main.cpp.obj (symbol from plugin):(.gnu.linkonce.t._ZN5cycfi8elements18basic_radio_buttonD1Ev[_ZThn24_N5cycfi8elements18basic_radio_buttonD1Ev]+0x0): first defined here
    C:/mingw64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.1/../../../../x86_64-w64-mingw32/bin/ld.exe: radio_button.cpp.obj (symbol from plugin):(.gnu.linkonce.t._ZN5cycfi8elements18basic_radio_buttonD1Ev[_ZThn208_N5cycfi8elements18basic_radio_buttonD1Ev]+0x0): multiple definition of `non-virtual thunk to cycfi::elements::basic_radio_button::~basic_radio_button()'; main.cpp.obj (symbol from plugin):(.gnu.linkonce.t._ZN5cycfi8elements18basic_radio_buttonD1Ev[_ZThn24_N5cycfi8elements18basic_radio_buttonD1Ev]+0x0): first defined here
    C:/mingw64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.1/../../../../x86_64-w64-mingw32/bin/ld.exe: radio_button.cpp.obj (symbol from plugin):(.gnu.linkonce.t._ZN5cycfi8elements18basic_radio_buttonD1Ev[_ZThn208_N5cycfi8elements18basic_radio_buttonD1Ev]+0x0): multiple definition of `non-virtual thunk to cycfi::elements::basic_radio_button::~basic_radio_button()'; main.cpp.obj (symbol from plugin):(.gnu.linkonce.t._ZN5cycfi8elements18basic_radio_buttonD1Ev[_ZThn24_N5cycfi8elements18basic_radio_buttonD1Ev]+0x0): first defined here
    collect2.exe: error: ld returned 1 exit status
    

    Checking what could cause the error, I'm basically gettting multiple definitions of some virtual tables and the basic_radio_button destructor.

    Things I noted so far:

    • There is no diamond inheritance problem.
    • Currently I can not build anything past 104cef3cc19bf6f568b233a29679135a2c1f06ca, but yesterday I made a #68 PR and I actually build this one
    • I'm getting a CMake warning about INTERPROCEDURAL_OPTIMIZATION property and policy 0069. Divergence in linker settings can actually create problems when LTO is (not) applied and some targets expects or do not expect certain symbols. GCC is known to have problems in some cases with targets with different linker flags.
  • leaks in font map

    leaks in font map

    Welcome to another episode of Why I hate global variables although this time the problem is more due to a lack of RAII (nonetheless I would like to get rid of as many globals as possible, possibly moving them to instantiate by library users explicitly).

    Whenever I close any of examples which has some text, I'm getting SPAMMED with this and similar:

    Indirect leak of 192 byte(s) in 6 object(s) allocated from:
        #0 0x7fbc79fc7f90 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xedf90)
        #1 0x7fbc78f958ed in FcStrSetCreate (/usr/lib/x86_64-linux-gnu/libfontconfig.so.1+0x218ed)
        #2 0x55564e0f315b in match /home/xeverous/workspace/elements/lib/src/support/font.cpp:221
        #3 0x55564e0f4baa in cycfi::elements::font::font(cycfi::elements::font_descr) /home/xeverous/workspace/elements/lib/src/support/font.cpp:292
        #4 0x55564e04f292 in cycfi::elements::theme::theme() /home/xeverous/workspace/elements/lib/src/support/theme.cpp:71
        #5 0x55564e0511b7 in cycfi::elements::global_theme::_theme() /home/xeverous/workspace/elements/lib/src/support/theme.cpp:78
        #6 0x55564e05121a in cycfi::elements::get_theme() /home/xeverous/workspace/elements/lib/src/support/theme.cpp:84
        #7 0x55564dfe84d8 in cycfi::elements::default_label::font_size() const (/home/xeverous/workspace/elements/build/examples/doc_aspects/Aspects+0x3b94d8)
        #8 0x55564e007af0 in cycfi::elements::default_label::limits(cycfi::elements::basic_context const&) const /home/xeverous/workspace/elements/lib/src/element/label.cpp:16
        #9 0x55564dff2588 in cycfi::elements::margin_element<cycfi::elements::rect, cycfi::elements::label_gen<cycfi::elements::basic_label_base<cycfi::elements::default_label> > >::limits(cycfi::elements::basic_context const&) const (/home/xeverous/workspace/elements/build/examples/doc_aspects/Aspects+0x3c3588)
        #10 0x55564e00ab88 in cycfi::elements::layer_element::limits(cycfi::elements::basic_context const&) const /home/xeverous/workspace/elements/lib/src/element/layer.cpp:20
        #11 0x55564e01d5cd in cycfi::elements::slider_base::limits(cycfi::elements::basic_context const&) const /home/xeverous/workspace/elements/lib/src/element/slider.cpp:16
        #12 0x55564dff2040 in cycfi::elements::halign_element<cycfi::elements::basic_slider<cycfi::elements::composite<std::array<std::shared_ptr<cycfi::elements::element>, 2ul>, cycfi::elements::layer_element>&, cycfi::elements::hsize_element<cycfi::elements::box_element>&, cycfi::elements::basic_slider_base> >::limits(cycfi::elements::basic_context const&) const (/home/xeverous/workspace/elements/build/examples/doc_aspects/Aspects+0x3c3040)
        #13 0x55564e00ab88 in cycfi::elements::layer_element::limits(cycfi::elements::basic_context const&) const /home/xeverous/workspace/elements/lib/src/element/layer.cpp:20
        #14 0x55564e0a0145 in cycfi::elements::indirect<cycfi::elements::reference<cycfi::elements::composite<std::vector<std::shared_ptr<cycfi::elements::element>, std::allocator<std::shared_ptr<cycfi::elements::element> > >, cycfi::elements::layer_element> > >::limits(cycfi::elements::basic_context const&) const (/home/xeverous/workspace/elements/build/examples/doc_aspects/Aspects+0x471145)
        #15 0x55564e08c507 in cycfi::elements::scale_element<cycfi::elements::indirect<cycfi::elements::reference<cycfi::elements::composite<std::vector<std::shared_ptr<cycfi::elements::element>, std::allocator<std::shared_ptr<cycfi::elements::element> > >, cycfi::elements::layer_element> > > >::limits(cycfi::elements::basic_context const&) const /home/xeverous/workspace/elements/lib/include/elements/element/size.hpp:608
        #16 0x55564e05b558 in cycfi::elements::view::set_limits() /home/xeverous/workspace/elements/lib/src/view.cpp:53
        #17 0x55564dfeac66 in void cycfi::elements::view::content<cycfi::elements::halign_element<cycfi::elements::basic_slider<cycfi::elements::composite<std::array<std::shared_ptr<cycfi::elements::element>, 2ul>, cycfi::elements::layer_element>&, cycfi::elements::hsize_element<cycfi::elements::box_element>&, cycfi::elements::basic_slider_base> >, cycfi::elements::box_element&>(cycfi::elements::halign_element<cycfi::elements::basic_slider<cycfi::elements::composite<std::array<std::shared_ptr<cycfi::elements::element>, 2ul>, cycfi::elements::layer_element>&, cycfi::elements::hsize_element<cycfi::elements::box_element>&, cycfi::elements::basic_slider_base> >&&, cycfi::elements::box_element&) (/home/xeverous/workspace/elements/build/examples/doc_aspects/Aspects+0x3bbc66)
        #18 0x55564dfe4d28 in main /home/xeverous/workspace/elements/examples/doc_aspects/main.cpp:96
        #19 0x7fbc7690bb96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    
    SUMMARY: AddressSanitizer: 128202 byte(s) leaked in 4154 allocation(s).
    

    init_font_map() is allocating some resources, but there is no counterpart. This function should be a member of come font-map-type constructor and have a respective destructor.

  • Update canvas transform functions

    Update canvas transform functions

    Different methods are needed for distance conversions and coordinate conversions. See issue

    Fixed:

    • canvas::device_to_user
    • canvas::user_to_device

    Added:

    • canvas::device_to_user_distance
    • canvas::user_to_device_distance
  • device_to_user point conversion

    device_to_user point conversion

    Hi! Why does the canvas::device_to_user method use cairo_device_to_user_distance instead of cairo_device_to_user?

    Because of this, an unpleasant effect is observed:

    canvas.translate({10, 10});
    
    point p{0, 0};
    auto up = canvas.device_to_user(p);
    assert(up != p); // Fail!
    

    The distance in both systems is the same, but the coordinate must be different

  • Are there menu buttons intended for top menus ?

    Are there menu buttons intended for top menus ?

    Hi, I was wondering if elements has a widget relative to top menus ? (the ones for "file" "edit" "help" etc) because I tried to make one atm using standard menu buttons but it doesn't feel as good as the usual top menus because for instance moving the mouse won't make switch to the next dropdown and they also don't really feel connected, also uually in top menus there aren't down arrows Capture d’écran du 2022-09-22 18-37-30

  • Implement X11 host UI

    Implement X11 host UI

    This PR adds a straight Xlib host UI implementation. It also provides a couple of amenities for developing plugins, ~namely allowing providing a native_window_handle to constructors to allow client code to manage window creation~, and app::tick() for running a single UI iteration.

    It is still a work in progress. Notable limitations:

    • [x] The other ports do not handle the native_window_handle argument to the window constructor
    • [ ] The clipboard is not implemented
    • [x] Double clicks are not yet detected
    • [ ] Display scaling is not detected; this may require some opportunistic hacks or DBus calls, I have not researched.
    • [ ] IME handling for non-English languages is basically untested (pointers on "easy mode" for testing e.g. pinyin input would be greatly appreciated)
    • [x] The macOS port doesn't build because apparently Objective C classes (NSWindow) cannot be named from pure C++ code - still figuring this out.
  • GTK complains about command-line arguments

    GTK complains about command-line arguments

    If you try to launch any of the examples from master branch with additional command-line argument, GTK complains and closes the application:

    $ ./examples/empty/EmptyStarter .
    
    (EmptyStarter:29297): GLib-GIO-CRITICAL **: 20:49:57.956: This application can not open files.
    
    (EmptyStarter:29297): GLib-GObject-CRITICAL **: 20:49:57.958: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
    

    Passing 1 instead of argc to app constructor works around that, but it doesn't feel too good. I also tried patching elements, replacing G_APPLICATION_FLAGS_NONE with G_APPLICATION_HANDLES_OPEN and G_APPLICATION_HANDLES_COMMAND_LINE, but it appears to be just another can with worms, with GTK complaining about missing handlers.

This is a collection of widgets and utilities for the immediate mode GUI (imgui) that I am developing for the critic2 GUI
This is a collection of widgets and utilities for the immediate mode GUI (imgui) that I am developing for the critic2 GUI

ImGui Goodies This is a collection of widgets and utilities for the immediate mode GUI (imgui) that I am developing for the critic2 GUI. Currently, th

Nov 19, 2022
Minimalistic C++/Python GUI library for OpenGL, GLES2/3, Metal, and WebAssembly/WebGL
Minimalistic C++/Python GUI library for OpenGL, GLES2/3, Metal, and WebAssembly/WebGL

NanoGUI NanoGUI is a minimalistic cross-platform widget library for OpenGL 3+, GLES 2/3, and Metal. It supports automatic layout generation, stateful

Dec 28, 2022
A single-header ANSI C immediate mode cross-platform GUI library
A single-header ANSI C immediate mode cross-platform GUI library

Nuklear This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed a

Dec 24, 2022
A library for creating native cross-platform GUI apps

Yue A library for creating native cross-platform GUI apps. Getting started Documentations FAQ Development Examples Sample apps (with screenshots) Muba

Jan 7, 2023
A barebones single-header GUI library for Win32 and X11.
A barebones single-header GUI library for Win32 and X11.

luigi A barebones single-header GUI library for Win32 and X11. Building example Windows Update luigi_example.c to #define UI_WINDOWS at the top of the

Dec 30, 2022
✔️The smallest header-only GUI library(4 KLOC) for all platforms
✔️The smallest header-only GUI library(4 KLOC) for all platforms

Welcome to GUI-lite The smallest header-only GUI library (4 KLOC) for all platforms. 中文 Lightweight ✂️ Small: 4,000+ lines of C++ code, zero dependenc

Jan 8, 2023
Minimalistic GUI library for OpenGL
Minimalistic GUI library for OpenGL

NanoGUI NanoGUI is a minimalistic cross-platform widget library for OpenGL 3.x or higher. It supports automatic layout generation, stateful C++11 lamb

Jan 1, 2023
raygui is a simple and easy-to-use immediate-mode-gui library.
raygui is a simple and easy-to-use immediate-mode-gui library.

raygui is a simple and easy-to-use immediate-mode-gui library.

Dec 30, 2022
Cross-platform GUI library

Harbour Nuklear backend This backend provides support for Nuklear. It works on on all supported platforms with an OpenGL backend, including iOS and An

Jan 19, 2022
Fishui - CutefishOS GUI library, based on Qt Quick.

FishUI FishUI is a GUI library based on QQC2 (Qt Quick Controls 2), every Cutefish application uses it. Features Light and Dark Mode Borderless window

Dec 30, 2022
libui-ng: a portable GUI library for C
 libui-ng: a portable GUI library for C

libui-ng: a portable GUI library for C Fork of andlabs/libui. This README is being written. Status See CHANGELOG.md Old announcements can be found in

Jan 7, 2023
Nana is a C++ standard-like GUI library

Nana C++ Library Linux (gcc 8.3.0 and 9.2) including (nana-demos) Windows (Microsoft (R) Build Engine version 15.9.21) Nana is a C++ standard-like GUI

Jan 3, 2023
Examples, tutorials and applications for the LVGL embedded GUI library
Examples, tutorials and applications for the LVGL embedded GUI library

Examples, tutorials and applications for the LVGL embedded GUI library

Nov 11, 2022
Addon widgets for GUI library Dear ImGui.
Addon widgets for GUI library Dear ImGui.

ImGui-Addons Addon widgets for GUI library Dear ImGui. File Dialog A simple cross-platform file dialog that uses dirent interface for reading director

Jan 7, 2023
GWork is a skinnable, embeddable GUI library with an extensive control set

GWork is a skinnable, embeddable GUI library with an extensive control set. Control rendering is abstracted, and can be implemented by any application wishing to use the library. Gwork (pronounced "gw-orc") is a fork of the GUI library GWEN. It was forked to fix issues with GWEN and add new features.

Nov 24, 2022
The HorusUI library allows you to quickly develop GUIs for your applications by leveraging the ease of use provided by immediate mode GUI concepts.
The HorusUI library allows you to quickly develop GUIs for your applications by leveraging the ease of use provided by immediate mode GUI concepts.

Immediate Mode Graphical User Interface for Tools OVERVIEW The HorusUI library allows you to quickly develop GUIs for your applications by leveraging

Dec 12, 2022
HastyBadger is a branch of the excellent widget and GUI library Turbo Badger.

Branch Notice - HastyBadger Hasty is not Turbo. HastyBadger is a branch of the excellent widget and GUI library Turbo Badger. Notabe additions are c++

Nov 17, 2022
FlatUI is a immediate mode C++ GUI library for games and graphical applications.

FlatUI is a immediate mode C++ GUI library for games and graphical applications. Go to our landing page to browse our documentation.

Dec 23, 2022
Purely native C++ cross-platform GUI framework for Android and iOS development. https://www.boden.io
Purely native C++ cross-platform GUI framework for Android and iOS development. https://www.boden.io

BODEN CROSS-PLATFORM FRAMEWORK Build purely native cross-platform experiences with Boden Website ⬡ Getting Started ⬡ API Reference ⬡ Guides ⬡ Twitter

Dec 27, 2022