lib/minigl/text.rb in minigl-2.2.2 vs lib/minigl/text.rb in minigl-2.2.3

- old
+ new

@@ -1,188 +1,190 @@ -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 <code>Gosu::Font</code> 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. - # [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_rel text, x - effect_size, y - effect_size, z_index, rel, 0, 1, 1, effect_color - @font.draw_rel text, x, y - effect_size, z_index, rel, 0, 1, 1, effect_color - @font.draw_rel text, x + effect_size, y - effect_size, z_index, rel, 0, 1, 1, effect_color - @font.draw_rel text, x + effect_size, y, z_index, rel, 0, 1, 1, effect_color - @font.draw_rel text, x + effect_size, y + effect_size, z_index, rel, 0, 1, 1, effect_color - @font.draw_rel text, x, y + effect_size, z_index, rel, 0, 1, 1, effect_color - @font.draw_rel text, x - effect_size, y + effect_size, z_index, rel, 0, 1, 1, effect_color - @font.draw_rel text, x - effect_size, y, z_index, rel, 0, 1, 1, effect_color - elsif effect == :shadow - @font.draw_rel text, x + effect_size, y + effect_size, z_index, rel, 0, 1, 1, effect_color - end - end - @font.draw_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. - # [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.text_width word - if line_width + w > width - @font.draw_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.text_width "#{word} " - end - @font.draw_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.text_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.text_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 words[index], new_x, y, z_index, 1, 1, color - new_x += @font.text_width(words[index]) + s - index += 1 - end - y += @font.height + @line_spacing - end - y - end - end -end +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 <code>Gosu::Font</code> 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 + # `<b>` tag for bold, `<i>` for italic and `<c=rrggbb>` 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 + # `<b>` tag for bold, `<i>` for italic and `<c=rrggbb>` 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