Git init
[external/pango1.0.git] / pango / pango-tabs.c
1 /* Pango
2  * pango-tabs.c: Tab-related stuff
3  *
4  * Copyright (C) 2000 Red Hat Software
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include "pango-tabs.h"
24 #include "pango-impl-utils.h"
25 #include <string.h>
26
27 typedef struct _PangoTab PangoTab;
28
29 struct _PangoTab
30 {
31   gint location;                /* Offset in pixels of this tab stop
32                                  * from the left margin of the text.
33                                  */
34   PangoTabAlign alignment;      /* Where the tab stop appears relative
35                                  * to the text.
36                                  */
37 };
38
39 struct _PangoTabArray
40 {
41   gint size;
42   gint allocated;
43   gboolean positions_in_pixels;
44   PangoTab *tabs;
45 };
46
47 static void
48 init_tabs (PangoTabArray *array, gint start, gint end)
49 {
50   while (start < end)
51     {
52       array->tabs[start].location = 0;
53       array->tabs[start].alignment = PANGO_TAB_LEFT;
54       ++start;
55     }
56 }
57
58 /**
59  * pango_tab_array_new:
60  * @initial_size: Initial number of tab stops to allocate, can be 0
61  * @positions_in_pixels: whether positions are in pixel units
62  *
63  * Creates an array of @initial_size tab stops. Tab stops are specified in
64  * pixel units if @positions_in_pixels is %TRUE, otherwise in Pango
65  * units. All stops are initially at position 0.
66  *
67  * Return value: the newly allocated #PangoTabArray, which should
68  *               be freed with pango_tab_array_free().
69  **/
70 PangoTabArray*
71 pango_tab_array_new (gint initial_size,
72                      gboolean positions_in_pixels)
73 {
74   PangoTabArray *array;
75
76   g_return_val_if_fail (initial_size >= 0, NULL);
77
78   /* alloc enough to treat array->tabs as an array of length
79    * size, though it's declared as an array of length 1.
80    * If we allowed tab array resizing we'd need to drop this
81    * optimization.
82    */
83   array = g_slice_new (PangoTabArray);
84   array->size = initial_size;
85   array->allocated = initial_size;
86
87   if (array->allocated > 0)
88     {
89       array->tabs = g_new (PangoTab, array->allocated);
90       init_tabs (array, 0, array->allocated);
91     }
92   else
93     array->tabs = NULL;
94
95   array->positions_in_pixels = positions_in_pixels;
96
97   return array;
98 }
99
100 /**
101  * pango_tab_array_new_with_positions:
102  * @size: number of tab stops in the array
103  * @positions_in_pixels: whether positions are in pixel units
104  * @first_alignment: alignment of first tab stop
105  * @first_position: position of first tab stop
106  * @varargs: additional alignment/position pairs
107  *
108  * This is a convenience function that creates a #PangoTabArray
109  * and allows you to specify the alignment and position of each
110  * tab stop. You <emphasis>must</emphasis> provide an alignment
111  * and position for @size tab stops.
112  *
113  * Return value: the newly allocated #PangoTabArray, which should
114  *               be freed with pango_tab_array_free().
115  **/
116 PangoTabArray  *
117 pango_tab_array_new_with_positions (gint           size,
118                                     gboolean       positions_in_pixels,
119                                     PangoTabAlign  first_alignment,
120                                     gint           first_position,
121                                     ...)
122 {
123   PangoTabArray *array;
124   va_list args;
125   int i;
126
127   g_return_val_if_fail (size >= 0, NULL);
128
129   array = pango_tab_array_new (size, positions_in_pixels);
130
131   if (size == 0)
132     return array;
133
134   array->tabs[0].alignment = first_alignment;
135   array->tabs[0].location = first_position;
136
137   if (size == 1)
138     return array;
139
140   va_start (args, first_position);
141
142   i = 1;
143   while (i < size)
144     {
145       PangoTabAlign align = va_arg (args, PangoTabAlign);
146       int pos = va_arg (args, int);
147
148       array->tabs[i].alignment = align;
149       array->tabs[i].location = pos;
150
151       ++i;
152     }
153
154   va_end (args);
155
156   return array;
157 }
158
159 GType
160 pango_tab_array_get_type (void)
161 {
162   static GType our_type = 0;
163
164   if (G_UNLIKELY (our_type == 0))
165     our_type = g_boxed_type_register_static (I_("PangoTabArray"),
166                                              (GBoxedCopyFunc)pango_tab_array_copy,
167                                              (GBoxedFreeFunc)pango_tab_array_free);
168   return our_type;
169 }
170
171 /**
172  * pango_tab_array_copy:
173  * @src: #PangoTabArray to copy
174  *
175  * Copies a #PangoTabArray
176  *
177  * Return value: the newly allocated #PangoTabArray, which should
178  *               be freed with pango_tab_array_free().
179  **/
180 PangoTabArray*
181 pango_tab_array_copy (PangoTabArray *src)
182 {
183   PangoTabArray *copy;
184
185   g_return_val_if_fail (src != NULL, NULL);
186
187   copy = pango_tab_array_new (src->size, src->positions_in_pixels);
188
189   memcpy (copy->tabs, src->tabs, sizeof(PangoTab)*src->size);
190
191   return copy;
192 }
193
194 /**
195  * pango_tab_array_free:
196  * @tab_array: a #PangoTabArray
197  *
198  * Frees a tab array and associated resources.
199  *
200  **/
201 void
202 pango_tab_array_free   (PangoTabArray *tab_array)
203 {
204   g_return_if_fail (tab_array != NULL);
205
206   g_free (tab_array->tabs);
207
208   g_slice_free (PangoTabArray, tab_array);
209 }
210
211 /**
212  * pango_tab_array_get_size:
213  * @tab_array: a #PangoTabArray
214  *
215  * Gets the number of tab stops in @tab_array.
216  *
217  * Return value: the number of tab stops in the array.
218  **/
219 gint
220 pango_tab_array_get_size (PangoTabArray *tab_array)
221 {
222   g_return_val_if_fail (tab_array != NULL, 0);
223
224   return tab_array->size;
225 }
226
227 /**
228  * pango_tab_array_resize:
229  * @tab_array: a #PangoTabArray
230  * @new_size: new size of the array
231  *
232  * Resizes a tab array. You must subsequently initialize any tabs that
233  * were added as a result of growing the array.
234  *
235  **/
236 void
237 pango_tab_array_resize (PangoTabArray *tab_array,
238                         gint           new_size)
239 {
240   if (new_size > tab_array->allocated)
241     {
242       gint current_end = tab_array->allocated;
243
244       /* Ratchet allocated size up above the index. */
245       if (tab_array->allocated == 0)
246         tab_array->allocated = 2;
247
248       while (new_size > tab_array->allocated)
249         tab_array->allocated = tab_array->allocated * 2;
250
251       tab_array->tabs = g_renew (PangoTab, tab_array->tabs,
252                                  tab_array->allocated);
253
254       init_tabs (tab_array, current_end, tab_array->allocated);
255     }
256
257   tab_array->size = new_size;
258 }
259
260 /**
261  * pango_tab_array_set_tab:
262  * @tab_array: a #PangoTabArray
263  * @tab_index: the index of a tab stop
264  * @alignment: tab alignment
265  * @location: tab location in Pango units
266  *
267  * Sets the alignment and location of a tab stop.
268  * @alignment must always be #PANGO_TAB_LEFT in the current
269  * implementation.
270  *
271  **/
272 void
273 pango_tab_array_set_tab  (PangoTabArray *tab_array,
274                           gint           tab_index,
275                           PangoTabAlign  alignment,
276                           gint           location)
277 {
278   g_return_if_fail (tab_array != NULL);
279   g_return_if_fail (tab_index >= 0);
280   g_return_if_fail (alignment == PANGO_TAB_LEFT);
281   g_return_if_fail (location >= 0);
282
283   if (tab_index >= tab_array->size)
284     pango_tab_array_resize (tab_array, tab_index + 1);
285
286   tab_array->tabs[tab_index].alignment = alignment;
287   tab_array->tabs[tab_index].location = location;
288 }
289
290 /**
291  * pango_tab_array_get_tab:
292  * @tab_array: a #PangoTabArray
293  * @tab_index: tab stop index
294  * @alignment: location to store alignment, or %NULL
295  * @location: location to store tab position, or %NULL
296  *
297  * Gets the alignment and position of a tab stop.
298  *
299  **/
300 void
301 pango_tab_array_get_tab  (PangoTabArray *tab_array,
302                           gint           tab_index,
303                           PangoTabAlign *alignment,
304                           gint          *location)
305 {
306   g_return_if_fail (tab_array != NULL);
307   g_return_if_fail (tab_index < tab_array->size);
308   g_return_if_fail (tab_index >= 0);
309
310   if (alignment)
311     *alignment = tab_array->tabs[tab_index].alignment;
312
313   if (location)
314     *location = tab_array->tabs[tab_index].location;
315 }
316
317 /**
318  * pango_tab_array_get_tabs:
319  * @tab_array: a #PangoTabArray
320  * @alignments: location to store an array of tab stop alignments, or %NULL
321  * @locations: location to store an array of tab positions, or %NULL
322  *
323  * If non-%NULL, @alignments and @locations are filled with allocated
324  * arrays of length pango_tab_array_get_size(). You must free the
325  * returned array.
326  *
327  **/
328 void
329 pango_tab_array_get_tabs (PangoTabArray *tab_array,
330                           PangoTabAlign **alignments,
331                           gint          **locations)
332 {
333   gint i;
334
335   g_return_if_fail (tab_array != NULL);
336
337   if (alignments)
338     *alignments = g_new (PangoTabAlign, tab_array->size);
339
340   if (locations)
341     *locations = g_new (gint, tab_array->size);
342
343   i = 0;
344   while (i < tab_array->size)
345     {
346       if (alignments)
347         (*alignments)[i] = tab_array->tabs[i].alignment;
348       if (locations)
349         (*locations)[i] = tab_array->tabs[i].location;
350
351       ++i;
352     }
353 }
354
355 /**
356  * pango_tab_array_get_positions_in_pixels:
357  * @tab_array: a #PangoTabArray
358  *
359  * Returns %TRUE if the tab positions are in pixels, %FALSE if they are
360  * in Pango units.
361  *
362  * Return value: whether positions are in pixels.
363  **/
364 gboolean
365 pango_tab_array_get_positions_in_pixels (PangoTabArray *tab_array)
366 {
367   g_return_val_if_fail (tab_array != NULL, FALSE);
368
369   return tab_array->positions_in_pixels;
370 }