1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  *    (See accompanying file LICENSE_1_0.txt or copy at
4  *          http://www.boost.org/LICENSE_1_0.txt)
5  */
6 module pango.attributes;
7 
8 import pango.utils;
9 import pango.font;
10 import pango.language;
11 import pango.gravity;
12 import pango.types;
13 import pango.c.attributes;
14 import pango.c.font;
15 import pango.c.gravity;
16 
17 import glib;
18 
19 import std..string;
20 import std.typecons;
21 
22 
23 /* Color */
24 /**
25  * PangoColor:
26  * @red: value of red component
27  * @green: value of green component
28  * @blue: value of blue component
29  *
30  * The #PangoColor structure is used to
31  * represent a color in an uncalibrated RGB color-space.
32  */
33 
34 alias Color = PangoColor;
35 
36 bool parseColor(string spec, out Color color) {
37     return cast(bool)pango_color_parse(&color, toStringz(spec));
38 }
39 
40 
41 string toString(in Color color) {
42     auto str = pango_color_to_string(&color);
43     scope(exit) g_free(str);
44     return fromStringz(str).dup;
45 }
46 
47 
48 /**
49  * PangoAttrIterator:
50  *
51  * The #PangoAttrIterator structure is used to represent an
52  * iterator through a #PangoAttrList. A new iterator is created
53  * with pango_attr_list_get_iterator(). Once the iterator
54  * is created, it can be advanced through the style changes
55  * in the text using pango_attr_iterator_next(). At each
56  * style change, the range of the current style segment and the
57  * attributes currently in effect can be queried.
58  */
59 /**
60  * PangoAttrList:
61  *
62  * The #PangoAttrList structure represents a list of attributes
63  * that apply to a section of text. The attributes are, in general,
64  * allowed to overlap in an arbitrary fashion, however, if the
65  * attributes are manipulated only through pango_attr_list_change(),
66  * the overlap between properties will meet stricter criteria.
67  *
68  * Since the #PangoAttrList structure is stored as a linear list,
69  * it is not suitable for storing attributes for large amounts
70  * of text. In general, you should not use a single #PangoAttrList
71  * for more than one paragraph of text.
72  */
73 
74 /**
75  * PangoAttrType:
76  * @PANGO_ATTR_INVALID: does not happen
77  * @PANGO_ATTR_LANGUAGE: language (#PangoAttrLanguage)
78  * @PANGO_ATTR_FAMILY: font family name list (#PangoAttrString)
79  * @PANGO_ATTR_STYLE: font slant style (#PangoAttrInt)
80  * @PANGO_ATTR_WEIGHT: font weight (#PangoAttrInt)
81  * @PANGO_ATTR_VARIANT: font variant (normal or small caps) (#PangoAttrInt)
82  * @PANGO_ATTR_STRETCH: font stretch (#PangoAttrInt)
83  * @PANGO_ATTR_SIZE: font size in points scaled by %PANGO_SCALE (#PangoAttrInt)
84  * @PANGO_ATTR_FONT_DESC: font description (#PangoAttrFontDesc)
85  * @PANGO_ATTR_FOREGROUND: foreground color (#PangoAttrColor)
86  * @PANGO_ATTR_BACKGROUND: background color (#PangoAttrColor)
87  * @PANGO_ATTR_UNDERLINE: whether the text has an underline (#PangoAttrInt)
88  * @PANGO_ATTR_STRIKETHROUGH: whether the text is struck-through (#PangoAttrInt)
89  * @PANGO_ATTR_RISE: baseline displacement (#PangoAttrInt)
90  * @PANGO_ATTR_SHAPE: shape (#PangoAttrShape)
91  * @PANGO_ATTR_SCALE: font size scale factor (#PangoAttrFloat)
92  * @PANGO_ATTR_FALLBACK: whether fallback is enabled (#PangoAttrInt)
93  * @PANGO_ATTR_LETTER_SPACING: letter spacing (#PangoAttrInt)
94  * @PANGO_ATTR_UNDERLINE_COLOR: underline color (#PangoAttrColor)
95  * @PANGO_ATTR_STRIKETHROUGH_COLOR: strikethrough color (#PangoAttrColor)
96  * @PANGO_ATTR_ABSOLUTE_SIZE: font size in pixels scaled by %PANGO_SCALE (#PangoAttrInt)
97  * @PANGO_ATTR_GRAVITY: base text gravity (#PangoAttrInt)
98  * @PANGO_ATTR_GRAVITY_HINT: gravity hint (#PangoAttrInt)
99  *
100  * The #PangoAttrType
101  * distinguishes between different types of attributes. Along with the
102  * predefined values, it is possible to allocate additional values
103  * for custom attributes using pango_attr_type_register(). The predefined
104  * values are given below. The type of structure used to store the
105  * attribute is listed in parentheses after the description.
106  */
107 enum AttrType
108 {
109   Invalid               = PangoAttrType.PANGO_ATTR_INVALID,           /* 0 is an invalid attribute type */
110   Language              = PangoAttrType.PANGO_ATTR_LANGUAGE,		/* PangoAttrLanguage */
111   Family                = PangoAttrType.PANGO_ATTR_FAMILY,		/* PangoAttrString */
112   Style                 = PangoAttrType.PANGO_ATTR_STYLE,		/* PangoAttrInt */
113   Weight                = PangoAttrType.PANGO_ATTR_WEIGHT,		/* PangoAttrInt */
114   Variant               = PangoAttrType.PANGO_ATTR_VARIANT,		/* PangoAttrInt */
115   Stretch               = PangoAttrType.PANGO_ATTR_STRETCH,		/* PangoAttrInt */
116   Size                  = PangoAttrType.PANGO_ATTR_SIZE,		/* PangoAttrSize */
117   FontDesc              = PangoAttrType.PANGO_ATTR_FONT_DESC,		/* PangoAttrFontDesc */
118   Foreground            = PangoAttrType.PANGO_ATTR_FOREGROUND,	/* PangoAttrColor */
119   Background            = PangoAttrType.PANGO_ATTR_BACKGROUND,	/* PangoAttrColor */
120   Underline             = PangoAttrType.PANGO_ATTR_UNDERLINE,		/* PangoAttrInt */
121   Strikethrough         = PangoAttrType.PANGO_ATTR_STRIKETHROUGH,	/* PangoAttrInt */
122   Rise                  = PangoAttrType.PANGO_ATTR_RISE,		/* PangoAttrInt */
123   Shape                 = PangoAttrType.PANGO_ATTR_SHAPE,		/* PangoAttrShape */
124   Scale                 = PangoAttrType.PANGO_ATTR_SCALE,             /* PangoAttrFloat */
125   Fallback              = PangoAttrType.PANGO_ATTR_FALLBACK,          /* PangoAttrInt */
126   LetterSpacing         = PangoAttrType.PANGO_ATTR_LETTER_SPACING,    /* PangoAttrInt */
127   UnderlineColor        = PangoAttrType.PANGO_ATTR_UNDERLINE_COLOR,	/* PangoAttrColor */
128   StrikethroughColor    = PangoAttrType.PANGO_ATTR_STRIKETHROUGH_COLOR,/* PangoAttrColor */
129   AbsoluteSize          = PangoAttrType.PANGO_ATTR_ABSOLUTE_SIZE,	/* PangoAttrSize */
130   Gravity               = PangoAttrType.PANGO_ATTR_GRAVITY,		/* PangoAttrInt */
131   GravityHint           = PangoAttrType.PANGO_ATTR_GRAVITY_HINT	/* PangoAttrInt */
132 }
133 
134 
135 @property string name(AttrType at) {
136     return fromStringz(pango_attr_type_get_name(cast(PangoAttrType)at)).idup;
137 }
138 
139 /**
140  * PangoUnderline:
141  * @PANGO_UNDERLINE_NONE: no underline should be drawn
142  * @PANGO_UNDERLINE_SINGLE: a single underline should be drawn
143  * @PANGO_UNDERLINE_DOUBLE: a double underline should be drawn
144  * @PANGO_UNDERLINE_LOW: a single underline should be drawn at a position
145  * beneath the ink extents of the text being
146  * underlined. This should be used only for underlining
147  * single characters, such as for keyboard
148  * accelerators. %PANGO_UNDERLINE_SINGLE should
149  * be used for extended portions of text.
150  * @PANGO_UNDERLINE_ERROR: a wavy underline should be drawn below.
151  * This underline is typically used to indicate
152  * an error such as a possilble mispelling; in some
153  * cases a contrasting color may automatically
154  * be used. This type of underlining is available since Pango 1.4.
155  *
156  * The #PangoUnderline enumeration is used to specify
157  * whether text should be underlined, and if so, the type
158  * of underlining.
159  */
160 enum Underline {
161   None      = PangoUnderline.PANGO_UNDERLINE_NONE,
162   Single    = PangoUnderline.PANGO_UNDERLINE_SINGLE,
163   Double    = PangoUnderline.PANGO_UNDERLINE_DOUBLE,
164   Low       = PangoUnderline.PANGO_UNDERLINE_LOW,
165   Error     = PangoUnderline.PANGO_UNDERLINE_ERROR
166 }
167 
168 
169 
170 abstract class Attribute
171 {
172     mixin NativePtrHolder!(PangoAttribute, pango_attribute_destroy);
173 
174     package this (PangoAttribute *ptr, Transfer transfer) {
175         initialize(ptr, transfer);
176     }
177 
178     pure @property inout(PangoAttribute)* nativePtr() inout { return nativePtr_; }
179 
180     @property AttrType type() const {
181         if (!nativePtr.klass) return AttrType.Invalid;
182         return cast(AttrType) nativePtr.klass.type;
183     }
184 
185     static Attribute getAttrDObject(PangoAttribute *attr, Transfer transfer)
186     {
187         if (!attr || !attr.klass) return null;
188 
189         final switch(cast(AttrType)(attr.klass.type)) {
190             case AttrType.Language:
191                 return getDObject!AttrLanguage(cast(PangoAttrLanguage*)attr, transfer);
192             case AttrType.Family:
193                 return getDObject!AttrString(cast(PangoAttrString*)attr, transfer);
194             case AttrType.Style:
195             case AttrType.Weight:
196             case AttrType.Variant:
197             case AttrType.Stretch:
198             case AttrType.Underline:
199             case AttrType.Strikethrough:
200             case AttrType.Rise:
201             case AttrType.Fallback:
202             case AttrType.LetterSpacing:
203             case AttrType.Gravity:
204             case AttrType.GravityHint:
205                 return getDObject!AttrInt(cast(PangoAttrInt*)attr, transfer);
206             case AttrType.Size:
207             case AttrType.AbsoluteSize:
208                 return getDObject!AttrSize(cast(PangoAttrSize*)attr, transfer);
209             case AttrType.FontDesc:
210                 return getDObject!AttrFontDesc(cast(PangoAttrFontDesc*)attr, transfer);
211             case AttrType.Foreground:
212             case AttrType.Background:
213             case AttrType.UnderlineColor:
214             case AttrType.StrikethroughColor:
215                 return getDObject!AttrColor(cast(PangoAttrColor*)attr, transfer);
216             case AttrType.Shape:
217                 return getDObject!AttrShape(cast(PangoAttrShape*)attr, transfer);
218             case AttrType.Scale:
219                 return getDObject!AttrFloat(cast(PangoAttrFloat*)attr, transfer);
220             case AttrType.Invalid:
221                 return null;
222         }
223     }
224 
225     //void             pango_attribute_init        (PangoAttribute       *attr,
226     //                          const(PangoAttrClass) *klass);
227 
228     abstract Attribute copy() const;
229 
230     pure bool equal(const(Attribute) attr)
231     {
232         if (!attr) return false;
233         return cast(bool)pango_attribute_equal(nativePtr, attr.nativePtr);
234     }
235 
236     pure override bool opEquals(Object obj) const
237     {
238         if (!obj) return false;
239         auto attr = cast(const(Attribute))obj;
240         if (!attr) return false;
241         return cast(bool)pango_attribute_equal(nativePtr, attr.nativePtr);
242     }
243 
244     static Attribute languageNew(Language language) {
245         return getDObject!AttrLanguage(cast(PangoAttrLanguage*)
246                                            pango_attr_language_new(language.nativePtr),
247                                            Transfer.Full);
248     }
249 
250     static Attribute familyNew(string family) {
251         return getDObject!AttrString(cast(PangoAttrString*)pango_attr_family_new(toStringz(family)), Transfer.Full);
252     }
253 
254     static Attribute foregroundNew(ushort red, ushort green, ushort blue) {
255         return getDObject!AttrColor(cast(PangoAttrColor*)pango_attr_foreground_new(red, green, blue), Transfer.Full);
256     }
257 
258     static Attribute backgroundNew(ushort red, ushort green, ushort blue) {
259         return getDObject!AttrColor(cast(PangoAttrColor*)pango_attr_background_new(red, green, blue), Transfer.Full);
260     }
261 
262     static Attribute sizeNew(int size) {
263         return getDObject!AttrSize(cast(PangoAttrSize*)pango_attr_size_new(size), Transfer.Full);
264     }
265 
266     static Attribute sizeNewAbsolute(int size) {
267         return getDObject!AttrSize(cast(PangoAttrSize*)pango_attr_size_new_absolute(size), Transfer.Full);
268     }
269 
270     static Attribute styleNew(Style style) {
271         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_style_new(cast(PangoStyle)style), Transfer.Full);
272     }
273 
274     static Attribute weightNew(Weight weight) {
275         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_weight_new(cast(PangoWeight)weight), Transfer.Full);
276     }
277 
278     static Attribute variantNew(Variant variant) {
279         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_variant_new(cast(PangoVariant)variant), Transfer.Full);
280     }
281 
282     static Attribute stretchNew(Stretch stretch) {
283         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_stretch_new(cast(PangoStretch)stretch), Transfer.Full);
284     }
285 
286     static Attribute fontDescNew(const(FontDescription) fontDesc) {
287         return getDObject!AttrFontDesc(cast(PangoAttrFontDesc*)pango_attr_font_desc_new(fontDesc.nativePtr), Transfer.Full);
288     }
289 
290     static Attribute underlineNew(Underline underline) {
291         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_underline_new(cast(PangoUnderline)underline), Transfer.Full);
292     }
293 
294     static Attribute underlineColorNew(ushort red, ushort green, ushort blue) {
295         return getDObject!AttrColor(cast(PangoAttrColor*)pango_attr_underline_color_new(red, green, blue), Transfer.Full);
296     }
297 
298     static Attribute strikethroughNew(bool strikethrough) {
299         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_strikethrough_new(strikethrough), Transfer.Full);
300     }
301 
302     static Attribute strikethroughColorNew(ushort red, ushort green, ushort blue) {
303         return getDObject!AttrColor(cast(PangoAttrColor*)pango_attr_strikethrough_color_new(red, green, blue), Transfer.Full);
304     }
305 
306     static Attribute riseNew(int rise) {
307         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_rise_new(rise), Transfer.Full);
308     }
309 
310     static Attribute scaleNew(double scaleFactor) {
311         return getDObject!AttrFloat(cast(PangoAttrFloat*)pango_attr_scale_new(scaleFactor), Transfer.Full);
312     }
313 
314     static Attribute fallbackNew(bool enableFallback) {
315         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_fallback_new(enableFallback), Transfer.Full);
316     }
317 
318     static Attribute letterSpacingNew(int letterSpacing) {
319         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_letter_spacing_new(letterSpacing), Transfer.Full);
320     }
321 
322     static Attribute shapeNew(in Rectangle inkRect, in Rectangle logicalRect) {
323         return getDObject!AttrShape(cast(PangoAttrShape*)pango_attr_shape_new(&inkRect, &logicalRect), Transfer.Full);
324     }
325 
326     //PangoAttribute *pango_attr_shape_new_with_data (const(PangoRectangle)       *ink_rect,
327     //                        const(PangoRectangle)       *logical_rect,
328     //                        gpointer                    data,
329     //                        PangoAttrDataCopyFunc       copy_func,
330     //                        GDestroyNotify              destroy_func);
331 
332     static Attribute gravityNew(Gravity gravity) {
333         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_gravity_new(cast(PangoGravity)gravity), Transfer.Full);
334     }
335 
336     static Attribute gravityHintNew(GravityHint hint) {
337         return getDObject!AttrInt(cast(PangoAttrInt*)pango_attr_gravity_hint_new(cast(PangoGravityHint)hint), Transfer.Full);
338     }
339 
340 }
341 
342 
343 class AttrWithType(PangoAttrType) : Attribute
344 {
345     package this(PangoAttrType *attr, Transfer transfer) {
346         super(cast(PangoAttribute*)attr, transfer);
347     }
348 
349     override Attribute copy() const {
350         return getDObject!(AttrWithType!(PangoAttrType)) (
351                 cast(PangoAttrType*)pango_attribute_copy(nativePtr),
352                 Transfer.Full
353         );
354     }
355 }
356 
357 alias AttrLanguage = AttrWithType!PangoAttrLanguage;
358 alias AttrString = AttrWithType!PangoAttrString;
359 alias AttrInt = AttrWithType!PangoAttrInt;
360 alias AttrSize = AttrWithType!PangoAttrSize;
361 alias AttrFontDesc = AttrWithType!PangoAttrFontDesc;
362 alias AttrColor = AttrWithType!PangoAttrColor;
363 alias AttrShape = AttrWithType!PangoAttrShape;
364 alias AttrFloat = AttrWithType!PangoAttrFloat;
365 
366 
367 struct AttrList
368 {
369     mixin RefCountedGObj!(PangoAttrList, "pango_attr_list");
370 
371     package this(PangoAttrList *ptr, Transfer transfer) {
372         initialize(ptr, transfer);
373     }
374 
375     AttrList create() {
376         return AttrList(pango_attr_list_new(), Transfer.Full);
377     }
378 
379     //PangoAttrList *    pango_attr_list_copy          (PangoAttrList  *list);
380 
381     void insert(Attribute attr) {
382         pango_attr_list_insert(nativePtr, attr.nativePtr);
383     }
384 
385     void insertBefore(Attribute attr) {
386         pango_attr_list_insert_before(nativePtr, attr.nativePtr);
387     }
388 
389     void change(Attribute attr) {
390         pango_attr_list_change(nativePtr, attr.nativePtr);
391     }
392 
393     void splice(AttrList other, int pos, int len) {
394         pango_attr_list_splice(nativePtr, other.nativePtr, pos, len);
395     }
396 
397     AttrList filter(PangoAttrFilterFunc func, gpointer data) {
398         return AttrList(pango_attr_list_filter(nativePtr, func, data), Transfer.Full);
399     }
400 
401     @property AttrIterator iterator() {
402         return getDObject!AttrIterator(pango_attr_list_get_iterator(nativePtr), Transfer.Full);
403     }
404 
405 
406 }
407 
408 
409 class AttrIterator
410 {
411     mixin NativePtrHolder!(PangoAttrIterator, pango_attr_iterator_destroy);
412 
413     package this(PangoAttrIterator* ptr, Transfer transfer) {
414         initialize(ptr, transfer);
415     }
416 
417 
418     void range (out int start, out int end) {
419         pango_attr_iterator_range(nativePtr, &start, &end);
420     }
421 
422     bool next() {
423         return cast(bool)pango_attr_iterator_next(nativePtr);
424     }
425 
426     Attribute get(AttrType type) {
427         return Attribute.getAttrDObject(pango_attr_iterator_get(nativePtr, cast(PangoAttrType)type), Transfer.None);
428     }
429 
430     //void               pango_attr_iterator_get_font (PangoAttrIterator     *iterator,
431     //                         PangoFontDescription  *desc,
432     //                         PangoLanguage        **language,
433     //                         GSList               **extra_attrs);
434     //GSList *          pango_attr_iterator_get_attrs (PangoAttrIterator     *iterator);
435 }
436 
437 //
438 //
439 //gboolean pango_parse_markup (const(char)                 *markup_text,
440 //                 int                         length,
441 //                 gunichar                    accel_marker,
442 //                 PangoAttrList             **attr_list,
443 //                 char                      **text,
444 //                 gunichar                   *accel_char,
445 //                 GError                    **error);
446 //
447 //GMarkupParseContext * pango_markup_parser_new (gunichar               accel_marker);
448 //gboolean              pango_markup_parser_finish (GMarkupParseContext   *context,
449 //                                                  PangoAttrList        **attr_list,
450 //                                                  char                 **text,
451 //                                                  gunichar              *accel_char,
452 //                                                  GError               **error);
453 //
454