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.layout; 7 8 import pango.utils; 9 import pango.bidi_type; 10 import pango.context; 11 import pango.attributes; 12 import pango.break_; 13 import pango.font; 14 import pango.types; 15 import pango.tabs; 16 import pango.glyph_item; 17 import pango.c.layout; 18 import pango.c.font; 19 20 import glib; 21 import gobject; 22 23 import std..string; 24 25 /** 26 * PangoLayoutRun: 27 * 28 * The #PangoLayoutRun structure represents a single run within 29 * a #PangoLayoutLine; it is simply an alternate name for 30 * #PangoGlyphItem. 31 * See the #PangoGlyphItem docs for details on the fields. 32 */ 33 alias LayoutRun = GlyphItem; 34 35 /** 36 * PangoAlignment: 37 * @PANGO_ALIGN_LEFT: Put all available space on the right 38 * @PANGO_ALIGN_CENTER: Center the line within the available space 39 * @PANGO_ALIGN_RIGHT: Put all available space on the left 40 * 41 * A #PangoAlignment describes how to align the lines of a #PangoLayout within the 42 * available space. If the #PangoLayout is set to justify 43 * using pango_layout_set_justify(), this only has effect for partial lines. 44 */ 45 enum Alignment { 46 Left = PangoAlignment.PANGO_ALIGN_LEFT, 47 Center = PangoAlignment.PANGO_ALIGN_CENTER, 48 Right = PangoAlignment.PANGO_ALIGN_RIGHT 49 } 50 51 /** 52 * PangoWrapMode: 53 * @PANGO_WRAP_WORD: wrap lines at word boundaries. 54 * @PANGO_WRAP_CHAR: wrap lines at character boundaries. 55 * @PANGO_WRAP_WORD_CHAR: wrap lines at word boundaries, but fall back to character boundaries if there is not 56 * enough space for a full word. 57 * 58 * A #PangoWrapMode describes how to wrap the lines of a #PangoLayout to the desired width. 59 */ 60 enum WrapMode { 61 Word = PangoWrapMode.PANGO_WRAP_WORD, 62 Char = PangoWrapMode.PANGO_WRAP_CHAR, 63 WordChar = PangoWrapMode.PANGO_WRAP_WORD_CHAR 64 } 65 66 /** 67 * PangoEllipsizeMode: 68 * @PANGO_ELLIPSIZE_NONE: No ellipsization 69 * @PANGO_ELLIPSIZE_START: Omit characters at the start of the text 70 * @PANGO_ELLIPSIZE_MIDDLE: Omit characters in the middle of the text 71 * @PANGO_ELLIPSIZE_END: Omit characters at the end of the text 72 * 73 * The #PangoEllipsizeMode type describes what sort of (if any) 74 * ellipsization should be applied to a line of text. In 75 * the ellipsization process characters are removed from the 76 * text in order to make it fit to a given width and replaced 77 * with an ellipsis. 78 */ 79 enum EllipsizeMode { 80 None = PangoEllipsizeMode.PANGO_ELLIPSIZE_NONE, 81 Start = PangoEllipsizeMode.PANGO_ELLIPSIZE_START, 82 Middle = PangoEllipsizeMode.PANGO_ELLIPSIZE_MIDDLE, 83 End = PangoEllipsizeMode.PANGO_ELLIPSIZE_END 84 } 85 86 87 /* The PangoLayout and PangoLayoutClass structs are private; if you 88 * need to create a subclass of these, file a bug. 89 */ 90 class Layout : D_GObject 91 { 92 mixin GObjectHolder!PangoLayout; 93 94 package this(PangoLayout *ptr, Transfer transfer) { 95 super(cast(GObject*)ptr, transfer); 96 } 97 98 this(Context context) { 99 super(cast(GObject*)pango_layout_new(context.nativePtr), Transfer.Full); 100 } 101 102 Layout copy() { 103 return getDObject!Layout(pango_layout_copy(nativePtr), Transfer.Full); 104 } 105 106 @property Context context() { 107 return getDObject!Context(pango_layout_get_context(nativePtr), Transfer.None); 108 } 109 110 @property AttrList attributes() { 111 return getDObject!AttrList(pango_layout_get_attributes(nativePtr), Transfer.None); 112 } 113 114 @property void attributes(AttrList attrs) { 115 pango_layout_set_attributes(nativePtr, attrs.nativePtr); 116 } 117 118 @property void text(string text) { 119 pango_layout_set_text(nativePtr, text.ptr, cast(int)text.length); 120 } 121 122 @property string text() { 123 return fromStringz(pango_layout_get_text(nativePtr)).idup; 124 } 125 126 @property int characterCount() { 127 return pango_layout_get_character_count(nativePtr); 128 } 129 130 void setMarkup(string markup) { 131 pango_layout_set_markup(nativePtr, markup.ptr, cast(int)markup.length); 132 } 133 134 void setMarkupWithAccel(string markup, dchar accelMarker, out dchar accelChar) { 135 pango_layout_set_markup_with_accel(nativePtr, markup.ptr, cast(int)markup.length, accelMarker, &accelChar); 136 } 137 138 @property void fontDescription (const(FontDescription) desc) { 139 pango_layout_set_font_description(nativePtr, desc.nativePtr); 140 } 141 142 @property const(FontDescription) fontDescription() { 143 return getDObject!FontDescription(cast(PangoFontDescription*)pango_layout_get_font_description(nativePtr), Transfer.None); 144 } 145 146 @property void width(int w) { 147 pango_layout_set_width(nativePtr, w); 148 } 149 150 @property int width() { 151 return pango_layout_get_width(nativePtr); 152 } 153 154 @property void height(int h) { 155 pango_layout_set_height(nativePtr, h); 156 } 157 158 @property int height() { 159 return pango_layout_get_height(nativePtr); 160 } 161 162 @property WrapMode wrap() { 163 return cast(WrapMode)pango_layout_get_wrap(nativePtr); 164 } 165 166 @property void wrap(WrapMode mode) { 167 return pango_layout_set_wrap(nativePtr, cast(PangoWrapMode)mode); 168 } 169 170 @property bool wrapped() { 171 return cast(bool)pango_layout_is_wrapped(nativePtr); 172 } 173 174 @property void indent(int val) { 175 pango_layout_set_indent(nativePtr, val); 176 } 177 178 @property int indent() { 179 return pango_layout_get_indent(nativePtr); 180 } 181 182 @property void spacing(int val) { 183 pango_layout_set_spacing(nativePtr, val); 184 } 185 186 @property int spacing() { 187 return pango_layout_get_spacing(nativePtr); 188 } 189 190 @property void justify(bool val) { 191 pango_layout_set_justify(nativePtr, cast(gboolean)val); 192 } 193 194 @property bool justify() { 195 return cast(bool)pango_layout_get_justify(nativePtr); 196 } 197 198 @property void autoDir(bool val) { 199 pango_layout_set_auto_dir(nativePtr, cast(gboolean)val); 200 } 201 202 @property bool autoDir() { 203 return cast(bool)pango_layout_get_auto_dir(nativePtr); 204 } 205 206 @property void alignment(Alignment val) { 207 pango_layout_set_alignment(nativePtr, cast(PangoAlignment)val); 208 } 209 210 @property Alignment alignment() { 211 return cast(Alignment) pango_layout_get_alignment(nativePtr); 212 } 213 214 @property tabs(TabArray tabs) { 215 pango_layout_set_tabs(nativePtr, tabs.nativePtr); 216 } 217 218 @property TabArray tabs() { 219 return getDObject!TabArray(pango_layout_get_tabs(nativePtr), Transfer.Full); 220 } 221 222 @property void singleParagraphMode(bool val) { 223 pango_layout_set_single_paragraph_mode(nativePtr, cast(gboolean)val); 224 } 225 226 @property bool singleParagraphMode() { 227 return cast(bool)pango_layout_get_single_paragraph_mode(nativePtr); 228 } 229 230 231 @property void ellipsize(EllipsizeMode val) { 232 pango_layout_set_ellipsize(nativePtr, cast(PangoEllipsizeMode)val); 233 } 234 235 @property EllipsizeMode ellipsize() { 236 return cast(EllipsizeMode) pango_layout_get_ellipsize(nativePtr); 237 } 238 239 @property bool ellipsized() { 240 return cast(bool) pango_layout_is_ellipsized(nativePtr); 241 } 242 243 @property int unknownGlyphsCount() { 244 return pango_layout_get_unknown_glyphs_count(nativePtr); 245 } 246 247 void contextChanged() { 248 pango_layout_context_changed(nativePtr); 249 } 250 251 @property uint serial() { 252 return pango_layout_get_serial(nativePtr); 253 } 254 255 @property LogAttr[] logAttrs() { 256 return listValues!(LogAttr, pango_layout_get_log_attrs)(nativePtr); 257 } 258 259 @property const(LogAttr)[] logAttrsReadOnly() { 260 int n; 261 const(LogAttr)* attrs = pango_layout_get_log_attrs_readonly(nativePtr, &n); 262 return attrs[0 .. n]; 263 } 264 265 Rectangle indexToPos(int index) { 266 Rectangle pos; 267 pango_layout_index_to_pos(nativePtr, index, &pos); 268 return pos; 269 } 270 271 void indexToLineX(int index, bool trailing, out int line, out int xPos) { 272 pango_layout_index_to_line_x(nativePtr, index, trailing, &line, &xPos); 273 } 274 275 void cursorPos(int index, out Rectangle strongPos, out Rectangle weakPos) { 276 pango_layout_get_cursor_pos(nativePtr, index, &strongPos, &weakPos); 277 } 278 279 void moveCursorVisually(bool strong, int oldIndex, int oldTrailing, int direction, 280 out int newIndex, out int newTrailing) { 281 pango_layout_move_cursor_visually(nativePtr, strong, oldIndex, oldTrailing, 282 direction, &newIndex, &newTrailing); 283 } 284 285 bool xyToIndex(int x, int y, out int index, out int trailing) { 286 return cast(bool)pango_layout_xy_to_index(nativePtr, x, y, &index, &trailing); 287 } 288 289 void extents(out Rectangle inkRect, out Rectangle logicalRect) { 290 pango_layout_get_extents(nativePtr, &inkRect, &logicalRect); 291 } 292 293 void pixelExtents(out Rectangle inkRect, out Rectangle logicalRect) { 294 pango_layout_get_pixel_extents(nativePtr, &inkRect, &logicalRect); 295 } 296 297 void size(out int width, out int height) { 298 pango_layout_get_size(nativePtr, &width, &height); 299 } 300 301 void pixelSize(out int width, out int height) { 302 pango_layout_get_pixel_size(nativePtr, &width, &height); 303 } 304 305 @property int baseline() { 306 return pango_layout_get_baseline(nativePtr); 307 } 308 309 @property int lineCount() { 310 return pango_layout_get_line_count(nativePtr); 311 } 312 313 LayoutLine line(int line) { 314 return getDObject!LayoutLine(pango_layout_get_line(nativePtr, line), Transfer.None); 315 } 316 317 LayoutLine lineReadOnly(int line) { 318 return getDObject!LayoutLine(pango_layout_get_line_readonly(nativePtr, line), Transfer.None); 319 } 320 321 322 LayoutLine[] lines() { 323 GSList *list = pango_layout_get_lines(nativePtr); 324 LayoutLine[] res; 325 while (list) { 326 res ~= getDObject!LayoutLine(cast(PangoLayoutLine*)list.data, Transfer.None); 327 list = list.next; 328 } 329 return res; 330 } 331 332 LayoutLine[] linesReadOnly() { 333 GSList *list = pango_layout_get_lines_readonly(nativePtr); 334 LayoutLine[] res; 335 while (list) { 336 res ~= getDObject!LayoutLine(cast(PangoLayoutLine*)list.data, Transfer.None); 337 list = list.next; 338 } 339 return res; 340 } 341 342 343 @property LayoutIter iter() { 344 return getDObject!LayoutIter(pango_layout_get_iter(nativePtr), Transfer.Full); 345 } 346 } 347 348 349 350 /** 351 * PangoLayoutLine: 352 * @start_index: start of line as byte index into layout->text 353 * @length: length of line in bytes 354 * @is_paragraph_start: #TRUE if this is the first line of the paragraph 355 * @resolved_dir: #Resolved PangoDirection of line 356 * 357 * The #PangoLayoutLine structure represents one of the lines resulting 358 * from laying out a paragraph via #PangoLayout. #PangoLayoutLine 359 * structures are obtained by calling pango_layout_get_line() and 360 * are only valid until the text, attributes, or settings of the 361 * parent #PangoLayout are modified. 362 * 363 * Routines for rendering PangoLayout objects are provided in 364 * code specific to each rendering system. 365 */ 366 367 struct LayoutLine 368 { 369 mixin RefCountedGObj!(PangoLayoutLine, "pango_layout_line"); 370 371 package this(PangoLayoutLine *ptr, Transfer transfer) { 372 initialize(ptr, transfer); 373 } 374 375 @property Layout layout() { return getDObject!Layout(nativePtr.layout, Transfer.None); } 376 @property void layout(Layout l) { nativePtr.layout = l.nativePtr; } 377 378 @property int startIndex() const { return nativePtr.start_index; } 379 @property void startIndex(int val) { nativePtr.start_index = val; } 380 381 @property int length() const { return nativePtr.length; } 382 @property void length(int val) { nativePtr.length = val; } 383 384 // GSList * runs; 385 386 @property bool isParagraphStart() { return cast(bool)nativePtr.is_paragraph_start; } 387 @property void isParagraphStart(bool val) { nativePtr.is_paragraph_start = cast(uint)val; } 388 389 @property Direction resolvedDir() { return cast(Direction)nativePtr.resolved_dir; } 390 @property void resolvedDir(Direction direction) { nativePtr.resolved_dir = cast(uint)direction; } 391 392 393 bool xToIndex(int xPos, out int index, out int trailing) { 394 return cast(bool)pango_layout_line_x_to_index(nativePtr, xPos, &index, &trailing); 395 } 396 397 int indexToX(int index, bool trailing) { 398 int res; 399 pango_layout_line_index_to_x(nativePtr, index, trailing, &res); 400 return res; 401 } 402 403 int[2][] xRanges(int startIndex, int endIndex) { 404 int *arr; 405 int n; 406 pango_layout_line_get_x_ranges(nativePtr, startIndex, endIndex, &arr, &n); 407 if (!n) return []; 408 scope(exit) g_free(arr); 409 int[2][] res; 410 foreach(i; 0..n) { 411 res ~= [ arr[2*i], arr[2*i+1] ]; 412 } 413 return res; 414 } 415 416 void extents(out Rectangle inkRect, out Rectangle logicalRect) { 417 pango_layout_line_get_extents(nativePtr, &inkRect, &logicalRect); 418 } 419 420 void pixelExtents(out Rectangle inkRect, out Rectangle logicalRect) { 421 pango_layout_line_get_pixel_extents(nativePtr, &inkRect, &logicalRect); 422 } 423 } 424 425 426 class LayoutIter { 427 mixin NativePtrHolder!(PangoLayoutIter, pango_layout_iter_free); 428 429 this (PangoLayoutIter *ptr, Transfer transfer) { 430 initialize(ptr, transfer); 431 } 432 433 434 @property int index() { 435 return pango_layout_iter_get_index(nativePtr); 436 } 437 438 @property LayoutRun run() { 439 return getDObject!LayoutRun(pango_layout_iter_get_run(nativePtr), Transfer.None); 440 } 441 442 @property LayoutRun runReadOnly() { 443 return getDObject!LayoutRun(pango_layout_iter_get_run_readonly(nativePtr), Transfer.None); 444 } 445 446 @property LayoutLine line() { 447 return getDObject!LayoutLine(pango_layout_iter_get_line(nativePtr), Transfer.None); 448 } 449 450 @property LayoutLine lineReadOnly() { 451 return getDObject!LayoutLine(pango_layout_iter_get_line_readonly(nativePtr), Transfer.None); 452 } 453 454 @property bool atLastLine() { 455 return cast(bool)pango_layout_iter_at_last_line(nativePtr); 456 } 457 458 @property Layout layout() { 459 return getDObject!Layout(pango_layout_iter_get_layout(nativePtr), Transfer.None); 460 } 461 462 bool nextChar() { 463 return cast(bool)pango_layout_iter_next_char(nativePtr); 464 } 465 466 bool nextCluster() { 467 return cast(bool)pango_layout_iter_next_cluster(nativePtr); 468 } 469 470 bool nextRun() { 471 return cast(bool)pango_layout_iter_next_run(nativePtr); 472 } 473 474 bool nextLine() { 475 return cast(bool)pango_layout_iter_next_line(nativePtr); 476 } 477 478 void charExtents(out Rectangle logicalRect) { 479 pango_layout_iter_get_char_extents(nativePtr, &logicalRect); 480 } 481 482 void clusterExtents(out Rectangle inkRect, out Rectangle logicalRect) { 483 pango_layout_iter_get_cluster_extents(nativePtr, &inkRect, &logicalRect); 484 } 485 486 void runExtents(out Rectangle inkRect, out Rectangle logicalRect) { 487 pango_layout_iter_get_run_extents(nativePtr, &inkRect, &logicalRect); 488 } 489 490 void lineExtents(out Rectangle inkRect, out Rectangle logicalRect) { 491 pango_layout_iter_get_line_extents(nativePtr, &inkRect, &logicalRect); 492 } 493 494 495 /* All the yranges meet, unlike the logical_rect's (i.e. the yranges 496 * assign between-line spacing to the nearest line) 497 */ 498 @property int[2] lineYRange() { 499 int[2] res; 500 pango_layout_iter_get_line_yrange(nativePtr, &res[0], &res[1]); 501 return res; 502 } 503 504 void layoutExtents(out Rectangle inkRect, out Rectangle logicalRect) { 505 pango_layout_iter_get_layout_extents(nativePtr, &inkRect, &logicalRect); 506 } 507 508 @property int baseline() { 509 return pango_layout_iter_get_baseline(nativePtr); 510 } 511 512 }