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 \
|
||||
window.cc \
|
||||
dialogs.cc \
|
||||
ui-actions.cc \
|
||||
globals.cc \
|
||||
profiling.cc \
|
||||
shaders.cc \
|
||||
|
|
68
main.cc
68
main.cc
|
@ -50,6 +50,45 @@ T_Main::T_Main( )
|
|||
{
|
||||
Globals::Init( );
|
||||
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( )
|
||||
|
@ -208,33 +247,8 @@ void T_Main::makeUI( )
|
|||
bool eSequencer{ sequencer };
|
||||
if ( BeginMainMenuBar( ) ) {
|
||||
if ( BeginMenu( "File" ) ) {
|
||||
if ( MenuItem( "Save curves" , "C-s" , false , sync.curvesModified( ) ) ) {
|
||||
if ( 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 {
|
||||
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 } );
|
||||
}
|
||||
Globals::Window( ).actionMenu( "Save curves" );
|
||||
Globals::Window( ).actionMenu( "Reload curves" );
|
||||
Separator( );
|
||||
if ( MenuItem( "Undo" , "C-z" , false , undo.canUndo( ) ) ) {
|
||||
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( );
|
||||
}
|
||||
|
||||
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(
|
||||
const bool capture ,
|
||||
ImVec2 const& mouseInitial ) const
|
||||
|
|
11
window.hh
11
window.hh
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "dialogs.hh"
|
||||
#include "mousectrl.hh"
|
||||
#include "ui-actions.hh"
|
||||
|
||||
|
||||
/*= 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
|
||||
{ return defaultFont_; }
|
||||
ImFont* smallFont( ) const noexcept
|
||||
|
@ -48,5 +55,9 @@ struct T_Window
|
|||
ImFont* defaultFont_;
|
||||
ImFont* smallFont_;
|
||||
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