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>
2019-06-07 11:48:27 +02:00
# include <LibCore/CFile.h>
2019-09-17 22:39:48 +02:00
# include <LibDraw/PNGLoader.h>
2019-04-12 17:10:30 +02:00
# include <LibGUI/GAction.h>
2019-09-17 21:00:11 +02:00
# include <LibGUI/GBoxLayout.h>
2019-06-07 11:48:27 +02:00
# include <LibGUI/GMenu.h>
2019-05-08 04:39:42 +02:00
# include <LibGUI/GMessageBox.h>
2019-06-07 11:48:27 +02:00
# include <LibGUI/GPainter.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 ;
}
2019-04-11 00:05:47 +02:00
VBForm : : VBForm ( const String & name , GWidget * parent )
: GWidget ( parent )
2019-04-11 03:34:37 +02:00
, 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-06-30 09:23:16 +02:00
set_background_color ( Color : : WarmGray ) ;
2019-04-11 03:34:37 +02:00
set_greedy_for_hits ( true ) ;
2019-04-11 01:59:07 +02:00
2019-12-09 21:05:28 +01:00
m_context_menu = GMenu : : construct ( ) ;
2019-09-14 22:42:02 +02:00
m_context_menu - > add_action ( GCommonActions : : 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
} ) ) ;
2019-09-14 22:42:02 +02:00
m_context_menu - > add_action ( GCommonActions : : 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 ( ) ;
2019-09-17 22:39:48 +02:00
m_context_menu - > add_action ( GAction : : create ( " Lay out horizontally " , load_png ( " /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 " ;
widget - > gwidget ( ) - > set_layout ( make < GBoxLayout > ( Orientation : : Horizontal ) ) ;
}
} ) ) ;
2019-09-17 22:39:48 +02:00
m_context_menu - > add_action ( GAction : : create ( " Lay out vertically " , load_png ( " /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 " ;
widget - > gwidget ( ) - > set_layout ( make < GBoxLayout > ( Orientation : : Vertical ) ) ;
}
} ) ) ;
m_context_menu - > add_separator ( ) ;
2019-09-14 22:32:56 +02:00
m_context_menu - > add_action ( GCommonActions : : 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
}
void VBForm : : context_menu_event ( GContextMenuEvent & event )
{
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 ) ;
Point insertion_position = m_next_insertion_position ;
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 ( )
{
}
void VBForm : : paint_event ( GPaintEvent & event )
{
GPainter painter ( * this ) ;
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
}
void VBForm : : second_paint_event ( GPaintEvent & event )
{
GPainter painter ( * this ) ;
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
}
VBWidget * VBForm : : widget_at ( const Point & position )
{
2019-09-17 21:00:11 +02:00
auto result = hit_test ( position , GWidget : : ShouldRespectGreediness : : No ) ;
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
}
2019-04-19 23:09:38 +02:00
void VBForm : : grabber_mousedown_event ( GMouseEvent & 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 ;
}
2019-04-16 23:01:37 +02:00
void VBForm : : keydown_event ( GKeyEvent & event )
{
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 ;
}
2019-04-16 23:18:26 +02:00
int selected_widget_index = 0 ;
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 ( ) ;
}
2019-04-11 01:59:07 +02:00
void VBForm : : mousedown_event ( GMouseEvent & event )
{
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 ;
}
2019-04-16 03:52:26 +02:00
if ( event . button ( ) = = GMouseButton : : Left | | event . button ( ) = = GMouseButton : : 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
}
}
void VBForm : : mousemove_event ( GMouseEvent & event )
{
2019-04-19 22:46:16 +02:00
if ( event . buttons ( ) & GMouseButton : : 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 ( ) ;
Size minimum_size { 5 , 5 } ;
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 )
{
2019-09-21 20:50:06 +02:00
auto file = CFile : : construct ( path ) ;
if ( ! file - > open ( CIODevice : : ReadOnly ) ) {
2019-07-16 21:32:10 +02:00
GMessageBox : : show ( String : : format ( " Could not open '%s' for reading " , path . characters ( ) ) , " Error " , GMessageBox : : Type : : Error , GMessageBox : : 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 ( ) ) {
2019-07-16 21:32:10 +02:00
GMessageBox : : show ( String : : format ( " Could not parse '%s' " , path . characters ( ) ) , " Error " , GMessageBox : : Type : : Error , GMessageBox : : 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 )
{
2019-09-21 20:50:06 +02:00
auto file = CFile : : construct ( path ) ;
if ( ! file - > open ( CIODevice : : WriteOnly ) ) {
2019-07-16 21:32:10 +02:00
GMessageBox : : show ( String : : format ( " Could not open '%s' for writing " , path . characters ( ) ) , " Error " , GMessageBox : : Type : : Error , GMessageBox : : 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 ( ) ) ;
else if ( property . value ( ) . is_int ( ) )
widget_object . set ( property . name ( ) , property . value ( ) . to_int ( ) ) ;
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 " ) ;
}
}
2019-04-11 01:59:07 +02:00
void VBForm : : mouseup_event ( GMouseEvent & event )
{
if ( event . button ( ) = = GMouseButton : : 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 :
window ( ) - > set_override_cursor ( GStandardCursor : : ResizeVertical ) ;
break ;
case Direction : : Left :
case Direction : : Right :
window ( ) - > set_override_cursor ( GStandardCursor : : ResizeHorizontal ) ;
break ;
case Direction : : UpLeft :
case Direction : : DownRight :
window ( ) - > set_override_cursor ( GStandardCursor : : ResizeDiagonalTLBR ) ;
break ;
case Direction : : UpRight :
case Direction : : DownLeft :
window ( ) - > set_override_cursor ( GStandardCursor : : ResizeDiagonalBLTR ) ;
break ;
case Direction : : None :
window ( ) - > set_override_cursor ( GStandardCursor : : None ) ;
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 ( ) ;
}