gimpframe.c 7.67 KB
Newer Older
1 2 3 4 5 6
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 *
 * gimpframe.c
 * Copyright (C) 2004  Sven Neumann <sven@gimp.org>
 *
7
 * This library is free software: you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 3 of the License, or (at your option) any later version.
11 12 13 14 15 16 17
 *
 * 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
18
 * License along with this library.  If not, see
19
 * <https://www.gnu.org/licenses/>.
20 21 22 23
 */

#include "config.h"

24 25
#include <string.h>

26 27
#include <babl/babl.h>

28 29 30 31 32
#include <gtk/gtk.h>

#include "gimpwidgetstypes.h"

#include "gimpframe.h"
33
#include "gimpwidgetsutils.h"
34 35


36 37 38 39 40 41 42 43 44 45
/**
 * SECTION: gimpframe
 * @title: GimpFrame
 * @short_description: A widget providing a HIG-compliant subclass
 *                     of #GtkFrame.
 *
 * A widget providing a HIG-compliant subclass of #GtkFrame.
 **/


46
#define DEFAULT_LABEL_SPACING       6
47 48
#define DEFAULT_LABEL_BOLD          TRUE

49 50
#define GIMP_FRAME_INDENT_KEY       "gimp-frame-indent"
#define GIMP_FRAME_IN_EXPANDER_KEY  "gimp-frame-in-expander"
51 52


53
static void      gimp_frame_style_updated        (GtkWidget      *widget);
54 55
static gboolean  gimp_frame_draw                 (GtkWidget      *widget,
                                                  cairo_t        *cr);
56 57 58 59
static void      gimp_frame_label_widget_notify  (GimpFrame      *frame);
static void      gimp_frame_child_notify         (GimpFrame      *frame);
static gint      gimp_frame_get_indent           (GimpFrame      *frame);
static gint      gimp_frame_get_label_spacing    (GimpFrame      *frame);
60 61


62
G_DEFINE_TYPE (GimpFrame, gimp_frame, GTK_TYPE_FRAME)
63

64
#define parent_class gimp_frame_parent_class
65 66 67 68 69


static void
gimp_frame_class_init (GimpFrameClass *klass)
{
70
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
71

72 73
  widget_class->style_updated = gimp_frame_style_updated;
  widget_class->draw          = gimp_frame_draw;
74

75
  gtk_widget_class_install_style_property (widget_class,
76
                                           g_param_spec_boolean ("label-bold",
77 78
                                                                 "Label Bold",
                                                                 "Whether the frame's label should be bold",
79 80
                                                                 DEFAULT_LABEL_BOLD,
                                                                 G_PARAM_READABLE));
81
  gtk_widget_class_install_style_property (widget_class,
82
                                           g_param_spec_int ("label-spacing",
83 84
                                                             "Label Spacing",
                                                             "The spacing between the label and the frame content",
85 86 87 88 89 90 91 92 93 94 95 96 97
                                                             0,
                                                             G_MAXINT,
                                                             DEFAULT_LABEL_SPACING,
                                                             G_PARAM_READABLE));
}


static void
gimp_frame_init (GimpFrame *frame)
{
  g_signal_connect (frame, "notify::label-widget",
                    G_CALLBACK (gimp_frame_label_widget_notify),
                    NULL);
98 99 100
  g_signal_connect (frame, "notify::child",
                    G_CALLBACK (gimp_frame_child_notify),
                    NULL);
101 102
}

103
static void
104
gimp_frame_style_updated (GtkWidget *widget)
105
{
106 107
  GTK_WIDGET_CLASS (parent_class)->style_updated (widget);

108
  /*  font changes invalidate the indentation  */
109
  g_object_set_data (G_OBJECT (widget), GIMP_FRAME_INDENT_KEY, NULL);
110

111 112
  gimp_frame_label_widget_notify (GIMP_FRAME (widget));
  gimp_frame_child_notify (GIMP_FRAME (widget));
113 114
}

115
static gboolean
116 117
gimp_frame_draw (GtkWidget *widget,
                 cairo_t   *cr)
118
{
119
  GtkWidgetClass *widget_class = g_type_class_peek_parent (parent_class);
120

121
  return widget_class->draw (widget, cr);
122 123 124
}

static void
125
gimp_frame_label_widget_notify (GimpFrame *frame)
126
{
127
  GtkWidget *label_widget = gtk_frame_get_label_widget (GTK_FRAME (frame));
128 129

  if (label_widget)
130
    {
131
      GtkLabel *label = NULL;
132

133
      if (GTK_IS_LABEL (label_widget))
134
        {
135 136 137
          gfloat xalign, yalign;

          label = GTK_LABEL (label_widget);
138

139
          gtk_frame_get_label_align (GTK_FRAME (frame), &xalign, &yalign);
140 141
          gtk_label_set_xalign (GTK_LABEL (label), xalign);
          gtk_label_set_yalign (GTK_LABEL (label), yalign);
142
        }
143
      else if (GTK_IS_BIN (label_widget))
144
        {
145
          GtkWidget *child = gtk_bin_get_child (GTK_BIN (label_widget));
146

147 148 149
          if (GTK_IS_LABEL (child))
            label = GTK_LABEL (child);
        }
150

151 152
      if (label)
        {
153
          gboolean bold;
154

155 156 157
          gtk_widget_style_get (GTK_WIDGET (frame),
                                "label-bold", &bold,
                                NULL);
158

159 160 161
          gimp_label_set_attributes (label,
                                     PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
                                     -1);
162
        }
163 164 165
    }
}

166 167 168 169 170
static void
gimp_frame_child_notify (GimpFrame *frame)
{
  GtkWidget *child = gtk_bin_get_child (GTK_BIN (frame));

171 172 173 174 175
  if (child)
    {
      gtk_widget_set_margin_start (child, gimp_frame_get_indent (frame));
      gtk_widget_set_margin_top (child, gimp_frame_get_label_spacing (frame));
    }
176 177
}

178
static gint
179
gimp_frame_get_indent (GimpFrame *frame)
180
{
181
  gint width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (frame),
182
                                                   GIMP_FRAME_INDENT_KEY));
183

184 185 186 187 188
  if (! width)
    {
      PangoLayout *layout;

      /*  the HIG suggests to use four spaces so do just that  */
189
      layout = gtk_widget_create_pango_layout (GTK_WIDGET (frame), "    ");
190 191 192
      pango_layout_get_pixel_size (layout, &width, NULL);
      g_object_unref (layout);

193
      g_object_set_data (G_OBJECT (frame),
194 195
                         GIMP_FRAME_INDENT_KEY, GINT_TO_POINTER (width));
    }
196 197 198 199

  return width;
}

200
static gint
201
gimp_frame_get_label_spacing (GimpFrame *frame)
202
{
203
  GtkWidget *label_widget = gtk_frame_get_label_widget (GTK_FRAME (frame));
204
  gint       spacing      = 0;
205

206
  if ((label_widget && gtk_widget_get_visible (label_widget)) ||
207
      (g_object_get_data (G_OBJECT (frame), GIMP_FRAME_IN_EXPANDER_KEY)))
208 209 210 211 212 213 214 215 216
    {
      gtk_widget_style_get (GTK_WIDGET (frame),
                            "label_spacing", &spacing,
                            NULL);
    }

  return spacing;
}

217 218 219 220 221 222 223 224
/**
 * gimp_frame_new:
 * @label: text to set as the frame's title label (or %NULL for no title)
 *
 * Creates a #GimpFrame widget. A #GimpFrame 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
225
 * the GNOME HIG (see https://developer.gnome.org/hig/stable/).
226 227 228
 *
 * Return value: a new #GimpFrame widget
 *
229
 * Since: 2.2
230 231 232 233
 **/
GtkWidget *
gimp_frame_new (const gchar *label)
{
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
  GtkWidget *frame;
  gboolean   expander = FALSE;

  /*  somewhat hackish, should perhaps be an object property of GimpFrame  */
  if (label && strcmp (label, "<expander>") == 0)
    {
      expander = TRUE;
      label    = NULL;
    }

  frame = g_object_new (GIMP_TYPE_FRAME,
                        "label", label,
                        NULL);

  if (expander)
    g_object_set_data (G_OBJECT (frame),
250
                       GIMP_FRAME_IN_EXPANDER_KEY, (gpointer) TRUE);
251 252

  return frame;
253
}