2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* subviewport_container.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2020-04-01 20:28:09 +02:00
# include "subviewport_container.h"
2017-03-05 15:47:28 +01:00
2020-11-07 23:33:38 +01:00
# include "core/config/engine.h"
2016-10-05 06:26:35 +02:00
# include "scene/main/viewport.h"
2020-04-01 20:28:09 +02:00
Size2 SubViewportContainer : : get_minimum_size ( ) const {
2020-05-14 16:41:43 +02:00
if ( stretch ) {
2016-10-05 06:26:35 +02:00
return Size2 ( ) ;
2020-05-14 16:41:43 +02:00
}
2016-10-05 06:26:35 +02:00
Size2 ms ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2020-03-04 02:51:12 +01:00
SubViewport * c = Object : : cast_to < SubViewport > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! c ) {
2016-10-05 06:26:35 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-10-05 06:26:35 +02:00
Size2 minsize = c - > get_size ( ) ;
2024-03-03 12:49:08 +01:00
ms = ms . max ( minsize ) ;
2016-10-05 06:26:35 +02:00
}
return ms ;
}
2020-04-01 20:28:09 +02:00
void SubViewportContainer : : set_stretch ( bool p_enable ) {
2022-03-16 08:50:48 +01:00
if ( stretch = = p_enable ) {
return ;
}
2017-03-05 16:44:50 +01:00
stretch = p_enable ;
2023-02-13 00:34:16 +01:00
recalc_force_viewport_sizes ( ) ;
2020-11-21 22:32:26 +01:00
update_minimum_size ( ) ;
2016-10-05 06:26:35 +02:00
queue_sort ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-10-05 06:26:35 +02:00
}
2020-04-01 20:28:09 +02:00
bool SubViewportContainer : : is_stretch_enabled ( ) const {
2016-10-05 06:26:35 +02:00
return stretch ;
}
2020-04-01 20:28:09 +02:00
void SubViewportContainer : : set_stretch_shrink ( int p_shrink ) {
2017-10-31 18:23:25 +01:00
ERR_FAIL_COND ( p_shrink < 1 ) ;
2020-05-14 16:41:43 +02:00
if ( shrink = = p_shrink ) {
2017-10-31 18:23:25 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-10-31 18:23:25 +01:00
shrink = p_shrink ;
2023-02-13 00:34:16 +01:00
recalc_force_viewport_sizes ( ) ;
queue_redraw ( ) ;
}
void SubViewportContainer : : recalc_force_viewport_sizes ( ) {
2020-05-14 16:41:43 +02:00
if ( ! stretch ) {
2017-10-31 18:23:25 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-10-31 18:23:25 +01:00
2023-02-13 00:34:16 +01:00
// If stretch is enabled, make sure that all child SubViwewports have the correct size.
2017-10-31 18:23:25 +01:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2020-03-04 02:51:12 +01:00
SubViewport * c = Object : : cast_to < SubViewport > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! c ) {
2017-10-31 18:23:25 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-10-31 18:23:25 +01:00
2022-10-04 21:53:18 +02:00
c - > set_size_force ( get_size ( ) / shrink ) ;
2017-10-31 18:23:25 +01:00
}
}
2020-04-01 20:28:09 +02:00
int SubViewportContainer : : get_stretch_shrink ( ) const {
2017-10-31 18:23:25 +01:00
return shrink ;
}
2021-11-08 21:53:41 +01:00
Vector < int > SubViewportContainer : : get_allowed_size_flags_horizontal ( ) const {
return Vector < int > ( ) ;
}
Vector < int > SubViewportContainer : : get_allowed_size_flags_vertical ( ) const {
return Vector < int > ( ) ;
}
2020-04-01 20:28:09 +02:00
void SubViewportContainer : : _notification ( int p_what ) {
2022-02-15 18:06:48 +01:00
switch ( p_what ) {
case NOTIFICATION_RESIZED : {
2023-02-13 00:34:16 +01:00
recalc_force_viewport_sizes ( ) ;
2022-02-15 18:06:48 +01:00
} break ;
case NOTIFICATION_ENTER_TREE :
case NOTIFICATION_VISIBILITY_CHANGED : {
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
SubViewport * c = Object : : cast_to < SubViewport > ( get_child ( i ) ) ;
if ( ! c ) {
continue ;
}
if ( is_visible_in_tree ( ) ) {
c - > set_update_mode ( SubViewport : : UPDATE_ALWAYS ) ;
} else {
c - > set_update_mode ( SubViewport : : UPDATE_DISABLED ) ;
}
c - > set_handle_input_locally ( false ) ; //do not handle input locally here
2020-05-14 16:41:43 +02:00
}
2022-02-15 18:06:48 +01:00
} break ;
case NOTIFICATION_DRAW : {
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
SubViewport * c = Object : : cast_to < SubViewport > ( get_child ( i ) ) ;
if ( ! c ) {
continue ;
}
if ( stretch ) {
draw_texture_rect ( c - > get_texture ( ) , Rect2 ( Vector2 ( ) , get_size ( ) ) ) ;
} else {
draw_texture_rect ( c - > get_texture ( ) , Rect2 ( Vector2 ( ) , c - > get_size ( ) ) ) ;
}
2020-05-14 16:41:43 +02:00
}
2022-02-15 18:06:48 +01:00
} break ;
2022-02-15 22:14:39 +01:00
2023-07-09 19:23:19 +02:00
case NOTIFICATION_FOCUS_ENTER : {
// If focused, send InputEvent to the SubViewport before the Gui-Input stage.
set_process_input ( true ) ;
set_process_unhandled_input ( false ) ;
} break ;
case NOTIFICATION_FOCUS_EXIT : {
// A different Control has focus and should receive Gui-Input before the InputEvent is sent to the SubViewport.
set_process_input ( false ) ;
set_process_unhandled_input ( true ) ;
} break ;
2022-02-15 22:14:39 +01:00
}
}
void SubViewportContainer : : _notify_viewports ( int p_notification ) {
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
SubViewport * c = Object : : cast_to < SubViewport > ( get_child ( i ) ) ;
if ( ! c ) {
continue ;
}
c - > notification ( p_notification ) ;
2016-10-05 06:26:35 +02:00
}
}
2021-08-22 17:37:22 +02:00
void SubViewportContainer : : input ( const Ref < InputEvent > & p_event ) {
2023-07-09 19:23:19 +02:00
_propagate_nonpositional_event ( p_event ) ;
}
void SubViewportContainer : : unhandled_input ( const Ref < InputEvent > & p_event ) {
_propagate_nonpositional_event ( p_event ) ;
}
void SubViewportContainer : : _propagate_nonpositional_event ( const Ref < InputEvent > & p_event ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2018-01-15 00:36:57 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-01-15 00:36:57 +01:00
2022-03-31 12:01:04 +02:00
if ( _is_propagated_in_gui_input ( p_event ) ) {
return ;
}
2018-01-15 00:36:57 +01:00
2023-06-27 20:05:39 +02:00
bool send ;
if ( GDVIRTUAL_CALL ( _propagate_input_event , p_event , send ) ) {
if ( ! send ) {
return ;
}
}
2022-03-31 12:01:04 +02:00
_send_event_to_viewports ( p_event ) ;
}
void SubViewportContainer : : gui_input ( const Ref < InputEvent > & p_event ) {
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
return ;
2018-01-15 00:36:57 +01:00
}
2022-03-31 12:01:04 +02:00
if ( ! _is_propagated_in_gui_input ( p_event ) ) {
return ;
}
2018-01-15 00:36:57 +01:00
2023-06-27 20:05:39 +02:00
bool send ;
if ( GDVIRTUAL_CALL ( _propagate_input_event , p_event , send ) ) {
if ( ! send ) {
return ;
}
}
2022-03-31 12:01:04 +02:00
if ( stretch & & shrink > 1 ) {
Transform2D xform ;
xform . scale ( Vector2 ( 1 , 1 ) / shrink ) ;
_send_event_to_viewports ( p_event - > xformed_by ( xform ) ) ;
} else {
_send_event_to_viewports ( p_event ) ;
}
}
2018-01-15 00:36:57 +01:00
2022-03-31 12:01:04 +02:00
void SubViewportContainer : : _send_event_to_viewports ( const Ref < InputEvent > & p_event ) {
2018-01-15 00:36:57 +01:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2020-03-04 02:51:12 +01:00
SubViewport * c = Object : : cast_to < SubViewport > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! c | | c - > is_input_disabled ( ) ) {
2018-01-15 00:36:57 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-01-15 00:36:57 +01:00
2022-03-31 12:01:04 +02:00
c - > push_input ( p_event ) ;
}
}
bool SubViewportContainer : : _is_propagated_in_gui_input ( const Ref < InputEvent > & p_event ) {
// Propagation of events with a position property happen in gui_input
// Propagation of other events happen in input
if ( Object : : cast_to < InputEventMouse > ( * p_event ) | | Object : : cast_to < InputEventScreenDrag > ( * p_event ) | | Object : : cast_to < InputEventScreenTouch > ( * p_event ) | | Object : : cast_to < InputEventGesture > ( * p_event ) ) {
return true ;
2018-01-15 00:36:57 +01:00
}
2022-03-31 12:01:04 +02:00
return false ;
2018-01-15 00:36:57 +01:00
}
2022-11-23 14:13:07 +01:00
void SubViewportContainer : : add_child_notify ( Node * p_child ) {
if ( Object : : cast_to < SubViewport > ( p_child ) ) {
queue_redraw ( ) ;
}
}
void SubViewportContainer : : remove_child_notify ( Node * p_child ) {
if ( Object : : cast_to < SubViewport > ( p_child ) ) {
queue_redraw ( ) ;
}
}
2024-02-17 19:03:21 +01:00
PackedStringArray SubViewportContainer : : get_configuration_warnings ( ) const {
PackedStringArray warnings = Node : : get_configuration_warnings ( ) ;
2022-03-26 19:33:54 +01:00
bool has_viewport = false ;
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
if ( Object : : cast_to < SubViewport > ( get_child ( i ) ) ) {
has_viewport = true ;
break ;
}
}
if ( ! has_viewport ) {
2022-03-28 15:24:14 +02:00
warnings . push_back ( RTR ( " This node doesn't have a SubViewport as child, so it can't display its intended content. \n Consider adding a SubViewport as a child to provide something displayable. " ) ) ;
2022-03-26 19:33:54 +01:00
}
2023-07-23 02:14:41 +02:00
if ( get_default_cursor_shape ( ) ! = Control : : CURSOR_ARROW ) {
warnings . push_back ( RTR ( " The default mouse cursor shape of SubViewportContainer has no effect. \n Consider leaving it at its initial value `CURSOR_ARROW`. " ) ) ;
}
2022-03-26 19:33:54 +01:00
return warnings ;
}
2020-04-01 20:28:09 +02:00
void SubViewportContainer : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " set_stretch " , " enable " ) , & SubViewportContainer : : set_stretch ) ;
ClassDB : : bind_method ( D_METHOD ( " is_stretch_enabled " ) , & SubViewportContainer : : is_stretch_enabled ) ;
2016-10-05 06:26:35 +02:00
2020-04-01 20:28:09 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_stretch_shrink " , " amount " ) , & SubViewportContainer : : set_stretch_shrink ) ;
ClassDB : : bind_method ( D_METHOD ( " get_stretch_shrink " ) , & SubViewportContainer : : get_stretch_shrink ) ;
2017-10-31 18:23:25 +01:00
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " stretch " ) , " set_stretch " , " is_stretch_enabled " ) ;
2024-05-29 03:03:15 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " stretch_shrink " , PROPERTY_HINT_RANGE , " 1,32,1,or_greater " ) , " set_stretch_shrink " , " get_stretch_shrink " ) ;
2023-06-27 20:05:39 +02:00
GDVIRTUAL_BIND ( _propagate_input_event , " event " ) ;
2016-10-05 06:26:35 +02:00
}
2020-04-01 20:28:09 +02:00
SubViewportContainer : : SubViewportContainer ( ) {
2023-07-09 19:23:19 +02:00
set_process_unhandled_input ( true ) ;
set_focus_mode ( FOCUS_CLICK ) ;
2016-10-05 06:26:35 +02:00
}