Made the button cell renderer draw and size much more nicely than it did before, fixing a few bugs along the way.
This commit is contained in:
parent
0907ea47bd
commit
1cb0e9046f
|
@ -3,10 +3,9 @@
|
||||||
|
|
||||||
// TODOs
|
// TODOs
|
||||||
// - it's a rather tight fit
|
// - it's a rather tight fit
|
||||||
// - selected row text color is white
|
// - selected row text color is white (TODO not on 3.22)
|
||||||
// - resizing a column with a button in it crashes the program
|
|
||||||
// - accessibility
|
// - accessibility
|
||||||
// - right side too big?
|
// - right side too big? (TODO reverify)
|
||||||
|
|
||||||
#define cellRendererButtonType (cellRendererButton_get_type())
|
#define cellRendererButtonType (cellRendererButton_get_type())
|
||||||
#define cellRendererButton(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), cellRendererButtonType, cellRendererButton))
|
#define cellRendererButton(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), cellRendererButtonType, cellRendererButton))
|
||||||
|
@ -58,6 +57,7 @@ static GtkSizeRequestMode cellRendererButton_get_request_mode(GtkCellRenderer *r
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is basically what GtkCellRendererToggle did in 3.10 and does in 3.20, as well as what the Foreign Drawing gtk3-demo demo does
|
// this is basically what GtkCellRendererToggle did in 3.10 and does in 3.20, as well as what the Foreign Drawing gtk3-demo demo does
|
||||||
|
// TODO how does this seem to work with highlight on 3.22, and does that work with 3.10 too
|
||||||
static GtkStyleContext *setButtonStyle(GtkWidget *widget)
|
static GtkStyleContext *setButtonStyle(GtkWidget *widget)
|
||||||
{
|
{
|
||||||
GtkStyleContext *base, *context;
|
GtkStyleContext *base, *context;
|
||||||
|
@ -90,7 +90,56 @@ void unsetButtonStyle(GtkStyleContext *context)
|
||||||
g_object_unref(context);
|
g_object_unref(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is based on what GtkCellRendererText does
|
// this is based on what GtkCellRendererText in GTK+ 3.22.30 does
|
||||||
|
// TODO compare to 3.10.9 (https://gitlab.gnome.org/GNOME/gtk/blob/3.10.9/gtk/gtkcellrenderertext.c)
|
||||||
|
static PangoLayout *cellRendererButtonPangoLayout(cellRendererButton *c, GtkWidget *widget)
|
||||||
|
{
|
||||||
|
PangoLayout *layout;
|
||||||
|
|
||||||
|
layout = gtk_widget_create_pango_layout(widget, c->text);
|
||||||
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||||
|
pango_layout_set_width(layout, -1);
|
||||||
|
pango_layout_set_wrap(layout, PANGO_WRAP_CHAR);
|
||||||
|
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is based on what GtkCellRendererText in GTK+ 3.22.30 does
|
||||||
|
// TODO compare to 3.10.9 (https://gitlab.gnome.org/GNOME/gtk/blob/3.10.9/gtk/gtkcellrenderertext.c)
|
||||||
|
static void cellRendererButtonSize(cellRendererButton *c, GtkWidget *widget, PangoLayout *layout, const GdkRectangle *cell_area, gint *xoff, gint *yoff, gint *width, gint *height)
|
||||||
|
{
|
||||||
|
PangoRectangle rect;
|
||||||
|
gint xpad, ypad;
|
||||||
|
gfloat xalign, yalign;
|
||||||
|
|
||||||
|
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad);
|
||||||
|
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
||||||
|
if (rect.width > cell_area->width - (2 * xpad))
|
||||||
|
rect.width = cell_area->width - (2 * xpad);
|
||||||
|
if (rect.height > cell_area->height - (2 * ypad))
|
||||||
|
rect.height = cell_area->height - (2 * ypad);
|
||||||
|
|
||||||
|
gtk_cell_renderer_get_alignment(GTK_CELL_RENDERER(c), &xalign, &yalign);
|
||||||
|
if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
|
||||||
|
xalign = 1.0 - xalign;
|
||||||
|
if (xoff != NULL) {
|
||||||
|
*xoff = cell_area->width - (rect.width + (2 * xpad));
|
||||||
|
*xoff = (gint) ((gfloat) (*xoff) * xalign);
|
||||||
|
}
|
||||||
|
if (yoff != NULL) {
|
||||||
|
*yoff = cell_area->height - (rect.height + (2 * ypad));
|
||||||
|
*yoff = (gint) ((gfloat) (*yoff) * yalign);
|
||||||
|
if (*yoff < 0)
|
||||||
|
*yoff = 0;
|
||||||
|
}
|
||||||
|
if (width != NULL)
|
||||||
|
*width = rect.width - (2 * xpad);
|
||||||
|
if (height != NULL)
|
||||||
|
*height = rect.height - (2 * ypad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is based on what GtkCellRendererText in GTK+ 3.22.30 does
|
||||||
|
// TODO compare to 3.10.9 (https://gitlab.gnome.org/GNOME/gtk/blob/3.10.9/gtk/gtkcellrenderertext.c)
|
||||||
static void cellRendererButton_get_preferred_width(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural)
|
static void cellRendererButton_get_preferred_width(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
cellRendererButton *c = cellRendererButton(r);
|
cellRendererButton *c = cellRendererButton(r);
|
||||||
|
@ -101,19 +150,21 @@ static void cellRendererButton_get_preferred_width(GtkCellRenderer *r, GtkWidget
|
||||||
|
|
||||||
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, NULL);
|
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, NULL);
|
||||||
|
|
||||||
layout = gtk_widget_create_pango_layout(widget, c->text);
|
layout = cellRendererButtonPangoLayout(c, widget);
|
||||||
pango_layout_set_width(layout, -1);
|
|
||||||
pango_layout_get_extents(layout, NULL, &rect);
|
pango_layout_get_extents(layout, NULL, &rect);
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
|
|
||||||
out = 2 * xpad + PANGO_PIXELS_CEIL(rect.width);
|
out = PANGO_PIXELS_CEIL(rect.width) + (2 * xpad);
|
||||||
|
if (rect.x > 0)
|
||||||
|
out += rect.x;
|
||||||
if (minimum != NULL)
|
if (minimum != NULL)
|
||||||
*minimum = out;
|
*minimum = out;
|
||||||
if (natural != NULL)
|
if (natural != NULL)
|
||||||
*natural = out;
|
*natural = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is based on what GtkCellRendererText does
|
// this is based on what GtkCellRendererText in GTK+ 3.22.30 does
|
||||||
|
// TODO compare to 3.10.9 (https://gitlab.gnome.org/GNOME/gtk/blob/3.10.9/gtk/gtkcellrenderertext.c)
|
||||||
static void cellRendererButton_get_preferred_height_for_width(GtkCellRenderer *r, GtkWidget *widget, gint width, gint *minimum, gint *natural)
|
static void cellRendererButton_get_preferred_height_for_width(GtkCellRenderer *r, GtkWidget *widget, gint width, gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
cellRendererButton *c = cellRendererButton(r);
|
cellRendererButton *c = cellRendererButton(r);
|
||||||
|
@ -124,19 +175,20 @@ static void cellRendererButton_get_preferred_height_for_width(GtkCellRenderer *r
|
||||||
|
|
||||||
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad);
|
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad);
|
||||||
|
|
||||||
layout = gtk_widget_create_pango_layout(widget, c->text);
|
layout = cellRendererButtonPangoLayout(c, widget);
|
||||||
pango_layout_set_width(layout, ((2 * xpad + width) * PANGO_SCALE));
|
pango_layout_set_width(layout, (width + (xpad * 2)) * PANGO_SCALE);
|
||||||
pango_layout_get_pixel_size(layout, NULL, &height);
|
pango_layout_get_pixel_size(layout, NULL, &height);
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
|
|
||||||
out = 2 * ypad + height;
|
out = height + (ypad * 2);
|
||||||
if (minimum != NULL)
|
if (minimum != NULL)
|
||||||
*minimum = out;
|
*minimum = out;
|
||||||
if (natural != NULL)
|
if (natural != NULL)
|
||||||
*natural = out;
|
*natural = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is basically what GtkCellRendererText does
|
// this is based on what GtkCellRendererText in GTK+ 3.22.30 does
|
||||||
|
// TODO compare to 3.10.9 (https://gitlab.gnome.org/GNOME/gtk/blob/3.10.9/gtk/gtkcellrenderertext.c)
|
||||||
static void cellRendererButton_get_preferred_height(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural)
|
static void cellRendererButton_get_preferred_height(GtkCellRenderer *r, GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
gint width;
|
gint width;
|
||||||
|
@ -145,84 +197,65 @@ static void cellRendererButton_get_preferred_height(GtkCellRenderer *r, GtkWidge
|
||||||
gtk_cell_renderer_get_preferred_height_for_width(r, widget, width, minimum, natural);
|
gtk_cell_renderer_get_preferred_height_for_width(r, widget, width, minimum, natural);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is based on what GtkCellRendererText does
|
// this is based on what GtkCellRendererText in GTK+ 3.22.30 does
|
||||||
|
// TODO compare to 3.10.9 (https://gitlab.gnome.org/GNOME/gtk/blob/3.10.9/gtk/gtkcellrenderertext.c)
|
||||||
static void cellRendererButton_get_aligned_area(GtkCellRenderer *r, GtkWidget *widget, GtkCellRendererState flags, const GdkRectangle *cell_area, GdkRectangle *aligned_area)
|
static void cellRendererButton_get_aligned_area(GtkCellRenderer *r, GtkWidget *widget, GtkCellRendererState flags, const GdkRectangle *cell_area, GdkRectangle *aligned_area)
|
||||||
{
|
{
|
||||||
cellRendererButton *c = cellRendererButton(r);
|
cellRendererButton *c = cellRendererButton(r);
|
||||||
gint xpad, ypad;
|
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
PangoRectangle rect;
|
gint xoff, yoff;
|
||||||
gfloat xalign, yalign;
|
gint width, height;
|
||||||
gint xoffset, yoffset;
|
|
||||||
|
|
||||||
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad);
|
layout = cellRendererButtonPangoLayout(c, widget);
|
||||||
|
cellRendererButtonSize(c, widget, layout, cell_area,
|
||||||
|
&xoff, &yoff, &width, &height);
|
||||||
|
|
||||||
layout = gtk_widget_create_pango_layout(widget, c->text);
|
aligned_area->x = cell_area->x + xoff;
|
||||||
pango_layout_set_width(layout, -1);
|
aligned_area->y = cell_area->y + yoff;
|
||||||
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
aligned_area->width = width;
|
||||||
|
aligned_area->height = height;
|
||||||
xoffset = 0;
|
|
||||||
yoffset = 0;
|
|
||||||
if (cell_area != NULL) {
|
|
||||||
gtk_cell_renderer_get_alignment(GTK_CELL_RENDERER(c), &xalign, &yalign);
|
|
||||||
xoffset = cell_area->width - (2 * xpad + rect.width);
|
|
||||||
// use explicit casts just to be safe
|
|
||||||
if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
|
|
||||||
xoffset = ((gdouble) xoffset) * (1.0 - xalign);
|
|
||||||
else
|
|
||||||
xoffset *= ((gdouble) xoffset) * xalign;
|
|
||||||
yoffset = yalign * (cell_area->height - (2 * ypad + rect.height));
|
|
||||||
yoffset = MAX(yoffset, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
aligned_area->x = cell_area->x + xoffset;
|
|
||||||
aligned_area->y = cell_area->y + yoffset;
|
|
||||||
aligned_area->width = 2 * xpad + rect.width;
|
|
||||||
aligned_area->height = 2 * ypad + rect.height;
|
|
||||||
|
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is based on both what GtkCellRendererText does and what GtkCellRendererToggle does
|
// this is based on both what GtkCellRendererText on 3.22.30 does and what GtkCellRendererToggle does (TODO verify the latter; both on 3.10.9)
|
||||||
static void cellRendererButton_render(GtkCellRenderer *r, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags)
|
static void cellRendererButton_render(GtkCellRenderer *r, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags)
|
||||||
{
|
{
|
||||||
cellRendererButton *c = cellRendererButton(r);
|
cellRendererButton *c = cellRendererButton(r);
|
||||||
gint xpad, ypad;
|
gint xpad, ypad;
|
||||||
GdkRectangle alignedArea;
|
GdkRectangle alignedArea;
|
||||||
gint xoffset, yoffset;
|
gint xoff, yoff;
|
||||||
GtkStyleContext *context;
|
GtkStyleContext *context;
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
PangoRectangle rect;
|
PangoRectangle rect;
|
||||||
|
|
||||||
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad);
|
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(c), &xpad, &ypad);
|
||||||
gtk_cell_renderer_get_aligned_area(GTK_CELL_RENDERER(c), widget, flags, cell_area, &alignedArea);
|
layout = cellRendererButtonPangoLayout(c, widget);
|
||||||
xoffset = alignedArea.x - cell_area->x;
|
cellRendererButtonSize(c, widget, layout, cell_area,
|
||||||
yoffset = alignedArea.y - cell_area->y;
|
&xoff, &yoff, NULL, NULL);
|
||||||
|
|
||||||
context = setButtonStyle(widget);
|
context = setButtonStyle(widget);
|
||||||
layout = gtk_widget_create_pango_layout(widget, c->text);
|
|
||||||
|
|
||||||
gtk_render_background(context, cr,
|
gtk_render_background(context, cr,
|
||||||
background_area->x + xoffset + xpad,
|
background_area->x + xpad,
|
||||||
background_area->y + yoffset + ypad,
|
background_area->y + ypad,
|
||||||
background_area->width - 2 * xpad,
|
background_area->width - (xpad * 2),
|
||||||
background_area->height - 2 * ypad);
|
background_area->height - (ypad * 2));
|
||||||
gtk_render_frame(context, cr,
|
gtk_render_frame(context, cr,
|
||||||
background_area->x + xoffset + xpad,
|
background_area->x + xpad,
|
||||||
background_area->y + yoffset + ypad,
|
background_area->y + ypad,
|
||||||
background_area->width - 2 * xpad,
|
background_area->width - (xpad * 2),
|
||||||
background_area->height - 2 * ypad);
|
background_area->height - (ypad * 2));
|
||||||
|
|
||||||
pango_layout_set_width(layout, -1);
|
|
||||||
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
||||||
xoffset -= rect.x;
|
xoff -= rect.x;
|
||||||
gtk_render_layout(context, cr,
|
gtk_render_layout(context, cr,
|
||||||
cell_area->x + xoffset + xpad,
|
cell_area->x + xoff + xpad,
|
||||||
cell_area->y + yoffset + ypad,
|
cell_area->y + yoff + ypad,
|
||||||
layout);
|
layout);
|
||||||
|
|
||||||
g_object_unref(layout);
|
|
||||||
unsetButtonStyle(context);
|
unsetButtonStyle(context);
|
||||||
|
g_object_unref(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static guint clickedSignal;
|
static guint clickedSignal;
|
||||||
|
|
Loading…
Reference in New Issue