Merge branch 'wip/chergert/textview-widgets' into 'master'

textview: use GtkWidget for borders and center_child

See merge request GNOME/gtk!1099
This commit is contained in:
Christian Hergert 2019-10-04 23:30:04 +00:00
commit d71995ab5c
10 changed files with 1116 additions and 769 deletions

View File

@ -3070,7 +3070,7 @@ gtk_text_view_get_line_at_y
gtk_text_view_get_line_yrange
gtk_text_view_get_iter_at_location
gtk_text_view_get_iter_at_position
gtk_text_view_buffer_to_surface_coords
gtk_text_view_buffer_to_window_coords
gtk_text_view_window_to_buffer_coords
gtk_text_view_set_border_window_size
gtk_text_view_get_border_window_size
@ -3085,8 +3085,10 @@ GtkTextChildAnchor
gtk_text_child_anchor_new
gtk_text_child_anchor_get_widgets
gtk_text_child_anchor_get_deleted
gtk_text_view_add_child_in_window
gtk_text_view_move_child
gtk_text_view_get_gutter
gtk_text_view_set_gutter
gtk_text_view_add_overlay
gtk_text_view_move_overlay
gtk_text_view_set_wrap_mode
gtk_text_view_get_wrap_mode
gtk_text_view_set_editable

View File

@ -513,7 +513,7 @@ gtk_text_view_accessible_get_character_extents (AtkText *text,
*height = rectangle.height;
*width = rectangle.width;
gtk_text_view_buffer_to_surface_coords (view, GTK_TEXT_WINDOW_WIDGET,
gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_WIDGET,
rectangle.x, rectangle.y, x, y);
if (coords != ATK_XY_WINDOW)
{

View File

@ -158,6 +158,19 @@ set_attributes_from_style (GtkStyleContext *context,
gtk_style_context_get (context, "font", &values->font, NULL);
}
static gint
get_border_window_size (GtkTextView *text_view,
GtkTextWindowType window_type)
{
GtkWidget *gutter;
gutter = gtk_text_view_get_gutter (text_view, window_type);
if (gutter != NULL)
return gtk_widget_get_width (gutter);
return 0;
}
GdkPaintable *
gtk_text_util_create_rich_drag_icon (GtkWidget *widget,
GtkTextBuffer *buffer,
@ -208,8 +221,8 @@ gtk_text_util_create_rich_drag_icon (GtkWidget *widget,
if (GTK_IS_TEXT_VIEW (widget))
{
layout_width = layout_width
- gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_LEFT)
- gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_RIGHT);
- get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_LEFT)
- get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_RIGHT);
}
style->direction = gtk_widget_get_direction (widget);

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,6 @@ G_BEGIN_DECLS
/**
* GtkTextWindowType:
* @GTK_TEXT_WINDOW_PRIVATE: Private value, used internally
* @GTK_TEXT_WINDOW_WIDGET: Window that floats over scrolling areas.
* @GTK_TEXT_WINDOW_TEXT: Scrollable text window.
* @GTK_TEXT_WINDOW_LEFT: Left side border window.
@ -56,8 +55,7 @@ G_BEGIN_DECLS
*/
typedef enum
{
GTK_TEXT_WINDOW_PRIVATE,
GTK_TEXT_WINDOW_WIDGET,
GTK_TEXT_WINDOW_WIDGET = 1,
GTK_TEXT_WINDOW_TEXT,
GTK_TEXT_WINDOW_LEFT,
GTK_TEXT_WINDOW_RIGHT,
@ -266,7 +264,7 @@ void gtk_text_view_get_line_at_y (GtkTextView *text_view
gint *line_top);
GDK_AVAILABLE_IN_ALL
void gtk_text_view_buffer_to_surface_coords (GtkTextView *text_view,
void gtk_text_view_buffer_to_window_coords (GtkTextView *text_view,
GtkTextWindowType win,
gint buffer_x,
gint buffer_y,
@ -280,14 +278,6 @@ void gtk_text_view_window_to_buffer_coords (GtkTextView *text_view,
gint *buffer_x,
gint *buffer_y);
GDK_AVAILABLE_IN_ALL
void gtk_text_view_set_border_window_size (GtkTextView *text_view,
GtkTextWindowType type,
gint size);
GDK_AVAILABLE_IN_ALL
gint gtk_text_view_get_border_window_size (GtkTextView *text_view,
GtkTextWindowType type);
GDK_AVAILABLE_IN_ALL
gboolean gtk_text_view_forward_display_line (GtkTextView *text_view,
GtkTextIter *iter);
@ -316,22 +306,26 @@ void gtk_text_view_reset_im_context (GtkTextView
/* Adding child widgets */
GDK_AVAILABLE_IN_ALL
GtkWidget *gtk_text_view_get_gutter (GtkTextView *text_view,
GtkTextWindowType win);
GDK_AVAILABLE_IN_ALL
void gtk_text_view_set_gutter (GtkTextView *text_view,
GtkTextWindowType win,
GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_text_view_add_child_at_anchor (GtkTextView *text_view,
GtkWidget *child,
GtkTextChildAnchor *anchor);
GDK_AVAILABLE_IN_ALL
void gtk_text_view_add_child_in_window (GtkTextView *text_view,
void gtk_text_view_add_overlay (GtkTextView *text_view,
GtkWidget *child,
GtkTextWindowType which_window,
/* window coordinates */
gint xpos,
gint ypos);
GDK_AVAILABLE_IN_ALL
void gtk_text_view_move_child (GtkTextView *text_view,
void gtk_text_view_move_overlay (GtkTextView *text_view,
GtkWidget *child,
/* window coordinates */
gint xpos,
gint ypos);

516
gtk/gtktextviewchild.c Normal file
View File

@ -0,0 +1,516 @@
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
/* GTK - The GIMP Toolkit
* gtk_text_view_child.c Copyright (C) 2019 Red Hat, Inc.
*
* This library 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 library 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 library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcssnodeprivate.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtkstylecontext.h"
#include "gtktextview.h"
#include "gtktextviewchildprivate.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
typedef struct
{
GList link;
GtkWidget *widget;
int x;
int y;
} Overlay;
struct _GtkTextViewChild
{
GtkContainer parent_instance;
GtkTextWindowType window_type;
GQueue overlays;
int xoffset;
int yoffset;
GtkWidget *child;
};
enum {
PROP_0,
PROP_WINDOW_TYPE,
N_PROPS
};
G_DEFINE_TYPE (GtkTextViewChild, gtk_text_view_child, GTK_TYPE_CONTAINER)
static GParamSpec *properties[N_PROPS];
static Overlay *
overlay_new (GtkWidget *widget,
int x,
int y)
{
Overlay *overlay;
overlay = g_slice_new0 (Overlay);
overlay->link.data = overlay;
overlay->widget = g_object_ref (widget);
overlay->x = x;
overlay->y = y;
return overlay;
}
static void
overlay_free (Overlay *overlay)
{
g_assert (overlay->link.prev == NULL);
g_assert (overlay->link.next == NULL);
g_object_unref (overlay->widget);
g_slice_free (Overlay, overlay);
}
static void
gtk_text_view_child_remove_overlay (GtkTextViewChild *self,
Overlay *overlay)
{
g_queue_unlink (&self->overlays, &overlay->link);
gtk_widget_unparent (overlay->widget);
overlay_free (overlay);
}
static Overlay *
gtk_text_view_child_get_overlay (GtkTextViewChild *self,
GtkWidget *widget)
{
GList *iter;
for (iter = self->overlays.head; iter; iter = iter->next)
{
Overlay *overlay = iter->data;
if (overlay->widget == widget)
return overlay;
}
return NULL;
}
static void
gtk_text_view_child_add (GtkContainer *container,
GtkWidget *widget)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (container);
if (self->child != NULL)
{
g_warning ("%s allows a single child and already contains a %s",
G_OBJECT_TYPE_NAME (self),
G_OBJECT_TYPE_NAME (widget));
return;
}
self->child = g_object_ref (widget);
gtk_widget_set_parent (widget, GTK_WIDGET (self));
}
static void
gtk_text_view_child_remove (GtkContainer *container,
GtkWidget *widget)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (container);
if (widget == self->child)
{
self->child = NULL;
gtk_widget_unparent (widget);
g_object_unref (widget);
}
else
{
Overlay *overlay = gtk_text_view_child_get_overlay (self, widget);
if (overlay != NULL)
gtk_text_view_child_remove_overlay (self, overlay);
}
}
static void
gtk_text_view_child_forall (GtkContainer *container,
GtkCallback callback,
gpointer callback_data)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (container);
const GList *iter;
if (self->child != NULL)
callback (self->child, callback_data);
iter = self->overlays.head;
while (iter != NULL)
{
Overlay *overlay = iter->data;
iter = iter->next;
callback (overlay->widget, callback_data);
}
}
static void
gtk_text_view_child_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *min_size,
int *nat_size,
int *min_baseline,
int *nat_baseline)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (widget);
const GList *iter;
int real_min_size = 0;
int real_nat_size = 0;
if (self->child != NULL)
gtk_widget_measure (self->child,
orientation,
for_size,
&real_min_size,
&real_nat_size,
NULL,
NULL);
for (iter = self->overlays.head; iter; iter = iter->next)
{
Overlay *overlay = iter->data;
int child_min_size = 0;
int child_nat_size = 0;
gtk_widget_measure (overlay->widget,
orientation,
for_size,
&child_min_size,
&child_nat_size,
NULL,
NULL);
if (child_min_size > real_min_size)
real_min_size = child_min_size;
if (child_nat_size > real_nat_size)
real_nat_size = child_nat_size;
}
if (min_size)
*min_size = real_min_size;
if (nat_size)
*nat_size = real_nat_size;
if (min_baseline)
*min_baseline = -1;
if (nat_baseline)
*nat_baseline = -1;
}
static void
gtk_text_view_child_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (widget);
GtkRequisition min_req;
GdkRectangle rect;
const GList *iter;
GTK_WIDGET_CLASS (gtk_text_view_child_parent_class)->size_allocate (widget, width, height, baseline);
if (self->child != NULL)
{
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
gtk_widget_size_allocate (self->child, &rect, baseline);
}
for (iter = self->overlays.head; iter; iter = iter->next)
{
Overlay *overlay = iter->data;
gtk_widget_get_preferred_size (overlay->widget, &min_req, NULL);
rect.width = min_req.width;
rect.height = min_req.height;
if (self->window_type == GTK_TEXT_WINDOW_TEXT ||
self->window_type == GTK_TEXT_WINDOW_TOP ||
self->window_type == GTK_TEXT_WINDOW_BOTTOM)
rect.x = overlay->x - self->xoffset;
else
rect.x = overlay->x;
if (self->window_type == GTK_TEXT_WINDOW_TEXT ||
self->window_type == GTK_TEXT_WINDOW_RIGHT ||
self->window_type == GTK_TEXT_WINDOW_LEFT)
rect.y = overlay->y - self->yoffset;
else
rect.y = overlay->y;
gtk_widget_size_allocate (overlay->widget, &rect, -1);
}
}
static void
gtk_text_view_child_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (widget);
const GList *iter;
GTK_WIDGET_CLASS (gtk_text_view_child_parent_class)->snapshot (widget, snapshot);
if (self->child)
gtk_widget_snapshot_child (widget, self->child, snapshot);
for (iter = self->overlays.head; iter; iter = iter->next)
{
Overlay *overlay = iter->data;
gtk_widget_snapshot_child (widget, overlay->widget, snapshot);
}
}
static void
gtk_text_view_child_constructed (GObject *object)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (object);
GtkCssNode *css_node;
G_OBJECT_CLASS (gtk_text_view_child_parent_class)->constructed (object);
css_node = gtk_widget_get_css_node (GTK_WIDGET (self));
switch (self->window_type)
{
case GTK_TEXT_WINDOW_LEFT:
gtk_css_node_set_name (css_node, "border");
gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_LEFT));
break;
case GTK_TEXT_WINDOW_RIGHT:
gtk_css_node_set_name (css_node, "border");
gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_RIGHT));
break;
case GTK_TEXT_WINDOW_TOP:
gtk_css_node_set_name (css_node, "border");
gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_TOP));
break;
case GTK_TEXT_WINDOW_BOTTOM:
gtk_css_node_set_name (css_node, "border");
gtk_css_node_add_class (css_node, g_quark_from_static_string (GTK_STYLE_CLASS_BOTTOM));
break;
case GTK_TEXT_WINDOW_TEXT:
gtk_css_node_set_name (css_node, "text");
break;
case GTK_TEXT_WINDOW_WIDGET:
default:
break;
}
}
static void
gtk_text_view_child_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (object);
switch (prop_id)
{
case PROP_WINDOW_TYPE:
g_value_set_enum (value, self->window_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_text_view_child_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkTextViewChild *self = GTK_TEXT_VIEW_CHILD (object);
switch (prop_id)
{
case PROP_WINDOW_TYPE:
self->window_type = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_text_view_child_class_init (GtkTextViewChildClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
object_class->constructed = gtk_text_view_child_constructed;
object_class->get_property = gtk_text_view_child_get_property;
object_class->set_property = gtk_text_view_child_set_property;
widget_class->measure = gtk_text_view_child_measure;
widget_class->size_allocate = gtk_text_view_child_size_allocate;
widget_class->snapshot = gtk_text_view_child_snapshot;
container_class->add = gtk_text_view_child_add;
container_class->remove = gtk_text_view_child_remove;
container_class->forall = gtk_text_view_child_forall;
/**
* GtkTextViewChild:window-type:
*
* The "window-type" property is the #GtkTextWindowType of the
* #GtkTextView that the child is attached.
*/
properties[PROP_WINDOW_TYPE] =
g_param_spec_enum ("window-type",
P_("Window Type"),
P_("The GtkTextWindowType"),
GTK_TYPE_TEXT_WINDOW_TYPE,
GTK_TEXT_WINDOW_TEXT,
GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
gtk_text_view_child_init (GtkTextViewChild *self)
{
self->window_type = GTK_TEXT_WINDOW_TEXT;
gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
}
GtkWidget *
gtk_text_view_child_new (GtkTextWindowType window_type)
{
g_return_val_if_fail (window_type == GTK_TEXT_WINDOW_LEFT ||
window_type == GTK_TEXT_WINDOW_RIGHT ||
window_type == GTK_TEXT_WINDOW_TOP ||
window_type == GTK_TEXT_WINDOW_BOTTOM ||
window_type == GTK_TEXT_WINDOW_TEXT,
NULL);
return g_object_new (GTK_TYPE_TEXT_VIEW_CHILD,
"window-type", window_type,
NULL);
}
void
gtk_text_view_child_add_overlay (GtkTextViewChild *self,
GtkWidget *widget,
int xpos,
int ypos)
{
Overlay *overlay;
g_return_if_fail (GTK_IS_TEXT_VIEW_CHILD (self));
g_return_if_fail (GTK_IS_WIDGET (widget));
overlay = overlay_new (widget, xpos, ypos);
g_queue_push_tail (&self->overlays, &overlay->link);
gtk_widget_set_parent (widget, GTK_WIDGET (self));
}
void
gtk_text_view_child_move_overlay (GtkTextViewChild *self,
GtkWidget *widget,
int xpos,
int ypos)
{
Overlay *overlay;
g_return_if_fail (GTK_IS_TEXT_VIEW_CHILD (self));
g_return_if_fail (GTK_IS_WIDGET (widget));
overlay = gtk_text_view_child_get_overlay (self, widget);
if (overlay != NULL)
{
overlay->x = xpos;
overlay->y = ypos;
if (gtk_widget_get_visible (GTK_WIDGET (self)) &&
gtk_widget_get_visible (widget))
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
}
GtkTextWindowType
gtk_text_view_child_get_window_type (GtkTextViewChild *self)
{
g_return_val_if_fail (GTK_IS_TEXT_VIEW_CHILD (self), 0);
return self->window_type;
}
void
gtk_text_view_child_set_offset (GtkTextViewChild *self,
int xoffset,
int yoffset)
{
gboolean changed = FALSE;
g_return_if_fail (GTK_IS_TEXT_VIEW_CHILD (self));
if (self->window_type == GTK_TEXT_WINDOW_TEXT ||
self->window_type == GTK_TEXT_WINDOW_TOP ||
self->window_type == GTK_TEXT_WINDOW_BOTTOM)
{
if (self->xoffset != xoffset)
{
self->xoffset = xoffset;
changed = TRUE;
}
}
if (self->window_type == GTK_TEXT_WINDOW_TEXT ||
self->window_type == GTK_TEXT_WINDOW_LEFT ||
self->window_type == GTK_TEXT_WINDOW_RIGHT)
{
if (self->yoffset != yoffset)
{
self->yoffset = yoffset;
changed = TRUE;
}
}
if (changed)
gtk_widget_queue_draw (GTK_WIDGET (self));
}

View File

@ -0,0 +1,48 @@
/* GTK - The GIMP Toolkit
* gtktextviewchild-private.h Copyright (C) 2019 Red Hat, Inc.
*
* This library 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 library 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 library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_TEXT_VIEW_CHILD_PRIVATE_H__
#define __GTK_TEXT_VIEW_CHILD_PRIVATE_H__
#include <gtk/gtkcontainer.h>
#include <gtk/gtktextview.h>
#define GTK_TYPE_TEXT_VIEW_CHILD (gtk_text_view_child_get_type())
G_GNUC_INTERNAL
G_DECLARE_FINAL_TYPE (GtkTextViewChild, gtk_text_view_child, GTK, TEXT_VIEW_CHILD, GtkContainer)
G_GNUC_INTERNAL
GtkWidget *gtk_text_view_child_new (GtkTextWindowType window_type);
G_GNUC_INTERNAL
GtkTextWindowType gtk_text_view_child_get_window_type (GtkTextViewChild *self);
G_GNUC_INTERNAL
void gtk_text_view_child_add_overlay (GtkTextViewChild *self,
GtkWidget *widget,
int xpos,
int ypos);
G_GNUC_INTERNAL
void gtk_text_view_child_move_overlay (GtkTextViewChild *self,
GtkWidget *widget,
int xpos,
int ypos);
G_GNUC_INTERNAL
void gtk_text_view_child_set_offset (GtkTextViewChild *child,
int xoffset,
int yoffset);
#endif /* __GTK_TEXT_VIEW_CHILD_PRIVATE_H__ */

View File

@ -145,6 +145,7 @@ gtk_private_sources = files([
'gtkstylecascade.c',
'gtkstyleproperty.c',
'gtktextbtree.c',
'gtktextviewchild.c',
'gtktrashmonitor.c',
'gtktreedatalist.c',
])

View File

@ -193,9 +193,8 @@ main (int argc, char **argv)
gtk_container_add (GTK_CONTAINER (window), sw);
gtk_container_add (GTK_CONTAINER (sw), textview);
gtk_text_view_add_child_in_window (GTK_TEXT_VIEW (textview),
gtk_text_view_add_overlay (GTK_TEXT_VIEW (textview),
button,
GTK_TEXT_WINDOW_TEXT,
50, 150);
gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (textview),

View File

@ -17,12 +17,23 @@
#include <gtk/gtk.h>
static void
set_border_window_size (GtkTextView *text_view,
GtkTextWindowType win,
gint size)
{
GtkWidget *label;
label = gtk_label_new (NULL);
gtk_widget_set_size_request (label, size, size);
gtk_text_view_set_gutter (text_view, win, label);
}
G_MODULE_EXPORT void
add_border_windows (GtkTextView *text_view)
{
gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, 30);
gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_RIGHT, 30);
gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_TOP, 30);
gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_BOTTOM, 30);
set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, 30);
set_border_window_size (text_view, GTK_TEXT_WINDOW_RIGHT, 30);
set_border_window_size (text_view, GTK_TEXT_WINDOW_TOP, 30);
set_border_window_size (text_view, GTK_TEXT_WINDOW_BOTTOM, 30);
}