Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #==============================================================================#
- # #
- # ,o888888o. .8. 8 888888888o #
- # 8888 `88. .888. 8 8888 `88. #
- # ,8 8888 `8. :88888. 8 8888 `88 #
- # 88 8888 . `88888. 8 8888 ,88 #
- # 88 8888 .8. `88888. 8 8888. ,88' #
- # 88 8888 .8`8. `88888. 8 8888888888 #
- # 88 8888 8888888 .8' `8. `88888. 8 8888 `88. #
- # `8 8888 .8'.8' `8. `88888. 8 8888 88 #
- # 8888 ,88'.888888888. `88888. 8 8888 ,88' #
- # `8888888P' .8' `8. `88888. 8 888888888P #
- # #
- # ,o888888o. ,o888888o. 8 888888888o. 8 8888888888 #
- # 8888 `88. . 8888 `88. 8 8888 `88. 8 888888888 #
- # ,8 8888 `8. ,8 8888 `8b 8 8888 `88 8 8888 #
- # 88 8888 88 8888 `8b 8 8888 ,88 8 8888 #
- # 88 8888 88 8888 88 8 8888. ,88' 8 88888888 #
- # 88 8888 88 8888 88 8 888888888P' 8 88888888 #
- # 88 8888 88 8888 ,8P 8 8888`8b 8 8888 #
- # `8 8888 .8' `8 8888 ,8P 8 8888 `8b. 8 8888 #
- # 8888 ,88' ` 8888 ,88' 8 8888 `8b. 8 88888888888 #
- # `8888888P' `8888888P' 8 8888 `88. 8 888888888888 #
- # #
- #------------------------------------------------------------------------------#
- # O Gab Core é um conjunto de códigos utilitários para diversos scripters. #
- # A função primordial é auxiliar na compatibilização e facilitação da progra- #
- # mação para este público alvo. Para isto, o core está documentado e com as #
- # especificações necessárias explicadas abaixo. #
- #------------------------------------------------------------------------------#
- # #
- # A documentação apresenta o seguinte padrão: #
- # #
- # #
- # 1 - Módulos e Classes: #
- # #
- # a) Cada classe ou módulo apresenta asteriscos duplos antes de seu nome, #
- # tal como no exemplo: #
- # ** String #
- # #
- # b) As classes definidas pelo core apresentam uma linha tracejada (---) e #
- # logo abaixo a sua descrição, utilidade, funcionamente e/ou utilização. #
- # #
- # #
- # 2 - Métodos: #
- # #
- # a) A documentação para métodos é realizada logo acima de cada um, contendo #
- # a explicação sobre qual sua finalidade, a classe esperada para cada um #
- # de seus argumentos, o nome do argumento e a descrição de cada um. #
- # Além de apresentar também a classe do retora e uma descrição sobre. #
- # #
- # b) A classe dos argumentos possui alguns diferenciais, para facilitar a #
- # descrição da variedade de possibilidades alguns padrões: #
- # #
- # - [Mixed] indica que o objeto pode ser de diferentes classes, isto #
- # dependerá de como o método foi chamado. #
- # #
- # - [Boolean] se refere a um objeto TrueClass ou FalseClass. #
- # #
- # - [Lista: Klass] se refere a uma sequência de objetos da classe Klass. #
- # Pode ser utilizada ainda como [Lista: Klass1, Klass2, ...] que se #
- # refere a uma lista que tem um objeto da classe Klass1, seguido de um #
- # da class Klass2 e assim por diante. #
- # #
- # - [Klass1|Klass2] indica que o objeto pode ser da classe Klass1 *ou* #
- # Klass2. #
- # #
- # d) Quando a classe do retorno não for especificada, significa que o método #
- # pode não retornar (chamar erro), porém isto será especificado na des- #
- # crição. #
- # #
- # e) Quando não especificado, o retorno será nulo ou sem importância. #
- # #
- # #
- #------------------------------------------------------------------------------#
- # #
- # Mapa de versionamento: #
- # #
- # #
- # Frodo Release: #
- # - Core (1.0) #
- # - RPG Maker Utils (1.0) #
- # - Array Plus (1.0) #
- # - Color Plus (1.0) #
- # - Number Plus (1.0) #
- # - Module Plus (1.0) #
- # - Kernel Plus (1.0) #
- # - Position Helper (1.0) #
- # - Dir Plus (1.0) #
- # - Rect Plus (1.0) #
- # - Bitmap Plus (1.0) #
- # - Binary Control (1.0) #
- # - INIReader (1.0) #
- # #
- #==============================================================================#
- #=============================================================================
- # ** Gab
- #---------------------------------------------------------------------------
- # Responsável por gerenciar scripts incluídos e versionamento
- #=============================================================================
- module Gab
- #---------------------#
- # Classes de Erro #
- #---------------------#
- class ScriptRequired < ::StandardError
- end
- class ObsoleteScript < ::StandardError
- end
- #---------------------#
- # Mensagens de Erro #
- #---------------------#
- @@ERROR = {
- :ScriptRequired => "Script não encontrado: %s (v%s) (por %s)",
- :ObsoleteScript => "Script obsoleto: %s (v%s) (por %s). Versão requerida: %s"
- }
- #---------------------#
- # Scripts Registrados #
- #---------------------#
- @@REGISTERED = {}
- @@POST_REGISTER = {}
- module_function
- #---------------------------------------------------------------------------
- # Registra novo script se não estiver registrado. Atualiza caso já exista.
- # O retorno é a permissão para incluir o script, que só será verdadeiro se
- # o script não estiver registrado ou se a versão registrada for menor.
- # Caso algum dos requerimentos ainda não tenha sido registrado, o script
- # será guardado em cache até que todos os requirimentos sejam registrados e
- # só então ele será executado.
- #
- # [Symbol ] name : Nome do script.
- # [String ] author : Nome do autor.
- # [Numeric] version : Versão do script.
- # [Array ] requires : Requerimentos. É uma array com sub-arrays, cada uma
- # deve conter, necessariamente o símbolo do script e
- # o autor. Pode conter também a versão requerida e o
- # tipo de comparação. (Ver Gab.registered?)
- # [Proc ] block : Bloco com a definição do script.
- #
- # Exemplo:
- #
- # # Registro do script A, que depende do script B, do autor "Gab!":
- # Gab.register(:A, "Autor Qualquer", 1.0, [[:B, "Gab!"]]){
- # print Say.hello # Deveria dar erro, porque "Say" não foi definido.
- # }
- #
- # # Registro do script B:
- # Gab.register(:B, "Gab!", 1.0){
- # module Say
- # module_function
- # def hello
- # print "Hello Gab's Core World"
- # end
- # end
- # }
- #
- # # Com a definição do script B, o script A pode rodar:
- # #=> "Hello Gab's Core World"
- #
- #---------------------------------------------------------------------------
- def register(name, author, version, requires = [], &block)
- needed = []
- requires.each{|req| needed << req unless Gab.registered?(*req) }
- if needed.empty?
- @@REGISTERED[[name, author]] = version
- block.call
- @@POST_REGISTER.each_pair{|(_name, _author, _version), (need, _block)|
- need.delete_if{|req| Gab.registered?(*req) }
- if need.empty?
- @@POST_REGISTER.delete([_name, _author, _version])
- Gab.register(_name, _author, _version, &_block)
- end
- }
- else
- @@POST_REGISTER[[name, author, version]] = [needed, block]
- end
- return nil
- end
- #---------------------------------------------------------------------------
- # Verifica a existência de um script na versão desejada.
- #
- # [Symbol ] name : Nome do script
- # [String ] author : Nome do autor
- # [Numeric] version : Versão desejada. Se for nulo, qualquer uma.
- # [Symbol ] compare : Tipo de comparação. Deve ser um método da classe
- # Numeric. Por exemplo, :>= aceitará qualquer script
- # que for de versão igual ou maior à especificada.
- # :== só aceitará a versão especificada, entre outros.
- #
- # [Boolean] Retorno : Script especificado existe?
- #---------------------------------------------------------------------------
- def registered?(name, author, version = nil, compare = :>=)
- if @@REGISTERED.has_key?([name, author])
- return true if version.nil?
- script = @@REGISTERED[[name, author]]
- return script.method(compare).call(version)
- else
- return false
- end
- end
- #---------------------------------------------------------------------------
- # Define um script como requerido. Um erro será executado caso o script não
- # exista ou tenha versão não desejada, de acordo com o operador definido.
- #
- # [Symbol ] name : Nome do script
- # [String ] author : Nome do autor
- # [Numeric] version : Versão desejada. Se for nulo, qualquer uma.
- # [Symbol ] compare : Tipo de comparação. Deve ser um método da classe
- # Numeric. Por exemplo, :>= aceitará qualquer script
- # que for de versão igual ou maior à especificada.
- # :== só aceitará a versão especificada, entre outros.
- #
- # Retorno: - TrueClass se o script existir na versão especificada.
- # - Chama a classe de erro Gab::ObsoleteScript caso a versão seja
- # diferente da especificada.
- # - Chama a classe de erro Gab::ScriptRequired caso o script não
- # exista.
- #---------------------------------------------------------------------------
- def required(name, author, version=nil, versionCompare = :>=)
- if @@REGISTERED.has_key?([name, author])
- return true if version.nil?
- script = @@REGISTERED[[name, author]]
- unless script.method(versionCompare).call(version)
- raise(
- Gab::ObsoleteScript,
- @@ERROR[:ObsoleteScript] % [name, script, author, version]
- )
- else
- return true
- end
- else
- raise(
- Gab::ScriptRequired,
- @@ERROR[:ScriptRequired] % [name, version, author]
- )
- end
- end
- end
- Gab.register(:Core, "Gab!", 1.0){}
- #=============================================================================
- # ** MakerUtils
- #---------------------------------------------------------------------------
- # Utilitários para o RPG Maker
- #=============================================================================
- Gab.register(:RPGMakerUtils, "Gab!", 1.0) {
- module MakerUtils
- #---------------------#
- # Versão do RPG Maker #
- #---------------------#
- if RUBY_VERSION < "1.9"
- XP = defined?(Hangup)
- VX = !XP
- VXA = false
- VERSION = XP ? :XP : :VX
- else
- XP = false
- VX = false
- VXA = true
- VERSION = :VXA
- end
- module_function
- #-------------------------------------------------------------------------
- # Decisão entre dois valores, caso o jogo esteja sendo testado ou não
- #
- # [Mixed] v1 : Valor retornado caso o jogo esteja em testes.
- # [Mixed] v2 : Valor retornado caso o jogo não esteja em testes.
- #
- # [Mixed] Retorno : Valor de acordo com o estado de testes do jogo.
- #-------------------------------------------------------------------------
- if XP
- def test(v1, v2)
- return $DEBUG ? v1 : v2
- end
- else
- def test(v1, v2)
- return $TEST ? v1 : v2
- end
- end
- end
- }
- #=============================================================================
- # ** Array
- #=============================================================================
- Gab.register(:ArrayPlus, "Gab!", 1.0, [[:RPGMakerUtils, "Gab!"]]) {
- class Array
- unless MakerUtils::VXA
- #-----------------------------------------------------------------------
- # Rotaciona a array (remove elementos de uma extremidade e adiciona na
- # outra). Caso o argumento seja positivo, a array será rotacionada para
- # a direita. Caso seja negativo, será rotacionada para a esquerda.
- #
- # [Integer] n : Quantos elementos devem ser rotacionados?
- #
- # [Array] Retorno : Cópia rotacionada.
- #-----------------------------------------------------------------------
- def rotate(n)
- return clone.rotate!(n)
- end
- #-----------------------------------------------------------------------
- # Mesmo efeito que o método Array#rotate(n), porém rotaciona de modo
- # permantente.
- #
- # [Integer] n : Quantos elementos devem ser rotacionados?
- #
- # [Array] Retorno : Própria array rotacionada.
- #-----------------------------------------------------------------------
- def rotate!(n)
- n > 0 ? unshift(*slice!(n % size, n)) : push(*slice!(0, -n))
- return self
- end
- #-----------------------------------------------------------------------
- # Mantém na array os valores que obedecerem às condições do block que
- # for enviado.
- #
- # [Proc ] block : Bloco condicional
- #
- # [Array] Retorno : Cópia com elementos que obedecem a condição
- #
- # Exemplo:
- #
- # [1, 2, 3, 4, 5, 6, 7].keep_if{|a| a < 4} #=> [1, 2, 3]
- #-----------------------------------------------------------------------
- def keep_if(&block)
- return clone.keep_if!(&block)
- end
- #-----------------------------------------------------------------------
- # Mesmo efeito que o método Array#keep_if(&block), porém permanentemente
- #
- # [Proc ] block : Bloco condicional
- #
- # [Array] Retorno : Própria array com elementos que obedecem a condição
- #-----------------------------------------------------------------------
- def keep_if!(&block)
- return self unless block_given?
- actual = 0
- until actual == self.size
- if yield(self[actual])
- actual += 1
- else
- delete_at(actual)
- end
- end
- return self
- end
- #-----------------------------------------------------------------------
- # Retorna um elemento aleatório da array
- #
- # [Mixed] Retorno : Elemento randômico
- #-----------------------------------------------------------------------
- def sample
- return at(rand(size))
- end
- end # unless VXA
- #-------------------------------------------------------------------------
- # Alinha o conteúdo da array à direita e preenche com o objeto definido
- #
- # [Numeric] size : Tamanho final da array
- # [Mixed ] object : Objeto que será utilizado para o preenchimento
- #
- # [Array] Retorno : Própria array
- #-------------------------------------------------------------------------
- def rjust(size, object)
- unshift(object) until self.size >= size
- return self
- end
- #-------------------------------------------------------------------------
- # Alinha o conteúdo da array à esquerda e preenche com o objeto definido
- #
- # [Numeric] size : Tamanho final da array
- # [Mixed ] object : Objeto que será utilizado para o preenchimento
- #
- # [Array] Retorno : Própria array
- #-------------------------------------------------------------------------
- def ljust(size, object)
- push(object) until self.size >= size
- return self
- end
- #-------------------------------------------------------------------------
- # Remove um elemento aleatório e o retorna
- #
- # [Mixed] Retorno : Elemento aleatório da array
- #-------------------------------------------------------------------------
- def pick
- return delete_at(rand(size))
- end
- #-------------------------------------------------------------------------
- # Possibilita a entrada de blocos para o método Array#first para que haja
- # checagem.
- # Retorna o primeiro valor quando nenhum dos valores atender ao bloco.
- #
- # [Mixed] Retorno : Primeiro valor que obedece a condição, ou o primeiro
- # da array, caso nenhum obedeça.
- #
- # Exemplo:
- #
- # [1,2,3,4,5].first{|e| e > 3} #=> 4
- #-------------------------------------------------------------------------
- def first
- each{|e| return e if yield(e)} if block_given?
- return at(0)
- end
- #-------------------------------------------------------------------------
- # Variação do método each para retornar vários elementos
- #
- # [Integer] n : Número de elementos que serão separados em cada sub-array
- #
- # [Array] Retorno : Caso um bloco seja dado, o retorno é a própria array,
- # caso contrário, a array retornada é a que contem cada
- # grupo de "n" números. (Ver exemplo)
- #
- # Exemplo:
- #
- # [6, 5, 4, 3, 2, 1].each_n(2){|elements|
- # print elements
- # #=> [6, 5]
- # #=> [4, 3]
- # #=> [2, 1]
- #
- # } #=> [6, 5, 4, 3, 2, 1]
- #
- # [6, 5, 4, 3, 2, 1].each_n(4) #=> [[6, 5, 4, 3], [2, 1]]
- #-------------------------------------------------------------------------
- def each_n(n)
- i = -n
- t = (size/n.to_f).ceil
- if block_given?
- t.times{ yield(*self[i += n, n]) }
- return self
- else
- r = []
- t.times{ r.push(self[i += n, n]) }
- return r
- end
- end
- #-------------------------------------------------------------------------
- # Variação do método each que retorna o cada elemento e os 'n' próximos
- #
- # [Integer] n : Número de elementos além do que está apontando o índice
- # que serão retornados.
- #
- # [Array] Retorno : Caso um bloco seja dado, o retorno é a própria array,
- # caso contrário, a array retornada é a que contem cada
- # grupo de "n" números. (Ver exemplo)
- #
- # Exemplo:
- # [6, 5, 4, 3, 2, 1].each_with_next(2){|elements|
- # print elements
- # #=> [6, 5, 4]
- # #=> [5, 4, 3]
- # #=> [4, 3, 2]
- # #=> [3, 2, 1]
- # #=> [2, 1]
- # #=> [1]
- #
- # } #=> [6, 5, 4, 3, 2, 1]
- #
- # [6, 5, 4, 3, 2, 1].each_with_next(1) #=> [[6,5],[5,4],[4,3],[3,2],[2,1],[1]]
- #-------------------------------------------------------------------------
- def each_with_next(n)
- n += 1
- if block_given?
- each_index{|i| yield(*self[i, n]) }
- return self
- else
- r = []
- each_index{|i| r.push(self[i, n]) }
- return r
- end
- end
- end # Array
- }
- #=============================================================================
- # ** Color
- #=============================================================================
- Gab.register(:ColorPlus, "Gab!", 1.0) {
- class << Color
- #----------------#
- # Classe de Erro #
- #----------------#
- class MalformedString < ::StandardError
- end
- ERROR = {
- :MalformedString => "String em formato desconhecido: (%s)"
- }
- #----------------------#
- # Expressões regulares #
- #----------------------#
- SIMPLE_HEX = /#?([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/i
- DUAL_HEX = /#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/i
- #-------------------------------------------------------------------------
- # Permite inicialização a partir de string de hexadecimais
- #
- # [String] str : String com formato hexadecimal. Formatos:
- # #RRGGBBAA
- # RRGGBBAA
- # #RRGGBB
- # RRGGBB
- # #RGBA
- # RGBA
- # #RGB
- # RGB
- #
- # [Color] Retorno : Cor de acordo com o argumento.
- #
- # Exemplo:
- #
- # Color.hex("#FFFFFFFF") #=> Color.new(255, 255, 255, 255)
- # Color.hex("FF0000") #=> Color.new(255, 0, 0)
- # Color.hex("#FF00") #=> Color.new(255, 255, 0, 0)
- # Color.hex("FF0") #=> Color.new(255, 255, 0)
- #-------------------------------------------------------------------------
- def hex(str)
- if str.match(DUAL_HEX)
- r, g, b, a = [$1, $2, $3, $4 || "FF"].map{|c|
- n = c.to_i(16)
- }
- elsif str.match(SIMPLE_HEX)
- r, g, b, a = [$1, $2, $3, $4 || "F"].map{|c|
- n = c.to_i(16)
- (n | (n << 4))
- }
- else
- raise(MalformedString, ERROR[:MalformedString] % [str])
- end
- return Color.new(r, g, b, a)
- end
- #-------------------------------------------------------------------------
- # Permite inicialização através do método CMYK[A]
- #
- # [Numeric] c : Ciano
- # [Numeric] m : Magenta
- # [Numeric] y : Amarelo
- # [Numeric] k : Preto
- # [Numeric] a : Opacidade
- #
- # [Color] Retorno : Cor convertida
- #-------------------------------------------------------------------------
- def cmyk(c, m, y, k, a = 255)
- cyan = [255, c + k].min
- magenta = [255, m + k].min
- yellow = [255, y + k].min
- r = 255 - cyan
- g = 255 - magenta
- b = 255 - yellow
- return Color.new(r, g, b, a)
- end
- #-------------------------------------------------------------------------
- # Permite inicialização através do método HSV[A]
- #
- # [Numeric] h : Matiz [0 - 360]
- # [Numeric] s : Saturação [0 - 1]
- # [Numeric] v : Valor [0 - 1]
- # [Numeric] a : Opacidade [0 - 255]
- #
- # [Color] Retorno : Cor convertida
- #-------------------------------------------------------------------------
- def hsv(h, s, v, a = 255)
- if s.zero?
- r = g = b = v
- else
- h /= 60.0
- i = h.floor
- f = h - i
- p = v * (1 - s)
- q = v * (1 - s * f)
- t = v * (1 - s * (1 - f))
- case i
- when 0; r, g, b = v, t, p
- when 1; r, g, b = q, v, p
- when 2; r, g, b = p, v, t
- when 3; r, g, b = p, q, v
- when 4; r, g, b = t, p, v
- else; r, g, b = v, p, q
- end
- end
- return Color.new(255 * r, 255 * g, 255 * b, a)
- end
- #-------------------------------------------------------------------------
- # Permite inicialização através do método Cris
- # Modestos agradecimentos pelo algoritmo: Cristiano "cristianoforce" Modesto
- #
- # [Color] Retorno : Cor única do modelo Cris de cores
- #-------------------------------------------------------------------------
- def cris
- return Color.new(0, 0, 0, 255)
- end
- #-------------------------------------------------------------------------
- # Inicialização de cores através do nome.
- # Color.white, Color.black, ...
- #
- # Todos os métodos definidos têm apenas um argumento.
- #
- # [Numeric] alpha : Opacidade
- #
- # [Color] Retorno : Cor referente ao nome.
- #-------------------------------------------------------------------------
- {
- :white => [0xFF, 0xFF, 0xFF], :black => [0x00, 0x00, 0x00],
- :red => [0xFF, 0x00, 0x00], :magenta => [0xFF, 0x00, 0xFF],
- :blue => [0x00, 0x00, 0x00], :cyan => [0x00, 0xFF, 0xFF],
- :marron => [0x80, 0x00, 0x00], :darkred => [0x8B, 0x00, 0x00],
- :lightpink => [0xFF, 0xB6, 0xC1], :crimson => [0xDC, 0x14, 0x3C],
- :paleviletred => [0xFF, 0x69, 0xB4], :hotpink => [0xFF, 0x69, 0xB4],
- :deeppink => [0xFF, 0x14, 0x93], :mediumvioletred => [0xC7, 0x15, 0x85],
- :purple => [0x80, 0x00, 0x80], :darkmagenta => [0x8B, 0x00, 0x8B],
- :orchid => [0xDA, 0x70, 0xD6], :thistle => [0xD8, 0xBF, 0xD8],
- :plum => [0xDD, 0xA0, 0xDD], :violet => [0xEE, 0x82, 0xEE],
- :fuchsia => [0xFF, 0x00, 0xFF], :mediumorchid => [0xBA, 0x55, 0xD3],
- :darkviolet => [0x94, 0x00, 0xD3], :darkorchid => [0x99, 0x32, 0xCC],
- :blueviolet => [0x8A, 0x2B, 0xE2], :indigo => [0x4B, 0x00, 0x82],
- :mediumpurple => [0x93, 0x70, 0xDB], :slateblue => [0x6A, 0x5A, 0xCD],
- :mediumslateblue => [0x7B, 0x68, 0xEE], :darkblue => [0x00, 0x00, 0x8B],
- :mediumblue => [0x00, 0x00, 0xCD], :blue => [0x00, 0x00, 0xFF],
- :navy => [0x00, 0x00, 0x80], :midnightblue => [0x19, 0x19, 0x70],
- :darkslateblue => [0x48, 0x3D, 0x8B], :royalblue => [0x41, 0x69, 0xE1],
- :cornflowerblue => [0x64, 0x95, 0xED], :lightsteelblue => [0xB0, 0xC4, 0xDE],
- :aliceblue => [0xF0, 0xF8, 0xFF], :ghostwhite => [0xF8, 0xF8, 0xFF],
- :lavender => [0xE6, 0xE6, 0xFA], :dodgerblue => [0x1E, 0x90, 0xFF],
- :steelblue => [0x46, 0x82, 0xB4], :deepskyblue => [0x00, 0xBF, 0xFF],
- :slategray => [0x70, 0x80, 0x90], :lightslategray => [0x77, 0x88, 0x99],
- :lightskyblue => [0x87, 0xCE, 0xFA], :skyblue => [0x87, 0xCE, 0xEB],
- :lightblue => [0xAD, 0xD8, 0xE6], :teal => [0x00, 0x80, 0x80],
- :darkcyan => [0x00, 0x8B, 0x8B], :darkturquoise => [0x00, 0xCE, 0xD1],
- :aqua => [0x00, 0xFF, 0xFF], :mediumturquoise => [0x48, 0xD1, 0xCC],
- :cadetblue => [0x5F, 0x9E, 0xA0], :paleturquoise => [0xAF, 0xEE, 0xEE],
- :lightcyan => [0xE0, 0xFF, 0xFF], :azure => [0xF0, 0xFF, 0xFF],
- :lightseagreen => [0x20, 0xB2, 0xAA], :turquoise => [0x40, 0xE0, 0xD0],
- :powderblue => [0xB0, 0xE0, 0xE6], :darkslategray => [0x2F, 0x4F, 0x4F],
- :aquamarine => [0x7F, 0xFF, 0xD4], :mediumspringgreen => [0x00, 0xFA, 0x9A],
- :mediumaquamarine => [0x66, 0xCD, 0xAA], :springgreen => [0x00, 0xFF, 0x7F],
- :mediumseagreen => [0x3C, 0xB3, 0x71], :seagreen => [0x2E, 0x8B, 0x57],
- :limegreen => [0x32, 0xCD, 0x32], :darkgreen => [0x00, 0x64, 0x00],
- :green => [0x00, 0x80, 0x00], :lime => [0x00, 0xFF, 0x00],
- :forestgreen => [0x22, 0x8B, 0x22], :darkseagreen => [0x8F, 0xBC, 0x8F],
- :lightgreen => [0x90, 0xEE, 0x90], :palegreen => [0x98, 0xFB, 0x98],
- :mintcream => [0xF5, 0xFF, 0xFA], :honeydew => [0xF0, 0xFF, 0xF0],
- :chartreuse => [0x7F, 0xFF, 0x00], :lawngreen => [0x7C, 0xFC, 0x00],
- :olivedrab => [0x6B, 0x8E, 0x23], :darkolivegreen => [0x55, 0x6B, 0x2F],
- :yellowgreen => [0x9A, 0xCD, 0x32], :greenyellow => [0xAD, 0xFF, 0x2F],
- :beige => [0xF5, 0xF5, 0xDC], :linen => [0xFA, 0xF0, 0xE6],
- :lightgoldenrodyellow => [0xFA, 0xFA, 0xD2], :olive => [0x80, 0x80, 0x00],
- :yellow => [0xFF, 0xFF, 0x00], :lightyellow => [0xFF, 0xFF, 0xE0],
- :ivory => [0xFF, 0xFF, 0xF0], :darkkhaki => [0xBD, 0xB7, 0x6B],
- :khaki => [0xF0, 0xE6, 0x8C], :palegoldenrod => [0xEE, 0xE8, 0xAA],
- :wheat => [0xF5, 0xDE, 0xB3], :gold => [0xFF, 0xD7, 0x00],
- :lemonchiffon => [0xFF, 0xFA, 0xCD], :papayawhip => [0xFF, 0xEF, 0xD5],
- :darkgoldenrod => [0xB8, 0x86, 0x0B], :goldenrod => [0xDA, 0xA5, 0x20],
- :antiquewhite => [0xFA, 0xEB, 0xD7], :cornsilk => [0xFF, 0xF8, 0xDC],
- :oldlace => [0xFD, 0xF5, 0xE6], :moccasin => [0xFF, 0xE4, 0xB5],
- :navajowhite => [0xFF, 0xDE, 0xAD], :orange => [0xFF, 0xA5, 0x00],
- :bisque => [0xFF, 0xE4, 0xC4], :tan => [0xD2, 0xB4, 0x8C],
- :darkorange => [0xFF, 0x8C, 0x00], :burlywood => [0xDE, 0xB8, 0x87],
- :saddlebrown => [0x8B, 0x45, 0x13], :sandybrown => [0xF4, 0xA4, 0x60],
- :blanchedalmond => [0xFF, 0xEB, 0xCD], :lavenderblush => [0xFF, 0xF0, 0xF5],
- :seashell => [0xFF, 0xF5, 0xEE], :floralwhite => [0xFF, 0xFA, 0xF0],
- :snow => [0xFF, 0xFA, 0xFA], :peru => [0xCD, 0x85, 0x3F],
- :peachpuff => [0xFF, 0xDA, 0xB9], :chocolate => [0xD2, 0x69, 0x1E],
- :sienna => [0xA0, 0x52, 0x2D], :lightsalmon => [0xFF, 0xA0, 0x7A],
- :coral => [0xFF, 0x7F, 0x50], :darksalmon => [0xE9, 0x96, 0x7A],
- :mistyrose => [0xFF, 0xE4, 0xE1], :orangered => [0xFF, 0x45, 0x00],
- :salmon => [0xFA, 0x80, 0x72], :tomato => [0xFF, 0x63, 0x47],
- :rosybrown => [0xBC, 0x8F, 0x8F], :pink => [0xFF, 0xC0, 0xCB],
- :indianred => [0xCD, 0x5C, 0x5C], :lightcoral => [0xF0, 0x80, 0x80],
- :brown => [0xA5, 0x2A, 0x2A], :firebrick => [0xB2, 0x22, 0x22],
- :dimgray => [0x69, 0x69, 0x69], :gray => [0x80, 0x80, 0x80],
- :darkgray => [0xA9, 0xA9, 0xA9], :silver => [0xC0, 0xC0, 0xC0],
- :lightgrey => [0xD3, 0xD3, 0xD3], :gainsboro => [0xDC, 0xDC, 0xDC],
- :whitesmoke => [0xF5, 0xF5, 0xF5],
- }.each_pair{|name, channels|
- define_method(name){|alpha|
- return Color.new(channels[0], channels[1], channels[2], alpha || 255)
- }
- }
- end # class << Color
- class Color
- #--------------------------------------------------------------------------
- # Suavidade da cor
- #
- # [Numeric] Retorno : Suavidade da cor
- #--------------------------------------------------------------------------
- def lightness
- data = [red, green, blue]
- return (data.max + data.min) / 2.0
- end
- #--------------------------------------------------------------------------
- # Média entre os canais
- #
- # [Numeric] Retorno : Média entre os canais. Ou também luminosidade da cor
- # quando removida toda sua saturação.
- #--------------------------------------------------------------------------
- def average
- return (red + green + blue) / 3.0
- end
- #--------------------------------------------------------------------------
- # Luminosidade
- #
- # [Numeric] Retorno : Luminosidade da cor
- #--------------------------------------------------------------------------
- def luminosity
- return 0.21 * red + 0.71 * green + 0.07 * blue
- end
- #--------------------------------------------------------------------------
- # Inverte a cor
- #
- # [Color] Retorno : Cópia invertida
- #--------------------------------------------------------------------------
- def reverse
- return dup.reverse!
- end
- alias inverse reverse
- alias -@ reverse
- #--------------------------------------------------------------------------
- # Inverte definitivamente (e.g.: Branco fica preto)
- #
- # [Color] Retorno : A própria cor, porém invertida
- #--------------------------------------------------------------------------
- def reverse!
- set(255 - red, 255 - green, 255 - blue, alpha)
- return self
- end
- alias inverse! reverse!
- #--------------------------------------------------------------------------
- # Operações com cores: Soma
- #
- # [Array|Color] value : Valor com que a cor será somada. No caso de uma
- # array, ela pode estar no formato [R, G, B] ou
- # [R, G, B, A]
- #
- # [Color] Retorno : Nova cor
- #--------------------------------------------------------------------------
- def +(value)
- if value.is_a?(Array)
- if value.size.between?(3,4)
- r = self.red + value[0]
- g = self.green + value[1]
- b = self.blue + value[2]
- a = self.alpha + (value.size == 4 ? value[3] : 0)
- return Color.new(r, g, b, a)
- end
- elsif value.is_a?(Color)
- r = self.red + value.red
- g = self.green + value.green
- b = self.blue + value.blue
- a = self.alpha + value.alpha
- return Color.new(r, g, b, a)
- end
- raise(ArgumentError)
- end
- #--------------------------------------------------------------------------
- # Operações com cores: Subtração
- #
- # [Array|Color] value : Valor que será subtraído da cor. No caso de uma
- # array, ela pode estar no formato [R, G, B] ou
- # [R, G, B, A]
- #
- # [Color] Retorno : Nova cor
- #--------------------------------------------------------------------------
- def -(value)
- if value.is_a?(Array)
- if value.size.between?(3,4)
- r = self.red - value[0]
- g = self.green - value[1]
- b = self.blue - value[2]
- a = self.alpha - (value.size == 4 ? value[3] : 0)
- return Color.new(r, g, b, a)
- end
- elsif value.is_a?(Color)
- r = self.red - value.red
- g = self.green - value.green
- b = self.blue - value.blue
- a = self.alpha - value.alpha
- return Color.new(r, g, b, a)
- end
- raise(ArgumentError)
- end
- #--------------------------------------------------------------------------
- # Operações com cores: Multiplicação
- #
- # [Array|Color] value : Valor com que a cor será multiplicada. No caso de
- # uma array, ela pode estar no formato [R, G, B] ou
- # [R, G, B, A]
- #
- # [Color] Retorno : Nova cor
- #--------------------------------------------------------------------------
- def *(value)
- if value.is_a?(Array)
- if value.size.between?(3,4)
- r = (self.red * value[0]) / 255.0
- g = (self.green * value[1]) / 255.0
- b = (self.blue * value[2]) / 255.0
- a = (self.alpha * (value.size == 4 ? value[3] : 0)) / 255.0
- return Color.new(r, g, b, a)
- end
- elsif value.is_a?(Color)
- r = (self.red * value.red ) / 255.0
- g = (self.green * value.green) / 255.0
- b = (self.blue * value.blue ) / 255.0
- a = (self.alpha * value.alpha) / 255.0
- return Color.new(r, g, b, a)
- end
- raise(ArgumentError)
- end
- #--------------------------------------------------------------------------
- # Operações com cores: Divisão
- #
- # [Array|Color] value : Valor pelo qual a cor será dividida. No caso de uma
- # array, ela pode estar no formato [R, G, B] ou
- # [R, G, B, A]
- #
- # [Color] Retorno : Nova cor
- #--------------------------------------------------------------------------
- def /(value)
- if value.is_a?(Array)
- if value.size.between?(3,4)
- r = value[0].zero? ? 0 : 255.0 / value[0]
- g = value[1].zero? ? 0 : 255.0 / value[1]
- b = value[2].zero? ? 0 : 255.0 / value[2]
- a = value.size == 4 && value[3].zero? ? 0 : 255.0 / value[3]
- return Color.new(r, g, b, a)
- end
- elsif value.is_a?(Color)
- r = value.red.zero? ? 0 : 255.0 / value.red
- g = value.green.zero? ? 0 : 255.0 / value.green
- b = value.blue.zero? ? 0 : 255.0 / value.blue
- a = value.alpha.zero? ? 0 : 255.0 / value.alpha
- return Color.new(r, g, b, a)
- end
- raise(ArgumentError)
- end
- #--------------------------------------------------------------------------
- # Executa blendagem a partir do canal alpha
- #
- # [Color] color : Cor que será mesclada com a instância
- #
- # [Color] Retorno : Cor mesclada
- #--------------------------------------------------------------------------
- def blend(color)
- return color if self.alpha == 0 or color.alpha == 255
- return self if color.alpha == 0
- srcA = color.alpha / 255.0
- #cplA = (1 - srcA)
- # O = (x * A) + (y * B)
- # B = (1 - A)
- # O = Ax + y - Ay
- # O = A(x - y) + y
- #outR = (color.red * srcA) + (self.red * cplA)
- #outG = (color.green * srcA) + (self.green * cplA)
- #outB = (color.blue * srcA) + (self.blue * cplA)
- #outA = (color.alpha * srcA) + (self.alpha * cplA)
- outR = srcA * (color.red - self.red ) + self.red
- outG = srcA * (color.green - self.green) + self.green
- outB = srcA * (color.blue - self.blue ) + self.blue
- outA = srcA * (color.alpha - self.alpha) + self.alpha
- return Color.new(outR, outG, outB, outA)
- end
- #--------------------------------------------------------------------------
- # Conversão implícita para array
- # Permite isso: r, g, b, a = Color.new(255, 0, 0, 127)
- #
- # [Array] Retorno : Canais da cor em uma array
- #--------------------------------------------------------------------------
- def to_ary
- return [red, green, blue, alpha]
- end
- #--------------------------------------------------------------------------
- # Conversão para hash
- #
- # [Boolean] complete : Utilizar chaves com nome completo do canal? (red,
- # green, blue, alpha). Caso seja falso, as chaves
- # serão apenas a letra inicial de cada canal.
- #
- # [Array] Retorno : Canais da cor em uma hash
- #--------------------------------------------------------------------------
- def to_hash(complete = true)
- if complete
- return {
- :red => self.red,
- :green => self.green,
- :blue => self.blue,
- :alpha => self.alpha
- }
- else
- return {
- :r => self.red,
- :g => self.green,
- :b => self.blue,
- :a => self.alpha
- }
- end
- end
- end
- }
- #=============================================================================
- # ** Number (Numeric, Float, Integer)
- #=============================================================================
- Gab.register(:NumberPlus, "Gab!", 1.0, [[:RPGMakerUtils, "Gab!"]]) {
- class Numeric
- #-------------------------------------------------------------------------
- # Delimita o inteiro.
- #
- # [Numeric] min : Valor mínimo
- # [Numeric] max : Valor máximo
- #
- # [Numeric] Retorno : Se a instância for menor que 'min', retorna 'min'.
- # Se a instância for maior que 'max', retorna 'max'.
- #-------------------------------------------------------------------------
- def clamp(min, max)
- min, max = max, min if min > max
- return self < min ? min : self > max ? max : self
- end
- end
- class Integer
- unless MakerUtils::VXA
- #-----------------------------------------------------------------------
- # Número par?
- #
- # [Boolean] Retorno : Verifica se o número é par
- #-----------------------------------------------------------------------
- def even?
- return (self & 1) == 0
- end
- #-----------------------------------------------------------------------
- # Número ímpar?
- #
- # [Boolean] Retorno : Verifica se o número é ímpar
- #-----------------------------------------------------------------------
- def odd?
- return (self & 1) == 1
- end
- end
- end
- class Float
- #-------------------------------------------------------------------------
- # Parte fracionária de um ponto flutuante
- #
- # [Float] Retorno : Parte fracionário da instância.
- #
- # Exemplo:
- #
- # 1.25.fpart #=> 0.25
- # 4.98.fpart #=> 0.98
- #-------------------------------------------------------------------------
- def fpart
- return self - to_i
- end
- #-------------------------------------------------------------------------
- # Parte complementar fracionária
- #
- # [Float] Retorno : Parte complementar (1 - x) da parte fracionária.
- #
- # Exemplo:
- #
- # 1.25.rfpart #=> 0.75
- # 4.98.rfpart #=> 0.02
- #-------------------------------------------------------------------------
- def rfpart
- return 1 - self + to_i
- end
- end
- }
- #=============================================================================
- # ** Module
- #=============================================================================
- Gab.register(:ModulePlus, "Gab!", 1.0, [[:ArrayPlus, "Gab!"]]) {
- class Module
- #-----------------------------------------------------------------------
- # Atributo de leitura com retorno padrão caso a variável ainda não
- # esteja definida.
- #
- # [Lista: Symbol, Mixed] args : Lista com o padrão :nome, 'objeto padrão'
- #
- # Exemplos:
- #
- # class Pessoa
- # attr_def_reader :nome, 'João'
- # end
- #
- # Pessoa.new.nome #=> 'João'
- #
- # class Espada
- # def initialize(material)
- # p "Iniciando espada de #{material}"
- # end
- # end
- #
- # class Ninja < Pessoa
- # attr_def_reader :espada, 'Espada.new("madeira")', :arma, '"Espada"'
- # end
- #
- # Ninja.new.espada #=> "Iniciando espada de madeira"
- # #=> Retorna instância da espada iniciada
- # Ninja.new.roupa #=> "Espada"
- #-----------------------------------------------------------------------
- def attr_def_reader(*args)
- args.each_n(2){|name, default|
- module_eval("
- def #{name}
- @#{name} = #{default} unless defined?(@#{name})
- return @#{name}
- end
- ")
- }
- return nil
- end
- #-----------------------------------------------------------------------
- # Atributo de leitura com retorno padrão caso a variável ainda não
- # esteja definida. E atributo de escrita comum.
- #
- # [Lista: Symbol, Mixed] args : Lista com o padrão :nome, 'objeto padrão'
- #-----------------------------------------------------------------------
- def attr_def_accessor(*args)
- args.each_n(2){|name, *| attr_writer(name) }
- attr_def_reader(*args)
- return nil
- end
- #-----------------------------------------------------------------------
- # Define o método especificado caso não exista
- #
- # [String|Symbol] name : Nome do método
- # [Lista: Mixed ] args : Parâmetros para o método define_method, se
- # necessários.
- # [Proc ] block : Definição do método.
- #
- # [Boolean] Retorno : Verdadeiro se o método foi definido, falso caso
- # contrário.
- #-----------------------------------------------------------------------
- def define_unexistent_method(name, *args, &block)
- unless method_defined?(name)
- define_method(name, *args, &block)
- return true
- else
- return false
- end
- end
- end
- }
- #=============================================================================
- # ** Kernel
- #=============================================================================
- Gab.register(:KernelPlus, "Gab!", 1.0){
- module Kernel
- module_function
- #-----------------------------------------------------------------------
- # Verifica quantidade de argumentos
- #
- # [Array ] args : Array com os argumentos
- # [Integer] expect : Número de argumentos esperados
- #
- # Retorno : TrueClass se a quantidade de argumentos está correta. Caso
- # contrário, chama o erro ArgumentError.
- #-----------------------------------------------------------------------
- def assert_args_count(args, expect)
- return true if args.size == expect
- raise(ArgumentError, "wrong number of arguments (#{args.size} for #{expect})")
- end
- #-----------------------------------------------------------------------
- # Verifica o tipo do objeto
- #
- # [Mixed ] obj : Objeto que será verificado o tipo
- # [Class|Array] klass : Quando do tipo Class, verifica se o objeto é da
- # classe klass. Quando do tipo Array, verifica se
- # o objeto é de uma das classes (Class) que estão
- # na array.
- # [Boolean ] _raise : Se verdadeiro, o método chamará um erro quando
- # o objeto não for da classe esperada. Se for
- # falso, o retorno será também FalseClass.
- #
- # Retorno : TrueClass se o o objeto pertencer à classe esperada. Caso
- # contrário, chama o erro ArgumentError.
- #-----------------------------------------------------------------------
- def assert_type(obj, klass, _raise = true)
- if klass.is_a?(Array)
- return true if klass.any?{|k| obj.kind_of?(k)}
- else
- return true if obj.kind_of?(klass)
- end
- return false unless _raise
- raise(TypeError, "expected kind of #{klass} but recieved #{obj.class}")
- end
- end
- }
- #=============================================================================
- # ** PositionHelper
- #---------------------------------------------------------------------------
- # Auxiliar de posicionamento. Permite que a posição de um objeto seja definida
- # de acordo com um "container imaginário cujo tamanho é especificado ao incluir
- # o PositionHelper na classe.
- # O objeto deve ter, necessariamente, os atributos x, y, width e height.
- # Os método adicionados são os seguintes, sendo que os nomes são
- # auto-explicativos:
- #
- # Posicionamento X | Posicionamento Y | Posicionamento X,Y
- # posCenterX | posCenterY | posLeftTop
- # posLeft | posTop | posLeftCenter
- # posRight | posBottom | posLeftBottom
- # | | posCemterTop
- # | | posCenterCenter
- # | | posCenter
- # | | posCenterBottom
- # | | posRightTop
- # | | posRightCenter
- # | | posRightBottom
- # |
- #
- # Exemplo:
- #
- # class Janela
- # # Define os atributos necessários
- # attr_accessor :x, :y, :width, :height
- #
- # # Coloca a instância dentro do container de 100x100 com offset de 10, 20
- # include PositionHelper[100, 100, 10, 20]
- # end
- #
- # j = Janela.new # Cria instância
- # j.x = 0 # Posiciona em x = 0
- # j.y = 0 # Posiciona em y = 0
- # j.width = 50 # Define largura
- # j.height = 50 # Define altura
- #
- # # Centraliza no container e verifica posicionamento
- # j.posCenter
- # print j.x, j.y #=> 35 (25 + 10), 45 (25 + 20)
- #
- # # Coloca no canto inferior direito e verifica posicionamento
- # j.posRightBottom
- # print j.x, j.y #=> 60 (50 + 10), 70 (50 + 20)
- #
- #=============================================================================
- Gab.register(:PositionHelper, "Gab!", 1.0) {
- module PositionHelper
- module_function
- #-----------------------------------------------------------------------
- # Cria o módulo para a largura e a altura especificadas.
- #
- # [Numeric] width : Largura
- # [Numeric] height : Altura
- # [Numeric] offsetX : Valor fixo somado à posição X
- # [Numeric] offsetY : Valor fixo somado à posição Y
- #
- # [Module] Retorno : Módulo para posicionamento
- #-----------------------------------------------------------------------
- def [](width, height, offsetX = 0, offsetY = 0)
- positionHelper = Module.new {
- #-------------------------------------------------------------------
- # Centraliza em X
- #-------------------------------------------------------------------
- def posCenterX
- self.x = self.class::POSITION_HELPER_RECT.x +
- ((self.class::POSITION_HELPER_RECT.width - self.width) / 2)
- end
- #-------------------------------------------------------------------
- # Centraliza em Y
- #-------------------------------------------------------------------
- def posCenterY
- self.y = self.class::POSITION_HELPER_RECT.y +
- ((self.class::POSITION_HELPER_RECT.height - self.height) / 2)
- end
- #-------------------------------------------------------------------
- # Posiciona a esquerda
- #-------------------------------------------------------------------
- def posLeft
- self.x = self.class::POSITION_HELPER_RECT.x
- end
- #-------------------------------------------------------------------
- # Posiciona a direita
- #-------------------------------------------------------------------
- def posRight
- self.x = self.class::POSITION_HELPER_RECT.x +
- (self.class::POSITION_HELPER_RECT.width - self.width)
- end
- #-------------------------------------------------------------------
- # Posiciona na parte superior
- #-------------------------------------------------------------------
- def posTop
- self.y = self.class::POSITION_HELPER_RECT.y
- end
- #-------------------------------------------------------------------
- # Posiciona na parte inferior
- #-------------------------------------------------------------------
- def posBottom
- self.y = self.class::POSITION_HELPER_RECT.y +
- (self.class::POSITION_HELPER_RECT.height - self.height)
- end
- {
- :posLeftTop => [:posTop, :posLeft],
- :posCenterTop => [:posTop, :posCenterX],
- :posRightTop => [:posTop, :posRight],
- :posLeftCenter => [:posCenterY, :posLeft],
- :posCenterCenter => [:posCenterY, :posCenterX],
- :posCenter => [:posCenterY, :posCenterX],
- :posRightCenter => [:posCenterY, :posRight],
- :posLeftBottom => [:posBottom, :posLeft],
- :posCenterBottom => [:posBottom, :posCenterX],
- :posRightBottom => [:posBottom, :posRight]
- }.each_pair{|meth, calls|
- module_eval("
- define_method(meth){
- #{calls[0]}
- #{calls[1]}
- }")
- }
- }
- positionHelper.const_set(:POSITION_HELPER_RECT, Rect.new(offsetX, offsetY, width, heigth))
- return positionHelper
- end
- end
- }
- #=============================================================================
- # ** Dir
- #=============================================================================
- Gab.register(:DirPlus, "Gab!", 1.0) {
- class << Dir
- #-----------------------------------------------------------------------
- # Mapeia o diretório em uma array que contem entradas para arquivos e
- # e sub-diretórios. O valor de cada índice é uma hase com as chaves
- # :type (:file ou :folder), :name, :path e, no caso de pastas, :entries
- # que é uma array com o mapeamento desta.
- #
- # [String] path : Caminho para a pasta
- #
- # [Array] Retorno : Diretório mapeado
- #-----------------------------------------------------------------------
- def map(path)
- result = []
- (Dir.entries(path) - ['.', '..']).each{|filename|
- entry = File.join(path, filename)
- entryData = {
- :name => filename,
- :path => entry,
- }
- if File.directory?(entry)
- entryData[:type] = :folder
- entryData[:entries] = Dir.map(entry)
- else
- entryData[:type] = :file
- end
- result.push(entryData)
- }
- return result
- end
- #-----------------------------------------------------------------------
- # Mapeia o diretório porém só inclui arquivos e pastas que atendam à
- # expressão regular determinada.
- #
- # [String] path : Caminho para a pasta
- # [Regexp] pattern : Expressão regular que determina nomes esperados
- #
- # [Array] Retorno : Diretório mapeado
- #-----------------------------------------------------------------------
- def map_scan(path, pattern)
- result = []
- (Dir.entries(path) - ['.', '..']).each{|filename|
- entry = File.join(path, filename)
- entryData = {
- :name => filename,
- :path => entry,
- }
- if File.directory?(entry)
- entryData[:type] = :folder
- tmpEntries = Dir.map_scan(entry, pattern)
- if tmpEntries.empty? and !filename.match(pattern)
- next
- else
- entryData[:entries] = tmpEntries
- end
- else
- next unless filename.match(pattern)
- entryData[:type] = :file
- end
- result.push(entryData)
- }
- return result
- end
- end
- }
- #=============================================================================
- # ** Rect
- #=============================================================================
- Gab.register(:RectPlus, "Gab!", 1.0){
- class Rect
- #-----------------------------------------------------------------------
- # Retorna interseção com o argumento, que deve ser também do tipo Rect
- #
- # [Rect] rect : Rect que deverá ser interceptada com a instância atual
- #
- # [Rect] Retorno : Rect interceptada.
- #-----------------------------------------------------------------------
- def intercept(rect)
- x = [self.x, rect.x].max
- y = [self.y, rect.y].max
- w = [self.x + self.width, rect.x + rect.width ].min - x
- h = [self.y + self.height, rect.y + rect.height].min - y
- return Rect.new(x, y, w, h)
- end
- alias & intercept
- #-----------------------------------------------------------------------
- # Rect que engloba tanto self quanto a rect de argumento
- #
- # [Rect] rect : Rect que deverá ser considerada junto com a instância
- # atual para gerar a rect que cobre ambas
- #
- # [Rect] Retorno : Rect que cobre ambas as rects (argumento e instância)
- #-----------------------------------------------------------------------
- def cover(rect)
- x = [self.x, rect.x].min
- y = [self.y, rect.y].min
- w = [self.x + self.width, rect.x + rect.width ].max - x
- h = [self.y + self.height, rect.y + rect.height].max - y
- return Rect.new(x, y, w, h)
- end
- alias | cover
- #-----------------------------------------------------------------------
- # Posição do lado esquerdo
- #
- # [Numeric] Retorno : Posição X do lado esquerdo
- #-----------------------------------------------------------------------
- def left
- return self.x
- end
- #-----------------------------------------------------------------------
- # Posição do lado direito
- #
- # [Numeric] Retorno : Posição X do lado direito
- #-----------------------------------------------------------------------
- def right
- return self.x + self.width
- end
- #-----------------------------------------------------------------------
- # Posição do topo
- #
- # [Numeric] Retorno : Posição Y do topo
- #-----------------------------------------------------------------------
- def top
- return self.y
- end
- #-----------------------------------------------------------------------
- # Posição da borda inferior
- #
- # [Numeric] Retorno : Posição Y da parte de baixo
- #-----------------------------------------------------------------------
- def bottom
- return self.y + self.height
- end
- #-----------------------------------------------------------------------
- # Conversão implícita/explícita para array
- #
- # [Array] Retorno : Array com as características da rect
- #-----------------------------------------------------------------------
- def to_ary
- return [x, y, width, height]
- end
- #-----------------------------------------------------------------------
- # Itera em cada posição (x,y) da rect com o espaço determinado. Permite
- # que, dado um bloco, todas as posições x,y sejam consideradas.
- #
- # [Numeric] xstep : Diferença de cada posição x
- # [Numeric] ystep : Diferença de cada posição y
- #
- # Exemplo:
- #
- # r = Rect.new(0, 0, 1, 1)
- #
- # r.iterate(0.5, 0.5){|x, y|
- # p [x, y] #=> [0.0, 0.0]
- # #=> [0.0, 0.5]
- # #=> [0.0, 1.0]
- # #=> [0.5, 0.0]
- # #=> [0.5, 0.5]
- # #=> [0.5, 1.0]
- # #=> [1.0, 0.0]
- # #=> [1.0, 0.5]
- # #=> [1.0, 1.0]
- # }
- #-----------------------------------------------------------------------
- def iterate(xstep = 1, ystep = xstep)
- ((self.x)..(self.x + self.width)).step(xstep){|ax|
- ((self.y)..(self.y + self.height)).step(ystep){|ay|
- yield(ax, ay)
- }
- }
- return nil
- end
- end
- }
- #=============================================================================
- # ** Bitmap
- #=============================================================================
- Gab.register(:BitmapPlus, "Gab!", 1.0, [[:ColorPlus, "Gab!"], [:RectPlus, "Gab!"], [:NumberPlus, "Gab!"]]){
- class Bitmap
- #-----------------------------------------------------------------------
- # Inverte um segmento do bitmap (efeito negativo)
- #
- # [Rect] rect : Rect que compreende a área que será invertida.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def inverse_rect(*args)
- case args.size
- when 1
- rect = *args
- when 4
- rect = Rect.new(*args)
- else
- assert_args_count(args, 1)
- end
- self.rect.intercept(rect).iterate{|x, y|
- set_pixel(x, y, get_pixel(x, y).inverse)
- }
- return self
- end
- #-----------------------------------------------------------------------
- # Inverte o bitmap (efeito negativo)
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def inverse
- return inverse_rect(self.rect)
- end
- #-----------------------------------------------------------------------
- # Aumenta o brilho de um segmento
- #
- # [Rect ] rect : Rect que compreende a área que terá o brilho
- # aumentado.
- # Caso sejam dados quatro argumentos eles serão
- # utilizados como argumento para Rect.new.
- # [Numeric] amount : Quantidade de brilho que será aumentada
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def brighten_rect(*args)
- case args.size
- when 2
- rect, amount = *args
- when 5
- amount, rect = args.pop, Rect.new(*args)
- else
- assert_args_count(args, 2)
- end
- self.rect.intercept(rect).iterate{|x, y|
- px = get_pixel(x, y)
- px.red += amount
- px.green += amount
- px.blue += amount
- set_pixel(x, y, px)
- }
- return self
- end
- #-----------------------------------------------------------------------
- # Aumenta o brilho do bitmap
- #
- # [Numeric] amount : Quantidade de brilho que será aumentada
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def brighten(amount)
- return brighten_rect(self.rect, amount)
- end
- #-----------------------------------------------------------------------
- # Coloca um segmento em escala de cinza
- #
- # [Rect] rect : Rect que compreende a área que ficará em escala de cinza.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def grayscale_rect(*args)
- case args.size
- when 1
- rect = *args
- when 4
- rect = Rect.new(*args)
- else
- assert_args_count(args, size)
- end
- self.rect.intercept(rect).iterate{|x, y|
- px = get_pixel(x, y)
- m = (px.red + px.green + px.blue) / 3
- c = Color.new(m, m, m, px.alpha)
- set_pixel(x, y, c)
- }
- return self
- end
- #-----------------------------------------------------------------------
- # Coloca o bitmap em escala de cinza
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def grayscale
- return grayscale_rect(self.rect)
- end
- #-----------------------------------------------------------------------
- # Pixeliza um segmento do bitmap
- #
- # [Rect ] rect : Rect que compreende a área que será pixelizada.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- # [Integer] size : Tamanho da pixelização.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def pixelate_rect(*args)
- case args.size
- when 2
- rect, size = *args
- when 5
- size, rect = args.pop, Rect.new(*args)
- else
- assert_args_count(args, 2)
- end
- sqSize = size ** 2
- self.rect.intercept(rect).iterate(size){|x, y|
- c = [0, 0, 0, 0]
- size.times{|ax| size.times{|ay|
- px = get_pixel(x + ax, y + ay)
- c[0] += px.red
- c[1] += px.green
- c[2] += px.blue
- c[3] += px.alpha
- }}
- color = Color.new(*c.map{|i| i / sqSize })
- fill_rect(x, y, size, size, color)
- }
- return self
- end
- #-----------------------------------------------------------------------
- # Pixeliza o bitmap inteiro
- #
- # [Integer] size : Tamanho da pixelização.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def pixelate(size)
- return pixelate_rect(self.rect, size)
- end
- #-----------------------------------------------------------------------
- # Balanceamento de cor de uma rect
- #
- # [Rect ] rect : Rect que compreende a área que será balanceada.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- # [Numeric] r : Coeficiente de vermelho.
- # [Numeric] g : Coeficiente de verde.
- # [Numeric] b : Coeficiente de azul.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def color_balance_rect(*args)
- case args.size
- when 4
- rect, r, g, b = *args
- when 7
- b, g, r, rect = args.pop, args.pop, args.pop, Rect.new(*args)
- else
- assert_args_count(args, 4)
- end
- self.rect.intercept(rect).iterate{|x, y|
- px = get_pixel(x, y)
- px.red += r * (255 - px.red)
- px.green += g * (255 - px.green)
- px.blue += b * (255 - px.blue)
- set_pixel(x, y, px)
- }
- return self
- end
- #-----------------------------------------------------------------------
- # Balanceamento de cor do bitmap por inteiro
- #
- # [Numeric] r : Coeficiente de vermelho.
- # [Numeric] g : Coeficiente de verde.
- # [Numeric] b : Coeficiente de azul.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def color_balance(r, g, b)
- return color_balance_rect(self.rect, r, g, b)
- end
- #-----------------------------------------------------------------------
- # Contraste binário de um segmento
- #
- # [Rect ] rect : Rect que compreende a área que será constrastada.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- # [Numeric] f : Fator de sombra. As cores que tiverem sua média
- # (Color#average) menor que o fator, serão transformadas
- # em preto. As que forem maiores, em branco.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def threshold_rect(*args)
- case args.size
- when 2
- rect, shadowFactor = *args
- when 5
- shadowFactor, rect = args.pop, Rect.new(*args)
- else
- assert_args_count(args, 2)
- end
- if shadowFactor.between?(0, 1)
- shadowFactor *= 255
- end
- shadowFactor = shadowFactor.to_i
- self.rect.intercept(rect).iterate{|x, y|
- px = get_pixel(x, y)
- m = px.average
- set_pixel(x, y, m < shadowFactor ? Color.black(px.alpha) : Color.white(px.alpha))
- }
- return self
- end
- #-----------------------------------------------------------------------
- # Constraste binário de todo o bitmap
- #
- # [Numeric] f : Fator de sombra. As cores que tiverem sua média
- # (Color#average) menor que o fator, serão transformadas
- # em preto. As que forem maiores, em branco.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def threshold(f)
- return self.threshold_rect(self.rect, f)
- end
- #-----------------------------------------------------------------------
- # Recorta uma rect do bitmap em um novo bitmap
- #
- # [Rect] rect : Rect que compreende a área que será recortada.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- #
- # [Bitmap] Retorno : Bitmap recortado
- #-----------------------------------------------------------------------
- def crop(*args)
- case args.size
- when 1
- rect = *args
- when 4
- rect = Rect.new(*args)
- else
- assert_args_count(args, 1)
- end
- dstRect = self.rect.intercept(rect)
- dstBmp = Bitmap.new(dstRect.width, dstRect.height)
- dstBmp.blt(0, 0, self, dstRect)
- return dstBmp
- end
- #-----------------------------------------------------------------------
- # Preenche o bitmap com uma cor
- #
- # [Color] color : Cor de preenchimento
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def fill(color)
- fill_rect(self.rect, color)
- return self
- end
- #-----------------------------------------------------------------------
- # Sobrepõe um pixel com uma cor (mescla as cores)
- #
- # [Integer] x : Posição x do pixel sobreposto
- # [Integer] y : Posição y do pixel sobreposto
- # [Color] c : Cor de sobreposição
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def plot(x, y, c)
- set_pixel(x, y, get_pixel(x, y).blend(c))
- return self
- end
- #-----------------------------------------------------------------------
- # Sobrepõe uma rect com uma cor
- #
- # [Rect ] rect : Rect que compreende a área que será sobreposta.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- # [Color] color : Cor de sobreposição
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def plot_rect(*args)
- case args.size
- when 2
- rect, color = *args
- when 5
- color, rect = args.pop, Rect.new(*args)
- else
- assert_args_count(args, 2)
- end
- self.rect.intercept(rect).iterate{|x, y| plot(x, y, color) }
- return self
- end
- #-----------------------------------------------------------------------
- # Desenha uma linha sem anti-alias
- # Algoritmo: Bresenham (Otimizado)
- #
- # [Integer] x0 : Posição x inicial
- # [Integer] y0 : Posição y inicial
- # [Integer] x1 : Posição x final
- # [Integer] y1 : Posição y final
- # [Color ] c : Cor da linha. Se não especificada, será utilizada a cor
- # da fonte do bitmap.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def draw_line(x0, y0, x1, y1, c = nil)
- c ||= self.font.color
- dx = x1 - x0
- dy = y1 - y0
- d = 2 * dy - dx
- plot(x0, y0, c)
- y = y0
- for x in (x0 + 1)..(x1)
- if d > 0
- y += 1
- d -= 2 * dx
- end
- d += 2 * dy
- plot(x, y, c)
- end
- return self
- end
- #-----------------------------------------------------------------------
- # Desenha uma linha com anti-alias
- # Algoritmo: Xiaolin Wu
- #
- # [Integer] x0 : Posição x inicial
- # [Integer] y0 : Posição y inicial
- # [Integer] x1 : Posição x final
- # [Integer] y1 : Posição y final
- # [Color ] c : Cor da linha. Se não especificada, será utilizada a cor
- # da fonte do bitmap.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def draw_antialiased_line(x0, y0, x1, y1, c = nil)
- c ||= self.font.color
- steep = (y1 - y0).abs > (x1 - x0).abs
- if steep
- x0, y0 = y0, x0
- x1, y1 = y1, x1
- end
- if x0 > x1
- x0, x1 = x1, x0
- y0, y1 = y1, y0
- end
- dx = x1 - x0
- dy = y1 - y0
- gradient = dy.to_f / dx
- xend = (x0 + 0.5).to_i
- yend = y0 + gradient * (xend - x0)
- xgap = (x0 + 0.5).rfpart
- xpxl1 = xend
- ypxl1 = yend.to_i
- if steep
- c.alpha = 255 * (yend.rfpart * xgap)
- plot(ypxl1, xpxl1, c)
- c.alpha = 255 * (yend.fpart * xgap)
- plot(ypxl1 + 1, xpxl1, c)
- else
- c.alpha = 255 * (yend.rfpart * xgap)
- plot(xpxl1, ypxl1, c)
- c.alpha = 255 * (yend.fpart * xgap)
- plot(xpxl1, ypxl1 + 1, c)
- end
- intery = yend + gradient
- xend = x1.round
- yend = y1 + gradient * (xend - x1)
- xgap = (x1 + 0.5).fpart
- xpxl2 = xend
- ypxl2 = yend.to_i
- if steep
- c.alpha = 255 * (yend.rfpart * xgap)
- plot(ypxl2, xpx21, c)
- c.alpha = 255 * (yend.fpart * xgap)
- plot(ypxl2 + 1, xpx21, c)
- else
- c.alpha = 255 * (yend.rfpart * xgap)
- plot(xpxl2, ypxl2, c)
- c.alpha = 255 * (yend.fpart * xgap)
- plot(xpxl1, ypxl2 + 1, c)
- end
- for x in (xpxl1 + 1)..(xpxl2 - 1)
- if steep
- c.alpha = 255 * intery.rfpart
- plot(intery.to_i, x, c)
- c.alpha = 255 * intery.fpart
- plot(intery.to_i + 1, x, c)
- else
- c.alpha = 255 * intery.rfpart
- plot(x, intery.to_i, c)
- c.alpha = 255 * intery.fpart
- plot(x, intery.to_i + 1, c)
- end
- intery += gradient
- end
- return self
- end
- #-----------------------------------------------------------------------
- # Desenha um círculo sem anti-alias
- # Algoritmo: Bresenham (Otimizado)
- #
- # [Integer] x : Centro x
- # [Integer] y : Centro y
- # [Integer] radius : Raio do círculo
- # [Color ] c : Cor da linha. Se não especificada, será utilizada
- # a cor da fonte do bitmap.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def draw_circle(cx, cy, radius, c = nil)
- return self if radius <= 0
- c ||= self.font.color
- if radius == 1
- plot(cx, cy, c)
- return self
- end
- error = -radius
- x = radius
- y = 0
- while (x >= y)
- 2.times{
- plot(cx + x, cy + y, c)
- plot(cx - x, cy + y, c) unless x.zero?
- plot(cx + x, cy - y, c) unless y.zero?
- plot(cx - x, cy - y, c)
- break if x == y
- x, y = y, x
- }
- error += 2 * (y += 1) - 1
- error -= 2 * (x -= 1) + 1 if (error >= 0)
- end
- return self
- end
- #-----------------------------------------------------------------------
- # Preenche um círculo
- # Algoritmo: Bresenham (Adaptações)
- #
- # [Integer] x : Centro x
- # [Integer] y : Centro y
- # [Integer] radius : Raio do círculo
- # [Color ] c : Cor da linha. Se não especificada, será utilizada
- # a cor da fonte do bitmap.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- def fill_circle(cx, cy, radius, c = nil)
- c ||= self.font.color
- x = -radius
- y = 0
- err = 2 * (1 - radius)
- begin
- plot_rect(cx + x, cy + y, -2 * x, 1, c)
- plot_rect(cx + x, cy - y, -2 * x, 1, c)
- r = err
- err += 2 * (y += 1) + 1 if (r <= y)
- err += 2 * (x += 1) + 1 if (r > x || err > y)
- end while x < 0
- return self
- end
- #-----------------------------------------------------------------------
- # Preenche rect com gradiente
- #
- # [Rect ] rect : Rect que compreende a área que será preenchida.
- # Caso sejam dados quatro argumentos eles serão utilizados
- # como argumento para Rect.new.
- # [Color ] c1 : Cor 1
- # [Color ] c2 : Cor 2
- # [Boolean] vertical : Se verdadeiro, o gradiente será preenchido na
- # vertical. Caso contrário, na horizontal.
- #
- # [Bitmap] Retorno : A própria instância.
- #-----------------------------------------------------------------------
- if MakerUtils::XP
- def gradient_fill_rect(*args)
- case args.size
- when 3
- verical, rect, c1, c2 = false, *args
- when 4
- rect, c1, c2, vertical = *args
- when 6
- c2, c1, rect, vertical = args.pop, args.pop, Rect.new(*args), false
- when 7
- vertical, c2, c1, rect = args.pop, args.pop, args.pop, Rect.new(*args)
- else
- assert_args_count(args, 3)
- end
- resultRect = self.rect.intercept(rect)
- ac = Color.new(*c1.to_ary)
- if vertical
- size = rect.height.to_f
- return if size.zero?
- rates = [:red, :green, :blue, :alpha].map{|channel|
- (c2.send(channel) - c1.send(channel)) / size
- }
- resultRect.top.upto(resultRect.bottom){|y|
- fill_rect(resultRect.left, y, resultRect.width, 1, ac)
- ac += rates
- }
- else
- size = rect.width.to_f
- return if size.zero?
- rates = [:red, :green, :blue, :alpha].map{|channel|
- (c2.send(channel) - c1.send(channel)) / size
- }
- resultRect.left.upto(resultRect.right){|x|
- fill_rect(x, resultRect.top, 1, resultRect.height, ac)
- ac += rates
- }
- end
- return self
- end
- end
- end
- }
- #=============================================================================
- # ** Binary
- #---------------------------------------------------------------------------
- # Módulo que gerencia escrita e leitura de arquivos binários.
- #=============================================================================
- Gab.register(:BinaryControl, "Gab!", 1.0){
- module Binary
- #-----------------------------------------------------------------------
- # Tabela de correspondência (nome, tamanho, unpack)
- #-----------------------------------------------------------------------
- DATA_TYPES = [
- [:char, [1, "c"]],
- [:signed_char, :char ],
- [:int8, :char ],
- [:uchar, [1, "C"]],
- [:unsigned_char, :uchar ],
- [:uint8, :uchar ],
- [:unsigned_int8, :uchar ],
- [:byte, :uchar ],
- [:short, [2, "s"]],
- [:word, :short ],
- [:signed_short, :short ],
- [:ushort, [2, "S"]],
- [:unsigned_short, :ushort ],
- [:int32, [4, "l"]],
- [:signed_int32, :int32 ],
- [:uint32, [4, "L"]],
- [:unsigned_int32, :uint32 ],
- [:int64, [8, "q"]],
- [:signed_int64, :int64 ],
- [:uint64, [8, "Q"]],
- [:unsigned_int64, :uint64 ],
- [:float, [4, "F"]],
- [:double, [8, "D"]],
- ]
- #=========================================================================
- # ** Binary::Reader
- #=========================================================================
- class Reader
- #---------------------------------------------------------------------
- # Inicializa classe, o argumento deve ser uma instância da classe IO
- # (ou File) para que a leitura seja feita em tempo real.
- #---------------------------------------------------------------------
- def initialize(source)
- @source = source
- end
- #---------------------------------------------------------------------
- # Métodos de leitura
- #
- # [Mixed] Retorno : Objeto lido
- #---------------------------------------------------------------------
- DATA_TYPES.each{|type|
- sym = type.first
- data = type.size == 2 ? type[1] : type[1,2]
- name = "read_#{sym}"
- if data.is_a?(Array)
- size, upk = *data
- define_method(name){
- rd = @source.read(size)
- if rd
- return rd.unpack(upk).first
- elsif @source.eof?
- raise(EOFError)
- else
- raise(Exception) # DUH
- end
- }
- else
- name2 = "read_#{data}"
- alias_method(name, name2)
- end
- }
- #---------------------------------------------------------------------
- # Lê uma string (sequência de bytes até o byte 0)
- #
- # [String] Retorno : String lida
- #---------------------------------------------------------------------
- def read_string
- data = ""
- until (byte = self.read_byte).zero?
- data << byte.chr
- end
- return data
- end
- end
- #=========================================================================
- # ** Binary::Writer
- #=========================================================================
- class Writer
- #-----------------------------------------------------------------------
- # Inicializa classe, o argumento deve ser uma instância da classe IO
- # (ou File) para que a escrita seja feita em tempo real ou pelo método
- # de stack/atualização.
- #-----------------------------------------------------------------------
- def initialize(source)
- @source = source
- @stack = []
- @args = []
- end
- #-----------------------------------------------------------------------
- # Limpa o stack e escreve todos os objetos no arquivo
- #-----------------------------------------------------------------------
- def flush
- pack = @args.map{|(pk, count)| count == 1 ? pk : "#{pk}#{count}"}.join
- @source << @stack.pack(pack)
- @stack.clear
- @args.clear
- return nil
- end
- #-----------------------------------------------------------------------
- # Métodos de escrita
- #
- # [Mixed] value : Valor que será escrito no arquivo
- #-----------------------------------------------------------------------
- DATA_TYPES.each{|type|
- sym = type.first
- data = type.size == 2 ? type[1] : type[1,2]
- name = ["write_#{sym}", "add_#{sym}", "update_with_#{sym}"]
- if data.is_a?(Array)
- size, pk = *data
- define_method(name[0]){|value|
- @source << [value].pack(pk)
- }
- define_method(name[1]){|value|
- @stack << value
- if @args[-1] and @args[-1][0] == pk
- @args[-1][1] += 1
- else
- @args << [pk, 1]
- end
- }
- alias_method(name[2], name[1])
- else
- name.zip([
- "write_#{data}",
- "add_#{data}",
- "update_with_#{data}"
- ]).each{|names|
- alias_method(*names)
- }
- end
- }
- #---------------------------------------------------------------------
- # Escreve uma string
- #
- # [String] str : String que será 'empacotada'
- #---------------------------------------------------------------------
- def write_string(str)
- @source << [value].pack("Z*")
- return nil
- end
- #---------------------------------------------------------------------
- # Adiciona uma string no stack
- #
- # [String] str : String que será 'empacotada'
- #---------------------------------------------------------------------
- def add_string(str)
- @stack << str
- @args << ["Z", str.size + 1]
- return nil
- end
- alias update_with_string add_string
- end
- end
- }
- #=============================================================================
- # ** DLL Wrapper
- #---------------------------------------------------------------------------
- # Utilitário para definir módulos referentes a DLL's.
- #
- # Exemplo:
- #
- # MinhaDLL = DLL.wrap('nome_da_dll', [
- # [:Constante1, 0xA],
- # [:Constante2, 0xB],
- # ], [
- # [:Funcao1, 'LI', 'I'], # Nome, Entrada, Saída
- # [:Funcao2, 'LI', 'I'], # Nome, Entrada, Saída
- # ])
- #
- # MinhaDLL::Constante1 #=> 0xA
- # MinhaDLL.Funcao1(20, 40) #=> 60
- #=============================================================================
- Gab.register(:DLLWrapper, "Gab!", 1.0){
- class << (DLL = Class.new)
- def wrap(name, constants = [], functions = [])
- dll = Module.new {
- def self.method_missing(name, *args)
- apiList = const_get(:DLL_WRAPPER_INTERNAL_API)
- name = name.to_s
- if apiList.has_key?(name.to_s)
- apiList[name].call(*args)
- else
- super(name, args)
- end
- end
- }
- dll.const_set(:DLL_WRAPPER_INTERNAL_API, {})
- constants.each{|(cname, value)|
- dll.const_set(cname, value)
- }
- functions.each{|(fname, argin, argout)|
- dll::DLL_WRAPPER_INTERNAL_API[fname.to_s] = Win32API.new(name, fname.to_s, argin, argout)
- }
- return dll
- end
- undef :new
- end
- }
- #=============================================================================
- # ** INIReader
- #---------------------------------------------------------------------------
- # Classe que permite a leitura de arquivos INI
- #=============================================================================
- Gab.register(:INIReader, "Gab!", 1.0){
- class INIReader
- #----------------------#
- # Expressões regulares #
- #----------------------#
- REGEX = {
- :Comment => /^.*(;.*)$/,
- :Section => /^\s*\[(.+)\]$/,
- :Variable => /^\s*([^=]+)=(.*)$/,
- :Int => /^\d+$/
- }
- #-----------------------------------------------------------------------
- # Inicialização do objeto
- #
- # [String|IO] source : Arquivo aberto ou nome do arquivo
- #-----------------------------------------------------------------------
- def initialize(source)
- assert_type(source, [String, IO])
- if source.is_a?(IO)
- pos = source.pos
- @data = source.read
- source.seek(pos)
- else
- _source = File.open(source, 'rb')
- @data = _source.read
- _source.close
- end
- @globalSection = {}
- @sections = {}
- self.parseData
- end
- #-----------------------------------------------------------------------
- # Seções do arquivo
- #
- # [Array] Retorno : Nome das seções (sem contar a global)
- #-----------------------------------------------------------------------
- def sections
- return @sections.keys
- end
- #-----------------------------------------------------------------------
- # Verifica a existência de uma seção
- #
- # [String] section : Nome da seção
- #
- # [Boolean] Retorno : Existência da seção
- #-----------------------------------------------------------------------
- def hasSection?(section)
- return @sections.has_key?(section)
- end
- #-----------------------------------------------------------------------
- # Variáveis de uma seção
- #
- # [String] section : Seção alvo
- #
- # [Mixed] Retorno : Nulo se a seção não existir, array com as variáveis
- # dela caso contrário.
- #-----------------------------------------------------------------------
- def variables(section)
- return @sections.has_key?(section) ? @sections[section].keys : nil
- end
- #-----------------------------------------------------------------------
- # Verifica a existência de uma seção global
- #
- # [Boolean] Retorno : Verdadeiro se existe uma seção global
- #-----------------------------------------------------------------------
- def hasGlobalSection?
- return !@globalSection.size.zero?
- end
- #-----------------------------------------------------------------------
- # Retorna uma variável de uma determinada seção
- #
- # [String] section : Nome da seção
- # [String] variable : Nome da variável
- #
- # [Mixed] Retorno : Nulo se a seção ou variável não existir, caso
- # contrário, o valor da variável.
- #-----------------------------------------------------------------------
- def [](section, variable)
- return nil unless @sections.has_key?(section)
- return nil unless @sections[section].has_key?(variable)
- return @sections[section][variable]
- end
- #-----------------------------------------------------------------------
- # Processa o conteúdo do arquivo
- #-----------------------------------------------------------------------
- protected
- def parseData
- section = :global
- @data.each_line{|line|
- line.sub!(REGEX[:Comment], '')
- line.strip!
- if data = line.match(REGEX[:Section])
- section = data[1]
- @sections[section] ||= {}
- elsif data = line.match(REGEX[:Variable])
- value = data[2].empty? ? nil : data[2]
- value = value.to_i if value and value.match(REGEX[:Int])
- if section == :global
- @globalSection[data[1]] = value
- else
- @sections[section][data[1]] = value
- end
- end
- }
- end
- end
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement