demo-rotatedtext.lua 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. return function(parent, dir)
  2. local lgi = require 'lgi'
  3. local Gtk = lgi.Gtk
  4. local Gdk = lgi.Gdk
  5. local cairo = lgi.cairo
  6. local Pango = lgi.Pango
  7. local PangoCairo = lgi.PangoCairo
  8. local RADIUS = 150
  9. local N_WORDS = 5
  10. local FONT = 'Serif 18'
  11. local HEART = '♥'
  12. local TEXT = 'I ♥ GTK+'
  13. local window = Gtk.Window {
  14. title = "Rotated Text",
  15. default_width = 4 * RADIUS,
  16. default_height = 2 * RADIUS,
  17. Gtk.Box {
  18. orientation = 'HORIZONTAL',
  19. homogeneous = true,
  20. Gtk.DrawingArea {
  21. id = 'circle',
  22. },
  23. Gtk.Label {
  24. id = 'label',
  25. angle = 45,
  26. label = TEXT,
  27. },
  28. }
  29. }
  30. -- Override background color of circle drawing area.
  31. window.child.circle:override_background_color(
  32. 'NORMAL', Gdk.RGBA { red = 1, green = 1, blue = 1, alpha = 1 })
  33. local function fancy_shape_renderer(cr, attr, do_path)
  34. cr:translate(cr:get_current_point())
  35. cr:scale(attr.ink_rect.width / Pango.SCALE,
  36. attr.ink_rect.height / Pango.SCALE)
  37. -- Draw the manually.
  38. cr:move_to(0.5, 0)
  39. cr:line_to(0.9, -0.4)
  40. cr:curve_to(1.1, -0.8, 0.5, -0.9, 0.5, -0.5)
  41. cr:curve_to(0.5, -0.9, -0.1, -0.8, 0.1, -0.4)
  42. cr:close_path()
  43. if not do_path then
  44. cr:set_source_rgb(1, 0, 0)
  45. cr:fill()
  46. end
  47. end
  48. local function create_fancy_attr_list_for_layout(layout)
  49. -- Get font metrics and prepare fancy shape size.
  50. local ascent = layout.context:get_metrics(layout.font_description).ascent
  51. local rect = Pango.Rectangle { x = 0, width = ascent,
  52. y = -ascent, height = ascent }
  53. -- Create attribute list, add specific shape renderer for every
  54. -- occurence of heart symbol.
  55. local attrs = Pango.AttrList()
  56. local start_index, end_index = 1, 1
  57. while true do
  58. start_index, end_index = TEXT:find(HEART, end_index + 1, true)
  59. if not start_index then break end
  60. local attr = Pango.Attribute.shape_new(rect, rect)
  61. attr.start_index = start_index - 1
  62. attr.end_index = end_index
  63. attrs:insert(attr)
  64. end
  65. return attrs
  66. end
  67. function window.child.circle:on_draw(cr)
  68. -- Create a cairo context and set up a transformation matrix so that
  69. -- the user space coordinates for the centered square where we draw
  70. -- are [-RADIUS, RADIUS], [-RADIUS, RADIUS]. We first center, then
  71. -- change the scale.
  72. local device_radius = math.min(self.width, self.height) / 2
  73. cr:translate(device_radius + (self.width - 2 * device_radius) / 2,
  74. device_radius + (self.height - 2 * device_radius) / 2)
  75. cr:scale(device_radius / RADIUS, device_radius / RADIUS)
  76. -- Create a subtle gradient source and use it.
  77. local pattern = cairo.Pattern.create_linear(-RADIUS, -RADIUS,
  78. RADIUS, RADIUS)
  79. pattern:add_color_stop_rgb(0, 0.5, 0, 0)
  80. pattern:add_color_stop_rgb(1, 0, 0, 0.5)
  81. cr:set_source(pattern)
  82. -- Create a Pango.Context and set up our shape renderer.
  83. local context = self:create_pango_context()
  84. context.shape_renderer = fancy_shape_renderer
  85. -- Create a Pango.Layout, set the text, font and attributes.
  86. local layout = Pango.Layout.new(context)
  87. layout.text = TEXT
  88. layout.font_description = Pango.FontDescription.from_string(FONT)
  89. layout.attributes = create_fancy_attr_list_for_layout(layout)
  90. -- Draw the layout N_WORDS times in a circle.
  91. for i = 1, N_WORDS do
  92. -- Inform Pango to re-layout the text with the new transformation
  93. -- matrix.
  94. cr:update_layout(layout)
  95. local width, height = layout:get_pixel_size()
  96. cr:move_to(-width / 2, -RADIUS * 0.9)
  97. cr:show_layout(layout)
  98. -- Rotate for the next turn.
  99. cr:rotate(2 * math.pi / N_WORDS)
  100. end
  101. end
  102. -- Set up fancy stuff on the label.
  103. local label = window.child.label
  104. local layout = label:get_layout()
  105. layout.context.shape_renderer = fancy_shape_renderer
  106. label:set_attributes(create_fancy_attr_list_for_layout(layout))
  107. window:show_all()
  108. return window
  109. end,
  110. "Rotated Text",
  111. table.concat {
  112. [[This demo shows how to use PangoCairo to draw rotated and transformed ]],
  113. [[text. The right pane shows a rotated Gtk.Label widget.
  114. ]],
  115. [[In both cases, a custom PangoCairo shape renderer is installed ]],
  116. [[to draw a red heard using cairo drawing operations instead of ]],
  117. [[the Unicode heart character.]]
  118. }