Bitmap styles
#1
Bitmap styles
by Jimmie
Jul 8 2009

This is a locked, single-post thread from Creation Asylum. Archived here to prevent its loss.
No support is given. If you are the owner of the thread, please contact administration.


Introduction
First off, let me say that I'm not finished. I'm still working on implementing (or rather, designing) positioning (for things other than underlines) borders (for things other than text) and runtime changes of a bitmap's style. Even so, I find what I have rather useful. I'd also like comments and requests!

This is my take on styling. So far, it handles only text, but my ambition is to expand it to anything you draw on a Bitmap. You set up styles (either by creating classes for each individual one or by instantiating a base class and modifying it at run-time) and then use that style when you create a Bitmap. The style then determines how text is drawn. Each "main" style can contain several "sub" styles which you can swap between while drawing text, just like you can normally change color or size.

Examples
Normal menu (almost)

Styled menu


This change was achieved by editing a single line of code.

Code
The system consists of three parts:

A modification of Window_Base
A modification of Bitmap
A definition of Styles

Once installed, all windows are affected immediately.
So without further ado, here are the scripts. Paste them all in any order anywhere between "Window_Base" and "Main".

Code:
#========================================================================
# ** Window_Base modification for CSS-like Styles
# * Version 1.0 by Jimme Reashu @ 8 July 2009
#========================================================================

class Window_Base
  
  #--------------------------------------------------------------------------
  # * Shorthands for changing the bitmap's font to various styles
  #--------------------------------------------------------------------------
  def set_normal_font
    self.contents.set_font_style(:normal_font)
  end
  
  def set_title_font
    self.contents.set_font_style(:title_font)
  end
  
  def set_system_font
    self.contents.set_font_style(:system_font)
  end
  
  
  #--------------------------------------------------------------------------
  # * Draws the name of an actor in the "title" style
  #--------------------------------------------------------------------------
  def draw_actor_name(actor, x, y)
    set_title_font
    self.contents.draw_text(x, y, 120, 32, actor.name)
  end
  
  #--------------------------------------------------------------------------
  # * Draws the name of an actor's class
  #--------------------------------------------------------------------------
  def draw_actor_class(actor, x, y)
    set_normal_font
    self.contents.draw_text(x, y, 236, 32, actor.class_name)
  end
  #--------------------------------------------------------------------------
  # * Draws an actor's level along with "Lvl" label
  #--------------------------------------------------------------------------
  def draw_actor_level(actor, x, y)
    set_system_font
    self.contents.draw_text(x, y, 32, 32, "Lvl")
    set_normal_font
    self.contents.draw_text(x + 32, y, 24, 32, actor.level.to_s, 2)
  end
  
  #--------------------------------------------------------------------------
  # * Draws the name of an actor's most urgent states
  #--------------------------------------------------------------------------
  def draw_actor_state(actor, x, y, width = 120)
    set_normal_font
    text = make_battler_state_text(actor, width, true)
    self.contents.font.color = actor.hp == 0 ? knockout_color : normal_color
    self.contents.draw_text(x, y, width, 32, text)
  end
  
  #--------------------------------------------------------------------------
  # * Draws an actor's current exp and the amount needed for next level
  # * along with "XP" label
  #--------------------------------------------------------------------------
  def draw_actor_exp(actor, x, y)
    set_system_font
    self.contents.draw_text(x, y, 24, 32, "XP")
    set_normal_font
    self.contents.draw_text(x + 24, y, 84, 32, actor.exp_s, 2)
    self.contents.draw_text(x + 108, y, 12, 32, "/", 1)
    self.contents.draw_text(x + 120, y, 84, 32, actor.next_exp_s)
  end
  #--------------------------------------------------------------------------
  # * Draws an actor's current hit points and "HP" label. If there is
  # * enough space, draws maximum hit points too.
  #--------------------------------------------------------------------------
  def draw_actor_hp(actor, x, y, width = 144)
    # Draw the "HP" label
    set_system_font
    self.contents.draw_text(x, y, 32, 32, $data_system.words.hp)
    # Does MaxHP fit?
    if width - 32 >= 108
      hp_x = x + width - 108
      flag = true
    elsif width - 32 >= 48
      hp_x = x + width - 48
      flag = false
    end
    # Draw HP
    set_normal_font
    self.contents.font.color = actor.hp == 0 ? knockout_color :
      actor.hp <= actor.maxhp / 4 ? crisis_color : normal_color
    self.contents.draw_text(hp_x, y, 48, 32, actor.hp.to_s, 2)
    # Draw MaxHP if it fits
    if flag
      set_normal_font
      self.contents.draw_text(hp_x + 48, y, 12, 32, "/", 1)
      self.contents.draw_text(hp_x + 60, y, 48, 32, actor.maxhp.to_s)
    end
  end
  
  #--------------------------------------------------------------------------
  # * Same as draw_actor_hp, for skill points
  #--------------------------------------------------------------------------
  def draw_actor_sp(actor, x, y, width = 144)
    # Draw "SP" label
    set_system_font
    self.contents.draw_text(x, y, 32, 32, $data_system.words.sp)
    # Does MaxSP fit?
    if width - 32 >= 108
      sp_x = x + width - 108
      flag = true
    elsif width - 32 >= 48
      sp_x = x + width - 48
      flag = false
    end
    # Draw SP
    set_normal_font
    self.contents.font.color = actor.sp == 0 ? knockout_color :
      actor.sp <= actor.maxsp / 4 ? crisis_color : normal_color
    self.contents.draw_text(sp_x, y, 48, 32, actor.sp.to_s, 2)
    # Draw MaxSP if it fits
    if flag
      set_normal_font
      self.contents.draw_text(sp_x + 48, y, 12, 32, "/", 1)
      self.contents.draw_text(sp_x + 60, y, 48, 32, actor.maxsp.to_s)
    end
  end
  
  #--------------------------------------------------------------------------
  # * Draw one of an actor's parameters
  # * type =  0: Atk
  #           1: Pdef
  #           2: Mdef
  #           3: Str
  #           4: Dex
  #           5: Agi
  #           6: Int
  #--------------------------------------------------------------------------
  def draw_actor_parameter(actor, x, y, type)
    case type
    when 0
      parameter_name = $data_system.words.atk
      parameter_value = actor.atk
    when 1
      parameter_name = $data_system.words.pdef
      parameter_value = actor.pdef
    when 2
      parameter_name = $data_system.words.mdef
      parameter_value = actor.mdef
    when 3
      parameter_name = $data_system.words.str
      parameter_value = actor.str
    when 4
      parameter_name = $data_system.words.dex
      parameter_value = actor.dex
    when 5
      parameter_name = $data_system.words.agi
      parameter_value = actor.agi
    when 6
      parameter_name = $data_system.words.int
      parameter_value = actor.int
    end
    set_system_font
    self.contents.draw_text(x, y, 120, 32, parameter_name)
    set_normal_font
    self.contents.draw_text(x + 120, y, 36, 32, parameter_value.to_s, 2)
  end
  
  #--------------------------------------------------------------------------
  # * Draw the name and icon of an item (or a weapon, or an armor)
  #--------------------------------------------------------------------------
  def draw_item_name(item, x, y)
    if item == nil
      return
    end
    bitmap = RPG::Cache.icon(item.icon_name)
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24))
    set_normal_font
    self.contents.draw_text(x + 28, y, 212, 32, item.name)
  end
end

Code:
#========================================================================
# ** Bitmap modification for CSS-like Styles
# * Version 1.0 by Jimme Reashu @ 8 July 2009
#========================================================================

class Bitmap
  
  alias jr_styles_init_fix_initialize initialize
  def initialize(width, height=0, style = Serif_Style.new)
    if width.is_a?(String)
      jr_styles_init_fix_initialize(width)
      if height.is_a?(Bitmap_Style)
        style = height
      end
    else
      jr_styles_init_fix_initialize(width, height)
    end
    
    @font_style = :normal_font
    @style = style
    self.font.name = style[@font_style][:name]
    self.font.size = style[@font_style][:size]
    self.font.color = style[@font_style][:color]
  end
  
  def set_font_style(font_style)
    @font_style = font_style
    self.font.name = @style[@font_style][:name]
    self.font.size = @style[@font_style][:size]
    self.font.color = @style[@font_style][:color]
  end
  
  alias jr_styles_width_fix_draw_text draw_text
  def draw_text(x, y, width, height, text, align)
    
    if (a = text_size(text).width) > width
      dummy = Bitmap.new(a+1, height)
      dummy.font = self.font
      dummy.jr_styles_width_fix_draw_text(0, 0, a+1, height, text, align)
      stretch_blt(Rect.new(x, y, width, height), dummy, Rect.new(0, 0, a+1, height))
    else
      jr_styles_width_fix_draw_text(x, y, width, height, text, align)
    end
  end
  
  alias jr_styles_style_fix_draw_text draw_text
  def draw_text(x, y, width = 0, height = 0, text = 0, align = 0, style = 0)
    if x.is_a?(Rect)
      align = width
      text = y
      height = x.height
      width = x.width
      y = x.y
      x = x.x
    end
    
    shadow = @style[@font_style][:shadow_style]
    if shadow[:used]
      col = self.font.color.clone
      self.font.color = shadow[:color]
      jr_styles_style_fix_draw_text(x + shadow[:x_offset], y + shadow[:y_offset], width, height, text, align)
      self.font.color = col
    end
    
    if @style[@font_style][:border_style][:used]
      col = self.font.color.clone
      self.font.color = @style[@font_style][:border_style][:color]
      for a in [[1,0],[0, 1]]
        for b in [1, -1]
          jr_styles_style_fix_draw_text(x+a[0]*b, y+a[1]*b, width, height, text, align)
        end
      end
      self.font.color = col
    end
    
    underline = @style[@font_style][:underline_style]
    if underline[:used]
      left = x + underline[:left_offset]
      width = [text_size(text).width, width].min + underline[:right_offset] - underline[:left_offset]
      top = y + underline[:y_offset] + text_size(text).height
      if underline[:shadow_style][:used]
        shadow_col = underline[:shadow_style][:color]
        self.fill_rect(left + underline[:shadow_style][:x_offset], top + underline[:shadow_style][:y_offset], width, underline[:height], shadow_col)
      end
      
      if underline[:border_style][:used]
        border_col = underline[:border_style][:color]
        for a in [[1, 0], [0, 1]]
          for b in [1, -1]
            self.fill_rect(left + a[0]*b, top + a[1]*b, width, underline[:height], border_col)
          end
        end
      end
  
      self.fill_rect(left, top, width, underline[:height], underline[:color])
    end
    jr_styles_style_fix_draw_text(x, y, width, height, text, align)
  end
end

Code:
#========================================================================
# ** Style definitions for CSS-like Styles
# * Version 1.0 by Jimme Reashu @ 8 July 2009
#========================================================================

class Style
  def [](x)
    return @properties[x]
  end
  
  def []=(x,y)
    return @properties[x] = y
  end
  
  def normal_color
    return Color.new(255, 255, 255, 255)
  end
  
  def system_color
    return Color.new(192, 224, 255, 255)
  end
end

class Bitmap_Style < Style
  def initialize
    @properties = {}
    
    @properties[:title_font] = Font_Style.new
    
    @properties[:normal_font] = Font_Style.new
    
    @properties[:system_font] = Font_Style.new
    @properties[:system_font][:color] = system_color
  end
end

class Serif_Style < Bitmap_Style
  def initialize
    super
    @properties[:title_font].instance_eval do
      self[:name] = "Verdana"
      self[:size] += 8
      self[:border_style][:used] = true
      self[:underline_style].instance_eval do
        self[:used] = true
        self[:border_style][:used] = true
        self[:left_offset] = -10
        self[:right_offset] = 10
        self[:y_offset] = -2
        self[:height] = 3
      end
    end
    
    @properties[:normal_font][:name] = "Georgia"
    @properties[:system_font][:name] = "Georgia"
    @properties[:system_font][:underline_style][:used] = true
    @properties[:system_font][:underline_style][:color] = system_color
    @properties[:system_font][:underline_style][:y_offset] = 5
    @properties[:system_font][:size] = 18
  end
end

class Font_Style < Style
  def initialize(name = Font.default_name, size = Font.default_size)
    @properties = {}
    @properties[:name] = name
    @properties[:size] = size
    @properties[:color] = normal_color
    @properties[:underline_style] = Underline_Style.new(false)
    @properties[:border_style] = Border_Style.new(false)
    @properties[:shadow_style] = Shadow_Style.new(false)
  end
end

class Underline_Style < Style
  def initialize(used, color = normal_color,
          left_offset = -1, right_offset = 1, y_offset = 4, height = 1,
          border_style = Border_Style.new(false),
          shadow_style = Shadow_Style.new(false))
    @properties = {}
    @properties[:used] = used
    @properties[:color] = color
    @properties[:left_offset] = left_offset
    @properties[:right_offset] = right_offset
    @properties[:y_offset] = y_offset
    @properties[:height] = height
    @properties[:border_style] = border_style
    @properties[:shadow_style] = shadow_style
  end
end

class Border_Style < Style
  def initialize(used, color = Color.new(0,0,0))
    @properties = {}
    @properties[:used] = used
    @properties[:color] = color
  end
end

class Shadow_Style < Style
  def initialize(used, x_offset = 2, y_offset = 3,
          color = Color.new(0,0,0, 128))
    @properties = {}
    @properties[:used] = used
    @properties[:x_offset] = x_offset
    @properties[:y_offset] = y_offset
    @properties[:color] = color
  end
end

Further development
As I mentioned in the introduction, I don't consider this complete (even though I've versioned it 1.0). Future plans include

Possibility to modify position (of text or image) in relation to Bitmap or original position
Possibility to have a border on images as well as text
Possibility to change the style of a Bitmap after creation
Any good ideas you guys put forward

I'm also intrigued by the idea of style-sheets which are imported from a text file, just like "real" CSS should be. This would be a lot of work, so I don't want to do it if it's just me... Perhaps also having "inline" styles where certain keywords within text would cause a change of style, although this is probably not worth the effort.

Support
If you can't make out how to use it from just the code, here's some help:

Look at the third line of code in the Bitmap modification
Look at the draw_actor_name (etc.) methods in the Window_Base modification
Look at Serif_Style and Bitmap_Style in the Style definitions.
When making your own styles, make sure they're subclasses of Bitmap_Style!

If you still need help, post! :D


//Jimmie
}




Users browsing this thread: 1 Guest(s)