ThallionDarkshine
Member
Alright, so I'm working on a really customizable HUD framework. It uses a language sort of like HTML, only not as great. Right now I'm working on adding new features and elements and stuff like that, but if anyone would like to try it out, here's the script. This is basically a tool for non-scripters to create awesome-looking huds that look exactly how they want them to look.
I originally started making this in RMXP, but ported it over to RMVXA when it appeared that I had found a bug in RMXP's ruby interpreter. However, I just tried back-porting it to RMXP, and it worked. So now, I will resume development in RMXP. Here is the current RMXP version of the script:
And here's a list of the elements and properties that I've already added:
Edit - Here's a screenie of some of the different types of gradient bars.
Code:
module DesignHUD
# This HUD uses an easy to use format for configuration much like html
# it has many types of tags, each inserting different information into the
# HUD, such as icons, hp/sp/xp bars, and different information about the
# actors.
#
# Tags:
#
# Formatting Elements:
# * <i></i>
# - italicizes text
# * <b></b>
# - bolds text
# * <c=R:G:B[:A]></c>
# - changes the color to Color.new(R, G, B, A) (A is unnecessary)
# * <font=NAME:SIZE></font>
# - changes the font to NAME and the font size to SIZE
# Graphical Elements:
# * <ico=X:Y>
# - inserts the icon in the iconset with an offset of X, Y
# * <pic='FILENAME'>
# - inserts the picture named FILENAME
# * <bar='TYPE:STYLE:WIDTH'>
# - inserts the blizzart bar (if using blizzart bars) in style STYLE
# and with colors corresponding to the stat TYPE with width WIDTH
# - types: HP, SP, EXP
# Positioning Elements:
# * <pos x=VALX y=VALY></pos>
# - positions the contents at an x position of VALX and
# at a y position of VALY
# * <offset x=VALX y=VALY></offset>
# - adds VALX and VALY to the position of the contents
# * <table></table>
# - starts a table
# * <tr></tr>
# - adds a row to a table
# * <td></td>
# - adds a cell to a row of a table
# * <left></left>
# - aligns the contents to the left
# * <center></center>
# - aligns the contents in the center
# * <right></right>
# - aligns the contents to the right
# * <ln></ln>
# - denotes one line in the HUD
# * <width=VAL></width>
# - sets the width of the contents to VAL
# * <height=VAL></height>
# - sets the height of the contents to VAL
# HUD Properties:
# * <hud>
# - this tag has many properties, listed below
# * skin_tone=R:G:B
# - sets the tone of the windowskin
# * bg='FILENAME'
# - sets the background image of the HUD to the picture named FILENAME
# * align=ALIGN
# - sets the align of the HUD to ALIGN
# - possible aligns: TL, TC, TR, ML, MC, MR, BL, BC, BR (top-left,
# top-center, top-right, middle-left, middle-center, middle-right,
# bottom-left, bottom-center, bottom-right)
# * offsetx=VAL
# - sets the xoffset of the HUD to VAL
# * offsety=VAL
# - and the yoffset of the HUD to VAL
# * width=VAL
# - sets the width of the HUD to VAL
# * height=VAL
# - sets the height of the HUD to VAL
# * back_opacity=VAL
# - sets the back opacity of the HUD to VAL
# * contents_opacity=VAL
# - sets the contents opacity of the HUD to VAL
# * opacity=VAL
# - sets the opacity of the HUD to VAL
HUD = <<-HUD
<hud bg=Cdd1I windowskin=Window skin_tone=255:-127:10 align='Bc' width=128 offsetx=0 offsety=0 opacity=0 contents_opacity=255>
<ln><right><c=255:255:0><var=gold>G</c></right></ln>
<ln><font=Times New Roman:24>Test</font></ln>
HUD
NO_END = ['ico', 'pic', 'hud', 'var']
BLOCK_ELS = ['ln']
def self.var_expression(name)
case name
when 'gold' then return proc { $game_party.gold }
else return proc {}
end
end
end
class HUD < Window_Base
attr_accessor :tmp_attrs
def initialize(text)
super(0, 0, 33, 33)
create_contents
self.visible = false
@align = 'TL'
@xoffset, @yoffset = 0, 0
@tmp_attrs = {}
@text = text
Element.reset_id
parse_text
setup_hud
setup_align
@dom.delete_if { |el| el.el_type == 'hud' }
create_contents
tmp = self.contents
render_hud
end
def update
redim = []
vars = []
redraw = []
@var_nodes.each { |el|
val = el.val
if val != el.attrs[:val]
vars.push(el)
redim |= [el.last_line]
pos = el.attrs[:pos]
rect = el.attrs[:size]
rect.x, rect.y = *pos
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
el.attrs[:val] = val
end
}
@dom.each { |el|
comp = false
el.each_child_ex2(proc { |child|
comp = false
}) { |child|
if child.attrs[:size] and !comp
pos = child.attrs[:pos]
rect = child.attrs[:size]
rect.x, rect.y = *pos
if vars.select { |el| pos = el.attrs[:pos];tmp = el.attrs[:size];tmp.x, tmp.y = *pos;tmp.intersect?(rect) }.length > 0
redraw.push(child)
comp = true
end
end
}
}
redraw ||= vars
redetermine_size(redim) if redim.length > 0
setup_align
redraw_hud(redraw) if redraw.length > 0
end
def redetermine_size(els)
@tmp_attrs[:ox] = 0
@tmp_attrs[:oy] = 0
pos = [0, 0]
@dom.each { |el|
ln_height = ln_width = 0
if els.include?(el)
pos = el.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
case el.el_type
when 'ln'
el.each_child_ex(proc { |child|
if @tmp_attrs[:tmp]
unless child.attrs[:size].nil?
rect = child.attrs[:size]
rect.x, rect.y = *child.attrs[:pos]
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
end
if @tmp_attrs[:abs_pos]
child.attrs[:pos] = [@tmp_attrs[:abs_pos].last[0] + @tmp_attrs[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]
else
child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]
end
end
if els.include?(child)
pos = child.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
case child
when FormatNode
tmp = child.attrs[:start].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
},
proc { |child|
case child
when FormatNode
tmp = child.attrs[:finish].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
if @tmp_attrs[:tmp]
if els.include?(child)
@tmp_attrs[:tmp].pop
@tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
end
end
unless child.children.empty?
resize(child)
end
}) { |child|
if @tmp_attrs[:tmp]
case child
when TextNode
size = self.contents.text_size(child.attrs[:val])
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
when VariableNode
size = self.contents.text_size(child.val)
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
when IconNode, PictureNode
size = child.attrs[:bitmap].rect
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
end
end
}
end
#pos[1] += ln_height + @tmp_attrs[:oy]
#ln_widths.push(ln_width)
if @tmp_attrs[:tmp]
if els.include?(el)
@tmp_attrs[:tmp].pop
@tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
end
end
}
@dom.each { |child|
if child.block?
child.attrs[:size].width = self.width - padding * 2
end
}
end
def redraw_hud(els)
@tmp_attrs = {}
@dom.each { |el|
align = 0
case el.el_type
when 'ln'
if els.include?(el)
pos = el.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
el.each_child_ex(proc { |child|
if els.include?(child)
pos = child.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
case child
when FormatNode
child.attrs[:start].call(child, self)
end
},
proc { |child|
case child
when FormatNode
child.attrs[:finish].call(child, self)
end
if @tmp_attrs[:tmp]
if els.include?(child)
@tmp_attrs[:tmp].pop
@tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
end
end
}) { |child|
if @tmp_attrs[:tmp]
case child
when TextNode
pos = child.attrs[:pos]
text = child.attrs[:val]
size = child.attrs[:size]#self.contents.text_size(text)
#ln_height = [size.height, ln_height].max
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when VariableNode
pos = child.attrs[:pos]
text = child.val
size = child.attrs[:size]
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when IconNode, PictureNode
pos = child.attrs[:pos]
bitmap = child.attrs[:bitmap]
self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)
end
end
}
#if ind <= text.length - 1
# text[ind..text.length - 1].each { |i|
# self.contents.draw_text(Rect.new(x, y, self.width, 32), i)
# x += self.contents.text_size(i).width
# }
#end
end
}
end
def parse_text
text = @text.clone
@dom, @var_nodes = [], []
index = 0
current_id = -1
current_el = nil
parent = nil
parent_els = []
spattern = /<([\w\-]+)(?:=([\w\"\'\-\_\:\$\.]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/
epattern = /<\/[\w\-]+>/
while text.length != 0
s_ind = text.index(spattern)
if s_ind != nil
contents = nil
el_name = $1
el_val = $2 || ''
el_attrs = {}
tmp = $3.strip
tmp.gsub(/(\w+)\s+=\s+([\w\"\'\-\:]+)/, "\\1=\\2").split(/\s+/).each { |el| el_attrs[el.split('=')[0].to_sym] = el.split('=')[1].gsub(/[\'\"]/, '') }
el_val.gsub!(/[\'\"]/, '') if el_val
el_attrs[:val] = el_val
level, tmp_name, tmp_ind = 0, '', s_ind
if !DesignHUD::NO_END.include?(el_name)
loop do
text.sub!(spattern, '')
tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]
tmp.push(text.index(/<\/#{el_name}>/, tmp_ind))
if !tmp[1]
contents = text[s_ind...text.length - 4 - el_name.length]
text = ''
elsif !tmp[0]
contents = text[s_ind...text.length - 4 - el_name.length]
text = ''
elsif tmp[1] < tmp[0]
contents = text[s_ind...tmp[1]]
text = text[tmp[1]...text.length]
else
level += 1
tmp_ind = tmp[0] + 2 + el_name.length
end
break if contents != nil
end
case el_name
when 'ln'
element = ContainerNode.new('ln', el_attrs, nil, contents)
@dom.push(element)
end
else
text.sub!(spattern, '')
case el_name
when 'hud'
element = HudNode.new('hud', el_attrs)
@dom.push(element)
end
end
end
end
end
def setup_hud
@dom.each { |el|
el.each_child { |tmp|
if tmp.el_type == 'hud'
self.width = tmp.attrs[:width].to_i if tmp.attrs[:width]
self.height = tmp.attrs[:height].to_i if tmp.attrs[:height]
@align = tmp.attrs[:align] if tmp.attrs[:align]
@xoffset = tmp.attrs[:offsetx].to_i if tmp.attrs[:offsetx]
@yoffset = tmp.attrs[:offsety].to_i if tmp.attrs[:offsety]
self.opacity = tmp.attrs[:opacity].to_i if tmp.attrs[:opacity]
self.back_opacity = tmp.attrs[:back_opacity].to_i if tmp.attrs[:back_opacity]
self.contents_opacity = tmp.attrs[:contents_opacity].to_i if tmp.attrs[:contents_opacity]
begin
self.windowskin = ((tmp.attrs[:windowskin] == '') ? Bitmap.new(1, 1) : Cache.system(tmp.attrs[:windowskin])) if tmp.attrs[:windowskin]
rescue
self.windowskin = Bitmap.new(1, 1)
end
self.tone = Tone.new(*tmp.attrs[:skin_tone].split(':').map{|i|i.to_f}) if tmp.attrs[:skin_tone]
@bg = Sprite.new
@bg.z = self.z - 1
if tmp.attrs[:bg]
@bg.bitmap = Cache.picture(tmp.attrs[:bg])
else
@bg.visible = false
end
end
}
}
tmp_width, tmp_height = get_dimensions
if self.width == 33
self.width = [tmp_width, 1].max + 32
end
if self.height == 33
self.height = [tmp_height, 1].max + 32
end
@dom.each { |child|
if child.block?
child.attrs[:size].width = self.width - padding * 2
end
}
@align.downcase!
xmod = (['l','c'].include?(@align[1..1]) ? 1 : -1)
ymod = (['t','m'].include?(@align[0..0]) ? 1 : -1)
xstrt = case @align[1..1]
when 'l' then 0
when 'r' then Graphics.width - self.width
when 'c' then (Graphics.width - self.width) / 2
end
ystrt = case @align[0..0]
when 't' then 0
when 'b' then Graphics.height - self.height
when 'm' then (Graphics.height - self.height) / 2
end
self.x = xstrt + xmod * @xoffset
self.y = ystrt + ymod * @yoffset
if @bg.visible
@bg.x = self.x + (self.width - @bg.bitmap.width) / 2
@bg.y = self.y + (self.height - @bg.bitmap.height) / 2
end
self.visible = true
end
def get_dimensions
ln_widths = []
height = 0
@tmp_attrs[:ox] = 0
@tmp_attrs[:oy] = 0
@tmp_attrs[:align] = 0
pos = [0, 0]
@dom.each { |el|
pos[0] = 0
ln_width = 0
ln_height = 0
case el.el_type
when 'ln'
el.attrs[:pos] = pos.clone
el.attrs[:align] = @tmp_attrs[:abs_pos]
el.attrs[:abs] = 0
el.each_child_ex(proc { |child| # start proc
child.attrs[:align] = (@tmp_attrs[:abs_pos] ? 0 : @tmp_attrs[:align])
if @tmp_attrs[:abs_pos]
child.attrs[:pos] = [@tmp_attrs[:abs_pos].last[0] + @tmp_attrs[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]
child.attrs[:abs] = @tmp_attrs[:abs_pos].length
else
child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]
child.attrs[:abs] = 0
end
case child
when FormatNode
tmp = child.attrs[:start].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
},
proc { |child| # end proc
case child
when FormatNode
tmp = child.attrs[:finish].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
if !child.children.empty?
resize(child)
elsif child.block?
child.attrs[:size] = Rect.new(0, 0, 0, 0)
end
}) { |child| # main proc
case child
when TextNode
size = self.contents.text_size(child.attrs[:val])
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
when VariableNode
size = self.contents.text_size(child.val.to_s)
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
@var_nodes.push(child)
when IconNode, PictureNode
size = child.attrs[:bitmap].rect
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
end
}
end
pos[1] += ln_height + @tmp_attrs[:oy]
ln_widths.push(ln_width)
}
height = pos[1]
width = ln_widths.max
return width, height
end
def resize(el)
size = Rect.new(0, 0, 0, 0)
x1, y1 = 640, 480
x2 = y2 = 0
len = el.attrs[:abs]
el.children.each { |i|
next if i.attrs[:abs] > len
x, y = *i.attrs[:pos]
ns = i.attrs[:size]
x1 = [x1, x].min
y1 = [y1, y].min
x2 = [x2, x + ns.width].max
y2 = [y2, y + ns.height].max
}
size.width = x2 - x1
size.height = y2 - y1
pos = [x1, y1]
el.attrs[:pos], el.attrs[:size] = pos, size
end
def setup_align
aligned = nil
@dom.each { |el|
case el.el_type
when 'ln'
el.each_child_ex(proc {|child|},
proc { |child| # end proc
case child
when FormatNode
if child.attrs[:tmp]
child.attrs.delete_at(:tmp)
aligned.pop
aligned = nil if aligned.empty?
end
end
}) { |child| # main proc
break unless aligned.nil?
if ['right', 'left', 'center'].include?(child.el_type)
child.attrs[:tmp] = true
if aligned
aligned.push(true)
else
aligned = [true]
end
end
case child.attrs[:align]
when 0
pos = child.attrs[:pos]
fb = child.last_block
np = fb.attrs[:pos]
child.attrs[:pos] = np.clone
child.each_child_ex(proc{},proc{}) { |i|
i.attrs[:pos][0] += np[0] - pos[0]
i.attrs[:pos][1] += np[1] - pos[1]
}
when 1
pos = child.attrs[:pos]
fb = child.last_block
fbw = fb.attrs[:size].width
fbp = fb.attrs[:pos]
w = child.attrs[:size].width
np = [(fbw - w) / 2, pos[1]]
child.attrs[:pos] = np.clone
child.each_child_ex(proc{},proc{}) { |i|
i.attrs[:pos][0] += np[0] - pos[0]
i.attrs[:pos][1] += np[1] - pos[1]
}
when 2
pos = child.attrs[:pos]
fb = child.last_block
fbw = fb.attrs[:size].width
fbp = fb.attrs[:pos]
w = child.attrs[:size].width
np = [fbw - w, pos[1]]
child.attrs[:pos] = np.clone
child.each_child_ex(proc{},proc{}) { |i|
i.attrs[:pos][0] += np[0] - pos[0]
i.attrs[:pos][1] += np[1] - pos[1]
}
end
}
end
}
end
#~ def realign
#~ aligned = nil
#~ @dom.each { |el|
#~ case el.el_type
#~ when 'ln'
#~ el.each_child_ex(proc { |child| # start proc
#~ case child
#~ when FormatNode
#~ tmp = child.attrs[:start].call(child, self)
#~ child.attrs = tmp if tmp and tmp.is_a?(Hash)
#~ end
#~ },
#~ proc { |child| # end proc
#~ case child
#~ when FormatNode
#~ tmp = child.attrs[:finish].call(child, self)
#~ child.attrs = tmp if tmp and tmp.is_a?(Hash)
#~ if child.attrs[:tmp]
#~ child.attrs.delete_at(:tmp)
#~ aligned.pop
#~ aligned = nil if aligned.empty?
#~ end
#~ end
#~ }) { |child| # main proc
#~ break unless aligned.nil?
#~ if ['right', 'left', 'center'].include?(child.el_type)
#~ child.attrs[:tmp] = true
#~ if aligned
#~ aligned.push(true)
#~ else
#~ aligned = [true]
#~ end
#~ end
#~ case child.attrs[:align]
#~ when 0
#~ pos = child.attrs[:pos]
#~ fb = child.last_block
#~ np = fb.attrs[:pos]
#~ child.attrs[:pos] = np.clone
#~ child.each_child_ex(proc{},proc{}) { |i|
#~ i.attrs[:pos][0] += np[0] - pos[0]
#~ i.attrs[:pos][1] += np[1] - pos[1]
#~ }
#~ when 1
#~ pos = child.attrs[:pos]
#~ fb = child.last_block
#~ fbw = fb.attrs[:size].width
#~ fbp = fb.attrs[:pos]
#~ w = child.attrs[:size].width
#~ np = [(fbw - w) / 2, pos[1]]
#~ child.attrs[:pos] = np.clone
#~ child.each_child_ex(proc{},proc{}) { |i|
#~ i.attrs[:pos][0] += np[0] - pos[0]
#~ i.attrs[:pos][1] += np[1] - pos[1]
#~ }
#~ when 2
#~ pos = child.attrs[:pos]
#~ fb = child.last_block
#~ fbw = fb.attrs[:size].width
#~ fbp = fb.attrs[:pos]
#~ w = child.attrs[:size].width
#~ np = [fbw - w, pos[1]]
#~ child.attrs[:pos] = np.clone
#~ child.each_child_ex(proc{},proc{}) { |i|
#~ i.attrs[:pos][0] += np[0] - pos[0]
#~ i.attrs[:pos][1] += np[1] - pos[1]
#~ }
#~ end
#~ }
#~ end
#~ }
#~ end
def render_hud
@dom.each { |el|
align = 0
case el.el_type
when 'ln'
el.each_child_ex(proc { |child|
case child
when FormatNode
child.attrs[:start].call(child, self)
end
},
proc { |child|
case child
when FormatNode
child.attrs[:finish].call(child, self)
end
}) { |child|
case child
when TextNode
pos = child.attrs[:pos]
text = child.attrs[:val]
size = child.attrs[:size]#self.contents.text_size(text)
#ln_height = [size.height, ln_height].max
#~ if @tmp_attrs[:tmpalign]
#~ case @tmp_attrs[:tmpalign].last
#~ when 'r'
#~ pos = pos.clone
#~ pos[0] = contents.width - pos[0] - size.width
#~ end
#~ end
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when VariableNode
pos = child.attrs[:pos]
text = child.val.to_s
size = child.attrs[:size]
#~ if @tmp_attrs[:tmpalign]
#~ case @tmp_attrs[:tmpalign].last
#~ when 'r'
#~ pos = pos.clone
#~ pos[0] = contents.width - pos[0] - size.width
#~ end
#~ end
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when IconNode, PictureNode
pos = child.attrs[:pos]
bitmap = child.attrs[:bitmap]
self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)
end
}
end
}
end
def get_el(path)
el = @dom[path[0]]
if path.length > 1
path[1..path.length - 1].each { |tmp|
el = el.children[tmp]
}
end
el
end
end
class Element
@@id = 0
attr_accessor :children, :el_type, :attrs, :el_id, :parent
def initialize(el_type, attrs, parent)
@children = []
@el_type = el_type.downcase
@attrs = attrs
@parent = parent
@contents = ''
@el_id = @@id
@@id += 1
end
def block?
return DesignHUD::BLOCK_ELS.include?(@el_type)
end
def inline?
return !DesignHUD::BLOCK_ELS.include?(@el_type)
end
def self.reset_id
@@id = 0
end
def parents
if @parent != nil
parents = [@parent]
parent = @parent
while parent.parent != nil
parents.push(parent.parent)
parent = parent.parent
end
return parents
else
return []
end
end
def last_block
if @parent != nil
last = self
parent = @parent
while last.inline?
last = parent
parent = parent.parent
break if parent.nil?
end
return last
else
return nil
end
end
def last_line
if @parent != nil
last = self
parent = @parent
while last.el_type != 'ln'
last = parent
parent = parent.parent
break if parent.nil?
end
return last
else
return nil
end
end
def each_child(&block)
block.call(self)
path = [0]
cur = self
loop {
child = cur.children[path.last]
if child
block.call(child)
cur = child
path.push(0)
else
cur = cur.parent
path.pop
break unless cur
path[path.length - 1] += 1
end
}
end
def each_child_ex(start, finish, &block)
path = [0]
cur = self
loop {
child = cur.children[path.last]
if child
start.call(child)
block.call(child)
cur = child
path.push(0)
else
finish.call(cur)
cur = cur.parent
path.pop
break unless cur and path.length > 0
path[path.length-1] += 1
end
}
end
def each_child_ex2(finish, &block)
block.call(self)
path = [0]
cur = self
loop {
child = cur.children[path.last]
if child
block.call(child)
cur = child
path.push(0)
else
finish.call(cur)
cur = cur.parent
path.pop
break unless cur
path[path.length - 1] += 1
end
}
end
def parse_contents(text)
@tmp_attrs = {}
spattern = /<([\w\-]+)(?:=([\w\"\'\-\_\:\$\.\s]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/
epattern = /<\/[\w\-]+>/
while text != ''
s_ind = text.index(spattern)
if s_ind != nil
if s_ind > 0
contents = text[0...s_ind]
text = text[s_ind...text.length]
element = TextNode.new('', self, contents)
@children.push(element)
end
contents = nil
el_name = $1
el_val = $2 || ''
el_attrs = {}
tmp = $3.strip
tmp.gsub(/(\w+)\s+=\s+([\w\"\'\-\:]+)/, "\\1=\\2").split(/\s+/).each { |el| el_attrs[el.split('=')[0].to_sym] = eval(el.split('=')[1]) }
el_val.gsub!(/[\'\"]/, '') if el_val
el_attrs[:val] = el_val
level, tmp_name, tmp_ind = 0, '', 0
if !DesignHUD::NO_END.include?(el_name)
text.sub!(spattern, '')
last_ind = nil
loop do
tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]
tmp2 = tmp_ind
for i in 0..level
tmp2 = text.index(/<\/#{el_name}>/, tmp2) + 2 + el_name.length
end
tmp.push(tmp2 - 2 - el_name.length)
if !tmp[1]
contents = text[0...text.length]
text = ''
elsif !tmp[0]
contents = text[0...tmp[1]]
text = text[tmp[1] + 3 + el_name.length...text.length]
level = [level - 1, 0].max
elsif tmp[1] < tmp[0]
contents = text[0...tmp[1]]
text = text[tmp[1] + 3 + el_name.length...text.length]
level = [level - 1, 0].max
else
level += 1 unless last_ind != nil and tmp[0] > last_ind[1]
tmp_ind = tmp[0] + 2 + el_name.length
end
last_ind = tmp
break if contents != nil
end
case el_name
when 'ln'
element = ContainerNode.new('ln', el_attrs, self, contents)
@children.push(element)
when 'b'
element = FormatNode.new('b', self, contents, proc { |child, hud|
if !@tmp_attrs[:tmpb]
@tmp_attrs[:tmpb] = [hud.contents.font.bold]
else
@tmp_attrs[:tmpb].push(hud.contents.font.bold)
end
hud.contents.font.bold = true
},
proc { |child, hud|
hud.contents.font.bold = @tmp_attrs[:tmpb].pop
})
@children.push(element)
when 'i'
element = FormatNode.new('i', self, contents, proc { |child, hud|
if !@tmp_attrs[:tmpi]
@tmp_attrs[:tmpi] = [hud.contents.font.italic]
else
@tmp_attrs[:tmpi].push(hud.contents.font.italic)
end
hud.contents.font.italic = true
},
proc { |child, hud|
hud.contents.font.italic = @tmp_attrs[:tmpi].pop
})
@children.push(element)
when 'c'
element = FormatNode.new('c', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpc]
hud.tmp_attrs[:tmpc] = [hud.contents.font.color.clone]
else
hud.tmp_attrs[:tmpc].push(hud.contents.font.color.clone)
end
hud.contents.font.color = Color.new(*child.attrs[:val].split(':').map { |i| i.to_i })
},
proc { |child, hud|
hud.contents.font.color = hud.tmp_attrs[:tmpc].pop
}, el_val)
@children.push(element)
when 'font'
element = FormatNode.new('font', self, contents, proc { |child, hud|
if !@tmp_attrs[:tmpfn]
hud.tmp_attrs[:tmpfn] = [[hud.contents.font.name.clone, hud.contents.font.size]]
else
hud.tmp_attrs[:tmpfn].push([hud.contents.font.name.clone, hud.contents.font.size])
end
if Font.exist?(child.attrs[:val].split(':')[0])
hud.contents.font.name = child.attrs[:val].split(':')[0]
hud.contents.font.size = child.attrs[:val].split(':')[1].to_i
end
},
proc { |child, hud|
hud.contents.font.name, hud.contents.font.size = *hud.tmp_attrs[:tmpfn].pop
}, el_val)
@children.push(element)
when 'pos'
element = FormatNode.new('pos', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:abs_pos]
hud.tmp_attrs[:abs_pos] = [[child.attrs[:x], child.attrs[:y]]]
else
hud.tmp_attrs[:abs_pos].push([child.attrs[:x], child.attrs[:y]])
end
},
proc { |child, hud|
hud.tmp_attrs[:abs_pos].pop
hud.tmp_attrs.delete(:abs_pos) if hud.tmp_attrs[:abs_pos].length == 0
}, el_val, el_attrs)
@children.push(element)
when 'offset'
element = FormatNode.new('offset', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpofst]
hud.tmp_attrs[:tmpofst] = [[hud.tmp_attrs[:ox], hud.tmp_attrs[:oy]]]
else
hud.tmp_attrs[:tmpofst].push([hud.tmp_attrs[:ox], hud.tmp_attrs[:oy]])
end
hud.tmp_attrs[:ox], hud.tmp_attrs[:oy] = child.attrs[:x], child.attrs[:y]
},
proc { |child, hud|
hud.tmp_attrs[:ox], hud.tmp_attrs[:oy] = *hud.tmp_attrs[:tmpofst].pop
}, el_val, el_attrs)
@children.push(element)
when 'right'
element = FormatNode.new('right', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpalign]
hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
else
hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
end
hud.tmp_attrs[:align] = 2
child.attrs[:align] = 2
},
proc { |child, hud|
hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
}, el_val, el_attrs)
@children.push(element)
when 'center'
element = FormatNode.new('center', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpalign]
hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
else
hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
end
hud.tmp_attrs[:align] = 1
child.attrs[:align] = 1
},
proc { |child, hud|
hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
}, el_val, el_attrs)
@children.push(element)
when 'left'
element = FormatNode.new('left', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpalign]
hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
else
hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
end
hud.tmp_attrs[:align] = 0
child.attrs[:align] = 0
},
proc { |child, hud|
hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
}, el_val, el_attrs)
@children.push(element)
end
else
text.sub!(spattern, '')
case el_name
when 'hud'
element = HudNode.new('hud', el_attrs, self)
@children.push(element)
when 'var'
element = VariableNode.new(self, el_val)
@children.push(element)
when 'ico'
element = IconNode.new(self, el_val)
@children.push(element)
when 'pic'
element = PictureNode.new(self, el_val)
@children.push(element)
end
end
else
contents = text
text = ''
element = TextNode.new('', self, contents)
@children.push(element)
end
end
end
end
class TextNode < Element
def initialize(type, parent, text)
super(type, {}, parent)
@attrs[:val] = text
end
end
class PictureNode < Element
def initialize(parent, val)
super('pic', {}, parent)
@attrs[:bitmap] = Cache.picture(val)
end
end
class IconNode < Element
def initialize(parent, val)
super('ico', {}, parent)
offset = val.split(':').map { |i| i.to_i * 24 }
@attrs[:bitmap] = Bitmap.new(24, 24)
iconset = Cache.system('IconSet')
@attrs[:bitmap].blt(0, 0, iconset, Rect.new(offset[0], offset[1], 24, 24))
end
end
class VariableNode < Element
def initialize(parent, name)
super('var', {}, parent)
@attrs[:expr] = DesignHUD.var_expression(name)
@attrs[:val] = @attrs[:expr].call || 0
end
def val
tmp = @attrs[:expr].call
return (tmp.nil? ? 0 : tmp)
end
end
class BarNode < Element
end
class HudNode < Element
def initialize(type, attrs, parent = nil)
super('hud', attrs, parent)
end
end
class ContainerNode < Element
def initialize(type, attrs, parent, contents)
super(type, attrs, parent)
parse_contents(contents)
end
end
class FormatNode < Element
def initialize(type, parent, contents, start, finish, val=nil, attrs = {})
super(type, attrs, parent)
parse_contents(contents)
@attrs[:val] = val if val
@attrs[:start] = start
@attrs[:finish] = finish
end
end
class Rect
def intersect?(rect)
return false if rect.width * rect.height == 0 or self.width * self.height == 0
return true if (self.x.between?(rect.x - 1, rect.x + rect.width) or
(self.x + self.width).between?(rect.x - 1, rect.x + rect.width)) and
(self.y.between?(rect.y - 1, rect.y + rect.height) or
(self.y + self.height).between?(rect.y - 1, rect.y + rect.height))
return false
end
end
I originally started making this in RMXP, but ported it over to RMVXA when it appeared that I had found a bug in RMXP's ruby interpreter. However, I just tried back-porting it to RMXP, and it worked. So now, I will resume development in RMXP. Here is the current RMXP version of the script:
Code:
module DesignHUD
# This HUD uses an easy to use format for configuration much like html
# it has many types of tags, each inserting different information into the
# HUD, such as icons, hp/sp/xp bars, and different information about the
# actors.
#
# Tags:
#
# Formatting Elements:
# * <i></i>
# - italicizes text
# * <b></b>
# - bolds text
# * <c=R:G:B[:A]></c>
# - changes the color to Color.new(R, G, B, A) (A is unnecessary)
# * <font=NAME:SIZE></font>
# - changes the font to NAME and the font size to SIZE
# Graphical Elements:
# * <ico=FILENAME>
# - inserts the icon named FILENAME
# * <pic=FILENAME>
# - inserts the picture named FILENAME
# * <bar='TYPE:STYLE:WIDTH'>
# - inserts the blizzart bar (if using blizzart bars) in style STYLE
# and with colors corresponding to the stat TYPE with width WIDTH
# - types: HP, SP, EXP
# Positioning Elements:
# * <pos x=VALX y=VALY></pos>
# - positions the contents at an x position of VALX and
# at a y position of VALY
# * <offset x=VALX y=VALY></offset>
# - adds VALX and VALY to the position of the contents
# * <table></table>
# - starts a table
# * <tr></tr>
# - adds a row to a table
# * <td></td>
# - adds a cell to a row of a table
# * <left></left>
# - aligns the contents to the left
# * <center></center>
# - aligns the contents in the center
# * <right></right>
# - aligns the contents to the right
# * <ln></ln>
# - denotes one line in the HUD
# * <width=VAL></width>
# - sets the width of the contents to VAL
# * <height=VAL></height>
# - sets the height of the contents to VAL
# HUD Properties:
# * <hud>
# - this tag has many properties, listed below
# * windowskin='FILENAME'
# - sets the windowskin of the HUD to the windowskin named FILENAME
# * bg='FILENAME'
# - sets the background image of the HUD to the picture named FILENAME
# * align=ALIGN
# - sets the align of the HUD to ALIGN
# - possible aligns: TL, TC, TR, ML, MC, MR, BL, BC, BR (top-left,
# top-center, top-right, middle-left, middle-center, middle-right,
# bottom-left, bottom-center, bottom-right)
# * offsetx=VAL
# - sets the xoffset of the HUD to VAL
# * offsety=VAL
# - and the yoffset of the HUD to VAL
# * width=VAL
# - sets the width of the HUD to VAL
# * height=VAL
# - sets the height of the HUD to VAL
# * back_opacity=VAL
# - sets the back opacity of the HUD to VAL
# * contents_opacity=VAL
# - sets the contents opacity of the HUD to VAL
# * opacity=VAL
# - sets the opacity of the HUD to VAL
HUD = <<-HUD
<hud bg=Cdd1I windowskin=Window align='Bc' width=128 offsetx=0 offsety=0 opacity=0 contents_opacity=255>
<ln><right><c=255:255:0><var=gold>G</c></right></ln>
<ln><font=Times New Roman:24>Test</font></ln>
HUD
NO_END = ['ico', 'pic', 'hud', 'var']
BLOCK_ELS = ['ln']
def self.var_expression(name)
case name
when 'gold' then return proc { $game_party.gold }
else return proc {}
end
end
end
class HUD < Window_Base
attr_accessor :tmp_attrs
def initialize(text)
super(0, 0, 33, 33)
self.contents = Bitmap.new(1, 1)
self.visible = false
@align = 'TL'
@xoffset, @yoffset = 0, 0
@tmp_attrs = {}
@text = text
Element.reset_id
parse_text
setup_hud
setup_align
@dom.delete_if { |el| el.el_type == 'hud' }
self.contents = Bitmap.new(width - 32, height - 32)
tmp = self.contents
render_hud
end
def update
redim = []
vars = []
redraw = []
@var_nodes.each { |el|
val = el.val
if val != el.attrs[:val]
vars.push(el)
redim |= [el.last_line]
pos = el.attrs[:pos]
rect = el.attrs[:size]
rect.x, rect.y = *pos
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
el.attrs[:val] = val
end
}
@dom.each { |el|
comp = false
el.each_child_ex2(proc { |child|
comp = false
}) { |child|
if child.attrs[:size] and !comp
pos = child.attrs[:pos]
rect = child.attrs[:size]
rect.x, rect.y = *pos
if vars.select { |el| pos = el.attrs[:pos];tmp = el.attrs[:size];tmp.x, tmp.y = *pos;tmp.intersect?(rect) }.length > 0
redraw.push(child)
comp = true
end
end
}
}
redraw ||= vars
redetermine_size(redim) if redim.length > 0
setup_align
redraw_hud(redraw) if redraw.length > 0
end
def redetermine_size(els)
@tmp_attrs[:ox] = 0
@tmp_attrs[:oy] = 0
pos = [0, 0]
@dom.each { |el|
ln_height = ln_width = 0
if els.include?(el)
pos = el.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
case el.el_type
when 'ln'
el.each_child_ex(proc { |child|
if @tmp_attrs[:tmp]
unless child.attrs[:size].nil?
rect = child.attrs[:size]
rect.x, rect.y = *child.attrs[:pos]
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
end
if @tmp_attrs[:abs_pos]
child.attrs[:pos] = [@tmp_attrs[:abs_pos].last[0] + @tmp_attrs[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]
else
child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]
end
end
if els.include?(child)
pos = child.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
case child
when FormatNode
tmp = child.attrs[:start].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
},
proc { |child|
case child
when FormatNode
tmp = child.attrs[:finish].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
if @tmp_attrs[:tmp]
if els.include?(child)
@tmp_attrs[:tmp].pop
@tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
end
end
unless child.children.empty?
resize(child)
end
}) { |child|
if @tmp_attrs[:tmp]
case child
when TextNode
size = self.contents.text_size(child.attrs[:val])
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
when VariableNode
size = self.contents.text_size(child.val.to_s)
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
when IconNode, PictureNode
size = child.attrs[:bitmap].rect
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
end
end
}
end
#pos[1] += ln_height + @tmp_attrs[:oy]
#ln_widths.push(ln_width)
if @tmp_attrs[:tmp]
if els.include?(el)
@tmp_attrs[:tmp].pop
@tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
end
end
}
@dom.each { |child|
if child.block?
child.attrs[:size].width = self.width - 32
end
}
end
def redraw_hud(els)
@tmp_attrs = {}
@dom.each { |el|
align = 0
case el.el_type
when 'ln'
if els.include?(el)
pos = el.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
el.each_child_ex(proc { |child|
if els.include?(child)
pos = child.attrs[:pos].clone unless @tmp_attrs[:tmp]
if @tmp_attrs[:tmp]
@tmp_attrs[:tmp].push(true)
else
@tmp_attrs[:tmp] = [true]
end
end
case child
when FormatNode
child.attrs[:start].call(child, self)
end
},
proc { |child|
case child
when FormatNode
child.attrs[:finish].call(child, self)
end
if @tmp_attrs[:tmp]
if els.include?(child)
@tmp_attrs[:tmp].pop
@tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
end
end
}) { |child|
if @tmp_attrs[:tmp]
case child
when TextNode
pos = child.attrs[:pos]
text = child.attrs[:val]
size = child.attrs[:size]#self.contents.text_size(text)
#ln_height = [size.height, ln_height].max
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when VariableNode
pos = child.attrs[:pos]
text = child.val.to_s
size = child.attrs[:size]
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when IconNode, PictureNode
pos = child.attrs[:pos]
bitmap = child.attrs[:bitmap]
self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)
end
end
}
#if ind <= text.length - 1
# text[ind..text.length - 1].each { |i|
# self.contents.draw_text(Rect.new(x, y, self.width, 32), i)
# x += self.contents.text_size(i).width
# }
#end
end
}
end
def parse_text
text = @text.clone
@dom, @var_nodes = [], []
index = 0
current_id = -1
current_el = nil
parent = nil
parent_els = []
spattern = /<([\w\-]+)(?:=([\w\"\'\-\_\:\$\.]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/
epattern = /<\/[\w\-]+>/
while text.length != 0
s_ind = text.index(spattern)
if s_ind != nil
contents = nil
el_name = $1
el_val = $2 || ''
el_attrs = {}
tmp = $3.strip
tmp.gsub(/(\w+)\s+=\s+([\w\"\'\-\:]+)/, "\\1=\\2").split(/\s+/).each { |el| el_attrs[el.split('=')[0].to_sym] = el.split('=')[1].gsub(/[\'\"]/, '') }
el_val.gsub!(/[\'\"]/, '') if el_val
el_attrs[:val] = el_val
level, tmp_name, tmp_ind = 0, '', s_ind
if !DesignHUD::NO_END.include?(el_name)
loop do
text.sub!(spattern, '')
tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]
tmp.push(text.index(/<\/#{el_name}>/, tmp_ind))
if !tmp[1]
contents = text[s_ind...text.length - 4 - el_name.length]
text = ''
elsif !tmp[0]
contents = text[s_ind...text.length - 4 - el_name.length]
text = ''
elsif tmp[1] < tmp[0]
contents = text[s_ind...tmp[1]]
text = text[tmp[1]...text.length]
else
level += 1
tmp_ind = tmp[0] + 2 + el_name.length
end
break if contents != nil
end
case el_name
when 'ln'
element = ContainerNode.new('ln', el_attrs, nil, contents)
@dom.push(element)
end
else
text.sub!(spattern, '')
case el_name
when 'hud'
element = HudNode.new('hud', el_attrs)
@dom.push(element)
end
end
end
end
end
def setup_hud
@dom.each { |el|
el.each_child { |tmp|
if tmp.el_type == 'hud'
self.width = tmp.attrs[:width].to_i if tmp.attrs[:width]
self.height = tmp.attrs[:height].to_i if tmp.attrs[:height]
@align = tmp.attrs[:align] if tmp.attrs[:align]
@xoffset = tmp.attrs[:offsetx].to_i if tmp.attrs[:offsetx]
@yoffset = tmp.attrs[:offsety].to_i if tmp.attrs[:offsety]
self.opacity = tmp.attrs[:opacity].to_i if tmp.attrs[:opacity]
self.back_opacity = tmp.attrs[:back_opacity].to_i if tmp.attrs[:back_opacity]
self.contents_opacity = tmp.attrs[:contents_opacity].to_i if tmp.attrs[:contents_opacity]
begin
self.windowskin = ((tmp.attrs[:windowskin] == '') ? Bitmap.new(1, 1) : Cache.system(tmp.attrs[:windowskin])) if tmp.attrs[:windowskin]
rescue
self.windowskin = Bitmap.new(1, 1)
end
@bg = Sprite.new
@bg.z = self.z - 1
if tmp.attrs[:bg]
@bg.bitmap = RPG::Cache.picture(tmp.attrs[:bg])
else
@bg.visible = false
end
end
}
}
tmp_width, tmp_height = get_dimensions
if self.width == 33
self.width = [tmp_width, 1].max + 32
end
if self.height == 33
self.height = [tmp_height, 1].max + 32
end
@dom.each { |child|
if child.block?
child.attrs[:size].width = self.width - 32
end
}
@align.downcase!
xmod = (['l','c'].include?(@align[1..1]) ? 1 : -1)
ymod = (['t','m'].include?(@align[0..0]) ? 1 : -1)
xstrt = case @align[1..1]
when 'l' then 0
when 'r' then 640 - self.width
when 'c' then (640 - self.width) / 2
end
ystrt = case @align[0..0]
when 't' then 0
when 'b' then 480 - self.height
when 'm' then (480 - self.height) / 2
end
self.x = xstrt + xmod * @xoffset
self.y = ystrt + ymod * @yoffset
if @bg.visible
@bg.x = self.x + (self.width - @bg.bitmap.width) / 2
@bg.y = self.y + (self.height - @bg.bitmap.height) / 2
end
self.visible = true
end
def get_dimensions
ln_widths = []
height = 0
@tmp_attrs[:ox] = 0
@tmp_attrs[:oy] = 0
@tmp_attrs[:align] = 0
pos = [0, 0]
@dom.each { |el|
pos[0] = 0
ln_width = 0
ln_height = 0
case el.el_type
when 'ln'
el.attrs[:pos] = pos.clone
el.attrs[:align] = @tmp_attrs[:abs_pos]
el.attrs[:abs] = 0
el.each_child_ex(proc { |child| # start proc
child.attrs[:align] = (@tmp_attrs[:abs_pos] ? 0 : @tmp_attrs[:align])
if @tmp_attrs[:abs_pos]
child.attrs[:pos] = [@tmp_attrs[:abs_pos].last[0] + @tmp_attrs[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]
child.attrs[:abs] = @tmp_attrs[:abs_pos].length
else
child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]
child.attrs[:abs] = 0
end
case child
when FormatNode
tmp = child.attrs[:start].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
},
proc { |child| # end proc
case child
when FormatNode
tmp = child.attrs[:finish].call(child, self)
child.attrs = tmp if tmp and tmp.is_a?(Hash)
end
if !child.children.empty?
resize(child)
elsif child.block?
child.attrs[:size] = Rect.new(0, 0, 0, 0)
end
}) { |child| # main proc
case child
when TextNode
size = self.contents.text_size(child.attrs[:val])
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
when VariableNode
size = self.contents.text_size(child.val.to_s)
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
@var_nodes.push(child)
when IconNode, PictureNode
size = child.attrs[:bitmap].rect
child.attrs[:size] = size
ln_height = [size.height, ln_height].max
if @tmp_attrs[:abs_pos]
tmp = @tmp_attrs[:abs_pos]
ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
@tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
else
ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
pos[0] += size.width
end
end
}
end
pos[1] += ln_height + @tmp_attrs[:oy]
ln_widths.push(ln_width)
}
height = pos[1]
width = ln_widths.max
return width, height
end
def resize(el)
size = Rect.new(0, 0, 0, 0)
x1, y1 = 640, 480
x2 = y2 = 0
len = el.attrs[:abs]
el.children.each { |i|
next if i.attrs[:abs] > len
x, y = *i.attrs[:pos]
ns = i.attrs[:size]
x1 = [x1, x].min
y1 = [y1, y].min
x2 = [x2, x + ns.width].max
y2 = [y2, y + ns.height].max
}
size.width = x2 - x1
size.height = y2 - y1
pos = [x1, y1]
el.attrs[:pos], el.attrs[:size] = pos, size
end
def setup_align
aligned = nil
@dom.each { |el|
case el.el_type
when 'ln'
el.each_child_ex(proc {|child|},
proc { |child| # end proc
case child
when FormatNode
if child.attrs[:tmp]
child.attrs.delete_at(:tmp)
aligned.pop
aligned = nil if aligned.empty?
end
end
}) { |child| # main proc
break unless aligned.nil?
if ['right', 'left', 'center'].include?(child.el_type)
child.attrs[:tmp] = true
if aligned
aligned.push(true)
else
aligned = [true]
end
end
case child.attrs[:align]
when 0
pos = child.attrs[:pos]
fb = child.last_block
np = fb.attrs[:pos]
child.attrs[:pos] = np.clone
child.each_child_ex(proc{},proc{}) { |i|
i.attrs[:pos][0] += np[0] - pos[0]
i.attrs[:pos][1] += np[1] - pos[1]
}
when 1
pos = child.attrs[:pos]
fb = child.last_block
fbw = fb.attrs[:size].width
fbp = fb.attrs[:pos]
w = child.attrs[:size].width
np = [(fbw - w) / 2, pos[1]]
child.attrs[:pos] = np.clone
child.each_child_ex(proc{},proc{}) { |i|
i.attrs[:pos][0] += np[0] - pos[0]
i.attrs[:pos][1] += np[1] - pos[1]
}
when 2
pos = child.attrs[:pos]
fb = child.last_block
fbw = fb.attrs[:size].width
fbp = fb.attrs[:pos]
w = child.attrs[:size].width
np = [fbw - w, pos[1]]
child.attrs[:pos] = np.clone
child.each_child_ex(proc{},proc{}) { |i|
i.attrs[:pos][0] += np[0] - pos[0]
i.attrs[:pos][1] += np[1] - pos[1]
}
end
}
end
}
end
#~ def realign
#~ aligned = nil
#~ @dom.each { |el|
#~ case el.el_type
#~ when 'ln'
#~ el.each_child_ex(proc { |child| # start proc
#~ case child
#~ when FormatNode
#~ tmp = child.attrs[:start].call(child, self)
#~ child.attrs = tmp if tmp and tmp.is_a?(Hash)
#~ end
#~ },
#~ proc { |child| # end proc
#~ case child
#~ when FormatNode
#~ tmp = child.attrs[:finish].call(child, self)
#~ child.attrs = tmp if tmp and tmp.is_a?(Hash)
#~ if child.attrs[:tmp]
#~ child.attrs.delete_at(:tmp)
#~ aligned.pop
#~ aligned = nil if aligned.empty?
#~ end
#~ end
#~ }) { |child| # main proc
#~ break unless aligned.nil?
#~ if ['right', 'left', 'center'].include?(child.el_type)
#~ child.attrs[:tmp] = true
#~ if aligned
#~ aligned.push(true)
#~ else
#~ aligned = [true]
#~ end
#~ end
#~ case child.attrs[:align]
#~ when 0
#~ pos = child.attrs[:pos]
#~ fb = child.last_block
#~ np = fb.attrs[:pos]
#~ child.attrs[:pos] = np.clone
#~ child.each_child_ex(proc{},proc{}) { |i|
#~ i.attrs[:pos][0] += np[0] - pos[0]
#~ i.attrs[:pos][1] += np[1] - pos[1]
#~ }
#~ when 1
#~ pos = child.attrs[:pos]
#~ fb = child.last_block
#~ fbw = fb.attrs[:size].width
#~ fbp = fb.attrs[:pos]
#~ w = child.attrs[:size].width
#~ np = [(fbw - w) / 2, pos[1]]
#~ child.attrs[:pos] = np.clone
#~ child.each_child_ex(proc{},proc{}) { |i|
#~ i.attrs[:pos][0] += np[0] - pos[0]
#~ i.attrs[:pos][1] += np[1] - pos[1]
#~ }
#~ when 2
#~ pos = child.attrs[:pos]
#~ fb = child.last_block
#~ fbw = fb.attrs[:size].width
#~ fbp = fb.attrs[:pos]
#~ w = child.attrs[:size].width
#~ np = [fbw - w, pos[1]]
#~ child.attrs[:pos] = np.clone
#~ child.each_child_ex(proc{},proc{}) { |i|
#~ i.attrs[:pos][0] += np[0] - pos[0]
#~ i.attrs[:pos][1] += np[1] - pos[1]
#~ }
#~ end
#~ }
#~ end
#~ }
#~ end
def render_hud
@dom.each { |el|
align = 0
case el.el_type
when 'ln'
el.each_child_ex(proc { |child|
case child
when FormatNode
child.attrs[:start].call(child, self)
end
},
proc { |child|
case child
when FormatNode
child.attrs[:finish].call(child, self)
end
}) { |child|
case child
when TextNode
pos = child.attrs[:pos]
text = child.attrs[:val]
size = child.attrs[:size]#self.contents.text_size(text)
#ln_height = [size.height, ln_height].max
#~ if @tmp_attrs[:tmpalign]
#~ case @tmp_attrs[:tmpalign].last
#~ when 'r'
#~ pos = pos.clone
#~ pos[0] = contents.width - pos[0] - size.width
#~ end
#~ end
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when VariableNode
pos = child.attrs[:pos]
text = child.val.to_s
size = child.attrs[:size]
#~ if @tmp_attrs[:tmpalign]
#~ case @tmp_attrs[:tmpalign].last
#~ when 'r'
#~ pos = pos.clone
#~ pos[0] = contents.width - pos[0] - size.width
#~ end
#~ end
self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)
when IconNode, PictureNode
pos = child.attrs[:pos]
bitmap = child.attrs[:bitmap]
self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)
end
}
end
}
end
def get_el(path)
el = @dom[path[0]]
if path.length > 1
path[1..path.length - 1].each { |tmp|
el = el.children[tmp]
}
end
el
end
end
class Element
@@id = 0
attr_accessor :children, :el_type, :attrs, :el_id, :parent
def initialize(el_type, attrs, parent)
@children = []
@el_type = el_type.downcase
@attrs = attrs
@parent = parent
@contents = ''
@el_id = @@id
@@id += 1
end
def block?
return DesignHUD::BLOCK_ELS.include?(@el_type)
end
def inline?
return !DesignHUD::BLOCK_ELS.include?(@el_type)
end
def self.reset_id
@@id = 0
end
def parents
if @parent != nil
parents = [@parent]
parent = @parent
while parent.parent != nil
parents.push(parent.parent)
parent = parent.parent
end
return parents
else
return []
end
end
def last_block
if @parent != nil
last = self
parent = @parent
while last.inline?
last = parent
parent = parent.parent
break if parent.nil?
end
return last
else
return nil
end
end
def last_line
if @parent != nil
last = self
parent = @parent
while last.el_type != 'ln'
last = parent
parent = parent.parent
break if parent.nil?
end
return last
else
return nil
end
end
def each_child(&block)
block.call(self)
path = [0]
cur = self
loop {
child = cur.children[path.last]
if child
block.call(child)
cur = child
path.push(0)
else
cur = cur.parent
path.pop
break unless cur
path[path.length - 1] += 1
end
}
end
def each_child_ex(start, finish, &block)
path = [0]
cur = self
loop {
child = cur.children[path.last]
if child
start.call(child)
block.call(child)
cur = child
path.push(0)
else
finish.call(cur)
cur = cur.parent
path.pop
break unless cur and path.length > 0
path[path.length-1] += 1
end
}
end
def each_child_ex2(finish, &block)
block.call(self)
path = [0]
cur = self
loop {
child = cur.children[path.last]
if child
block.call(child)
cur = child
path.push(0)
else
finish.call(cur)
cur = cur.parent
path.pop
break unless cur
path[path.length - 1] += 1
end
}
end
def parse_contents(text)
@tmp_attrs = {}
spattern = /<([\w\-]+)(?:=([\w\"\'\-\_\:\$\.\s]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/
epattern = /<\/[\w\-]+>/
while text != ''
s_ind = text.index(spattern)
if s_ind != nil
if s_ind > 0
contents = text[0...s_ind]
text = text[s_ind...text.length]
element = TextNode.new('', self, contents)
@children.push(element)
end
contents = nil
el_name = $1
el_val = $2 || ''
el_attrs = {}
tmp = $3.strip
tmp.gsub(/(\w+)\s+=\s+([\w\"\'\-\:]+)/, "\\1=\\2").split(/\s+/).each { |el| el_attrs[el.split('=')[0].to_sym] = eval(el.split('=')[1]) }
el_val.gsub!(/[\'\"]/, '') if el_val
el_attrs[:val] = el_val
level, tmp_name, tmp_ind = 0, '', 0
if !DesignHUD::NO_END.include?(el_name)
text.sub!(spattern, '')
last_ind = nil
loop do
tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]
tmp2 = tmp_ind
for i in 0..level
tmp2 = text.index(/<\/#{el_name}>/, tmp2) + 2 + el_name.length
end
tmp.push(tmp2 - 2 - el_name.length)
if !tmp[1]
contents = text[0...text.length]
text = ''
elsif !tmp[0]
contents = text[0...tmp[1]]
text = text[tmp[1] + 3 + el_name.length...text.length]
level = [level - 1, 0].max
elsif tmp[1] < tmp[0]
contents = text[0...tmp[1]]
text = text[tmp[1] + 3 + el_name.length...text.length]
level = [level - 1, 0].max
else
level += 1 unless last_ind != nil and tmp[0] > last_ind[1]
tmp_ind = tmp[0] + 2 + el_name.length
end
last_ind = tmp
break if contents != nil
end
case el_name
when 'ln'
element = ContainerNode.new('ln', el_attrs, self, contents)
@children.push(element)
when 'b'
element = FormatNode.new('b', self, contents, proc { |child, hud|
if !@tmp_attrs[:tmpb]
@tmp_attrs[:tmpb] = [hud.contents.font.bold]
else
@tmp_attrs[:tmpb].push(hud.contents.font.bold)
end
hud.contents.font.bold = true
},
proc { |child, hud|
hud.contents.font.bold = @tmp_attrs[:tmpb].pop
})
@children.push(element)
when 'i'
element = FormatNode.new('i', self, contents, proc { |child, hud|
if !@tmp_attrs[:tmpi]
@tmp_attrs[:tmpi] = [hud.contents.font.italic]
else
@tmp_attrs[:tmpi].push(hud.contents.font.italic)
end
hud.contents.font.italic = true
},
proc { |child, hud|
hud.contents.font.italic = @tmp_attrs[:tmpi].pop
})
@children.push(element)
when 'c'
element = FormatNode.new('c', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpc]
hud.tmp_attrs[:tmpc] = [hud.contents.font.color.clone]
else
hud.tmp_attrs[:tmpc].push(hud.contents.font.color.clone)
end
hud.contents.font.color = Color.new(*child.attrs[:val].split(':').map { |i| i.to_i })
},
proc { |child, hud|
hud.contents.font.color = hud.tmp_attrs[:tmpc].pop
}, el_val)
@children.push(element)
when 'font'
element = FormatNode.new('font', self, contents, proc { |child, hud|
if !@tmp_attrs[:tmpfn]
hud.tmp_attrs[:tmpfn] = [[hud.contents.font.name.clone, hud.contents.font.size]]
else
hud.tmp_attrs[:tmpfn].push([hud.contents.font.name.clone, hud.contents.font.size])
end
if Font.exist?(child.attrs[:val].split(':')[0])
hud.contents.font.name = child.attrs[:val].split(':')[0]
hud.contents.font.size = child.attrs[:val].split(':')[1].to_i
end
},
proc { |child, hud|
hud.contents.font.name, hud.contents.font.size = *hud.tmp_attrs[:tmpfn].pop
}, el_val)
@children.push(element)
when 'pos'
element = FormatNode.new('pos', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:abs_pos]
hud.tmp_attrs[:abs_pos] = [[child.attrs[:x], child.attrs[:y]]]
else
hud.tmp_attrs[:abs_pos].push([child.attrs[:x], child.attrs[:y]])
end
},
proc { |child, hud|
hud.tmp_attrs[:abs_pos].pop
hud.tmp_attrs.delete(:abs_pos) if hud.tmp_attrs[:abs_pos].length == 0
}, el_val, el_attrs)
@children.push(element)
when 'offset'
element = FormatNode.new('offset', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpofst]
hud.tmp_attrs[:tmpofst] = [[hud.tmp_attrs[:ox], hud.tmp_attrs[:oy]]]
else
hud.tmp_attrs[:tmpofst].push([hud.tmp_attrs[:ox], hud.tmp_attrs[:oy]])
end
hud.tmp_attrs[:ox], hud.tmp_attrs[:oy] = child.attrs[:x], child.attrs[:y]
},
proc { |child, hud|
hud.tmp_attrs[:ox], hud.tmp_attrs[:oy] = *hud.tmp_attrs[:tmpofst].pop
}, el_val, el_attrs)
@children.push(element)
when 'right'
element = FormatNode.new('right', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpalign]
hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
else
hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
end
hud.tmp_attrs[:align] = 2
child.attrs[:align] = 2
},
proc { |child, hud|
hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
}, el_val, el_attrs)
@children.push(element)
when 'center'
element = FormatNode.new('center', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpalign]
hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
else
hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
end
hud.tmp_attrs[:align] = 1
child.attrs[:align] = 1
},
proc { |child, hud|
hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
}, el_val, el_attrs)
@children.push(element)
when 'left'
element = FormatNode.new('left', self, contents, proc { |child, hud|
if !hud.tmp_attrs[:tmpalign]
hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
else
hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
end
hud.tmp_attrs[:align] = 0
child.attrs[:align] = 0
},
proc { |child, hud|
hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
}, el_val, el_attrs)
@children.push(element)
end
else
text.sub!(spattern, '')
case el_name
when 'hud'
element = HudNode.new('hud', el_attrs, self)
@children.push(element)
when 'var'
element = VariableNode.new(self, el_val)
@children.push(element)
when 'ico'
element = IconNode.new(self, el_val)
@children.push(element)
when 'pic'
element = PictureNode.new(self, el_val)
@children.push(element)
end
end
else
contents = text
text = ''
element = TextNode.new('', self, contents)
@children.push(element)
end
end
end
end
class TextNode < Element
def initialize(type, parent, text)
super(type, {}, parent)
@attrs[:val] = text
end
end
class PictureNode < Element
def initialize(parent, val)
super('pic', {}, parent)
@attrs[:bitmap] = RPG::Cache.picture(val)
end
end
class IconNode < Element
def initialize(parent, val)
super('ico', {}, parent)
@attrs[:bitmap] = RPG::Cache.icon(el_val).clone
end
end
class VariableNode < Element
def initialize(parent, name)
super('var', {}, parent)
@attrs[:expr] = DesignHUD.var_expression(name)
@attrs[:val] = @attrs[:expr].call || 0
end
def val
tmp = @attrs[:expr].call
return (tmp.nil? ? 0 : tmp)
end
end
class BarNode < Element
end
class HudNode < Element
def initialize(type, attrs, parent = nil)
super('hud', attrs, parent)
end
end
class ContainerNode < Element
def initialize(type, attrs, parent, contents)
super(type, attrs, parent)
parse_contents(contents)
end
end
class FormatNode < Element
def initialize(type, parent, contents, start, finish, val=nil, attrs = {})
super(type, attrs, parent)
parse_contents(contents)
@attrs[:val] = val if val
@attrs[:start] = start
@attrs[:finish] = finish
end
end
class Rect
def intersect?(rect)
return false if rect.width * rect.height == 0 or self.width * self.height == 0
return true if (self.x.between?(rect.x - 1, rect.x + rect.width) or
(self.x + self.width).between?(rect.x - 1, rect.x + rect.width)) and
(self.y.between?(rect.y - 1, rect.y + rect.height) or
(self.y + self.height).between?(rect.y - 1, rect.y + rect.height))
return false
end
end
And here's a list of the elements and properties that I've already added:
<hud>
Properties Implemented:
windowskin=FILENAME
bg=FILENAME
width=WIDTH
height=HEIGHT
align=ALIGN
offsetx=OFFSETX
offsety=OFFSETY
back_opacity=OPACITY
contents_opacity=OPACITY
opacity=OPACITY
skin_tone=R:G:B (VXA only)
<ln></ln>
<right></right>
<left></left>
<center></center>
<pos x=X y=Y></pos>
<offset x=X y=Y></pos>
<ico=X:Y> (VXA only)
<ico=FILENAME> (XP only)
<pic=FILENAME>
<b></b>
<i></i>
<c=R:G:B[:A]></c>
<font=NAME:SIZE></font>
Properties Implemented:
windowskin=FILENAME
bg=FILENAME
width=WIDTH
height=HEIGHT
align=ALIGN
offsetx=OFFSETX
offsety=OFFSETY
back_opacity=OPACITY
contents_opacity=OPACITY
opacity=OPACITY
skin_tone=R:G:B (VXA only)
<ln></ln>
<right></right>
<left></left>
<center></center>
<pos x=X y=Y></pos>
<offset x=X y=Y></pos>
<ico=X:Y> (VXA only)
<ico=FILENAME> (XP only)
<pic=FILENAME>
<b></b>
<i></i>
<c=R:G:B[:A]></c>
<font=NAME:SIZE></font>
Edit - Here's a screenie of some of the different types of gradient bars.
