
#==============================================================================#
# $Id: stroke.rb,v 1.2 2004/01/16 14:37:33 yuya Exp $
# $Source: /cvsroot/gruby/gruby/lib/grb/stroke.rb,v $
#==============================================================================#

module GRb

  class Stroke

    def initialize(color = nil, width = 1, pattern = nil, opacity = 100)
      @color   = color
      @width   = width
      @pattern = pattern
      @opacity = opacity
    end

    attr_accessor :color, :width, :pattern, :opacity

    def self.new_from(style)
      case style
      when Stroke   then return style
      when Color    then return self.new(style)
      when Hash     then return self.new_from_hash(style)
      when NilClass then return self.new
      else raise(TypeError, "GRb::Stroke/GRb::Color/Hash required")
      end
    end

    def self.new_from_hash(hash)
      stroke = self.new
      stroke.color   = hash[:color]   || nil
      stroke.width   = hash[:width]   || 1
      stroke.pattern = hash[:pattern] || nil
      stroke.opacity = hash[:opacity] || 100

      return stroke
    end

    def create_brush(image, size, color)
      trans = color.invert

      if size == 2
        brush = GD::Image.new(2, 2)
        brush.colorAllocate(*color.rgb)
      elsif size >= 3
        if image.truecolor?
          brush = GD::Image.newTrueColor(size, size)
          t = brush.colorAllocate(*trans.rgb)
          c = brush.colorAllocate(*color.rgb)
          brush.transparent(t)
          brush.filledRectangle(0, 0, size - 1, size - 1, GD::Transparent)
        else
          brush = GD::Image.new(size, size)
          t = brush.colorAllocate(*trans.rgb)
          c = brush.colorAllocate(*color.rgb)
          brush.colorAllocate(*trans.rgb)
          brush.transparent(t)
        end

        case size
        when 3
          brush.setPixel(1, 0, c)   #  *
          brush.line(0, 1, 2, 1, c) # ***
          brush.setPixel(1, 2, c)   #  *
        when 4
          brush.line(1, 0, 2, 0, c) #  **
          brush.line(0, 1, 3, 1, c) # ****
          brush.line(0, 2, 3, 2, c) # ****
          brush.line(1, 3, 2, 3, c) #  **
        when 5
          brush.setPixel(2, 0, c)   #   *
          brush.line(1, 1, 3, 1, c) #  ***
          brush.line(0, 2, 4, 2, c) # *****
          brush.line(1, 3, 3, 3, c) #  ***
          brush.setPixel(2, 4, c)   #   *
        when 6
          brush.line(2, 0, 3, 0, c) #   **
          brush.line(1, 1, 4, 1, c) #  ****
          brush.line(0, 2, 5, 2, c) # ******
          brush.line(0, 3, 5, 3, c) # ******
          brush.line(1, 4, 4, 4, c) #  ****
          brush.line(2, 5, 3, 5, c) #   **
        when 7
          brush.line(2, 0, 4, 0, c) #   ***
          brush.line(1, 1, 5, 1, c) #  *****
          brush.line(0, 2, 6, 2, c) # *******
          brush.line(0, 3, 6, 3, c) # *******
          brush.line(0, 4, 6, 4, c) # *******
          brush.line(1, 5, 5, 5, c) #  *****
          brush.line(2, 6, 4, 6, c) #   ***
        when 8
          brush.line(3, 0, 4, 0, c) #    **
          brush.line(1, 1, 6, 1, c) #  ******
          brush.line(1, 2, 6, 2, c) #  ******
          brush.line(0, 3, 7, 3, c) # ********
          brush.line(0, 4, 7, 4, c) # ********
          brush.line(1, 5, 6, 5, c) #  ******
          brush.line(1, 6, 6, 6, c) #  ******
          brush.line(3, 7, 4, 7, c) #    **
        when 9
          brush.setPixel(4, 0, c)   #     *
          brush.line(2, 1, 6, 1, c) #   *****
          brush.line(1, 2, 7, 2, c) #  *******
          brush.line(1, 3, 7, 3, c) #  *******
          brush.line(0, 4, 8, 4, c) # *********
          brush.line(1, 5, 7, 5, c) #  *******
          brush.line(1, 6, 7, 6, c) #  *******
          brush.line(2, 7, 6, 7, c) #   *****
          brush.setPixel(4, 8, c)   #     *
        when 10
          brush.line(4, 0, 5, 0, c) #     **
          brush.line(2, 1, 7, 1, c) #   ******
          brush.line(1, 2, 8, 2, c) #  ********
          brush.line(1, 3, 8, 3, c) #  ********
          brush.line(0, 4, 9, 4, c) # **********
          brush.line(0, 5, 9, 5, c) # **********
          brush.line(1, 6, 8, 6, c) #  ********
          brush.line(1, 7, 8, 7, c) #  ********
          brush.line(2, 8, 7, 8, c) #   ******
          brush.line(4, 9, 5, 9, c) #     **
        else
          half = (size / 2.0).floor
          brush.filledArc(half, half, size, size, 0, 360, 1, GD::Arc)
        end
      else
        raise(ArgumentError, 'invalid size')
      end

      return brush
    end
    protected :create_brush

    def create_pattern(pattern, cidx)
      array = []

      pattern.each_with_index { |repeat, index|
        repeat.times {
          array << (index % 2 == 0 ? cidx : GD::Transparent)
        }
      }

      return array
    end
    protected :create_pattern

    def draw?
      return false if @color.nil?
      return false if @opacity <= 0
      return true
    end

    def set(image)
      with_brush   = (!!@width   && @width >= 2)
      with_pattern = (!!@pattern && @pattern.kind_of?(Array))

      if with_brush
        brush = self.create_brush(image, @width, @color)
        image.set_brush(brush)
      end

      if with_pattern
        style = self.create_pattern(@pattern, @color.set(image))
        image.set_style(*style)
      end

      case [with_brush, with_pattern]
      when [true,  true]  then return GD::StyledBrushed
      when [true,  false] then return GD::Brushed
      when [false, true]  then return GD::Styled
      when [false, false] then return color.set(image)
      end
    end

  end # Stroke

end # GRb

#==============================================================================#
#==============================================================================#
