UI - Started working on actions

+ Can be registered
+ Can be used to draw menu items and toolbar buttons
This commit is contained in:
Emmanuel BENOîT 2017-11-23 13:54:27 +01:00
parent 89d125761a
commit 88e5724fe9
6 changed files with 223 additions and 27 deletions

View file

@ -26,6 +26,7 @@ COMMON = \
filewatcher.cc \
window.cc \
dialogs.cc \
ui-actions.cc \
globals.cc \
profiling.cc \
shaders.cc \

68
main.cc
View file

@ -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
View 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
View 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;
};

View file

@ -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

View file

@ -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;
} };
};