UI - Global keyboard shortcuts
This commit is contained in:
parent
0fcfeb1fee
commit
fa242b08a4
5 changed files with 116 additions and 42 deletions
|
@ -28,6 +28,14 @@ void T_KeyboardShortcut::toString(
|
|||
}( ) );
|
||||
}
|
||||
|
||||
namespace ebcl {
|
||||
M_DEFINE_HASH( T_KeyboardShortcut )
|
||||
{
|
||||
return uint32_t( item.character ) << 8
|
||||
| uint32_t( item.modifiers );
|
||||
}
|
||||
} // namespace ebcl
|
||||
|
||||
|
||||
/*= T_UIAction ===============================================================*/
|
||||
|
||||
|
|
|
@ -17,7 +17,14 @@ struct T_KeyboardShortcut
|
|||
|
||||
// Writes the keyboard shortcut to a buffer
|
||||
void toString( char* buffer , size_t size ) const noexcept;
|
||||
|
||||
// Equality operators
|
||||
bool operator ==( T_KeyboardShortcut const& other ) const noexcept
|
||||
{ return other.character == character && other.modifiers == modifiers; }
|
||||
bool operator !=( T_KeyboardShortcut const& other ) const noexcept
|
||||
{ return other.character != character || other.modifiers != modifiers; }
|
||||
};
|
||||
namespace ebcl { M_DECLARE_HASH( T_KeyboardShortcut ); }
|
||||
|
||||
struct T_UIAction
|
||||
{
|
||||
|
|
109
ui-app.cc
109
ui-app.cc
|
@ -19,6 +19,8 @@ static const ImWchar IconsRanges_[] = {
|
|||
};
|
||||
} // namespace <anon>
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_UIApp::T_UIApp( )
|
||||
{
|
||||
SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER );
|
||||
|
@ -83,9 +85,22 @@ T_UIApp::~T_UIApp( )
|
|||
SDL_Quit( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_UIApp::addAction(
|
||||
T_UIAction action ) noexcept
|
||||
{
|
||||
if ( action.shortcut ) {
|
||||
const auto idx{ shortcuts_.indexOf( *action.shortcut ) };
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
using namespace ebcl;
|
||||
T_Set< T_String > nSet{ UseTag< ArrayBacked< 8 > >( ) };
|
||||
nSet.add( action.id );
|
||||
shortcuts_.add( *action.shortcut , std::move( nSet ) );
|
||||
} else {
|
||||
shortcuts_[ idx ].add( action.id );
|
||||
}
|
||||
}
|
||||
actions_.set( std::move( action ) );
|
||||
}
|
||||
|
||||
|
@ -107,10 +122,13 @@ void T_UIApp::actionButton(
|
|||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_UIApp::handleEvents( ) noexcept
|
||||
{
|
||||
SDL_Event event;
|
||||
mMove_ = ImVec2( );
|
||||
kbKeys_.clear( );
|
||||
while ( SDL_PollEvent( &event ) ) {
|
||||
ImGui_ImplSdl_ProcessEvent( &event );
|
||||
if ( event.type == SDL_QUIT ) {
|
||||
|
@ -123,13 +141,54 @@ void T_UIApp::handleEvents( ) noexcept
|
|||
mMove_.x += event.motion.xrel;
|
||||
mMove_.y += event.motion.yrel;
|
||||
}
|
||||
|
||||
if ( event.type == SDL_KEYDOWN ) {
|
||||
const auto sym{ event.key.keysym.sym };
|
||||
if ( sym >= 0 && sym <= 127 ) {
|
||||
kbKeys_.add( char( sym ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui_ImplSdl_NewFrame( window_ , mCapture_ , mInitial_ );
|
||||
ImGui::GetIO( ).MouseDrawCursor = true;
|
||||
|
||||
auto& io( ImGui::GetIO( ) );
|
||||
io.MouseDrawCursor = true;
|
||||
kbMods_ = ( ([&io]() {
|
||||
T_KeyboardModifiers kb;
|
||||
if ( io.KeyCtrl ) {
|
||||
kb |= E_KeyboardModifier::CTRL;
|
||||
}
|
||||
if ( io.KeyShift ) {
|
||||
kb |= E_KeyboardModifier::SHIFT;
|
||||
}
|
||||
if ( io.KeyAlt ) {
|
||||
kb |= E_KeyboardModifier::ALT;
|
||||
}
|
||||
return kb;
|
||||
})() );
|
||||
|
||||
handleKeyboardShortcuts( );
|
||||
handleMouseCapture( );
|
||||
}
|
||||
|
||||
void T_UIApp::render( ) noexcept
|
||||
{
|
||||
handleDialogs( );
|
||||
glUseProgram( 0 );
|
||||
glBindProgramPipeline( 0 );
|
||||
UI::Textures( ).reset( );
|
||||
glClearColor( 0 , 0 , 0 , 1 );
|
||||
ImGui::Render( );
|
||||
}
|
||||
|
||||
void T_UIApp::swap( ) const noexcept
|
||||
{
|
||||
SDL_GL_SwapWindow( window_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_UIApp::handleMouseCapture( ) noexcept
|
||||
{
|
||||
using namespace ImGui;
|
||||
|
@ -147,19 +206,6 @@ void T_UIApp::handleMouseCapture( ) noexcept
|
|||
}
|
||||
return mb;
|
||||
})() );
|
||||
const T_KeyboardModifiers kb( ([&io]() {
|
||||
T_KeyboardModifiers kb;
|
||||
if ( io.KeyCtrl ) {
|
||||
kb |= E_KeyboardModifier::CTRL;
|
||||
}
|
||||
if ( io.KeyShift ) {
|
||||
kb |= E_KeyboardModifier::SHIFT;
|
||||
}
|
||||
if ( io.KeyAlt ) {
|
||||
kb |= E_KeyboardModifier::ALT;
|
||||
}
|
||||
return kb;
|
||||
})() );
|
||||
const bool appCanGrab( !( ImGui::IsMouseHoveringAnyWindow( )
|
||||
|| io.WantCaptureMouse
|
||||
|| io.WantCaptureKeyboard ) );
|
||||
|
@ -173,7 +219,7 @@ void T_UIApp::handleMouseCapture( ) noexcept
|
|||
|
||||
} else if ( mCapture_ && mDelegate_ ) {
|
||||
SetMouseCursor( ImGuiMouseCursor_Move );
|
||||
mDelegate_->handleDragAndDrop( mMove_ , kb , mb );
|
||||
mDelegate_->handleDragAndDrop( mMove_ , kbMods_ , mb );
|
||||
|
||||
} else if ( appCanGrab && mb && mDelegate_ ) {
|
||||
mCapture_ = true;
|
||||
|
@ -184,23 +230,34 @@ void T_UIApp::handleMouseCapture( ) noexcept
|
|||
}
|
||||
|
||||
if ( ( appCanGrab || mCapture_ ) && io.MouseWheel && mDelegate_ ) {
|
||||
mDelegate_->handleWheel( io.MouseWheel , kb , mb );
|
||||
mDelegate_->handleWheel( io.MouseWheel , kbMods_ , mb );
|
||||
}
|
||||
}
|
||||
|
||||
void T_UIApp::render( ) noexcept
|
||||
void T_UIApp::handleKeyboardShortcuts( ) noexcept
|
||||
{
|
||||
handleDialogs( );
|
||||
glUseProgram( 0 );
|
||||
glBindProgramPipeline( 0 );
|
||||
UI::Textures( ).reset( );
|
||||
glClearColor( 0 , 0 , 0 , 1 );
|
||||
ImGui::Render( );
|
||||
auto const& io{ ImGui::GetIO( ) };
|
||||
if ( io.WantCaptureKeyboard || io.WantTextInput || !modals_.empty( ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
void T_UIApp::swap( ) const noexcept
|
||||
{
|
||||
SDL_GL_SwapWindow( window_ );
|
||||
for ( auto i = 0u ; i < kbKeys_.size( ) ; i ++ ) {
|
||||
const T_KeyboardShortcut k{ kbKeys_[ i ] , kbMods_ };
|
||||
auto const* const ksSet{ shortcuts_.get( k ) };
|
||||
if ( !ksSet ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto nsk{ ksSet->size( ) };
|
||||
for ( auto j = 0u ; j < nsk ; j ++ ) {
|
||||
T_String const& s{ (*ksSet)[ j ] };
|
||||
auto const* const a{ actions_.get( s ) };
|
||||
if ( a && ( !a->enabled || a->enabled( ) ) ) {
|
||||
a->handler( );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void T_UIApp::handleDialogs( ) noexcept
|
||||
|
|
20
ui-app.hh
20
ui-app.hh
|
@ -3,6 +3,8 @@
|
|||
#include "ui-mousectrl.hh"
|
||||
#include "ui-actions.hh"
|
||||
|
||||
#include <ebcl/Sets.hh>
|
||||
|
||||
|
||||
/*= WINDOW MANAGEMENT ========================================================*/
|
||||
|
||||
|
@ -33,15 +35,6 @@ struct T_UIApp
|
|||
void actionMenu( T_String const& id ) const noexcept;
|
||||
void actionButton( T_String const& id ) const noexcept;
|
||||
|
||||
template< typename... Args >
|
||||
T_UIAction& newAction( Args&&... args )
|
||||
{
|
||||
T_UIAction a{ std::forward< Args >( args ) ... };
|
||||
T_String id{ a.id };
|
||||
addAction( std::move( a ) );
|
||||
return *actions_.get( id );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
ImFont* defaultFont( ) const noexcept
|
||||
|
@ -78,6 +71,10 @@ struct T_UIApp
|
|||
// Do we need to quit?
|
||||
bool exiting_{ false };
|
||||
|
||||
// Keyboard events / state
|
||||
T_KeyboardModifiers kbMods_;
|
||||
T_AutoArray< char , 32 > kbKeys_;
|
||||
|
||||
// Mouse capture
|
||||
bool mCapture_{ false };
|
||||
ImVec2 mInitial_{ 0 , 0 };
|
||||
|
@ -92,8 +89,13 @@ struct T_UIApp
|
|||
[]( T_UIAction const& a ) -> T_String {
|
||||
return a.id;
|
||||
} };
|
||||
T_KeyValueTable< T_KeyboardShortcut , ebcl::T_Set< T_String > > shortcuts_;
|
||||
|
||||
// Event handling
|
||||
void handleMouseCapture( ) noexcept;
|
||||
void handleKeyboardShortcuts( ) noexcept;
|
||||
|
||||
// Modals
|
||||
void handleDialogs( ) noexcept;
|
||||
};
|
||||
|
||||
|
|
12
ui-sync.cc
12
ui-sync.cc
|
@ -12,7 +12,7 @@
|
|||
|
||||
T_UISync::T_UISync( )
|
||||
{
|
||||
UI::Main( ).newAction( "Save curves" , []() {
|
||||
UI::Main( ).addAction( T_UIAction{ "Save curves" , []() {
|
||||
if ( Common::Sync( ).curvesFileChanged( ) ) {
|
||||
UI::Main( ).msgbox(
|
||||
"Curves file changed" ,
|
||||
|
@ -27,12 +27,12 @@ T_UISync::T_UISync( )
|
|||
} else {
|
||||
Common::Sync( ).saveCurves( );
|
||||
}
|
||||
} ).setEnabledCheck( []() {
|
||||
} }.setEnabledCheck( []() {
|
||||
return Common::Sync( ).curvesModified( );
|
||||
} ).setIcon( ICON_FA_FLOPPY_O )
|
||||
.setShortcut( T_KeyboardShortcut{ 's' , E_KeyboardModifier::CTRL } );
|
||||
.setShortcut( T_KeyboardShortcut{ 's' , E_KeyboardModifier::CTRL } ) );
|
||||
//-----------------------------------------------------------------------------
|
||||
UI::Main( ).newAction( "Reload curves" , []() {
|
||||
UI::Main( ).addAction( T_UIAction{ "Reload curves" , []() {
|
||||
UI::Main( ).msgbox(
|
||||
"Reload curves?" ,
|
||||
"Changes you made to the curves will be lost. Do you "
|
||||
|
@ -42,11 +42,11 @@ T_UISync::T_UISync( )
|
|||
Common::Sync( ).loadCurves( );
|
||||
}
|
||||
} , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } );
|
||||
} ).setEnabledCheck( []() {
|
||||
} }.setEnabledCheck( []() {
|
||||
return Common::Sync( ).curvesModified( );
|
||||
} ).setIcon( ICON_FA_DOWNLOAD )
|
||||
.setShortcut( T_KeyboardShortcut{ 'r' ,
|
||||
{ E_KeyboardModifier::CTRL , E_KeyboardModifier::SHIFT } } );
|
||||
{ E_KeyboardModifier::CTRL , E_KeyboardModifier::SHIFT } } ) );
|
||||
//-----------------------------------------------------------------------------
|
||||
const auto addui{ [this]( char const* type , F_Override ov ) {
|
||||
const bool ok{ sovuis_.add( T_String{ type } , std::move( ov ) ) };
|
||||
|
|
Loading…
Reference in a new issue