Description: This is a scripting tool. It's purpose is to allow the user to input an unbroken string and have returned a paragraph which has the ends of each line in line with each other. It serves roughly the same function as does the justifying option in Microsoft Word. See the screenshots if you are still confused.
Script Name: Paragraph Formatter
Author: modern algebra
Version: 2.0
Number Of Scripts: 3 (1 required, 2 optional)
Description:
This is a scripting tool. It's purpose is to allow the user to input an unbroken string and have returned a paragraph which has the ends of each line in line with each other. It serves roughly the same function as does the justifying option in Microsoft Word. See the screenshots if you are still confused.
Features
* A nice, easy way to display long strings in a paragraph format
* Easy to add and modify at runtime, allowing for the switching between formatting classes for each situation
* You can write your own formatter or artist classes and use the paragraphing tool to suit your situation.
* Highly customizable.
Screenshots:
Instructions:
As a scripter's tool, it can be quite heavy for non-scripters to use. That is why I wrote a facade for common use of the tool. Naturally, you will still need some scripting knowledge, but the facade allows for this code:
bitmap.draw_paragraph (x, y, max_width, max_height, string)
Where bitmap is the bitmap you are drawing to. This can be self.contents in a window, or any instance of the bitmap class.
It can be used like this, if you want to draw the paragraph in a different way:
formatter =artist = specifications = pg = Paragrapher.new (formatter, artist) text_bitmap = pg.paragraph (string, specifications) bitmap.blt (x, y, text_bitmap, Rect.new (0,0,text_bitmap.width, text_bitmap.height))
Basically, you choose your formatter and artist class at runtime. This means that if you want to use Paragraph::Formatter_2, because you are using a font with set width for all characters, then you would choose that here. Currently, there is only one Artist class, Paragraph::Artist, but of course you can make your own if it does not suit you. You can either specify a bitmap or a fixnum. The fixnum would just be the max width, and the paragrapher would create a bitmap which was at font_size 22, default font name, and it would space each line 32 pixels. With a bitmap, you specify max_width, max_height, font and font size, and anything else that has an effect. Naturally, bitmap in the code is the bitmap you are drawing the paragraph on. If you have any questions, just ask. Also, the text_size method of Bitmap does not, in fact, work properly. In a little while I will post a way to get around this problem as it can get in the way of drawing nice paragraphs.
Put the scripts above main and below the default scripts. For all additional Paragrapher classes, just add them in the Script Editor below the Paragraph Formatter in their own slots, but still above Main. For more pertinent instructions, see the header of the script.
Author's Notes
This script was inspired by Zeriab, and pretty much everything that is good about this script is due to Zeriab. Zeriab deserves more credit for this script then I do, rightly, but since the world isn't just... Anyway, he deserves all my thanks for being an excellent teacher.
Frequently Asked Questions:
N/A
Scripts:
Paragraph Formatter -Required
Spoiler
#============================================================================== # Paragraph Formatter (VX) # Version: 2.0 # Author: modern algebra (rmrk.net) # Date: September 10, 2009 #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Description: # The idea behind this script is to easily separate a long string into a # paragraph that fits in to the dimensions you specify. More than that, you # can also justify the paragraph #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Instructions: # For ease of use of people who are not neccesarily interested in writing # their own algorithm, I have included a facade which you can use simply by # this code: # # bitmap.draw_paragraph (x, y, width, height, string) # # where x & y are the x & y coordinates on the specified bitmap, and width # and height are the maximum dimensions of the paragraph and string is the # text you want to display in paragraph form. You can easily change which # formatter or artist classes you want to use with the codes: # # bitmap.paragraph_formatter = Paragrapher::# bitmap.paragraph_artist = Paragrapher:: @max_width next_line (@last_word) end if character == "\n" next_line (i) @format_text.blank_width[-1] = 0 end @last_word = i end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Proceed to Next Line # last_word : the index of the beginning of the previous word #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def next_line (last_word) line = @string[@line_break, last_word - @line_break] # Adds current line to f.lines @format_text.lines.push ( line.scan (/./) ) # Calculates the blank space left to cover in the line line_blank = @max_width - @format_text.bitmap.text_size(line).width @format_text.blank_width.push (line_blank.to_f / (line.size.to_f - 1.0) ) # Keeps track of the position in the array of each line @line_break = last_word + 1 end end #============================================================================ # ** Artist #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Interprets a Formatted Text object and returns a bitmap of the paragraph #============================================================================ class Artist #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Draw # f : Formatted Text Object # justify_text : boolean value on whether to justify text #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def draw (f, justify_text = true) # Calculates the necessary distance between lines line_distance = f.bitmap.height.to_f / f.lines.size.to_f line_distance = [f.bitmap.font.size + 4, line_distance].min # For all lines in the lines array for i in 0...f.lines.size blank_space = f.blank_width[i] position = 0 # For all indices of the line array for j in 0...f.lines[i].size string = f.lines[i][j] tw = f.bitmap.text_size (string).width # Draws the string located at each index f.bitmap.draw_text (position, line_distance*i, tw, line_distance, string) # Keeps track of the position we are in in pixels position += tw position += blank_space if justify_text end end return f.bitmap end end end #======================================================================== # ** Game_System #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Summary of changes: # new instance variables - default_formatter, default_artist # aliased methods - initialize #======================================================================== class Game_System #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Public Instance Variables #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attr_accessor :default_formatter attr_accessor :default_artist #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Object Initialization #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias ma_paragraph_formatter_init initialize def initialize # Run original method ma_paragraph_formatter_init # Initialize original default format and artist classes @default_formatter = Paragrapher::Formatter @default_artist = Paragrapher::Artist end end
Special Codes Formatter - Optional
Spoiler
#==============================================================================
# Special Codes Formatter (Addon for Paragraph Formatter 2.0)
# Version: 1.0
# Author: modern algebra (rmrk.net)
# Date: September 15, 2009
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Description:
#
# This is a formatter and artist combo that interprets and accounts for
# various special codes:
#
# \n - line break to next paragraph (Note the single \, NOT \\)
# \\v[x] - Shows the value located in the variable x
# \\n[x] - Shows the name of the Actor with ID x
# \\c[x] - Changes the colour of the text to x. x can be 0 - 31
# \\c[#hex] - Changes the colour of text to the hex value
# \\ - \
# \\pid[x] - Shows Actor ID of Party Member in position X (0-3)
# \\nc[x]- Shows the name of class with ID x
# \\np[x]- Shows the name of the Party Member with index x
# \\ne[x]- Shows the name of Event with ID x on the map
# \\nm[x]- Shows the name of Monster with ID x
# \\ni[x]- Shows the name of Item with ID x
# \\nw[x]- Shows the name of Weapon with ID x
# \\na[x]- Shows the name of Armour with ID x
# \\pi[x]- Shows the price of Item with ID x
# \\pw[x]- Shows the price of Weapon with ID x
# \\pa[x]- Shows the price of Armour with ID x
# \\iicon[x] - Shows the Icon of Item with ID x
# \\wicon[x] - Shows the Icon of Weapon with ID x
# \\aicon[x] - Shows the Icon of Armour with ID x
# \\icon[x] - Shows the Icon with ID x
# \\vocab[value] - prints vocab for that item type. Suitable values are:
# level, level_a, hp, hp_a, mp, mp_a, atk, def, spi,
# agi, weapon, armor1, armor2, armor3, armor4, weapon1,
# weapon2, attack, skill, guard, item, equip, status, save,
# game_end, fight, escape, new_game, shutdown, to_title,
# continue, cancel, gold
# \\f[key] - Show Filter phrase attached to key
# \\b - Bold ON
# \/b - Bold OFF
# \\i - Italic ON
# \/i - Italic OFF
# \\u - Underline ON
# \/u - Underline OFF
# \\s - Shadow ON
# \/s - Shadow OFF
# \\hl[x] - Highlights with color x. \\hl toggles off
# \\ac[x]- Shows class of actor with ID x
# \\a...[x] - Shows the ... of Actor X. ... can be any of the following:
# hp, maxhp, mp, maxmp, atk, def, spi, agi, exp_s, next_exp_s,
# next_rest_exp_s, level, weapon_id, armor1_id, armor2_id,
# armor3_id, armor4_id - and any other methods from Game_Actor.
# \\c - Centres text
# \\r - Sets right alignment to text
#
# It otherwise functions the same as the default Formatter and Artist combo.
# The names of the classes are:
#
# Formatter_SpecialCodes
# Artist_SpecialCodes
#==============================================================================
module Paragrapher
#============================================================================
# ** FILTERS
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# FILTERS allows you to set a filter and replace any \F[x] code with it's
# corresponding Entry in the Hash. Leave the FILTERS = {} line alone and
# below it, you can set all of the codes you will want to be able to put
# as an argument in the \F code.
#============================================================================
FILTERS = {}
FILTERS['PF3'] = '\c[1]Paragraph Formatter\c[0], Version 2.0: Formatter_SpecialCodes'
FILTERS[0] = 'Numbered filters work too'
#============================================================================
# ** Formatter 3
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# This class converts a string into a formatted text object, but also
# recognizes special message codes.
#============================================================================
class Formatter_SpecialCodes "
elsif no_args_codes.include? (character)
extract_code (character)
elsif character == " "
char_width = @format_text.bitmap.text_size (character).width
if @line_width + char_width + @word_width > @max_width
if @line_width == 0 # Really long word!
@last_word = i
@line_width = @word_width
end
next_line (@last_word)
else
@line_width += char_width
@line_letter_count += 1
end
@line_width += @word_width
@line_letter_count += @word_letter_count
@word_width = 0
@word_letter_count = 0
@last_word = i
elsif character == "\n" # Line break
char_width = @format_text.bitmap.text_size (" ").width
next_line (@last_word) if @line_width + char_width + @word_width > @max_width
@line_width += @word_width
@line_letter_count += @word_letter_count
next_line (i)
# Add in \n independent of system
@format_text.lines[-1].push (character)
@format_text.blank_width[-1] = 0
@word_width = 0
@last_word = i
else # Regular Character
@word_width += @format_text.bitmap.text_size(character).width
@word_letter_count += 1
if i == @string.size - 1
next_line (@last_word) if @line_width + @word_width > @max_width
end
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Proceed to Next Line
# last_word : the index of the beginning of the previous word
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def next_line (last_word)
line = @string[@line_break, last_word - @line_break]
# Adds current line to f.lines
@format_text.lines.push ( line.scan (/./) )
# Calculates the blank space left to cover in the line
line_blank = @max_width - @line_width
@format_text.blank_width.push (line_blank.to_f / (@line_letter_count.to_f) )
# Keeps track of the position in the array of each line
@line_break = last_word + 1
@line_width = 0
@line_letter_count = 0
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Convert Special Characters
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def convert_special_characters (text = @string)
return "" if text == nil
text = perform_substitution (text)
# Get substitutions
text.gsub! (/\\C\[(\d+)\]/i) { "\x01" } # Palette Color
text.gsub! (/\\C\[#([\dABCDEF]+)\]/i) { "\x01" } # Hex Color
text.gsub! (/\\IIC?O?N?\[(\d+)\]/i) { $1.to_i > 0 ? "\x02" : ""} # Item Icon
text.gsub! (/\\WIC?O?N?\[(\d+)\]/i) { $1.to_i > 0 ? "\x02" : ""} # Weapon Icon
text.gsub! (/\\AIC?O?N?\[(\d+)\]/i) { $1.to_i > 0 ? "\x02" : ""} # Armor Icon
text.gsub! (/\\IC?O?N?\[(\d+)\]/i) { "\x02" } # Icon
text.gsub! (/\\B/i) { "\x03" } # Bold ON
text.gsub! (/\\I/i) { "\x04" } # Italic ON
text.gsub! (/\\S/i) { "\x05" } # Shadow ON
text.gsub! (/\\U/i) { "\x06" } # Underline ON
text.gsub! (/\/B/i) { "\x07" } # Bold OFF
text.gsub! (/\/S/i) { "\x09" } # Shadow OFF
text.gsub! (/\/I/i) { "\x08" } # Italic OFF
text.gsub! (/\/U/i) { "\x10" } # Underline OFF
text.gsub! (/\\HL\[(-*\d+)\]/i) { "\x11" } # HighLight
text.gsub! (/\\HL/i) { "\x11" }
text.gsub! (/\\C/i) { "\x12" } # Align Centre
text.gsub! (/\\CENTRE/i) { "\x12" } # Align Centre
text.gsub! (/\\RI?G?H?T?/i) { "\x12" } # Align Right
return text
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Perform Substitution
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def perform_substitution (text = @string)
text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } # Variable
# FILTERS
text.gsub!(/\\F\[["'](.+?)["']\]/i) { FILTERS[$1.to_s] }
text.gsub!(/\\F\[(.+?)\]/i) { FILTERS[$1.to_i] }
# Party ID to Actor ID
while text[/\\PID\[(\d+)\]/i] != nil
x = $1.to_i 0 ? $game_actors[$1.to_i].name : ""} # Actor Name
text.gsub!(/\\\\/) { "\\" }
# New Codes
begin
text.gsub! (/\\VOCAB\[(\w+)\]/i) { Vocab.send ($1.downcase) } # Vocab
rescue
end
text.gsub! (/\\AC\[(\d+)\]/i) { $game_actors[$1.to_i].class.name } # Actor Class
# Actor Stats
begin
text.gsub! (/\\A([^\[]+?)\[(\d+)\]/i) { $game_actors[$2.to_i].send ($1.to_s.downcase) }
rescue
end
text.gsub! (/\\NC\[(\d+)\]/i) { $1.to_i > 0 ? $data_classes[$1.to_i].name : "" } # Class Name
text.gsub! (/\\NE\[(\d+)\]/i) { $1.to_i > 0 ? $game_map.events[$1.to_i].name : "" } # Event Name
text.gsub! (/\\NM\[(\d+)\]/i) { $1.to_i > 0 ? $data_enemies[$1.to_i].name : "" } # Monster Name
text.gsub! (/\\NI\[(\d+)\]/i) { $1.to_i > 0 ? $data_items[$1.to_i].name : "" } # Item Name
text.gsub! (/\\NW\[(\d+)\]/i) { $1.to_i > 0 ? $data_weapons[$1.to_i].name : "" } # Weapon Name
text.gsub! (/\\NA\[(\d+)\]/i) { $1.to_i > 0 ? $data_armors[$1.to_i].name : "" } # Armor Name
text.gsub! (/\\PI\[(\d+)\]/i) { $1.to_i > 0 ? $data_items[$1.to_i].price.to_s : "" } # Item Price
text.gsub! (/\\PW\[(\d+)\]/i) { $1.to_i > 0 ? $data_weapons[$1.to_i].price.to_s : "" } # Weapon Price
text.gsub! (/\\PA\[(\d+)\]/i) { $1.to_i > 0 ? $data_armors[$1.to_i].price.to_s : "" } # Armor Price
text.gsub! (/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } # Variable
return text
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Extract Code
# code : the code to extract
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def extract_code (code)
case code
when "\x02"
@word_letter_count += 1
@word_width += 24
when "\x03" then @format_text.bitmap.font.bold = true # Bold
when "\x04" then @format_text.bitmap.font.italic = true # Italic
when "\x05" then @format_text.bitmap.font.shadow = true # Shadow
when "\x07" then @format_text.bitmap.font.bold = false # Bold
when "\x08" then @format_text.bitmap.font.italic = false # Italic
when "\x09" then @format_text.bitmap.font.shadow = false # Shadow
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Argument Codes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def no_args_codes
return ["\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x10"]
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Argument Codes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def args_codes
return ["\x01", "\x02", "\x11", "\x12"]
end
end
#============================================================================
# ** Artist 2
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# This is an artist class designed to recognize some special message codes.
#============================================================================
class Artist_SpecialCodes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Draw
# f : Formatted Text Object
# justify_text : boolean value on whether to justify text
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def draw (f, justify_text = true)
@f = f
@justify_text = justify_text
@highlight = -1
@underline = false
# Calculates the necessary distance between lines
line_distance = @f.bitmap.height.to_f / @f.lines.size.to_f
@line_distance = [@f.bitmap.font.size + 4, line_distance].min
# For all lines in the lines array
for i in 0...@f.lines.size
# Compose line into a single string
@text = ""
@f.lines[i].each { |char| @text += char }
@blank_space = @f.blank_width[i]
@centre = @text[/\x12/] != nil
@right = @text[/\x12/] != nil && !@centre
total_blank = 0
if @centre || @right
@real_bitmap = @f.bitmap.dup
@f.bitmap = Bitmap.new (@real_bitmap.width, @line_distance)
@f.bitmap.font = @real_bitmap.font.dup
@y = 0
else
@y = i*@line_distance
end
@x = 0
# For all indices of the line array
loop do
c = @text.slice!(/./m)
break if c.nil?
interpret_string (c)
end
# Align Text
if @centre || @right
blank = (@real_bitmap.width - @x)
blank /= 2 if @centre
rect = Rect.new (0, 0, @real_bitmap.width, @line_distance)
@real_bitmap.blt (blank, i*@line_distance, @f.bitmap, rect)
@real_bitmap.font = @f.bitmap.font.dup
@f.bitmap.dispose
@f.bitmap = @real_bitmap
end
end
return @f.bitmap
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Get Text Color
# n : Text color number (0-31)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def text_color(n)
x = 64 + (n % 8) * 8
y = 96 + (n / 8) * 8
windowskin = Cache.system ("Window")
return windowskin.get_pixel(x, y)
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Draw Icon
# icon_index : Icon number
# x,y : draw spot coordinates
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def draw_icon(icon_index, x, y)
bitmap = Cache.system("Iconset")
rect = Rect.new(icon_index % 16 * 24, icon_index / 16 * 24, 24, 24)
@f.bitmap.blt(x, y, bitmap, rect)
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Interpret Character
# char : the char to decode
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def interpret_string (char)
case char
when "\x01" # Colour
@text.slice! (//i)
if $1.include? ("#")
r, g, b = $1[1, 2].to_i (16), $1[3, 2].to_i (16), $1[5, 2].to_i (16)
@f.bitmap.font.color = Color.new (r, g, B)
else
@f.bitmap.font.color = text_color ($1.to_i)
end
when "\x02" # Icon
@text.slice! (//)
draw_icon ($1.to_i, @x, @y)
@x += 24
@x += @justify_text && !@centre && !@right ? @blank_space : 0
when "\x03" then @f.bitmap.font.bold = true # Bold ON
when "\x04" then @f.bitmap.font.italic = true # Italic ON
when "\x05" then @f.bitmap.font.shadow = true # Shadow ON
when "\x06" then @underline = true # Underline ON
when "\x07" then @f.bitmap.font.bold = false # Bold OFF
when "\x08" then @f.bitmap.font.italic = false # Italic OFF
when "\x09" then @f.bitmap.font.shadow = false # Shadow OFF
when "\x10" then @underline = false # Underline OFF
when "\x11" # Highlight
@text.slice! (//)
@highlight = $1.to_i
when "\x12" # Centre or Right
@text.slice! (//)
when "\n" # Draw nothing when blank space
else
draw_character (char)
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Draw Character
# string : the string to draw
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def draw_character (string)
tw = @f.bitmap.text_size (string).width
ls = @justify_text && !@centre && !@right ? @blank_space : 0
hl_rect = Rect.new (@x, @y, tw + ls, @line_distance)
# Draw Highlight
if @highlight.between? (0, 31)
colour = text_color (@highlight)
colour.alpha = 120
contents.fill_rect (hl_rect, colour)
end
# Draw Underline
if @underline
y = @y + @line_distance - 2
@f.bitmap.fill_rect (@x, y, hl_rect.width, 2, @f.bitmap.font.color)
end
# Draws the string located at each index
@f.bitmap.draw_text (@x, @y, tw, @line_distance, string)
# Keeps track of the position we are in in pixels
@x += tw + ls
end
end
end
Paragrapher::Formatter 2 - Optional
Spoiler
#==============================================================================
# ** Paragrapher::Formatter 2 (Using Zeriab's Algorithm)
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# This algorithm was written by Zeriab for fonts which have characters of
# the same width. This is like Courier New, UMEGothic and fonts of that sort.
# This algorithm attaches a cost to each line based on the amount of white
# space at the end of that line. It will display the way of writing the text
# with the lowest total cost. In prcatice, this will mean that it will, as
# much as possible, reduce the spacing between letters in a line and make
# the spacing more consistent for each line of the paragraph
#==============================================================================
module Paragrapher
class Formatter_2
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Format
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def format (string, specifications)
f = Formatted_Text.new
f.lines, f.blank_width, word_lengths, words = [], [], [], []
tracker = 0
for i in 0...string.size
if string[i,1] == " " || i == string.size - 1
if i == string.size - 1
i += 1
end
word_lengths.push (i - tracker)
words.push (string[tracker, i - tracker])
tracker = i + 1
end
end
if specifications.class == Bitmap
max_width = specifications.width
f.bitmap = specifications
elsif specifications.class == Fixnum || specifications.class == Float
max_width = specifications
f.bitmap = Bitmap.new (1,1)
else
# Error Catching: Bad specification
bitmap = Bitmap.new (200, 64)
f = format ('Specifications Error', bitmap)
p 'Specifications Error: Please Pass Fixnum, Float or Bitmap'
return f
end
tw = f.bitmap.text_size('a').width
max_width = [max_width / tw, 180].min
# Error Catching: Word too long
if word_lengths.max > max_width
f = format ('Too long' , specifications)
p 'One or more words is too long for specified width'
return f
end
position = line_break (word_lengths, max_width)
lines = give_lines (position, position.size - 1, words)
max_width *= tw
for i in 0...lines.size
line = lines[i]
f.lines.push (line.scan (/./))
if i == lines.size - 1
f.blank_width.push (0)
else
text_width = line.size * tw
extra_space = max_width - text_width
f.blank_width.push (extra_space.to_f / (line.size.to_f - 1.0))
end
end
if f.bitmap != specifications
f.bitmap = Bitmap.new (max_width, f.lines.size*32)
end
return f
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Line Break (written by Zeriab)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def line_break(word_lengths, max_length)
return false if max_length > 180
word_lengths.unshift(nil)
extra_spaces = Table.new(word_lengths.size,word_lengths.size)
line_prices = Table.new(word_lengths.size,word_lengths.size)
word_price = []
position = []
inf = max_length*max_length + 1
for i in 1...word_lengths.size
extra_spaces[i,i] = max_length - word_lengths[i]
for j in (i+1)..[word_lengths.size-1, max_length/2+i+1].min
extra_spaces[i,j] = extra_spaces[i,j-1] - word_lengths[j]-1
end
end
for i in 1...word_lengths.size
for j in i..[word_lengths.size-1, max_length/2+i+1].min
if extra_spaces[i,j] = 0
line_prices[i,j] = 0
else
line_prices[i,j] = extra_spaces[i,j]*extra_spaces[i,j]
end
end
end
word_price[0] = 0
for j in 1...word_lengths.size
word_price[j] = inf
for ik in 1..j
i = j - ik + 1
break if line_prices[i,j] == inf
if word_price[i-1] + line_prices[i,j]


Help

