2017-10-04 11:20:27 +02:00
|
|
|
#include "externals.hh"
|
2017-11-24 11:59:15 +01:00
|
|
|
|
|
|
|
#include "common.hh"
|
|
|
|
#include "c-sync.hh"
|
|
|
|
#include "c-undo.hh"
|
|
|
|
|
2017-11-24 09:51:05 +01:00
|
|
|
#include "ui.hh"
|
2017-11-23 22:51:50 +01:00
|
|
|
#include "ui-app.hh"
|
2017-11-23 14:47:25 +01:00
|
|
|
#include "ui-imgui-sdl.hh"
|
2017-11-24 09:51:05 +01:00
|
|
|
#include "ui-texture.hh"
|
2017-11-23 14:47:25 +01:00
|
|
|
|
2017-11-20 21:54:46 +01:00
|
|
|
#include <imgui_internal.h>
|
2017-10-04 11:20:27 +02:00
|
|
|
|
2017-11-22 14:13:02 +01:00
|
|
|
|
2017-11-23 22:51:50 +01:00
|
|
|
/*= T_UIApp =================================================================*/
|
2017-11-22 14:13:02 +01:00
|
|
|
|
2017-11-21 17:32:52 +01:00
|
|
|
namespace {
|
|
|
|
#include "font-awesome.inl"
|
|
|
|
|
|
|
|
static const ImWchar IconsRanges_[] = {
|
|
|
|
ICON_MIN_FA ,
|
|
|
|
ICON_MAX_FA ,
|
|
|
|
0
|
|
|
|
};
|
2017-11-22 14:13:02 +01:00
|
|
|
} // namespace <anon>
|
2017-10-04 11:20:27 +02:00
|
|
|
|
2017-11-24 11:34:17 +01:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2017-11-23 22:51:50 +01:00
|
|
|
T_UIApp::T_UIApp( )
|
2017-10-04 11:20:27 +02:00
|
|
|
{
|
|
|
|
SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER );
|
|
|
|
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER , 1 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE , 24 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE , 8 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION , 2 );
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION , 2 );
|
|
|
|
|
|
|
|
SDL_DisplayMode current;
|
|
|
|
SDL_GetCurrentDisplayMode( 0 , ¤t );
|
2017-11-24 10:08:41 +01:00
|
|
|
window_ = SDL_CreateWindow( "Tourista",
|
2017-10-04 11:20:27 +02:00
|
|
|
SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED ,
|
|
|
|
1280 , 720 ,
|
|
|
|
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
|
2017-11-24 09:51:05 +01:00
|
|
|
gl_ = SDL_GL_CreateContext( window_ );
|
2017-10-04 11:20:27 +02:00
|
|
|
glewInit( );
|
|
|
|
if ( !GLEW_VERSION_4_5 ) {
|
|
|
|
fprintf( stderr , "OpenGL 4.5 required\n" );
|
|
|
|
exit( 1 );
|
|
|
|
}
|
|
|
|
|
2017-11-24 09:51:05 +01:00
|
|
|
ImGui_ImplSdl_Init( window_ );
|
2017-11-20 21:54:46 +01:00
|
|
|
|
|
|
|
using namespace ImGui;
|
2017-11-21 17:32:52 +01:00
|
|
|
StyleColorsDark( );
|
2017-11-20 21:54:46 +01:00
|
|
|
ImGuiIO& io{ GetIO( ) };
|
2017-11-22 09:01:51 +01:00
|
|
|
io.IniFilename = nullptr;
|
2017-11-20 21:54:46 +01:00
|
|
|
{
|
|
|
|
ImFontConfig cfg;
|
|
|
|
cfg.SizePixels = 13.0f;
|
|
|
|
defaultFont_ = io.Fonts->AddFontDefault( &cfg );
|
2017-11-21 17:32:52 +01:00
|
|
|
|
|
|
|
ImFontConfig icons;
|
|
|
|
icons.MergeMode = true;
|
|
|
|
icons.PixelSnapH = true;
|
|
|
|
io.Fonts->AddFontFromMemoryCompressedBase85TTF(
|
|
|
|
FontAwesome__compressed_data_base85 , 13.f ,
|
|
|
|
&icons , IconsRanges_ );
|
2017-11-20 21:54:46 +01:00
|
|
|
}
|
|
|
|
{
|
|
|
|
ImFontConfig cfg;
|
2017-11-25 09:31:08 +01:00
|
|
|
cfg.SizePixels = 11.0f;
|
2017-11-20 21:54:46 +01:00
|
|
|
smallFont_ = io.Fonts->AddFontDefault( &cfg );
|
2017-11-21 17:32:52 +01:00
|
|
|
|
|
|
|
ImFontConfig icons;
|
|
|
|
icons.MergeMode = true;
|
|
|
|
icons.PixelSnapH = true;
|
|
|
|
icons.DstFont = smallFont_;
|
|
|
|
io.Fonts->AddFontFromMemoryCompressedBase85TTF(
|
|
|
|
FontAwesome__compressed_data_base85 , 9.f ,
|
|
|
|
&icons , IconsRanges_ );
|
2017-11-20 21:54:46 +01:00
|
|
|
}
|
2017-11-24 11:59:15 +01:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Keyboard shortcuts for undo/redo/quit/etc.
|
|
|
|
|
|
|
|
addAction( T_UIAction{ "Undo" , []() {
|
|
|
|
Common::Undo( ).undo( );
|
|
|
|
} }.setEnabledCheck( []() {
|
|
|
|
return Common::Undo( ).canUndo( );
|
|
|
|
} ).setIcon( ICON_FA_UNDO )
|
|
|
|
.setShortcut( T_KeyboardShortcut{ 'z' , E_KbdMod::CTRL } ) );
|
|
|
|
|
|
|
|
addAction( T_UIAction{ "Redo" , []() {
|
|
|
|
Common::Undo( ).redo( );
|
|
|
|
} }.setEnabledCheck( []() {
|
|
|
|
return Common::Undo( ).canRedo( );
|
|
|
|
} ).setShortcut( T_KeyboardShortcut{ 'z' , { E_KbdMod::CTRL , E_KbdMod::SHIFT } } ) );
|
|
|
|
|
|
|
|
addAction( T_UIAction{ "Play" , []() {
|
|
|
|
Common::Sync( ).playing( ) = true;
|
|
|
|
} }.setEnabledCheck( []() {
|
|
|
|
auto const& s{ Common::Sync( ) };
|
|
|
|
return !s.playing( ) && !s.finished( );
|
|
|
|
} ).setIcon( ICON_FA_PLAY )
|
|
|
|
.setShortcut( T_KeyboardShortcut{ ' ' } ) );
|
|
|
|
|
|
|
|
addAction( T_UIAction{ "Stop" , []() {
|
|
|
|
Common::Sync( ).playing( ) = false;
|
|
|
|
} }.setEnabledCheck( []() {
|
|
|
|
auto const& s{ Common::Sync( ) };
|
|
|
|
return s.playing( );
|
|
|
|
} ).setIcon( ICON_FA_STOP )
|
|
|
|
.setShortcut( T_KeyboardShortcut{ ' ' } ) );
|
|
|
|
|
|
|
|
addAction( T_UIAction{ "Quit" , [this]() {
|
|
|
|
exiting_ = true;
|
|
|
|
} }.setShortcut( T_KeyboardShortcut{ 'q' , E_KbdMod::CTRL } ) );
|
2017-10-04 11:20:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-23 22:51:50 +01:00
|
|
|
T_UIApp::~T_UIApp( )
|
2017-10-04 11:20:27 +02:00
|
|
|
{
|
|
|
|
ImGui_ImplSdl_Shutdown( );
|
2017-11-24 09:51:05 +01:00
|
|
|
SDL_GL_DeleteContext( gl_ );
|
|
|
|
SDL_DestroyWindow( window_ );
|
2017-10-04 11:20:27 +02:00
|
|
|
SDL_Quit( );
|
|
|
|
}
|
|
|
|
|
2017-11-24 11:34:17 +01:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2017-11-23 22:51:50 +01:00
|
|
|
void T_UIApp::addAction(
|
2017-11-23 13:54:27 +01:00
|
|
|
T_UIAction action ) noexcept
|
|
|
|
{
|
2017-11-24 11:34:17 +01:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
2017-11-23 13:54:27 +01:00
|
|
|
actions_.set( std::move( action ) );
|
|
|
|
}
|
|
|
|
|
2017-11-23 22:51:50 +01:00
|
|
|
void T_UIApp::actionMenu(
|
2017-11-23 13:54:27 +01:00
|
|
|
T_String const& id ) const noexcept
|
|
|
|
{
|
|
|
|
auto const* const a{ actions_.get( id ) };
|
|
|
|
if ( a ) {
|
|
|
|
a->menuItem( );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 22:51:50 +01:00
|
|
|
void T_UIApp::actionButton(
|
2017-11-23 13:54:27 +01:00
|
|
|
T_String const& id ) const noexcept
|
|
|
|
{
|
|
|
|
auto const* const a{ actions_.get( id ) };
|
|
|
|
if ( a ) {
|
|
|
|
a->tbButton( );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-24 11:34:17 +01:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2017-11-24 09:51:05 +01:00
|
|
|
void T_UIApp::handleEvents( ) noexcept
|
2017-10-04 11:20:27 +02:00
|
|
|
{
|
2017-11-24 09:51:05 +01:00
|
|
|
SDL_Event event;
|
|
|
|
mMove_ = ImVec2( );
|
2017-11-24 11:34:17 +01:00
|
|
|
kbKeys_.clear( );
|
2017-11-24 09:51:05 +01:00
|
|
|
while ( SDL_PollEvent( &event ) ) {
|
|
|
|
ImGui_ImplSdl_ProcessEvent( &event );
|
|
|
|
if ( event.type == SDL_QUIT ) {
|
|
|
|
#warning FIXME request confirmation
|
|
|
|
exiting_ = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( mCapture_ && event.type == SDL_MOUSEMOTION ) {
|
|
|
|
mMove_.x += event.motion.xrel;
|
|
|
|
mMove_.y += event.motion.yrel;
|
|
|
|
}
|
2017-11-24 11:34:17 +01:00
|
|
|
|
|
|
|
if ( event.type == SDL_KEYDOWN ) {
|
|
|
|
const auto sym{ event.key.keysym.sym };
|
|
|
|
if ( sym >= 0 && sym <= 127 ) {
|
|
|
|
kbKeys_.add( char( sym ) );
|
|
|
|
}
|
|
|
|
}
|
2017-11-24 09:51:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui_ImplSdl_NewFrame( window_ , mCapture_ , mInitial_ );
|
2017-11-24 11:34:17 +01:00
|
|
|
|
|
|
|
auto& io( ImGui::GetIO( ) );
|
|
|
|
io.MouseDrawCursor = true;
|
|
|
|
kbMods_ = ( ([&io]() {
|
2017-11-24 11:48:08 +01:00
|
|
|
T_KbdMods kb;
|
2017-11-24 11:34:17 +01:00
|
|
|
if ( io.KeyCtrl ) {
|
2017-11-24 11:48:08 +01:00
|
|
|
kb |= E_KbdMod::CTRL;
|
2017-11-24 11:34:17 +01:00
|
|
|
}
|
|
|
|
if ( io.KeyShift ) {
|
2017-11-24 11:48:08 +01:00
|
|
|
kb |= E_KbdMod::SHIFT;
|
2017-11-24 11:34:17 +01:00
|
|
|
}
|
|
|
|
if ( io.KeyAlt ) {
|
2017-11-24 11:48:08 +01:00
|
|
|
kb |= E_KbdMod::ALT;
|
2017-11-24 11:34:17 +01:00
|
|
|
}
|
|
|
|
return kb;
|
|
|
|
})() );
|
|
|
|
|
|
|
|
handleKeyboardShortcuts( );
|
2017-11-24 09:51:05 +01:00
|
|
|
handleMouseCapture( );
|
|
|
|
}
|
|
|
|
|
2017-11-24 11:34:17 +01:00
|
|
|
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_ );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
2017-11-24 09:51:05 +01:00
|
|
|
void T_UIApp::handleMouseCapture( ) noexcept
|
|
|
|
{
|
|
|
|
using namespace ImGui;
|
|
|
|
auto const& io( GetIO( ) );
|
|
|
|
const T_MouseButtons mb( ([]() {;
|
|
|
|
T_MouseButtons mb;
|
|
|
|
if ( IsMouseDown( 0 ) ) {
|
|
|
|
mb |= E_MouseButton::LEFT;
|
|
|
|
}
|
|
|
|
if ( IsMouseDown( 1 ) ) {
|
|
|
|
mb |= E_MouseButton::RIGHT;
|
|
|
|
}
|
|
|
|
if ( IsMouseDown( 2 ) ) {
|
|
|
|
mb |= E_MouseButton::MIDDLE;
|
|
|
|
}
|
|
|
|
return mb;
|
|
|
|
})() );
|
|
|
|
const bool appCanGrab( !( ImGui::IsMouseHoveringAnyWindow( )
|
|
|
|
|| io.WantCaptureMouse
|
|
|
|
|| io.WantCaptureKeyboard ) );
|
|
|
|
|
|
|
|
if ( mCapture_ && !( mb && mDelegate_ ) ) {
|
|
|
|
mCapture_ = false;
|
|
|
|
CaptureMouseFromApp( false );
|
|
|
|
SDL_SetRelativeMouseMode( SDL_FALSE );
|
|
|
|
SDL_WarpMouseInWindow( window_ , mInitial_.x , mInitial_.y );
|
|
|
|
SetMouseCursor( ImGuiMouseCursor_Arrow );
|
|
|
|
|
|
|
|
} else if ( mCapture_ && mDelegate_ ) {
|
|
|
|
SetMouseCursor( ImGuiMouseCursor_Move );
|
2017-11-24 11:34:17 +01:00
|
|
|
mDelegate_->handleDragAndDrop( mMove_ , kbMods_ , mb );
|
2017-11-24 09:51:05 +01:00
|
|
|
|
|
|
|
} else if ( appCanGrab && mb && mDelegate_ ) {
|
|
|
|
mCapture_ = true;
|
|
|
|
mInitial_ = GetMousePos( );
|
|
|
|
CaptureMouseFromApp( true );
|
|
|
|
SDL_SetRelativeMouseMode( SDL_TRUE );
|
|
|
|
SetMouseCursor( ImGuiMouseCursor_Move );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ( appCanGrab || mCapture_ ) && io.MouseWheel && mDelegate_ ) {
|
2017-11-24 11:34:17 +01:00
|
|
|
mDelegate_->handleWheel( io.MouseWheel , kbMods_ , mb );
|
2017-11-24 09:51:05 +01:00
|
|
|
}
|
2017-10-04 11:20:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-24 11:34:17 +01:00
|
|
|
void T_UIApp::handleKeyboardShortcuts( ) noexcept
|
2017-10-04 11:20:27 +02:00
|
|
|
{
|
2017-11-24 11:34:17 +01:00
|
|
|
auto const& io{ ImGui::GetIO( ) };
|
|
|
|
if ( io.WantCaptureKeyboard || io.WantTextInput || !modals_.empty( ) ) {
|
|
|
|
return;
|
|
|
|
}
|
2017-10-04 11:20:27 +02:00
|
|
|
|
2017-11-24 11:34:17 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-04 11:20:27 +02:00
|
|
|
}
|
2017-11-22 14:13:02 +01:00
|
|
|
|
2017-11-23 22:51:50 +01:00
|
|
|
void T_UIApp::handleDialogs( ) noexcept
|
2017-11-22 14:13:02 +01:00
|
|
|
{
|
|
|
|
const auto nDialogs{ modals_.size( ) };
|
|
|
|
for ( auto i = 0u ; i < nDialogs ; i ++ ) {
|
|
|
|
const bool keep{ modals_[ i ]->draw( ) };
|
|
|
|
assert( keep || i + 1 == nDialogs );
|
|
|
|
if ( !keep ) {
|
|
|
|
modals_.removeLast( );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|