2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-05-13 21:14:39 +02:00
# include "CreateNewLayerDialog.h"
2020-05-12 22:22:45 +02:00
# include "Image.h"
# include "ImageEditor.h"
# include "Layer.h"
2019-06-10 19:54:09 +02:00
# include "PaletteWidget.h"
2020-05-13 19:30:07 +02:00
# include "Tool.h"
2019-06-12 05:58:31 +02:00
# include "ToolboxWidget.h"
2020-02-06 20:33:02 +01:00
# include <LibGUI/AboutDialog.h>
# include <LibGUI/Action.h>
# include <LibGUI/Application.h>
# include <LibGUI/BoxLayout.h>
# include <LibGUI/FilePicker.h>
# include <LibGUI/Menu.h>
# include <LibGUI/MenuBar.h>
# include <LibGUI/MessageBox.h>
2020-05-12 23:00:23 +02:00
# include <LibGUI/Model.h>
# include <LibGUI/TableView.h>
2020-02-06 20:33:02 +01:00
# include <LibGUI/Window.h>
2020-02-16 09:17:49 +01:00
# include <LibGfx/Bitmap.h>
2020-01-13 12:22:49 +01:00
# include <stdio.h>
2019-06-10 19:29:33 +02:00
int main ( int argc , char * * argv )
{
2020-02-28 19:48:29 +01:00
if ( pledge ( " stdio thread shared_buffer accept rpath unix wpath cpath fattr " , nullptr ) < 0 ) {
2020-01-13 12:22:49 +01:00
perror ( " pledge " ) ;
return 1 ;
}
2020-02-02 15:07:41 +01:00
GUI : : Application app ( argc , argv ) ;
2019-06-10 19:29:33 +02:00
2020-02-28 19:48:29 +01:00
if ( pledge ( " stdio thread shared_buffer accept rpath wpath cpath " , nullptr ) < 0 ) {
2020-01-13 12:22:49 +01:00
perror ( " pledge " ) ;
return 1 ;
}
2020-02-02 15:07:41 +01:00
auto window = GUI : : Window : : construct ( ) ;
2019-06-10 19:29:33 +02:00
window - > set_title ( " PaintBrush " ) ;
2020-05-13 22:12:03 +02:00
window - > set_rect ( 40 , 100 , 950 , 570 ) ;
2020-02-06 13:39:17 +01:00
window - > set_icon ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/app-paintbrush.png " ) ) ;
2019-06-10 19:29:33 +02:00
2020-03-04 09:46:23 +01:00
auto & horizontal_container = window - > set_main_widget < GUI : : Widget > ( ) ;
horizontal_container . set_layout < GUI : : HorizontalBoxLayout > ( ) ;
horizontal_container . layout ( ) - > set_spacing ( 0 ) ;
2019-06-10 19:54:09 +02:00
2020-05-12 23:44:46 +02:00
auto & toolbox = horizontal_container . add < PaintBrush : : ToolboxWidget > ( ) ;
2019-06-12 05:58:31 +02:00
2020-03-04 19:07:55 +01:00
auto & vertical_container = horizontal_container . add < GUI : : Widget > ( ) ;
vertical_container . set_layout < GUI : : VerticalBoxLayout > ( ) ;
vertical_container . layout ( ) - > set_spacing ( 0 ) ;
2019-06-12 05:58:31 +02:00
2020-05-12 22:22:45 +02:00
auto & image_editor = vertical_container . add < PaintBrush : : ImageEditor > ( ) ;
image_editor . set_focus ( true ) ;
2020-05-12 23:44:46 +02:00
toolbox . on_tool_selection = [ & ] ( auto * tool ) {
image_editor . set_active_tool ( tool ) ;
} ;
2020-05-13 12:47:47 +02:00
vertical_container . add < PaintBrush : : PaletteWidget > ( image_editor ) ;
2019-06-10 19:29:33 +02:00
2020-05-12 23:00:23 +02:00
auto & right_panel = horizontal_container . add < GUI : : Widget > ( ) ;
right_panel . set_size_policy ( GUI : : SizePolicy : : Fixed , GUI : : SizePolicy : : Fill ) ;
right_panel . set_preferred_size ( 230 , 0 ) ;
right_panel . set_layout < GUI : : VerticalBoxLayout > ( ) ;
auto & layer_table_view = right_panel . add < GUI : : TableView > ( ) ;
layer_table_view . set_size_columns_to_fit_content ( true ) ;
2019-06-10 19:29:33 +02:00
window - > show ( ) ;
2019-06-10 21:05:20 +02:00
2020-04-21 16:01:00 +02:00
auto menubar = GUI : : MenuBar : : construct ( ) ;
2020-04-04 12:18:40 +02:00
auto & app_menu = menubar - > add_menu ( " PaintBrush " ) ;
2019-10-01 00:18:20 -05:00
2020-04-04 12:18:40 +02:00
app_menu . add_action ( GUI : : CommonActions : : make_open_action ( [ & ] ( auto & ) {
2020-02-02 15:07:41 +01:00
Optional < String > open_path = GUI : : FilePicker : : get_open_filepath ( ) ;
2019-10-01 00:18:20 -05:00
if ( ! open_path . has_value ( ) )
return ;
2020-02-06 13:39:17 +01:00
auto bitmap = Gfx : : Bitmap : : load_from_file ( open_path . value ( ) ) ;
2019-10-01 00:18:20 -05:00
if ( ! bitmap ) {
2020-02-02 15:07:41 +01:00
GUI : : MessageBox : : show ( String : : format ( " Failed to load '%s' " , open_path . value ( ) . characters ( ) ) , " Open failed " , GUI : : MessageBox : : Type : : Error , GUI : : MessageBox : : InputType : : OK , window ) ;
2019-10-01 00:18:20 -05:00
return ;
}
} ) ) ;
2020-04-04 12:18:40 +02:00
app_menu . add_separator ( ) ;
app_menu . add_action ( GUI : : CommonActions : : make_quit_action ( [ ] ( auto & ) {
2020-02-02 15:07:41 +01:00
GUI : : Application : : the ( ) . quit ( 0 ) ;
2019-06-10 21:05:20 +02:00
return ;
} ) ) ;
2020-04-04 12:18:40 +02:00
menubar - > add_menu ( " Edit " ) ;
2019-06-10 21:05:20 +02:00
2020-05-13 19:30:07 +02:00
auto & tool_menu = menubar - > add_menu ( " Tool " ) ;
toolbox . for_each_tool ( [ & ] ( auto & tool ) {
if ( tool . action ( ) )
tool_menu . add_action ( * tool . action ( ) ) ;
return IterationDecision : : Continue ;
} ) ;
2020-05-13 21:14:39 +02:00
auto & layer_menu = menubar - > add_menu ( " Layer " ) ;
layer_menu . add_action ( GUI : : Action : : create ( " Create new layer... " , { Mod_Ctrl | Mod_Shift , Key_N } , [ & ] ( auto & ) {
auto dialog = PaintBrush : : CreateNewLayerDialog : : construct ( image_editor . image ( ) - > size ( ) , window ) ;
if ( dialog - > exec ( ) = = GUI : : Dialog : : ExecOK ) {
auto layer = PaintBrush : : Layer : : create_with_size ( dialog - > layer_size ( ) , dialog - > layer_name ( ) ) ;
if ( ! layer ) {
GUI : : MessageBox : : show_error ( String : : format ( " Unable to create layer with size %s " , dialog - > size ( ) . to_string ( ) . characters ( ) ) ) ;
return ;
}
image_editor . image ( ) - > add_layer ( layer . release_nonnull ( ) ) ;
image_editor . layers_did_change ( ) ;
}
} , window ) ) ;
2020-05-13 21:25:13 +02:00
layer_menu . add_separator ( ) ;
layer_menu . add_action ( GUI : : Action : : create ( " Select previous layer " , { 0 , Key_PageUp } , [ & ] ( auto & ) {
layer_table_view . move_selection ( 1 ) ;
} , window ) ) ;
layer_menu . add_action ( GUI : : Action : : create ( " Select next layer " , { 0 , Key_PageDown } , [ & ] ( auto & ) {
layer_table_view . move_selection ( - 1 ) ;
} , window ) ) ;
layer_menu . add_action ( GUI : : Action : : create ( " Select top layer " , { 0 , Key_Home } , [ & ] ( auto & ) {
layer_table_view . selection ( ) . set ( layer_table_view . model ( ) - > index ( image_editor . image ( ) - > layer_count ( ) - 1 ) ) ;
} , window ) ) ;
layer_menu . add_action ( GUI : : Action : : create ( " Select bottom layer " , { 0 , Key_End } , [ & ] ( auto & ) {
layer_table_view . selection ( ) . set ( layer_table_view . model ( ) - > index ( 0 ) ) ;
} , window ) ) ;
2020-05-14 14:18:47 +02:00
layer_menu . add_separator ( ) ;
2020-05-14 14:22:30 +02:00
layer_menu . add_action ( GUI : : Action : : create ( " Move active layer up " , { Mod_Ctrl , Key_PageUp } , [ & ] ( auto & ) {
auto active_layer = image_editor . active_layer ( ) ;
if ( ! active_layer )
return ;
image_editor . image ( ) - > move_layer_up ( * active_layer ) ;
layer_table_view . move_selection ( 1 ) ;
image_editor . layers_did_change ( ) ;
} , window ) ) ;
layer_menu . add_action ( GUI : : Action : : create ( " Move active layer down " , { Mod_Ctrl , Key_PageDown } , [ & ] ( auto & ) {
auto active_layer = image_editor . active_layer ( ) ;
if ( ! active_layer )
return ;
image_editor . image ( ) - > move_layer_down ( * active_layer ) ;
layer_table_view . move_selection ( - 1 ) ;
image_editor . layers_did_change ( ) ;
} , window ) ) ;
layer_menu . add_separator ( ) ;
2020-05-14 14:18:47 +02:00
layer_menu . add_action ( GUI : : Action : : create ( " Remove active layer " , { Mod_Ctrl , Key_D } , [ & ] ( auto & ) {
auto active_layer = image_editor . active_layer ( ) ;
if ( ! active_layer )
return ;
image_editor . image ( ) - > remove_layer ( * active_layer ) ;
image_editor . set_active_layer ( nullptr ) ;
image_editor . layers_did_change ( ) ;
} , window ) ) ;
2020-05-13 21:25:13 +02:00
2020-04-04 12:18:40 +02:00
auto & help_menu = menubar - > add_menu ( " Help " ) ;
help_menu . add_action ( GUI : : Action : : create ( " About " , [ & ] ( auto & ) {
2020-02-06 13:39:17 +01:00
GUI : : AboutDialog : : show ( " PaintBrush " , Gfx : : Bitmap : : load_from_file ( " /res/icons/32x32/app-paintbrush.png " ) , window ) ;
2019-06-10 21:05:20 +02:00
} ) ) ;
app . set_menubar ( move ( menubar ) ) ;
2020-05-13 21:46:19 +02:00
image_editor . on_active_layer_change = [ & ] ( auto & index ) {
if ( index . is_valid ( ) )
layer_table_view . selection ( ) . set ( index ) ;
else
layer_table_view . selection ( ) . clear ( ) ;
} ;
2020-05-12 22:22:45 +02:00
auto image = PaintBrush : : Image : : create_with_size ( { 640 , 480 } ) ;
auto bg_layer = PaintBrush : : Layer : : create_with_size ( { 640 , 480 } , " Background " ) ;
image - > add_layer ( * bg_layer ) ;
2020-05-13 22:28:33 +02:00
bg_layer - > bitmap ( ) . fill ( Color : : White ) ;
2020-05-12 22:22:45 +02:00
2020-05-12 23:00:23 +02:00
layer_table_view . set_model ( image - > layer_model ( ) ) ;
layer_table_view . on_selection_change = [ & ] {
auto index = layer_table_view . selection ( ) . first ( ) ;
if ( index . is_valid ( ) )
image_editor . set_active_layer ( const_cast < PaintBrush : : Layer * > ( & image - > layer ( index . row ( ) ) ) ) ;
else
image_editor . set_active_layer ( nullptr ) ;
} ;
2020-05-12 22:22:45 +02:00
image_editor . set_image ( image ) ;
2020-05-13 22:28:33 +02:00
image_editor . set_active_layer ( bg_layer ) ;
2020-05-12 22:22:45 +02:00
2019-06-10 19:29:33 +02:00
return app . exec ( ) ;
}