Giter Club home page Giter Club logo

elements's Introduction

Elements-Logo Elements C++ GUI library

CMake Build Matrix

Introduction

alt Elements Sampler

Elements is a lightweight, fine-grained, resolution-independent, extremely modular GUI library. The library is written using modern C++17 language features. It has a declarative interface with a sensible and easy-to-use Domain Specific Embedded Languages (DSEL) syntax for constructing the GUI elements. A declarative description of the GUI is written exclusively in C++, and therefore, there is no need for an external visual GUI editor or code generator.

Elements is embeddable, meaning you can embed it in any application, and it will play well with other GUI libraries and frameworks. This also implies that you can utilize it for the creation of plugins. It does not own the event loop and is able to co-exist with components within a plugin host, such as VST and AU. Porting to a new host target is straightforward, requiring the porting of only a few files.

Elements is distributed under the liberal and non-viral MIT License.

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

March 28, 2024: I decided to bring the Cairo-based backend of Elements back into the fold. It will be the master branch once again. The Skia backend version is still very much in active development, but it still needs a lot of testing and work, especially with the way Skia is integrated.

Follow this link for details.

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. 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-2024 Joel de Guzman. All rights reserved. Distributed under the MIT License

elements's People

Contributors

andersama avatar bold84 avatar czipperz avatar delta-dev-99 avatar dereksauer avatar djowel avatar dmacvicar avatar dpieve avatar eakoli avatar eisen avatar ex-purple avatar falktx avatar faywong avatar johannphilippe avatar jpcima avatar kcalbcube avatar klytje avatar melroy89 avatar na2axl avatar p-podsiadly avatar petiaccja avatar pkoretic avatar pragmatwice avatar redtide avatar samuel-rice avatar thirtythreeforty avatar volkanunal avatar way-how avatar xeverous avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elements's Issues

CMake assumes MSVC compiler on Windows

The following things break using GCC on Windows:


# Get rid of these warnings
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"
OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-braces -Wno-comma")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-backtrace-limit=0")
elseif (WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /wd4305 /wd4996 /wd4267 /wd4018")
endif()

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.

if (WIN32)
set(CAIRO_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/external/cairo/include)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CAIRO_LIBRARIES ${CMAKE_CURRENT_SOURCE_DIR}/external/cairo/lib/x64/cairo.lib)
else()
set(CAIRO_LIBRARIES ${CMAKE_CURRENT_SOURCE_DIR}/external/cairo/lib/x86/cairo.lib)
endif()
else()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
FIND_PACKAGE(CAIRO REQUIRED cairo)
endif()

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


elements/lib/CMakeLists.txt

Lines 178 to 182 in 9e73461

target_include_directories(libelements
PUBLIC include
${CAIRO_INCLUDE_DIRS}
${FREETYPE_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}

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


elements/CMakeMain.txt

Lines 93 to 98 in 9e73461

if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS}
/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup shcore.lib"
)

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.

Suggest hiding elements::app underneath the public api.

The very first example is

app _app(argc, argv);
.

It's quite generic for almost all kinds of GUI applications that having a similar GUI specific app being created from client code. And of cause, app writers will have to do a similar app.run() invocation to bring up the GUI message loop or similar stuffs.

But while reviewing elements, I found that it's quite good for super lightweight applications to offer some kind of viewable elements on screen for users. Well, here the application has wider definitions than just a GUI application. Meaning that real applications should have their own initialization process and some kind of message loops or even none of such things. These applications may just looking to show some window/view to users, get data quickly from users, and then get back into its own processing flow. Apps don't care about such a GUI app instance at all. Not even decoupling the main process with GUI subsystem.

So following this principle, I demonstrated a different example:

#include <elements.hpp>

void initialize_process()
{
  // Just initialise 
}

void finish_all_jobs()
{
  // Just finish the main processing flow, nothing related to the gui
  // subsystem!
}

// This should be safe to invoke from any thread!
void show_user_important_notice()
{
  namespace elements = cycfi::elements;
  using namespace cycfi::elements; // for share, box, rgba, etc. 

  // Apps just create a window to show some view any time.
  elements::window win("Important Notice");
  win.on_close = []{ /* report to the main processor */ };

  elements::view view(win);
  view.content({ share(box(rgba(35, 35, 37, 255))) });

  // Show up on screen.
  win.show();

# if false
  // Explicitly request to wait for closing the window.
  // It blocks the flow at the point.
  win.wait_for_close();
# endif
}

int main(int argc, const char* argv[])
{
  initialize_process();

  // This is to call GUI to do the job, but no any interruptions to the
  // major processing flow.
  show_user_important_notice(); // It shouldn't block here!

  // This could be the app's processing loop having nothing to do with
  // the GUI subsystem.
  finish_all_jobs();

  // It should be OPTIONAL to wait for quit signal. The GUI subsystem
  // should be highly isolated from the main process, it should be safe
  // to just quit without waiting (say if the main process flow has
  // longer lifetime than the GUI subsystem).
# if OPTIONAL_WAIT_FOR_GUI
  return elements::wait_quit_signal();
# else
  return 0; // Just return without waiting GUI.
# endif
}

Which should explain more.

Such a fast responsive super GUI system should suite more app development. Including non-gui-heavy apps or a daemon in the background to present something to users. Even a command line program can easily present a decent graphics on screen without coupling too much with the GUI system.

A GUI specific app instance is leading developers to easily messing up app processing and GUI processing.

So I suggest that elements as a latest implemented new GUI option, it should have special design on the point. It could be fully decoupled views and app logics since the beginning. (MVC?)

CMake problems are back: ELEMENTS_HOST_UI_LIBRARY

I have identified multiple problems with recent changes to support different host UI libraries

lib/include/elements/base_view.hpp:298:53: error: expected ')' before 'h'
  298 |                         base_view(host_window_handle h);
      |                                  ~                  ^~
      |                                                     )
lib/include/elements/base_view.hpp:318:7: error: 'host_view_handle' does not name a type
  318 |       host_view_handle  host() const { return _view; }
      |       ^~~~~~~~~~~~~~~~

Please, if you ever do any #ifdef stuff without a fallback always add an meaningful #else #error. This saves a ton of time for people who contribute and get the error like the above - the first thing I was searching were syntax/include errors but it's actually an #ifdef problem here:

#if defined(ELEMENTS_HOST_UI_LIBRARY_COCOA) || defined(ELEMENTS_HOST_UI_LIBRARY_GTK)
struct host_view;
using host_view_handle = host_view*;
struct host_window;
using host_window_handle = host_window*;
#elif defined(ELEMENTS_HOST_UI_LIBRARY_WIN32)
using host_view_handle = HWND;
using host_window_handle = HWND;
#endif

In my case, none of these was defined causing missing type definitions.


None of these are guuaranteed to work for descendant projects:

elements/CMakeLists.txt

Lines 40 to 55 in b5606c7

if(HOST_UI_LIBRARY STREQUAL "gtk")
add_definitions(-DELEMENTS_HOST_UI_LIBRARY_GTK)
elseif(HOST_UI_LIBRARY STREQUAL "cocoa")
add_definitions(-DELEMENTS_HOST_UI_LIBRARY_COCOA)
if(NOT APPLE)
message(FATAL_ERROR "Only macOS support HOST_UI_LIBRARY=cocoa")
endif()
elseif(HOST_UI_LIBRARY STREQUAL "win32")
add_definitions(-DELEMENTS_HOST_UI_LIBRARY_WIN32)
if(NOT WIN32)
message(FATAL_ERROR "Only Windows support HOST_UI_LIBRARY=win32")
endif()
else()
message(FATAL_ERROR "Invalid HOST_UI_LIBRARY=" ${HOST_UI_LIBRARY}
". Support gtk, cocoa and win32")
endif()

cmake.org/cmake/help/v3.17/command/add_definitions.html - directory-affecting (or directory-poisoning) commands are superseeded in modern CMake. Worse, they do not work at all for elements-descendant projects that do not put elements in their subdirectory.

These should be replaced with target_ commands with PUBLIC properties (not private because they are present in public headers). I will make a PR.

rich text label

This issue is for tracking any decisions before implementing this widget.

Wanted:

  • arbitrary text color in arbitrary places
  • arbitrary font support
  • bold, underline, italic

Need ideas how the widget data should be stored and how to offer a convenient API for adding/editing rich text. There is definitely a better way than a vector of "character" objects, each having color, font, bold, italic and underline variables.

app::app should not take const char**

Welcome to (one of the most unintuitive) type system corner cases. It is illegal to convert T** to const T**

The following code fails:

#include <elements/app.hpp>

int main(int argc, char** argv)
{
    cycfi::elements::app app(argc, argv); // invalid convertion for argv
}

https://stackoverflow.com/questions/48560778/intermediate-pointers-in-cast-must-be-const-qualified-why

http://c-faq.com/ansi/constmismatch.html

Current implementations of app:

  • Windows: both parameters ignored
  • MacOS: both parameters ignored
  • Linux: g_application_run(G_APPLICATION(_app), argc, const_cast<char**>(argv))

IMO the const_cast speaks for itself.

font_map segfault on startup on Windows

Something something font_map and static initialization before main(), debugging now. Seems an invalid key way given to operator[] (#2 in backtrace)

#0  0x000000006fd397ea in libstdc++-6!_ZSt9use_facetISt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEEERKT_RKSt6locale ()
#1  0x0000000000449194 in std::_Rb_tree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::vector<cycfi::elements::(anonymous namespace)::font_entry, std::allocator<cycfi::elements::(anonymous namespace)::font_entry> > >, std::_Select1st<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::vector<cycfi::elements::(anonymous namespace)::font_entry, std::allocator<cycfi::elements::(anonymous namespace)::font_entry> > > >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::vector<cycfi::elements::(anonymous namespace)::font_entry, std::allocator<cycfi::elements::(anonymous namespace)::font_entry> > > > >::_M_get_insert_unique_pos(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) [clone .constprop.0] ()
#2  0x000000000044b5d1 in std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<cycfi::elements::(anonymous namespace)::font_entry, std::allocator<cycfi::elements::(anonymous namespace)::font_entry> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::vector<cycfi::elements::(anonymous namespace)::font_entry, std::allocator<cycfi::elements::(anonymous namespace)::font_entry> > > > >::operator[](std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) [clone .constprop.0] ()
#3  0x000000000044d23f in cycfi::elements::(anonymous namespace)::match(cycfi::elements::font_descr) [clone .isra.0] [clone .lto_priv.0] ()
#4  0x000000000044b7a9 in cycfi::elements::font::font(cycfi::elements::font_descr) [clone .constprop.0] ()
#5  0x00000000004493b7 in global constructors keyed to 65535_0_objects.a_0xa8.56553 ()
#6  0x000000000043b193 in __do_global_ctors ()
    at E:/GitHub/MINGW-packages/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:67
#7  0x000000000043b1d9 in __main ()
    at E:/GitHub/MINGW-packages/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:83
#8  0x0000000000401328 in __tmainCRTStartup ()
    at E:/GitHub/MINGW-packages/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:329
#9  0x000000000040149c in WinMainCRTStartup ()
    at E:/GitHub/MINGW-packages/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:195

CMake improvements - expose ifs in options

The following switch is not visible in cmake -L or in the cmake-gui. A library user is not aware of being able to disable examples unless the variable is added blindly.

elements/CMakeLists.txt

Lines 19 to 21 in 9e73461

if (NOT ELEMENTS_NO_EXAMPLES)
add_subdirectory(examples)
endif()

With modern CMake, it is recommended to do such thing instead:

option(ELEMENTS_BUILD_EXAMPLES "build Elements library examples" ON)

if (NOT ELEMENTS_BUILD_EXAMPLES) 
    add_subdirectory(examples) 
endif() 

Would you like a PR for this?

Windows x86 compilation

To be able to compile the windows_port branch under windows x86 (32bits)
I had to correct the linking of the provided FreeType binary.

The CMakeFile.txt list it under "Win86" folder, I should be "Win32"

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.

build with MinGW and GTK ?

I noticed it is really easy to build elements with MinGW and GTK. I simply made everything behave as Linux except for the boost::asio and it works fine. Are there any plans to officially support building for MinGW and GTK?

examples do not build due to static asserts

In 3308ea6 I broke at least one example with new asserts.

In file included from [...]elements/element.hpp:11,
                 from [...]elements.hpp:12,
                 from [...]examples/buttons/main.cpp:6:
[...]elements/element/button.hpp: In instantiation of 'class cycfi::elements::basic_toggle_button<cycfi::elements::proxy<cycfi::elements::sprite&, cycfi::elements::basic_button> >':
[...]examples/buttons/main.cpp:101:64:   required from here
[...]elements/element/button.hpp:104:21: error: static assertion failed: basic_toggle_button Base type needs to be or inherit from layered_button
       static_assert(std::is_base_of_v<layered_button, Base>,
                     ^~~

Now I'm unsure what are actual template requirements. Apparently the default parameter is not the minimal requirement and the assert could be more permissive.

tracker<Base>::info

info has always the same definition, but currently its definition is dependent on the tracker's template type paramer, which might be unwanted - this can cause some interoperatibility issues between different tracker instantiations.

template <typename Base = element>
class tracker : public Base
{
public:
struct info

I propose to make info a standalone tracker_info type.

missing initializer warnings

These all look suspicious

[...]lib\src\support\draw_utils.cpp: In function 'void cycfi::elements::draw_box_vgradient(cycfi::elements::canvas&, cycfi::elements::rect, float)':
[...]lib\src\support\draw_utils.cpp:15:7: warning: missing initializer for member 'cycfi::elements::canvas::linear_gradient::space' [-Wmissing-field-initializers]
   15 |       };
      |       ^
[...]lib\src\support\draw_utils.cpp: In function 'void cycfi::elements::draw_button(cycfi::elements::canvas&, cycfi::elements::rect, cycfi::elements::color, float)':
[...]lib\src\support\draw_utils.cpp:86:7: warning: missing initializer for member 'cycfi::elements::canvas::linear_gradient::space' [-Wmissing-field-initializers]
   86 |       };
      |       ^
[...]lib\src\support\draw_utils.cpp: In function 'void cycfi::elements::draw_knob(cycfi::elements::canvas&, cycfi::elements::circle, cycfi::elements::color)':
[...]lib\src\support\draw_utils.cpp:117:10: warning: missing initializer for member 'cycfi::elements::canvas::radial_gradient::space' [-Wmissing-field-initializers]
  117 |          };
      |          ^
[...]lib\src\support\draw_utils.cpp:135:10: warning: missing initializer for member 'cycfi::elements::canvas::radial_gradient::space' [-Wmissing-field-initializers]
  135 |          };
      |          ^
[...]lib\src\support\draw_utils.cpp:167:10: warning: missing initializer for member 'cycfi::elements::canvas::linear_gradient::space' [-Wmissing-field-initializers]
  167 |          };
      |          ^
[...]lib\src\support\draw_utils.cpp: In function 'void cycfi::elements::draw_thumb(cycfi::elements::canvas&, cycfi::elements::circle, cycfi::elements::color, cycfi::elements::color)':
[...]lib\src\support\draw_utils.cpp:207:10: warning: missing initializer for member 'cycfi::elements::canvas::radial_gradient::space' [-Wmissing-field-initializers]
  207 |          };
      |          ^
[...]lib\src\support\draw_utils.cpp:232:10: warning: missing initializer for member 'cycfi::elements::canvas::linear_gradient::space' [-Wmissing-field-initializers]
  232 |          };
      |          ^
[...]lib\host\windows\base_view.cpp: In constructor 'cycfi::elements::{anonymous}::init_view_class::init_view_class()':
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::lpfnWndProc' [-Wmissing-field-initializers]
  475 |             WNDCLASSW windowClass = {0};
      |                                       ^
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::cbClsExtra' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::cbWndExtra' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::hInstance' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::hIcon' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::hCursor' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::hbrBackground' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::lpszMenuName' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:475:39: warning: missing initializer for member 'tagWNDCLASSW::lpszClassName' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp: In function 'HWND__* cycfi::elements::{anonymous}::make_window(cycfi::elements::base_view*, cycfi::elements::host_window_handle, RECT)':
[...]lib\host\windows\base_view.cpp:515:49: warning: missing initializer for member 'cycfi::elements::{anonymous}::view_info::click_start' [-Wmissing-field-initializers]
  515 |          view_info* info = new view_info{ _this };
      |                                                 ^
[...]lib\host\windows\base_view.cpp:515:49: warning: missing initializer for member 'cycfi::elements::{anonymous}::view_info::scroll_start' [-Wmissing-field-initializers]
[...]lib\host\windows\base_view.cpp:515:49: warning: missing initializer for member 'cycfi::elements::{anonymous}::view_info::keys' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp: In constructor 'cycfi::elements::{anonymous}::init_window_class::init_window_class()':
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::lpfnWndProc' [-Wmissing-field-initializers]
  146 |             WNDCLASSW windowClass = {0};
      |                                       ^
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::cbClsExtra' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::cbWndExtra' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::hInstance' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::hIcon' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::hCursor' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::hbrBackground' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::lpszMenuName' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp:146:39: warning: missing initializer for member 'tagWNDCLASSW::lpszClassName' [-Wmissing-field-initializers]
[...]lib\host\windows\window.cpp: In constructor 'cycfi::elements::window::window(const string&, int, const cycfi::elements::rect&)':
[...]lib\host\windows\window.cpp:176:49: warning: missing initializer for member 'cycfi::elements::{anonymous}::window_info::limits' [-Wmissing-field-initializers]
  176 |       window_info* info = new window_info{ this };
      |                                                 ^

box and background_fill elements are the same

struct box_element : element
{
box_element(color color_)
: _color(color_)
{}
void draw(context const& ctx) override
{
auto& cnv = ctx.canvas;
cnv.fill_style(_color);
cnv.fill_rect(ctx.bounds);
}
color _color;
};
inline auto box(color color_)
{
return box_element{ color_ };
}

struct background_fill : element
{
background_fill(color color_)
: _color(color_)
{}
void draw(context const& ctx) override;
color _color;
};

void background_fill::draw(context const& ctx)
{
auto& cnv = ctx.canvas;
cnv.fill_style(_color);
cnv.fill_rect(ctx.bounds);
}

Something was either forgotten in one of these or they are accidental code duplication ... in 1 file.

browse for file/directory widget

This issue is for tracking any decisions before implementing this widget.

  • likely just a button with predefined on_click function
  • requires platform-specific code

dropdown with text search/filter

This issue is for tracking any decisions before implementing this widget.

This is an idea for a smart dropdown that has a text box on its click area. When the dropdown is expanded, the user can enter text which will filter displayed options.

I would like at least 2 filtering algorithms:

  • Basic .contains() string-in-string search.
  • An algorithm that checks the order and presence of pattern letters - eg for options foo bar, foo baz, xyz foo, abc foo xyz
    • typing foo has no change
    • typing ba will leave only foo bar and foo baz
    • typing xf will leave only xyz foo
    • typing oz will leave only foo baz and abc foo xyz

element interface description

There are multiple virtual functions in the base type that are unclear. I think we should add at least an explanatory comment how derived types should implement these functions.

// Image
virtual view_limits limits(basic_context const& ctx) const;
virtual view_stretch stretch() const;
virtual element* hit_test(context const& ctx, point p);
virtual void draw(context const& ctx);
virtual void layout(context const& ctx);
virtual bool scroll(context const& ctx, point dir, point p);
virtual void refresh(context const& ctx, element& element, int outward = 0);
void refresh(context const& ctx, int outward = 0) { refresh(ctx, *this, outward); }
// Control
virtual element* click(context const& ctx, mouse_button btn);
virtual void drag(context const& ctx, mouse_button btn);
virtual bool key(context const& ctx, key_info k);
virtual bool text(context const& ctx, text_info info);
virtual bool cursor(context const& ctx, point p, cursor_tracking status);
virtual bool focus(focus_request r);
virtual element const* focus() const;
virtual element* focus();
virtual bool is_control() const;
// Receiver
virtual void value(bool val);
virtual void value(int val);
virtual void value(double val);
virtual void value(std::string val);

The context and basic_context could also get some documentation.

progress bar widget

This issue is for tracking any decisions before implementing this widget.

Ideally, we want to support different behaviors:

  • being able to specify the fill color
  • support for arbitrary rectangle size
  • support for both horizontal and vertical placement
  • progress circle widget? could have the same interface, just different draw() method implementation
  • support for indeterminate progress state (that is, instead of increasing filling of the rectangle, a generic animation of a moving bar)

table widget

Example screenshot: https://github.com/qPCR4vir/nana-docs/raw/master/screenshots/thdy_seq_expl.png (ignore the tree view on the left, although I also want this kind of widget, but this is covered by #39)

What is obvious is that I can fully compose such table from smaller widgets. That's the main goal of elements. I can even have the fancy features like the colored temperature column as on the linked image. What I have concerns about, is performance.

  • How the table should be build? Grid? Array of row elements? Array of column elements? I suppose array of rows, since they will be scrolled vertically, but asking for clarity. When going with rows or columns, is there any preferred strategy for calculating optimal column width?
  • What if the number of rows is big (say, 10-100k entries)? I suppose I should (re)create widgets only for entries that are visible, but then I wonder what will happen with the implementation of scrolling.
  • How the actual data should be accessed? Should the table widget just store a reference to the actual data structure?

build fail on Windows: missing ShellScalingAPI.h

I'm trying to build elements on Windows using MCF GCC 9.1. I downloaded elements, infra and json as the documentation says but there is no information how to handle Cairo dependency other than Mac OS brew install.

CMake does not complain about anything, yet there are missing includes:

> make
Scanning dependencies of target json_test
[  1%] Building CXX object json/test/CMakeFiles/json_test.dir/main.cpp.obj
[  3%] Linking CXX executable json_test.exe
[  3%] Built target json_test
Scanning dependencies of target libelements
[  5%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/button.cpp.obj
[  6%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/composite.cpp.obj
[  8%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/dial.cpp.obj
[ 10%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/element.cpp.obj
[ 12%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/floating.cpp.obj
[ 13%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/flow.cpp.obj
[ 15%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/gallery/button.cpp.obj
[ 17%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/gallery/check_box.cpp.obj
[ 18%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/gallery/icon_button.cpp.obj
[ 20%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/gallery/menu.cpp.obj
[ 22%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/image.cpp.obj
[ 24%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/layer.cpp.obj
[ 25%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/menu.cpp.obj
[ 27%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/misc.cpp.obj
[ 29%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/popup.cpp.obj
[ 31%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/port.cpp.obj
[ 32%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/proxy.cpp.obj
[ 34%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/slider.cpp.obj
[ 36%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/text.cpp.obj
[ 37%] Building CXX object lib/CMakeFiles/libelements.dir/src/element/tile.cpp.obj
[ 39%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/canvas.cpp.obj
[ 41%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/draw_utils.cpp.obj
[ 43%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/glyphs.cpp.obj
[ 44%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/pixmap.cpp.obj
[ 46%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/rect.cpp.obj
[ 48%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/resource_paths.cpp.obj
[ 50%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/text_utils.cpp.obj
[ 51%] Building CXX object lib/CMakeFiles/libelements.dir/src/support/theme.cpp.obj
[ 53%] Building CXX object lib/CMakeFiles/libelements.dir/src/view.cpp.obj
[ 55%] Building CXX object lib/CMakeFiles/libelements.dir/host/windows/app.cpp.obj
[...]\elements\lib\host\windows\app.cpp:12:10: fatal error: ShellScalingAPI.h: No such file or directory
   12 | #include <ShellScalingAPI.h>
      |          ^~~~~~~~~~~~~~~~~~~
compilation terminated.

After brief research, I find out this file is not from Cairo but a part of UWP. Do I miss some Windows SDK?

Windows size on Linux (Wayland)

I assume this is not normal:

Screenshot from 2020-04-07 00-53-52

The window can't be resized.

Opened for tracking. I will look into it in the next days if time permits.

Update Only happens with Wayland backend. GDK_BACKEND=x11 ./BasicSlidersAndKnobs works as expected.

get_button in windows/base_view.cpp

2 things are suspicious here

mouse_button get_button(
HWND hwnd, view_info* info, UINT message
, WPARAM wparam, LPARAM lparam)
{
float pos_x = GET_X_LPARAM(lparam);
float pos_y = GET_Y_LPARAM(lparam);
auto scale = GetDpiForWindow(hwnd) / 96.0;
pos_x /= scale;
pos_y /= scale;
bool down = info->is_dragging;
switch (message)
{
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
{
auto now = std::chrono::steady_clock::now();
auto elapsed = now - info->click_start;
info->click_start = now;
if (elapsed > std::chrono::milliseconds(GetDoubleClickTime()))
info->click_count = 1;
else
++info->click_count;
if (!info->is_dragging)
{
info->is_dragging = true;
SetCapture(hwnd);
}
down = true;
}
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
down = false;
if (info->is_dragging)
{
info->is_dragging = false;
ReleaseCapture();
}
break;
}
int click_count = 1;
mouse_button::what which;
switch (message)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
which = mouse_button::left;
break;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
which = mouse_button::middle;
break;
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
which = mouse_button::right;
break;
}
return {
down,
info->click_count,
mouse_button::left,
get_mods(),
{ pos_x, pos_y }
};
}

  • the click_count is never used (triggers unused variable warning)
    • this is either unneded or something was forgotten
  • mouse_button::what which is set in the switch but never used (triggers variable set but not used warning)
    • the switch which sets the value of which is either unneded or something was forgotten
    • the function always returns mouse_button::left, which looks like a potential replacement for which variable

Link-time optimization supported.

i have problem at "Setup and Installation" ( MacOS Installation )

i installed brew, cairo, boost, fontconfig, cmake.

And i got same issue like this linkโ†“
https://stackoverflow.com/questions/58081084/target-boostlibrary-already-has-an-imported-location-link-errors

so i edit like this

...

"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

include(CheckIPOSupported)
set(Boost_USE_MULTITHREADED TRUE) <==========Added
check_ipo_supported(RESULT IPO_SUPPORTED)
if(IPO_SUPPORTED)
message(STATUS "Link-time optimization supported. Will be enabled in Release build type")
endif()

...

And i got like this.
I tried to solve it, but I can`t solve it.
What should i do?

=======================================================================
uyunjaeui-Macmini:build uyunjae$ cmake -GXcode ../
-- Link-time optimization supported. Will be enabled in Release build type
CMake Error at CMakeLists.txt:31 (add_subdirectory):
add_subdirectory given source "../json" which is not an existing directory.

-- Configuring incomplete, errors occurred!
See also "/Users/uyunjae/Downloads/elements-master/build/CMakeFiles/CMakeOutput.log".

=======================================================================

linker fail after adding radio button

104cef3 - 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 104cef3, 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.

includes with "//"

This is likely a source of weird underlines in some IDEs, not sure whether these headers are actually used in any source or it "just compiles" (unix paths treat multiple slashes as one) but I get broken include/comment highlight.

#include <elements/element//gallery/button.hpp>
#include <elements/element//gallery/dialog.hpp>

#include <elements/element//gallery/button.hpp>

I guess fixing these can not go wrong. grep -rn "#include" lib/ | grep "//" does not report more.

replace_string

I don't get the purpose of this thing:

// A simple utility for replacing a std::string with the
// contents of a std::string_view
static void replace_string(std::string& dest, std::string_view text)
{
std::string str{ text.begin(), text.end() };
dest.swap(str);
}

  • std::basic_string<CharT, Traits, Allocator> supports operator= for respectove string views. dest = text just works.
  • This function uses copy-and-swap idiom where a copy is not actually used. It performs an unnecessary allocation and does not reuse the existing buffer.

clamp compile error

7288d29 broke the build

lib/src/element/dial.cpp: In member function 'virtual double cycfi::elements::dial_base::value_from_point(const cycfi::elements::context&, cycfi::elements::point)':
lib/src/element/dial.cpp:54:36: error: void value not ignored as it ought to be
          return clamp(val, 0.0, 1.0);
                                    ^

The clamp from infra does not return a value (it has an output parameter). That's why I prefer std::clamp - it's standard and return value is cleaner than out parameter.

name shadowing in derived types

Are these intended?

  • basic_button::value() - shadows other value() overloads from its parent types
  • sprite::size() shadows image::size()
  • view::refresh() shadows base_view::refresh()

strings in the API

There is some discrepancy in the API how strings are taken.

template <typename Button>
inline Button text_button(
std::string_view text
, float size = 1.0
, bool no_frame = false
)

inline basic_toggle_button<> check_box(std::string const& text)

inline auto dial(
char const* knob_sprite
, float knob_height
, char const* background_image
, char const* caption_text
, float scale = 1.0/4
, float caption_size = 1.0
)

Is there any reason behind this? Having std::string_view or std::string (if widgets store strings internally) everywhere would improve consistency. I would like to not have char const* parameters.

GCC 9.2 crash when building with LTO

[ 60%] Built target elements
[ 61%] Linking CXX executable EmptyStarter.exe
cd /d [...]\build\examples\empty && "C:\Program Files\CMake\bin\cmake.exe" -E cmake_link_script CMakeFiles\EmptyStarter.di
r\link.txt --verbose=1
"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-archiv
e  -o EmptyStarter.exe -Wl,--out-implib,libEmptyStarter.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles\EmptyStarter.dir\linklibs.rsp
lto1.exe: internal compiler error: in add_symbol_to_partition_1, at lto/lto-partition.c:153
libbacktrace could not find executable to open
Please submit a full bug report,
with preprocessed source if appropriate.

Obviously this is a bug in the compiler but after building with -DCMAKE_VERBOSE_MAKEFILE=1 I noticed that -flto is not actually present when building elements, only that gcc-ar is invoked with some flags when building examples. After checking the CMakeLists.txt and lib/CMakeLists.txt it turns out that the main CMake file checks for LTO but only sets a variable holding the result.

elements/CMakeLists.txt

Lines 20 to 24 in 1524011

include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_SUPPORTED)
if(IPO_SUPPORTED)
message(STATUS "Link-time optimization supported. Will be enabled in Release build type")
endif()

Examples have this:

elements/CMakeMain.txt

Lines 162 to 164 in 1524011

if(IPO_SUPPORTED AND CMAKE_BUILD_TYPE STREQUAL "Release")
set_target_properties(${ELEMENTS_APP_PROJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()

Apparently mixing non-LTO code with LTO code causes a compiler crash. Enabling for both solves the problem.

Build Failure on Fedora

Hello , let me start by saying awesome library , really dying to try it out but , i have got this issue running on Fedora 31 .

CMake Error at /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:146 (message):
  Could NOT find Boost (missing: filesystem system date_time regex) (found
  suitable version "1.69.0", minimum required is "1.68")
Call Stack (most recent call first):
  /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:393 (_FPHSA_FAILURE_MESSAGE)
  /usr/share/cmake/Modules/FindBoost.cmake:2179 (find_package_handle_standard_args)
  lib/CMakeLists.txt:240 (find_package)

Also any chance there will be a possible port to FreeBSD ?

hyperlink widget

This issue is for tracking any decisions before implementing this widget.

Some notes:

  • It will very-likely require platform-specific code (by default, on click it should open the link in default browser) - probably place such code in host directory.
  • The default appearance (blue color, underline) will require a rich text label widget first. In fact, a hyperlink widget should probably be nothing more than a rich label with predefined on_click function and its blue, underlined text appearance

calendar widget

This issue is for tracking any decisions before implementing this widget.

Likely dependent on boost date time

Coding conventions

looking at the source code I saw that you are using some conventions I don't know about

example

int main(int argc, const char* argv[])
{
   app _app(argc, argv);
   window _win(_app.name());
   _win.on_close = [&_app]() { _app.stop(); };

   view view_(_win);

   view_.content(
      {
         share(make_controls(view_)),
         share(background)
      }
   );

   _app.run();
   return 0;
}

What is the purpose of prefixing or post fixing with underscores?

Maybe you can point out to a document or webpage describing your coding style.

Thanks

Investigate the possibility of cross-graphics support with A Skia backend

I've been following the Cairo roadmap for quite some time (https://www.cairographics.org/roadmap/). At one point, Elements actually used NanoVG as the 2D graphics backend. It supported things like blurred drop-shadows that had to be poorly simulated in the switch to Cairo. So I was anticipating support for optimized gaussian blur effect as listed in the Cairo roadmap, supposedly targeted for cairo 1.16 (2017?). It's 2020 now.

And now James Berrow's scorching review of the c++ Cairo based 2D graphics proposal : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2005r0.html

I don't quite agree on a lot of things, but it might probably make sense to abstract away the 2d graphics backend.

better theming support

I like the support of being able to set custom theme object, but not all variables which impact drawing are there

class theme
{
public:
color panel_color = rgba(28, 30, 34, 192);
color frame_color = rgba(220, 220, 220, 80);
float frame_corner_radius = 3.0;
float frame_stroke_width = 1.0;

For example, the button has its own radius variable:

struct basic_button_body : public element
{
constexpr static float corner_radius = 4.0;

and some color changes too:

template <typename Button, typename Label>
inline Button make_button(
Label&& label
, color body_color = get_theme().default_button_color)
{
auto btn_body_off = basic_button_body(body_color.level(0.9));
auto btn_body_on = basic_button_body(body_color.opacity(0.5));

Could we move all such variables to the theme so that one can create a theme which changes color and corners of all elements? I would like to be able to create eg a full square-like UI as on this screen.

Investigate the possibility of testing elements

Testing GUIs is tricky. but nevertheless, I don't feel good without tests. Right now, I have to build the examples and inspect each one of them to make sure everything is good.

At the very least, a quick testing facility is probably something like:

  1. Saving the view to a PNG
  2. Comparing the PNGs to known 'golden' files and reporting the diffs.

It might be possible to simulate user interaction, but that can probably be done later.

element.hpp - duplicated smart pointer aliases

I guess the ones in the class can be removed?

class element : public std::enable_shared_from_this<element>
{
public:
using element_ptr = std::shared_ptr<element>;
using element_const_ptr = std::shared_ptr<element const>;

using element_ptr = std::shared_ptr<element>;
using element_const_ptr = std::shared_ptr<element const>;
using weak_element_ptr = std::weak_ptr<element>;
using weak_element_const_ptr = std::weak_ptr<element const>;

Remove string duplicates in widget factories

There are multiple factories like this one which unnecesarily copy the string:

inline basic_toggle_button<> check_box(std::string text)
{
return basic_toggle_button(
check_box_element<false>{ text }
, check_box_element<true>{ text }
);
}

Instead of creating a such hierarchy:

  • check_box
    • htile
      • layered_element
        • icon_on
        • icon_off
      • text

they create this:

  • check_box
    • layered_element
      • htile
        • icon_on
        • text
      • htile
        • icon_off
        • text

This issue is blocked by #87

List of widgets and planned features?

I have read the article about the library and I'm interested in using it. I know it's still very early (no documentation) but I struggle to find a modern C++ GUI that has non-intrusive build and a large set of widgets.

I think it would be good to have a list of planned/implemented features/widgets. I'm mostly interested in rich text display (bold, italics, color, custom fonts) and simple canvas.

Successfull on Windows

Just to let you know that everything (from the Windows-port branch) builds
correctly under Windows

Target : Windows 10
Toochain: Visual Studio 2017 (15.9 version)

I had initially trouble with installing boost with the instruction on the boost site
and I was using MSVC 15.6 which lacks some C++17 compatibility.

Finally after building and installing vcpkg and using it to get the boost packages
needed to build, upgrading the visual studio to 15.9 everything worked out of the box...

image

image

image

image

image

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)?

radio box

Another widget I would like to have, but I need some guidance how it should be implemented. The core invariant is that in any group of radio boxes only 1 can be enabled. How we should approach this? Should there be another type (eg. radio_box_group) that holds references to multiple radio boxes and intercepts their events?

ownership-aware API for strings

You can make multiple constructors:

  • const char(&)[N] - this must be a C-string, guuaranteed infinite lifetime
  • std::string_view - user manages lifetime
  • std::string - widget manages lifetime
  • const char* = delete because it is unknown, require the user to wrap the call into string or string_view.

Exactly! But not on the ctor, instead the factory...

Originally posted by @djowel in #23 (comment)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.