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 .
*/
2019-04-11 00:05:47 +02:00
# include "VBForm.h"
2019-05-08 04:39:42 +02:00
# include "VBProperty.h"
2019-06-07 11:48:27 +02:00
# include "VBWidget.h"
2019-06-29 12:06:46 +02:00
# include "VBWidgetRegistry.h"
2019-06-17 19:50:30 +02:00
# include <AK/JsonArray.h>
# include <AK/JsonObject.h>
2019-08-07 21:28:07 +02:00
# include <AK/StringBuilder.h>
2020-02-06 15:04:03 +01:00
# include <LibCore/File.h>
2020-02-06 20:33:02 +01:00
# include <LibGUI/Action.h>
# include <LibGUI/BoxLayout.h>
# include <LibGUI/Menu.h>
# include <LibGUI/MessageBox.h>
# include <LibGUI/Painter.h>
2019-04-11 00:05:47 +02:00
2019-04-11 04:13:11 +02:00
static VBForm * s_current ;
VBForm * VBForm : : current ( )
{
return s_current ;
}
2020-02-23 12:07:13 +01:00
VBForm : : VBForm ( const String & name )
: m_name ( name )
2019-04-11 00:05:47 +02:00
{
2019-04-11 04:13:11 +02:00
s_current = this ;
2019-04-11 00:05:47 +02:00
set_fill_with_background_color ( true ) ;
2019-04-11 03:34:37 +02:00
set_greedy_for_hits ( true ) ;
2019-04-11 01:59:07 +02:00
2020-02-02 15:07:41 +01:00
m_context_menu = GUI : : Menu : : construct ( ) ;
m_context_menu - > add_action ( GUI : : CommonActions : : make_move_to_front_action ( [ this ] ( auto & ) {
2019-04-19 22:46:16 +02:00
if ( auto * widget = single_selected_widget ( ) )
widget - > gwidget ( ) - > move_to_front ( ) ;
2019-04-16 03:52:26 +02:00
} ) ) ;
2020-02-02 15:07:41 +01:00
m_context_menu - > add_action ( GUI : : CommonActions : : make_move_to_back_action ( [ this ] ( auto & ) {
2019-04-19 22:46:16 +02:00
if ( auto * widget = single_selected_widget ( ) )
widget - > gwidget ( ) - > move_to_back ( ) ;
} ) ) ;
2019-09-17 21:02:05 +02:00
m_context_menu - > add_separator ( ) ;
2020-02-06 13:39:17 +01:00
m_context_menu - > add_action ( GUI : : Action : : create ( " Lay out horizontally " , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/layout-horizontally.png " ) , [ this ] ( auto & ) {
2019-09-17 21:02:05 +02:00
if ( auto * widget = single_selected_widget ( ) ) {
dbg ( ) < < " Giving " < < * widget - > gwidget ( ) < < " a horizontal box layout " ;
2020-03-04 09:43:54 +01:00
widget - > gwidget ( ) - > set_layout < GUI : : HorizontalBoxLayout > ( ) ;
2019-09-17 21:02:05 +02:00
}
} ) ) ;
2020-02-06 13:39:17 +01:00
m_context_menu - > add_action ( GUI : : Action : : create ( " Lay out vertically " , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/layout-vertically.png " ) , [ this ] ( auto & ) {
2019-09-17 21:02:05 +02:00
if ( auto * widget = single_selected_widget ( ) ) {
dbg ( ) < < " Giving " < < * widget - > gwidget ( ) < < " a vertical box layout " ;
2020-03-04 09:43:54 +01:00
widget - > gwidget ( ) - > set_layout < GUI : : VerticalBoxLayout > ( ) ;
2019-09-17 21:02:05 +02:00
}
} ) ) ;
m_context_menu - > add_separator ( ) ;
2020-02-02 15:07:41 +01:00
m_context_menu - > add_action ( GUI : : CommonActions : : make_delete_action ( [ this ] ( auto & ) {
2019-04-19 22:46:16 +02:00
delete_selected_widgets ( ) ;
2019-04-16 03:52:26 +02:00
} ) ) ;
2019-04-18 04:12:27 +02:00
}
2020-02-02 15:07:41 +01:00
void VBForm : : context_menu_event ( GUI : : ContextMenuEvent & event )
2019-04-18 04:12:27 +02:00
{
m_context_menu - > popup ( event . screen_position ( ) ) ;
2019-04-11 00:05:47 +02:00
}
2019-04-11 16:13:19 +02:00
void VBForm : : insert_widget ( VBWidgetType type )
2019-04-11 04:13:11 +02:00
{
2019-09-17 21:00:11 +02:00
auto * insertion_parent = single_selected_widget ( ) ;
auto widget = VBWidget : : create ( type , * this , insertion_parent ) ;
2020-02-06 13:08:32 +01:00
Gfx : : Point insertion_position = m_next_insertion_position ;
2019-09-17 21:00:11 +02:00
if ( insertion_parent )
insertion_position . move_by ( insertion_parent - > gwidget ( ) - > window_relative_rect ( ) . location ( ) ) ;
widget - > set_rect ( { insertion_position , { m_grid_size * 10 + 1 , m_grid_size * 5 + 1 } } ) ;
2019-04-11 04:13:11 +02:00
m_next_insertion_position . move_by ( m_grid_size , m_grid_size ) ;
m_widgets . append ( move ( widget ) ) ;
}
2019-04-11 00:05:47 +02:00
VBForm : : ~ VBForm ( )
{
}
2020-02-02 15:07:41 +01:00
void VBForm : : paint_event ( GUI : : PaintEvent & event )
2019-04-11 00:05:47 +02:00
{
2020-02-02 15:07:41 +01:00
GUI : : Painter painter ( * this ) ;
2019-04-11 00:05:47 +02:00
painter . add_clip_rect ( event . rect ( ) ) ;
for ( int y = 0 ; y < height ( ) ; y + = m_grid_size ) {
for ( int x = 0 ; x < width ( ) ; x + = m_grid_size ) {
2019-04-30 17:01:59 +02:00
painter . set_pixel ( { x , y } , Color : : from_rgb ( 0x404040 ) ) ;
2019-04-11 00:05:47 +02:00
}
}
2019-04-11 03:34:37 +02:00
}
2020-02-02 15:07:41 +01:00
void VBForm : : second_paint_event ( GUI : : PaintEvent & event )
2019-04-11 03:34:37 +02:00
{
2020-02-02 15:07:41 +01:00
GUI : : Painter painter ( * this ) ;
2019-04-11 03:34:37 +02:00
painter . add_clip_rect ( event . rect ( ) ) ;
2019-04-11 01:59:07 +02:00
for ( auto & widget : m_widgets ) {
2019-06-27 13:49:26 +02:00
if ( widget . is_selected ( ) ) {
for_each_direction ( [ & ] ( auto direction ) {
2019-09-17 21:22:15 +02:00
bool in_layout = widget . is_in_layout ( ) ;
auto grabber_rect = widget . grabber_rect ( direction ) ;
painter . fill_rect ( grabber_rect , in_layout ? Color : : White : Color : : Black ) ;
if ( in_layout )
painter . draw_rect ( grabber_rect , Color : : Black ) ;
2019-04-11 02:49:10 +02:00
} ) ;
}
2019-04-11 01:59:07 +02:00
}
}
bool VBForm : : is_selected ( const VBWidget & widget ) const
{
2019-04-19 22:46:16 +02:00
// FIXME: Fix HashTable and remove this const_cast.
return m_selected_widgets . contains ( const_cast < VBWidget * > ( & widget ) ) ;
2019-04-11 01:59:07 +02:00
}
2020-02-06 11:56:38 +01:00
VBWidget * VBForm : : widget_at ( const Gfx : : Point & position )
2019-04-11 01:59:07 +02:00
{
2020-02-02 15:07:41 +01:00
auto result = hit_test ( position , GUI : : Widget : : ShouldRespectGreediness : : No ) ;
2019-09-17 21:00:11 +02:00
if ( ! result . widget )
2019-04-16 03:52:26 +02:00
return nullptr ;
2019-09-17 21:11:52 +02:00
auto * gwidget = result . widget ;
while ( gwidget ) {
if ( auto * widget = m_gwidget_map . get ( gwidget ) . value_or ( nullptr ) )
return widget ;
gwidget = gwidget - > parent_widget ( ) ;
}
return nullptr ;
2019-04-11 01:59:07 +02:00
}
2020-02-02 15:07:41 +01:00
void VBForm : : grabber_mousedown_event ( GUI : : MouseEvent & event , Direction grabber )
2019-04-11 02:35:30 +02:00
{
m_transform_event_origin = event . position ( ) ;
2019-06-07 11:48:27 +02:00
for_each_selected_widget ( [ ] ( auto & widget ) { widget . capture_transform_origin_rect ( ) ; } ) ;
2019-04-11 02:35:30 +02:00
m_resize_direction = grabber ;
}
2020-02-02 15:07:41 +01:00
void VBForm : : keydown_event ( GUI : : KeyEvent & event )
2019-04-16 23:01:37 +02:00
{
2019-04-19 22:46:16 +02:00
if ( event . key ( ) = = KeyCode : : Key_Delete ) {
delete_selected_widgets ( ) ;
return ;
}
2019-04-16 23:01:37 +02:00
if ( event . key ( ) = = KeyCode : : Key_Tab ) {
2019-04-16 23:18:26 +02:00
if ( m_widgets . is_empty ( ) )
2019-04-16 23:01:37 +02:00
return ;
2019-04-19 22:46:16 +02:00
if ( m_selected_widgets . is_empty ( ) ) {
2019-06-27 13:49:26 +02:00
set_single_selected_widget ( & m_widgets . first ( ) ) ;
2019-04-16 23:01:37 +02:00
update ( ) ;
return ;
}
2020-02-25 14:49:47 +01:00
size_t selected_widget_index = 0 ;
2019-04-16 23:18:26 +02:00
for ( ; selected_widget_index < m_widgets . size ( ) ; + + selected_widget_index ) {
2019-06-27 13:49:26 +02:00
if ( & m_widgets [ selected_widget_index ] = = * m_selected_widgets . begin ( ) )
2019-04-16 23:18:26 +02:00
break ;
}
+ + selected_widget_index ;
if ( selected_widget_index = = m_widgets . size ( ) )
selected_widget_index = 0 ;
2019-06-27 13:49:26 +02:00
set_single_selected_widget ( & m_widgets [ selected_widget_index ] ) ;
2019-04-16 23:18:26 +02:00
update ( ) ;
2019-04-19 22:46:16 +02:00
return ;
2019-04-16 23:01:37 +02:00
}
2019-04-19 22:46:16 +02:00
if ( ! m_selected_widgets . is_empty ( ) ) {
2019-04-16 23:01:37 +02:00
switch ( event . key ( ) ) {
case KeyCode : : Key_Up :
update ( ) ;
2019-09-17 22:41:42 +02:00
for_each_selected_widget ( [ this ] ( auto & widget ) {
if ( widget . is_in_layout ( ) )
return ;
widget . gwidget ( ) - > move_by ( 0 , - m_grid_size ) ;
} ) ;
2019-04-16 23:01:37 +02:00
break ;
case KeyCode : : Key_Down :
update ( ) ;
2019-09-17 22:41:42 +02:00
for_each_selected_widget ( [ this ] ( auto & widget ) {
if ( widget . is_in_layout ( ) )
return ;
widget . gwidget ( ) - > move_by ( 0 , m_grid_size ) ;
} ) ;
2019-04-16 23:01:37 +02:00
break ;
case KeyCode : : Key_Left :
update ( ) ;
2019-09-17 22:41:42 +02:00
for_each_selected_widget ( [ this ] ( auto & widget ) {
if ( widget . is_in_layout ( ) )
return ;
widget . gwidget ( ) - > move_by ( - m_grid_size , 0 ) ;
} ) ;
2019-04-16 23:01:37 +02:00
break ;
case KeyCode : : Key_Right :
update ( ) ;
2019-09-17 22:41:42 +02:00
for_each_selected_widget ( [ this ] ( auto & widget ) {
if ( widget . is_in_layout ( ) )
return ;
widget . gwidget ( ) - > move_by ( m_grid_size , 0 ) ;
} ) ;
2019-04-16 23:01:37 +02:00
break ;
}
return ;
}
}
2019-04-19 22:46:16 +02:00
void VBForm : : set_single_selected_widget ( VBWidget * widget )
2019-04-16 23:11:35 +02:00
{
if ( ! widget ) {
2019-04-19 22:46:16 +02:00
if ( ! m_selected_widgets . is_empty ( ) ) {
m_selected_widgets . clear ( ) ;
on_widget_selected ( nullptr ) ;
2019-04-16 23:11:35 +02:00
update ( ) ;
}
return ;
}
2019-04-19 22:46:16 +02:00
m_selected_widgets . clear ( ) ;
m_selected_widgets . set ( widget ) ;
on_widget_selected ( m_selected_widgets . size ( ) = = 1 ? widget : nullptr ) ;
update ( ) ;
}
void VBForm : : add_to_selection ( VBWidget & widget )
{
m_selected_widgets . set ( & widget ) ;
update ( ) ;
}
void VBForm : : remove_from_selection ( VBWidget & widget )
{
m_selected_widgets . remove ( & widget ) ;
2019-04-16 23:11:35 +02:00
update ( ) ;
}
2020-02-02 15:07:41 +01:00
void VBForm : : mousedown_event ( GUI : : MouseEvent & event )
2019-04-11 01:59:07 +02:00
{
2019-04-19 22:46:16 +02:00
if ( m_resize_direction = = Direction : : None ) {
bool hit_grabber = false ;
2019-06-07 11:48:27 +02:00
for_each_selected_widget ( [ & ] ( auto & widget ) {
2019-09-17 21:22:15 +02:00
if ( widget . is_in_layout ( ) )
return ;
2019-04-19 22:46:16 +02:00
auto grabber = widget . grabber_at ( event . position ( ) ) ;
if ( grabber ! = Direction : : None ) {
hit_grabber = true ;
2019-04-19 23:09:38 +02:00
return grabber_mousedown_event ( event , grabber ) ;
2019-04-19 22:46:16 +02:00
}
} ) ;
if ( hit_grabber )
return ;
2019-04-11 02:35:30 +02:00
}
2019-04-11 01:59:07 +02:00
auto * widget = widget_at ( event . position ( ) ) ;
if ( ! widget ) {
2019-04-19 22:46:16 +02:00
set_single_selected_widget ( nullptr ) ;
2019-04-11 01:59:07 +02:00
return ;
}
2020-02-02 15:07:41 +01:00
if ( event . button ( ) = = GUI : : MouseButton : : Left | | event . button ( ) = = GUI : : MouseButton : : Right ) {
2019-04-11 01:59:07 +02:00
m_transform_event_origin = event . position ( ) ;
2019-04-19 22:46:16 +02:00
if ( event . modifiers ( ) = = Mod_Ctrl )
remove_from_selection ( * widget ) ;
else if ( event . modifiers ( ) = = Mod_Shift )
add_to_selection ( * widget ) ;
else if ( ! m_selected_widgets . contains ( widget ) )
set_single_selected_widget ( widget ) ;
2019-06-07 11:48:27 +02:00
for_each_selected_widget ( [ ] ( auto & widget ) { widget . capture_transform_origin_rect ( ) ; } ) ;
2019-04-19 23:09:38 +02:00
on_widget_selected ( single_selected_widget ( ) ) ;
2019-04-11 01:59:07 +02:00
}
}
2020-02-02 15:07:41 +01:00
void VBForm : : mousemove_event ( GUI : : MouseEvent & event )
2019-04-11 01:59:07 +02:00
{
2020-02-02 15:07:41 +01:00
if ( event . buttons ( ) & GUI : : MouseButton : : Left ) {
2019-04-11 02:35:30 +02:00
if ( m_resize_direction = = Direction : : None ) {
update ( ) ;
2019-04-19 22:46:16 +02:00
auto delta = event . position ( ) - m_transform_event_origin ;
2019-06-07 11:48:27 +02:00
for_each_selected_widget ( [ & ] ( auto & widget ) {
2019-09-17 21:22:15 +02:00
if ( widget . is_in_layout ( ) )
return ;
2019-04-19 22:46:16 +02:00
auto new_rect = widget . transform_origin_rect ( ) . translated ( delta ) ;
new_rect . set_x ( new_rect . x ( ) - ( new_rect . x ( ) % m_grid_size ) ) ;
new_rect . set_y ( new_rect . y ( ) - ( new_rect . y ( ) % m_grid_size ) ) ;
widget . set_rect ( new_rect ) ;
} ) ;
2019-04-11 02:35:30 +02:00
return ;
}
int diff_x = event . x ( ) - m_transform_event_origin . x ( ) ;
int diff_y = event . y ( ) - m_transform_event_origin . y ( ) ;
int change_x = 0 ;
int change_y = 0 ;
int change_w = 0 ;
int change_h = 0 ;
switch ( m_resize_direction ) {
case Direction : : DownRight :
change_w = diff_x ;
change_h = diff_y ;
break ;
case Direction : : Right :
change_w = diff_x ;
break ;
case Direction : : UpRight :
change_w = diff_x ;
change_y = diff_y ;
change_h = - diff_y ;
break ;
case Direction : : Up :
change_y = diff_y ;
change_h = - diff_y ;
break ;
case Direction : : UpLeft :
change_x = diff_x ;
change_w = - diff_x ;
change_y = diff_y ;
change_h = - diff_y ;
break ;
case Direction : : Left :
change_x = diff_x ;
change_w = - diff_x ;
break ;
case Direction : : DownLeft :
change_x = diff_x ;
change_w = - diff_x ;
change_h = diff_y ;
break ;
case Direction : : Down :
change_h = diff_y ;
break ;
default :
ASSERT_NOT_REACHED ( ) ;
}
2019-04-11 01:59:07 +02:00
update ( ) ;
2019-06-07 11:48:27 +02:00
for_each_selected_widget ( [ & ] ( auto & widget ) {
2019-09-17 21:22:15 +02:00
if ( widget . is_in_layout ( ) )
return ;
2019-04-19 22:46:16 +02:00
auto new_rect = widget . transform_origin_rect ( ) ;
2020-02-06 13:32:14 +01:00
Gfx : : Size minimum_size { 5 , 5 } ;
2019-04-19 22:46:16 +02:00
new_rect . set_x ( new_rect . x ( ) + change_x ) ;
new_rect . set_y ( new_rect . y ( ) + change_y ) ;
new_rect . set_width ( max ( minimum_size . width ( ) , new_rect . width ( ) + change_w ) ) ;
new_rect . set_height ( max ( minimum_size . height ( ) , new_rect . height ( ) + change_h ) ) ;
new_rect . set_x ( new_rect . x ( ) - ( new_rect . x ( ) % m_grid_size ) ) ;
new_rect . set_y ( new_rect . y ( ) - ( new_rect . y ( ) % m_grid_size ) ) ;
new_rect . set_width ( new_rect . width ( ) - ( new_rect . width ( ) % m_grid_size ) + 1 ) ;
new_rect . set_height ( new_rect . height ( ) - ( new_rect . height ( ) % m_grid_size ) + 1 ) ;
widget . set_rect ( new_rect ) ;
} ) ;
2019-08-29 22:41:41 -05:00
set_cursor_type_from_grabber ( m_resize_direction ) ;
} else {
2019-09-05 19:01:54 -05:00
for ( auto & widget : m_selected_widgets ) {
2019-09-17 21:22:15 +02:00
if ( widget - > is_in_layout ( ) )
continue ;
2019-09-05 19:01:54 -05:00
auto grabber_at = widget - > grabber_at ( event . position ( ) ) ;
set_cursor_type_from_grabber ( grabber_at ) ;
if ( grabber_at ! = Direction : : None )
break ;
}
2019-04-11 01:59:07 +02:00
}
}
2019-06-29 12:06:46 +02:00
void VBForm : : load_from_file ( const String & path )
{
2020-02-02 12:34:39 +01:00
auto file = Core : : File : : construct ( path ) ;
if ( ! file - > open ( Core : : IODevice : : ReadOnly ) ) {
2020-02-02 15:07:41 +01:00
GUI : : MessageBox : : show ( String : : format ( " Could not open '%s' for reading " , path . characters ( ) ) , " Error " , GUI : : MessageBox : : Type : : Error , GUI : : MessageBox : : InputType : : OK , window ( ) ) ;
2019-06-29 12:06:46 +02:00
return ;
}
2019-09-21 20:50:06 +02:00
auto file_contents = file - > read_all ( ) ;
2019-06-29 12:06:46 +02:00
auto form_json = JsonValue : : from_string ( file_contents ) ;
if ( ! form_json . is_object ( ) ) {
2020-02-02 15:07:41 +01:00
GUI : : MessageBox : : show ( String : : format ( " Could not parse '%s' " , path . characters ( ) ) , " Error " , GUI : : MessageBox : : Type : : Error , GUI : : MessageBox : : InputType : : OK , window ( ) ) ;
2019-06-29 12:06:46 +02:00
return ;
}
m_name = form_json . as_object ( ) . get ( " name " ) . to_string ( ) ;
auto widgets = form_json . as_object ( ) . get ( " widgets " ) . as_array ( ) ;
widgets . for_each ( [ & ] ( const JsonValue & widget_value ) {
auto & widget_object = widget_value . as_object ( ) ;
auto widget_class = widget_object . get ( " class " ) . as_string ( ) ;
auto widget_type = widget_type_from_class_name ( widget_class ) ;
2019-09-17 21:00:11 +02:00
// FIXME: Construct VBWidget within the right parent..
auto vbwidget = VBWidget : : create ( widget_type , * this , nullptr ) ;
2019-06-29 12:06:46 +02:00
widget_object . for_each_member ( [ & ] ( auto & property_name , const JsonValue & property_value ) {
( void ) property_name ;
( void ) property_value ;
VBProperty & property = vbwidget - > property ( property_name ) ;
2019-08-07 21:28:07 +02:00
dbgprintf ( " Set property %s.%s to '%s' \n " , widget_class . characters ( ) , property_name . characters ( ) , property_value . to_string ( ) . characters ( ) ) ;
2019-06-29 12:06:46 +02:00
property . set_value ( property_value ) ;
} ) ;
m_widgets . append ( vbwidget ) ;
} ) ;
}
2019-05-08 04:39:42 +02:00
void VBForm : : write_to_file ( const String & path )
{
2020-02-02 12:34:39 +01:00
auto file = Core : : File : : construct ( path ) ;
if ( ! file - > open ( Core : : IODevice : : WriteOnly ) ) {
2020-02-02 15:07:41 +01:00
GUI : : MessageBox : : show ( String : : format ( " Could not open '%s' for writing " , path . characters ( ) ) , " Error " , GUI : : MessageBox : : Type : : Error , GUI : : MessageBox : : InputType : : OK , window ( ) ) ;
2019-05-08 04:39:42 +02:00
return ;
}
2019-06-17 19:50:30 +02:00
JsonObject form_object ;
form_object . set ( " name " , m_name ) ;
JsonArray widget_array ;
2019-05-08 04:39:42 +02:00
for ( auto & widget : m_widgets ) {
2019-06-17 19:50:30 +02:00
JsonObject widget_object ;
2019-06-27 13:49:26 +02:00
widget . for_each_property ( [ & ] ( auto & property ) {
2019-06-17 19:50:30 +02:00
if ( property . value ( ) . is_bool ( ) )
widget_object . set ( property . name ( ) , property . value ( ) . to_bool ( ) ) ;
2020-01-27 10:55:10 +01:00
else if ( property . value ( ) . is_i32 ( ) )
widget_object . set ( property . name ( ) , property . value ( ) . to_i32 ( ) ) ;
else if ( property . value ( ) . is_i64 ( ) )
widget_object . set ( property . name ( ) , property . value ( ) . to_i64 ( ) ) ;
2019-06-17 19:50:30 +02:00
else
widget_object . set ( property . name ( ) , property . value ( ) . to_string ( ) ) ;
2019-05-08 04:39:42 +02:00
} ) ;
2019-06-17 19:50:30 +02:00
widget_array . append ( widget_object ) ;
2019-05-08 04:39:42 +02:00
}
2019-06-17 19:50:30 +02:00
form_object . set ( " widgets " , widget_array ) ;
2019-09-21 20:50:06 +02:00
file - > write ( form_object . to_string ( ) ) ;
2019-05-08 04:39:42 +02:00
}
2019-05-07 23:28:35 +02:00
void VBForm : : dump ( )
{
dbgprintf ( " [Form] \n " ) ;
dbgprintf ( " Name=%s \n " , m_name . characters ( ) ) ;
dbgprintf ( " \n " ) ;
int i = 0 ;
for ( auto & widget : m_widgets ) {
dbgprintf ( " [Widget %d] \n " , i + + ) ;
2019-06-27 13:49:26 +02:00
widget . for_each_property ( [ ] ( auto & property ) {
2019-05-08 04:39:42 +02:00
dbgprintf ( " %s=%s \n " , property . name ( ) . characters ( ) , property . value ( ) . to_string ( ) . characters ( ) ) ;
} ) ;
2019-05-07 23:28:35 +02:00
dbgprintf ( " \n " ) ;
}
}
2020-02-02 15:07:41 +01:00
void VBForm : : mouseup_event ( GUI : : MouseEvent & event )
2019-04-11 01:59:07 +02:00
{
2020-02-02 15:07:41 +01:00
if ( event . button ( ) = = GUI : : MouseButton : : Left ) {
2019-06-07 11:48:27 +02:00
m_transform_event_origin = { } ;
2019-04-11 02:35:30 +02:00
m_resize_direction = Direction : : None ;
2019-04-11 01:59:07 +02:00
}
2019-04-11 00:05:47 +02:00
}
2019-04-19 22:46:16 +02:00
void VBForm : : delete_selected_widgets ( )
{
2019-04-19 22:52:13 +02:00
Vector < VBWidget * > to_delete ;
2019-06-07 11:48:27 +02:00
for_each_selected_widget ( [ & ] ( auto & widget ) {
2019-04-19 22:52:13 +02:00
to_delete . append ( & widget ) ;
2019-04-19 22:46:16 +02:00
} ) ;
2019-09-17 21:11:52 +02:00
if ( to_delete . is_empty ( ) )
return ;
2019-04-19 22:52:13 +02:00
for ( auto & widget : to_delete )
2019-06-07 11:48:27 +02:00
m_widgets . remove_first_matching ( [ & widget ] ( auto & entry ) { return entry = = widget ; } ) ;
2019-04-19 22:52:13 +02:00
on_widget_selected ( single_selected_widget ( ) ) ;
2019-09-17 21:11:52 +02:00
update ( ) ;
2019-04-19 22:46:16 +02:00
}
template < typename Callback >
void VBForm : : for_each_selected_widget ( Callback callback )
{
for ( auto & widget : m_selected_widgets )
callback ( * widget ) ;
}
2019-08-29 22:41:41 -05:00
void VBForm : : set_cursor_type_from_grabber ( Direction grabber )
{
if ( grabber = = m_mouse_direction_type )
return ;
switch ( grabber ) {
case Direction : : Up :
case Direction : : Down :
2020-02-02 15:07:41 +01:00
window ( ) - > set_override_cursor ( GUI : : StandardCursor : : ResizeVertical ) ;
2019-08-29 22:41:41 -05:00
break ;
case Direction : : Left :
case Direction : : Right :
2020-02-02 15:07:41 +01:00
window ( ) - > set_override_cursor ( GUI : : StandardCursor : : ResizeHorizontal ) ;
2019-08-29 22:41:41 -05:00
break ;
case Direction : : UpLeft :
case Direction : : DownRight :
2020-02-02 15:07:41 +01:00
window ( ) - > set_override_cursor ( GUI : : StandardCursor : : ResizeDiagonalTLBR ) ;
2019-08-29 22:41:41 -05:00
break ;
case Direction : : UpRight :
case Direction : : DownLeft :
2020-02-02 15:07:41 +01:00
window ( ) - > set_override_cursor ( GUI : : StandardCursor : : ResizeDiagonalBLTR ) ;
2019-08-29 22:41:41 -05:00
break ;
case Direction : : None :
2020-02-02 15:07:41 +01:00
window ( ) - > set_override_cursor ( GUI : : StandardCursor : : None ) ;
2019-08-29 22:41:41 -05:00
break ;
}
m_mouse_direction_type = grabber ;
}
2019-04-19 22:46:16 +02:00
VBWidget * VBForm : : single_selected_widget ( )
{
if ( m_selected_widgets . size ( ) ! = 1 )
return nullptr ;
return * m_selected_widgets . begin ( ) ;
}