module MiniGL # This class provides methods for easily drawing one or multiple lines of # text, with control over the text alignment and coloring. class TextHelper # Creates a TextHelper. # # Parameters: # [font] A Gosu::Font that will be used to draw the text. # [line_spacing] When drawing multiple lines, the distance, in pixels, # between each line. def initialize(font, line_spacing = 0) @font = font @line_spacing = line_spacing end # Draws a single line of text. # # Parameters: # [text] The text to be drawn. No line breaks are allowed. You can use the # `` tag for bold, `` for italic and `` for colors. # [x] The horizontal reference for drawing the text. If +mode+ is +:left+, # all text will be drawn from this point to the right; if +mode+ is # +:right+, all text will be drawn from this point to the left; and if # +mode+ is +:center+, the text will be equally distributed to the # left and to the right of this point. # [y] The vertical reference for drawing the text. All text will be drawn # from this point down. # [mode] The alignment of the text. Valid values are +:left+, +:right+ and # +:center+. # [color] The color of the text, in hexadecimal RRGGBB format. # [alpha] The opacity of the text. Valid values vary from 0 (fully # transparent) to 255 (fully opaque). # [effect] Effect to add to the text. It can be either +nil+, for no effect, # +:border+ for bordered text, or +:shadow+ for shadowed text (the # shadow is always placed below and to the right of the text). # [effect_color] Color of the effect, if any. # [effect_size] Size of the effect, if any. In the case of +:border+, this # will be the width of the border (the border will only look # good when +effect_size+ is relatively small, compared to the # size of the font); in the case of +:shadow+, it will be the # distance between the text and the shadow. # [effect_alpha] Opacity of the effect, if any. For shadows, it is usual to # provide less than 255. # [z_index] The z-order to draw the object. Objects with larger z-orders # will be drawn on top of the ones with smaller z-orders. # # *Obs.:* This method accepts named parameters, but +text+, +x+ and +y+ are # mandatory. def write_line(text, x = nil, y = nil, mode = :left, color = 0, alpha = 0xff, effect = nil, effect_color = 0, effect_size = 1, effect_alpha = 0xff, z_index = 0) if text.is_a? Hash x = text[:x] y = text[:y] mode = text.fetch(:mode, :left) color = text.fetch(:color, 0) alpha = text.fetch(:alpha, 0xff) effect = text.fetch(:effect, nil) effect_color = text.fetch(:effect_color, 0) effect_size = text.fetch(:effect_size, 1) effect_alpha = text.fetch(:effect_alpha, 0xff) z_index = text.fetch(:z_index, 0) text = text[:text] end color = (alpha << 24) | color rel = case mode when :left then 0 when :center then 0.5 when :right then 1 else 0 end if effect effect_color = (effect_alpha << 24) | effect_color if effect == :border @font.draw_markup_rel text, x - effect_size, y - effect_size, z_index, rel, 0, 1, 1, effect_color @font.draw_markup_rel text, x, y - effect_size, z_index, rel, 0, 1, 1, effect_color @font.draw_markup_rel text, x + effect_size, y - effect_size, z_index, rel, 0, 1, 1, effect_color @font.draw_markup_rel text, x + effect_size, y, z_index, rel, 0, 1, 1, effect_color @font.draw_markup_rel text, x + effect_size, y + effect_size, z_index, rel, 0, 1, 1, effect_color @font.draw_markup_rel text, x, y + effect_size, z_index, rel, 0, 1, 1, effect_color @font.draw_markup_rel text, x - effect_size, y + effect_size, z_index, rel, 0, 1, 1, effect_color @font.draw_markup_rel text, x - effect_size, y, z_index, rel, 0, 1, 1, effect_color elsif effect == :shadow @font.draw_markup_rel text, x + effect_size, y + effect_size, z_index, rel, 0, 1, 1, effect_color end end @font.draw_markup_rel text, x, y, z_index, rel, 0, 1, 1, color end # Draws text, breaking lines when needed and when explicitly caused by the # "\n" character. # # Parameters: # [text] The text to be drawn. Line breaks are allowed. You can use the # `` tag for bold, `` for italic and `` for colors. # [x] The horizontal reference for drawing the text. Works like in # +write_line+ for the +:left+, +:right+ and +:center+ modes. For the # +:justified+ mode, works the same as for +:left+. # [y] The vertical reference for drawing the text. All text will be drawn # from this point down. # [width] The maximum width for the lines of text. Line is broken when # this width is exceeded. # [mode] The alignment of the text. Valid values are +:left+, +:right+, # +:center+ and +:justified+. # [color] The color of the text, in hexadecimal RRGGBB format. # [alpha] The opacity of the text. Valid values vary from 0 (fully # transparent) to 255 (fully opaque). # [z_index] The z-order to draw the object. Objects with larger z-orders # will be drawn on top of the ones with smaller z-orders. def write_breaking(text, x, y, width, mode = :left, color = 0, alpha = 0xff, z_index = 0) color = (alpha << 24) | color text.split("\n").each do |p| if mode == :justified y = write_paragraph_justified p, x, y, width, color, z_index else rel = case mode when :left then 0 when :center then 0.5 when :right then 1 else 0 end y = write_paragraph p, x, y, width, rel, color, z_index end end end private def write_paragraph(text, x, y, width, rel, color, z_index) line = '' line_width = 0 text.split(' ').each do |word| w = @font.markup_width word if line_width + w > width @font.draw_markup_rel line.chop, x, y, z_index, rel, 0, 1, 1, color line = '' line_width = 0 y += @font.height + @line_spacing end line += "#{word} " line_width += @font.markup_width "#{word} " end @font.draw_markup_rel line.chop, x, y, z_index, rel, 0, 1, 1, color unless line.empty? y + @font.height + @line_spacing end def write_paragraph_justified(text, x, y, width, color, z_index) space_width = @font.text_width ' ' spaces = [[]] line_index = 0 new_x = x words = text.split(' ') words.each do |word| w = @font.markup_width word if new_x + w > x + width space = x + width - new_x + space_width index = 0 while space > 0 spaces[line_index][index] += 1 space -= 1 index += 1 index = 0 if index == spaces[line_index].size - 1 end spaces << [] line_index += 1 new_x = x end new_x += @font.markup_width(word) + space_width spaces[line_index] << space_width end index = 0 spaces.each do |line| new_x = x line.each do |s| @font.draw_markup words[index], new_x, y, z_index, 1, 1, color new_x += @font.markup_width(words[index]) + s index += 1 end y += @font.height + @line_spacing end y end end end