]> Pileus Git - ~andy/gtk/blob - gtk/gtklabel.c
call the base class init fucntions from all parent types upon class
[~andy/gtk] / gtk / gtklabel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include <string.h>
20 #include "gtklabel.h"
21
22
23 enum {
24   ARG_0,
25   ARG_LABEL,
26   ARG_JUSTIFY
27 };
28
29 static void gtk_label_class_init   (GtkLabelClass  *klass);
30 static void gtk_label_init         (GtkLabel       *label);
31 static void gtk_label_set_arg      (GtkObject      *object,
32                                     GtkArg         *arg,
33                                     guint           arg_id);
34 static void gtk_label_get_arg      (GtkObject      *object,
35                                     GtkArg         *arg,
36                                     guint           arg_id);
37 static void gtk_label_finalize     (GtkObject      *object);
38 static void gtk_label_size_request (GtkWidget      *widget,
39                                     GtkRequisition *requisition);
40 static gint gtk_label_expose       (GtkWidget      *widget,
41                                     GdkEventExpose *event);
42 static void gtk_label_state_changed (GtkWidget      *widget,
43                                      guint           previous_state);
44 static void gtk_label_style_set     (GtkWidget      *widget,
45                                      GtkStyle       *previous_style);
46
47
48
49 static GtkMiscClass *parent_class = NULL;
50
51
52 GtkType
53 gtk_label_get_type (void)
54 {
55   static GtkType label_type = 0;
56   
57   if (!label_type)
58     {
59       GtkTypeInfo label_info =
60       {
61         "GtkLabel",
62         sizeof (GtkLabel),
63         sizeof (GtkLabelClass),
64         (GtkClassInitFunc) gtk_label_class_init,
65         (GtkObjectInitFunc) gtk_label_init,
66         /* reversed_1 */ NULL,
67         /* reversed_2 */ NULL,
68         (GtkClassInitFunc) NULL,
69       };
70       
71       label_type = gtk_type_unique (gtk_misc_get_type (), &label_info);
72       gtk_type_set_chunk_alloc (label_type, 32);
73     }
74   
75   return label_type;
76 }
77
78 static void
79 gtk_label_class_init (GtkLabelClass *class)
80 {
81   GtkObjectClass *object_class;
82   GtkWidgetClass *widget_class;
83   
84   object_class = (GtkObjectClass*) class;
85   widget_class = (GtkWidgetClass*) class;
86   
87   parent_class = gtk_type_class (gtk_misc_get_type ());
88   
89   gtk_object_add_arg_type ("GtkLabel::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
90   gtk_object_add_arg_type ("GtkLabel::justify", GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFY);
91
92   object_class->set_arg = gtk_label_set_arg;
93   object_class->get_arg = gtk_label_get_arg;
94   object_class->finalize = gtk_label_finalize;
95   
96   widget_class->size_request = gtk_label_size_request;
97   widget_class->expose_event = gtk_label_expose;
98   widget_class->style_set    = gtk_label_style_set;
99   widget_class->state_changed = gtk_label_state_changed;
100 }
101
102 static void
103 gtk_label_set_arg (GtkObject      *object,
104                    GtkArg         *arg,
105                    guint           arg_id)
106 {
107   GtkLabel *label;
108
109   label = GTK_LABEL (object);
110
111   switch (arg_id)
112     {
113     case ARG_LABEL:
114       gtk_label_set (label, GTK_VALUE_STRING (*arg));
115       break;
116     case ARG_JUSTIFY:
117       gtk_label_set_justify (label, GTK_VALUE_ENUM (*arg));
118       break;
119     default:
120       break;
121     }
122 }
123
124 static void
125 gtk_label_get_arg (GtkObject      *object,
126                    GtkArg         *arg,
127                    guint           arg_id)
128 {
129   GtkLabel *label;
130
131   label = GTK_LABEL (object);
132
133   switch (arg_id)
134     {
135     case ARG_LABEL:
136       GTK_VALUE_STRING (*arg) = g_strdup (label->label);
137       break;
138     case ARG_JUSTIFY:
139       GTK_VALUE_ENUM (*arg) = label->jtype;
140       break;
141     default:
142       arg->type = GTK_TYPE_INVALID;
143       break;
144     }
145 }
146
147 static void
148 gtk_label_init (GtkLabel *label)
149 {
150   GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
151   
152   label->label = NULL;
153   label->row = NULL;
154   label->max_width = 0;
155   label->jtype = GTK_JUSTIFY_CENTER;
156   label->needs_clear = FALSE;
157   
158   gtk_label_set (label, "");
159 }
160
161 GtkWidget*
162 gtk_label_new (const gchar *str)
163 {
164   GtkLabel *label;
165   
166   g_return_val_if_fail (str != NULL, NULL);
167   
168   label = gtk_type_new (gtk_label_get_type ());
169   
170   gtk_label_set (label, str);
171   
172   return GTK_WIDGET (label);
173 }
174
175 void
176 gtk_label_set (GtkLabel    *label,
177                const gchar *str)
178 {
179   char* p;
180   
181   g_return_if_fail (label != NULL);
182   g_return_if_fail (GTK_IS_LABEL (label));
183   g_return_if_fail (str != NULL);
184   
185   if (label->label)
186     g_free (label->label);
187   label->label = g_strdup (str);
188   
189   if (label->row)
190     g_slist_free (label->row);
191   label->row = NULL;
192   label->row = g_slist_append (label->row, label->label);
193   p = label->label;
194   while ((p = strchr(p, '\n')))
195     label->row = g_slist_append (label->row, ++p);
196   
197   if (GTK_WIDGET_VISIBLE (label))
198     {
199       if (GTK_WIDGET_MAPPED (label))
200         gdk_window_clear_area (GTK_WIDGET (label)->window,
201                                GTK_WIDGET (label)->allocation.x,
202                                GTK_WIDGET (label)->allocation.y,
203                                GTK_WIDGET (label)->allocation.width,
204                                GTK_WIDGET (label)->allocation.height);
205       
206       gtk_widget_queue_resize (GTK_WIDGET (label));
207     }
208 }
209
210 void
211 gtk_label_set_justify (GtkLabel        *label,
212                        GtkJustification jtype)
213 {
214   g_return_if_fail (label != NULL);
215   g_return_if_fail (GTK_IS_LABEL (label));
216   
217   if ((GtkJustification) label->jtype != jtype)
218     {
219       label->jtype = jtype;
220       
221       if (GTK_WIDGET_VISIBLE (label))
222         {
223           if (GTK_WIDGET_MAPPED (label))
224             gdk_window_clear_area (GTK_WIDGET (label)->window,
225                                    GTK_WIDGET (label)->allocation.x,
226                                    GTK_WIDGET (label)->allocation.y,
227                                    GTK_WIDGET (label)->allocation.width,
228                                    GTK_WIDGET (label)->allocation.height);
229           
230           gtk_widget_queue_resize (GTK_WIDGET (label));
231         }
232     }
233 }
234
235 void
236 gtk_label_get (GtkLabel  *label,
237                gchar    **str)
238 {
239   g_return_if_fail (label != NULL);
240   g_return_if_fail (GTK_IS_LABEL (label));
241   g_return_if_fail (str != NULL);
242   
243   *str = label->label;
244 }
245
246
247 static void
248 gtk_label_finalize (GtkObject *object)
249 {
250   GtkLabel *label;
251   
252   g_return_if_fail (object != NULL);
253   g_return_if_fail (GTK_IS_LABEL (object));
254   
255   label = GTK_LABEL (object);
256   
257   g_free (label->label);
258   g_slist_free (label->row);
259   
260   (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
261 }
262
263 static void
264 gtk_label_size_request (GtkWidget      *widget,
265                         GtkRequisition *requisition)
266 {
267   GtkLabel *label;
268   GSList *row;
269   gint width;
270   
271   g_return_if_fail (widget != NULL);
272   g_return_if_fail (GTK_IS_LABEL (widget));
273   g_return_if_fail (requisition != NULL);
274   
275   label = GTK_LABEL (widget);
276   
277   row = label->row;
278   width = 0;
279   while (row)
280     {
281       if (row->next)
282         width = MAX (width,
283                      gdk_text_width (GTK_WIDGET (label)->style->font,
284                                      row->data,
285                                      (gchar*) row->next->data - (gchar*) row->data - 1));
286       else
287         width = MAX (width, gdk_string_width (GTK_WIDGET (label)->style->font, row->data));
288       row = row->next;
289     }
290
291   label->max_width = width;
292   requisition->width = width + label->misc.xpad * 2;
293   requisition->height = ((GTK_WIDGET (label)->style->font->ascent +
294                           GTK_WIDGET (label)->style->font->descent + 2) *
295                          g_slist_length(label->row) +
296                          label->misc.ypad * 2);
297 }
298
299 static gint
300 gtk_label_expose (GtkWidget      *widget,
301                   GdkEventExpose *event)
302 {
303   GtkLabel *label;
304   GtkMisc *misc;
305   GSList *row;
306   gint state;
307   gint offset;
308   gint len;
309   gint x, y;
310   
311   g_return_val_if_fail (widget != NULL, FALSE);
312   g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
313   g_return_val_if_fail (event != NULL, FALSE);
314   
315   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
316     {
317       label = GTK_LABEL (widget);
318       misc = GTK_MISC (widget);
319       
320       state = widget->state;
321       
322       /*
323        * GC Clipping
324        */
325       gdk_gc_set_clip_rectangle (widget->style->white_gc, &event->area);
326       gdk_gc_set_clip_rectangle (widget->style->fg_gc[state], &event->area);
327       
328       /* We clear the whole allocation here so that if a partial
329        * expose is triggered we don't just clear part and mess up
330        * when the queued redraw comes along. (There will always
331        * be a complete queued redraw when the needs_clear flag
332        * is set.)
333        */
334       if (label->needs_clear)
335         {
336           gdk_window_clear_area (widget->window,
337                                  widget->allocation.x,
338                                  widget->allocation.y,
339                                  widget->allocation.width,
340                                  widget->allocation.height);
341           
342           label->needs_clear = FALSE;
343         }
344       
345       x = widget->allocation.x + misc->xpad +
346         (widget->allocation.width - (label->max_width + label->misc.xpad * 2))
347         * misc->xalign + 0.5;
348       
349       y = (widget->allocation.y * (1.0 - misc->yalign) +
350            (widget->allocation.y + widget->allocation.height -
351             (widget->requisition.height - misc->ypad * 2)) *
352            misc->yalign + widget->style->font->ascent) + 1.5;
353       
354       row = label->row;
355       while (row && row->next)
356         {
357           len = (gchar*) row->next->data - (gchar*) row->data - 1;
358           offset = 0;
359           
360           if (label->jtype == GTK_JUSTIFY_CENTER)
361             offset = (label->max_width - gdk_text_width (widget->style->font, row->data, len)) / 2;
362           
363           else if (label->jtype == GTK_JUSTIFY_RIGHT)
364             offset = (label->max_width - gdk_text_width (widget->style->font, row->data, len));
365           
366           if (state == GTK_STATE_INSENSITIVE)
367             gdk_draw_text (widget->window, widget->style->font,
368                            widget->style->white_gc,
369                            offset + x + 1, y + 1, row->data, len);
370           
371           gdk_draw_text (widget->window, widget->style->font,
372                          widget->style->fg_gc[state],
373                          offset + x, y, row->data, len);
374           row = row->next;
375           y += widget->style->font->ascent + widget->style->font->descent + 2;
376         }
377       
378       /* 
379        * COMMENT: we can avoid gdk_text_width() calls here storing in label->row
380        * the widths of the rows calculated in gtk_label_set.
381        * Once we have a wrapping interface we can support GTK_JUSTIFY_FILL.
382        */
383       offset = 0;
384       
385       if (label->jtype == GTK_JUSTIFY_CENTER)
386         offset = (label->max_width - gdk_string_width (widget->style->font, row->data)) / 2;
387       
388       else if (label->jtype == GTK_JUSTIFY_RIGHT)
389         offset = (label->max_width - gdk_string_width (widget->style->font, row->data));
390       
391       if (state == GTK_STATE_INSENSITIVE)
392         gdk_draw_string (widget->window, widget->style->font,
393                          widget->style->white_gc,
394                          offset + x + 1, y + 1, row->data);
395       
396       gdk_draw_string (widget->window, widget->style->font,
397                        widget->style->fg_gc[state],
398                        offset + x, y, row->data);
399       
400       gdk_gc_set_clip_mask (widget->style->white_gc, NULL);
401       gdk_gc_set_clip_mask (widget->style->fg_gc[state], NULL);
402       
403     }
404   return TRUE;
405 }
406
407 static void 
408 gtk_label_state_changed (GtkWidget      *widget,
409                          guint           previous_state)
410 {
411   if (GTK_WIDGET_DRAWABLE (widget))
412     GTK_LABEL (widget)->needs_clear = TRUE;
413 }
414
415 static void 
416 gtk_label_style_set (GtkWidget  *widget,
417                      GtkStyle   *previous_style)
418 {
419   if (GTK_WIDGET_DRAWABLE (widget))
420     GTK_LABEL (widget)->needs_clear = TRUE;
421 }
422