2026-05-11 23:06:39 +03:00
/*
* InfiniPaint
* Copyright ( C ) 2025 - 2026 Yousef Khadadeh
*
* This program is free software : you can redistribute it and / or modify
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
*/
2025-07-06 20:43:53 +03:00
# include "MainProgram.hpp"
2026-04-05 20:26:03 +03:00
# include "CustomEvents.hpp"
2025-11-17 16:08:42 +03:00
# include "VersionConstants.hpp"
2025-11-20 12:38:28 +03:00
# include <SDL3/SDL_render.h>
# include <SDL3/SDL_video.h>
2025-07-06 20:43:53 +03:00
# include <include/core/SkAlphaType.h>
# include <include/core/SkColor.h>
# include <include/core/SkPaint.h>
# include <filesystem>
# include <iostream>
# include <include/core/SkFont.h>
# include <include/core/SkData.h>
# include <include/core/SkSurfaceProps.h>
# include "InputManager.hpp"
# include <cereal/types/vector.hpp>
# include <cereal/types/unordered_map.hpp>
# include <Eigen/Core>
# include <cereal/archives/json.hpp>
# include <Helpers/Serializers.hpp>
# include <nlohmann/json.hpp>
# include <include/core/SkSurface.h>
# ifdef USE_SKIA_BACKEND_GRAPHITE
# include <include/gpu/graphite/Surface.h>
# elif USE_SKIA_BACKEND_GANESH
# include <include/gpu/ganesh/GrDirectContext.h>
# include <include/gpu/ganesh/SkSurfaceGanesh.h>
# endif
# ifdef __EMSCRIPTEN__
# include <emscripten.h>
# endif
# include <Helpers/Logger.hpp>
MainProgram : : MainProgram ( ) :
2026-03-01 17:28:43 +03:00
input ( * this ) ,
2025-11-16 10:42:01 +03:00
fonts ( std : : make_shared < FontData > ( ) ) ,
2026-03-31 13:33:15 +03:00
g ( * this )
2025-07-06 20:43:53 +03:00
{
2026-04-27 21:30:31 +03:00
g . gui . io . layoutRun = [ & ] {
screen - > gui_layout_run ( ) ;
} ;
2025-07-06 20:43:53 +03:00
Logger : : get ( ) . add_log ( " WORLDFATAL " , [ & ] ( const std : : string & text ) {
* logFile < < " [WORLDFATAL] " < < text < < std : : endl ;
std : : cout < < " [WORLDFATAL] " < < text < < std : : endl ;
2026-04-12 12:36:00 +03:00
logMessages . emplace_front ( UserLogMessage { text , UserLogMessage : : COLOR_ERROR } ) ;
2025-07-06 20:43:53 +03:00
if ( logMessages . size ( ) = = LOG_SIZE )
logMessages . pop_back ( ) ;
2026-04-05 22:01:30 +03:00
g . gui . set_to_layout ( ) ;
2025-07-06 20:43:53 +03:00
} ) ;
Logger : : get ( ) . add_log ( " USERINFO " , [ & ] ( const std : : string & text ) {
* logFile < < " [USERINFO] " < < text < < std : : endl ;
std : : cout < < " [USERINFO] " < < text < < std : : endl ;
2026-04-12 12:36:00 +03:00
logMessages . emplace_front ( UserLogMessage { text , UserLogMessage : : COLOR_NORMAL } ) ;
2025-07-06 20:43:53 +03:00
if ( logMessages . size ( ) = = LOG_SIZE )
logMessages . pop_back ( ) ;
2026-04-05 22:01:30 +03:00
g . gui . set_to_layout ( ) ;
2025-07-06 20:43:53 +03:00
} ) ;
Logger : : get ( ) . add_log ( " CHAT " , [ & ] ( const std : : string & text ) {
* logFile < < " [CHAT] " < < text < < std : : endl ;
std : : cout < < " [CHAT] " < < text < < std : : endl ;
} ) ;
2025-10-16 21:22:08 +03:00
}
2025-07-06 20:43:53 +03:00
2025-10-16 21:22:08 +03:00
void MainProgram : : update ( ) {
2025-10-20 17:30:36 +03:00
deltaTime . update_time_since ( ) ;
deltaTime . update_time_point ( ) ;
2026-04-09 10:20:40 +03:00
input . update ( ) ;
2026-04-07 22:21:06 +03:00
g . update ( ) ;
2026-04-12 12:36:00 +03:00
screen - > update ( ) ;
for ( auto & w : worlds )
w - > update ( ) ;
2025-10-20 17:30:36 +03:00
NetLibrary : : update ( ) ;
2026-04-05 22:01:30 +03:00
post_callback ( ) ;
2025-07-06 20:43:53 +03:00
}
2026-01-18 13:39:49 +03:00
bool MainProgram : : app_close_requested ( ) {
2026-04-12 12:36:00 +03:00
return screen - > app_close_requested ( ) ;
2026-01-18 13:39:49 +03:00
}
2025-07-08 12:18:55 +03:00
void MainProgram : : update_display_names ( ) {
for ( auto & w : worlds ) {
2026-01-01 22:46:02 +03:00
if ( ! w - > netObjMan . is_connected ( ) )
2026-03-31 13:17:58 +03:00
w - > ownClientData - > set_display_name ( conf . displayName ) ;
2025-07-08 12:18:55 +03:00
}
}
2025-10-27 20:19:47 +03:00
void MainProgram : : init_net_library ( ) {
2026-04-12 12:36:00 +03:00
NetLibrary : : init ( conf . configPath / " p2p.json " ) ;
2025-10-27 20:19:47 +03:00
}
2025-07-06 20:43:53 +03:00
void MainProgram : : save_config ( ) {
2026-04-23 20:56:11 +03:00
using json = nlohmann : : json ;
json j ;
j [ " version " ] = VersionConstants : : CURRENT_VERSION_STRING ;
j [ " settings " ] = conf . get_config_json ( input ) ;
j [ " window " ] [ " pos " ] = window . writtenPos ;
j [ " window " ] [ " size " ] = window . writtenSize ;
j [ " window " ] [ " maximized " ] = window . maximized ;
j [ " window " ] [ " fullscreen " ] = window . fullscreen ;
j [ " fileselectorpath " ] = conf . currentSearchPath ;
j [ " toolConfig " ] = toolConfig ;
std : : stringstream f ;
f < < std : : setw ( 4 ) < < j ;
SDL_SaveFile ( ( conf . configPath / " config.json " ) . string ( ) . c_str ( ) , f . view ( ) . data ( ) , f . view ( ) . size ( ) ) ;
2026-05-13 14:31:35 +03:00
2026-04-12 12:36:00 +03:00
conf . save_palettes ( ) ;
2025-07-06 20:43:53 +03:00
}
void MainProgram : : load_config ( ) {
2026-04-12 12:36:00 +03:00
conf . currentSearchPath = homePath ;
2026-04-23 20:56:11 +03:00
using json = nlohmann : : json ;
try {
json j ( nlohmann : : json : : parse ( read_file_to_string ( conf . configPath / " config.json " ) ) ) ;
2025-11-17 16:08:42 +03:00
2026-04-23 20:56:11 +03:00
VersionNumber version ( 0 , 0 , 1 ) ;
2025-07-06 20:43:53 +03:00
try {
2026-04-23 20:56:11 +03:00
std : : string versionStr ;
j . at ( " version " ) . get_to ( versionStr ) ;
auto optVersion = version_str_to_version_numbers ( versionStr ) ;
if ( optVersion . has_value ( ) )
version = optVersion . value ( ) ;
}
catch ( . . . ) { }
2025-11-17 16:08:42 +03:00
2026-04-23 20:56:11 +03:00
try {
conf . set_config_json ( input , j [ " settings " ] , version ) ;
}
catch ( . . . ) { }
2025-07-06 20:43:53 +03:00
# ifndef __EMSCRIPTEN__
2026-04-23 20:56:11 +03:00
try {
j . at ( " window " ) . at ( " size " ) . get_to ( window . size ) ;
window . writtenSize = window . size ;
j . at ( " window " ) . at ( " pos " ) . get_to ( window . pos ) ;
window . writtenPos = window . pos ;
j . at ( " window " ) . at ( " maximized " ) . get_to ( window . maximized ) ;
j . at ( " window " ) . at ( " fullscreen " ) . get_to ( window . fullscreen ) ;
}
catch ( . . . ) { }
try {
j . at ( " fileselectorpath " ) . get_to ( conf . currentSearchPath ) ;
}
catch ( . . . ) {
conf . currentSearchPath = homePath ;
}
2025-07-06 20:43:53 +03:00
# endif
2026-04-23 20:56:11 +03:00
try {
j . at ( " toolConfig " ) . get_to ( toolConfig ) ;
}
catch ( . . . ) { }
} catch ( . . . ) { }
2025-07-06 20:43:53 +03:00
# ifdef __EMSCRIPTEN__
else
2026-04-12 17:31:32 +03:00
conf . viewWebVersionWelcome = true ;
2025-07-06 20:43:53 +03:00
# endif
2026-04-12 12:36:00 +03:00
conf . load_palettes ( ) ;
g . load_theme ( conf . configPath , conf . themeCurrentlyLoaded ) ;
conf . load_licenses ( ) ;
2025-10-27 20:19:47 +03:00
2026-04-12 12:36:00 +03:00
NetLibrary : : copy_default_p2p_config_to_path ( conf . configPath / " p2p.json " ) ;
2026-03-20 20:53:59 +03:00
2026-03-31 13:17:58 +03:00
update_display_names ( ) ;
set_vsync_value ( conf . vsyncValue ) ;
2026-03-20 20:53:59 +03:00
refresh_draw_surfaces ( ) ;
2025-07-06 20:43:53 +03:00
}
2025-11-20 12:38:28 +03:00
void MainProgram : : set_vsync_value ( int vsyncValue ) {
if ( ! SDL_GL_SetSwapInterval ( vsyncValue ) ) {
Logger : : get ( ) . log ( " INFO " , " Vsync value " + std : : to_string ( vsyncValue ) + " not available. Setting to 1 " ) ;
2025-11-20 13:12:41 +03:00
if ( vsyncValue = = - 1 ) {
Logger : : get ( ) . log ( " USERINFO " , " Adaptive VSync not available. Setting Vsync to On " ) ;
vsyncValue = 1 ;
}
2025-11-20 12:38:28 +03:00
SDL_GL_SetSwapInterval ( 1 ) ;
}
2026-03-31 13:17:58 +03:00
conf . vsyncValue = vsyncValue ;
2025-11-20 12:38:28 +03:00
}
2025-11-23 12:53:50 +03:00
void MainProgram : : update_scale_and_density ( ) {
2025-11-23 20:51:14 +03:00
# ifdef __EMSCRIPTEN__
window . scale = 1.0f ;
# else
2026-03-31 13:17:58 +03:00
window . scale = conf . applyDisplayScale ? SDL_GetWindowDisplayScale ( window . sdlWindow ) : 1.0f ;
2025-11-23 20:51:14 +03:00
# endif
2025-11-23 12:53:50 +03:00
window . density = SDL_GetWindowPixelDensity ( window . sdlWindow ) ;
}
float MainProgram : : get_scale_and_density_factor_gui ( ) {
return window . scale * window . density ;
}
2026-03-20 20:53:59 +03:00
void MainProgram : : refresh_draw_surfaces ( ) {
if ( window . canCreateSurfaces ) {
window . defaultMSAASampleCount = 0 ;
2026-03-31 13:17:58 +03:00
window . defaultMSAASurfaceProps = SkSurfaceProps ( conf . antialiasing = = GlobalConfig : : AntiAliasing : : DYNAMIC_MSAA ? SkSurfaceProps : : kDynamicMSAA_Flag : SkSurfaceProps : : kDefault_Flag , kUnknown_SkPixelGeometry ) ;
2026-04-09 01:05:52 +03:00
if ( conf . antialiasing = = GlobalConfig : : AntiAliasing : : DYNAMIC_MSAA )
window . intermediateSurfaceMSAA = create_native_surface ( window . size , true ) ;
else
window . intermediateSurfaceMSAA = nullptr ;
2026-03-20 20:53:59 +03:00
2026-04-08 17:34:50 +03:00
g . delete_cache_surface ( ) ;
2026-03-20 20:53:59 +03:00
DrawingProgramCache : : delete_all_draw_cache ( ) ;
}
}
2026-04-17 19:32:49 +03:00
void MainProgram : : draw_world ( SkCanvas * canvas , std : : shared_ptr < World > worldToDraw , const DrawData & drawData ) {
2026-02-25 13:26:35 +03:00
canvas - > clear ( drawData . transparentBackground ? SkColor4f { 0.0f , 0.0f , 0.0f , 0.0f } : worldToDraw - > canvasTheme . get_back_color ( ) ) ;
2026-03-20 20:53:59 +03:00
DrawData drawDataCopy = drawData ;
2026-03-31 13:17:58 +03:00
drawDataCopy . skiaAA = conf . antialiasing = = GlobalConfig : : AntiAliasing : : SKIA ;
2026-03-20 20:53:59 +03:00
worldToDraw - > draw ( canvas , drawDataCopy ) ;
2026-04-17 19:32:49 +03:00
}
void MainProgram : : draw ( SkCanvas * canvas ) {
screen - > draw ( canvas ) ;
g . draw ( canvas , conf . antialiasing = = GlobalConfig : : AntiAliasing : : SKIA ) ;
2025-07-06 20:43:53 +03:00
}
2026-02-16 21:27:42 +03:00
sk_sp < SkSurface > MainProgram : : create_native_surface ( Vector2i resolution , bool isMSAA ) {
2026-03-20 20:53:59 +03:00
if ( window . canCreateSurfaces ) {
2026-04-09 01:52:19 +03:00
SkImageInfo imgInfo = SkImageInfo : : MakeN32Premul ( resolution . x ( ) , resolution . y ( ) ) ;
2026-03-20 20:53:59 +03:00
SkSurfaceProps defaultProps ;
# ifdef USE_SKIA_BACKEND_GRAPHITE
auto surfaceToRet = SkSurfaces : : RenderTarget ( window . recorder ( ) , imgInfo , skgpu : : Mipmapped : : kNo , isMSAA ? & window . defaultMSAASurfaceProps : & defaultProps ) ;
# elif USE_SKIA_BACKEND_GANESH
auto surfaceToRet = SkSurfaces : : RenderTarget ( window . ctx . get ( ) , skgpu : : Budgeted : : kNo , imgInfo , isMSAA ? window . defaultMSAASampleCount : 0 , isMSAA ? & window . defaultMSAASurfaceProps : & defaultProps ) ;
# endif
if ( ! surfaceToRet )
throw std : : runtime_error ( " [MainProgram::create_native_surface] Could not make native surface " ) ;
return surfaceToRet ;
}
return nullptr ;
2026-02-16 21:27:42 +03:00
}
2026-04-11 16:36:24 +03:00
void MainProgram : : create_new_tab ( const CustomEvents : : OpenInfiniPaintFileEvent & openFile ) {
2026-04-05 20:26:03 +03:00
std : : shared_ptr < World > newWorld ;
try {
newWorld = std : : make_shared < World > ( * this , openFile ) ;
}
catch ( const std : : runtime_error & e ) {
Logger : : get ( ) . log ( " WORLDFATAL " , " Failed to open canvas: " + ( openFile . filePathSource . has_value ( ) ? openFile . filePathSource . value ( ) . string ( ) : " NO PATH " ) + " with error: " + e . what ( ) ) ;
return ;
}
worlds . emplace_back ( newWorld ) ;
switch_to_tab ( worlds . size ( ) - 1 ) ;
g . gui . set_to_layout ( ) ;
}
void MainProgram : : set_tab_to_close ( World * world ) {
tabsToClose . emplace ( world ) ;
}
void MainProgram : : switch_to_tab ( size_t wIndex ) {
world = worlds [ wIndex ] ;
worldIndex = wIndex ;
}
void MainProgram : : post_callback ( ) {
2026-04-28 14:51:35 +03:00
g . gui . run_post_callback_func ( ) ;
run_new_screen_func ( ) ;
2026-04-05 20:26:03 +03:00
close_set_to_close_tabs ( ) ;
2026-04-28 14:51:35 +03:00
g . gui . layout_if_necessary ( ) ;
}
void MainProgram : : input_app_about_to_go_to_background_callback ( ) {
screen - > input_app_about_to_go_to_background_callback ( ) ;
2026-05-13 14:31:35 +03:00
save_config ( ) ;
2026-04-28 14:51:35 +03:00
post_callback ( ) ;
2026-04-05 20:26:03 +03:00
}
2026-04-11 16:36:24 +03:00
void MainProgram : : input_add_file_to_canvas_callback ( const CustomEvents : : AddFileToCanvasEvent & addFile ) {
2026-04-12 12:36:00 +03:00
screen - > input_add_file_to_canvas_callback ( addFile ) ;
2026-04-11 16:36:24 +03:00
post_callback ( ) ;
}
void MainProgram : : input_open_infinipaint_file_callback ( const CustomEvents : : OpenInfiniPaintFileEvent & openFile ) {
2026-04-12 12:36:00 +03:00
screen - > input_open_infinipaint_file_callback ( openFile ) ;
2026-04-27 21:30:31 +03:00
g . gui . set_to_layout ( ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
}
2026-04-11 16:36:24 +03:00
void MainProgram : : input_paste_callback ( const CustomEvents : : PasteEvent & paste ) {
2026-04-04 17:52:43 +03:00
g . input_paste_callback ( paste ) ;
2026-04-12 12:36:00 +03:00
screen - > input_paste_callback ( paste ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
2026-04-04 17:52:43 +03:00
}
2026-05-11 23:06:39 +03:00
void MainProgram : : input_android_text_box_input_callback ( const CustomEvents : : AndroidTextBoxInputEvent & textboxInput ) {
g . input_android_text_box_input_callback ( textboxInput ) ;
screen - > input_android_text_box_input_callback ( textboxInput ) ;
post_callback ( ) ;
}
2026-04-27 17:20:16 +03:00
void MainProgram : : input_global_back_button_callback ( ) {
screen - > input_global_back_button_callback ( ) ;
post_callback ( ) ;
}
2026-04-02 19:18:39 +03:00
bool MainProgram : : input_keybind_callback ( const Vector2ui32 & newKey ) {
if ( keybindWaiting . has_value ( ) ) {
unsigned v = keybindWaiting . value ( ) ;
input . keyAssignments . erase ( newKey ) ;
auto f = std : : find_if ( input . keyAssignments . begin ( ) , input . keyAssignments . end ( ) , [ & ] ( auto & p ) {
return p . second = = v ;
} ) ;
if ( f ! = input . keyAssignments . end ( ) )
input . keyAssignments . erase ( f ) ;
input . keyAssignments . emplace ( newKey , v ) ;
keybindWaiting = std : : nullopt ;
g . gui . set_to_layout ( ) ;
2026-04-05 22:01:30 +03:00
post_callback ( ) ;
2026-04-02 19:18:39 +03:00
return true ;
}
return false ;
}
2026-03-04 11:03:05 +03:00
void MainProgram : : input_drop_file_callback ( const InputManager : : DropCallbackArgs & drop ) {
2026-04-12 12:36:00 +03:00
screen - > input_drop_file_callback ( drop ) ;
post_callback ( ) ;
2026-03-04 11:03:05 +03:00
}
void MainProgram : : input_drop_text_callback ( const InputManager : : DropCallbackArgs & drop ) {
2026-04-12 12:36:00 +03:00
screen - > input_drop_text_callback ( drop ) ;
post_callback ( ) ;
2026-03-04 11:03:05 +03:00
}
2026-03-02 16:36:34 +03:00
void MainProgram : : input_key_callback ( const InputManager : : KeyCallbackArgs & key ) {
2026-04-12 12:36:00 +03:00
if ( key . key = = InputManager : : KEY_FULLSCREEN ) {
if ( key . down & & ! key . repeat )
toggle_full_screen ( ) ;
2026-03-02 16:36:34 +03:00
}
2026-03-31 17:33:09 +03:00
g . input_key_callback ( key ) ;
2026-04-12 12:36:00 +03:00
screen - > input_key_callback ( key ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
2026-03-02 16:36:34 +03:00
}
2026-04-03 23:02:33 +03:00
void MainProgram : : input_text_key_callback ( const InputManager : : KeyCallbackArgs & key ) {
g . input_text_key_callback ( key ) ;
2026-04-12 12:36:00 +03:00
screen - > input_text_key_callback ( key ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
2026-04-02 10:15:22 +03:00
}
2026-04-04 17:52:43 +03:00
void MainProgram : : input_text_callback ( const InputManager : : TextCallbackArgs & text ) {
g . input_text_callback ( text ) ;
2026-04-12 12:36:00 +03:00
screen - > input_text_callback ( text ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
2026-04-02 10:15:22 +03:00
}
2026-03-02 16:36:34 +03:00
void MainProgram : : input_mouse_button_callback ( const InputManager : : MouseButtonCallbackArgs & button ) {
2026-03-31 17:33:09 +03:00
g . input_mouse_button_callback ( button ) ;
2026-04-12 12:36:00 +03:00
screen - > input_mouse_button_callback ( button ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
2026-03-02 16:36:34 +03:00
}
void MainProgram : : input_mouse_motion_callback ( const InputManager : : MouseMotionCallbackArgs & motion ) {
2026-03-31 17:33:09 +03:00
g . input_mouse_motion_callback ( motion ) ;
2026-04-12 12:36:00 +03:00
screen - > input_mouse_motion_callback ( motion ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
2026-03-02 16:36:34 +03:00
}
2026-03-02 23:09:48 +03:00
void MainProgram : : input_mouse_wheel_callback ( const InputManager : : MouseWheelCallbackArgs & wheel ) {
2026-03-31 17:33:09 +03:00
g . input_mouse_wheel_callback ( wheel ) ;
2026-04-12 12:36:00 +03:00
screen - > input_mouse_wheel_callback ( wheel ) ;
2026-04-05 20:26:03 +03:00
post_callback ( ) ;
2026-03-02 23:09:48 +03:00
}
2026-03-03 14:59:18 +03:00
void MainProgram : : input_pen_button_callback ( const InputManager : : PenButtonCallbackArgs & button ) {
2026-04-12 12:36:00 +03:00
screen - > input_pen_button_callback ( button ) ;
post_callback ( ) ;
2026-03-03 14:59:18 +03:00
}
void MainProgram : : input_pen_touch_callback ( const InputManager : : PenTouchCallbackArgs & touch ) {
2026-04-12 12:36:00 +03:00
screen - > input_pen_touch_callback ( touch ) ;
post_callback ( ) ;
2026-03-03 14:59:18 +03:00
}
void MainProgram : : input_pen_motion_callback ( const InputManager : : PenMotionCallbackArgs & motion ) {
2026-04-12 12:36:00 +03:00
screen - > input_pen_motion_callback ( motion ) ;
post_callback ( ) ;
2026-03-03 16:01:21 +03:00
}
void MainProgram : : input_pen_axis_callback ( const InputManager : : PenAxisCallbackArgs & axis ) {
2026-04-12 12:36:00 +03:00
screen - > input_pen_axis_callback ( axis ) ;
post_callback ( ) ;
2026-03-03 14:59:18 +03:00
}
2026-03-05 21:09:30 +03:00
void MainProgram : : input_multi_finger_touch_callback ( const InputManager : : MultiFingerTouchCallbackArgs & touch ) {
2026-04-12 12:36:00 +03:00
screen - > input_multi_finger_touch_callback ( touch ) ;
post_callback ( ) ;
2026-03-05 12:03:10 +03:00
}
2026-03-05 21:09:30 +03:00
void MainProgram : : input_multi_finger_motion_callback ( const InputManager : : MultiFingerMotionCallbackArgs & motion ) {
2026-04-12 12:36:00 +03:00
screen - > input_multi_finger_motion_callback ( motion ) ;
post_callback ( ) ;
2026-03-05 12:03:10 +03:00
}
2026-03-05 21:09:30 +03:00
void MainProgram : : input_finger_touch_callback ( const InputManager : : FingerTouchCallbackArgs & touch ) {
2026-04-28 20:13:47 +03:00
g . input_finger_touch_callback ( touch ) ;
2026-04-12 12:36:00 +03:00
screen - > input_finger_touch_callback ( touch ) ;
post_callback ( ) ;
2026-03-05 21:09:30 +03:00
}
void MainProgram : : input_finger_motion_callback ( const InputManager : : FingerMotionCallbackArgs & motion ) {
2026-04-28 20:13:47 +03:00
g . input_finger_motion_callback ( motion ) ;
2026-04-12 12:36:00 +03:00
screen - > input_finger_motion_callback ( motion ) ;
post_callback ( ) ;
2026-03-05 21:09:30 +03:00
}
2026-04-07 20:21:41 +03:00
void MainProgram : : input_window_resize_callback ( const InputManager : : WindowResizeCallbackArgs & w ) {
2026-04-09 20:44:45 +03:00
for ( auto & wor : worlds )
wor - > drawData . cam . set_viewing_area ( window . size . cast < float > ( ) ) ;
2026-04-07 20:21:41 +03:00
g . window_update ( ) ;
2026-04-12 12:36:00 +03:00
screen - > input_window_resize_callback ( w ) ;
2026-04-07 20:21:41 +03:00
post_callback ( ) ;
}
void MainProgram : : input_window_scale_callback ( const InputManager : : WindowScaleCallbackArgs & w ) {
g . window_update ( ) ;
2026-04-12 12:36:00 +03:00
screen - > input_window_scale_callback ( w ) ;
2026-04-07 20:21:41 +03:00
post_callback ( ) ;
}
2026-05-07 21:48:47 +03:00
std : : optional < InputManager : : TextBoxStartInfo > MainProgram : : get_text_box_start_info ( ) {
auto toRet = g . get_text_box_start_info ( ) ;
if ( toRet )
return toRet ;
return screen - > get_text_box_start_info ( ) ;
}
2026-04-07 20:33:48 +03:00
void MainProgram : : toggle_full_screen ( ) {
window . fullscreen = ! window . fullscreen ;
SDL_SetWindowFullscreen ( window . sdlWindow , window . fullscreen ) ;
}
2026-04-28 14:51:35 +03:00
void MainProgram : : set_first_screen ( std : : unique_ptr < Screen > firstScreen ) {
set_screen ( [ & ] ( std : : unique_ptr < Screen > ) { return std : : move ( firstScreen ) ; } ) ;
run_new_screen_func ( ) ;
}
void MainProgram : : run_new_screen_func ( ) {
if ( newScreenFunc ) {
screen = newScreenFunc ( std : : move ( screen ) ) ;
g . gui . io . redrawSurface = true ;
g . gui . set_to_layout ( ) ;
newScreenFunc = nullptr ;
}
}
void MainProgram : : set_screen ( std : : function < std : : unique_ptr < Screen > ( std : : unique_ptr < Screen > ) > screenFunc ) {
newScreenFunc = screenFunc ;
2026-04-27 21:30:31 +03:00
}
2026-04-05 20:26:03 +03:00
void MainProgram : : close_set_to_close_tabs ( ) {
if ( ! tabsToClose . empty ( ) ) {
std : : erase_if ( worlds , [ & ] ( auto & w ) {
if ( tabsToClose . contains ( w . get ( ) ) ) {
if ( w = = world )
world = nullptr ;
return true ;
}
return false ;
} ) ;
if ( worlds . empty ( ) )
create_new_tab ( {
. isClient = false
} ) ;
else if ( world )
worldIndex = std : : find ( worlds . begin ( ) , worlds . end ( ) , world ) - worlds . begin ( ) ;
else
switch_to_tab ( 0 ) ;
tabsToClose . clear ( ) ;
g . gui . set_to_layout ( ) ;
}
}
2025-07-06 20:43:53 +03:00
bool MainProgram : : network_being_used ( ) {
for ( auto & w : worlds ) {
2026-01-01 22:46:02 +03:00
if ( w - > netObjMan . is_connected ( ) )
2025-07-06 20:43:53 +03:00
return true ;
}
return false ;
}
bool MainProgram : : net_server_hosted ( ) {
for ( auto & w : worlds ) {
2026-01-01 22:46:02 +03:00
if ( w - > netServer )
2025-07-06 20:43:53 +03:00
return true ;
}
return false ;
}
void MainProgram : : early_destroy ( ) {
for ( auto & w : worlds )
w - > early_destroy ( ) ;
}
MainProgram : : ~ MainProgram ( ) {
2026-04-23 20:56:11 +03:00
screen = nullptr ; // Destroy screen first to let destructor run
2025-07-06 20:43:53 +03:00
NetLibrary : : destroy ( ) ;
}