Compare commits

...

4 Commits

Author SHA1 Message Date
Jasper St. Pierre
7fb047cdc3 gtkbox: Add support for padding using the new helper APIs
Now, finally, we can have padded boxes! And look at that implementation!
That's how easy it is to add correct box model behavior to your widgets!
I'll be fixing a whole slew of these now...

Note that some reftests need fixing, not because this actually breaks
anything, but because Raleigh has a really silly style: * { padding: 2px; }
and reftests often use GtkBox to emulate other widgets like grids. We need
to add some CSS that resets all properties to make sure that this padding
isn't added to the boxes when trying to e.g. emulate grids.

Obviously, Raleigh is pretty broken here regardless, but layout tests like
this shouldn't be affected by style.

Adwaita is perfectly fine.
2013-11-01 16:51:42 -04:00
Jasper St. Pierre
810f73381f Add support for min-width, min-height, max-width and max-height
Do this through the new helper classes. Yes, this means that if the
widget isn't using the new helper methods, it won't get constrainment
support... the price we pay for backwards compatibility...
2013-11-01 16:51:32 -04:00
Jasper St. Pierre
88fd432f5a Use these new helper methods in some of the easier-to-port widgets
Namely, gtkinfobar and gtkbubblewindow.
2013-11-01 16:51:32 -04:00
Jasper St. Pierre
d047fff56b widget: Add new helper methods for implementing CSS box model semantics
Based on the approach used in gnome-shell's "St", we add a few new
helper methods so that widgets can upgrade to a CSS box model at
their own leisure, without a bunch of copy/paste code as had been
carried out in a bunch of other widgets.
2013-11-01 16:51:32 -04:00
18 changed files with 351 additions and 73 deletions

View File

@@ -1226,6 +1226,7 @@ gtk_box_get_preferred_width (GtkWidget *widget,
gint *natural_size)
{
gtk_box_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size, NULL, NULL);
_gtk_widget_adjust_preferred_width (widget, minimum_size, natural_size);
}
static void
@@ -1234,6 +1235,7 @@ gtk_box_get_preferred_height (GtkWidget *widget,
gint *natural_size)
{
gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size, NULL, NULL);
_gtk_widget_adjust_preferred_height (widget, minimum_size, natural_size);
}
static void
@@ -1528,10 +1530,14 @@ gtk_box_get_preferred_width_for_height (GtkWidget *widget,
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *private = box->priv;
_gtk_widget_adjust_for_height (widget, &height);
if (private->orientation == GTK_ORIENTATION_VERTICAL)
gtk_box_compute_size_for_opposing_orientation (box, height, minimum_width, natural_width, NULL, NULL);
else
gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width);
_gtk_widget_adjust_preferred_width (widget, minimum_width, natural_width);
}
static void
@@ -1545,6 +1551,8 @@ gtk_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *private = box->priv;
_gtk_widget_adjust_for_width (widget, &width);
if (width < 0)
gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_height, natural_height, minimum_baseline, natural_baseline);
else
@@ -1560,6 +1568,9 @@ gtk_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
}
}
_gtk_widget_adjust_preferred_height (widget, minimum_height, natural_height);
_gtk_widget_adjust_baseline (widget, minimum_baseline, natural_baseline);
}
static void

View File

@@ -40,6 +40,7 @@
#include "gtkmain.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkwidgetprivate.h"
#define TAIL_GAP_WIDTH 24
#define TAIL_HEIGHT 12
@@ -609,25 +610,6 @@ gtk_bubble_window_draw (GtkWidget *widget,
return TRUE;
}
static void
get_padding_and_border (GtkWidget *widget,
GtkBorder *border)
{
GtkStyleContext *context;
GtkStateFlags state;
GtkBorder tmp;
context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget);
gtk_style_context_get_padding (context, state, border);
gtk_style_context_get_border (context, state, &tmp);
border->top += tmp.top;
border->right += tmp.right;
border->bottom += tmp.bottom;
border->left += tmp.left;
}
static void
gtk_bubble_window_get_preferred_width (GtkWidget *widget,
gint *minimum_width,
@@ -636,7 +618,6 @@ gtk_bubble_window_get_preferred_width (GtkWidget *widget,
GtkBubbleWindowPrivate *priv;
GtkWidget *child;
gint min, nat;
GtkBorder border;
priv = GTK_BUBBLE_WINDOW (widget)->priv;
child = gtk_bin_get_child (GTK_BIN (widget));
@@ -645,10 +626,6 @@ gtk_bubble_window_get_preferred_width (GtkWidget *widget,
if (child)
gtk_widget_get_preferred_width (child, &min, &nat);
get_padding_and_border (widget, &border);
min += border.left + border.right;
nat += border.left + border.right;
if (!POS_IS_VERTICAL (priv->final_position))
{
min += TAIL_HEIGHT;
@@ -660,6 +637,8 @@ gtk_bubble_window_get_preferred_width (GtkWidget *widget,
if (natural_width)
*natural_width = MAX (nat, TAIL_GAP_WIDTH);
_gtk_widget_adjust_preferred_width (widget, minimum_width, natural_width);
}
static void
@@ -670,7 +649,6 @@ gtk_bubble_window_get_preferred_height (GtkWidget *widget,
GtkBubbleWindowPrivate *priv;
GtkWidget *child;
gint min, nat;
GtkBorder border;
priv = GTK_BUBBLE_WINDOW (widget)->priv;
child = gtk_bin_get_child (GTK_BIN (widget));
@@ -679,10 +657,6 @@ gtk_bubble_window_get_preferred_height (GtkWidget *widget,
if (child)
gtk_widget_get_preferred_height (child, &min, &nat);
get_padding_and_border (widget, &border);
min += border.top + border.bottom;
nat += border.top + border.bottom;
if (POS_IS_VERTICAL (priv->final_position))
{
min += TAIL_HEIGHT;
@@ -694,6 +668,8 @@ gtk_bubble_window_get_preferred_height (GtkWidget *widget,
if (natural_height)
*natural_height = MAX (nat, TAIL_GAP_WIDTH);
_gtk_widget_adjust_preferred_height (widget, minimum_height, natural_height);
}
static void
@@ -710,14 +686,8 @@ gtk_bubble_window_size_allocate (GtkWidget *widget,
if (child)
{
GtkAllocation child_alloc;
GtkBorder border;
get_padding_and_border (widget, &border);
child_alloc.x = border.left;
child_alloc.y = border.top;
child_alloc.width = allocation->width - border.left - border.right;
child_alloc.height = allocation->height - border.top - border.bottom;
_gtk_widget_get_content_box (widget, allocation, &child_alloc);
if (POS_IS_VERTICAL (priv->final_position))
child_alloc.height -= TAIL_HEIGHT;

View File

@@ -843,6 +843,16 @@ parse_border_width (GtkCssStyleProperty *property,
| GTK_CSS_PARSE_LENGTH);
}
static GtkCssValue *
parse_size (GtkCssStyleProperty *property,
GtkCssParser *parser)
{
return _gtk_css_number_value_parse (parser,
GTK_CSS_POSITIVE_ONLY
| GTK_CSS_NUMBER_AS_PIXELS
| GTK_CSS_PARSE_LENGTH);
}
static GtkCssValue *
background_repeat_value_parse_one (GtkCssParser *parser)
{
@@ -975,6 +985,39 @@ _gtk_css_style_property_init_properties (void)
NULL,
_gtk_css_shadows_value_new_none ());
gtk_css_style_property_register ("min-width",
GTK_CSS_PROPERTY_MIN_WIDTH,
G_TYPE_INT,
GTK_STYLE_PROPERTY_ANIMATED,
parse_size,
query_length_as_int,
assign_length_from_int,
_gtk_css_number_value_new (0.0, GTK_CSS_PX));
gtk_css_style_property_register ("min-height",
GTK_CSS_PROPERTY_MIN_HEIGHT,
G_TYPE_INT,
GTK_STYLE_PROPERTY_ANIMATED,
parse_size,
query_length_as_int,
assign_length_from_int,
_gtk_css_number_value_new (0.0, GTK_CSS_PX));
gtk_css_style_property_register ("max-width",
GTK_CSS_PROPERTY_MAX_WIDTH,
G_TYPE_INT,
GTK_STYLE_PROPERTY_ANIMATED,
parse_size,
query_length_as_int,
assign_length_from_int,
_gtk_css_number_value_new (G_MAXDOUBLE, GTK_CSS_PX));
gtk_css_style_property_register ("max-height",
GTK_CSS_PROPERTY_MAX_HEIGHT,
G_TYPE_INT,
GTK_STYLE_PROPERTY_ANIMATED,
parse_size,
query_length_as_int,
assign_length_from_int,
_gtk_css_number_value_new (G_MAXDOUBLE, GTK_CSS_PX));
gtk_css_style_property_register ("margin-top",
GTK_CSS_PROPERTY_MARGIN_TOP,
G_TYPE_INT,

View File

@@ -82,6 +82,10 @@ enum { /*< skip >*/
GTK_CSS_PROPERTY_TEXT_SHADOW,
GTK_CSS_PROPERTY_ICON_SHADOW,
GTK_CSS_PROPERTY_BOX_SHADOW,
GTK_CSS_PROPERTY_MIN_WIDTH,
GTK_CSS_PROPERTY_MIN_HEIGHT,
GTK_CSS_PROPERTY_MAX_WIDTH,
GTK_CSS_PROPERTY_MAX_HEIGHT,
GTK_CSS_PROPERTY_MARGIN_TOP,
GTK_CSS_PROPERTY_MARGIN_LEFT,
GTK_CSS_PROPERTY_MARGIN_BOTTOM,

View File

@@ -47,6 +47,7 @@
#include "gtkorientable.h"
#include "gtktypebuiltins.h"
#include "deprecated/gtkstock.h"
#include "gtkwidgetprivate.h"
/**
* SECTION:gtkinfobar
@@ -302,42 +303,15 @@ gtk_info_bar_close (GtkInfoBar *info_bar)
GTK_RESPONSE_CANCEL);
}
static void
get_padding_and_border (GtkWidget *widget,
GtkBorder *border)
{
GtkStyleContext *context;
GtkStateFlags state;
GtkBorder tmp;
context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget);
gtk_style_context_get_padding (context, state, border);
gtk_style_context_get_border (context, state, &tmp);
border->top += tmp.top;
border->right += tmp.right;
border->bottom += tmp.bottom;
border->left += tmp.left;
}
static void
gtk_info_bar_get_preferred_width (GtkWidget *widget,
gint *minimum_width,
gint *natural_width)
{
GtkBorder border;
get_padding_and_border (widget, &border);
GTK_WIDGET_CLASS (gtk_info_bar_parent_class)->get_preferred_width (widget,
minimum_width,
natural_width);
if (minimum_width)
*minimum_width += border.left + border.right;
if (natural_width)
*natural_width += border.left + border.right;
_gtk_widget_adjust_preferred_width (widget, minimum_width, natural_width);
}
static void
@@ -345,18 +319,10 @@ gtk_info_bar_get_preferred_height (GtkWidget *widget,
gint *minimum_height,
gint *natural_height)
{
GtkBorder border;
get_padding_and_border (widget, &border);
GTK_WIDGET_CLASS (gtk_info_bar_parent_class)->get_preferred_height (widget,
minimum_height,
natural_height);
if (minimum_height)
*minimum_height += border.top + border.bottom;
if (natural_height)
*natural_height += border.top + border.bottom;
_gtk_widget_adjust_preferred_width (widget, minimum_height, natural_height);
}
static gboolean

View File

@@ -16011,3 +16011,251 @@ gtk_widget_get_template_child (GtkWidget *widget,
return ret;
}
static int
get_width_inc (GtkStyleContext *context)
{
return (_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_LEFT), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_RIGHT), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 0));
}
static int
get_height_inc (GtkStyleContext *context)
{
return (_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_TOP), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_BOTTOM), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 0));
}
static int
get_content_offset_x (GtkStyleContext *context)
{
return (_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_LEFT), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 0));
}
static int
get_content_offset_y (GtkStyleContext *context)
{
return (_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_TOP), 0) +
_gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 0));
}
static void
constrain_width (GtkStyleContext *context,
int *width)
{
double min_width, max_width;
if (!width)
return;
min_width = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_MIN_WIDTH), 0);
max_width = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_MAX_WIDTH), 0);
if (*width < min_width)
*width = min_width;
if (*width > max_width)
*width = max_width;
}
static void
constrain_height (GtkStyleContext *context,
int *height)
{
double min_height, max_height;
if (!height)
return;
min_height = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_MIN_HEIGHT), 0);
max_height = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_MAX_HEIGHT), 0);
if (*height < min_height)
*height = min_height;
if (*height > max_height)
*height = max_height;
}
/**
* _gtk_widget_get_context_box:
* @context: A #GtkWidget
* @box: The input allocation
* @content_box: (out): The content box for the widget
*
* Given an input allocation, @box, this calculates the "context box"
* in CSS box model terms. Currently this simply subtracts padding
* and border from the input allocation, but in the future could be
* expanded to reflect the addition of a 'box-sizing' property in CSS.
*
* This is meant as a helper method for widgets to use in their
* size_allocate() implementation.
*
* Since: 3.12
*/
void
_gtk_widget_get_content_box (GtkWidget *widget,
const GtkAllocation *box,
GtkAllocation *content_box)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
content_box->x = get_content_offset_x (context);
content_box->y = get_content_offset_y (context);
content_box->width = box->width;
content_box->height = box->height;
constrain_width (context, &content_box->width);
constrain_height (context, &content_box->height);
content_box->width -= get_width_inc (context);
content_box->height -= get_height_inc (context);
if (content_box->width < 0)
content_box->width = 0;
if (content_box->height < 0)
content_box->height = 0;
}
/**
* _gtk_widget_adjust_for_width:
* @widget: A #GtkWidget
* @for_width: (inout): The width request
*
* Adjusts @for_width to remove elements outside the content box,
* such as padding and border.
*
* This is meant as a helper method for widgets to use at the top
* of their get_preferred_height_for_width() implementation.
*
* Since: 3.12
*/
void
_gtk_widget_adjust_for_width (GtkWidget *widget,
int *for_width)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
if (*for_width >= 0)
*for_width = MAX (0, *for_width - get_width_inc (context));
}
/**
* _gtk_widget_adjust_preferred_width:
* @widget: A #GtkWidget
* @minimum_width: (inout): The minimum width
* @natural_width: (inout): The natural width
*
* Adjusts @minimum_width and @natural_width to include elements
* outside the content box, such as padding and border.
*
* This is meant as a helper method for widgets to use at the bottom
* of their get_preferred_width() and get_preferred_width_for_height()
* implementations: simply calculate the width required for the
* content, and adjust it with this method to make sure you've
* calculated everything correctly.
*
* Since: 3.12
*/
void
_gtk_widget_adjust_preferred_width (GtkWidget *widget,
int *minimum_width,
int *natural_width)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
int width_inc = get_width_inc (context);
if (minimum_width)
*minimum_width += width_inc;
if (natural_width)
*natural_width += width_inc;
constrain_width (context, minimum_width);
constrain_width (context, natural_width);
}
/**
* _gtk_widget_adjust_for_height:
* @widget: A #GtkWidget
* @for_height: (inout): The height request
*
* Adjusts @for_height to remove elements outside the content box.
*
* This is meant as a helper method for widgets to use at the top
* of their get_preferred_width_for_height() implementation.
*
* Since: 3.12
*/
void
_gtk_widget_adjust_for_height (GtkWidget *widget,
int *for_height)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
if (*for_height >= 0)
*for_height = MAX (0, *for_height - get_height_inc (context));
}
/**
* _gtk_widget_adjust_preferred_height:
* @widget: A #GtkWidget
* @minimum_height: (inout): The minimum height
* @natural_height: (inout): The natural height
*
* Adjusts @minimum_height and @natural_height to include elements
* outside the content box, such as padding and border.
*
* This is meant as a helper method for widgets to use at the bottom
* of their get_preferred_height() and get_preferred_height_for_width()
* implementations: simply calculate the height required for the
* content, and adjust it with this method to make sure you've
* calculated everything correctly.
*
* Since: 3.12
*/
void
_gtk_widget_adjust_preferred_height (GtkWidget *widget,
int *minimum_height,
int *natural_height)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
int height_inc = get_height_inc (context);
if (minimum_height)
*minimum_height += height_inc;
if (natural_height)
*natural_height += height_inc;
constrain_height (context, minimum_height);
constrain_height (context, natural_height);
}
/**
* _gtk_widget_adjust_baseline:
* @widget: A #GtkWidget
* @minimum_baseline: (inout): The minimum baseline
* @natural_baseline: (inout): The natural baseline
*
* Adjusts @minimum_baseline and @natural_baseline to include elements
* outside the content box, such as padding and border.
*
* This is meant as a helper method for widgets to use at the bottom
* of their get_preferred_height_and_baseline_for_width() implementation.
*
* Since: 3.12
*/
void
_gtk_widget_adjust_baseline (GtkWidget *widget,
int *minimum_baseline,
int *natural_baseline)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
int offset_y = get_content_offset_y (context);
if (minimum_baseline && *minimum_baseline >= 0)
*minimum_baseline += offset_y;
if (natural_baseline && *natural_baseline >= 0)
*natural_baseline += offset_y;
}

View File

@@ -149,6 +149,23 @@ void _gtk_widget_style_context_invalidated (GtkWidget *widget
void _gtk_widget_update_parent_muxer (GtkWidget *widget);
GtkActionMuxer * _gtk_widget_get_action_muxer (GtkWidget *widget);
void _gtk_widget_get_content_box (GtkWidget *widget,
const GtkAllocation *box,
GtkAllocation *content_box);
void _gtk_widget_adjust_for_width (GtkWidget *widget,
int *for_width);
void _gtk_widget_adjust_preferred_width (GtkWidget *widget,
int *minimum_width,
int *natural_width);
void _gtk_widget_adjust_for_height (GtkWidget *widget,
int *for_height);
void _gtk_widget_adjust_preferred_height (GtkWidget *widget,
int *minimum_height,
int *natural_height);
void _gtk_widget_adjust_baseline (GtkWidget *widget,
int *minimum_baseline,
int *natural_baseline);
G_END_DECLS
#endif /* __GTK_WIDGET_PRIVATE_H__ */

View File

@@ -115,6 +115,7 @@ testdata = \
border-style.css \
border-style.ref.ui \
border-style.ui \
box-child-expand.css \
box-child-expand.ref.ui \
box-child-expand.ui \
box-packing.css \
@@ -197,8 +198,10 @@ testdata = \
grid-homogeneous.css \
grid-homogeneous.ref.ui \
grid-homogeneous.ui \
grid-spacing1.css \
grid-spacing1.ref.ui \
grid-spacing1.ui \
grid-spacing2.css \
grid-spacing2.ref.ui \
grid-spacing2.ui \
grid-spacing3.css \
@@ -273,6 +276,7 @@ testdata = \
reset-to-defaults.css \
rotated-layout.ref.ui \
rotated-layout.ui \
separator-size.css \
separator-size.ref.ui \
separator-size.ui \
shorthand-entry-border.css \
@@ -283,6 +287,7 @@ testdata = \
sizegroups-basics.css \
sizegroups-basics.ui \
sizegroups-basics.ref.ui \
sizegroups-evolution-identity-page.css \
sizegroups-evolution-identity-page.ui \
sizegroups-evolution-identity-page.ref.ui \
sizegroups-get-preferred-null.ui \

View File

@@ -0,0 +1 @@
@import "reset-to-defaults.css";

View File

@@ -1,3 +1,5 @@
@import "reset-to-defaults.css";
#red {
background-color: red;
}

View File

@@ -0,0 +1 @@
@import "reset-to-defaults.css";

View File

@@ -0,0 +1 @@
@import "reset-to-defaults.css";

View File

@@ -1,3 +1,5 @@
@import "reset-to-defaults.css";
#red {
background-color: red;
}

View File

@@ -1,3 +1,5 @@
@import "reset-to-defaults.css";
GtkBox > :nth-child(1) {
-gtk-image-effect: none;
}

View File

@@ -1,3 +1,5 @@
@import "reset-to-defaults.css";
/* For nth-child, we have a custom rule for every multiple of
* the prime numbers.
* For nth-last-child, we also color the prime number itself.

View File

@@ -0,0 +1 @@
@import "reset-to-defaults.css";

View File

@@ -0,0 +1 @@
@import "reset-to-defaults.css";

View File

@@ -0,0 +1 @@
@import "reset-to-defaults.css";