265 lines
8.1 KiB
C
265 lines
8.1 KiB
C
/* LIBPIKA - The PIKA Library
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
*
|
|
* pikaframe.c
|
|
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
|
|
*
|
|
* 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 3 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
|
|
* <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <babl/babl.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "pikawidgetstypes.h"
|
|
|
|
#include "pikaframe.h"
|
|
#include "pikawidgetsutils.h"
|
|
|
|
|
|
/**
|
|
* SECTION: pikaframe
|
|
* @title: PikaFrame
|
|
* @short_description: A widget providing a HIG-compliant subclass
|
|
* of #GtkFrame.
|
|
*
|
|
* A widget providing a HIG-compliant subclass of #GtkFrame.
|
|
**/
|
|
|
|
|
|
#define DEFAULT_LABEL_SPACING 6
|
|
#define DEFAULT_LABEL_BOLD TRUE
|
|
|
|
#define PIKA_FRAME_INDENT_KEY "pika-frame-indent"
|
|
#define PIKA_FRAME_IN_EXPANDER_KEY "pika-frame-in-expander"
|
|
|
|
|
|
static void pika_frame_style_updated (GtkWidget *widget);
|
|
static gboolean pika_frame_draw (GtkWidget *widget,
|
|
cairo_t *cr);
|
|
static void pika_frame_label_widget_notify (PikaFrame *frame);
|
|
static void pika_frame_child_added (PikaFrame *frame,
|
|
GtkWidget *child,
|
|
gpointer user_data);
|
|
static void pika_frame_apply_margins (PikaFrame *frame);
|
|
static gint pika_frame_get_indent (PikaFrame *frame);
|
|
static gint pika_frame_get_label_spacing (PikaFrame *frame);
|
|
|
|
|
|
G_DEFINE_TYPE (PikaFrame, pika_frame, GTK_TYPE_FRAME)
|
|
|
|
#define parent_class pika_frame_parent_class
|
|
|
|
|
|
static void
|
|
pika_frame_class_init (PikaFrameClass *klass)
|
|
{
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
widget_class->style_updated = pika_frame_style_updated;
|
|
widget_class->draw = pika_frame_draw;
|
|
|
|
gtk_widget_class_install_style_property (widget_class,
|
|
g_param_spec_boolean ("label-bold",
|
|
"Label Bold",
|
|
"Whether the frame's label should be bold",
|
|
DEFAULT_LABEL_BOLD,
|
|
G_PARAM_READABLE));
|
|
gtk_widget_class_install_style_property (widget_class,
|
|
g_param_spec_int ("label-spacing",
|
|
"Label Spacing",
|
|
"The spacing between the label and the frame content",
|
|
0,
|
|
G_MAXINT,
|
|
DEFAULT_LABEL_SPACING,
|
|
G_PARAM_READABLE));
|
|
}
|
|
|
|
|
|
static void
|
|
pika_frame_init (PikaFrame *frame)
|
|
{
|
|
g_signal_connect (frame, "notify::label-widget",
|
|
G_CALLBACK (pika_frame_label_widget_notify),
|
|
NULL);
|
|
g_signal_connect (frame, "add",
|
|
G_CALLBACK (pika_frame_child_added),
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
pika_frame_style_updated (GtkWidget *widget)
|
|
{
|
|
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
|
|
|
|
/* font changes invalidate the indentation */
|
|
g_object_set_data (G_OBJECT (widget), PIKA_FRAME_INDENT_KEY, NULL);
|
|
|
|
pika_frame_label_widget_notify (PIKA_FRAME (widget));
|
|
pika_frame_apply_margins (PIKA_FRAME (widget));
|
|
}
|
|
|
|
static gboolean
|
|
pika_frame_draw (GtkWidget *widget,
|
|
cairo_t *cr)
|
|
{
|
|
GtkWidgetClass *widget_class = g_type_class_peek_parent (parent_class);
|
|
|
|
return widget_class->draw (widget, cr);
|
|
}
|
|
|
|
static void
|
|
pika_frame_label_widget_notify (PikaFrame *frame)
|
|
{
|
|
GtkWidget *label_widget = gtk_frame_get_label_widget (GTK_FRAME (frame));
|
|
|
|
if (label_widget)
|
|
{
|
|
GtkLabel *label = NULL;
|
|
|
|
if (GTK_IS_LABEL (label_widget))
|
|
{
|
|
gfloat xalign, yalign;
|
|
|
|
label = GTK_LABEL (label_widget);
|
|
|
|
gtk_frame_get_label_align (GTK_FRAME (frame), &xalign, &yalign);
|
|
gtk_label_set_xalign (GTK_LABEL (label), xalign);
|
|
gtk_label_set_yalign (GTK_LABEL (label), yalign);
|
|
}
|
|
else if (GTK_IS_BIN (label_widget))
|
|
{
|
|
GtkWidget *child = gtk_bin_get_child (GTK_BIN (label_widget));
|
|
|
|
if (GTK_IS_LABEL (child))
|
|
label = GTK_LABEL (child);
|
|
}
|
|
|
|
if (label)
|
|
{
|
|
gboolean bold;
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (frame),
|
|
"label-bold", &bold,
|
|
NULL);
|
|
|
|
pika_label_set_attributes (label,
|
|
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
|
|
-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
pika_frame_child_added (PikaFrame *frame,
|
|
GtkWidget *child,
|
|
gpointer user_data)
|
|
{
|
|
pika_frame_apply_margins (frame);
|
|
}
|
|
|
|
static void
|
|
pika_frame_apply_margins (PikaFrame *frame)
|
|
{
|
|
GtkWidget *child = gtk_bin_get_child (GTK_BIN (frame));
|
|
|
|
if (child)
|
|
{
|
|
gtk_widget_set_margin_start (child, pika_frame_get_indent (frame));
|
|
gtk_widget_set_margin_top (child, pika_frame_get_label_spacing (frame));
|
|
}
|
|
}
|
|
|
|
static gint
|
|
pika_frame_get_indent (PikaFrame *frame)
|
|
{
|
|
gint width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (frame),
|
|
PIKA_FRAME_INDENT_KEY));
|
|
|
|
if (! width)
|
|
{
|
|
PangoLayout *layout;
|
|
|
|
/* the HIG suggests to use four spaces so do just that */
|
|
layout = gtk_widget_create_pango_layout (GTK_WIDGET (frame), " ");
|
|
pango_layout_get_pixel_size (layout, &width, NULL);
|
|
g_object_unref (layout);
|
|
|
|
g_object_set_data (G_OBJECT (frame),
|
|
PIKA_FRAME_INDENT_KEY, GINT_TO_POINTER (width));
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|
|
static gint
|
|
pika_frame_get_label_spacing (PikaFrame *frame)
|
|
{
|
|
GtkWidget *label_widget = gtk_frame_get_label_widget (GTK_FRAME (frame));
|
|
gint spacing = 0;
|
|
|
|
if ((label_widget && gtk_widget_get_visible (label_widget)) ||
|
|
(g_object_get_data (G_OBJECT (frame), PIKA_FRAME_IN_EXPANDER_KEY)))
|
|
{
|
|
gtk_widget_style_get (GTK_WIDGET (frame),
|
|
"label-spacing", &spacing,
|
|
NULL);
|
|
}
|
|
|
|
return spacing;
|
|
}
|
|
|
|
/**
|
|
* pika_frame_new:
|
|
* @label: (nullable): text to set as the frame's title label (or %NULL for no title)
|
|
*
|
|
* Creates a #PikaFrame widget. A #PikaFrame is a HIG-compliant
|
|
* variant of #GtkFrame. It doesn't render a frame at all but
|
|
* otherwise behaves like a frame. The frame's title is rendered in
|
|
* bold and the frame content is indented four spaces as suggested by
|
|
* the GNOME HIG (see https://developer.gnome.org/hig/stable/).
|
|
*
|
|
* Returns: a new #PikaFrame widget
|
|
*
|
|
* Since: 2.2
|
|
**/
|
|
GtkWidget *
|
|
pika_frame_new (const gchar *label)
|
|
{
|
|
GtkWidget *frame;
|
|
gboolean expander = FALSE;
|
|
|
|
/* somewhat hackish, should perhaps be an object property of PikaFrame */
|
|
if (label && strcmp (label, "<expander>") == 0)
|
|
{
|
|
expander = TRUE;
|
|
label = NULL;
|
|
}
|
|
|
|
frame = g_object_new (PIKA_TYPE_FRAME,
|
|
"label", label,
|
|
NULL);
|
|
|
|
if (expander)
|
|
g_object_set_data (G_OBJECT (frame),
|
|
PIKA_FRAME_IN_EXPANDER_KEY, (gpointer) TRUE);
|
|
|
|
return frame;
|
|
}
|