2013-04-21 11:51:14 +00:00
/*
* Copyright ( c ) 2013 Red Hat , Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU Lesser General Public
* License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* Author : Alexander Larsson < alexl @ redhat . com >
*
*/
# include "config.h"
# include <gtk/gtk.h>
# include "gtkstack.h"
# include "gtkprivate.h"
# include "gtkintl.h"
2016-03-01 06:24:39 +00:00
# include "gtkprogresstrackerprivate.h"
2016-05-01 04:39:55 +00:00
# include "gtksettingsprivate.h"
2018-03-11 05:29:46 +00:00
# include "gtksnapshot.h"
2015-12-09 04:03:38 +00:00
# include "gtkwidgetprivate.h"
2019-02-10 23:22:54 +00:00
# include "gtksingleselection.h"
# include "gtklistlistmodelprivate.h"
2016-05-29 11:51:02 +00:00
# include "a11y/gtkstackaccessible.h"
# include "a11y/gtkstackaccessibleprivate.h"
2013-04-21 11:51:14 +00:00
# include <math.h>
# include <string.h>
2013-04-21 14:14:46 +00:00
/**
* SECTION : gtkstack
* @ Short_description : A stacking container
* @ Title : GtkStack
* @ See_also : # GtkNotebook , # GtkStackSwitcher
*
* The GtkStack widget is a container which only shows
* one of its children at a time . In contrast to GtkNotebook ,
2013-04-25 02:07:09 +00:00
* GtkStack does not provide a means for users to change the
* visible child . Instead , the # GtkStackSwitcher widget can be
* used with GtkStack to provide this functionality .
2013-04-21 14:14:46 +00:00
*
* Transitions between pages can be animated as slides or
* fades . This can be controlled with gtk_stack_set_transition_type ( ) .
2014-01-22 01:58:13 +00:00
* These animations respect the # GtkSettings : gtk - enable - animations
2013-04-21 14:14:46 +00:00
* setting .
*
2019-02-06 17:54:18 +00:00
* GtkStack maintains a # GtkStackPage object for each added
* child , which holds additional per - child properties . You
* obtain the # GtkStackPage for a child with gtk_stack_get_page ( ) .
2015-11-04 04:19:28 +00:00
*
2019-02-06 17:54:18 +00:00
* # GtkStack as GtkBuildable
*
* To set child - specific properties in a . ui file , create GtkStackPage
2020-05-28 08:00:03 +00:00
* objects explicitly , and set the child widget as a property on it :
2019-02-06 17:54:18 +00:00
* | [
* < object class = " GtkStack " id = " stack " >
* < child >
* < object class = " GtkStackPage " >
* < property name = " name " > page1 < / property >
* < property name = " title " > In the beginning … < / property >
* < property name = " child " >
* < object class = " GtkLabel " >
* < property name = " label " > It was dark < / property >
* < / object >
* < / property >
* < / object >
* < / child >
* ] |
2020-06-18 05:55:22 +00:00
*
2015-11-04 04:19:28 +00:00
* # CSS nodes
*
* GtkStack has a single CSS node named stack .
2013-04-21 14:14:46 +00:00
*/
/**
* GtkStackTransitionType :
* @ GTK_STACK_TRANSITION_TYPE_NONE : No transition
* @ GTK_STACK_TRANSITION_TYPE_CROSSFADE : A cross - fade
2013-04-22 00:17:40 +00:00
* @ GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT : Slide from left to right
* @ GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT : Slide from right to left
* @ GTK_STACK_TRANSITION_TYPE_SLIDE_UP : Slide from bottom up
* @ GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN : Slide from top down
2013-06-13 18:33:42 +00:00
* @ GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT : Slide from left or right according to the children order
* @ GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN : Slide from top down or bottom up according to the order
2018-02-05 19:13:20 +00:00
* @ GTK_STACK_TRANSITION_TYPE_OVER_UP : Cover the old page by sliding up
* @ GTK_STACK_TRANSITION_TYPE_OVER_DOWN : Cover the old page by sliding down
* @ GTK_STACK_TRANSITION_TYPE_OVER_LEFT : Cover the old page by sliding to the left
* @ GTK_STACK_TRANSITION_TYPE_OVER_RIGHT : Cover the old page by sliding to the right
* @ GTK_STACK_TRANSITION_TYPE_UNDER_UP : Uncover the new page by sliding up
* @ GTK_STACK_TRANSITION_TYPE_UNDER_DOWN : Uncover the new page by sliding down
* @ GTK_STACK_TRANSITION_TYPE_UNDER_LEFT : Uncover the new page by sliding to the left
* @ GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT : Uncover the new page by sliding to the right
* @ GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN : Cover the old page sliding up or uncover the new page sliding down , according to order
* @ GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP : Cover the old page sliding down or uncover the new page sliding up , according to order
* @ GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT : Cover the old page sliding left or uncover the new page sliding right , according to order
* @ GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT : Cover the old page sliding right or uncover the new page sliding left , according to order
2019-03-05 19:44:45 +00:00
* @ GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT : Pretend the pages are sides of a cube and rotate that cube to the left
* @ GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT : Pretend the pages are sides of a cube and rotate that cube to the right
* @ GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT_RIGHT : Pretend the pages are sides of a cube and rotate that cube to the left or right according to the children order
2013-04-21 14:14:46 +00:00
*
* These enumeration values describe the possible transitions
* between pages in a # GtkStack widget .
2013-08-31 16:00:47 +00:00
*
* New values may be added to this enumeration over time .
2013-04-21 14:14:46 +00:00
*/
2013-04-21 11:51:14 +00:00
/* TODO:
* filter events out events to the last_child widget during transitions
*/
2019-05-28 22:35:07 +00:00
struct _GtkStack {
2020-05-07 20:04:42 +00:00
GtkWidget parent_instance ;
2019-05-28 22:35:07 +00:00
} ;
typedef struct _GtkStackClass GtkStackClass ;
struct _GtkStackClass {
2020-05-07 20:04:42 +00:00
GtkWidgetClass parent_class ;
2019-05-28 22:35:07 +00:00
} ;
2019-02-06 17:54:18 +00:00
typedef struct {
GList * children ;
GtkStackPage * visible_child ;
gboolean hhomogeneous ;
gboolean vhomogeneous ;
GtkStackTransitionType transition_type ;
guint transition_duration ;
GtkStackPage * last_visible_child ;
guint tick_id ;
GtkProgressTracker tracker ;
gboolean first_frame_skipped ;
gint last_visible_widget_width ;
gint last_visible_widget_height ;
gboolean interpolate_size ;
GtkStackTransitionType active_transition_type ;
2019-02-10 23:22:54 +00:00
GtkSelectionModel * pages ;
2019-02-06 17:54:18 +00:00
} GtkStackPrivate ;
static void gtk_stack_buildable_interface_init ( GtkBuildableIface * iface ) ;
2020-05-07 20:04:42 +00:00
G_DEFINE_TYPE_WITH_CODE ( GtkStack , gtk_stack , GTK_TYPE_WIDGET ,
2019-02-06 17:54:18 +00:00
G_ADD_PRIVATE ( GtkStack )
G_IMPLEMENT_INTERFACE ( GTK_TYPE_BUILDABLE ,
gtk_stack_buildable_interface_init ) )
2013-04-21 11:51:14 +00:00
enum {
PROP_0 ,
2014-10-26 18:59:21 +00:00
PROP_HHOMOGENEOUS ,
PROP_VHOMOGENEOUS ,
2013-04-21 11:51:14 +00:00
PROP_VISIBLE_CHILD ,
PROP_VISIBLE_CHILD_NAME ,
PROP_TRANSITION_DURATION ,
2013-11-05 10:11:35 +00:00
PROP_TRANSITION_TYPE ,
2013-11-11 21:38:35 +00:00
PROP_TRANSITION_RUNNING ,
2015-07-19 15:39:41 +00:00
PROP_INTERPOLATE_SIZE ,
2019-02-13 19:14:54 +00:00
PROP_PAGES ,
2013-11-05 10:11:35 +00:00
LAST_PROP
2013-04-21 11:51:14 +00:00
} ;
enum
{
CHILD_PROP_0 ,
2019-02-06 17:54:18 +00:00
CHILD_PROP_CHILD ,
2013-04-21 11:51:14 +00:00
CHILD_PROP_NAME ,
CHILD_PROP_TITLE ,
CHILD_PROP_ICON_NAME ,
2015-09-07 22:53:25 +00:00
CHILD_PROP_NEEDS_ATTENTION ,
2019-02-10 23:13:03 +00:00
CHILD_PROP_VISIBLE ,
2020-04-30 23:17:34 +00:00
CHILD_PROP_USE_UNDERLINE ,
2015-09-07 22:53:25 +00:00
LAST_CHILD_PROP
2013-04-21 11:51:14 +00:00
} ;
2020-02-18 08:27:42 +00:00
struct _GtkStackPage
{
GObject parent_instance ;
2013-04-21 11:51:14 +00:00
GtkWidget * widget ;
2020-02-18 08:27:42 +00:00
char * name ;
char * title ;
char * icon_name ;
2014-12-11 03:32:45 +00:00
GtkWidget * last_focus ;
2020-04-30 23:17:34 +00:00
guint needs_attention : 1 ;
guint visible : 1 ;
guint use_underline : 1 ;
2013-04-21 11:51:14 +00:00
} ;
2019-05-28 22:35:07 +00:00
typedef struct _GtkStackPageClass GtkStackPageClass ;
2020-02-18 08:27:42 +00:00
struct _GtkStackPageClass
{
2019-02-06 17:54:18 +00:00
GObjectClass parent_class ;
} ;
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
static GParamSpec * stack_props [ LAST_PROP ] = { NULL , } ;
2020-06-18 05:55:22 +00:00
static GParamSpec * stack_page_props [ LAST_CHILD_PROP ] = { NULL , } ;
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
G_DEFINE_TYPE ( GtkStackPage , gtk_stack_page , G_TYPE_OBJECT )
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
static void
gtk_stack_page_init ( GtkStackPage * page )
{
2019-02-10 23:13:03 +00:00
page - > visible = TRUE ;
2019-02-06 17:54:18 +00:00
}
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
static void
gtk_stack_page_finalize ( GObject * object )
{
GtkStackPage * page = GTK_STACK_PAGE ( object ) ;
2013-04-21 18:22:35 +00:00
2019-02-06 17:54:18 +00:00
g_clear_object ( & page - > widget ) ;
g_free ( page - > name ) ;
g_free ( page - > title ) ;
g_free ( page - > icon_name ) ;
2015-05-24 14:55:34 +00:00
2019-02-06 17:54:18 +00:00
if ( page - > last_focus )
g_object_remove_weak_pointer ( G_OBJECT ( page - > last_focus ) ,
( gpointer * ) & page - > last_focus ) ;
2015-07-19 15:39:41 +00:00
2019-02-06 17:54:18 +00:00
G_OBJECT_CLASS ( gtk_stack_page_parent_class ) - > finalize ( object ) ;
}
2014-02-16 21:22:59 +00:00
2019-02-06 17:54:18 +00:00
static void
gtk_stack_page_get_property ( GObject * object ,
guint property_id ,
GValue * value ,
GParamSpec * pspec )
{
GtkStackPage * info = GTK_STACK_PAGE ( object ) ;
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
switch ( property_id )
{
case CHILD_PROP_CHILD :
g_value_set_object ( value , info - > widget ) ;
break ;
case CHILD_PROP_NAME :
2020-06-18 05:55:22 +00:00
g_value_set_string ( value , gtk_stack_page_get_name ( info ) ) ;
2019-02-06 17:54:18 +00:00
break ;
case CHILD_PROP_TITLE :
2020-06-18 05:55:22 +00:00
g_value_set_string ( value , gtk_stack_page_get_title ( info ) ) ;
2019-02-06 17:54:18 +00:00
break ;
case CHILD_PROP_ICON_NAME :
2020-06-18 05:55:22 +00:00
g_value_set_string ( value , gtk_stack_page_get_icon_name ( info ) ) ;
2019-02-06 17:54:18 +00:00
break ;
case CHILD_PROP_NEEDS_ATTENTION :
2020-06-18 05:55:22 +00:00
g_value_set_boolean ( value , gtk_stack_page_get_needs_attention ( info ) ) ;
2019-02-06 17:54:18 +00:00
break ;
2019-02-10 23:13:03 +00:00
case CHILD_PROP_VISIBLE :
2020-02-18 08:27:42 +00:00
g_value_set_boolean ( value , gtk_stack_page_get_visible ( info ) ) ;
2019-02-10 23:13:03 +00:00
break ;
2020-04-30 23:17:34 +00:00
case CHILD_PROP_USE_UNDERLINE :
2020-06-18 05:55:22 +00:00
g_value_set_boolean ( value , gtk_stack_page_get_use_underline ( info ) ) ;
2020-04-30 23:17:34 +00:00
break ;
2019-02-06 17:54:18 +00:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
gtk_stack_page_set_property ( GObject * object ,
guint property_id ,
const GValue * value ,
GParamSpec * pspec )
{
GtkStackPage * info = GTK_STACK_PAGE ( object ) ;
switch ( property_id )
{
case CHILD_PROP_CHILD :
g_set_object ( & info - > widget , g_value_get_object ( value ) ) ;
break ;
case CHILD_PROP_NAME :
2020-06-18 05:55:22 +00:00
gtk_stack_page_set_name ( info , g_value_get_string ( value ) ) ;
2019-02-06 17:54:18 +00:00
break ;
case CHILD_PROP_TITLE :
2020-06-18 05:55:22 +00:00
gtk_stack_page_set_title ( info , g_value_get_string ( value ) ) ;
2019-02-06 17:54:18 +00:00
break ;
case CHILD_PROP_ICON_NAME :
2020-06-18 05:55:22 +00:00
gtk_stack_page_set_icon_name ( info , g_value_get_string ( value ) ) ;
2019-02-06 17:54:18 +00:00
break ;
case CHILD_PROP_NEEDS_ATTENTION :
2020-06-18 05:55:22 +00:00
gtk_stack_page_set_needs_attention ( info , g_value_get_boolean ( value ) ) ;
2019-02-06 17:54:18 +00:00
break ;
2019-02-10 23:13:03 +00:00
case CHILD_PROP_VISIBLE :
2020-02-18 08:27:42 +00:00
gtk_stack_page_set_visible ( info , g_value_get_boolean ( value ) ) ;
2019-02-10 23:13:03 +00:00
break ;
2020-04-30 23:17:34 +00:00
case CHILD_PROP_USE_UNDERLINE :
2020-06-18 05:55:22 +00:00
gtk_stack_page_set_use_underline ( info , g_value_get_boolean ( value ) ) ;
2020-04-30 23:17:34 +00:00
break ;
2019-02-06 17:54:18 +00:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
gtk_stack_page_class_init ( GtkStackPageClass * class )
{
GObjectClass * object_class = G_OBJECT_CLASS ( class ) ;
object_class - > finalize = gtk_stack_page_finalize ;
object_class - > get_property = gtk_stack_page_get_property ;
object_class - > set_property = gtk_stack_page_set_property ;
2020-06-18 05:55:22 +00:00
stack_page_props [ CHILD_PROP_CHILD ] =
2019-02-06 17:54:18 +00:00
g_param_spec_object ( " child " ,
P_ ( " Child " ) ,
P_ ( " The child of the page " ) ,
GTK_TYPE_WIDGET ,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ) ;
2020-06-18 05:55:22 +00:00
stack_page_props [ CHILD_PROP_NAME ] =
2019-02-06 17:54:18 +00:00
g_param_spec_string ( " name " ,
P_ ( " Name " ) ,
P_ ( " The name of the child page " ) ,
NULL ,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ) ;
2020-06-18 05:55:22 +00:00
stack_page_props [ CHILD_PROP_TITLE ] =
2019-02-06 17:54:18 +00:00
g_param_spec_string ( " title " ,
P_ ( " Title " ) ,
P_ ( " The title of the child page " ) ,
NULL ,
GTK_PARAM_READWRITE ) ;
2020-06-18 05:55:22 +00:00
stack_page_props [ CHILD_PROP_ICON_NAME ] =
2019-02-06 17:54:18 +00:00
g_param_spec_string ( " icon-name " ,
P_ ( " Icon name " ) ,
P_ ( " The icon name of the child page " ) ,
NULL ,
GTK_PARAM_READWRITE ) ;
/**
2020-06-13 19:25:21 +00:00
* GtkStackPage : needs - attention :
2019-02-06 17:54:18 +00:00
*
2020-06-13 19:25:21 +00:00
* Sets a flag specifying whether the oage requires the user attention .
2019-02-06 17:54:18 +00:00
* This is used by the # GtkStackSwitcher to change the appearance of the
* corresponding button when a page needs attention and it is not the
* current one .
*/
2020-06-18 05:55:22 +00:00
stack_page_props [ CHILD_PROP_NEEDS_ATTENTION ] =
2019-02-06 17:54:18 +00:00
g_param_spec_boolean ( " needs-attention " ,
P_ ( " Needs Attention " ) ,
P_ ( " Whether this page needs attention " ) ,
FALSE ,
2019-02-08 14:03:45 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2019-02-06 17:54:18 +00:00
2020-06-18 05:55:22 +00:00
stack_page_props [ CHILD_PROP_VISIBLE ] =
2019-02-10 23:13:03 +00:00
g_param_spec_boolean ( " visible " ,
P_ ( " Visible " ) ,
P_ ( " Whether this page is visible " ) ,
TRUE ,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2020-06-18 05:55:22 +00:00
stack_page_props [ CHILD_PROP_USE_UNDERLINE ] =
2020-04-30 23:17:34 +00:00
g_param_spec_boolean ( " use-underline " ,
P_ ( " Use underline " ) ,
P_ ( " If set, an underline in the title indicates the next character should be used for the mnemonic accelerator key " ) ,
FALSE ,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2020-06-18 05:55:22 +00:00
g_object_class_install_properties ( object_class , LAST_CHILD_PROP , stack_page_props ) ;
2019-02-06 17:54:18 +00:00
}
2013-11-05 10:11:35 +00:00
2019-02-10 23:22:54 +00:00
# define GTK_TYPE_STACK_PAGES (gtk_stack_pages_get_type ())
G_DECLARE_FINAL_TYPE ( GtkStackPages , gtk_stack_pages , GTK , STACK_PAGES , GObject )
struct _GtkStackPages
{
GObject parent_instance ;
GtkStack * stack ;
} ;
struct _GtkStackPagesClass
{
GObjectClass parent_class ;
} ;
static GType
gtk_stack_pages_get_item_type ( GListModel * model )
{
return GTK_TYPE_STACK_PAGE ;
}
static guint
gtk_stack_pages_get_n_items ( GListModel * model )
{
GtkStackPages * pages = GTK_STACK_PAGES ( model ) ;
GtkStackPrivate * priv = gtk_stack_get_instance_private ( pages - > stack ) ;
return g_list_length ( priv - > children ) ;
}
static gpointer
gtk_stack_pages_get_item ( GListModel * model ,
guint position )
{
GtkStackPages * pages = GTK_STACK_PAGES ( model ) ;
GtkStackPrivate * priv = gtk_stack_get_instance_private ( pages - > stack ) ;
GtkStackPage * page ;
page = g_list_nth_data ( priv - > children , position ) ;
return g_object_ref ( page ) ;
}
static void
gtk_stack_pages_list_model_init ( GListModelInterface * iface )
{
iface - > get_item_type = gtk_stack_pages_get_item_type ;
iface - > get_n_items = gtk_stack_pages_get_n_items ;
iface - > get_item = gtk_stack_pages_get_item ;
}
static gboolean
gtk_stack_pages_is_selected ( GtkSelectionModel * model ,
guint position )
{
GtkStackPages * pages = GTK_STACK_PAGES ( model ) ;
GtkStackPrivate * priv = gtk_stack_get_instance_private ( pages - > stack ) ;
GtkStackPage * page ;
2019-02-13 13:40:13 +00:00
page = g_list_nth_data ( priv - > children , position ) ;
2019-02-10 23:22:54 +00:00
return page = = priv - > visible_child ;
}
static void set_visible_child ( GtkStack * stack ,
GtkStackPage * child_info ,
GtkStackTransitionType transition_type ,
guint transition_duration ) ;
static gboolean
gtk_stack_pages_select_item ( GtkSelectionModel * model ,
guint position ,
gboolean exclusive )
{
GtkStackPages * pages = GTK_STACK_PAGES ( model ) ;
GtkStackPrivate * priv = gtk_stack_get_instance_private ( pages - > stack ) ;
GtkStackPage * page ;
2019-02-13 13:40:13 +00:00
page = g_list_nth_data ( priv - > children , position ) ;
2019-02-10 23:22:54 +00:00
set_visible_child ( pages - > stack , page , priv - > transition_type , priv - > transition_duration ) ;
return TRUE ;
}
static void
gtk_stack_pages_selection_model_init ( GtkSelectionModelInterface * iface )
{
iface - > is_selected = gtk_stack_pages_is_selected ;
iface - > select_item = gtk_stack_pages_select_item ;
}
G_DEFINE_TYPE_WITH_CODE ( GtkStackPages , gtk_stack_pages , G_TYPE_OBJECT ,
G_IMPLEMENT_INTERFACE ( G_TYPE_LIST_MODEL , gtk_stack_pages_list_model_init )
G_IMPLEMENT_INTERFACE ( GTK_TYPE_SELECTION_MODEL , gtk_stack_pages_selection_model_init ) )
static void
gtk_stack_pages_init ( GtkStackPages * pages )
{
}
static void
gtk_stack_pages_class_init ( GtkStackPagesClass * class )
{
}
static GtkStackPages *
gtk_stack_pages_new ( GtkStack * stack )
{
GtkStackPages * pages ;
pages = g_object_new ( GTK_TYPE_STACK_PAGES , NULL ) ;
pages - > stack = stack ;
return pages ;
}
2020-05-07 20:04:42 +00:00
static GtkStackPage * gtk_stack_add_internal ( GtkStack * stack ,
GtkWidget * child ,
const char * name ,
const char * title ) ;
static GtkSizeRequestMode gtk_stack_get_request_mode ( GtkWidget * widget ) ;
2013-04-21 11:51:14 +00:00
static void gtk_stack_compute_expand ( GtkWidget * widget ,
gboolean * hexpand ,
gboolean * vexpand ) ;
2018-08-16 04:53:03 +00:00
static void gtk_stack_size_allocate ( GtkWidget * widget ,
int width ,
int height ,
int baseline ) ;
2016-12-13 08:45:09 +00:00
static void gtk_stack_snapshot ( GtkWidget * widget ,
GtkSnapshot * snapshot ) ;
2017-05-05 15:18:15 +00:00
static void gtk_stack_measure ( GtkWidget * widget ,
2016-10-22 14:06:14 +00:00
GtkOrientation orientation ,
int for_size ,
int * minimum ,
int * natural ,
int * minimum_baseline ,
int * natural_baseline ) ;
2019-02-10 23:22:54 +00:00
static void gtk_stack_dispose ( GObject * obj ) ;
2013-04-21 11:51:14 +00:00
static void gtk_stack_finalize ( GObject * obj ) ;
static void gtk_stack_get_property ( GObject * object ,
guint property_id ,
GValue * value ,
GParamSpec * pspec ) ;
static void gtk_stack_set_property ( GObject * object ,
guint property_id ,
const GValue * value ,
GParamSpec * pspec ) ;
static void gtk_stack_unschedule_ticks ( GtkStack * stack ) ;
2019-02-06 17:54:18 +00:00
static void gtk_stack_add_page ( GtkStack * stack ,
GtkStackPage * page ) ;
2020-05-07 20:04:42 +00:00
static GtkBuildableIface * parent_buildable_iface ;
2019-02-06 17:54:18 +00:00
static void
gtk_stack_buildable_add_child ( GtkBuildable * buildable ,
GtkBuilder * builder ,
GObject * child ,
const char * type )
{
if ( GTK_IS_STACK_PAGE ( child ) )
gtk_stack_add_page ( GTK_STACK ( buildable ) , GTK_STACK_PAGE ( child ) ) ;
else if ( GTK_IS_WIDGET ( child ) )
2020-05-07 20:04:42 +00:00
gtk_stack_add_internal ( GTK_STACK ( buildable ) , GTK_WIDGET ( child ) , NULL , NULL ) ;
2019-02-06 17:54:18 +00:00
else
2020-05-07 20:04:42 +00:00
parent_buildable_iface - > add_child ( buildable , builder , child , type ) ;
2019-02-06 17:54:18 +00:00
}
static void
gtk_stack_buildable_interface_init ( GtkBuildableIface * iface )
{
2020-05-07 20:04:42 +00:00
parent_buildable_iface = g_type_interface_peek_parent ( iface ) ;
2019-02-06 17:54:18 +00:00
iface - > add_child = gtk_stack_buildable_add_child ;
}
2013-04-21 11:51:14 +00:00
2019-02-10 23:22:54 +00:00
static void stack_remove ( GtkStack * stack ,
GtkWidget * child ,
gboolean in_dispose ) ;
static void
gtk_stack_dispose ( GObject * obj )
{
GtkStack * stack = GTK_STACK ( obj ) ;
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2020-05-07 20:04:42 +00:00
GtkWidget * child ;
2019-02-10 23:22:54 +00:00
if ( priv - > pages )
g_list_model_items_changed ( G_LIST_MODEL ( priv - > pages ) , 0 , g_list_length ( priv - > children ) , 0 ) ;
2019-02-14 17:24:22 +00:00
2020-05-07 20:04:42 +00:00
while ( ( child = gtk_widget_get_first_child ( GTK_WIDGET ( stack ) ) ) )
stack_remove ( stack , child , TRUE ) ;
2019-02-10 23:22:54 +00:00
G_OBJECT_CLASS ( gtk_stack_parent_class ) - > dispose ( obj ) ;
}
2013-04-21 11:51:14 +00:00
static void
gtk_stack_finalize ( GObject * obj )
{
GtkStack * stack = GTK_STACK ( obj ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2019-02-14 17:24:22 +00:00
if ( priv - > pages )
g_object_remove_weak_pointer ( G_OBJECT ( priv - > pages ) , ( gpointer * ) & priv - > pages ) ;
2013-04-21 11:51:14 +00:00
gtk_stack_unschedule_ticks ( stack ) ;
G_OBJECT_CLASS ( gtk_stack_parent_class ) - > finalize ( obj ) ;
}
static void
gtk_stack_get_property ( GObject * object ,
2014-10-26 18:59:21 +00:00
guint property_id ,
GValue * value ,
GParamSpec * pspec )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( object ) ;
switch ( property_id )
{
2014-10-26 18:59:21 +00:00
case PROP_HHOMOGENEOUS :
g_value_set_boolean ( value , gtk_stack_get_hhomogeneous ( stack ) ) ;
break ;
case PROP_VHOMOGENEOUS :
g_value_set_boolean ( value , gtk_stack_get_vhomogeneous ( stack ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_VISIBLE_CHILD :
2013-11-25 01:39:13 +00:00
g_value_set_object ( value , gtk_stack_get_visible_child ( stack ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_VISIBLE_CHILD_NAME :
g_value_set_string ( value , gtk_stack_get_visible_child_name ( stack ) ) ;
break ;
case PROP_TRANSITION_DURATION :
2013-04-22 01:31:29 +00:00
g_value_set_uint ( value , gtk_stack_get_transition_duration ( stack ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_TRANSITION_TYPE :
2013-04-22 01:16:46 +00:00
g_value_set_enum ( value , gtk_stack_get_transition_type ( stack ) ) ;
2013-04-21 11:51:14 +00:00
break ;
2013-11-11 21:38:35 +00:00
case PROP_TRANSITION_RUNNING :
g_value_set_boolean ( value , gtk_stack_get_transition_running ( stack ) ) ;
break ;
2015-07-19 15:39:41 +00:00
case PROP_INTERPOLATE_SIZE :
g_value_set_boolean ( value , gtk_stack_get_interpolate_size ( stack ) ) ;
break ;
2019-02-13 19:14:54 +00:00
case PROP_PAGES :
g_value_set_object ( value , gtk_stack_get_pages ( stack ) ) ;
break ;
2013-04-21 11:51:14 +00:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
gtk_stack_set_property ( GObject * object ,
2014-10-26 18:59:21 +00:00
guint property_id ,
const GValue * value ,
GParamSpec * pspec )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( object ) ;
switch ( property_id )
{
2014-10-26 18:59:21 +00:00
case PROP_HHOMOGENEOUS :
gtk_stack_set_hhomogeneous ( stack , g_value_get_boolean ( value ) ) ;
break ;
case PROP_VHOMOGENEOUS :
gtk_stack_set_vhomogeneous ( stack , g_value_get_boolean ( value ) ) ;
break ;
2013-04-21 11:51:14 +00:00
case PROP_VISIBLE_CHILD :
gtk_stack_set_visible_child ( stack , g_value_get_object ( value ) ) ;
break ;
case PROP_VISIBLE_CHILD_NAME :
gtk_stack_set_visible_child_name ( stack , g_value_get_string ( value ) ) ;
break ;
case PROP_TRANSITION_DURATION :
2013-04-22 01:31:29 +00:00
gtk_stack_set_transition_duration ( stack , g_value_get_uint ( value ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_TRANSITION_TYPE :
2013-04-22 01:16:46 +00:00
gtk_stack_set_transition_type ( stack , g_value_get_enum ( value ) ) ;
2013-04-21 11:51:14 +00:00
break ;
2015-07-19 15:39:41 +00:00
case PROP_INTERPOLATE_SIZE :
gtk_stack_set_interpolate_size ( stack , g_value_get_boolean ( value ) ) ;
break ;
2013-04-21 11:51:14 +00:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
gtk_stack_class_init ( GtkStackClass * klass )
{
GObjectClass * object_class = G_OBJECT_CLASS ( klass ) ;
GtkWidgetClass * widget_class = GTK_WIDGET_CLASS ( klass ) ;
object_class - > get_property = gtk_stack_get_property ;
object_class - > set_property = gtk_stack_set_property ;
2019-02-10 23:22:54 +00:00
object_class - > dispose = gtk_stack_dispose ;
2013-04-21 11:51:14 +00:00
object_class - > finalize = gtk_stack_finalize ;
widget_class - > size_allocate = gtk_stack_size_allocate ;
2016-12-13 08:45:09 +00:00
widget_class - > snapshot = gtk_stack_snapshot ;
2017-05-05 15:18:15 +00:00
widget_class - > measure = gtk_stack_measure ;
2013-04-21 11:51:14 +00:00
widget_class - > compute_expand = gtk_stack_compute_expand ;
2020-05-07 20:04:42 +00:00
widget_class - > get_request_mode = gtk_stack_get_request_mode ;
2013-04-21 11:51:14 +00:00
2014-10-26 18:59:21 +00:00
/**
* GtkStack : hhomogeneous :
*
* % TRUE if the stack allocates the same width for all children .
*/
stack_props [ PROP_HHOMOGENEOUS ] =
g_param_spec_boolean ( " hhomogeneous " , P_ ( " Horizontally homogeneous " ) , P_ ( " Horizontally homogeneous sizing " ) ,
TRUE ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-10-26 18:59:21 +00:00
/**
* GtkStack : vhomogeneous :
*
* % TRUE if the stack allocates the same height for all children .
*/
stack_props [ PROP_VHOMOGENEOUS ] =
g_param_spec_boolean ( " vhomogeneous " , P_ ( " Vertically homogeneous " ) , P_ ( " Vertically homogeneous sizing " ) ,
2014-06-07 03:30:44 +00:00
TRUE ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-06-07 03:30:44 +00:00
stack_props [ PROP_VISIBLE_CHILD ] =
g_param_spec_object ( " visible-child " , P_ ( " Visible child " ) , P_ ( " The widget currently visible in the stack " ) ,
GTK_TYPE_WIDGET ,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
stack_props [ PROP_VISIBLE_CHILD_NAME ] =
g_param_spec_string ( " visible-child-name " , P_ ( " Name of visible child " ) , P_ ( " The name of the widget currently visible in the stack " ) ,
NULL ,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
stack_props [ PROP_TRANSITION_DURATION ] =
g_param_spec_uint ( " transition-duration " , P_ ( " Transition duration " ) , P_ ( " The animation duration, in milliseconds " ) ,
0 , G_MAXUINT , 200 ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-06-07 03:30:44 +00:00
stack_props [ PROP_TRANSITION_TYPE ] =
g_param_spec_enum ( " transition-type " , P_ ( " Transition type " ) , P_ ( " The type of animation used to transition " ) ,
GTK_TYPE_STACK_TRANSITION_TYPE , GTK_STACK_TRANSITION_TYPE_NONE ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-06-07 03:30:44 +00:00
stack_props [ PROP_TRANSITION_RUNNING ] =
g_param_spec_boolean ( " transition-running " , P_ ( " Transition running " ) , P_ ( " Whether or not the transition is currently running " ) ,
FALSE ,
GTK_PARAM_READABLE ) ;
2015-07-19 15:39:41 +00:00
stack_props [ PROP_INTERPOLATE_SIZE ] =
g_param_spec_boolean ( " interpolate-size " , P_ ( " Interpolate size " ) , P_ ( " Whether or not the size should smoothly change when changing between differently sized children " ) ,
FALSE ,
2015-11-09 14:27:40 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2015-07-19 15:39:41 +00:00
2019-02-13 19:14:54 +00:00
stack_props [ PROP_PAGES ] =
g_param_spec_object ( " pages " , P_ ( " Pages " ) , P_ ( " A selection model with the stacks pages " ) ,
GTK_TYPE_SELECTION_MODEL ,
GTK_PARAM_READABLE ) ;
2013-11-05 10:11:35 +00:00
g_object_class_install_properties ( object_class , LAST_PROP , stack_props ) ;
2013-04-21 11:51:14 +00:00
2015-11-04 04:19:28 +00:00
2016-05-29 11:51:02 +00:00
gtk_widget_class_set_accessible_type ( widget_class , GTK_TYPE_STACK_ACCESSIBLE ) ;
2017-11-18 03:49:57 +00:00
gtk_widget_class_set_css_name ( widget_class , I_ ( " stack " ) ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_new :
*
* Creates a new # GtkStack container .
*
* Returns : a new # GtkStack
*/
2013-04-21 11:51:14 +00:00
GtkWidget *
gtk_stack_new ( void )
{
return g_object_new ( GTK_TYPE_STACK , NULL ) ;
}
2019-02-06 17:54:18 +00:00
static GtkStackPage *
2013-04-21 11:51:14 +00:00
find_child_info_for_widget ( GtkStack * stack ,
GtkWidget * child )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * info ;
2013-04-21 11:51:14 +00:00
GList * l ;
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
info = l - > data ;
if ( info - > widget = = child )
return info ;
}
return NULL ;
}
2014-03-19 00:49:46 +00:00
static inline gboolean
is_left_transition ( GtkStackTransitionType transition_type )
{
return ( transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_LEFT ) ;
}
static inline gboolean
is_right_transition ( GtkStackTransitionType transition_type )
{
return ( transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_RIGHT ) ;
}
static inline gboolean
is_up_transition ( GtkStackTransitionType transition_type )
{
return ( transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_UP | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_UP ) ;
}
static inline gboolean
is_down_transition ( GtkStackTransitionType transition_type )
{
return ( transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_DOWN ) ;
}
/* Transitions that cause the bin window to move */
static inline gboolean
is_window_moving_transition ( GtkStackTransitionType transition_type )
{
return ( transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT | |
transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT | |
transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_UP | |
transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_UP | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_DOWN | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_LEFT | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_RIGHT ) ;
}
/* Transitions that change direction depending on the relative order of the
old and new child */
static inline gboolean
is_direction_dependent_transition ( GtkStackTransitionType transition_type )
{
return ( transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT | |
transition_type = = GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN | |
2014-03-19 03:42:59 +00:00
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP | |
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT | |
2019-03-05 19:44:45 +00:00
transition_type = = GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT | |
transition_type = = GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT_RIGHT ) ;
2014-03-19 00:49:46 +00:00
}
/* Returns simple transition type for a direction dependent transition, given
whether the new child ( the one being switched to ) is first in the stacking order
( added earlier ) . */
static inline GtkStackTransitionType
get_simple_transition_type ( gboolean new_child_first ,
GtkStackTransitionType transition_type )
{
switch ( transition_type )
{
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT :
return new_child_first ? GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT : GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT ;
2019-03-05 19:44:45 +00:00
case GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT_RIGHT :
return new_child_first ? GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT : GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT ;
2014-03-19 00:49:46 +00:00
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN :
return new_child_first ? GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN : GTK_STACK_TRANSITION_TYPE_SLIDE_UP ;
case GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN :
return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_DOWN : GTK_STACK_TRANSITION_TYPE_OVER_UP ;
2014-03-19 03:42:59 +00:00
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP :
return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_UP : GTK_STACK_TRANSITION_TYPE_OVER_DOWN ;
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT :
return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT : GTK_STACK_TRANSITION_TYPE_OVER_LEFT ;
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT :
return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_LEFT : GTK_STACK_TRANSITION_TYPE_OVER_RIGHT ;
2017-10-06 19:19:42 +00:00
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP :
case GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN :
case GTK_STACK_TRANSITION_TYPE_OVER_UP :
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN :
case GTK_STACK_TRANSITION_TYPE_UNDER_UP :
case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN :
case GTK_STACK_TRANSITION_TYPE_NONE :
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT :
case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT :
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT :
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT :
case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT :
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT :
case GTK_STACK_TRANSITION_TYPE_CROSSFADE :
2019-03-05 19:44:45 +00:00
case GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT :
case GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT :
2017-10-06 19:19:42 +00:00
default :
return transition_type ;
2014-03-19 00:49:46 +00:00
}
}
2013-04-21 11:51:14 +00:00
static gint
2017-06-04 15:30:40 +00:00
get_bin_window_x ( GtkStack * stack )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2017-12-06 06:56:12 +00:00
int width ;
2013-04-21 11:51:14 +00:00
int x = 0 ;
2017-12-06 06:56:12 +00:00
width = gtk_widget_get_width ( GTK_WIDGET ( stack ) ) ;
2017-06-04 15:30:40 +00:00
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) ! = GTK_PROGRESS_STATE_AFTER )
2013-04-21 11:51:14 +00:00
{
2014-03-19 00:49:46 +00:00
if ( is_left_transition ( priv - > active_transition_type ) )
2017-06-18 13:45:42 +00:00
x = width * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2014-03-19 00:49:46 +00:00
if ( is_right_transition ( priv - > active_transition_type ) )
2017-06-18 13:45:42 +00:00
x = - width * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-04-21 11:51:14 +00:00
}
2017-06-04 15:30:40 +00:00
return x ;
2013-04-21 11:51:14 +00:00
}
2013-04-22 00:17:40 +00:00
static gint
2017-06-04 15:30:40 +00:00
get_bin_window_y ( GtkStack * stack )
2013-04-22 00:17:40 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2017-12-06 06:56:12 +00:00
int height ;
2013-04-22 00:17:40 +00:00
int y = 0 ;
2017-12-06 06:56:12 +00:00
height = gtk_widget_get_height ( GTK_WIDGET ( stack ) ) ;
2017-06-04 15:30:40 +00:00
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) ! = GTK_PROGRESS_STATE_AFTER )
2013-04-22 00:17:40 +00:00
{
2014-03-19 00:49:46 +00:00
if ( is_up_transition ( priv - > active_transition_type ) )
2017-06-18 13:45:42 +00:00
y = height * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2014-03-19 00:49:46 +00:00
if ( is_down_transition ( priv - > active_transition_type ) )
2017-06-18 13:45:42 +00:00
y = - height * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-04-22 00:17:40 +00:00
}
2017-06-04 15:30:40 +00:00
return y ;
2013-04-22 00:17:40 +00:00
}
2016-03-01 06:24:39 +00:00
static void
gtk_stack_progress_updated ( GtkStack * stack )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2015-05-24 19:27:33 +00:00
if ( ! priv - > vhomogeneous | | ! priv - > hhomogeneous )
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
2017-06-04 15:30:40 +00:00
else if ( is_window_moving_transition ( priv - > active_transition_type ) )
gtk_widget_queue_allocate ( GTK_WIDGET ( stack ) ) ;
2018-12-23 07:23:03 +00:00
else
gtk_widget_queue_draw ( GTK_WIDGET ( stack ) ) ;
2013-04-21 11:51:14 +00:00
2020-06-12 19:40:34 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) = = GTK_PROGRESS_STATE_AFTER & &
priv - > last_visible_child ! = NULL )
2013-04-21 11:51:14 +00:00
{
2020-06-12 19:40:34 +00:00
gtk_widget_set_child_visible ( priv - > last_visible_child - > widget , FALSE ) ;
priv - > last_visible_child = NULL ;
2013-04-21 11:51:14 +00:00
}
}
static gboolean
2014-04-16 13:36:22 +00:00
gtk_stack_transition_cb ( GtkWidget * widget ,
2013-04-21 11:51:14 +00:00
GdkFrameClock * frame_clock ,
gpointer user_data )
{
2014-04-16 13:36:22 +00:00
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2016-03-02 01:19:50 +00:00
if ( priv - > first_frame_skipped )
gtk_progress_tracker_advance_frame ( & priv - > tracker ,
gdk_frame_clock_get_frame_time ( frame_clock ) ) ;
else
priv - > first_frame_skipped = TRUE ;
2013-04-21 11:51:14 +00:00
/* Finish animation early if not mapped anymore */
2015-05-24 19:08:00 +00:00
if ( ! gtk_widget_get_mapped ( widget ) )
2016-03-01 06:24:39 +00:00
gtk_progress_tracker_finish ( & priv - > tracker ) ;
gtk_stack_progress_updated ( GTK_STACK ( widget ) ) ;
2013-04-21 11:51:14 +00:00
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) = = GTK_PROGRESS_STATE_AFTER )
2013-04-21 11:51:14 +00:00
{
priv - > tick_id = 0 ;
2013-11-11 21:38:35 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_TRANSITION_RUNNING ] ) ;
2013-04-21 11:51:14 +00:00
return FALSE ;
}
return TRUE ;
}
static void
gtk_stack_schedule_ticks ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > tick_id = = 0 )
{
priv - > tick_id =
2014-04-16 13:36:22 +00:00
gtk_widget_add_tick_callback ( GTK_WIDGET ( stack ) , gtk_stack_transition_cb , stack , NULL ) ;
2013-11-11 21:38:35 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_TRANSITION_RUNNING ] ) ;
2013-04-21 11:51:14 +00:00
}
}
static void
gtk_stack_unschedule_ticks ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > tick_id ! = 0 )
{
gtk_widget_remove_tick_callback ( GTK_WIDGET ( stack ) , priv - > tick_id ) ;
priv - > tick_id = 0 ;
2013-11-11 21:38:35 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_TRANSITION_RUNNING ] ) ;
2013-04-21 11:51:14 +00:00
}
}
2013-04-21 23:53:57 +00:00
static GtkStackTransitionType
effective_transition_type ( GtkStack * stack ,
GtkStackTransitionType transition_type )
{
2017-01-11 14:27:51 +00:00
if ( _gtk_widget_get_direction ( GTK_WIDGET ( stack ) ) = = GTK_TEXT_DIR_RTL )
2013-04-21 23:53:57 +00:00
{
2014-03-19 00:49:46 +00:00
switch ( transition_type )
{
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT :
return GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT ;
case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT :
return GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT ;
2019-03-05 19:44:45 +00:00
case GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT :
return GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT ;
case GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT :
return GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT ;
2014-03-19 00:49:46 +00:00
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT :
return GTK_STACK_TRANSITION_TYPE_OVER_RIGHT ;
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT :
return GTK_STACK_TRANSITION_TYPE_OVER_LEFT ;
case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT :
return GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT ;
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT :
return GTK_STACK_TRANSITION_TYPE_UNDER_LEFT ;
2017-10-06 19:19:42 +00:00
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP :
case GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN :
case GTK_STACK_TRANSITION_TYPE_OVER_UP :
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN :
case GTK_STACK_TRANSITION_TYPE_UNDER_UP :
case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN :
case GTK_STACK_TRANSITION_TYPE_NONE :
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT :
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN :
case GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN :
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP :
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT :
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT :
case GTK_STACK_TRANSITION_TYPE_CROSSFADE :
2019-03-05 19:44:45 +00:00
case GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT_RIGHT :
2017-10-06 19:19:42 +00:00
default :
return transition_type ;
2014-03-19 00:49:46 +00:00
}
2013-04-21 23:53:57 +00:00
}
2017-10-06 19:19:42 +00:00
else
{
return transition_type ;
}
2013-04-21 23:53:57 +00:00
}
2013-04-21 11:51:14 +00:00
static void
2013-04-21 18:22:35 +00:00
gtk_stack_start_transition ( GtkStack * stack ,
GtkStackTransitionType transition_type ,
guint transition_duration )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkWidget * widget = GTK_WIDGET ( stack ) ;
if ( gtk_widget_get_mapped ( widget ) & &
2016-05-01 04:39:55 +00:00
gtk_settings_get_enable_animations ( gtk_widget_get_settings ( widget ) ) & &
2013-04-21 18:22:35 +00:00
transition_type ! = GTK_STACK_TRANSITION_TYPE_NONE & &
transition_duration ! = 0 & &
2013-04-21 11:51:14 +00:00
priv - > last_visible_child ! = NULL )
{
2013-04-21 23:53:57 +00:00
priv - > active_transition_type = effective_transition_type ( stack , transition_type ) ;
2016-03-02 01:19:50 +00:00
priv - > first_frame_skipped = FALSE ;
2013-04-21 11:51:14 +00:00
gtk_stack_schedule_ticks ( stack ) ;
2016-03-01 06:24:39 +00:00
gtk_progress_tracker_start ( & priv - > tracker ,
priv - > transition_duration * 1000 ,
0 ,
1.0 ) ;
2013-04-21 11:51:14 +00:00
}
else
{
gtk_stack_unschedule_ticks ( stack ) ;
2013-04-21 18:22:35 +00:00
priv - > active_transition_type = GTK_STACK_TRANSITION_TYPE_NONE ;
2016-03-01 06:24:39 +00:00
gtk_progress_tracker_finish ( & priv - > tracker ) ;
2013-04-21 11:51:14 +00:00
}
2016-05-13 07:22:20 +00:00
gtk_stack_progress_updated ( GTK_STACK ( widget ) ) ;
2013-04-21 11:51:14 +00:00
}
static void
2013-04-21 18:22:35 +00:00
set_visible_child ( GtkStack * stack ,
2019-02-06 17:54:18 +00:00
GtkStackPage * child_info ,
2013-04-21 18:22:35 +00:00
GtkStackTransitionType transition_type ,
guint transition_duration )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * info ;
2013-04-21 11:51:14 +00:00
GtkWidget * widget = GTK_WIDGET ( stack ) ;
GList * l ;
2014-12-11 03:32:45 +00:00
GtkWidget * focus ;
gboolean contains_focus = FALSE ;
2019-02-13 14:01:07 +00:00
guint old_pos = GTK_INVALID_LIST_POSITION ;
guint new_pos = GTK_INVALID_LIST_POSITION ;
2013-04-21 11:51:14 +00:00
2014-02-16 21:22:59 +00:00
/* if we are being destroyed, do not bother with transitions
2015-06-23 10:44:31 +00:00
* and notifications
*/
if ( gtk_widget_in_destruction ( widget ) )
2014-02-16 21:22:59 +00:00
return ;
2013-04-21 11:51:14 +00:00
/* If none, pick first visible */
if ( child_info = = NULL )
{
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
info = l - > data ;
if ( gtk_widget_get_visible ( info - > widget ) )
{
child_info = info ;
break ;
}
}
}
if ( child_info = = priv - > visible_child )
return ;
2019-02-10 23:22:54 +00:00
if ( priv - > pages )
{
guint position ;
for ( l = priv - > children , position = 0 ; l ! = NULL ; l = l - > next , position + + )
{
info = l - > data ;
if ( info = = priv - > visible_child )
old_pos = position ;
else if ( info = = child_info )
new_pos = position ;
}
}
2019-03-02 13:49:00 +00:00
if ( gtk_widget_get_root ( widget ) )
focus = gtk_root_get_focus ( gtk_widget_get_root ( widget ) ) ;
else
focus = NULL ;
if ( focus & &
priv - > visible_child & &
priv - > visible_child - > widget & &
gtk_widget_is_ancestor ( focus , priv - > visible_child - > widget ) )
2014-12-11 03:32:45 +00:00
{
2019-03-02 13:49:00 +00:00
contains_focus = TRUE ;
if ( priv - > visible_child - > last_focus )
g_object_remove_weak_pointer ( G_OBJECT ( priv - > visible_child - > last_focus ) ,
( gpointer * ) & priv - > visible_child - > last_focus ) ;
priv - > visible_child - > last_focus = focus ;
g_object_add_weak_pointer ( G_OBJECT ( priv - > visible_child - > last_focus ) ,
( gpointer * ) & priv - > visible_child - > last_focus ) ;
2014-12-11 03:32:45 +00:00
}
2013-04-21 11:51:14 +00:00
if ( priv - > last_visible_child )
gtk_widget_set_child_visible ( priv - > last_visible_child - > widget , FALSE ) ;
priv - > last_visible_child = NULL ;
if ( priv - > visible_child & & priv - > visible_child - > widget )
{
if ( gtk_widget_is_visible ( widget ) )
2015-05-24 14:55:34 +00:00
{
priv - > last_visible_child = priv - > visible_child ;
2020-06-12 19:40:34 +00:00
priv - > last_visible_widget_width = gtk_widget_get_width ( widget ) ;
priv - > last_visible_widget_height = gtk_widget_get_height ( widget ) ;
2015-05-24 14:55:34 +00:00
}
2013-04-21 11:51:14 +00:00
else
2015-05-24 14:55:34 +00:00
{
gtk_widget_set_child_visible ( priv - > visible_child - > widget , FALSE ) ;
}
2013-04-21 11:51:14 +00:00
}
2016-05-29 11:51:02 +00:00
gtk_stack_accessible_update_visible_child ( stack ,
priv - > visible_child ? priv - > visible_child - > widget : NULL ,
child_info ? child_info - > widget : NULL ) ;
2013-04-21 11:51:14 +00:00
priv - > visible_child = child_info ;
if ( child_info )
2014-12-11 03:32:45 +00:00
{
gtk_widget_set_child_visible ( child_info - > widget , TRUE ) ;
if ( contains_focus )
{
if ( child_info - > last_focus )
gtk_widget_grab_focus ( child_info - > last_focus ) ;
else
gtk_widget_child_focus ( child_info - > widget , GTK_DIR_TAB_FORWARD ) ;
}
}
2013-04-21 11:51:14 +00:00
2013-06-13 18:33:42 +00:00
if ( ( child_info = = NULL | | priv - > last_visible_child = = NULL ) & &
2014-03-19 00:49:46 +00:00
is_direction_dependent_transition ( transition_type ) )
2013-06-13 18:33:42 +00:00
{
transition_type = GTK_STACK_TRANSITION_TYPE_NONE ;
}
2014-03-19 00:49:46 +00:00
else if ( is_direction_dependent_transition ( transition_type ) )
2013-06-13 18:33:42 +00:00
{
gboolean i_first = FALSE ;
2014-11-10 23:45:58 +00:00
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
2013-06-13 18:33:42 +00:00
{
if ( child_info = = l - > data )
{
i_first = TRUE ;
break ;
}
if ( priv - > last_visible_child = = l - > data )
break ;
}
2014-03-19 00:49:46 +00:00
transition_type = get_simple_transition_type ( i_first , transition_type ) ;
2013-06-13 18:33:42 +00:00
}
2015-11-04 18:11:14 +00:00
if ( priv - > hhomogeneous & & priv - > vhomogeneous )
gtk_widget_queue_allocate ( widget ) ;
else
gtk_widget_queue_resize ( widget ) ;
2013-11-05 10:18:37 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_VISIBLE_CHILD ] ) ;
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_VISIBLE_CHILD_NAME ] ) ;
2013-04-21 11:51:14 +00:00
2019-02-10 23:22:54 +00:00
if ( priv - > pages )
2019-02-13 14:01:07 +00:00
{
if ( old_pos = = GTK_INVALID_LIST_POSITION & & new_pos = = GTK_INVALID_LIST_POSITION )
; /* nothing to do */
else if ( old_pos = = GTK_INVALID_LIST_POSITION )
gtk_selection_model_selection_changed ( priv - > pages , new_pos , 1 ) ;
else if ( new_pos = = GTK_INVALID_LIST_POSITION )
gtk_selection_model_selection_changed ( priv - > pages , old_pos , 1 ) ;
else
gtk_selection_model_selection_changed ( priv - > pages ,
MIN ( old_pos , new_pos ) ,
MAX ( old_pos , new_pos ) - MIN ( old_pos , new_pos ) + 1 ) ;
}
2019-02-10 23:22:54 +00:00
2013-04-21 18:22:35 +00:00
gtk_stack_start_transition ( stack , transition_type , transition_duration ) ;
2013-04-21 11:51:14 +00:00
}
static void
stack_child_visibility_notify_cb ( GObject * obj ,
GParamSpec * pspec ,
gpointer user_data )
{
GtkStack * stack = GTK_STACK ( user_data ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkWidget * child = GTK_WIDGET ( obj ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * child_info ;
2013-04-21 11:51:14 +00:00
child_info = find_child_info_for_widget ( stack , child ) ;
2020-03-06 04:56:29 +00:00
g_return_if_fail ( child_info ! = NULL ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > visible_child = = NULL & &
gtk_widget_get_visible ( child ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , child_info , priv - > transition_type , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
else if ( priv - > visible_child = = child_info & &
! gtk_widget_get_visible ( child ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , NULL , priv - > transition_type , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
if ( child_info = = priv - > last_visible_child )
{
gtk_widget_set_child_visible ( priv - > last_visible_child - > widget , FALSE ) ;
priv - > last_visible_child = NULL ;
}
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_add_titled :
* @ stack : a # GtkStack
* @ child : the widget to add
* @ name : the name for @ child
* @ title : a human - readable title for @ child
*
* Adds a child to @ stack .
* The child is identified by the @ name . The @ title
* will be used by # GtkStackSwitcher to represent
* @ child in a tab bar , so it should be short .
2019-11-04 02:05:03 +00:00
*
* Returns : ( transfer none ) : the # GtkStackPage for @ child
2013-04-21 14:14:46 +00:00
*/
2019-11-04 02:05:03 +00:00
GtkStackPage *
2013-04-21 11:51:14 +00:00
gtk_stack_add_titled ( GtkStack * stack ,
GtkWidget * child ,
const gchar * name ,
const gchar * title )
{
2019-11-04 02:05:03 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
g_return_val_if_fail ( GTK_IS_WIDGET ( child ) , NULL ) ;
2013-04-21 11:51:14 +00:00
2019-11-04 02:05:03 +00:00
return gtk_stack_add_internal ( stack , child , name , title ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_add_named :
* @ stack : a # GtkStack
* @ child : the widget to add
* @ name : the name for @ child
*
* Adds a child to @ stack .
* The child is identified by the @ name .
2019-11-04 02:05:03 +00:00
*
* Returns : ( transfer none ) : the # GtkStackPage for @ child
2013-04-21 14:14:46 +00:00
*/
2019-11-04 02:05:03 +00:00
GtkStackPage *
2013-04-21 11:51:14 +00:00
gtk_stack_add_named ( GtkStack * stack ,
GtkWidget * child ,
const gchar * name )
{
2019-11-04 02:05:03 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
g_return_val_if_fail ( GTK_IS_WIDGET ( child ) , NULL ) ;
2013-04-21 11:51:14 +00:00
2019-11-04 02:05:03 +00:00
return gtk_stack_add_internal ( stack , child , name , NULL ) ;
2013-04-21 11:51:14 +00:00
}
2019-11-04 02:05:03 +00:00
static GtkStackPage *
2019-02-06 17:54:18 +00:00
gtk_stack_add_internal ( GtkStack * stack ,
GtkWidget * child ,
const char * name ,
const char * title )
{
GtkStackPage * child_info ;
2013-04-21 11:51:14 +00:00
2019-11-04 02:05:03 +00:00
g_return_val_if_fail ( child ! = NULL , NULL ) ;
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
child_info = g_object_new ( GTK_TYPE_STACK_PAGE , NULL ) ;
child_info - > widget = g_object_ref ( child ) ;
child_info - > name = g_strdup ( name ) ;
child_info - > title = g_strdup ( title ) ;
2013-04-21 11:51:14 +00:00
child_info - > icon_name = NULL ;
2013-08-30 20:32:42 +00:00
child_info - > needs_attention = FALSE ;
2014-12-11 03:32:45 +00:00
child_info - > last_focus = NULL ;
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
gtk_stack_add_page ( stack , child_info ) ;
g_object_unref ( child_info ) ;
2019-11-04 02:05:03 +00:00
return child_info ;
2019-02-06 17:54:18 +00:00
}
static void
gtk_stack_add_page ( GtkStack * stack ,
GtkStackPage * child_info )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
GList * l ;
g_return_if_fail ( child_info - > widget ! = NULL ) ;
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
GtkStackPage * info = l - > data ;
if ( info - > name & &
g_strcmp0 ( info - > name , child_info - > name ) = = 0 )
{
g_warning ( " While adding page: duplicate child name in GtkStack: %s " , child_info - > name ) ;
break ;
}
}
priv - > children = g_list_append ( priv - > children , g_object_ref ( child_info ) ) ;
2013-04-21 11:51:14 +00:00
2019-02-06 17:54:18 +00:00
gtk_widget_set_child_visible ( child_info - > widget , FALSE ) ;
gtk_widget_set_parent ( child_info - > widget , GTK_WIDGET ( stack ) ) ;
2013-04-21 11:51:14 +00:00
2019-02-10 23:22:54 +00:00
if ( priv - > pages )
g_list_model_items_changed ( G_LIST_MODEL ( priv - > pages ) , g_list_length ( priv - > children ) - 1 , 0 , 1 ) ;
2019-02-06 17:54:18 +00:00
g_signal_connect ( child_info - > widget , " notify::visible " ,
2013-04-21 11:51:14 +00:00
G_CALLBACK ( stack_child_visibility_notify_cb ) , stack ) ;
if ( priv - > visible_child = = NULL & &
2019-02-06 17:54:18 +00:00
gtk_widget_get_visible ( child_info - > widget ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , child_info , priv - > transition_type , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
2014-10-26 18:59:21 +00:00
if ( priv - > hhomogeneous | | priv - > vhomogeneous | | priv - > visible_child = = child_info )
2013-04-21 11:51:14 +00:00
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
}
static void
2019-02-10 23:22:54 +00:00
stack_remove ( GtkStack * stack ,
GtkWidget * child ,
gboolean in_dispose )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * child_info ;
2013-04-21 11:51:14 +00:00
gboolean was_visible ;
child_info = find_child_info_for_widget ( stack , child ) ;
if ( child_info = = NULL )
return ;
priv - > children = g_list_remove ( priv - > children , child_info ) ;
2019-02-10 23:22:54 +00:00
2013-04-21 11:51:14 +00:00
g_signal_handlers_disconnect_by_func ( child ,
stack_child_visibility_notify_cb ,
stack ) ;
was_visible = gtk_widget_get_visible ( child ) ;
2019-02-13 13:42:58 +00:00
g_clear_object ( & child_info - > widget ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > visible_child = = child_info )
2019-02-10 23:22:54 +00:00
{
if ( in_dispose )
priv - > visible_child = NULL ;
else
set_visible_child ( stack , NULL , priv - > transition_type , priv - > transition_duration ) ;
}
2013-04-21 11:51:14 +00:00
if ( priv - > last_visible_child = = child_info )
priv - > last_visible_child = NULL ;
gtk_widget_unparent ( child ) ;
2019-02-06 17:54:18 +00:00
g_object_unref ( child_info ) ;
2013-04-21 11:51:14 +00:00
2019-02-10 23:22:54 +00:00
if ( ! in_dispose & &
( priv - > hhomogeneous | | priv - > vhomogeneous ) & &
was_visible )
2013-04-21 11:51:14 +00:00
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
}
2020-05-07 19:49:04 +00:00
/**
* gtk_stack_remove :
* @ stack : a # GtkStack
* @ child : the child to remove
*
* Removes a child widget from @ stack .
*/
void
gtk_stack_remove ( GtkStack * stack ,
GtkWidget * child )
2019-02-10 23:22:54 +00:00
{
2020-05-07 19:49:04 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-10 23:22:54 +00:00
GList * l ;
guint position ;
2020-05-07 19:49:04 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
g_return_if_fail ( GTK_IS_WIDGET ( child ) ) ;
g_return_if_fail ( gtk_widget_get_parent ( child ) = = GTK_WIDGET ( stack ) ) ;
2019-02-10 23:22:54 +00:00
for ( l = priv - > children , position = 0 ; l ; l = l - > next , position + + )
{
GtkStackPage * page = l - > data ;
if ( page - > widget = = child )
break ;
}
2020-05-07 19:49:04 +00:00
stack_remove ( stack , child , FALSE ) ;
2019-02-10 23:22:54 +00:00
if ( priv - > pages )
g_list_model_items_changed ( G_LIST_MODEL ( priv - > pages ) , position , 1 , 0 ) ;
}
2019-02-06 17:54:18 +00:00
/**
* gtk_stack_get_page :
* @ stack : a # GtkStack
* @ child : a child of @ stack
*
* Returns the # GtkStackPage object for @ child .
*
* Returns : ( transfer none ) : the # GtkStackPage for @ child
*/
GtkStackPage *
gtk_stack_get_page ( GtkStack * stack ,
GtkWidget * child )
{
return find_child_info_for_widget ( stack , child ) ;
}
2014-01-20 08:32:37 +00:00
/**
* gtk_stack_get_child_by_name :
* @ stack : a # GtkStack
* @ name : the name of the child to find
*
* Finds the child of the # GtkStack with the name given as
* the argument . Returns % NULL if there is no child with this
* name .
*
2015-11-24 08:44:08 +00:00
* Returns : ( transfer none ) ( nullable ) : the requested child of the # GtkStack
2014-01-20 08:32:37 +00:00
*/
GtkWidget *
gtk_stack_get_child_by_name ( GtkStack * stack ,
const gchar * name )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * info ;
2014-01-20 08:32:37 +00:00
GList * l ;
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
g_return_val_if_fail ( name ! = NULL , NULL ) ;
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
info = l - > data ;
if ( info - > name & & strcmp ( info - > name , name ) = = 0 )
return info - > widget ;
}
return NULL ;
}
2019-02-06 17:54:18 +00:00
/**
* gtk_stack_page_get_child :
* @ page : a # GtkStackPage
*
* Returns the stack child to which @ page belongs .
*
* Returns : ( transfer none ) : the child to which @ page belongs
*/
GtkWidget *
gtk_stack_page_get_child ( GtkStackPage * page )
{
return page - > widget ;
}
2014-10-26 18:59:21 +00:00
/**
* gtk_stack_set_hhomogeneous :
* @ stack : a # GtkStack
* @ hhomogeneous : % TRUE to make @ stack horizontally homogeneous
*
* Sets the # GtkStack to be horizontally homogeneous or not .
* If it is homogeneous , the # GtkStack will request the same
* width for all its children . If it isn ' t , the stack
* may change width when a different child becomes visible .
*/
void
gtk_stack_set_hhomogeneous ( GtkStack * stack ,
gboolean hhomogeneous )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
hhomogeneous = ! ! hhomogeneous ;
if ( priv - > hhomogeneous = = hhomogeneous )
return ;
2015-05-24 19:15:44 +00:00
2014-10-26 18:59:21 +00:00
priv - > hhomogeneous = hhomogeneous ;
if ( gtk_widget_get_visible ( GTK_WIDGET ( stack ) ) )
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_HHOMOGENEOUS ] ) ;
}
/**
* gtk_stack_get_hhomogeneous :
* @ stack : a # GtkStack
*
* Gets whether @ stack is horizontally homogeneous .
* See gtk_stack_set_hhomogeneous ( ) .
*
* Returns : whether @ stack is horizontally homogeneous .
*/
gboolean
gtk_stack_get_hhomogeneous ( GtkStack * stack )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , FALSE ) ;
return priv - > hhomogeneous ;
}
/**
* gtk_stack_set_vhomogeneous :
* @ stack : a # GtkStack
* @ vhomogeneous : % TRUE to make @ stack vertically homogeneous
*
* Sets the # GtkStack to be vertically homogeneous or not .
* If it is homogeneous , the # GtkStack will request the same
* height for all its children . If it isn ' t , the stack
* may change height when a different child becomes visible .
*/
void
gtk_stack_set_vhomogeneous ( GtkStack * stack ,
gboolean vhomogeneous )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
vhomogeneous = ! ! vhomogeneous ;
if ( priv - > vhomogeneous = = vhomogeneous )
return ;
2015-05-24 19:15:44 +00:00
2014-10-26 18:59:21 +00:00
priv - > vhomogeneous = vhomogeneous ;
if ( gtk_widget_get_visible ( GTK_WIDGET ( stack ) ) )
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_VHOMOGENEOUS ] ) ;
}
/**
* gtk_stack_get_vhomogeneous :
* @ stack : a # GtkStack
*
* Gets whether @ stack is vertically homogeneous .
* See gtk_stack_set_vhomogeneous ( ) .
*
* Returns : whether @ stack is vertically homogeneous .
*/
gboolean
gtk_stack_get_vhomogeneous ( GtkStack * stack )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , FALSE ) ;
return priv - > vhomogeneous ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_get_transition_duration :
* @ stack : a # GtkStack
*
2013-04-22 14:24:20 +00:00
* Returns the amount of time ( in milliseconds ) that
2013-04-21 14:14:46 +00:00
* transitions between pages in @ stack will take .
*
* Returns : the transition duration
*/
2013-04-22 01:31:29 +00:00
guint
2013-04-21 11:51:14 +00:00
gtk_stack_get_transition_duration ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , 0 ) ;
2013-07-02 11:43:20 +00:00
return priv - > transition_duration ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_set_transition_duration :
* @ stack : a # GtkStack
2013-04-22 03:13:16 +00:00
* @ duration : the new duration , in milliseconds
2013-04-21 14:14:46 +00:00
*
* Sets the duration that transitions between pages in @ stack
* will take .
*/
2013-04-21 11:51:14 +00:00
void
gtk_stack_set_transition_duration ( GtkStack * stack ,
2013-04-22 03:13:16 +00:00
guint duration )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2014-06-07 03:35:53 +00:00
if ( priv - > transition_duration = = duration )
return ;
2013-07-02 11:43:20 +00:00
priv - > transition_duration = duration ;
2013-11-05 10:18:37 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_TRANSITION_DURATION ] ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_get_transition_type :
* @ stack : a # GtkStack
*
* Gets the type of animation that will be used
* for transitions between pages in @ stack .
*
2014-02-19 23:49:43 +00:00
* Returns : the current transition type of @ stack
2013-04-21 14:14:46 +00:00
*/
2013-04-21 11:51:14 +00:00
GtkStackTransitionType
gtk_stack_get_transition_type ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , GTK_STACK_TRANSITION_TYPE_NONE ) ;
2013-07-02 11:43:20 +00:00
return priv - > transition_type ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_set_transition_type :
* @ stack : a # GtkStack
2013-04-22 03:13:16 +00:00
* @ transition : the new transition type
2013-04-21 14:14:46 +00:00
*
* Sets the type of animation that will be used for
* transitions between pages in @ stack . Available
* types include various kinds of fades and slides .
*
* The transition type can be changed without problems
* at runtime , so it is possible to change the animation
* based on the page that is about to become current .
*/
2013-04-21 11:51:14 +00:00
void
2013-04-21 14:14:46 +00:00
gtk_stack_set_transition_type ( GtkStack * stack ,
2013-04-22 03:13:16 +00:00
GtkStackTransitionType transition )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2014-06-07 03:35:53 +00:00
if ( priv - > transition_type = = transition )
return ;
2013-07-02 11:43:20 +00:00
priv - > transition_type = transition ;
2013-11-05 10:18:37 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_TRANSITION_TYPE ] ) ;
2013-04-21 11:51:14 +00:00
}
2013-11-11 21:38:35 +00:00
/**
* gtk_stack_get_transition_running :
* @ stack : a # GtkStack
*
* Returns whether the @ stack is currently in a transition from one page to
* another .
*
2014-02-19 23:49:43 +00:00
* Returns : % TRUE if the transition is currently running , % FALSE otherwise .
2013-11-11 21:38:35 +00:00
*/
gboolean
gtk_stack_get_transition_running ( GtkStack * stack )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , FALSE ) ;
return ( priv - > tick_id ! = 0 ) ;
}
2015-07-19 15:39:41 +00:00
/**
* gtk_stack_set_interpolate_size :
* @ stack : A # GtkStack
2015-08-09 21:31:36 +00:00
* @ interpolate_size : the new value
2015-07-19 15:39:41 +00:00
*
* Sets whether or not @ stack will interpolate its size when
2016-02-08 21:49:01 +00:00
* changing the visible child . If the # GtkStack : interpolate - size
2015-12-15 14:48:16 +00:00
* property is set to % TRUE , @ stack will interpolate its size between
* the current one and the one it ' ll take after changing the
* visible child , according to the set transition duration .
2015-07-19 15:39:41 +00:00
*/
void
gtk_stack_set_interpolate_size ( GtkStack * stack ,
gboolean interpolate_size )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
interpolate_size = ! ! interpolate_size ;
if ( priv - > interpolate_size = = interpolate_size )
return ;
priv - > interpolate_size = interpolate_size ;
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_INTERPOLATE_SIZE ] ) ;
}
/**
* gtk_stack_get_interpolate_size :
* @ stack : A # GtkStack
*
2015-12-15 14:48:16 +00:00
* Returns wether the # GtkStack is set up to interpolate between
2016-01-19 11:52:58 +00:00
* the sizes of children on page switch .
2015-12-15 14:48:16 +00:00
*
* Returns : % TRUE if child sizes are interpolated
2015-07-19 15:39:41 +00:00
*/
gboolean
gtk_stack_get_interpolate_size ( GtkStack * stack )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2015-07-20 13:55:40 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , FALSE ) ;
2015-07-19 15:39:41 +00:00
return priv - > interpolate_size ;
}
2013-04-21 11:51:14 +00:00
/**
* gtk_stack_get_visible_child :
* @ stack : a # GtkStack
*
2013-04-21 14:14:46 +00:00
* Gets the currently visible child of @ stack , or % NULL if
* there are no visible children .
2013-04-21 11:51:14 +00:00
*
2015-11-24 08:44:08 +00:00
* Returns : ( transfer none ) ( nullable ) : the visible child of the # GtkStack
2013-04-21 14:14:46 +00:00
*/
2013-04-21 11:51:14 +00:00
GtkWidget *
gtk_stack_get_visible_child ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
2013-07-02 11:43:20 +00:00
return priv - > visible_child ? priv - > visible_child - > widget : NULL ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_get_visible_child_name :
* @ stack : a # GtkStack
*
* Returns the name of the currently visible child of @ stack , or
* % NULL if there is no visible child .
*
2015-11-24 08:44:08 +00:00
* Returns : ( transfer none ) ( nullable ) : the name of the visible child of the # GtkStack
2013-04-21 14:14:46 +00:00
*/
2013-04-21 11:51:14 +00:00
const gchar *
gtk_stack_get_visible_child_name ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
2013-07-02 11:43:20 +00:00
if ( priv - > visible_child )
return priv - > visible_child - > name ;
2013-04-21 11:51:14 +00:00
return NULL ;
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_set_visible_child :
* @ stack : a # GtkStack
* @ child : a child of @ stack
*
* Makes @ child the visible child of @ stack .
*
* If @ child is different from the currently
* visible child , the transition between the
* two will be animated with the current
* transition type of @ stack .
*
2014-03-07 03:50:40 +00:00
* Note that the @ child widget has to be visible itself
* ( see gtk_widget_show ( ) ) in order to become the visible
* child of @ stack .
2013-04-21 14:14:46 +00:00
*/
2013-04-21 11:51:14 +00:00
void
gtk_stack_set_visible_child ( GtkStack * stack ,
GtkWidget * child )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * child_info ;
2013-04-21 11:51:14 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
g_return_if_fail ( GTK_IS_WIDGET ( child ) ) ;
child_info = find_child_info_for_widget ( stack , child ) ;
if ( child_info = = NULL )
2013-10-07 12:46:16 +00:00
{
g_warning ( " Given child of type '%s' not found in GtkStack " ,
G_OBJECT_TYPE_NAME ( child ) ) ;
return ;
}
2013-04-21 11:51:14 +00:00
if ( gtk_widget_get_visible ( child_info - > widget ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , child_info ,
2013-07-02 11:43:20 +00:00
priv - > transition_type ,
priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_set_visible_child_name :
* @ stack : a # GtkStack
* @ name : the name of the child to make visible
*
* Makes the child with the given name visible .
*
* If @ child is different from the currently
* visible child , the transition between the
* two will be animated with the current
* transition type of @ stack .
*
2014-03-07 03:50:40 +00:00
* Note that the child widget has to be visible itself
* ( see gtk_widget_show ( ) ) in order to become the visible
* child of @ stack .
2013-04-21 14:14:46 +00:00
*/
2013-04-21 11:51:14 +00:00
void
gtk_stack_set_visible_child_name ( GtkStack * stack ,
const gchar * name )
2013-04-21 18:22:35 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2018-04-19 01:58:57 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2013-07-02 11:43:20 +00:00
gtk_stack_set_visible_child_full ( stack , name , priv - > transition_type ) ;
2013-04-21 18:22:35 +00:00
}
/**
2013-04-22 15:19:54 +00:00
* gtk_stack_set_visible_child_full :
2013-04-21 18:22:35 +00:00
* @ stack : a # GtkStack
* @ name : the name of the child to make visible
2013-04-22 03:13:16 +00:00
* @ transition : the transition type to use
2013-04-21 18:22:35 +00:00
*
* Makes the child with the given name visible .
*
2014-03-07 03:50:40 +00:00
* Note that the child widget has to be visible itself
* ( see gtk_widget_show ( ) ) in order to become the visible
* child of @ stack .
2013-04-21 18:22:35 +00:00
*/
void
gtk_stack_set_visible_child_full ( GtkStack * stack ,
const gchar * name ,
2013-04-22 03:13:16 +00:00
GtkStackTransitionType transition )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * child_info , * info ;
2013-04-21 11:51:14 +00:00
GList * l ;
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2014-11-25 05:14:47 +00:00
if ( name = = NULL )
return ;
2013-04-21 11:51:14 +00:00
child_info = NULL ;
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
info = l - > data ;
if ( info - > name ! = NULL & &
strcmp ( info - > name , name ) = = 0 )
{
child_info = info ;
break ;
}
}
2013-10-07 12:46:16 +00:00
if ( child_info = = NULL )
{
g_warning ( " Child name '%s' not found in GtkStack " , name ) ;
return ;
}
if ( gtk_widget_get_visible ( child_info - > widget ) )
2013-04-22 03:13:16 +00:00
set_visible_child ( stack , child_info , transition , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
}
static void
gtk_stack_compute_expand ( GtkWidget * widget ,
gboolean * hexpand_p ,
gboolean * vexpand_p )
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
gboolean hexpand , vexpand ;
2019-02-06 17:54:18 +00:00
GtkStackPage * child_info ;
2013-04-21 11:51:14 +00:00
GtkWidget * child ;
GList * l ;
hexpand = FALSE ;
vexpand = FALSE ;
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
child_info = l - > data ;
child = child_info - > widget ;
if ( ! hexpand & &
gtk_widget_compute_expand ( child , GTK_ORIENTATION_HORIZONTAL ) )
hexpand = TRUE ;
if ( ! vexpand & &
gtk_widget_compute_expand ( child , GTK_ORIENTATION_VERTICAL ) )
vexpand = TRUE ;
if ( hexpand & & vexpand )
break ;
}
* hexpand_p = hexpand ;
* vexpand_p = vexpand ;
}
2020-05-07 20:04:42 +00:00
static GtkSizeRequestMode
gtk_stack_get_request_mode ( GtkWidget * widget )
{
GtkWidget * w ;
int wfh = 0 , hfw = 0 ;
for ( w = gtk_widget_get_first_child ( widget ) ;
w ! = NULL ;
w = gtk_widget_get_next_sibling ( w ) )
{
GtkSizeRequestMode mode = gtk_widget_get_request_mode ( w ) ;
switch ( mode )
{
case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH :
hfw + + ;
break ;
case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
wfh + + ;
break ;
case GTK_SIZE_REQUEST_CONSTANT_SIZE :
default :
break ;
}
}
if ( hfw = = 0 & & wfh = = 0 )
return GTK_SIZE_REQUEST_CONSTANT_SIZE ;
else
return wfh > hfw ?
GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH ;
}
2013-04-21 11:51:14 +00:00
static void
2016-12-13 08:45:09 +00:00
gtk_stack_snapshot_crossfade ( GtkWidget * widget ,
GtkSnapshot * snapshot )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2016-03-01 06:24:39 +00:00
gdouble progress = gtk_progress_tracker_get_progress ( & priv - > tracker , FALSE ) ;
2016-12-13 08:45:09 +00:00
2018-04-24 01:17:23 +00:00
gtk_snapshot_push_cross_fade ( snapshot , progress ) ;
2013-07-04 11:30:51 +00:00
2020-06-12 19:40:34 +00:00
if ( priv - > last_visible_child )
2013-04-21 11:51:14 +00:00
{
2020-06-12 19:40:34 +00:00
gtk_widget_snapshot_child ( widget ,
priv - > last_visible_child - > widget ,
snapshot ) ;
2016-12-17 06:44:10 +00:00
}
2017-01-12 23:39:59 +00:00
gtk_snapshot_pop ( snapshot ) ;
2016-12-17 06:44:10 +00:00
2017-01-12 21:00:38 +00:00
gtk_widget_snapshot_child ( widget ,
priv - > visible_child - > widget ,
snapshot ) ;
2017-01-12 23:39:59 +00:00
gtk_snapshot_pop ( snapshot ) ;
2013-04-21 11:51:14 +00:00
}
2013-08-31 16:00:47 +00:00
static void
2016-12-13 08:45:09 +00:00
gtk_stack_snapshot_under ( GtkWidget * widget ,
GtkSnapshot * snapshot )
2013-08-31 16:00:47 +00:00
{
GtkStack * stack = GTK_STACK ( widget ) ;
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2017-06-28 06:19:35 +00:00
int widget_width , widget_height ;
2013-08-31 16:00:47 +00:00
gint x , y , width , height , pos_x , pos_y ;
2017-06-28 06:19:35 +00:00
2013-08-31 16:00:47 +00:00
x = y = 0 ;
2017-12-06 06:56:12 +00:00
width = widget_width = gtk_widget_get_width ( widget ) ;
height = widget_height = gtk_widget_get_height ( widget ) ;
2017-07-01 17:15:01 +00:00
2013-08-31 16:00:47 +00:00
pos_x = pos_y = 0 ;
2017-10-06 19:19:42 +00:00
switch ( ( guint ) priv - > active_transition_type )
2013-08-31 16:00:47 +00:00
{
case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN :
y = 0 ;
2017-06-28 06:19:35 +00:00
height = widget_height * ( gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-08-31 16:00:47 +00:00
pos_y = height ;
break ;
case GTK_STACK_TRANSITION_TYPE_UNDER_UP :
2017-06-28 06:19:35 +00:00
y = widget_height * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
height = widget_height - y ;
pos_y = y - widget_height ;
2013-08-31 16:00:47 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT :
2017-06-28 06:19:35 +00:00
x = widget_width * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
width = widget_width - x ;
pos_x = x - widget_width ;
2013-08-31 16:00:47 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT :
x = 0 ;
2017-06-28 06:19:35 +00:00
width = widget_width * ( gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-08-31 16:00:47 +00:00
pos_x = width ;
break ;
default :
g_assert_not_reached ( ) ;
}
2018-04-24 01:17:23 +00:00
gtk_snapshot_push_clip ( snapshot , & GRAPHENE_RECT_INIT ( x , y , width , height ) ) ;
2013-08-31 16:00:47 +00:00
2017-01-07 16:02:20 +00:00
gtk_widget_snapshot_child ( widget ,
priv - > visible_child - > widget ,
snapshot ) ;
2013-08-31 16:00:47 +00:00
2017-01-12 23:39:59 +00:00
gtk_snapshot_pop ( snapshot ) ;
2013-08-31 16:00:47 +00:00
2020-06-12 19:40:34 +00:00
if ( priv - > last_visible_child )
2013-08-31 16:00:47 +00:00
{
2019-02-21 04:34:12 +00:00
gtk_snapshot_save ( snapshot ) ;
gtk_snapshot_translate ( snapshot , & GRAPHENE_POINT_INIT ( pos_x , pos_y ) ) ;
2020-06-12 19:40:34 +00:00
gtk_widget_snapshot_child ( widget , priv - > last_visible_child - > widget , snapshot ) ;
2019-02-21 04:34:12 +00:00
gtk_snapshot_restore ( snapshot ) ;
2013-08-31 16:00:47 +00:00
}
}
2019-03-05 19:44:45 +00:00
static void
gtk_stack_snapshot_cube ( GtkWidget * widget ,
GtkSnapshot * snapshot )
{
GtkStack * stack = GTK_STACK ( widget ) ;
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
double progress = gtk_progress_tracker_get_progress ( & priv - > tracker , FALSE ) ;
if ( priv - > active_transition_type = = GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT )
progress = 1 - progress ;
2020-06-12 19:40:34 +00:00
if ( priv - > last_visible_child & & progress > 0.5 )
2019-03-05 19:44:45 +00:00
{
gtk_snapshot_save ( snapshot ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
gtk_widget_get_width ( widget ) / 2.f ,
gtk_widget_get_height ( widget ) / 2.f ,
0 ) ) ;
gtk_snapshot_perspective ( snapshot , 2 * gtk_widget_get_width ( widget ) / 1.f ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
0 , 0 ,
- gtk_widget_get_width ( widget ) / 2.f ) ) ;
gtk_snapshot_rotate_3d ( snapshot , - 90 * progress , graphene_vec3_y_axis ( ) ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
- gtk_widget_get_width ( widget ) / 2.f ,
- gtk_widget_get_height ( widget ) / 2.f ,
gtk_widget_get_width ( widget ) / 2.f ) ) ;
if ( priv - > active_transition_type = = GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT )
2020-06-12 19:40:34 +00:00
gtk_widget_snapshot_child ( widget , priv - > last_visible_child - > widget , snapshot ) ;
2019-03-05 19:44:45 +00:00
else
gtk_widget_snapshot_child ( widget , priv - > visible_child - > widget , snapshot ) ;
gtk_snapshot_restore ( snapshot ) ;
}
gtk_snapshot_save ( snapshot ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
gtk_widget_get_width ( widget ) / 2.f ,
gtk_widget_get_height ( widget ) / 2.f ,
0 ) ) ;
gtk_snapshot_perspective ( snapshot , 2 * gtk_widget_get_width ( widget ) / 1.f ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
0 , 0 ,
- gtk_widget_get_width ( widget ) / 2.f ) ) ;
gtk_snapshot_rotate_3d ( snapshot , 90 * ( 1.0 - progress ) , graphene_vec3_y_axis ( ) ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
- gtk_widget_get_width ( widget ) / 2.f ,
- gtk_widget_get_height ( widget ) / 2.f ,
gtk_widget_get_width ( widget ) / 2.f ) ) ;
if ( priv - > active_transition_type = = GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT )
gtk_widget_snapshot_child ( widget , priv - > visible_child - > widget , snapshot ) ;
else
2020-06-12 19:40:34 +00:00
gtk_widget_snapshot_child ( widget , priv - > last_visible_child - > widget , snapshot ) ;
2019-03-05 19:44:45 +00:00
gtk_snapshot_restore ( snapshot ) ;
2020-06-12 19:40:34 +00:00
if ( priv - > last_visible_child & & progress < = 0.5 )
2019-03-05 19:44:45 +00:00
{
gtk_snapshot_save ( snapshot ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
gtk_widget_get_width ( widget ) / 2.f ,
gtk_widget_get_height ( widget ) / 2.f ,
0 ) ) ;
gtk_snapshot_perspective ( snapshot , 2 * gtk_widget_get_width ( widget ) / 1.f ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
0 , 0 ,
- gtk_widget_get_width ( widget ) / 2.f ) ) ;
gtk_snapshot_rotate_3d ( snapshot , - 90 * progress , graphene_vec3_y_axis ( ) ) ;
gtk_snapshot_translate_3d ( snapshot , & GRAPHENE_POINT3D_INIT (
- gtk_widget_get_width ( widget ) / 2.f ,
- gtk_widget_get_height ( widget ) / 2.f ,
gtk_widget_get_width ( widget ) / 2.f ) ) ;
if ( priv - > active_transition_type = = GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT )
2020-06-12 19:40:34 +00:00
gtk_widget_snapshot_child ( widget , priv - > last_visible_child - > widget , snapshot ) ;
2019-03-05 19:44:45 +00:00
else
gtk_widget_snapshot_child ( widget , priv - > visible_child - > widget , snapshot ) ;
gtk_snapshot_restore ( snapshot ) ;
}
}
2013-04-21 11:51:14 +00:00
static void
2016-12-13 08:45:09 +00:00
gtk_stack_snapshot_slide ( GtkWidget * widget ,
GtkSnapshot * snapshot )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2020-06-12 19:40:34 +00:00
if ( priv - > last_visible_child )
2013-11-01 05:49:29 +00:00
{
int x , y ;
2017-06-28 06:19:35 +00:00
int width , height ;
2013-04-21 11:51:14 +00:00
2017-12-06 06:56:12 +00:00
width = gtk_widget_get_width ( widget ) ;
height = gtk_widget_get_height ( widget ) ;
2013-04-22 00:17:40 +00:00
2017-06-04 15:30:40 +00:00
x = get_bin_window_x ( stack ) ;
y = get_bin_window_y ( stack ) ;
2013-04-22 00:17:40 +00:00
2017-10-06 19:19:42 +00:00
switch ( ( guint ) priv - > active_transition_type )
2013-11-01 05:49:29 +00:00
{
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT :
2017-06-28 06:19:35 +00:00
x - = width ;
2013-11-01 05:49:29 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT :
2017-06-28 06:19:35 +00:00
x + = width ;
2013-11-01 05:49:29 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP :
2017-06-28 06:19:35 +00:00
y - = height ;
2013-11-01 05:49:29 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN :
2017-06-28 06:19:35 +00:00
y + = height ;
2013-11-01 05:49:29 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_OVER_UP :
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN :
y = 0 ;
break ;
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT :
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT :
x = 0 ;
break ;
default :
g_assert_not_reached ( ) ;
break ;
}
2013-11-01 05:51:27 +00:00
2018-09-26 20:59:59 +00:00
if ( priv - > last_visible_child ! = NULL )
{
if ( gtk_widget_get_valign ( priv - > last_visible_child - > widget ) = = GTK_ALIGN_END & &
priv - > last_visible_widget_height > height )
y - = priv - > last_visible_widget_height - height ;
else if ( gtk_widget_get_valign ( priv - > last_visible_child - > widget ) = = GTK_ALIGN_CENTER )
y - = ( priv - > last_visible_widget_height - height ) / 2 ;
}
2015-05-24 19:27:33 +00:00
2019-02-21 04:34:12 +00:00
gtk_snapshot_save ( snapshot ) ;
gtk_snapshot_translate ( snapshot , & GRAPHENE_POINT_INIT ( x , y ) ) ;
2020-06-12 19:40:34 +00:00
gtk_widget_snapshot_child ( widget , priv - > last_visible_child - > widget , snapshot ) ;
2019-02-21 04:34:12 +00:00
gtk_snapshot_restore ( snapshot ) ;
2013-04-21 11:51:14 +00:00
}
2017-01-07 16:02:20 +00:00
gtk_widget_snapshot_child ( widget ,
priv - > visible_child - > widget ,
snapshot ) ;
2013-04-21 11:51:14 +00:00
}
2016-12-13 08:45:09 +00:00
static void
gtk_stack_snapshot ( GtkWidget * widget ,
GtkSnapshot * snapshot )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2015-12-09 04:03:38 +00:00
2013-06-13 18:50:41 +00:00
if ( priv - > visible_child )
2013-04-21 11:51:14 +00:00
{
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) ! = GTK_PROGRESS_STATE_AFTER )
2013-04-21 11:51:14 +00:00
{
2016-12-13 08:45:09 +00:00
gtk_snapshot_push_clip ( snapshot ,
& GRAPHENE_RECT_INIT (
0 , 0 ,
2017-12-06 06:56:12 +00:00
gtk_widget_get_width ( widget ) ,
gtk_widget_get_height ( widget )
2018-04-24 01:17:23 +00:00
) ) ;
2016-01-21 00:44:47 +00:00
2013-04-21 18:22:35 +00:00
switch ( priv - > active_transition_type )
2013-04-21 11:51:14 +00:00
{
case GTK_STACK_TRANSITION_TYPE_CROSSFADE :
2020-06-12 19:40:34 +00:00
gtk_stack_snapshot_crossfade ( widget , snapshot ) ;
2013-04-21 11:51:14 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT :
case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT :
2013-04-22 00:17:40 +00:00
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP :
case GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN :
2013-08-31 16:00:47 +00:00
case GTK_STACK_TRANSITION_TYPE_OVER_UP :
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN :
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT :
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT :
2016-12-13 08:45:09 +00:00
gtk_stack_snapshot_slide ( widget , snapshot ) ;
2013-04-21 11:51:14 +00:00
break ;
2013-08-31 16:00:47 +00:00
case GTK_STACK_TRANSITION_TYPE_UNDER_UP :
case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN :
case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT :
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT :
2020-06-12 19:40:34 +00:00
gtk_stack_snapshot_under ( widget , snapshot ) ;
2013-08-31 16:00:47 +00:00
break ;
2019-03-05 19:44:45 +00:00
case GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT :
case GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT :
2020-06-12 19:40:34 +00:00
gtk_stack_snapshot_cube ( widget , snapshot ) ;
2019-03-05 19:44:45 +00:00
break ;
2017-10-06 19:19:42 +00:00
case GTK_STACK_TRANSITION_TYPE_NONE :
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT :
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN :
case GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN :
case GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP :
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT :
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT :
2019-03-05 19:44:45 +00:00
case GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT_RIGHT :
2013-04-21 11:51:14 +00:00
default :
g_assert_not_reached ( ) ;
}
2017-01-12 23:39:59 +00:00
gtk_snapshot_pop ( snapshot ) ;
2013-04-21 11:51:14 +00:00
}
2016-11-22 18:31:03 +00:00
else
2017-01-07 16:02:20 +00:00
gtk_widget_snapshot_child ( widget ,
priv - > visible_child - > widget ,
snapshot ) ;
2013-04-21 11:51:14 +00:00
}
}
static void
2018-08-16 04:53:03 +00:00
gtk_stack_size_allocate ( GtkWidget * widget ,
int width ,
int height ,
int baseline )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2015-12-09 04:03:38 +00:00
GtkAllocation child_allocation ;
2013-04-21 11:51:14 +00:00
if ( priv - > last_visible_child )
2016-03-19 02:27:31 +00:00
{
2020-06-12 19:40:34 +00:00
int child_width , child_height ;
2016-03-19 02:27:31 +00:00
int min , nat ;
2016-11-12 17:58:18 +00:00
gtk_widget_measure ( priv - > last_visible_child - > widget , GTK_ORIENTATION_HORIZONTAL ,
- 1 ,
& min , & nat , NULL , NULL ) ;
2020-06-12 19:40:34 +00:00
child_width = MAX ( min , width ) ;
2016-11-12 17:58:18 +00:00
gtk_widget_measure ( priv - > last_visible_child - > widget , GTK_ORIENTATION_VERTICAL ,
2020-06-19 03:58:09 +00:00
child_width ,
2016-11-12 17:58:18 +00:00
& min , & nat , NULL , NULL ) ;
2020-06-12 19:40:34 +00:00
child_height = MAX ( min , height ) ;
2016-10-28 10:51:03 +00:00
2020-06-12 19:40:34 +00:00
gtk_widget_size_allocate ( priv - > last_visible_child - > widget ,
& ( GtkAllocation ) { 0 , 0 , child_width , child_height } , - 1 ) ;
2016-03-19 02:27:31 +00:00
}
2013-04-21 11:51:14 +00:00
2020-06-19 03:58:09 +00:00
child_allocation . x = get_bin_window_x ( stack ) ;
child_allocation . y = get_bin_window_y ( stack ) ;
2018-08-16 04:53:03 +00:00
child_allocation . width = width ;
child_allocation . height = height ;
2016-02-26 20:58:36 +00:00
2013-04-21 11:51:14 +00:00
if ( priv - > visible_child )
2015-05-24 19:27:33 +00:00
{
2016-10-28 10:56:36 +00:00
int min_width ;
int min_height ;
2015-05-30 13:43:56 +00:00
2016-10-28 10:56:36 +00:00
gtk_widget_measure ( priv - > visible_child - > widget , GTK_ORIENTATION_HORIZONTAL ,
2018-08-16 04:53:03 +00:00
height , & min_width , NULL , NULL , NULL ) ;
2016-10-28 10:56:36 +00:00
child_allocation . width = MAX ( child_allocation . width , min_width ) ;
gtk_widget_measure ( priv - > visible_child - > widget , GTK_ORIENTATION_VERTICAL ,
child_allocation . width , & min_height , NULL , NULL , NULL ) ;
child_allocation . height = MAX ( child_allocation . height , min_height ) ;
2018-08-16 04:53:03 +00:00
if ( child_allocation . width > width )
2015-07-19 15:39:41 +00:00
{
2016-10-28 10:56:36 +00:00
GtkAlign halign = gtk_widget_get_halign ( priv - > visible_child - > widget ) ;
if ( halign = = GTK_ALIGN_CENTER | | halign = = GTK_ALIGN_FILL )
2018-08-16 04:53:03 +00:00
child_allocation . x = ( width - child_allocation . width ) / 2 ;
2016-10-28 10:56:36 +00:00
else if ( halign = = GTK_ALIGN_END )
2018-08-16 04:53:03 +00:00
child_allocation . x = ( width - child_allocation . width ) ;
2016-10-28 10:56:36 +00:00
}
2018-08-16 04:53:03 +00:00
if ( child_allocation . height > height )
2016-10-28 10:56:36 +00:00
{
GtkAlign valign = gtk_widget_get_valign ( priv - > visible_child - > widget ) ;
if ( valign = = GTK_ALIGN_CENTER | | valign = = GTK_ALIGN_FILL )
2018-08-16 04:53:03 +00:00
child_allocation . y = ( height - child_allocation . height ) / 2 ;
2016-10-28 10:56:36 +00:00
else if ( valign = = GTK_ALIGN_END )
2018-08-16 04:53:03 +00:00
child_allocation . y = ( height - child_allocation . height ) ;
2015-07-19 15:39:41 +00:00
}
2016-02-26 20:58:22 +00:00
2018-03-31 19:02:28 +00:00
gtk_widget_size_allocate ( priv - > visible_child - > widget , & child_allocation , - 1 ) ;
2015-05-24 19:27:33 +00:00
}
2013-04-21 11:51:14 +00:00
}
2015-12-09 04:03:38 +00:00
# define LERP(a, b, t) ((a) + (((b) - (a)) * (1.0 - (t))))
2013-04-21 11:51:14 +00:00
static void
2017-05-05 15:18:15 +00:00
gtk_stack_measure ( GtkWidget * widget ,
2015-12-09 04:03:38 +00:00
GtkOrientation orientation ,
int for_size ,
int * minimum ,
int * natural ,
int * minimum_baseline ,
2017-05-05 15:18:15 +00:00
int * natural_baseline )
2015-12-09 04:03:38 +00:00
{
2013-04-21 11:51:14 +00:00
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2019-02-06 17:54:18 +00:00
GtkStackPage * child_info ;
2013-04-21 11:51:14 +00:00
GtkWidget * child ;
gint child_min , child_nat ;
GList * l ;
2015-12-09 04:03:38 +00:00
* minimum = 0 ;
* natural = 0 ;
2013-04-21 11:51:14 +00:00
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
child_info = l - > data ;
child = child_info - > widget ;
2015-12-09 04:03:38 +00:00
if ( ( ( orientation = = GTK_ORIENTATION_VERTICAL & & ! priv - > vhomogeneous ) | |
( orientation = = GTK_ORIENTATION_HORIZONTAL & & ! priv - > hhomogeneous ) ) & &
2015-05-24 19:15:44 +00:00
priv - > visible_child ! = child_info )
2013-04-21 11:51:14 +00:00
continue ;
2015-12-09 04:03:38 +00:00
2013-04-21 11:51:14 +00:00
if ( gtk_widget_get_visible ( child ) )
{
2016-10-27 07:38:45 +00:00
gtk_widget_measure ( child , orientation , for_size , & child_min , & child_nat , NULL , NULL ) ;
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
* minimum = MAX ( * minimum , child_min ) ;
* natural = MAX ( * natural , child_nat ) ;
2013-04-21 11:51:14 +00:00
}
}
2015-12-09 04:03:38 +00:00
if ( priv - > last_visible_child ! = NULL )
2013-04-21 11:51:14 +00:00
{
2015-12-09 04:03:38 +00:00
if ( orientation = = GTK_ORIENTATION_VERTICAL & & ! priv - > vhomogeneous )
{
2016-03-01 06:24:39 +00:00
gdouble t = priv - > interpolate_size ? gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) : 1.0 ;
2015-12-09 04:03:38 +00:00
* minimum = LERP ( * minimum , priv - > last_visible_widget_height , t ) ;
* natural = LERP ( * natural , priv - > last_visible_widget_height , t ) ;
}
if ( orientation = = GTK_ORIENTATION_HORIZONTAL & & ! priv - > hhomogeneous )
{
2016-03-01 06:24:39 +00:00
gdouble t = priv - > interpolate_size ? gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) : 1.0 ;
2015-12-09 04:03:38 +00:00
* minimum = LERP ( * minimum , priv - > last_visible_widget_width , t ) ;
* natural = LERP ( * natural , priv - > last_visible_widget_width , t ) ;
}
2013-04-21 11:51:14 +00:00
}
}
static void
2015-12-09 04:03:38 +00:00
gtk_stack_init ( GtkStack * stack )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
priv - > vhomogeneous = TRUE ;
priv - > hhomogeneous = TRUE ;
priv - > transition_duration = 200 ;
priv - > transition_type = GTK_STACK_TRANSITION_TYPE_NONE ;
2013-04-21 11:51:14 +00:00
}
2019-02-10 23:22:54 +00:00
/**
* gtk_stack_get_pages :
* @ stack : a # GtkStack
*
* Returns a # GListModel that contains the pages of the stack ,
2020-06-15 08:30:40 +00:00
* and can be used to keep an up - to - date view . The model also
2019-02-10 23:22:54 +00:00
* implements # GtkSelectionModel and can be used to track and
2020-06-15 08:30:40 +00:00
* modify the visible page .
2019-02-10 23:22:54 +00:00
*
* Returns : ( transfer full ) : a # GtkSelectionModel for the stack ' s children
*/
GtkSelectionModel *
gtk_stack_get_pages ( GtkStack * stack )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
if ( priv - > pages )
return g_object_ref ( priv - > pages ) ;
priv - > pages = GTK_SELECTION_MODEL ( gtk_stack_pages_new ( stack ) ) ;
g_object_add_weak_pointer ( G_OBJECT ( priv - > pages ) , ( gpointer * ) & priv - > pages ) ;
return priv - > pages ;
}
2020-02-18 08:27:42 +00:00
/**
* gtk_stack_page_get_visible :
* @ page : a # GtkStackPage
*
* Returns whether @ page is visible in its # GtkStack .
* This is independent from the # GtkWidget : visible value of its
* # GtkWidget .
*/
gboolean
2020-06-18 05:55:22 +00:00
gtk_stack_page_get_visible ( GtkStackPage * self )
2020-02-18 08:27:42 +00:00
{
2020-06-18 05:55:22 +00:00
g_return_val_if_fail ( GTK_IS_STACK_PAGE ( self ) , FALSE ) ;
2020-02-18 08:27:42 +00:00
2020-06-18 05:55:22 +00:00
return self - > visible ;
2020-02-18 08:27:42 +00:00
}
/**
* gtk_stack_page_set_visible :
* @ page : a # GtkStackPage
* @ visible : The new property value
*
* Sets the new value of the # GtkStackPage : visible property
* to @ visible .
*/
void
2020-06-18 05:55:22 +00:00
gtk_stack_page_set_visible ( GtkStackPage * self ,
2020-02-18 08:27:42 +00:00
gboolean visible )
{
2020-06-18 05:55:22 +00:00
g_return_if_fail ( GTK_IS_STACK_PAGE ( self ) ) ;
2020-02-18 08:27:42 +00:00
visible = ! ! visible ;
2020-06-18 05:55:22 +00:00
if ( visible = = self - > visible )
return ;
self - > visible = visible ;
g_object_notify_by_pspec ( G_OBJECT ( self ) , stack_page_props [ CHILD_PROP_VISIBLE ] ) ;
}
/**
* gtk_stack_page_get_needs_attention :
* @ self : a # GtkStackPage
*
* Returns the current value of the # GtkStackPage : needs - attention property .
*
* Returns : The value of the # GtkStackPage : needs - attention property .
* See gtk_stack_page_set_needs_attention ( ) for details on how to set a new value .
*/
gboolean
gtk_stack_page_get_needs_attention ( GtkStackPage * self )
{
return self - > needs_attention ;
}
/**
* gtk_stack_page_set_needs_attention :
* @ self : a # GtkStackPage
* @ setting : the new value to set
*
* Sets the new value of the # GtkStackPage : needs - attention property .
* See also gtk_stack_page_get_needs_attention ( )
*
*/
void
gtk_stack_page_set_needs_attention ( GtkStackPage * self ,
gboolean setting )
{
setting = ! ! setting ;
if ( setting = = self - > needs_attention )
return ;
self - > needs_attention = setting ;
g_object_notify_by_pspec ( G_OBJECT ( self ) , stack_page_props [ CHILD_PROP_NEEDS_ATTENTION ] ) ;
}
/**
* gtk_stack_page_get_use_underline :
* @ self : a # GtkStackPage
*
* Returns the current value of the # GtkStackPage : use - underline property .
*
* Returns : The value of the # GtkStackPage : use - underline property .
* See gtk_stack_page_set_use_underline ( ) for details on how to set a new value .
*/
gboolean
gtk_stack_page_get_use_underline ( GtkStackPage * self )
{
return self - > use_underline ;
}
/**
* gtk_stack_page_set_use_underline :
* @ self : a # GtkStackPage
* @ setting : the new value to set
*
* Sets the new value of the # GtkStackPage : use - underline property .
* See also gtk_stack_page_get_use_underline ( )
*
*/
void
gtk_stack_page_set_use_underline ( GtkStackPage * self ,
gboolean setting )
{
setting = ! ! setting ;
if ( setting = = self - > use_underline )
return ;
self - > use_underline = setting ;
g_object_notify_by_pspec ( G_OBJECT ( self ) , stack_page_props [ CHILD_PROP_USE_UNDERLINE ] ) ;
}
/**
* gtk_stack_page_get_name :
* @ self : a # GtkStackPage
*
* Returns the current value of the # GtkStackPage : name property .
*
* Returns : ( nullable ) : The value of the # GtkStackPage : name property .
* See gtk_stack_page_set_name ( ) for details on how to set a new value .
*/
const char *
gtk_stack_page_get_name ( GtkStackPage * self )
{
g_return_val_if_fail ( GTK_IS_STACK_PAGE ( self ) , NULL ) ;
return self - > name ;
}
/**
* gtk_stack_page_set_name :
* @ self : a # GtkStackPage
* @ setting : ( transfer none ) : the new value to set
*
* Sets the new value of the # GtkStackPage : name property .
* See also gtk_stack_page_get_name ( )
*/
void
gtk_stack_page_set_name ( GtkStackPage * self ,
const char * setting )
{
GtkStack * stack = NULL ;
GtkStackPrivate * priv = NULL ;
g_return_if_fail ( GTK_IS_STACK_PAGE ( self ) ) ;
if ( self - > widget & &
gtk_widget_get_parent ( self - > widget ) & &
GTK_IS_STACK ( gtk_widget_get_parent ( self - > widget ) ) )
2020-02-18 08:27:42 +00:00
{
2020-06-18 05:55:22 +00:00
GList * l ;
2020-02-18 08:27:42 +00:00
2020-06-18 05:55:22 +00:00
stack = GTK_STACK ( gtk_widget_get_parent ( self - > widget ) ) ;
priv = gtk_stack_get_instance_private ( stack ) ;
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
GtkStackPage * info2 = l - > data ;
if ( self = = info2 )
continue ;
if ( g_strcmp0 ( info2 - > name , setting ) = = 0 )
{
g_warning ( " Duplicate child name in GtkStack: %s " , setting ) ;
break ;
}
}
2020-02-18 08:27:42 +00:00
}
2020-06-18 05:55:22 +00:00
if ( setting = = self - > name )
return ;
g_free ( self - > name ) ;
self - > name = g_strdup ( setting ) ;
g_object_notify_by_pspec ( G_OBJECT ( self ) , stack_page_props [ CHILD_PROP_NAME ] ) ;
if ( priv & & priv - > visible_child = = self )
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_VISIBLE_CHILD_NAME ] ) ;
}
/**
* gtk_stack_page_get_title :
* @ self : a # GtkStackPage
*
* Returns the current value of the # GtkStackPage : title property .
*
* Returns : ( nullable ) : The value of the # GtkStackPage : title property .
* See gtk_stack_page_set_title ( ) for details on how to set a new value .
*/
const char *
gtk_stack_page_get_title ( GtkStackPage * self )
{
g_return_val_if_fail ( GTK_IS_STACK_PAGE ( self ) , NULL ) ;
return self - > title ;
}
/**
* gtk_stack_page_set_title :
* @ self : a # GtkStackPage
* @ setting : ( transfer none ) : the new value to set
*
* Sets the new value of the # GtkStackPage : title property .
* See also gtk_stack_page_get_title ( )
*/
void
gtk_stack_page_set_title ( GtkStackPage * self ,
const char * setting )
{
g_return_if_fail ( GTK_IS_STACK_PAGE ( self ) ) ;
if ( setting = = self - > title )
return ;
g_free ( self - > title ) ;
self - > title = g_strdup ( setting ) ;
g_object_notify_by_pspec ( G_OBJECT ( self ) , stack_page_props [ CHILD_PROP_TITLE ] ) ;
}
/**
* gtk_stack_page_get_icon_name :
* @ self : a # GtkStackPage
*
* Returns the current value of the # GtkStackPage : icon - name property .
*
* Returns : ( nullable ) : The value of the # GtkStackPage : icon - name property .
* See gtk_stack_page_set_icon_name ( ) for details on how to set a new value .
*/
const char *
gtk_stack_page_get_icon_name ( GtkStackPage * self )
{
g_return_val_if_fail ( GTK_IS_STACK_PAGE ( self ) , NULL ) ;
return self - > icon_name ;
}
/**
* gtk_stack_page_set_icon_name :
* @ self : a # GtkStackPage
* @ setting : ( transfer none ) : the new value to set
*
* Sets the new value of the # GtkStackPage : icon - name property .
* See also gtk_stack_page_get_icon_name ( )
*/
void
gtk_stack_page_set_icon_name ( GtkStackPage * self ,
const char * setting )
{
g_return_if_fail ( GTK_IS_STACK_PAGE ( self ) ) ;
if ( setting = = self - > icon_name )
return ;
g_free ( self - > icon_name ) ;
self - > icon_name = g_strdup ( setting ) ;
g_object_notify_by_pspec ( G_OBJECT ( self ) , stack_page_props [ CHILD_PROP_ICON_NAME ] ) ;
2020-02-18 08:27:42 +00:00
}