UI - Started working on actions
+ Can be registered + Can be used to draw menu items and toolbar buttons
This commit is contained in:
parent
89d125761a
commit
88e5724fe9
6 changed files with 223 additions and 27 deletions
1
Makefile
1
Makefile
|
@ -26,6 +26,7 @@ COMMON = \
|
||||||
filewatcher.cc \
|
filewatcher.cc \
|
||||||
window.cc \
|
window.cc \
|
||||||
dialogs.cc \
|
dialogs.cc \
|
||||||
|
ui-actions.cc \
|
||||||
globals.cc \
|
globals.cc \
|
||||||
profiling.cc \
|
profiling.cc \
|
||||||
shaders.cc \
|
shaders.cc \
|
||||||
|
|
68
main.cc
68
main.cc
|
@ -50,6 +50,45 @@ T_Main::T_Main( )
|
||||||
{
|
{
|
||||||
Globals::Init( );
|
Globals::Init( );
|
||||||
prevSize = ImVec2( -1 , -1 );
|
prevSize = ImVec2( -1 , -1 );
|
||||||
|
|
||||||
|
// FIXME: should be somewhere else
|
||||||
|
T_UIAction saveCurves{ "Save curves" , []() {
|
||||||
|
if ( Globals::Sync( ).curvesFileChanged( ) ) {
|
||||||
|
Globals::Window( ).msgbox(
|
||||||
|
"Curves file changed" ,
|
||||||
|
"The file containing the curves has been modified "
|
||||||
|
"on the disk. These changes will be overwritten. "
|
||||||
|
"Do you want to continue?" ,
|
||||||
|
[]( auto b ) {
|
||||||
|
if ( b == T_MessageBox::BT_YES ) {
|
||||||
|
Globals::Sync( ).saveCurves( );
|
||||||
|
}
|
||||||
|
} , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } );
|
||||||
|
} else {
|
||||||
|
Globals::Sync( ).saveCurves( );
|
||||||
|
}
|
||||||
|
} };
|
||||||
|
saveCurves.setEnabledCheck( []() { return Globals::Sync( ).curvesModified( ); } )
|
||||||
|
.setIcon( ICON_FA_FLOPPY_O )
|
||||||
|
.setShortcut( T_KeyboardShortcut{ 's' , E_KeyboardModifier::CTRL } );
|
||||||
|
Globals::Window( ).addAction( std::move( saveCurves ) );
|
||||||
|
|
||||||
|
T_UIAction reloadCurves{ "Reload curves" , []() {
|
||||||
|
Globals::Window( ).msgbox(
|
||||||
|
"Reload curves?" ,
|
||||||
|
"Changes you made to the curves will be lost. Do you "
|
||||||
|
"want to continue?" ,
|
||||||
|
[]( auto b ) {
|
||||||
|
if ( b == T_MessageBox::BT_YES ) {
|
||||||
|
Globals::Sync( ).loadCurves( );
|
||||||
|
}
|
||||||
|
} , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } );
|
||||||
|
} };
|
||||||
|
reloadCurves.setEnabledCheck( []() { return Globals::Sync( ).curvesModified( ); } )
|
||||||
|
.setIcon( ICON_FA_DOWNLOAD )
|
||||||
|
.setShortcut( T_KeyboardShortcut{ 'r' ,
|
||||||
|
{ E_KeyboardModifier::CTRL , E_KeyboardModifier::SHIFT } } );
|
||||||
|
Globals::Window( ).addAction( std::move( reloadCurves ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void T_Main::mainLoop( )
|
void T_Main::mainLoop( )
|
||||||
|
@ -208,33 +247,8 @@ void T_Main::makeUI( )
|
||||||
bool eSequencer{ sequencer };
|
bool eSequencer{ sequencer };
|
||||||
if ( BeginMainMenuBar( ) ) {
|
if ( BeginMainMenuBar( ) ) {
|
||||||
if ( BeginMenu( "File" ) ) {
|
if ( BeginMenu( "File" ) ) {
|
||||||
if ( MenuItem( "Save curves" , "C-s" , false , sync.curvesModified( ) ) ) {
|
Globals::Window( ).actionMenu( "Save curves" );
|
||||||
if ( sync.curvesFileChanged( ) ) {
|
Globals::Window( ).actionMenu( "Reload curves" );
|
||||||
Globals::Window( ).msgbox(
|
|
||||||
"Curves file changed" ,
|
|
||||||
"The file containing the curves has been modified "
|
|
||||||
"on the disk. These changes will be overwritten. "
|
|
||||||
"Do you want to continue?" ,
|
|
||||||
[]( auto b ) {
|
|
||||||
if ( b == T_MessageBox::BT_YES ) {
|
|
||||||
Globals::Sync( ).saveCurves( );
|
|
||||||
}
|
|
||||||
} , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } );
|
|
||||||
} else {
|
|
||||||
sync.saveCurves( );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( MenuItem( "Reload curves" , "C-R" , false , sync.curvesModified( ) ) ) {
|
|
||||||
Globals::Window( ).msgbox(
|
|
||||||
"Reload curves?" ,
|
|
||||||
"Changes you made to the curves will be lost. Do you "
|
|
||||||
"want to continue?" ,
|
|
||||||
[]( auto b ) {
|
|
||||||
if ( b == T_MessageBox::BT_YES ) {
|
|
||||||
Globals::Sync( ).loadCurves( );
|
|
||||||
}
|
|
||||||
} , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } );
|
|
||||||
}
|
|
||||||
Separator( );
|
Separator( );
|
||||||
if ( MenuItem( "Undo" , "C-z" , false , undo.canUndo( ) ) ) {
|
if ( MenuItem( "Undo" , "C-z" , false , undo.canUndo( ) ) ) {
|
||||||
undo.undo( );
|
undo.undo( );
|
||||||
|
|
89
ui-actions.cc
Normal file
89
ui-actions.cc
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include "externals.hh"
|
||||||
|
#include "ui-actions.hh"
|
||||||
|
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_KeyboardShortcut =======================================================*/
|
||||||
|
|
||||||
|
void T_KeyboardShortcut::toString(
|
||||||
|
char* const buffer ,
|
||||||
|
const size_t size ) const noexcept
|
||||||
|
{
|
||||||
|
const char ch[ 2 ] = {
|
||||||
|
char( ( modifiers & E_KeyboardModifier::SHIFT )
|
||||||
|
? toupper( character ) : tolower( character ) ) ,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
snprintf( buffer , size , "%s%s%s" ,
|
||||||
|
( modifiers & E_KeyboardModifier::CTRL ) ? "C-" : "" ,
|
||||||
|
( modifiers & E_KeyboardModifier::ALT ) ? "A-" : "" ,
|
||||||
|
[&]( ) {
|
||||||
|
switch ( character ) {
|
||||||
|
case ' ': return "<space>";
|
||||||
|
case '\n': return "<enter>";
|
||||||
|
default: return ch;
|
||||||
|
}
|
||||||
|
}( ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_UIAction ===============================================================*/
|
||||||
|
|
||||||
|
void T_UIAction::menuItem( ) const noexcept
|
||||||
|
{
|
||||||
|
const bool e{ enabled ? enabled( ) : true };
|
||||||
|
|
||||||
|
T_String const& title{ text ? text : id };
|
||||||
|
const uint32_t ts{ title.size( ) };
|
||||||
|
char name[ ts + 1 ];
|
||||||
|
memcpy( name , title.data( ) , ts );
|
||||||
|
name[ ts ] = 0;
|
||||||
|
|
||||||
|
char kbs[ 20 ];
|
||||||
|
char const* kbsp = shortcut ? kbs : nullptr;
|
||||||
|
if ( shortcut ) {
|
||||||
|
shortcut->toString( kbs , 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ImGui::MenuItem( name , kbsp , false , e ) ) {
|
||||||
|
handler( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void T_UIAction::tbButton( ) const noexcept
|
||||||
|
{
|
||||||
|
using namespace ImGui;
|
||||||
|
static T_StringBuilder sb;
|
||||||
|
|
||||||
|
sb.clear( ) << ( icon ? icon : "" ) << "##" << id << '\0';
|
||||||
|
|
||||||
|
const bool e{ enabled ? enabled( ) : true };
|
||||||
|
if ( !e ) {
|
||||||
|
PushItemFlag( ImGuiItemFlags_Disabled , true );
|
||||||
|
PushStyleVar( ImGuiStyleVar_Alpha ,
|
||||||
|
GetStyle( ).Alpha * .5f );
|
||||||
|
}
|
||||||
|
const bool rv{ Button( sb.data( ) , ImVec2{ 20 , 0 } ) };
|
||||||
|
if ( e && IsItemHovered( ) ) {
|
||||||
|
sb.clear( ) << ( text ? text : id );
|
||||||
|
if ( shortcut ) {
|
||||||
|
char kbs[ 20 ];
|
||||||
|
shortcut->toString( kbs , 20 );
|
||||||
|
sb << ' ' << kbs;
|
||||||
|
}
|
||||||
|
sb << '\0';
|
||||||
|
|
||||||
|
BeginTooltip( );
|
||||||
|
Text( "%s" , sb.data( ) );
|
||||||
|
EndTooltip( );
|
||||||
|
}
|
||||||
|
if ( !e ) {
|
||||||
|
PopItemFlag( );
|
||||||
|
PopStyleVar( );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rv ) {
|
||||||
|
handler( );
|
||||||
|
}
|
||||||
|
}
|
57
ui-actions.hh
Normal file
57
ui-actions.hh
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#pragma once
|
||||||
|
#include "ui-input.hh"
|
||||||
|
|
||||||
|
|
||||||
|
/*= COMMON ACTION DEFINITIONS ================================================*/
|
||||||
|
|
||||||
|
struct T_KeyboardShortcut
|
||||||
|
{
|
||||||
|
char character;
|
||||||
|
T_KeyboardModifiers modifiers;
|
||||||
|
|
||||||
|
explicit constexpr T_KeyboardShortcut(
|
||||||
|
char character ,
|
||||||
|
T_KeyboardModifiers modifiers = { } ) noexcept
|
||||||
|
: character{ character } , modifiers{ modifiers }
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Writes the keyboard shortcut to a buffer
|
||||||
|
void toString( char* buffer , size_t size ) const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct T_UIAction
|
||||||
|
{
|
||||||
|
// Function to call when the action is executed
|
||||||
|
using F_ActionHandler = std::function< void( void ) >;
|
||||||
|
// Function that checks whether the action is enabled
|
||||||
|
using F_ActionChecker = std::function< bool( void ) >;
|
||||||
|
|
||||||
|
T_String id;
|
||||||
|
T_String text; // Text, if different from the identifier
|
||||||
|
char const* icon{ nullptr };
|
||||||
|
T_Optional< T_KeyboardShortcut > shortcut;
|
||||||
|
F_ActionHandler handler;
|
||||||
|
F_ActionChecker enabled;
|
||||||
|
|
||||||
|
T_UIAction( char const* id ,
|
||||||
|
F_ActionHandler handler ) noexcept
|
||||||
|
: id( T_String::Pooled( id ) ) ,
|
||||||
|
handler( std::move( handler ) )
|
||||||
|
{ assert( this->handler ); }
|
||||||
|
T_UIAction( T_String const& id ,
|
||||||
|
F_ActionHandler handler ) noexcept
|
||||||
|
: id( id ) , handler( std::move( handler ) )
|
||||||
|
{ assert( this->handler ); }
|
||||||
|
|
||||||
|
T_UIAction& setShortcut( const T_KeyboardShortcut sc ) noexcept
|
||||||
|
{ shortcut = sc; return *this; }
|
||||||
|
T_UIAction& setText( T_String const& t ) noexcept
|
||||||
|
{ text = t; return *this; }
|
||||||
|
T_UIAction& setIcon( char const* const i ) noexcept
|
||||||
|
{ icon = i; return *this; }
|
||||||
|
T_UIAction& setEnabledCheck( F_ActionChecker check ) noexcept
|
||||||
|
{ enabled = std::move( check ); return *this; }
|
||||||
|
|
||||||
|
void menuItem( ) const noexcept;
|
||||||
|
void tbButton( ) const noexcept;
|
||||||
|
};
|
24
window.cc
24
window.cc
|
@ -80,6 +80,30 @@ T_Window::~T_Window( )
|
||||||
SDL_Quit( );
|
SDL_Quit( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void T_Window::addAction(
|
||||||
|
T_UIAction action ) noexcept
|
||||||
|
{
|
||||||
|
actions_.set( std::move( action ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void T_Window::actionMenu(
|
||||||
|
T_String const& id ) const noexcept
|
||||||
|
{
|
||||||
|
auto const* const a{ actions_.get( id ) };
|
||||||
|
if ( a ) {
|
||||||
|
a->menuItem( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void T_Window::actionButton(
|
||||||
|
T_String const& id ) const noexcept
|
||||||
|
{
|
||||||
|
auto const* const a{ actions_.get( id ) };
|
||||||
|
if ( a ) {
|
||||||
|
a->tbButton( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void T_Window::startFrame(
|
void T_Window::startFrame(
|
||||||
const bool capture ,
|
const bool capture ,
|
||||||
ImVec2 const& mouseInitial ) const
|
ImVec2 const& mouseInitial ) const
|
||||||
|
|
11
window.hh
11
window.hh
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dialogs.hh"
|
#include "dialogs.hh"
|
||||||
#include "mousectrl.hh"
|
#include "mousectrl.hh"
|
||||||
|
#include "ui-actions.hh"
|
||||||
|
|
||||||
|
|
||||||
/*= WINDOW MANAGEMENT ========================================================*/
|
/*= WINDOW MANAGEMENT ========================================================*/
|
||||||
|
@ -28,6 +29,12 @@ struct T_Window
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void addAction( T_UIAction action ) noexcept;
|
||||||
|
void actionMenu( T_String const& id ) const noexcept;
|
||||||
|
void actionButton( T_String const& id ) const noexcept;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
ImFont* defaultFont( ) const noexcept
|
ImFont* defaultFont( ) const noexcept
|
||||||
{ return defaultFont_; }
|
{ return defaultFont_; }
|
||||||
ImFont* smallFont( ) const noexcept
|
ImFont* smallFont( ) const noexcept
|
||||||
|
@ -48,5 +55,9 @@ struct T_Window
|
||||||
ImFont* defaultFont_;
|
ImFont* defaultFont_;
|
||||||
ImFont* smallFont_;
|
ImFont* smallFont_;
|
||||||
T_AutoArray< P_ModalDialog , 8 > modals_;
|
T_AutoArray< P_ModalDialog , 8 > modals_;
|
||||||
|
T_ObjectTable< T_String , T_UIAction > actions_{
|
||||||
|
[]( T_UIAction const& a ) -> T_String {
|
||||||
|
return a.id;
|
||||||
|
} };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue