2012-06-29 16:44:26 +02:00
//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
2020-07-30 11:42:28 -03:00
// Remere's Map Editor is free software: you can redistribute it and/or modify
2012-06-29 16:44:26 +02:00
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2016-09-29 19:24:45 -03:00
//
2020-07-30 11:42:28 -03:00
// Remere's Map Editor is distributed in the hope that it will be useful,
2012-06-29 16:44:26 +02:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2020-07-30 11:42:28 -03:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2012-06-29 16:44:26 +02:00
// GNU General Public License for more details.
2016-09-29 19:24:45 -03:00
//
2012-06-29 16:44:26 +02:00
// You should have received a copy of the GNU General Public License
2020-07-30 11:42:28 -03:00
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2012-06-29 16:44:26 +02:00
//////////////////////////////////////////////////////////////////////
# include "main.h"
# include "application.h"
# include "sprites.h"
# include "editor.h"
# include "common_windows.h"
# include "palette_window.h"
# include "preferences.h"
# include "result_window.h"
# include "minimap_window.h"
# include "about_window.h"
# include "main_menubar.h"
# include "updater.h"
2019-06-04 17:42:28 -03:00
# include "artprovider.h"
2012-06-29 16:44:26 +02:00
# include "materials.h"
# include "map.h"
# include "complexitem.h"
2021-05-25 00:29:12 -03:00
# include "monster.h"
# include "npc.h"
2026-03-02 14:07:42 -03:00
# include "lua/lua_script_manager.h"
2012-06-29 16:44:26 +02:00
2015-12-06 09:59:50 -03:00
# include "../brushes/icon/rme_icon.xpm"
2012-06-29 16:44:26 +02:00
BEGIN_EVENT_TABLE ( MainFrame , wxFrame )
2023-10-09 19:12:16 -07:00
EVT_CLOSE ( MainFrame : : OnExit )
2012-06-29 16:44:26 +02:00
2023-10-09 19:12:16 -07:00
// Update check complete
2012-06-29 16:44:26 +02:00
# ifdef _USE_UPDATER_
2023-10-09 19:12:16 -07:00
EVT_ON_UPDATE_CHECK_FINISHED ( wxID_ANY , MainFrame : : OnUpdateReceived )
2012-06-29 16:44:26 +02:00
# endif
2023-10-09 19:12:16 -07:00
EVT_ON_UPDATE_MENUS ( wxID_ANY , MainFrame : : OnUpdateMenus )
EVT_ON_UPDATE_ACTIONS ( wxID_ANY , MainFrame : : OnUpdateActions )
2012-06-29 16:44:26 +02:00
2023-10-09 19:12:16 -07:00
// Idle event handler
EVT_IDLE ( MainFrame : : OnIdle )
2012-06-29 16:44:26 +02:00
END_EVENT_TABLE ( )
BEGIN_EVENT_TABLE ( MapWindow , wxPanel )
2023-10-09 19:12:16 -07:00
EVT_SIZE ( MapWindow : : OnSize )
EVT_COMMAND_SCROLL_TOP ( MAP_WINDOW_HSCROLL , MapWindow : : OnScroll )
EVT_COMMAND_SCROLL_BOTTOM ( MAP_WINDOW_HSCROLL , MapWindow : : OnScroll )
EVT_COMMAND_SCROLL_THUMBTRACK ( MAP_WINDOW_HSCROLL , MapWindow : : OnScroll )
EVT_COMMAND_SCROLL_LINEUP ( MAP_WINDOW_HSCROLL , MapWindow : : OnScrollLineUp )
EVT_COMMAND_SCROLL_LINEDOWN ( MAP_WINDOW_HSCROLL , MapWindow : : OnScrollLineDown )
EVT_COMMAND_SCROLL_PAGEUP ( MAP_WINDOW_HSCROLL , MapWindow : : OnScrollPageUp )
EVT_COMMAND_SCROLL_PAGEDOWN ( MAP_WINDOW_HSCROLL , MapWindow : : OnScrollPageDown )
EVT_COMMAND_SCROLL_TOP ( MAP_WINDOW_VSCROLL , MapWindow : : OnScroll )
EVT_COMMAND_SCROLL_BOTTOM ( MAP_WINDOW_VSCROLL , MapWindow : : OnScroll )
EVT_COMMAND_SCROLL_THUMBTRACK ( MAP_WINDOW_VSCROLL , MapWindow : : OnScroll )
EVT_COMMAND_SCROLL_LINEUP ( MAP_WINDOW_VSCROLL , MapWindow : : OnScrollLineUp )
EVT_COMMAND_SCROLL_LINEDOWN ( MAP_WINDOW_VSCROLL , MapWindow : : OnScrollLineDown )
EVT_COMMAND_SCROLL_PAGEUP ( MAP_WINDOW_VSCROLL , MapWindow : : OnScrollPageUp )
EVT_COMMAND_SCROLL_PAGEDOWN ( MAP_WINDOW_VSCROLL , MapWindow : : OnScrollPageDown )
EVT_BUTTON ( MAP_WINDOW_GEM , MapWindow : : OnGem )
2012-06-29 16:44:26 +02:00
END_EVENT_TABLE ( )
BEGIN_EVENT_TABLE ( MapScrollBar , wxScrollBar )
2023-10-09 19:12:16 -07:00
EVT_KEY_DOWN ( MapScrollBar : : OnKey )
EVT_KEY_UP ( MapScrollBar : : OnKey )
EVT_CHAR ( MapScrollBar : : OnKey )
EVT_SET_FOCUS ( MapScrollBar : : OnFocus )
EVT_MOUSEWHEEL ( MapScrollBar : : OnWheel )
2012-06-29 16:44:26 +02:00
END_EVENT_TABLE ( )
2026-05-02 18:14:41 -03:00
# ifdef RME_CMAKE_BUILD
wxIMPLEMENT_APP_NO_MAIN ( Application ) ;
# else
2012-07-01 13:41:59 +02:00
wxIMPLEMENT_APP ( Application ) ;
2026-05-02 18:14:41 -03:00
# endif
2012-06-29 16:44:26 +02:00
2023-10-09 19:12:16 -07:00
Application : : ~ Application ( ) {
2012-06-29 16:44:26 +02:00
// Destroy
}
2023-10-09 19:12:16 -07:00
bool Application : : OnInit ( ) {
2014-01-22 20:16:17 +01:00
# if defined __DEBUG_MODE__ && defined __WINDOWS__
2023-10-09 19:12:16 -07:00
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ) ;
2012-06-29 16:44:26 +02:00
# endif
2025-05-10 16:38:45 -03:00
spdlog : : info ( " This is free software: you are free to change and redistribute it " ) ;
spdlog : : info ( " There is NO WARRANTY, to the extent permitted by law " ) ;
spdlog : : info ( " Review COPYING in RME distribution for details " ) ;
spdlog : : info ( " Visit our website for updates, support, and resources: https://docs.opentibiabr.com/ " ) ;
spdlog : : info ( " Application started sucessfull! \n " ) ;
2014-01-22 20:16:17 +01:00
mt_seed ( time ( nullptr ) ) ;
srand ( time ( nullptr ) ) ;
2012-06-29 16:44:26 +02:00
2014-01-24 02:33:09 -02:00
// Discover data directory
2016-09-29 20:30:54 -03:00
g_gui . discoverDataDirectory ( " clients.xml " ) ;
2014-01-24 02:33:09 -02:00
2012-06-29 16:44:26 +02:00
// Tell that we are the real thing
wxAppConsole : : SetInstance ( this ) ;
2019-06-04 17:42:28 -03:00
wxArtProvider : : Push ( new ArtProvider ( ) ) ;
2016-09-29 19:24:45 -03:00
2012-06-29 16:44:26 +02:00
// Load some internal stuff
2016-09-29 20:37:43 -03:00
g_settings . load ( ) ;
2016-09-29 20:30:54 -03:00
g_gui . LoadHotkeys ( ) ;
2025-05-10 16:38:45 -03:00
ClientAssets : : load ( ) ;
2012-06-29 16:44:26 +02:00
# ifdef _USE_PROCESS_COM
2023-10-09 19:12:16 -07:00
m_single_instance_checker = newd wxSingleInstanceChecker ; // Instance checker has to stay alive throughout the applications lifetime
2017-01-22 14:12:32 +01:00
if ( g_settings . getInteger ( Config : : ONLY_ONE_INSTANCE ) & & m_single_instance_checker - > IsAnotherRunning ( ) ) {
RMEProcessClient client ;
wxConnectionBase * connection = client . MakeConnection ( " localhost " , " rme_host " , " rme_talk " ) ;
if ( connection ) {
wxString fileName ;
if ( ParseCommandLineMap ( fileName ) ) {
2023-10-09 19:12:16 -07:00
wxLogNull nolog ; // We might get a timeout message if the file fails to open on the running instance. Let's not show that message.
2017-01-22 14:12:32 +01:00
connection - > Execute ( fileName ) ;
2012-06-29 16:44:26 +02:00
}
2017-01-22 14:12:32 +01:00
connection - > Disconnect ( ) ;
wxDELETE ( connection ) ;
2012-06-29 16:44:26 +02:00
}
2017-01-22 14:12:32 +01:00
wxDELETE ( m_single_instance_checker ) ;
2023-10-09 19:12:16 -07:00
return false ; // Since we return false - OnExit is never called
2017-01-22 14:12:32 +01:00
}
// We act as server then
m_proc_server = newd RMEProcessServer ( ) ;
2023-10-09 19:12:16 -07:00
if ( ! m_proc_server - > Create ( " rme_host " ) ) {
2017-01-22 14:12:32 +01:00
wxLogWarning ( " Could not register IPC service! " ) ;
2012-06-29 16:44:26 +02:00
}
# endif
// Image handlers
2023-10-09 19:12:16 -07:00
// wxImage::AddHandler(newd wxBMPHandler);
2012-06-29 16:44:26 +02:00
wxImage : : AddHandler ( newd wxPNGHandler ) ;
wxImage : : AddHandler ( newd wxJPEGHandler ) ;
wxImage : : AddHandler ( newd wxTGAHandler ) ;
2016-09-29 20:30:54 -03:00
g_gui . gfx . loadEditorSprites ( ) ;
2012-06-29 16:44:26 +02:00
# ifndef __DEBUG_MODE__
2023-10-09 19:12:16 -07:00
// wxHandleFatalExceptions(true);
2012-06-29 16:44:26 +02:00
# endif
2014-01-22 20:16:17 +01:00
2023-10-09 19:12:16 -07:00
m_file_to_open = wxEmptyString ;
ParseCommandLineMap ( m_file_to_open ) ;
2019-06-25 18:07:36 +02:00
2023-10-09 19:12:16 -07:00
g_gui . root = newd MainFrame ( __W_RME_APPLICATION_NAME__ , wxDefaultPosition , wxSize ( 700 , 500 ) ) ;
2016-09-29 20:30:54 -03:00
SetTopWindow ( g_gui . root ) ;
2016-11-05 15:28:14 +01:00
g_gui . SetTitle ( " " ) ;
2012-06-29 16:44:26 +02:00
2016-09-29 20:30:54 -03:00
g_gui . root - > LoadRecentFiles ( ) ;
2012-06-29 16:44:26 +02:00
// Load palette
2016-09-29 20:30:54 -03:00
g_gui . LoadPerspective ( ) ;
2012-06-29 16:44:26 +02:00
2026-03-02 14:07:42 -03:00
// Initialize Lua scripting system
if ( ! g_luaScripts . initialize ( ) ) {
feat: add Lua API modules and Script Manager UI (#161)
This commit adds the full Lua scripting API and integrates the Script Manager into the application.
It builds on top of the scripting engine introduced in #158, exposing all the API modules that Lua scripts can use and making everything accessible from the UI.
Changes:
- Added all Lua API modules: map, tile, item, brush, image, position, selection, creature, color, app, dialog, noise, algo, geo, json, http.
- Added map overlay system for scripts to draw on the map view.
- Added event system, context menu registration, persistent storage, and transaction support with undo/redo.
- Added support for package scripts (directory with manifest.lua) and script metadata tags.
- Added Scripts menu to the menubar with per-script execution and reload.
- Connected the Script Manager window to the UI.
- Added missing build dependencies and fixed MSVC compilation errors.
Notes:
- Build dependencies were added for HTTP and noise generation support.
- Some code was adjusted to compile correctly on MSVC.
2026-03-28 19:15:57 -03:00
spdlog : : error ( " Failed to initialize Lua scripting: {} " , g_luaScripts . getLastError ( ) ) ;
} else if ( g_gui . root & & g_gui . root - > menu_bar ) {
g_gui . root - > menu_bar - > LoadScriptsMenu ( ) ;
2026-03-02 14:07:42 -03:00
}
2023-10-09 19:12:16 -07:00
wxIcon icon ( rme_icon ) ;
g_gui . root - > SetIcon ( icon ) ;
2019-06-27 22:23:28 +02:00
2023-10-09 19:12:16 -07:00
if ( g_settings . getInteger ( Config : : WELCOME_DIALOG ) = = 1 & & m_file_to_open = = wxEmptyString ) {
g_gui . ShowWelcomeDialog ( icon ) ;
} else {
g_gui . root - > Show ( ) ;
}
2019-06-27 22:23:28 +02:00
2012-06-29 16:44:26 +02:00
// Set idle event handling mode
wxIdleEvent : : SetMode ( wxIDLE_PROCESS_SPECIFIED ) ;
// Goto RME website?
2023-10-09 19:12:16 -07:00
if ( g_settings . getInteger ( Config : : GOTO_WEBSITE_ON_BOOT ) = = 1 ) {
2016-11-05 15:28:14 +01:00
: : wxLaunchDefaultBrowser ( " http://www.remeresmapeditor.com/ " , wxBROWSER_NEW_WINDOW ) ;
2016-09-29 20:37:43 -03:00
g_settings . setInteger ( Config : : GOTO_WEBSITE_ON_BOOT , 0 ) ;
2012-06-29 16:44:26 +02:00
}
// Check for updates
# ifdef _USE_UPDATER_
2023-10-09 19:12:16 -07:00
if ( g_settings . getInteger ( Config : : USE_UPDATER ) = = - 1 ) {
2016-09-29 20:30:54 -03:00
int ret = g_gui . PopupDialog (
2016-11-05 15:28:14 +01:00
" Notice " ,
" Do you want the editor to automatically check for updates? \n "
" It will connect to the internet if you choose yes. \n "
2023-10-09 19:12:16 -07:00
" You can change this setting in the preferences later. " ,
wxYES | wxNO
) ;
if ( ret = = wxID_YES ) {
2016-09-29 20:37:43 -03:00
g_settings . setInteger ( Config : : USE_UPDATER , 1 ) ;
2015-12-06 11:42:37 -03:00
} else {
2016-09-29 20:37:43 -03:00
g_settings . setInteger ( Config : : USE_UPDATER , 0 ) ;
2012-06-29 16:44:26 +02:00
}
}
2023-10-09 19:12:16 -07:00
if ( g_settings . getInteger ( Config : : USE_UPDATER ) = = 1 ) {
2012-06-29 16:44:26 +02:00
UpdateChecker updater ;
2016-09-29 20:30:54 -03:00
updater . connect ( g_gui . root ) ;
2012-06-29 16:44:26 +02:00
}
# endif
2019-06-25 18:07:36 +02:00
FileName save_failed_file = GUI : : GetLocalDataDirectory ( ) ;
2016-11-05 15:28:14 +01:00
save_failed_file . SetName ( " .saving.txt " ) ;
2023-10-09 19:12:16 -07:00
if ( save_failed_file . FileExists ( ) ) {
2012-06-29 16:44:26 +02:00
std : : ifstream f ( nstr ( save_failed_file . GetFullPath ( ) ) . c_str ( ) , std : : ios : : in ) ;
2021-05-25 00:29:12 -03:00
std : : string backup_otbm , backup_house , backup_spawn , backup_spawn_npc ;
2012-06-29 16:44:26 +02:00
getline ( f , backup_otbm ) ;
getline ( f , backup_house ) ;
getline ( f , backup_spawn ) ;
2021-05-25 00:29:12 -03:00
getline ( f , backup_spawn_npc ) ;
2012-06-29 16:44:26 +02:00
// Remove the file
f . close ( ) ;
std : : remove ( nstr ( save_failed_file . GetFullPath ( ) ) . c_str ( ) ) ;
// Query file retrieval if possible
2023-10-09 19:12:16 -07:00
if ( ! backup_otbm . empty ( ) ) {
2021-05-25 00:29:12 -03:00
long ret = g_gui . PopupDialog (
2016-11-05 15:28:14 +01:00
" Editor Crashed " ,
2012-06-29 16:44:26 +02:00
wxString (
2016-11-05 15:28:14 +01:00
" IMPORTANT! THE EDITOR CRASHED WHILE SAVING! \n \n "
2023-10-09 19:12:16 -07:00
" Do you want to recover the lost map? (it will be opened immediately): \n "
) < < wxstr ( backup_otbm )
< < " \n "
< < wxstr ( backup_house ) < < " \n "
< < wxstr ( backup_spawn ) < < " \n "
< < wxstr ( backup_spawn_npc ) < < " \n " ,
wxYES | wxNO
) ;
if ( ret = = wxID_YES ) {
2012-06-29 16:44:26 +02:00
// Recover if the user so wishes
2012-07-04 23:18:15 +02:00
std : : remove ( backup_otbm . substr ( 0 , backup_otbm . size ( ) - 1 ) . c_str ( ) ) ;
2012-06-29 16:44:26 +02:00
std : : rename ( backup_otbm . c_str ( ) , backup_otbm . substr ( 0 , backup_otbm . size ( ) - 1 ) . c_str ( ) ) ;
2012-07-04 23:18:15 +02:00
2023-10-09 19:12:16 -07:00
if ( ! backup_house . empty ( ) ) {
2012-07-04 23:18:15 +02:00
std : : remove ( backup_house . substr ( 0 , backup_house . size ( ) - 1 ) . c_str ( ) ) ;
2012-06-29 16:44:26 +02:00
std : : rename ( backup_house . c_str ( ) , backup_house . substr ( 0 , backup_house . size ( ) - 1 ) . c_str ( ) ) ;
2012-07-04 23:18:15 +02:00
}
2023-10-09 19:12:16 -07:00
if ( ! backup_spawn . empty ( ) ) {
2012-07-04 23:18:15 +02:00
std : : remove ( backup_spawn . substr ( 0 , backup_spawn . size ( ) - 1 ) . c_str ( ) ) ;
2012-06-29 16:44:26 +02:00
std : : rename ( backup_spawn . c_str ( ) , backup_spawn . substr ( 0 , backup_spawn . size ( ) - 1 ) . c_str ( ) ) ;
2012-07-04 23:18:15 +02:00
}
2023-10-09 19:12:16 -07:00
if ( ! backup_spawn_npc . empty ( ) ) {
2021-05-25 00:29:12 -03:00
std : : remove ( backup_spawn_npc . substr ( 0 , backup_spawn_npc . size ( ) - 1 ) . c_str ( ) ) ;
std : : rename ( backup_spawn_npc . c_str ( ) , backup_spawn_npc . substr ( 0 , backup_spawn_npc . size ( ) - 1 ) . c_str ( ) ) ;
}
2016-09-29 19:24:45 -03:00
2012-06-29 16:44:26 +02:00
// Load the map
2016-09-29 20:30:54 -03:00
g_gui . LoadMap ( wxstr ( backup_otbm . substr ( 0 , backup_otbm . size ( ) - 1 ) ) ) ;
2012-06-29 16:44:26 +02:00
return true ;
}
}
}
2023-10-09 19:12:16 -07:00
// Keep track of first event loop entry
m_startup = true ;
2012-06-29 16:44:26 +02:00
return true ;
}
2020-06-26 08:44:56 +02:00
void Application : : OnEventLoopEnter ( wxEventLoopBase * loop ) {
2023-10-09 19:12:16 -07:00
// First startup?
if ( ! m_startup ) {
return ;
}
m_startup = false ;
// Open a map.
if ( m_file_to_open ! = wxEmptyString ) {
g_gui . LoadMap ( FileName ( m_file_to_open ) ) ;
} else if ( ! g_gui . IsWelcomeDialogShown ( ) & & g_gui . NewMap ( ) ) { // Open a new empty map
// You generally don't want to save this map...
g_gui . GetCurrentEditor ( ) - > clearChanges ( ) ;
}
2020-06-26 08:44:56 +02:00
}
2023-10-09 19:12:16 -07:00
void Application : : MacOpenFiles ( const wxArrayString & fileNames ) {
2016-11-26 00:14:06 +01:00
if ( ! fileNames . IsEmpty ( ) ) {
2019-06-27 22:23:28 +02:00
g_gui . LoadMap ( FileName ( fileNames . Item ( 0 ) ) ) ;
2012-06-29 16:44:26 +02:00
}
}
2023-10-09 19:12:16 -07:00
void Application : : Unload ( ) {
2016-09-29 20:30:54 -03:00
g_gui . CloseAllEditors ( ) ;
g_gui . SaveHotkeys ( ) ;
g_gui . SavePerspective ( ) ;
g_gui . root - > SaveRecentFiles ( ) ;
2025-05-10 16:38:45 -03:00
ClientAssets : : save ( ) ;
2016-09-29 20:37:43 -03:00
g_settings . save ( true ) ;
2016-09-29 20:30:54 -03:00
g_gui . root = nullptr ;
2012-06-29 16:44:26 +02:00
}
2023-10-09 19:12:16 -07:00
int Application : : OnExit ( ) {
2026-03-02 14:07:42 -03:00
g_luaScripts . shutdown ( ) ;
2012-06-29 16:44:26 +02:00
# ifdef _USE_PROCESS_COM
2017-01-22 14:12:32 +01:00
wxDELETE ( m_proc_server ) ;
wxDELETE ( m_single_instance_checker ) ;
2012-06-29 16:44:26 +02:00
# endif
return 1 ;
}
2026-04-22 19:23:35 -03:00
void Application : : ShutdownServices ( ) {
g_luaScripts . shutdown ( ) ;
# ifdef _USE_PROCESS_COM
wxDELETE ( m_proc_server ) ;
wxDELETE ( m_single_instance_checker ) ;
# endif
}
2023-10-09 19:12:16 -07:00
void Application : : OnFatalException ( ) {
2015-12-06 11:42:37 -03:00
////
2012-06-29 16:44:26 +02:00
}
2023-10-09 19:12:16 -07:00
bool Application : : ParseCommandLineMap ( wxString & fileName ) {
if ( argc = = 2 ) {
2016-12-02 16:40:51 +01:00
fileName = wxString ( argv [ 1 ] ) ;
2019-06-25 20:12:12 +02:00
return true ;
2012-06-29 16:44:26 +02:00
}
2019-06-25 20:12:12 +02:00
return false ;
2012-06-29 16:44:26 +02:00
}
2023-10-09 19:12:16 -07:00
MainFrame : : MainFrame ( const wxString & title , const wxPoint & pos , const wxSize & size ) :
wxFrame ( ( wxFrame * ) nullptr , - 1 , title , pos , size , wxDEFAULT_FRAME_STYLE ) {
2012-06-29 16:44:26 +02:00
// Receive idle events
SetExtraStyle ( wxWS_EX_PROCESS_IDLE ) ;
2016-12-05 21:53:41 +01:00
2023-10-09 19:12:16 -07:00
# if wxCHECK_VERSION(3, 1, 0) // 3.1.0 or higher
// Make sure ShowFullScreen() uses the full screen API on macOS
EnableFullScreenView ( true ) ;
# endif
2016-12-05 21:53:41 +01:00
2012-06-29 16:44:26 +02:00
// Creates the file-dropdown menu
menu_bar = newd MainMenuBar ( this ) ;
wxArrayString warnings ;
wxString error ;
2014-01-24 02:33:09 -02:00
wxFileName filename ;
2016-11-05 15:28:14 +01:00
filename . Assign ( g_gui . getFoundDataDirectory ( ) + " menubar.xml " ) ;
2023-10-09 19:12:16 -07:00
if ( ! filename . FileExists ( ) ) {
2019-06-25 18:07:36 +02:00
filename = FileName ( GUI : : GetDataDirectory ( ) + " menubar.xml " ) ;
2023-10-09 19:12:16 -07:00
}
2014-01-24 02:33:09 -02:00
2023-10-09 19:12:16 -07:00
if ( ! menu_bar - > Load ( filename , warnings , error ) ) {
2016-11-05 15:28:14 +01:00
wxLogError ( wxString ( ) + " Could not load menubar.xml, editor will NOT be able to show its menu. \n " ) ;
2014-01-24 02:33:09 -02:00
}
2012-06-29 16:44:26 +02:00
wxStatusBar * statusbar = CreateStatusBar ( ) ;
2016-02-25 21:32:05 -03:00
statusbar - > SetFieldsCount ( 4 ) ;
2019-06-25 18:07:36 +02:00
SetStatusText ( wxString ( " Welcome to " ) < < __W_RME_APPLICATION_NAME__ < < " " < < __W_RME_VERSION__ ) ;
2012-06-29 16:44:26 +02:00
// Le sizer
2016-09-29 20:30:54 -03:00
g_gui . aui_manager = newd wxAuiManager ( this ) ;
g_gui . tabbook = newd MapTabbook ( this , wxID_ANY ) ;
2016-09-29 19:24:45 -03:00
2019-06-03 14:14:18 -03:00
tool_bar = newd MainToolBar ( this , g_gui . aui_manager ) ;
2016-09-29 20:30:54 -03:00
g_gui . aui_manager - > AddPane ( g_gui . tabbook , wxAuiPaneInfo ( ) . CenterPane ( ) . Floatable ( false ) . CloseButton ( false ) . PaneBorder ( false ) ) ;
g_gui . aui_manager - > Update ( ) ;
2012-06-29 16:44:26 +02:00
UpdateMenubar ( ) ;
}
2019-06-25 18:07:36 +02:00
MainFrame : : ~ MainFrame ( ) = default ;
2012-06-29 16:44:26 +02:00
2023-10-09 19:12:16 -07:00
void MainFrame : : OnIdle ( wxIdleEvent & event ) {
2015-12-06 11:42:37 -03:00
////
2012-06-29 16:44:26 +02:00
}
# ifdef _USE_UPDATER_
2023-10-09 19:12:16 -07:00
void MainFrame : : OnUpdateReceived ( wxCommandEvent & event ) {
2012-06-29 16:44:26 +02:00
std : : string data = * ( std : : string * ) event . GetClientData ( ) ;
delete ( std : : string * ) event . GetClientData ( ) ;
size_t first_colon = data . find ( ' : ' ) ;
2023-10-09 19:12:16 -07:00
size_t second_colon = data . find ( ' : ' , first_colon + 1 ) ;
2012-06-29 16:44:26 +02:00
2023-10-09 19:12:16 -07:00
if ( first_colon = = std : : string : : npos | | second_colon = = std : : string : : npos ) {
2012-06-29 16:44:26 +02:00
return ;
2023-10-09 19:12:16 -07:00
}
2012-06-29 16:44:26 +02:00
std : : string update = data . substr ( 0 , first_colon ) ;
2023-10-09 19:12:16 -07:00
std : : string verstr = data . substr ( first_colon + 1 , second_colon - first_colon - 1 ) ;
std : : string url = ( second_colon = = data . size ( ) ? " " : data . substr ( second_colon + 1 ) ) ;
2012-06-29 16:44:26 +02:00
2023-10-09 19:12:16 -07:00
if ( update = = " yes " ) {
2016-09-29 20:30:54 -03:00
int ret = g_gui . PopupDialog (
2016-11-05 15:28:14 +01:00
" Update Notice " ,
2023-10-09 19:12:16 -07:00
wxString ( " There is a newd update available ( " ) < < wxstr ( verstr ) < < " ). Do you want to go to the website and download it? " ,
2012-06-29 16:44:26 +02:00
wxYES | wxNO ,
2016-11-05 15:28:14 +01:00
" I don't want any update notices " ,
2012-06-29 16:44:26 +02:00
Config : : AUTOCHECK_FOR_UPDATES
2023-10-09 19:12:16 -07:00
) ;
if ( ret = = wxID_YES ) {
: : wxLaunchDefaultBrowser ( wxstr ( url ) , wxBROWSER_NEW_WINDOW ) ;
}
2012-06-29 16:44:26 +02:00
}
}
# endif
2023-10-09 19:12:16 -07:00
void MainFrame : : OnUpdateMenus ( wxCommandEvent & ) {
2012-06-29 16:44:26 +02:00
UpdateMenubar ( ) ;
2016-09-29 20:30:54 -03:00
g_gui . UpdateMinimap ( true ) ;
g_gui . UpdateTitle ( ) ;
2012-06-29 16:44:26 +02:00
}
2023-10-09 19:12:16 -07:00
void MainFrame : : OnUpdateActions ( wxCommandEvent & ) {
2023-10-09 23:02:37 -03:00
tool_bar - > UpdateButtons ( ) ;
g_gui . RefreshActions ( ) ;
}
2012-06-29 16:44:26 +02:00
# ifdef __WINDOWS__
2023-10-09 19:12:16 -07:00
bool MainFrame : : MSWTranslateMessage ( WXMSG * msg ) {
if ( g_gui . AreHotkeysEnabled ( ) ) {
if ( wxFrame : : MSWTranslateMessage ( msg ) ) {
2012-06-29 16:44:26 +02:00
return true ;
2023-10-09 19:12:16 -07:00
}
2015-12-06 11:42:37 -03:00
} else {
2023-10-09 19:12:16 -07:00
if ( wxWindow : : MSWTranslateMessage ( msg ) ) {
2012-06-29 16:44:26 +02:00
return true ;
2023-10-09 19:12:16 -07:00
}
2012-06-29 16:44:26 +02:00
}
return false ;
}
# endif
2023-10-09 19:12:16 -07:00
void MainFrame : : UpdateMenubar ( ) {
2012-06-29 16:44:26 +02:00
menu_bar - > Update ( ) ;
2019-06-03 14:14:18 -03:00
tool_bar - > UpdateButtons ( ) ;
2012-06-29 16:44:26 +02:00
}
bool MainFrame : : DoQueryClose ( ) {
2016-09-29 20:30:54 -03:00
Editor * editor = g_gui . GetCurrentEditor ( ) ;
2023-10-09 19:12:16 -07:00
if ( editor ) {
if ( editor - > IsLive ( ) ) {
2016-09-29 20:30:54 -03:00
long ret = g_gui . PopupDialog (
2016-11-05 15:28:14 +01:00
" Must Close Server " ,
wxString ( " You are currently connected to a live server, to close this map the connection must be severed. " ) ,
2023-10-09 19:12:16 -07:00
wxOK | wxCANCEL
) ;
if ( ret = = wxID_OK ) {
2012-06-29 16:44:26 +02:00
editor - > CloseLiveServer ( ) ;
} else {
return false ;
}
}
}
return true ;
}
2024-06-07 15:03:37 -03:00
bool MainFrame : : DoQuerySaveTileset ( bool doclose ) {
if ( ! g_materials . needSave ( ) ) {
// skip dialog when there is nothing to save
return true ;
}
long ret = g_gui . PopupDialog (
" Export tileset " ,
" Do you want to export your tileset changes before exiting? " ,
wxYES | wxNO | wxCANCEL
) ;
if ( ret = = wxID_NO ) {
// "no" - exit without saving
return true ;
} else if ( ret = = wxID_CANCEL ) {
// "cancel" - just close the dialog
return false ;
}
// "yes" button was pressed, open tileset exporting dialog
if ( g_gui . GetCurrentEditor ( ) ) {
ExportTilesetsWindow dlg ( this , * g_gui . GetCurrentEditor ( ) ) ;
dlg . ShowModal ( ) ;
}
return ! g_materials . needSave ( ) ;
}
2026-04-22 19:23:35 -03:00
bool MainFrame : : DoQuerySave ( bool doclose , bool checkTileset ) {
2023-10-09 19:12:16 -07:00
if ( ! g_gui . IsEditorOpen ( ) ) {
2014-02-21 13:55:09 +01:00
return true ;
}
2016-09-29 19:24:45 -03:00
2026-04-22 19:23:35 -03:00
if ( checkTileset & & ! DoQuerySaveTileset ( ) ) {
2024-06-07 15:03:37 -03:00
return false ;
}
2023-10-09 19:12:16 -07:00
Editor & editor = * g_gui . GetCurrentEditor ( ) ;
if ( editor . IsLiveClient ( ) ) {
2016-09-29 20:30:54 -03:00
long ret = g_gui . PopupDialog (
2016-11-05 15:28:14 +01:00
" Disconnect " ,
" Do you want to disconnect? " ,
2014-02-21 13:55:09 +01:00
wxYES | wxNO
) ;
2012-06-29 16:44:26 +02:00
2023-10-09 19:12:16 -07:00
if ( ret ! = wxID_YES ) {
2012-06-29 16:44:26 +02:00
return false ;
}
2014-02-21 13:55:09 +01:00
editor . CloseLiveServer ( ) ;
return DoQuerySave ( doclose ) ;
2023-10-09 19:12:16 -07:00
} else if ( editor . IsLiveServer ( ) ) {
2016-09-29 20:30:54 -03:00
long ret = g_gui . PopupDialog (
2016-11-05 15:28:14 +01:00
" Shutdown " ,
" Do you want to shut down the server? (any clients will be disconnected) " ,
2014-02-21 13:55:09 +01:00
wxYES | wxNO
) ;
2023-10-09 19:12:16 -07:00
if ( ret ! = wxID_YES ) {
2012-06-29 16:44:26 +02:00
return false ;
}
2014-02-21 13:55:09 +01:00
editor . CloseLiveServer ( ) ;
return DoQuerySave ( doclose ) ;
2023-10-09 19:12:16 -07:00
} else if ( g_gui . ShouldSave ( ) ) {
2016-09-29 20:30:54 -03:00
long ret = g_gui . PopupDialog (
2016-11-05 15:28:14 +01:00
" Save changes " ,
" Do you want to save your changes to \" " + wxstr ( g_gui . GetCurrentMap ( ) . getName ( ) ) + " \" ? " ,
2014-02-21 13:55:09 +01:00
wxYES | wxNO | wxCANCEL
) ;
2023-10-09 19:12:16 -07:00
if ( ret = = wxID_YES ) {
if ( g_gui . GetCurrentMap ( ) . hasFile ( ) ) {
2016-09-29 20:30:54 -03:00
g_gui . SaveCurrentMap ( true ) ;
2014-02-21 13:55:09 +01:00
} else {
2019-06-25 18:07:36 +02:00
wxFileDialog file ( this , " Save... " , " " , " " , " *.otbm " , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
2014-02-21 13:55:09 +01:00
int32_t result = file . ShowModal ( ) ;
2023-10-09 19:12:16 -07:00
if ( result = = wxID_OK ) {
2016-09-29 20:30:54 -03:00
g_gui . SaveCurrentMap ( file . GetPath ( ) , true ) ;
2014-02-21 13:55:09 +01:00
} else {
return false ;
2012-06-29 16:44:26 +02:00
}
}
2023-10-09 19:12:16 -07:00
} else if ( ret = = wxID_CANCEL ) {
2014-02-21 13:55:09 +01:00
return false ;
2012-06-29 16:44:26 +02:00
}
}
2014-02-21 13:55:09 +01:00
2023-10-09 19:12:16 -07:00
if ( doclose ) {
2014-02-21 13:55:09 +01:00
UnnamedRenderingLock ( ) ;
2016-09-29 20:30:54 -03:00
g_gui . CloseCurrentEditor ( ) ;
2014-02-21 13:55:09 +01:00
}
2012-06-29 16:44:26 +02:00
return true ;
}
2025-05-10 16:38:45 -03:00
void MainFrame : : ShowMissingMonsters ( ) {
wxArrayString missingMonsters = g_monsters . getMissingMonsterNames ( ) ;
if ( ! missingMonsters . IsEmpty ( ) ) {
wxString missingMonstersStr = " Missing Monsters: \n " + wxJoin ( missingMonsters , ' \n ' ) ;
2026-07-29 19:44:25 -03:00
g_gui . ShowTextBox ( this , " Missing Monsters " , missingMonstersStr ) ;
2025-05-10 16:38:45 -03:00
}
}
void MainFrame : : ShowMissingNpcs ( ) {
2026-03-28 21:20:43 -03:00
wxArrayString missingNpcs = g_npcs . getMissingNpcNames ( ) ;
2025-05-10 16:38:45 -03:00
2026-03-28 21:20:43 -03:00
if ( ! missingNpcs . IsEmpty ( ) ) {
wxString missingNpcsStr = " Missing NPCs: \n " + wxJoin ( missingNpcs , ' \n ' ) ;
2026-07-29 19:44:25 -03:00
g_gui . ShowTextBox ( this , " Missing NPCs " , missingNpcsStr ) ;
2025-05-10 16:38:45 -03:00
}
}
2023-10-09 19:12:16 -07:00
bool MainFrame : : DoQueryImportCreatures ( ) {
2026-03-28 21:20:43 -03:00
if ( ! g_monsters . hasMissing ( ) & & ! g_npcs . hasMissing ( ) ) {
g_gui . RefreshPalettes ( ) ;
return true ;
}
std : : string monstersLuaDir = g_settings . getString ( Config : : MONSTERS_LUA_DIRECTORY ) ;
std : : string npcsLuaDir = g_settings . getString ( Config : : NPCS_LUA_DIRECTORY ) ;
const bool monstersLuaReady = ! monstersLuaDir . empty ( ) & & wxDir : : Exists ( wxstr ( monstersLuaDir ) ) ;
const bool npcsLuaReady = ! npcsLuaDir . empty ( ) & & wxDir : : Exists ( wxstr ( npcsLuaDir ) ) ;
bool needsConfig = ( g_monsters . hasMissing ( ) & & ! monstersLuaReady )
| | ( g_npcs . hasMissing ( ) & & ! npcsLuaReady ) ;
if ( needsConfig ) {
long ret = g_gui . PopupDialog ( " Missing creatures " , " There are missing creatures in the map. Would you like to configure the Lua directories to load them? " , wxYES | wxNO ) ;
2023-10-09 19:12:16 -07:00
if ( ret = = wxID_YES ) {
2026-03-28 21:20:43 -03:00
PreferencesWindow dialog ( g_gui . root ) ;
dialog . getBookCtrl ( ) . SetSelection ( 4 ) ;
dialog . ShowModal ( ) ;
2025-05-10 16:38:45 -03:00
2026-03-28 21:20:43 -03:00
monstersLuaDir = g_settings . getString ( Config : : MONSTERS_LUA_DIRECTORY ) ;
npcsLuaDir = g_settings . getString ( Config : : NPCS_LUA_DIRECTORY ) ;
}
2021-05-25 00:29:12 -03:00
}
2026-03-28 21:20:43 -03:00
if ( g_monsters . hasMissing ( ) & & ! monstersLuaDir . empty ( ) ) {
wxString luaErr ;
wxArrayString luaWarn ;
if ( ! g_monsters . loadFromLuaDir ( wxString ( monstersLuaDir ) , luaErr , luaWarn ) ) {
wxLogWarning ( " %s " , luaErr ) ;
}
for ( const auto & warn : luaWarn ) {
wxLogWarning ( " %s " , warn ) ;
2012-06-29 16:44:26 +02:00
}
2026-03-28 21:20:43 -03:00
}
2025-05-10 16:38:45 -03:00
2026-03-28 21:20:43 -03:00
if ( g_npcs . hasMissing ( ) & & ! npcsLuaDir . empty ( ) ) {
wxString luaErr ;
wxArrayString luaWarn ;
if ( ! g_npcs . loadFromLuaDir ( wxString ( npcsLuaDir ) , luaErr , luaWarn ) ) {
wxLogWarning ( " %s " , luaErr ) ;
}
for ( const auto & warn : luaWarn ) {
wxLogWarning ( " %s " , warn ) ;
}
2012-06-29 16:44:26 +02:00
}
2026-03-28 21:20:43 -03:00
ShowMissingMonsters ( ) ;
ShowMissingNpcs ( ) ;
2016-09-29 20:30:54 -03:00
g_gui . RefreshPalettes ( ) ;
2012-06-29 16:44:26 +02:00
return true ;
}
2023-10-09 19:12:16 -07:00
void MainFrame : : UpdateFloorMenu ( ) {
2012-06-29 16:44:26 +02:00
menu_bar - > UpdateFloorMenu ( ) ;
}
2023-10-09 19:12:16 -07:00
void MainFrame : : UpdateIndicatorsMenu ( ) {
2023-10-09 23:02:37 -03:00
menu_bar - > UpdateIndicatorsMenu ( ) ;
}
2023-10-09 19:12:16 -07:00
bool MainFrame : : LoadMap ( FileName name ) {
2016-09-29 20:30:54 -03:00
return g_gui . LoadMap ( name ) ;
2012-06-29 16:44:26 +02:00
}
2023-10-09 19:12:16 -07:00
void MainFrame : : OnExit ( wxCloseEvent & event ) {
2026-04-22 19:23:35 -03:00
if ( ! DoQuerySaveTileset ( ) ) {
if ( event . CanVeto ( ) ) {
event . Veto ( ) ;
return ;
}
}
2024-06-07 15:03:37 -03:00
2026-04-22 19:23:35 -03:00
std : : set < Map * > prompted ;
for ( int i = 0 ; i < g_gui . tabbook - > GetTabCount ( ) ; + + i ) {
auto * mapTab = dynamic_cast < MapTab * > ( g_gui . tabbook - > GetTab ( i ) ) ;
if ( ! mapTab | | ! mapTab - > GetMap ( ) | | ! mapTab - > GetMap ( ) - > hasChanged ( )
| | prompted . contains ( mapTab - > GetMap ( ) ) ) {
continue ;
}
prompted . insert ( mapTab - > GetMap ( ) ) ;
g_gui . tabbook - > SetFocusedTab ( i ) ;
if ( ! DoQuerySave ( false , false ) ) {
2023-10-09 19:12:16 -07:00
if ( event . CanVeto ( ) ) {
2012-06-29 16:44:26 +02:00
event . Veto ( ) ;
return ;
}
2026-04-22 19:23:35 -03:00
break ;
2012-06-29 16:44:26 +02:00
}
}
2026-04-22 19:23:35 -03:00
g_gui . SaveHotkeys ( ) ;
g_gui . SavePerspective ( ) ;
g_gui . root - > SaveRecentFiles ( ) ;
ClientAssets : : save ( ) ;
g_settings . save ( true ) ;
wxGetApp ( ) . ShutdownServices ( ) ;
2012-06-29 16:44:26 +02:00
exit ( 0 ) ;
}
2023-10-09 19:12:16 -07:00
void MainFrame : : AddRecentFile ( const FileName & file ) {
2012-06-29 16:44:26 +02:00
menu_bar - > AddRecentFile ( file ) ;
}
2023-10-09 19:12:16 -07:00
void MainFrame : : LoadRecentFiles ( ) {
2012-06-29 16:44:26 +02:00
menu_bar - > LoadRecentFiles ( ) ;
}
2023-10-09 19:12:16 -07:00
void MainFrame : : SaveRecentFiles ( ) {
2012-06-29 16:44:26 +02:00
menu_bar - > SaveRecentFiles ( ) ;
}
2023-10-09 19:12:16 -07:00
std : : vector < wxString > MainFrame : : GetRecentFiles ( ) {
return menu_bar - > GetRecentFiles ( ) ;
2019-06-25 18:07:36 +02:00
}
2023-10-09 19:12:16 -07:00
void MainFrame : : PrepareDC ( wxDC & dc ) {
dc . SetLogicalOrigin ( 0 , 0 ) ;
dc . SetAxisOrientation ( 1 , 0 ) ;
dc . SetUserScale ( 1.0 , 1.0 ) ;
dc . SetMapMode ( wxMM_TEXT ) ;
2012-06-29 16:44:26 +02:00
}
2023-03-28 08:54:17 -03:00
2026-05-02 18:14:41 -03:00
# ifdef RME_CMAKE_BUILD
// CMake builds use the console subsystem, so provide main without letting
// wxIMPLEMENT_APP generate a second wx entrypoint.
2023-10-09 19:12:16 -07:00
int main ( int argc , char * * argv ) {
2026-05-02 18:14:41 -03:00
return wxEntry ( argc , argv ) ;
2023-03-28 08:54:17 -03:00
}
# endif