Compare commits
39 Commits
matthiasc/
...
wip/baeder
Author | SHA1 | Date | |
---|---|---|---|
|
59aede163f | ||
|
427457f030 | ||
|
b2351f8fef | ||
|
c73e0709e4 | ||
|
8bafd03cdd | ||
|
ea94dab6d3 | ||
|
17f6169ac3 | ||
|
e2094ee517 | ||
|
6f06d5b8b8 | ||
|
06a8dd7cb1 | ||
|
fc2ce9a39a | ||
|
6e2f024285 | ||
|
87bca8399b | ||
|
64558335b1 | ||
|
fcfab338ec | ||
|
cdbb8d1e0f | ||
|
bcd6f0b75f | ||
|
57cd3391f6 | ||
|
63ef6a06f6 | ||
|
cf0d69d90e | ||
|
1345839921 | ||
|
88278e84d2 | ||
|
1f1be208a4 | ||
|
997e4381e1 | ||
|
13d9848da7 | ||
|
a80a17deba | ||
|
cce4acab90 | ||
|
7c8b1fd6d1 | ||
|
3e646ec6ca | ||
|
43ac1e7ca1 | ||
|
edd8183a2c | ||
|
379efea52c | ||
|
530d5493ec | ||
|
bd410a2da8 | ||
|
2a7fc5f24e | ||
|
0a938cca39 | ||
|
07e48d3972 | ||
|
4d3a07c516 | ||
|
020857e347 |
@@ -4409,6 +4409,7 @@ GtkTickCallback
|
||||
gtk_widget_add_tick_callback
|
||||
gtk_widget_remove_tick_callback
|
||||
gtk_widget_size_allocate
|
||||
gtk_widget_size_allocate_transformed
|
||||
gtk_widget_add_accelerator
|
||||
gtk_widget_remove_accelerator
|
||||
gtk_widget_set_accel_path
|
||||
|
@@ -134,16 +134,27 @@ print_render_node_tree (GskRenderNode *root, int level)
|
||||
static void G_GNUC_UNUSED
|
||||
dump_framebuffer (const char *filename, int w, int h)
|
||||
{
|
||||
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
|
||||
const int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
|
||||
guchar *data = g_malloc (h * stride);
|
||||
guchar *flipped = g_malloc (h * stride);
|
||||
cairo_surface_t *s;
|
||||
int i;
|
||||
|
||||
glReadPixels (0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, data);
|
||||
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, w, h, stride);
|
||||
for (i = 0; i < h; i ++)
|
||||
{
|
||||
memcpy (flipped + (stride * i),
|
||||
data + ((h - 1 - i) * stride),
|
||||
stride);
|
||||
|
||||
}
|
||||
g_free (data);
|
||||
|
||||
s = cairo_image_surface_create_for_data (flipped, CAIRO_FORMAT_ARGB32, w, h, stride);
|
||||
cairo_surface_write_to_png (s, filename);
|
||||
|
||||
cairo_surface_destroy (s);
|
||||
g_free (data);
|
||||
g_free (flipped);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -464,11 +475,11 @@ render_text_node (GskGLRenderer *self,
|
||||
const PangoFont *font = gsk_text_node_peek_font (node);
|
||||
const PangoGlyphInfo *glyphs = gsk_text_node_peek_glyphs (node);
|
||||
const float text_scale = ops_get_scale (builder);
|
||||
guint num_glyphs = gsk_text_node_get_num_glyphs (node);
|
||||
const guint num_glyphs = gsk_text_node_get_num_glyphs (node);
|
||||
const float x = gsk_text_node_get_x (node) + builder->dx;
|
||||
const float y = gsk_text_node_get_y (node) + builder->dy;
|
||||
int i;
|
||||
int x_position = 0;
|
||||
float x = gsk_text_node_get_x (node) + builder->dx;
|
||||
float y = gsk_text_node_get_y (node) + builder->dy;
|
||||
|
||||
/* If the font has color glyphs, we don't need to recolor anything */
|
||||
if (!force_color && font_has_color_glyphs (font))
|
||||
@@ -481,8 +492,6 @@ render_text_node (GskGLRenderer *self,
|
||||
ops_set_color (builder, color);
|
||||
}
|
||||
|
||||
/* We use one quad per character, unlike the other nodes which
|
||||
* use at most one quad altogether */
|
||||
for (i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
const PangoGlyphInfo *gi = &glyphs[i];
|
||||
@@ -811,35 +820,54 @@ render_transform_node (GskGLRenderer *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
const float min_x = node->bounds.origin.x;
|
||||
const float min_y = node->bounds.origin.y;
|
||||
const float max_x = min_x + node->bounds.size.width;
|
||||
const float max_y = min_y + node->bounds.size.height;
|
||||
const GskQuadVertex vertex_data[GL_N_VERTICES] = {
|
||||
{ { min_x, min_y }, { 0, 1 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
|
||||
{ { max_x, max_y }, { 1, 0 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
};
|
||||
const float min_x = child->bounds.origin.x;
|
||||
const float min_y = child->bounds.origin.y;
|
||||
const float max_x = min_x + child->bounds.size.width;
|
||||
const float max_y = min_y + child->bounds.size.height;
|
||||
int texture_id;
|
||||
gboolean is_offscreen;
|
||||
/* For non-trivial transforms, we draw everything on a texture and then
|
||||
* draw the texture transformed. */
|
||||
|
||||
/* TODO: We should compute a modelview containing only the "non-trivial"
|
||||
* part (e.g. the rotation) and use that. We want to keep the scale
|
||||
* for the texture.
|
||||
*/
|
||||
|
||||
add_offscreen_ops (self, builder,
|
||||
&node->bounds,
|
||||
&child->bounds,
|
||||
child,
|
||||
&texture_id, &is_offscreen,
|
||||
&texture_id,
|
||||
&is_offscreen,
|
||||
RESET_CLIP | RESET_OPACITY);
|
||||
ops_set_texture (builder, texture_id);
|
||||
ops_set_program (builder, &self->blit_program);
|
||||
ops_draw (builder, vertex_data);
|
||||
|
||||
if (is_offscreen)
|
||||
{
|
||||
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
|
||||
{ { min_x, min_y }, { 0, 1 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
|
||||
{ { max_x, max_y }, { 1, 0 }, },
|
||||
{ { min_x, max_y }, { 0, 0 }, },
|
||||
{ { max_x, min_y }, { 1, 1 }, },
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
|
||||
{ { min_x, min_y }, { 0, 0 }, },
|
||||
{ { min_x, max_y }, { 0, 1 }, },
|
||||
{ { max_x, min_y }, { 1, 0 }, },
|
||||
|
||||
{ { max_x, max_y }, { 1, 1 }, },
|
||||
{ { min_x, max_y }, { 0, 1 }, },
|
||||
{ { max_x, min_y }, { 1, 0 }, },
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
ops_pop_modelview (builder);
|
||||
}
|
||||
|
@@ -961,7 +961,7 @@ gtk_entry_accessible_get_character_extents (AtkText *text,
|
||||
pango_layout_index_to_pos (gtk_entry_get_layout (entry), index, &char_rect);
|
||||
pango_extents_to_pixels (&char_rect, NULL);
|
||||
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
surface = gtk_widget_get_surface (widget);
|
||||
gdk_surface_get_origin (surface, &x_surface, &y_surface);
|
||||
|
@@ -1601,6 +1601,14 @@ _gtk_css_style_property_init_properties (void)
|
||||
transform_value_parse,
|
||||
NULL,
|
||||
_gtk_css_transform_value_new_none ());
|
||||
gtk_css_style_property_register ("transform",
|
||||
GTK_CSS_PROPERTY_TRANSFORM,
|
||||
G_TYPE_NONE,
|
||||
GTK_STYLE_PROPERTY_ANIMATED,
|
||||
GTK_CSS_AFFECTS_TRANSFORM,
|
||||
transform_value_parse,
|
||||
NULL,
|
||||
_gtk_css_transform_value_new_none ());
|
||||
gtk_css_style_property_register ("-gtk-icon-filter",
|
||||
GTK_CSS_PROPERTY_ICON_FILTER,
|
||||
G_TYPE_NONE,
|
||||
@@ -1609,7 +1617,6 @@ _gtk_css_style_property_init_properties (void)
|
||||
filter_value_parse,
|
||||
NULL,
|
||||
gtk_css_filter_value_new_none ());
|
||||
|
||||
gtk_css_style_property_register ("border-spacing",
|
||||
GTK_CSS_PROPERTY_BORDER_SPACING,
|
||||
G_TYPE_NONE,
|
||||
|
@@ -75,7 +75,6 @@ struct _GtkCssValue {
|
||||
};
|
||||
|
||||
static GtkCssValue * gtk_css_transform_value_alloc (guint n_values);
|
||||
static gboolean gtk_css_transform_value_is_none (const GtkCssValue *value);
|
||||
|
||||
static void
|
||||
gtk_css_transform_clear (GtkCssTransform *transform)
|
||||
@@ -733,7 +732,7 @@ _gtk_css_transform_value_new_none (void)
|
||||
return _gtk_css_value_ref (&none_singleton);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gboolean
|
||||
gtk_css_transform_value_is_none (const GtkCssValue *value)
|
||||
{
|
||||
return value->n_transforms == 0;
|
||||
|
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
|
||||
|
||||
GtkCssValue * _gtk_css_transform_value_new_none (void);
|
||||
GtkCssValue * _gtk_css_transform_value_parse (GtkCssParser *parser);
|
||||
gboolean gtk_css_transform_value_is_none (const GtkCssValue *transform);
|
||||
|
||||
gboolean gtk_css_transform_value_get_matrix (const GtkCssValue *transform,
|
||||
graphene_matrix_t *matrix);
|
||||
|
@@ -115,6 +115,7 @@ typedef guint64 GtkCssChange;
|
||||
* @GTK_CSS_AFFECTS_POSTEFFECT: An effect is applied after drawing that changes
|
||||
* @GTK_CSS_AFFECTS_TEXT: Affects anything related to text rendering.
|
||||
* @GTK_CSS_AFFECTS_REDRAW: Affects anything that requires redraw.
|
||||
* @GTK_CSS_AFFECTS_TRANSFORM: Affects the element transformation.
|
||||
*
|
||||
* The generic effects that a CSS property can have. If a value is
|
||||
* set, then the property will have an influence on that feature.
|
||||
@@ -133,7 +134,8 @@ typedef enum {
|
||||
GTK_CSS_AFFECTS_SYMBOLIC_ICON = (1 << 8),
|
||||
GTK_CSS_AFFECTS_OUTLINE = (1 << 9),
|
||||
GTK_CSS_AFFECTS_SIZE = (1 << 10),
|
||||
GTK_CSS_AFFECTS_POSTEFFECT = (1 << 11)
|
||||
GTK_CSS_AFFECTS_POSTEFFECT = (1 << 11),
|
||||
GTK_CSS_AFFECTS_TRANSFORM = (1 << 12),
|
||||
} GtkCssAffects;
|
||||
|
||||
#define GTK_CSS_AFFECTS_REDRAW (GTK_CSS_AFFECTS_CONTENT | \
|
||||
@@ -220,6 +222,7 @@ enum { /*< skip >*/
|
||||
GTK_CSS_PROPERTY_ICON_SHADOW,
|
||||
GTK_CSS_PROPERTY_ICON_STYLE,
|
||||
GTK_CSS_PROPERTY_ICON_TRANSFORM,
|
||||
GTK_CSS_PROPERTY_TRANSFORM,
|
||||
GTK_CSS_PROPERTY_ICON_FILTER,
|
||||
GTK_CSS_PROPERTY_BORDER_SPACING,
|
||||
GTK_CSS_PROPERTY_MIN_WIDTH,
|
||||
|
@@ -3918,7 +3918,7 @@ gtk_flow_box_get_child_at_index (GtkFlowBox *box,
|
||||
* @y: the y coordinate of the child
|
||||
*
|
||||
* Gets the child in the (@x, @y) position. Both @x and @y are
|
||||
* assumed to be relative to the allocation of @box.
|
||||
* assumed to be relative to the origin of @box.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): the child widget, which will
|
||||
* always be a #GtkFlowBoxChild or %NULL in case no child widget
|
||||
@@ -3929,24 +3929,12 @@ gtk_flow_box_get_child_at_pos (GtkFlowBox *box,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkWidget *child;
|
||||
GSequenceIter *iter;
|
||||
GtkAllocation allocation;
|
||||
GtkWidget *child = gtk_widget_pick (GTK_WIDGET (box), x, y);
|
||||
|
||||
for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
|
||||
!g_sequence_iter_is_end (iter);
|
||||
iter = g_sequence_iter_next (iter))
|
||||
{
|
||||
child = g_sequence_get (iter);
|
||||
if (!child_is_visible (child))
|
||||
continue;
|
||||
if (!child)
|
||||
return NULL;
|
||||
|
||||
gtk_widget_get_allocation (child, &allocation);
|
||||
if (gdk_rectangle_contains_point (&allocation, x, y))
|
||||
return GTK_FLOW_BOX_CHILD (child);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return (GtkFlowBoxChild *)gtk_widget_get_ancestor (child, GTK_TYPE_FLOW_BOX_CHILD);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -94,13 +94,6 @@ void gtk_propagate_event_internal (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost);
|
||||
|
||||
gboolean gtk_widget_translate_coordinatesf (GtkWidget *src_widget,
|
||||
GtkWidget *dest_widget,
|
||||
double src_x,
|
||||
double src_y,
|
||||
double *dest_x,
|
||||
double *dest_y);
|
||||
|
||||
GtkWidget * _gtk_toplevel_pick (GtkWindow *toplevel,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
|
@@ -120,6 +120,103 @@ get_box_padding (GtkCssStyle *style,
|
||||
border->right = get_number (style, GTK_CSS_PROPERTY_PADDING_RIGHT);
|
||||
}
|
||||
|
||||
/* translate initial/final into start/end */
|
||||
static GtkAlign
|
||||
effective_align (GtkAlign align,
|
||||
GtkTextDirection direction)
|
||||
{
|
||||
switch (align)
|
||||
{
|
||||
case GTK_ALIGN_START:
|
||||
return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
|
||||
case GTK_ALIGN_END:
|
||||
return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
|
||||
case GTK_ALIGN_FILL:
|
||||
case GTK_ALIGN_CENTER:
|
||||
case GTK_ALIGN_BASELINE:
|
||||
default:
|
||||
return align;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
adjust_for_align (GtkAlign align,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size)
|
||||
{
|
||||
switch (align)
|
||||
{
|
||||
case GTK_ALIGN_BASELINE:
|
||||
case GTK_ALIGN_FILL:
|
||||
default:
|
||||
/* change nothing */
|
||||
break;
|
||||
case GTK_ALIGN_START:
|
||||
/* keep *allocated_pos where it is */
|
||||
*allocated_size = MIN (*allocated_size, *natural_size);
|
||||
break;
|
||||
case GTK_ALIGN_END:
|
||||
if (*allocated_size > *natural_size)
|
||||
{
|
||||
*allocated_pos += (*allocated_size - *natural_size);
|
||||
*allocated_size = *natural_size;
|
||||
}
|
||||
break;
|
||||
case GTK_ALIGN_CENTER:
|
||||
if (*allocated_size > *natural_size)
|
||||
{
|
||||
*allocated_pos += (*allocated_size - *natural_size) / 2;
|
||||
*allocated_size = MIN (*allocated_size, *natural_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
adjust_for_margin(gint start_margin,
|
||||
gint end_margin,
|
||||
gint *minimum_size,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size)
|
||||
{
|
||||
*minimum_size -= (start_margin + end_margin);
|
||||
*natural_size -= (start_margin + end_margin);
|
||||
*allocated_pos += start_margin;
|
||||
*allocated_size -= (start_margin + end_margin);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_widget_adjust_size_allocation (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint *minimum_size,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size)
|
||||
{
|
||||
GtkWidgetPrivate *priv = widget->priv;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
adjust_for_margin (priv->margin.left,
|
||||
priv->margin.right,
|
||||
minimum_size, natural_size,
|
||||
allocated_pos, allocated_size);
|
||||
adjust_for_align (effective_align (priv->halign, _gtk_widget_get_direction (widget)),
|
||||
natural_size, allocated_pos, allocated_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
adjust_for_margin (priv->margin.top,
|
||||
priv->margin.bottom,
|
||||
minimum_size, natural_size,
|
||||
allocated_pos, allocated_size);
|
||||
adjust_for_align (effective_align (priv->valign, GTK_TEXT_DIR_NONE),
|
||||
natural_size, allocated_pos, allocated_size);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_widget_query_size_for_orientation (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
|
770
gtk/gtkwidget.c
770
gtk/gtkwidget.c
File diff suppressed because it is too large
Load Diff
@@ -406,6 +406,12 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_size_allocate (GtkWidget *widget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_size_allocate_transformed (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline,
|
||||
const graphene_matrix_t *transform);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSizeRequestMode gtk_widget_get_request_mode (GtkWidget *widget);
|
||||
@@ -746,6 +752,14 @@ gboolean gtk_widget_translate_coordinates (GtkWidget *src_widget,
|
||||
gint *dest_x,
|
||||
gint *dest_y);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_widget_translate_coordinatesf (GtkWidget *src_widget,
|
||||
GtkWidget *dest_widget,
|
||||
double src_x,
|
||||
double src_y,
|
||||
double *dest_x,
|
||||
double *dest_y);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_widget_contains (GtkWidget *widget,
|
||||
gdouble x,
|
||||
@@ -1050,6 +1064,13 @@ void gtk_widget_snapshot_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkSnapshot *snapshot);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_set_transform (GtkWidget *widget,
|
||||
const graphene_matrix_t *transform);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_get_transform (GtkWidget *widget,
|
||||
graphene_matrix_t *out_transform);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidget, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkRequisition, gtk_requisition_free)
|
||||
|
||||
|
@@ -141,9 +141,14 @@ struct _GtkWidgetPrivate
|
||||
/* The widget's allocated size */
|
||||
GtkAllocation allocated_size;
|
||||
gint allocated_size_baseline;
|
||||
GtkAllocation allocation;
|
||||
int allocated_width;
|
||||
int allocated_height;
|
||||
gint allocated_baseline;
|
||||
|
||||
graphene_matrix_t allocated_transform;
|
||||
graphene_matrix_t transform;
|
||||
guint has_transform : 1;
|
||||
|
||||
/* The widget's requested sizes */
|
||||
SizeRequestCache requests;
|
||||
|
||||
@@ -292,12 +297,6 @@ void gtk_widget_adjust_size_request (GtkWidget *widg
|
||||
GtkOrientation orientation,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
void gtk_widget_adjust_size_allocation (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint *minimum_size,
|
||||
gint *natural_size,
|
||||
gint *allocated_pos,
|
||||
gint *allocated_size);
|
||||
void gtk_widget_adjust_baseline_request (GtkWidget *widget,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline);
|
||||
@@ -329,6 +328,11 @@ void gtk_widget_get_origin_relative_to_parent (GtkWidget *wi
|
||||
int *origin_x,
|
||||
int *origin_y);
|
||||
|
||||
gboolean gtk_widget_emit_event_signals (GtkWidget *widget,
|
||||
const GdkEvent *event);
|
||||
|
||||
void gtk_widget_init_legacy_controller (GtkWidget *widget);
|
||||
|
||||
void gtk_widget_cancel_event_sequence (GtkWidget *widget,
|
||||
GtkGesture *gesture,
|
||||
GdkEventSequence *sequence,
|
||||
@@ -451,13 +455,6 @@ _gtk_widget_get_surface (GtkWidget *widget)
|
||||
return widget->priv->surface;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_gtk_widget_get_allocation (GtkWidget *widget,
|
||||
GtkAllocation *allocation)
|
||||
{
|
||||
*allocation = widget->priv->allocation;
|
||||
}
|
||||
|
||||
static inline GtkWidget *
|
||||
_gtk_widget_get_prev_sibling (GtkWidget *widget)
|
||||
{
|
||||
|
@@ -1724,7 +1724,7 @@ edge_under_coordinates (GtkWindow *window,
|
||||
(priv->edge_constraints & constraints) != constraints)
|
||||
return FALSE;
|
||||
|
||||
_gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
|
||||
gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
|
||||
context = _gtk_widget_get_style_context (GTK_WIDGET (window));
|
||||
gtk_style_context_save_to_node (context, priv->decoration_node);
|
||||
|
||||
@@ -5224,7 +5224,7 @@ gtk_window_move (GtkWindow *window,
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
/* we have now sent a request with this position
|
||||
* with currently-active constraints, so toggle flag.
|
||||
@@ -6017,7 +6017,7 @@ popover_get_rect (GtkWindowPopover *popover,
|
||||
gdouble min, max;
|
||||
|
||||
gtk_widget_get_preferred_size (popover->widget, NULL, &req);
|
||||
_gtk_widget_get_allocation (GTK_WIDGET (window), &win_alloc);
|
||||
gtk_widget_get_allocation (GTK_WIDGET (window), &win_alloc);
|
||||
|
||||
get_shadow_width (window, &win_border);
|
||||
win_alloc.x += win_border.left;
|
||||
@@ -6385,11 +6385,11 @@ gtk_window_realize (GtkWidget *widget)
|
||||
if (!priv->client_decorated && gtk_window_should_use_csd (window))
|
||||
create_decoration (widget);
|
||||
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
/* ensure widget tree is properly size allocated */
|
||||
if (allocation.x == -1 &&
|
||||
allocation.y == -1 &&
|
||||
if (allocation.x == 0 &&
|
||||
allocation.y == 0 &&
|
||||
allocation.width == 1 &&
|
||||
allocation.height == 1)
|
||||
{
|
||||
@@ -6411,12 +6411,12 @@ gtk_window_realize (GtkWidget *widget)
|
||||
if (priv->hardcoded_surface)
|
||||
{
|
||||
surface = priv->hardcoded_surface;
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
gdk_surface_resize (surface, allocation.width, allocation.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
@@ -6787,7 +6787,7 @@ gtk_window_configure (GtkWindow *window,
|
||||
* have been a queued resize from child widgets, and so we
|
||||
* need to reallocate our children in case *they* changed.
|
||||
*/
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
if (priv->configure_request_count == 0 &&
|
||||
(allocation.width == width && allocation.height == height))
|
||||
{
|
||||
@@ -7008,7 +7008,7 @@ get_active_region_type (GtkWindow *window, gint x, gint y)
|
||||
gtk_widget_get_visible (priv->title_box) &&
|
||||
gtk_widget_get_child_visible (priv->title_box))
|
||||
{
|
||||
_gtk_widget_get_allocation (priv->title_box, &allocation);
|
||||
gtk_widget_get_allocation (priv->title_box, &allocation);
|
||||
if (allocation.x <= x && allocation.x + allocation.width > x &&
|
||||
allocation.y <= y && allocation.y + allocation.height > y)
|
||||
return GTK_WINDOW_REGION_TITLE;
|
||||
@@ -7386,7 +7386,7 @@ gtk_window_style_updated (GtkWidget *widget)
|
||||
GtkAllocation allocation;
|
||||
GtkBorder window_border;
|
||||
|
||||
_gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
get_shadow_width (window, &window_border);
|
||||
|
||||
update_opaque_region (window, &window_border, &allocation);
|
||||
@@ -7932,7 +7932,7 @@ gtk_window_compute_configure_request (GtkWindow *window,
|
||||
|
||||
gdk_surface_get_origin (surface, &ox, &oy);
|
||||
|
||||
_gtk_widget_get_allocation (parent_widget, &allocation);
|
||||
gtk_widget_get_allocation (parent_widget, &allocation);
|
||||
x = ox + (allocation.width - w) / 2;
|
||||
y = oy + (allocation.height - h) / 2;
|
||||
|
||||
|
@@ -41,6 +41,7 @@ gtk_tests = [
|
||||
['testflowbox'],
|
||||
['testfontchooser'],
|
||||
['testfontoptions'],
|
||||
['testformentry'],
|
||||
['testframe'],
|
||||
['testfullscreen'],
|
||||
['testgiconpixbuf'],
|
||||
@@ -122,6 +123,7 @@ gtk_tests = [
|
||||
['testpopupat'],
|
||||
['testgaction'],
|
||||
['testwidgetfocus'],
|
||||
['testwidgettransforms'],
|
||||
['testcenterbox'],
|
||||
['testgridbaseline'],
|
||||
['showrendernode'],
|
||||
@@ -129,6 +131,8 @@ gtk_tests = [
|
||||
['testoutsetshadowdrawing'],
|
||||
['testblur'],
|
||||
['testtexture'],
|
||||
['testshrinking'],
|
||||
['testflipping'],
|
||||
]
|
||||
|
||||
if os_unix
|
||||
|
209
tests/testflipping.c
Normal file
209
tests/testflipping.c
Normal file
@@ -0,0 +1,209 @@
|
||||
|
||||
#include<gtk/gtk.h>
|
||||
|
||||
typedef struct _GtkFlip GtkFlip;
|
||||
typedef struct _GtkFlipClass GtkFlipClass;
|
||||
|
||||
#define GTK_TYPE_FLIP (gtk_flip_get_type ())
|
||||
#define GTK_FLIP(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, GTK_TYPE_FLIP, GtkFlip))
|
||||
#define GTK_FLIP_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, GTK_TYPE_FLIP, GtkFlipClass))
|
||||
struct _GtkFlip
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *child;
|
||||
guint flipped : 1;
|
||||
};
|
||||
|
||||
struct _GtkFlipClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
GType gtk_flip_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_TYPE(GtkFlip, gtk_flip, GTK_TYPE_WIDGET);
|
||||
|
||||
#define OPPOSITE_ORIENTATION(o) (1 - o)
|
||||
|
||||
static void
|
||||
gtk_flip_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkFlip *self = (GtkFlip *)widget;
|
||||
|
||||
if (self->flipped)
|
||||
gtk_widget_measure (self->child, OPPOSITE_ORIENTATION (orientation), for_size,
|
||||
minimum, natural, NULL, NULL);
|
||||
else
|
||||
gtk_widget_measure (self->child, orientation, for_size, minimum, natural, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flip_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkFlip *self = (GtkFlip *)widget;
|
||||
int child_width;
|
||||
int child_height;
|
||||
graphene_matrix_t transform;
|
||||
|
||||
gtk_widget_measure (self->child, GTK_ORIENTATION_HORIZONTAL, -1, &child_width, NULL, NULL, NULL);
|
||||
gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, -1, &child_height, NULL, NULL, NULL);
|
||||
|
||||
if (self->flipped)
|
||||
{
|
||||
graphene_matrix_init_rotate (&transform, 90, graphene_vec3_z_axis ());
|
||||
graphene_matrix_translate (&transform,
|
||||
&GRAPHENE_POINT3D_INIT (child_height, 0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
graphene_matrix_init_identity (&transform);
|
||||
}
|
||||
|
||||
gtk_widget_size_allocate_transformed (self->child,
|
||||
child_width,
|
||||
child_height,
|
||||
-1, &transform);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flip_finalize (GObject *object)
|
||||
{
|
||||
GtkFlip *self = (GtkFlip *)object;
|
||||
|
||||
gtk_widget_unparent (self->child);
|
||||
|
||||
G_OBJECT_CLASS (gtk_flip_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flip_init (GtkFlip *self)
|
||||
{
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flip_class_init (GtkFlipClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = gtk_flip_finalize;
|
||||
|
||||
widget_class->measure = gtk_flip_measure;
|
||||
widget_class->size_allocate = gtk_flip_size_allocate;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_flip_new (GtkWidget *child)
|
||||
{
|
||||
GtkFlip *s = GTK_FLIP (g_object_new (GTK_TYPE_FLIP, NULL));
|
||||
|
||||
s->child = child;
|
||||
gtk_widget_set_parent (child, GTK_WIDGET (s));
|
||||
|
||||
return GTK_WIDGET (s);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flip_flip (GtkFlip *self)
|
||||
{
|
||||
self->flipped = !self->flipped;
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Stub definition of MyTextView which is used in the
|
||||
* widget-factory.ui file. We just need this so the
|
||||
* test keeps working
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GtkTextView tv;
|
||||
} MyTextView;
|
||||
|
||||
typedef GtkTextViewClass MyTextViewClass;
|
||||
|
||||
G_DEFINE_TYPE (MyTextView, my_text_view, GTK_TYPE_TEXT_VIEW)
|
||||
|
||||
static void
|
||||
my_text_view_init (MyTextView *tv) {}
|
||||
|
||||
static void
|
||||
my_text_view_class_init (MyTextViewClass *tv_class) {}
|
||||
|
||||
/* Copied from tests/scrolling-performance.c */
|
||||
GtkWidget *
|
||||
create_widget_factory_content (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *result;
|
||||
|
||||
g_type_ensure (my_text_view_get_type ());
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_add_from_file (builder,
|
||||
"../demos/widget-factory/widget-factory.ui",
|
||||
&error);
|
||||
if (error != NULL)
|
||||
g_error ("Failed to create widgets: %s", error->message);
|
||||
|
||||
result = GTK_WIDGET (gtk_builder_get_object (builder, "box1"));
|
||||
g_object_ref (result);
|
||||
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (result)),
|
||||
result);
|
||||
g_object_unref (builder);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
flip_button_clicked_cb (GtkButton *source,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFlip *flip = user_data;
|
||||
|
||||
gtk_flip_flip (flip);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *flip;
|
||||
GtkWidget *to_flip;
|
||||
GtkWidget *hb;
|
||||
GtkWidget *flip_button;
|
||||
|
||||
|
||||
gtk_init ();
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
hb = gtk_header_bar_new ();
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), hb);
|
||||
flip_button = gtk_button_new_with_label ("Flip");
|
||||
gtk_container_add (GTK_CONTAINER (hb), flip_button);
|
||||
to_flip = create_widget_factory_content ();
|
||||
g_object_set (G_OBJECT (to_flip), "margin", 0, NULL);
|
||||
flip = gtk_flip_new (to_flip);
|
||||
g_signal_connect (flip_button, "clicked", G_CALLBACK (flip_button_clicked_cb), flip);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (window), flip);
|
||||
|
||||
gtk_widget_show (window);
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
229
tests/testformentry.c
Normal file
229
tests/testformentry.c
Normal file
@@ -0,0 +1,229 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define GTK_TYPE_FORM_ENTRY (gtk_form_entry_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkFormEntry, gtk_form_entry, GTK, FORM_ENTRY, GtkWidget)
|
||||
|
||||
#define FINAL_SCALE 0.7
|
||||
#define TRANSITION_DURATION (200 * 1000)
|
||||
|
||||
struct _GtkFormEntry
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *entry;
|
||||
GtkWidget *placeholder;
|
||||
|
||||
double placeholder_scale;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkFormEntry, gtk_form_entry, GTK_TYPE_WIDGET)
|
||||
|
||||
|
||||
static void
|
||||
gtk_form_entry_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkFormEntry *self = (GtkFormEntry *)widget;
|
||||
int placeholder_height;
|
||||
int top;
|
||||
|
||||
gtk_widget_measure (self->placeholder, GTK_ORIENTATION_VERTICAL, -1,
|
||||
&placeholder_height, NULL, NULL, NULL);
|
||||
top = placeholder_height * FINAL_SCALE;
|
||||
|
||||
gtk_widget_size_allocate (self->entry,
|
||||
&(GtkAllocation) {
|
||||
0, top,
|
||||
width, height - top
|
||||
}, -1);
|
||||
|
||||
/* Placeholder allocation depends on self->placeholder_scale.
|
||||
* If that's 1.0, we don't scale it and center it on the
|
||||
* GtkEntry. Otherwise, we move it up until y = 0. */
|
||||
{
|
||||
const int max_y = top + ((height - top) / 2) - (placeholder_height / 2);
|
||||
const double t = self->placeholder_scale; /* TODO: Interpolate */
|
||||
const int y = 0 + (t * max_y);
|
||||
int x;
|
||||
graphene_matrix_t m;
|
||||
|
||||
/* Get 0 in entry coords so we can position the placeholder there. */
|
||||
gtk_widget_translate_coordinates (self->entry, widget, 0, 0, &x, NULL);
|
||||
|
||||
x *= t;
|
||||
|
||||
graphene_matrix_init_scale (&m,
|
||||
CLAMP (t, FINAL_SCALE, 1.0),
|
||||
CLAMP (t, FINAL_SCALE, 1.0),
|
||||
1);
|
||||
graphene_matrix_translate (&m,
|
||||
&GRAPHENE_POINT3D_INIT (x, y, 0));
|
||||
|
||||
gtk_widget_size_allocate_transformed (self->placeholder,
|
||||
width,
|
||||
placeholder_height,
|
||||
-1,
|
||||
&m);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_form_entry_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkFormEntry *self = (GtkFormEntry *)widget;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
int min1, nat1;
|
||||
int min2, nat2;
|
||||
|
||||
gtk_widget_measure (self->entry, orientation, for_size,
|
||||
&min1, &nat1, NULL, NULL);
|
||||
|
||||
gtk_widget_measure (self->placeholder, orientation, for_size,
|
||||
&min2, &nat2, NULL, NULL);
|
||||
|
||||
*minimum = MAX (min1, min2);
|
||||
*natural = MAX (nat1, nat2);
|
||||
}
|
||||
else /* VERTICAL */
|
||||
{
|
||||
int min, nat;
|
||||
int pmin, pnat;
|
||||
|
||||
gtk_widget_measure (self->entry, orientation, -1,
|
||||
&min, &nat, NULL, NULL);
|
||||
|
||||
gtk_widget_measure (self->placeholder, orientation, -1,
|
||||
&pmin, &pnat, NULL, NULL);
|
||||
|
||||
*minimum = min + (pmin * FINAL_SCALE);
|
||||
*natural = nat + (pnat * FINAL_SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tick_cb (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFormEntry *self = user_data;
|
||||
|
||||
self->placeholder_scale -= 0.02;
|
||||
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
gtk_widget_queue_draw (self->placeholder);
|
||||
|
||||
if (self->placeholder_scale <= 0)
|
||||
{
|
||||
self->placeholder_scale = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_form_entry_focused (GtkEventControllerKey *controller,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFormEntry *self = user_data;
|
||||
|
||||
gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_form_entry_unfocused (GtkEventControllerKey *controller,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFormEntry *self = user_data;
|
||||
|
||||
self->placeholder_scale = 1.0;
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
gtk_widget_queue_draw (self->placeholder);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_form_entry_class_init (GtkFormEntryClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
widget_class->measure = gtk_form_entry_measure;
|
||||
widget_class->size_allocate = gtk_form_entry_size_allocate;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_form_entry_init (GtkFormEntry *self)
|
||||
{
|
||||
GtkEventController *key_controller;
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
|
||||
|
||||
self->entry = gtk_entry_new ();
|
||||
self->placeholder = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (self->placeholder), 0);
|
||||
self->placeholder_scale = 1.0;
|
||||
|
||||
gtk_widget_set_parent (self->entry, GTK_WIDGET (self));
|
||||
gtk_widget_set_parent (self->placeholder, GTK_WIDGET (self));
|
||||
|
||||
key_controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect (key_controller, "focus-in", G_CALLBACK (gtk_form_entry_focused), self);
|
||||
g_signal_connect (key_controller, "focus-out", G_CALLBACK (gtk_form_entry_unfocused), self);
|
||||
gtk_widget_add_controller (self->entry, key_controller);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_form_entry_new (const char *text)
|
||||
{
|
||||
GtkWidget *w = g_object_new (GTK_TYPE_FORM_ENTRY, NULL);
|
||||
|
||||
gtk_label_set_text (GTK_LABEL (((GtkFormEntry*)w)->placeholder), text);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *box;
|
||||
GtkWidget *form_entry1;
|
||||
GtkWidget *form_entry2;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
form_entry1 = gtk_form_entry_new ("First Name");
|
||||
form_entry2 = gtk_form_entry_new ("Last Name");
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (box), form_entry1);
|
||||
gtk_container_add (GTK_CONTAINER (box), form_entry2);
|
||||
|
||||
|
||||
gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (box, GTK_ALIGN_CENTER);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
|
||||
|
||||
gtk_window_set_default_size ((GtkWindow *)window, 200, 200);
|
||||
g_signal_connect (window, "close-request", G_CALLBACK (gtk_main_quit), NULL);
|
||||
gtk_widget_show (window);
|
||||
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
184
tests/testshrinking.c
Normal file
184
tests/testshrinking.c
Normal file
@@ -0,0 +1,184 @@
|
||||
|
||||
#include<gtk/gtk.h>
|
||||
|
||||
typedef struct _GtkShrink GtkShrink;
|
||||
typedef struct _GtkShrinkClass GtkShrinkClass;
|
||||
|
||||
#define GTK_TYPE_SHRINK (gtk_shrink_get_type ())
|
||||
#define GTK_SHRINK(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, GTK_TYPE_SHRINK, GtkShrink))
|
||||
#define GTK_SHRINK_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, GTK_TYPE_SHRINK, GtkShrinkClass))
|
||||
struct _GtkShrink
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *child;
|
||||
};
|
||||
|
||||
struct _GtkShrinkClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
GType gtk_shrink_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_TYPE(GtkShrink, gtk_shrink, GTK_TYPE_WIDGET);
|
||||
|
||||
|
||||
static void
|
||||
gtk_shrink_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkShrink *self = (GtkShrink *)widget;
|
||||
|
||||
*minimum = 0;
|
||||
|
||||
gtk_widget_measure (self->child, orientation, for_size, NULL, natural, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shrink_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkShrink *self = (GtkShrink *)widget;
|
||||
int child_width;
|
||||
int child_height;
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
graphene_matrix_t transform;
|
||||
|
||||
gtk_widget_measure (self->child, GTK_ORIENTATION_HORIZONTAL, -1, &child_width, NULL, NULL, NULL);
|
||||
gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, -1, &child_height, NULL, NULL, NULL);
|
||||
|
||||
if (width < child_width)
|
||||
scale_x = (float)width / (float)child_width;
|
||||
else
|
||||
scale_x = 1.0f;
|
||||
|
||||
if (height < child_height)
|
||||
scale_y = (float)height / (float)child_height;
|
||||
else
|
||||
scale_y = 1.0f;
|
||||
|
||||
graphene_matrix_init_scale (&transform, scale_x, scale_y, 1.0f);
|
||||
|
||||
gtk_widget_size_allocate_transformed (self->child,
|
||||
MAX (width, child_width),
|
||||
MAX (height, child_height),
|
||||
-1, &transform);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shrink_finalize (GObject *object)
|
||||
{
|
||||
GtkShrink *self = (GtkShrink *)object;
|
||||
|
||||
gtk_widget_unparent (self->child);
|
||||
|
||||
G_OBJECT_CLASS (gtk_shrink_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shrink_init (GtkShrink *self)
|
||||
{
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shrink_class_init (GtkShrinkClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = gtk_shrink_finalize;
|
||||
|
||||
widget_class->measure = gtk_shrink_measure;
|
||||
widget_class->size_allocate = gtk_shrink_size_allocate;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_shrink_new (GtkWidget *child)
|
||||
{
|
||||
GtkShrink *s = GTK_SHRINK (g_object_new (GTK_TYPE_SHRINK, NULL));
|
||||
|
||||
s->child = child;
|
||||
gtk_widget_set_parent (child, GTK_WIDGET (s));
|
||||
|
||||
return GTK_WIDGET (s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Stub definition of MyTextView which is used in the
|
||||
* widget-factory.ui file. We just need this so the
|
||||
* test keeps working
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GtkTextView tv;
|
||||
} MyTextView;
|
||||
|
||||
typedef GtkTextViewClass MyTextViewClass;
|
||||
|
||||
G_DEFINE_TYPE (MyTextView, my_text_view, GTK_TYPE_TEXT_VIEW)
|
||||
|
||||
static void
|
||||
my_text_view_init (MyTextView *tv) {}
|
||||
|
||||
static void
|
||||
my_text_view_class_init (MyTextViewClass *tv_class) {}
|
||||
|
||||
/* Copied from tests/scrolling-performance.c */
|
||||
GtkWidget *
|
||||
create_widget_factory_content (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *result;
|
||||
|
||||
g_type_ensure (my_text_view_get_type ());
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_add_from_file (builder,
|
||||
"../demos/widget-factory/widget-factory.ui",
|
||||
&error);
|
||||
if (error != NULL)
|
||||
g_error ("Failed to create widgets: %s", error->message);
|
||||
|
||||
result = GTK_WIDGET (gtk_builder_get_object (builder, "box1"));
|
||||
g_object_ref (result);
|
||||
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (result)),
|
||||
result);
|
||||
g_object_unref (builder);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *shrink;
|
||||
GtkWidget *to_shrink;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
to_shrink = create_widget_factory_content ();
|
||||
g_object_set (G_OBJECT (to_shrink), "margin", 0, NULL);
|
||||
shrink = gtk_shrink_new (to_shrink);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (window), shrink);
|
||||
|
||||
gtk_widget_show (window);
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
349
tests/testwidgettransforms.c
Normal file
349
tests/testwidgettransforms.c
Normal file
@@ -0,0 +1,349 @@
|
||||
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static const char *css =
|
||||
"test>button {"
|
||||
" all: unset; "
|
||||
" background-color: white;"
|
||||
" border: 20px solid black;"
|
||||
" padding: 20px;"
|
||||
" margin: 40px;"
|
||||
"}"
|
||||
"test>button:hover {"
|
||||
" background-color: blue;"
|
||||
" border-color: red;"
|
||||
"}"
|
||||
"test image {"
|
||||
" background-color: teal;"
|
||||
"}"
|
||||
;
|
||||
|
||||
/* Just so we can avoid a signal */
|
||||
GtkWidget *transform_tester;
|
||||
GtkWidget *test_widget;
|
||||
GtkWidget *test_child;
|
||||
float scale = 1;
|
||||
gboolean do_picking = TRUE;
|
||||
graphene_matrix_t global_transform;
|
||||
|
||||
static const GdkRGBA RED = {1, 0, 0, 0.4};
|
||||
static const GdkRGBA GREEN = {0, 1, 0, 0.4};
|
||||
static const GdkRGBA BLUE = {0, 0, 1, 0.4};
|
||||
static const GdkRGBA BLACK = {0, 0, 0, 1};
|
||||
|
||||
|
||||
|
||||
/* ######################################################################### */
|
||||
/* ############################## MatrixChooser ############################ */
|
||||
/* ######################################################################### */
|
||||
|
||||
|
||||
#define GTK_TYPE_MATRIX_CHOOSER (gtk_matrix_chooser_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkMatrixChooser, gtk_matrix_chooser, GTK, MATRIX_CHOOSER, GtkWidget)
|
||||
|
||||
struct _GtkMatrixChooser
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkMatrixChooser, gtk_matrix_chooser, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
gtk_matrix_chooser_init (GtkMatrixChooser *self)
|
||||
{
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_matrix_chooser_class_init (GtkMatrixChooserClass *klass)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ######################################################################### */
|
||||
/* ############################# TransformTester ########################### */
|
||||
/* ######################################################################### */
|
||||
|
||||
#define TEST_WIDGET_MIN_SIZE 100
|
||||
|
||||
#define GTK_TYPE_TRANSFORM_TESTER (gtk_transform_tester_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkTransformTester, gtk_transform_tester, GTK, TRANSFORM_TESTER, GtkWidget);
|
||||
|
||||
struct _GtkTransformTester
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *test_widget;
|
||||
int pick_increase;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkTransformTester, gtk_transform_tester, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
gtk_transform_tester_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkTransformTester *self = (GtkTransformTester *)widget;
|
||||
|
||||
if (self->test_widget)
|
||||
{
|
||||
gtk_widget_measure (self->test_widget, orientation, for_size,
|
||||
minimum, natural, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_transform_tester_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkTransformTester *self = (GtkTransformTester *)widget;
|
||||
int w, h;
|
||||
|
||||
if (!self->test_widget)
|
||||
return;
|
||||
|
||||
scale += 2.5f;
|
||||
|
||||
gtk_widget_measure (self->test_widget, GTK_ORIENTATION_HORIZONTAL, -1,
|
||||
&w, NULL, NULL, NULL);
|
||||
gtk_widget_measure (self->test_widget, GTK_ORIENTATION_VERTICAL, w,
|
||||
&h, NULL, NULL, NULL);
|
||||
|
||||
graphene_matrix_init_identity (&global_transform);
|
||||
graphene_matrix_translate (&global_transform, &(graphene_point3d_t){ -w/2.0f, -h/2.0f, 0});
|
||||
|
||||
graphene_matrix_rotate (&global_transform, scale,
|
||||
graphene_vec3_z_axis ());
|
||||
|
||||
graphene_matrix_translate (&global_transform, &(graphene_point3d_t){ width / 2.0f, height / 2.0f, 0});
|
||||
|
||||
gtk_widget_size_allocate_transformed (self->test_widget,
|
||||
w, h,
|
||||
-1,
|
||||
&global_transform);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_transform_tester_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkTransformTester *self = (GtkTransformTester *)widget;
|
||||
const int width = gtk_widget_get_width (widget);
|
||||
const int height = gtk_widget_get_height (widget);
|
||||
const int inc = self->pick_increase;
|
||||
graphene_rect_t child_bounds;
|
||||
graphene_rect_t self_bounds;
|
||||
int x, y;
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_transform_tester_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
if (!do_picking)
|
||||
return;
|
||||
|
||||
gtk_widget_compute_bounds (self->test_widget, widget, &child_bounds);
|
||||
gtk_widget_compute_bounds (self->test_widget, self->test_widget, &self_bounds);
|
||||
|
||||
{
|
||||
const struct {
|
||||
graphene_point_t coords;
|
||||
GdkRGBA color;
|
||||
} points[4] = {
|
||||
{ self_bounds.origin, {1, 0, 0, 1} },
|
||||
{ GRAPHENE_POINT_INIT (self_bounds.origin.x + self_bounds.size.width, self_bounds.origin.y), {0, 1, 0, 1} },
|
||||
{ GRAPHENE_POINT_INIT (self_bounds.origin.x + self_bounds.size.width, self_bounds.origin.y + self_bounds.size.height), {0, 0, 1, 1} },
|
||||
{ GRAPHENE_POINT_INIT (self_bounds.origin.x, self_bounds.origin.y + self_bounds.size.height), {1, 0, 1, 1} }
|
||||
};
|
||||
|
||||
for (x = 0; x < G_N_ELEMENTS (points); x ++)
|
||||
{
|
||||
double px, py;
|
||||
|
||||
gtk_widget_translate_coordinatesf (self->test_widget, widget,
|
||||
points[x].coords.x, points[x].coords.y,
|
||||
&px, &py);
|
||||
|
||||
gtk_snapshot_append_color (snapshot, &points[x].color,
|
||||
&GRAPHENE_RECT_INIT (px, py,
|
||||
4,
|
||||
4));
|
||||
}
|
||||
}
|
||||
|
||||
/* Now add custom drawing */
|
||||
for (x = 0; x < width; x += inc)
|
||||
{
|
||||
for (y = 0; y < height; y += inc)
|
||||
{
|
||||
const float px = x;
|
||||
const float py = y;
|
||||
GtkWidget *picked;
|
||||
#if 1
|
||||
picked = gtk_widget_pick (widget, px, py);
|
||||
#else
|
||||
{
|
||||
double dx, dy;
|
||||
gtk_widget_translate_coordinatesf (widget, self->test_widget, px, py, &dx, &dy);
|
||||
picked = gtk_widget_pick (self->test_widget, dx, dy);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (picked == self->test_widget)
|
||||
gtk_snapshot_append_color (snapshot, &GREEN,
|
||||
&GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
|
||||
else if (picked == test_child)
|
||||
gtk_snapshot_append_color (snapshot, &BLUE,
|
||||
&GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
|
||||
|
||||
else
|
||||
gtk_snapshot_append_color (snapshot, &RED,
|
||||
&GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtk_snapshot_append_color (snapshot, &BLACK,
|
||||
&GRAPHENE_RECT_INIT (child_bounds.origin.x,
|
||||
child_bounds.origin.y,
|
||||
child_bounds.size.width,
|
||||
1));
|
||||
|
||||
gtk_snapshot_append_color (snapshot, &BLACK,
|
||||
&GRAPHENE_RECT_INIT (child_bounds.origin.x + child_bounds.size.width,
|
||||
child_bounds.origin.y,
|
||||
1,
|
||||
child_bounds.size.height));
|
||||
|
||||
gtk_snapshot_append_color (snapshot, &BLACK,
|
||||
&GRAPHENE_RECT_INIT (child_bounds.origin.x,
|
||||
child_bounds.origin.y + child_bounds.size.height,
|
||||
child_bounds.size.width,
|
||||
1));
|
||||
|
||||
gtk_snapshot_append_color (snapshot, &BLACK,
|
||||
&GRAPHENE_RECT_INIT (child_bounds.origin.x,
|
||||
child_bounds.origin.y,
|
||||
1,
|
||||
child_bounds.size.height));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_transform_tester_init (GtkTransformTester *self)
|
||||
{
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
|
||||
|
||||
self->pick_increase = 4;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_transform_tester_class_init (GtkTransformTesterClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
|
||||
|
||||
widget_class->measure = gtk_transform_tester_measure;
|
||||
widget_class->size_allocate = gtk_transform_tester_size_allocate;
|
||||
widget_class->snapshot = gtk_transform_tester_snapshot;
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "test");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tick_cb (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_widget_queue_allocate (widget);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_transform_tester_set_test_widget (GtkTransformTester *self,
|
||||
GtkWidget *test_widget)
|
||||
{
|
||||
g_assert (!self->test_widget);
|
||||
|
||||
self->test_widget = test_widget;
|
||||
gtk_widget_set_parent (test_widget, (GtkWidget *)self);
|
||||
|
||||
gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
toggled_cb (GtkToggleButton *source,
|
||||
gpointer user_data)
|
||||
{
|
||||
do_picking = gtk_toggle_button_get_active (source);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *matrix_chooser;
|
||||
GtkWidget *box;
|
||||
GtkWidget *titlebar;
|
||||
GtkWidget *toggle_button;
|
||||
GtkCssProvider *provider;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
matrix_chooser = g_object_new (GTK_TYPE_MATRIX_CHOOSER, NULL);
|
||||
transform_tester = g_object_new (GTK_TYPE_TRANSFORM_TESTER, NULL);
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
titlebar = gtk_header_bar_new ();
|
||||
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), titlebar);
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (titlebar), TRUE);
|
||||
|
||||
toggle_button = gtk_toggle_button_new ();
|
||||
gtk_button_set_label (GTK_BUTTON (toggle_button), "Picking");
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_button), do_picking);
|
||||
g_signal_connect (toggle_button, "toggled", G_CALLBACK (toggled_cb), NULL);
|
||||
gtk_container_add (GTK_CONTAINER (titlebar), toggle_button);
|
||||
|
||||
test_widget = gtk_button_new ();
|
||||
gtk_widget_set_size_request (test_widget, TEST_WIDGET_MIN_SIZE, TEST_WIDGET_MIN_SIZE);
|
||||
gtk_widget_set_halign (test_widget, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (test_widget, GTK_ALIGN_CENTER);
|
||||
|
||||
|
||||
test_child = gtk_image_new_from_icon_name ("corebird");
|
||||
gtk_widget_set_halign (test_child, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (test_child, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_size_request (test_child, TEST_WIDGET_MIN_SIZE / 2, TEST_WIDGET_MIN_SIZE / 2);
|
||||
gtk_container_add (GTK_CONTAINER (test_widget), test_child);
|
||||
|
||||
|
||||
gtk_transform_tester_set_test_widget (GTK_TRANSFORM_TESTER (transform_tester), test_widget);
|
||||
|
||||
gtk_widget_set_vexpand (transform_tester, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), transform_tester);
|
||||
gtk_container_add (GTK_CONTAINER (box), matrix_chooser);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
gtk_window_set_default_size ((GtkWindow *)window, 200, 200);
|
||||
g_signal_connect (window, "close-request", G_CALLBACK (gtk_main_quit), NULL);
|
||||
gtk_widget_show (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
@@ -53,6 +53,7 @@ tests = [
|
||||
['textbuffer'],
|
||||
['textiter'],
|
||||
['treelistmodel'],
|
||||
['translate'],
|
||||
['treemodel', ['treemodel.c', 'liststore.c', 'treestore.c', 'filtermodel.c',
|
||||
'modelrefcount.c', 'sortmodel.c', 'gtktreemodelrefcount.c']],
|
||||
['treepath'],
|
||||
|
424
testsuite/gtk/translate.c
Normal file
424
testsuite/gtk/translate.c
Normal file
@@ -0,0 +1,424 @@
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define BORDER_WIDTH 30
|
||||
|
||||
static const char *css =
|
||||
"button, box {"
|
||||
" all: unset; "
|
||||
"}"
|
||||
".with-border {"
|
||||
" border: 30px solid white;"
|
||||
"}"
|
||||
;
|
||||
|
||||
static void
|
||||
same_widget (void)
|
||||
{
|
||||
GtkWidget *a = gtk_button_new ();
|
||||
int i;
|
||||
|
||||
for (i = -1000; i < 1000; i ++)
|
||||
{
|
||||
int rx, ry;
|
||||
|
||||
gtk_widget_translate_coordinates (a, a, i, i, &rx, &ry);
|
||||
|
||||
g_assert_cmpint (rx, ==, i);
|
||||
g_assert_cmpint (ry, ==, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compute_bounds (void)
|
||||
{
|
||||
const int WIDTH = 200;
|
||||
const int HEIGHT = 100;
|
||||
GtkWidget *a = gtk_button_new ();
|
||||
graphene_matrix_t transform;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
graphene_matrix_init_scale (&transform, 2, 1, 1);
|
||||
|
||||
gtk_widget_measure (a, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (a, &(GtkAllocation){0, 0, WIDTH, HEIGHT}, -1);
|
||||
|
||||
gtk_widget_compute_bounds (a, a, &bounds);
|
||||
g_assert_cmpfloat (bounds.origin.x, ==, 0);
|
||||
g_assert_cmpfloat (bounds.origin.y, ==, 0);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.width, WIDTH, 1);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT, 1);
|
||||
|
||||
gtk_widget_set_transform (a, &transform);
|
||||
gtk_widget_compute_bounds (a, a, &bounds);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.width, WIDTH, 1);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
compute_bounds_with_parent (void)
|
||||
{
|
||||
const int WIDTH = 200;
|
||||
const int HEIGHT = 100;
|
||||
GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
GtkWidget *a = gtk_button_new ();
|
||||
graphene_matrix_t transform;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
gtk_widget_set_hexpand (a, FALSE);
|
||||
gtk_widget_set_vexpand (a, FALSE);
|
||||
gtk_widget_set_halign (a, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (a, GTK_ALIGN_START);
|
||||
gtk_widget_set_size_request (a, WIDTH, HEIGHT);
|
||||
gtk_widget_set_margin_start (a, 25);
|
||||
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (box), a);
|
||||
gtk_widget_measure (a, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_measure (box, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (box, &(GtkAllocation){0, 0, WIDTH * 10, HEIGHT * 10}, -1);
|
||||
|
||||
gtk_widget_compute_bounds (a, box, &bounds);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.origin.x, 25, 1);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.origin.y, 0, 1);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.width, WIDTH, 1);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT, 1);
|
||||
|
||||
|
||||
/* Now set a transform and check that the bounds returned by compute_bounds
|
||||
* have the proper values */
|
||||
|
||||
graphene_matrix_init_scale (&transform, 2, 1, 1);
|
||||
gtk_widget_set_transform (a, &transform);
|
||||
|
||||
|
||||
gtk_widget_compute_bounds (a, box, &bounds);
|
||||
/* FIXME: Positions here are borked */
|
||||
/*g_assert_cmpfloat_with_epsilon (bounds.origin.x, 25, 1);*/
|
||||
/*g_assert_cmpfloat_with_epsilon (bounds.origin.y, 0, 1);*/
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.width, WIDTH * 2, 1);
|
||||
g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT, 1);
|
||||
/*g_message ("RESULT: %f, %f, %f, %f",*/
|
||||
/*bounds.origin.x, bounds.origin.y,*/
|
||||
/*bounds.size.width, bounds.size.height);*/
|
||||
}
|
||||
|
||||
static void
|
||||
translate_with_parent (void)
|
||||
{
|
||||
const int WIDTH = 200;
|
||||
const int HEIGHT = 100;
|
||||
const float x_scale = 2.0f;
|
||||
const int x_margin = 25;
|
||||
GtkWidget *parent = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
GtkWidget *child = gtk_button_new ();
|
||||
graphene_matrix_t transform;
|
||||
int i;
|
||||
|
||||
gtk_widget_set_hexpand (child, FALSE);
|
||||
gtk_widget_set_vexpand (child, FALSE);
|
||||
gtk_widget_set_halign (child, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (child, GTK_ALIGN_START);
|
||||
gtk_widget_set_size_request (child, WIDTH, HEIGHT);
|
||||
gtk_widget_set_margin_start (child, x_margin);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (parent), child);
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_measure (parent, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (parent, &(GtkAllocation){0, 0, WIDTH * 10, HEIGHT * 10}, -1);
|
||||
|
||||
/* First we have no transformation. We take a coordinate and translate it from parent
|
||||
* to child, then back from child to parent and check if we get our original coordinate. */
|
||||
for (i = 0; i < 100; i ++)
|
||||
{
|
||||
double cx, cy;
|
||||
double px, py;
|
||||
|
||||
gtk_widget_translate_coordinatesf (parent, child, i, i, &cx, &cy);
|
||||
|
||||
/* Back up */
|
||||
gtk_widget_translate_coordinatesf (child, parent, cx, cy, &px, &py);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (px, i, 0.1f);
|
||||
g_assert_cmpfloat_with_epsilon (py, i, 0.1f);
|
||||
}
|
||||
|
||||
|
||||
graphene_matrix_init_scale (&transform, x_scale, 1, 1);
|
||||
gtk_widget_set_transform (child, &transform);
|
||||
|
||||
/* Same thing... */
|
||||
for (i = 1; i < 100; i ++)
|
||||
{
|
||||
double cx, cy;
|
||||
double px, py;
|
||||
|
||||
gtk_widget_translate_coordinatesf (parent, child, i, i, &cx, &cy);
|
||||
/*g_message ("### %d/%d in child coords: %f/%f", i, i, cx, cy);*/
|
||||
/*g_assert_cmpfloat_with_epsilon (cx, (-x_margin+i) / x_scale, 0.1f);*/
|
||||
/*g_assert_cmpfloat_with_epsilon (cy, i, 0.1f);*/
|
||||
|
||||
/* Back up */
|
||||
gtk_widget_translate_coordinatesf (child, parent, cx, cy, &px, &py);
|
||||
/*g_message ("%f, %f", px, py);*/
|
||||
/*g_message ("%f/%f in parent coords: %f/%f", cx, cy, px, py);*/
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (px, i, 0.1f);
|
||||
g_assert_cmpfloat_with_epsilon (py, i, 0.1f);
|
||||
}
|
||||
|
||||
|
||||
/* Now try a translation... */
|
||||
gtk_widget_set_margin_start (child, 0);
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_measure (parent, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (parent, &(GtkAllocation){0, 0, WIDTH * 10, HEIGHT * 10}, -1);
|
||||
graphene_matrix_init_translate (&transform,
|
||||
&(graphene_point3d_t){20, 0, 0});
|
||||
gtk_widget_set_transform (child, &transform);
|
||||
|
||||
{
|
||||
double dx, dy;
|
||||
|
||||
gtk_widget_translate_coordinatesf (parent, child, 0, 0, &dx, &dy);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (dx, -20, 0.1);
|
||||
g_assert_cmpfloat_with_epsilon (dy, 0, 0.1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
translate_with_css (void)
|
||||
{
|
||||
const int WIDTH = 200;
|
||||
const int HEIGHT = 100;
|
||||
GtkWidget *parent = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
GtkWidget *child = gtk_button_new ();
|
||||
graphene_matrix_t transform;
|
||||
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (child), "with-border");
|
||||
|
||||
gtk_widget_set_hexpand (child, FALSE);
|
||||
gtk_widget_set_vexpand (child, FALSE);
|
||||
gtk_widget_set_halign (child, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (child, GTK_ALIGN_START);
|
||||
gtk_widget_set_size_request (child, WIDTH, HEIGHT);
|
||||
/*gtk_widget_set_margin_start (child, x_margin);*/
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (parent), child);
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_measure (parent, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (parent, &(GtkAllocation){0, 0, WIDTH * 10, HEIGHT * 10}, -1);
|
||||
|
||||
/* Basic checks without a transformation */
|
||||
{
|
||||
double dx, dy;
|
||||
|
||||
gtk_widget_translate_coordinatesf (child, parent, 0, 0, &dx, &dy);
|
||||
g_assert_cmpfloat_with_epsilon (dx, BORDER_WIDTH, 0.1);
|
||||
g_assert_cmpfloat_with_epsilon (dy, BORDER_WIDTH, 0.1);
|
||||
|
||||
gtk_widget_translate_coordinatesf (parent, child, 0, 0, &dx, &dy);
|
||||
g_assert_cmpfloat_with_epsilon (dx, - BORDER_WIDTH, 0.1);
|
||||
g_assert_cmpfloat_with_epsilon (dy, - BORDER_WIDTH, 0.1);
|
||||
}
|
||||
|
||||
graphene_matrix_init_scale (&transform, 2, 2, 1);
|
||||
gtk_widget_set_transform (child, &transform);
|
||||
|
||||
/* Since the border is also scaled, the values should be double from above. */
|
||||
{
|
||||
double px, py;
|
||||
double cx, cy;
|
||||
|
||||
/*g_message (">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");*/
|
||||
gtk_widget_translate_coordinatesf (child, parent, 0, 0, &px, &py);
|
||||
/*g_message ("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");*/
|
||||
g_assert_cmpfloat_with_epsilon (px, BORDER_WIDTH * 2, 0.1);
|
||||
g_assert_cmpfloat_with_epsilon (py, BORDER_WIDTH * 2, 0.1);
|
||||
|
||||
gtk_widget_translate_coordinatesf (parent, child, px, py, &cx, &cy);
|
||||
g_assert_cmpfloat_with_epsilon (cx, 0, 0.1);
|
||||
g_assert_cmpfloat_with_epsilon (cy, 0, 0.1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
pick (void)
|
||||
{
|
||||
const int WIDTH = 200;
|
||||
const int HEIGHT = 100;
|
||||
GtkWidget *parent = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
GtkWidget *child = gtk_button_new ();
|
||||
graphene_matrix_t transform;
|
||||
|
||||
gtk_widget_set_hexpand (child, TRUE);
|
||||
gtk_widget_set_vexpand (child, TRUE);
|
||||
gtk_widget_set_halign (child, GTK_ALIGN_FILL);
|
||||
gtk_widget_set_valign (child, GTK_ALIGN_FILL);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (parent), child);
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_measure (parent, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (parent, &(GtkAllocation){0, 0, WIDTH, HEIGHT}, -1);
|
||||
|
||||
g_assert (gtk_widget_get_width (child) == WIDTH);
|
||||
g_assert (gtk_widget_get_height (child) == HEIGHT);
|
||||
|
||||
/* We scale the child widget to only half its size on the x axis,
|
||||
* which means doing a pick on the left half of the parent should
|
||||
* return the child but a pick on the right half should return the
|
||||
* parent. */
|
||||
graphene_matrix_init_scale (&transform, 0.5, 1, 1);
|
||||
gtk_widget_set_transform (child, &transform);
|
||||
|
||||
/* XXX These are disabled because gtk_widget_pick()
|
||||
* checks for gtk_widget_is_drawable(), which is not the case here
|
||||
* since the widgets aren't mapped!
|
||||
*/
|
||||
/*g_assert (gtk_widget_pick (parent, WIDTH * 0.25, HEIGHT / 2) == child);*/
|
||||
/*g_assert (gtk_widget_pick (parent, WIDTH * 0.75, HEIGHT / 2) == parent);*/
|
||||
|
||||
/* Now we test translations by simply offsetting the child widget by its own size,
|
||||
* which will move it to the left and entirely out of the parent's allocation. */
|
||||
graphene_matrix_init_translate (&transform,
|
||||
&(graphene_point3d_t){ - WIDTH, 0, 0 });
|
||||
gtk_widget_set_transform (child, &transform);
|
||||
|
||||
/* ... which means that picking on the parent with any positive x coordinate will
|
||||
* yield the parent widget, while negative x coordinates (up until -WIDTH) will
|
||||
* yield the child */
|
||||
/*g_assert (gtk_widget_pick (parent, WIDTH * 0.1, 0) == parent);*/
|
||||
/*g_assert (gtk_widget_pick (parent, WIDTH * 0.9, 0) == parent);*/
|
||||
|
||||
/*double dx, dy;*/
|
||||
/*gtk_widget_translate_coordinatesf (parent, child, - WIDTH * 0.1, 0, &dx, &dy);*/
|
||||
/*g_message ("translate: %f, %f", dx, dy);*/
|
||||
|
||||
|
||||
/*g_assert (gtk_widget_pick (parent, -WIDTH * 0.1, 0) == child);*/
|
||||
/*g_assert (gtk_widget_pick (parent, -WIDTH * 0.9, 0) == child);*/
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
single_widget_scale (void)
|
||||
{
|
||||
GtkWidget *p = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
GtkWidget *w = gtk_button_new ();
|
||||
graphene_matrix_t transform;
|
||||
GtkWidget *picked;
|
||||
int x, y;
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (p), w);
|
||||
|
||||
gtk_widget_set_hexpand (w, TRUE);
|
||||
gtk_widget_set_vexpand (w, TRUE);
|
||||
|
||||
graphene_matrix_init_scale (&transform, 0.5f, 0.5f, 1);
|
||||
gtk_widget_set_transform (w, &transform);
|
||||
|
||||
/* Just to shut up the GtkWidget warning... */
|
||||
gtk_widget_measure (p, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (p, &(GtkAllocation) {0, 0, 100, 100}, -1);
|
||||
|
||||
gtk_widget_translate_coordinates (p, w, 0, 0, &x, &y);
|
||||
g_assert_cmpint (x, ==, 0);
|
||||
g_assert_cmpint (y, ==, 0);
|
||||
|
||||
gtk_widget_translate_coordinates (p, w, 10, 10, &x, &y);
|
||||
g_assert_cmpint (x, ==, 10 / 2);
|
||||
g_assert_cmpint (y, ==, 10 / 2);
|
||||
|
||||
|
||||
gtk_widget_translate_coordinates (p, w, 100, 100, &x, &y);
|
||||
g_assert_cmpint (x, ==, 100 / 2);
|
||||
g_assert_cmpint (y, ==, 100 / 2);
|
||||
|
||||
picked = gtk_widget_pick (p, 0, 0);
|
||||
g_assert (picked == w);
|
||||
|
||||
picked = gtk_widget_pick (p, 51, 51);
|
||||
g_assert (picked == p);
|
||||
}
|
||||
|
||||
static void
|
||||
single_widget_rotate (void)
|
||||
{
|
||||
GtkWidget *p = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
GtkWidget *w = gtk_button_new ();
|
||||
graphene_matrix_t transform;
|
||||
GtkWidget *picked;
|
||||
int x, y;
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (p), w);
|
||||
|
||||
gtk_widget_set_hexpand (w, TRUE);
|
||||
gtk_widget_set_vexpand (w, TRUE);
|
||||
|
||||
graphene_matrix_init_rotate (&transform,
|
||||
45.0, /* Deg */
|
||||
graphene_vec3_z_axis ());
|
||||
gtk_widget_set_transform (w, &transform);
|
||||
|
||||
/* Just to shut up the GtkWidget warning... */
|
||||
gtk_widget_measure (p, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_size_allocate (p, &(GtkAllocation) {0, 0, 100, 100}, -1);
|
||||
|
||||
gtk_widget_translate_coordinates (p, w, 0, 0, &x, &y);
|
||||
g_assert_cmpint (x, ==, 0);
|
||||
g_assert_cmpint (y, ==, 0);
|
||||
|
||||
|
||||
picked = gtk_widget_pick (p, 0, 0);
|
||||
g_assert (picked == w);
|
||||
|
||||
picked = gtk_widget_pick (p, 0, 100);
|
||||
g_assert (picked == w);
|
||||
|
||||
/* Now it gets interesting... */
|
||||
|
||||
/* This should return the button parent since the button is rotated away from the
|
||||
* y axis on top */
|
||||
picked = gtk_widget_pick (p, 20, 0);
|
||||
g_assert (picked == p);
|
||||
|
||||
picked = gtk_widget_pick (p, 50, 10);
|
||||
g_assert (picked == p);
|
||||
|
||||
picked = gtk_widget_pick (p, 100, 100);
|
||||
g_assert (picked == p);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkCssProvider *provider;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
// TODO: Do this only conditionally and/or per-testcase.
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/translate/same-widget", same_widget);
|
||||
g_test_add_func ("/translate/compute-bounds", compute_bounds);
|
||||
g_test_add_func ("/translate/compute-bounds-with-parent", compute_bounds_with_parent);
|
||||
g_test_add_func ("/translate/translate-with-parent", translate_with_parent);
|
||||
g_test_add_func ("/translate/translate-with-css", translate_with_css);
|
||||
g_test_add_func ("/translate/pick", pick);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
Reference in New Issue
Block a user