PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
/*
* Copyright ( c ) 2018 - 2021 , Andreas Kling < kling @ serenityos . org >
2021-09-13 17:48:22 -03:00
* Copyright ( c ) 2021 , Mustafa Quraish < mustafa @ serenityos . org >
2021-09-10 12:41:28 -03:00
* Copyright ( c ) 2021 , Tobias Christiansen < tobyase @ serenityos . org >
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "MainWidget.h"
# include "CreateNewImageDialog.h"
# include "CreateNewLayerDialog.h"
# include "EditGuideDialog.h"
# include "FilterParams.h"
# include <Applications/PixelPaint/PixelPaintWindowGML.h>
2021-09-12 00:40:59 -03:00
# include <LibConfig/Client.h>
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
# include <LibCore/File.h>
# include <LibCore/MimeData.h>
# include <LibFileSystemAccessClient/Client.h>
# include <LibGUI/Application.h>
# include <LibGUI/Clipboard.h>
# include <LibGUI/Icon.h>
# include <LibGUI/Menubar.h>
# include <LibGUI/MessageBox.h>
# include <LibGUI/Toolbar.h>
# include <LibGfx/Bitmap.h>
namespace PixelPaint {
MainWidget : : MainWidget ( )
: Widget ( )
{
load_from_gml ( pixel_paint_window_gml ) ;
m_toolbox = find_descendant_of_type_named < PixelPaint : : ToolboxWidget > ( " toolbox " ) ;
m_statusbar = * find_descendant_of_type_named < GUI : : Statusbar > ( " statusbar " ) ;
m_tab_widget = find_descendant_of_type_named < GUI : : TabWidget > ( " tab_widget " ) ;
m_tab_widget - > set_container_margins ( { 4 , 5 , 5 , 4 } ) ;
m_tab_widget - > set_close_button_enabled ( true ) ;
m_palette_widget = * find_descendant_of_type_named < PixelPaint : : PaletteWidget > ( " palette_widget " ) ;
m_layer_list_widget = * find_descendant_of_type_named < PixelPaint : : LayerListWidget > ( " layer_list_widget " ) ;
m_layer_list_widget - > on_layer_select = [ & ] ( auto * layer ) {
if ( auto * editor = current_image_editor ( ) )
editor - > set_active_layer ( layer ) ;
} ;
m_layer_properties_widget = * find_descendant_of_type_named < PixelPaint : : LayerPropertiesWidget > ( " layer_properties_widget " ) ;
m_tool_properties_widget = * find_descendant_of_type_named < PixelPaint : : ToolPropertiesWidget > ( " tool_properties_widget " ) ;
m_toolbox - > on_tool_selection = [ & ] ( auto * tool ) {
if ( auto * editor = current_image_editor ( ) )
editor - > set_active_tool ( tool ) ;
m_tool_properties_widget - > set_active_tool ( tool ) ;
} ;
m_tab_widget - > on_tab_close_click = [ & ] ( auto & widget ) {
auto & image_editor = verify_cast < PixelPaint : : ImageEditor > ( widget ) ;
if ( m_tab_widget - > children ( ) . size ( ) = = 1 ) {
m_layer_list_widget - > set_image ( nullptr ) ;
m_layer_properties_widget - > set_layer ( nullptr ) ;
}
m_tab_widget - > deferred_invoke ( [ & ] {
m_tab_widget - > remove_tab ( image_editor ) ;
} ) ;
} ;
m_tab_widget - > on_change = [ & ] ( auto & widget ) {
auto & image_editor = verify_cast < PixelPaint : : ImageEditor > ( widget ) ;
m_palette_widget - > set_image_editor ( image_editor ) ;
m_layer_list_widget - > set_image ( & image_editor . image ( ) ) ;
m_layer_properties_widget - > set_layer ( image_editor . active_layer ( ) ) ;
2021-09-12 22:36:44 -03:00
if ( auto * active_tool = m_toolbox - > active_tool ( ) )
image_editor . set_active_tool ( active_tool ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
m_show_guides_action - > set_checked ( image_editor . guide_visibility ( ) ) ;
2021-09-05 07:22:27 -03:00
m_show_rulers_action - > set_checked ( image_editor . ruler_visibility ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
} ;
}
void MainWidget : : initialize_menubar ( GUI : : Window & window )
{
auto & file_menu = window . add_menu ( " &File " ) ;
m_new_image_action = GUI : : Action : : create (
" &New Image... " , { Mod_Ctrl , Key_N } , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/new.png " ) , [ & ] ( auto & ) {
auto dialog = PixelPaint : : CreateNewImageDialog : : construct ( & window ) ;
if ( dialog - > exec ( ) = = GUI : : Dialog : : ExecOK ) {
auto image = PixelPaint : : Image : : try_create_with_size ( dialog - > image_size ( ) ) ;
auto bg_layer = PixelPaint : : Layer : : try_create_with_size ( * image , image - > size ( ) , " Background " ) ;
VERIFY ( bg_layer ) ;
image - > add_layer ( * bg_layer ) ;
bg_layer - > bitmap ( ) . fill ( Color : : White ) ;
auto image_title = dialog - > image_name ( ) . trim_whitespace ( ) ;
image - > set_title ( image_title . is_empty ( ) ? " Untitled " : image_title ) ;
create_new_editor ( * image ) ;
m_layer_list_widget - > set_image ( image ) ;
m_layer_list_widget - > set_selected_layer ( bg_layer ) ;
}
} ) ;
m_open_image_action = GUI : : CommonActions : : make_open_action ( [ & ] ( auto & ) {
auto result = FileSystemAccessClient : : Client : : the ( ) . open_file ( window . window_id ( ) ) ;
if ( result . error ! = 0 )
return ;
open_image_fd ( * result . fd , * result . chosen_file ) ;
} ) ;
m_save_image_as_action = GUI : : CommonActions : : make_save_as_action ( [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto save_result = FileSystemAccessClient : : Client : : the ( ) . save_file ( window . window_id ( ) , " untitled " , " pp " ) ;
if ( save_result . error ! = 0 )
return ;
auto result = editor - > save_project_to_fd_and_close ( * save_result . fd ) ;
if ( result . is_error ( ) ) {
GUI : : MessageBox : : show_error ( & window , String : : formatted ( " Could not save {}: {} " , * save_result . chosen_file , result . error ( ) ) ) ;
return ;
}
editor - > image ( ) . set_path ( * save_result . chosen_file ) ;
} ) ;
file_menu . add_action ( * m_new_image_action ) ;
file_menu . add_action ( * m_open_image_action ) ;
file_menu . add_action ( * m_save_image_as_action ) ;
auto & export_submenu = file_menu . add_submenu ( " &Export " ) ;
export_submenu . add_action (
GUI : : Action : : create (
" As &BMP " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto save_result = FileSystemAccessClient : : Client : : the ( ) . save_file ( window . window_id ( ) , " untitled " , " bmp " ) ;
if ( save_result . error ! = 0 )
return ;
auto preserve_alpha_channel = GUI : : MessageBox : : show ( & window , " Do you wish to preserve transparency? " , " Preserve transparency? " , GUI : : MessageBox : : Type : : Question , GUI : : MessageBox : : InputType : : YesNo ) ;
auto result = editor - > image ( ) . export_bmp_to_fd_and_close ( * save_result . fd , preserve_alpha_channel = = GUI : : MessageBox : : ExecYes ) ;
if ( result . is_error ( ) )
GUI : : MessageBox : : show_error ( & window , String : : formatted ( " Export to BMP failed: {} " , result . error ( ) ) ) ;
} ) ) ;
export_submenu . add_action (
GUI : : Action : : create (
" As &PNG " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
auto save_result = FileSystemAccessClient : : Client : : the ( ) . save_file ( window . window_id ( ) , " untitled " , " png " ) ;
if ( save_result . error ! = 0 )
return ;
auto preserve_alpha_channel = GUI : : MessageBox : : show ( & window , " Do you wish to preserve transparency? " , " Preserve transparency? " , GUI : : MessageBox : : Type : : Question , GUI : : MessageBox : : InputType : : YesNo ) ;
auto result = editor - > image ( ) . export_png_to_fd_and_close ( * save_result . fd , preserve_alpha_channel = = GUI : : MessageBox : : ExecYes ) ;
if ( result . is_error ( ) )
GUI : : MessageBox : : show_error ( & window , String : : formatted ( " Export to PNG failed: {} " , result . error ( ) ) ) ;
} ) ) ;
file_menu . add_separator ( ) ;
2021-09-06 22:52:19 -03:00
file_menu . add_action (
GUI : : Action : : create (
" &Close Image " , { Mod_Ctrl , Key_W } , [ & ] ( auto & ) {
auto * active_widget = m_tab_widget - > active_widget ( ) ;
if ( ! active_widget )
return ;
m_tab_widget - > on_tab_close_click ( * active_widget ) ;
} ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
file_menu . add_action ( GUI : : CommonActions : : make_quit_action ( [ ] ( auto & ) {
GUI : : Application : : the ( ) - > quit ( ) ;
} ) ) ;
auto & edit_menu = window . add_menu ( " &Edit " ) ;
m_copy_action = GUI : : CommonActions : : make_copy_action ( [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( ! editor - > active_layer ( ) ) {
dbgln ( " Cannot copy with no active layer selected " ) ;
return ;
}
auto bitmap = editor - > active_layer ( ) - > try_copy_bitmap ( editor - > selection ( ) ) ;
if ( ! bitmap ) {
dbgln ( " try_copy_bitmap() from Layer failed " ) ;
return ;
}
GUI : : Clipboard : : the ( ) . set_bitmap ( * bitmap ) ;
} ) ;
m_copy_merged_action = GUI : : Action : : create (
" Copy &Merged " , { Mod_Ctrl | Mod_Shift , Key_C } , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/edit-copy.png " ) ,
[ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto bitmap = editor - > image ( ) . try_copy_bitmap ( editor - > selection ( ) ) ;
if ( ! bitmap ) {
dbgln ( " try_copy_bitmap() from Image failed " ) ;
return ;
}
GUI : : Clipboard : : the ( ) . set_bitmap ( * bitmap ) ;
} ) ;
m_paste_action = GUI : : CommonActions : : make_paste_action ( [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto bitmap = GUI : : Clipboard : : the ( ) . bitmap ( ) ;
if ( ! bitmap )
return ;
auto layer = PixelPaint : : Layer : : try_create_with_bitmap ( editor - > image ( ) , * bitmap , " Pasted layer " ) ;
VERIFY ( layer ) ;
editor - > image ( ) . add_layer ( * layer ) ;
editor - > set_active_layer ( layer ) ;
editor - > selection ( ) . clear ( ) ;
} ) ;
GUI : : Clipboard : : the ( ) . on_change = [ & ] ( auto & mime_type ) {
m_paste_action - > set_enabled ( mime_type = = " image/x-serenityos " ) ;
} ;
m_paste_action - > set_enabled ( GUI : : Clipboard : : the ( ) . mime_type ( ) = = " image/x-serenityos " ) ;
m_undo_action = GUI : : CommonActions : : make_undo_action ( [ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) )
editor - > undo ( ) ;
} ) ;
m_redo_action = GUI : : CommonActions : : make_redo_action ( [ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) )
editor - > redo ( ) ;
} ) ;
edit_menu . add_action ( * m_copy_action ) ;
edit_menu . add_action ( * m_copy_merged_action ) ;
edit_menu . add_action ( * m_paste_action ) ;
edit_menu . add_action ( * m_undo_action ) ;
edit_menu . add_action ( * m_redo_action ) ;
edit_menu . add_separator ( ) ;
edit_menu . add_action ( GUI : : CommonActions : : make_select_all_action ( [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor - > active_layer ( ) )
return ;
editor - > selection ( ) . merge ( editor - > active_layer ( ) - > relative_rect ( ) , PixelPaint : : Selection : : MergeMode : : Set ) ;
} ) ) ;
edit_menu . add_action ( GUI : : Action : : create (
" Clear &Selection " , { Mod_Ctrl | Mod_Shift , Key_A } , [ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) )
editor - > selection ( ) . clear ( ) ;
} ) ) ;
edit_menu . add_separator ( ) ;
edit_menu . add_action ( GUI : : Action : : create (
2021-09-12 22:50:46 -03:00
" S&wap Colors " , { Mod_None , Key_X } , [ & ] ( auto & ) {
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto old_primary_color = editor - > primary_color ( ) ;
editor - > set_primary_color ( editor - > secondary_color ( ) ) ;
editor - > set_secondary_color ( old_primary_color ) ;
} ) ) ;
edit_menu . add_action ( GUI : : Action : : create (
" &Default Colors " , { Mod_None , Key_D } , [ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) ) {
editor - > set_primary_color ( Color : : Black ) ;
editor - > set_secondary_color ( Color : : White ) ;
}
} ) ) ;
edit_menu . add_action ( GUI : : Action : : create (
" &Load Color Palette " , [ & ] ( auto & ) {
auto open_result = FileSystemAccessClient : : Client : : the ( ) . open_file ( window . window_id ( ) , " Load Color Palette " ) ;
if ( open_result . error ! = 0 )
return ;
auto result = PixelPaint : : PaletteWidget : : load_palette_fd_and_close ( * open_result . fd ) ;
if ( result . is_error ( ) ) {
GUI : : MessageBox : : show_error ( & window , String : : formatted ( " Loading color palette failed: {} " , result . error ( ) ) ) ;
return ;
}
m_palette_widget - > display_color_list ( result . value ( ) ) ;
} ) ) ;
edit_menu . add_action ( GUI : : Action : : create (
" Sa&ve Color Palette " , [ & ] ( auto & ) {
auto save_result = FileSystemAccessClient : : Client : : the ( ) . save_file ( window . window_id ( ) , " untitled " , " palette " ) ;
if ( save_result . error ! = 0 )
return ;
auto result = PixelPaint : : PaletteWidget : : save_palette_fd_and_close ( m_palette_widget - > colors ( ) , * save_result . fd ) ;
if ( result . is_error ( ) )
GUI : : MessageBox : : show_error ( & window , String : : formatted ( " Writing color palette failed: {} " , result . error ( ) ) ) ;
} ) ) ;
auto & view_menu = window . add_menu ( " &View " ) ;
m_zoom_in_action = GUI : : CommonActions : : make_zoom_in_action (
[ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) )
editor - > scale_by ( 0.1f ) ;
} ) ;
m_zoom_out_action = GUI : : CommonActions : : make_zoom_out_action (
[ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) )
editor - > scale_by ( - 0.1f ) ;
} ) ;
m_reset_zoom_action = GUI : : CommonActions : : make_reset_zoom_action (
[ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) )
editor - > reset_scale_and_position ( ) ;
} ) ;
m_add_guide_action = GUI : : Action : : create (
2021-09-12 22:50:46 -03:00
" &Add Guide " , [ & ] ( auto & ) {
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
auto dialog = PixelPaint : : EditGuideDialog : : construct ( & window ) ;
if ( dialog - > exec ( ) ! = GUI : : Dialog : : ExecOK )
return ;
if ( auto * editor = current_image_editor ( ) ) {
auto offset = dialog - > offset_as_pixel ( * editor ) ;
if ( ! offset . has_value ( ) )
return ;
editor - > add_guide ( PixelPaint : : Guide : : construct ( dialog - > orientation ( ) , offset . value ( ) ) ) ;
}
} ) ;
// Save this so other methods can use it
m_show_guides_action = GUI : : Action : : create_checkable (
2021-09-12 22:50:46 -03:00
" Show &Guides " , [ & ] ( auto & action ) {
2021-09-12 00:56:57 -03:00
Config : : write_bool ( " PixelPaint " , " Guides " , " Show " , action . is_checked ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
if ( auto * editor = current_image_editor ( ) ) {
editor - > set_guide_visibility ( action . is_checked ( ) ) ;
}
} ) ;
2021-09-12 00:40:59 -03:00
m_show_guides_action - > set_checked ( Config : : read_bool ( " PixelPaint " , " Guides " , " Show " , true ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
view_menu . add_action ( * m_zoom_in_action ) ;
view_menu . add_action ( * m_zoom_out_action ) ;
view_menu . add_action ( * m_reset_zoom_action ) ;
2021-09-07 15:14:18 -03:00
view_menu . add_action ( GUI : : Action : : create (
" &Fit Image To View " , [ & ] ( auto & ) {
if ( auto * editor = current_image_editor ( ) )
editor - > fit_image_to_view ( ) ;
} ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
view_menu . add_separator ( ) ;
view_menu . add_action ( * m_add_guide_action ) ;
view_menu . add_action ( * m_show_guides_action ) ;
2021-09-10 12:41:28 -03:00
view_menu . add_action ( GUI : : Action : : create (
2021-09-12 22:50:46 -03:00
" &Clear Guides " , [ & ] ( auto & ) {
2021-09-10 12:41:28 -03:00
if ( auto * editor = current_image_editor ( ) )
editor - > clear_guides ( ) ;
} ) ) ;
2021-09-11 00:12:25 -03:00
view_menu . add_separator ( ) ;
auto show_pixel_grid_action = GUI : : Action : : create_checkable (
2021-09-12 22:50:46 -03:00
" Show &Pixel Grid " , [ & ] ( auto & action ) {
2021-09-12 00:56:57 -03:00
Config : : write_bool ( " PixelPaint " , " PixelGrid " , " Show " , action . is_checked ( ) ) ;
2021-09-11 00:12:25 -03:00
if ( auto * editor = current_image_editor ( ) )
editor - > set_pixel_grid_visibility ( action . is_checked ( ) ) ;
} ) ;
2021-09-12 00:40:59 -03:00
show_pixel_grid_action - > set_checked ( Config : : read_bool ( " PixelPaint " , " PixelGrid " , " Show " , true ) ) ;
2021-09-11 00:12:25 -03:00
view_menu . add_action ( * show_pixel_grid_action ) ;
2021-09-10 12:41:28 -03:00
2021-09-05 07:22:27 -03:00
m_show_rulers_action = GUI : : Action : : create_checkable (
2021-09-12 22:50:46 -03:00
" Show R&ulers " , { Mod_Ctrl , Key_R } , [ & ] ( auto & action ) {
2021-09-12 00:56:57 -03:00
Config : : write_bool ( " PixelPaint " , " Rulers " , " Show " , action . is_checked ( ) ) ;
2021-09-05 07:22:27 -03:00
if ( auto * editor = current_image_editor ( ) ) {
editor - > set_ruler_visibility ( action . is_checked ( ) ) ;
}
} ) ;
2021-09-12 00:40:59 -03:00
m_show_rulers_action - > set_checked ( Config : : read_bool ( " PixelPaint " , " Rulers " , " Show " , true ) ) ;
2021-09-05 07:22:27 -03:00
view_menu . add_action ( * m_show_rulers_action ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
auto & tool_menu = window . add_menu ( " &Tool " ) ;
m_toolbox - > for_each_tool ( [ & ] ( auto & tool ) {
if ( tool . action ( ) )
tool_menu . add_action ( * tool . action ( ) ) ;
return IterationDecision : : Continue ;
} ) ;
auto & image_menu = window . add_menu ( " &Image " ) ;
image_menu . add_action ( GUI : : Action : : create (
" Flip &Vertically " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
editor - > image ( ) . flip ( Gfx : : Orientation : : Vertical ) ;
} ) ) ;
image_menu . add_action ( GUI : : Action : : create (
" Flip &Horizontally " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
editor - > image ( ) . flip ( Gfx : : Orientation : : Horizontal ) ;
} ) ) ;
image_menu . add_separator ( ) ;
image_menu . add_action ( GUI : : Action : : create (
" Rotate &Left " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
editor - > image ( ) . rotate ( Gfx : : RotationDirection : : CounterClockwise ) ;
} ) ) ;
image_menu . add_action ( GUI : : Action : : create (
" Rotate &Right " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
editor - > image ( ) . rotate ( Gfx : : RotationDirection : : Clockwise ) ;
} ) ) ;
2021-09-02 22:09:04 -03:00
image_menu . add_separator ( ) ;
image_menu . add_action ( GUI : : Action : : create (
" &Crop To Selection " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
// FIXME: disable this action if there is no selection
if ( ! editor | | editor - > selection ( ) . is_empty ( ) )
return ;
auto crop_rect = editor - > selection ( ) . bounding_rect ( ) ;
editor - > image ( ) . crop ( crop_rect ) ;
editor - > selection ( ) . clear ( ) ;
} ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
auto & layer_menu = window . add_menu ( " &Layer " ) ;
layer_menu . add_action ( GUI : : Action : : create (
" New &Layer... " , { Mod_Ctrl | Mod_Shift , Key_N } , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto dialog = PixelPaint : : CreateNewLayerDialog : : construct ( editor - > image ( ) . size ( ) , & window ) ;
if ( dialog - > exec ( ) = = GUI : : Dialog : : ExecOK ) {
auto layer = PixelPaint : : Layer : : try_create_with_size ( editor - > image ( ) , dialog - > layer_size ( ) , dialog - > layer_name ( ) ) ;
if ( ! layer ) {
GUI : : MessageBox : : show_error ( & window , String : : formatted ( " Unable to create layer with size {} " , dialog - > size ( ) . to_string ( ) ) ) ;
return ;
}
editor - > image ( ) . add_layer ( layer . release_nonnull ( ) ) ;
editor - > layers_did_change ( ) ;
m_layer_list_widget - > select_top_layer ( ) ;
}
} ) ) ;
layer_menu . add_separator ( ) ;
layer_menu . add_action ( GUI : : Action : : create (
" Select &Previous Layer " , { 0 , Key_PageUp } , [ & ] ( auto & ) {
m_layer_list_widget - > cycle_through_selection ( 1 ) ;
} ) ) ;
layer_menu . add_action ( GUI : : Action : : create (
" Select &Next Layer " , { 0 , Key_PageDown } , [ & ] ( auto & ) {
m_layer_list_widget - > cycle_through_selection ( - 1 ) ;
} ) ) ;
layer_menu . add_action ( GUI : : Action : : create (
" Select &Top Layer " , { 0 , Key_Home } , [ & ] ( auto & ) {
m_layer_list_widget - > select_top_layer ( ) ;
} ) ) ;
layer_menu . add_action ( GUI : : Action : : create (
2021-09-12 22:50:46 -03:00
" Select B&ottom Layer " , { 0 , Key_End } , [ & ] ( auto & ) {
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
m_layer_list_widget - > select_bottom_layer ( ) ;
} ) ) ;
layer_menu . add_separator ( ) ;
layer_menu . add_action ( GUI : : CommonActions : : make_move_to_front_action (
[ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto active_layer = editor - > active_layer ( ) ;
if ( ! active_layer )
return ;
editor - > image ( ) . move_layer_to_front ( * active_layer ) ;
editor - > layers_did_change ( ) ;
} ) ) ;
layer_menu . add_action ( GUI : : CommonActions : : make_move_to_back_action (
[ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto active_layer = editor - > active_layer ( ) ;
if ( ! active_layer )
return ;
editor - > image ( ) . move_layer_to_back ( * active_layer ) ;
editor - > layers_did_change ( ) ;
} ) ) ;
layer_menu . add_separator ( ) ;
layer_menu . add_action ( GUI : : Action : : create (
" Move Active Layer &Up " , { Mod_Ctrl , Key_PageUp } , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto active_layer = editor - > active_layer ( ) ;
if ( ! active_layer )
return ;
editor - > image ( ) . move_layer_up ( * active_layer ) ;
} ) ) ;
layer_menu . add_action ( GUI : : Action : : create (
" Move Active Layer &Down " , { Mod_Ctrl , Key_PageDown } , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto active_layer = editor - > active_layer ( ) ;
if ( ! active_layer )
return ;
editor - > image ( ) . move_layer_down ( * active_layer ) ;
} ) ) ;
layer_menu . add_separator ( ) ;
layer_menu . add_action ( GUI : : Action : : create (
" &Remove Active Layer " , { Mod_Ctrl , Key_D } , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/delete.png " ) , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto active_layer = editor - > active_layer ( ) ;
if ( ! active_layer )
return ;
auto active_layer_index = editor - > image ( ) . index_of ( * active_layer ) ;
editor - > image ( ) . remove_layer ( * active_layer ) ;
if ( editor - > image ( ) . layer_count ( ) ) {
auto & next_active_layer = editor - > image ( ) . layer ( active_layer_index > 0 ? active_layer_index - 1 : 0 ) ;
editor - > set_active_layer ( & next_active_layer ) ;
} else {
editor - > set_active_layer ( nullptr ) ;
}
} ) ) ;
m_layer_list_widget - > on_context_menu_request = [ & ] ( auto & event ) {
layer_menu . popup ( event . screen_position ( ) ) ;
} ;
layer_menu . add_separator ( ) ;
layer_menu . add_action ( GUI : : Action : : create (
2021-09-12 22:50:46 -03:00
" Fl&atten Image " , { Mod_Ctrl , Key_F } , [ & ] ( auto & ) {
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
editor - > image ( ) . flatten_all_layers ( ) ;
editor - > did_complete_action ( ) ;
} ) ) ;
layer_menu . add_action ( GUI : : Action : : create (
" &Merge Visible " , { Mod_Ctrl , Key_M } , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
editor - > image ( ) . merge_visible_layers ( ) ;
editor - > did_complete_action ( ) ;
} ) ) ;
layer_menu . add_action ( GUI : : Action : : create (
" M&erge Active Layer Down " , { Mod_Ctrl , Key_E } , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
auto active_layer = editor - > active_layer ( ) ;
if ( ! active_layer )
return ;
editor - > image ( ) . merge_active_layer_down ( * active_layer ) ;
editor - > did_complete_action ( ) ;
} ) ) ;
auto & filter_menu = window . add_menu ( " &Filter " ) ;
auto & spatial_filters_menu = filter_menu . add_submenu ( " &Spatial " ) ;
auto & edge_detect_submenu = spatial_filters_menu . add_submenu ( " &Edge Detect " ) ;
edge_detect_submenu . add_action ( GUI : : Action : : create ( " Laplacian (&Cardinal) " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : LaplacianFilter filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : LaplacianFilter > : : get ( false ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
edge_detect_submenu . add_action ( GUI : : Action : : create ( " Laplacian (&Diagonal) " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : LaplacianFilter filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : LaplacianFilter > : : get ( true ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
auto & blur_submenu = spatial_filters_menu . add_submenu ( " &Blur and Sharpen " ) ;
blur_submenu . add_action ( GUI : : Action : : create ( " &Gaussian Blur (3x3) " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : SpatialGaussianBlurFilter < 3 > filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : SpatialGaussianBlurFilter < 3 > > : : get ( ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
blur_submenu . add_action ( GUI : : Action : : create ( " G&aussian Blur (5x5) " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : SpatialGaussianBlurFilter < 5 > filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : SpatialGaussianBlurFilter < 5 > > : : get ( ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
blur_submenu . add_action ( GUI : : Action : : create ( " &Box Blur (3x3) " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : BoxBlurFilter < 3 > filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : BoxBlurFilter < 3 > > : : get ( ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
blur_submenu . add_action ( GUI : : Action : : create ( " B&ox Blur (5x5) " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : BoxBlurFilter < 5 > filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : BoxBlurFilter < 5 > > : : get ( ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
blur_submenu . add_action ( GUI : : Action : : create ( " &Sharpen " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : SharpenFilter filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : SharpenFilter > : : get ( ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
spatial_filters_menu . add_separator ( ) ;
spatial_filters_menu . add_action ( GUI : : Action : : create ( " Generic 5x5 &Convolution " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : GenericConvolutionFilter < 5 > filter ;
if ( auto parameters = PixelPaint : : FilterParameters < Gfx : : GenericConvolutionFilter < 5 > > : : get ( & window ) ) {
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) , * parameters ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
}
} ) ) ;
auto & color_filters_menu = filter_menu . add_submenu ( " &Color " ) ;
color_filters_menu . add_action ( GUI : : Action : : create ( " Grayscale " , [ & ] ( auto & ) {
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : GrayscaleFilter filter ;
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
} ) ) ;
2021-09-12 22:00:18 -03:00
color_filters_menu . add_action ( GUI : : Action : : create ( " Invert " , { Mod_Ctrl , Key_I } , [ & ] ( auto & ) {
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
auto * editor = current_image_editor ( ) ;
if ( ! editor )
return ;
if ( auto * layer = editor - > active_layer ( ) ) {
Gfx : : InvertFilter filter ;
filter . apply ( layer - > bitmap ( ) , layer - > rect ( ) , layer - > bitmap ( ) , layer - > rect ( ) ) ;
2021-09-12 22:09:07 -03:00
layer - > did_modify_bitmap ( layer - > rect ( ) ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
editor - > did_complete_action ( ) ;
}
} ) ) ;
auto & help_menu = window . add_menu ( " &Help " ) ;
help_menu . add_action ( GUI : : CommonActions : : make_about_action ( " Pixel Paint " , GUI : : Icon : : default_icon ( " app-pixel-paint " ) , & window ) ) ;
auto & toolbar = * find_descendant_of_type_named < GUI : : Toolbar > ( " toolbar " ) ;
toolbar . add_action ( * m_new_image_action ) ;
toolbar . add_action ( * m_open_image_action ) ;
toolbar . add_action ( * m_save_image_as_action ) ;
toolbar . add_separator ( ) ;
toolbar . add_action ( * m_copy_action ) ;
toolbar . add_action ( * m_paste_action ) ;
toolbar . add_action ( * m_undo_action ) ;
toolbar . add_action ( * m_redo_action ) ;
toolbar . add_separator ( ) ;
toolbar . add_action ( * m_zoom_in_action ) ;
toolbar . add_action ( * m_zoom_out_action ) ;
toolbar . add_action ( * m_reset_zoom_action ) ;
}
void MainWidget : : open_image_fd ( int fd , String const & path )
{
auto try_load = m_loader . try_load_from_fd_and_close ( fd , path ) ;
if ( try_load . is_error ( ) ) {
GUI : : MessageBox : : show_error ( window ( ) , String : : formatted ( " Unable to open file: {}, {} " , path , try_load . error ( ) ) ) ;
return ;
}
auto & image = * m_loader . release_image ( ) ;
create_new_editor ( image ) ;
m_layer_list_widget - > set_image ( & image ) ;
}
void MainWidget : : create_default_image ( )
{
auto image = Image : : try_create_with_size ( { 480 , 360 } ) ;
auto bg_layer = Layer : : try_create_with_size ( * image , image - > size ( ) , " Background " ) ;
VERIFY ( bg_layer ) ;
image - > add_layer ( * bg_layer ) ;
bg_layer - > bitmap ( ) . fill ( Color : : White ) ;
m_layer_list_widget - > set_image ( image ) ;
auto & editor = create_new_editor ( * image ) ;
editor . set_active_layer ( bg_layer ) ;
}
ImageEditor * MainWidget : : current_image_editor ( )
{
if ( ! m_tab_widget - > active_widget ( ) )
return nullptr ;
return verify_cast < PixelPaint : : ImageEditor > ( m_tab_widget - > active_widget ( ) ) ;
}
ImageEditor & MainWidget : : create_new_editor ( NonnullRefPtr < Image > image )
{
auto & image_editor = m_tab_widget - > add_tab < PixelPaint : : ImageEditor > ( " Untitled " , image ) ;
image_editor . on_active_layer_change = [ & ] ( auto * layer ) {
if ( current_image_editor ( ) ! = & image_editor )
return ;
m_layer_list_widget - > set_selected_layer ( layer ) ;
m_layer_properties_widget - > set_layer ( layer ) ;
} ;
image_editor . on_image_title_change = [ & ] ( auto const & title ) {
m_tab_widget - > set_tab_title ( image_editor , title ) ;
} ;
image_editor . on_image_mouse_position_change = [ & ] ( auto const & mouse_position ) {
auto const & image_size = current_image_editor ( ) - > image ( ) . size ( ) ;
auto image_rectangle = Gfx : : IntRect { 0 , 0 , image_size . width ( ) , image_size . height ( ) } ;
if ( image_rectangle . contains ( mouse_position ) ) {
m_statusbar - > set_override_text ( mouse_position . to_string ( ) ) ;
} else {
m_statusbar - > set_override_text ( { } ) ;
}
} ;
image_editor . on_leave = [ & ] ( ) {
m_statusbar - > set_override_text ( { } ) ;
} ;
image_editor . on_set_guide_visibility = [ & ] ( bool show_guides ) {
m_show_guides_action - > set_checked ( show_guides ) ;
} ;
2021-09-05 07:22:27 -03:00
image_editor . on_set_ruler_visibility = [ & ] ( bool show_rulers ) {
m_show_rulers_action - > set_checked ( show_rulers ) ;
} ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
// NOTE: We invoke the above hook directly here to make sure the tab title is set up.
image_editor . on_image_title_change ( image - > title ( ) ) ;
if ( image - > layer_count ( ) )
image_editor . set_active_layer ( & image - > layer ( 0 ) ) ;
if ( ! m_loader . is_raw_image ( ) ) {
m_loader . json_metadata ( ) . for_each ( [ & ] ( JsonValue const & value ) {
if ( ! value . is_object ( ) )
return ;
auto & json_object = value . as_object ( ) ;
auto orientation_value = json_object . get ( " orientation " sv ) ;
if ( ! orientation_value . is_string ( ) )
return ;
auto offset_value = json_object . get ( " offset " sv ) ;
if ( ! offset_value . is_number ( ) )
return ;
auto orientation_string = orientation_value . as_string ( ) ;
PixelPaint : : Guide : : Orientation orientation ;
if ( orientation_string = = " horizontal " sv )
orientation = PixelPaint : : Guide : : Orientation : : Horizontal ;
else if ( orientation_string = = " vertical " sv )
orientation = PixelPaint : : Guide : : Orientation : : Vertical ;
else
return ;
image_editor . add_guide ( PixelPaint : : Guide : : construct ( orientation , offset_value . to_number < float > ( ) ) ) ;
} ) ;
}
m_tab_widget - > set_active_widget ( & image_editor ) ;
image_editor . set_focus ( true ) ;
2021-09-11 15:36:24 -03:00
image_editor . fit_image_to_view ( ) ;
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
return image_editor ;
}
2021-09-06 01:24:12 -03:00
void MainWidget : : drop_event ( GUI : : DropEvent & event )
{
if ( ! event . mime_data ( ) . has_urls ( ) )
return ;
event . accept ( ) ;
if ( event . mime_data ( ) . urls ( ) . is_empty ( ) )
return ;
for ( auto & url : event . mime_data ( ) . urls ( ) ) {
if ( url . protocol ( ) ! = " file " )
continue ;
auto result = FileSystemAccessClient : : Client : : the ( ) . request_file ( window ( ) - > window_id ( ) , url . path ( ) , Core : : OpenMode : : ReadOnly ) ;
if ( result . error ! = 0 )
continue ;
open_image_fd ( * result . fd , * result . chosen_file ) ;
}
}
PixelPaint: Refactor `main.cpp` into `MainWidget`
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
2021-09-06 01:11:46 -03:00
}