lib/minigl/forms.rb
def update
      return unless @enabled and @visible

      ################################ Mouse ################################
      if Mouse.over? @x, @y, @w, @h
        if not @active and Mouse.button_pressed? :left
          focus
        end
      elsif Mouse.button_pressed? :left
        unfocus
      end

      return unless @active

      if Mouse.double_click? :left
        if @nodes.size > 1
          @anchor1 = 0
          @anchor2 = @nodes.size - 1
          @cur_node = @anchor2
          @double_clicked = true
        end
        set_cursor_visible
      elsif Mouse.button_pressed? :left
        set_node_by_mouse
        @anchor1 = @cur_node
        @anchor2 = nil
        @double_clicked = false
        set_cursor_visible
      elsif Mouse.button_down? :left
        if @anchor1 and not @double_clicked
          set_node_by_mouse
          if @cur_node != @anchor1; @anchor2 = @cur_node
          else; @anchor2 = nil; end
          set_cursor_visible
        end
      elsif Mouse.button_released? :left
        if @anchor1 and not @double_clicked
          if @cur_node != @anchor1; @anchor2 = @cur_node
          else; @anchor1 = nil; end
        end
      end

      @cursor_timer += 1
      if @cursor_timer >= 30
        @cursor_visible = (not @cursor_visible)
        @cursor_timer = 0
      end

      ############################### Keyboard ##############################
      shift = (KB.key_down?(@k[53]) or KB.key_down?(@k[54]))
      if KB.key_pressed?(@k[53]) or KB.key_pressed?(@k[54]) # shift
        @anchor1 = @cur_node if @anchor1.nil?
      elsif KB.key_released?(@k[53]) or KB.key_released?(@k[54])
        @anchor1 = nil if @anchor2.nil?
      end
      inserted = false
      for i in 0..46 # alnum
        if KB.key_pressed?(@k[i]) or KB.key_held?(@k[i])
          remove_interval true if @anchor1 and @anchor2
          if i < 26
            if shift
              insert_char @chars[i + 37]
            else
              insert_char @chars[i]
            end
          elsif i < 36
            if shift; insert_char @chars[i + 59]
            else; insert_char @chars[i]; end
          elsif shift
            insert_char(@chars[i + 49])
          else
            insert_char(@chars[i - 10])
          end
          inserted = true
          break
        end
      end

      return if inserted
      for i in 55..65 # special
        if KB.key_pressed?(@k[i]) or KB.key_held?(@k[i])
          remove_interval true if @anchor1 and @anchor2
          if shift; insert_char @chars[i + 19]
          else; insert_char @chars[i + 8]; end
          inserted = true
          break
        end
      end

      return if inserted
      for i in 66..69 # numpad operators
        if KB.key_pressed?(@k[i]) or KB.key_held?(@k[i])
          remove_interval true if @anchor1 and @anchor2
          insert_char @chars[i + 19]
          inserted = true
          break
        end
      end

      return if inserted
      if KB.key_pressed?(@k[47]) or KB.key_held?(@k[47]) # back
        if @anchor1 and @anchor2
          remove_interval
        elsif @cur_node > 0
          remove_char true
        end
      elsif KB.key_pressed?(@k[48]) or KB.key_held?(@k[48]) # del
        if @anchor1 and @anchor2
          remove_interval
        elsif @cur_node < @nodes.size - 1
          remove_char false
        end
      elsif KB.key_pressed?(@k[49]) or KB.key_held?(@k[49]) # left
        if @anchor1
          if shift
            if @cur_node > 0
              @cur_node -= 1
              @anchor2 = @cur_node
              set_cursor_visible
            end
          elsif @anchor2
            @cur_node = @anchor1 < @anchor2 ? @anchor1 : @anchor2
            @anchor1 = nil
            @anchor2 = nil
            set_cursor_visible
          end
        elsif @cur_node > 0
          @cur_node -= 1
          set_cursor_visible
        end
      elsif KB.key_pressed?(@k[50]) or KB.key_held?(@k[50]) # right
        if @anchor1
          if shift
            if @cur_node < @nodes.size - 1
              @cur_node += 1
              @anchor2 = @cur_node
              set_cursor_visible
            end
          elsif @anchor2
            @cur_node = @anchor1 > @anchor2 ? @anchor1 : @anchor2
            @anchor1 = nil
            @anchor2 = nil
            set_cursor_visible
          end
        elsif @cur_node < @nodes.size - 1
          @cur_node += 1
          set_cursor_visible
        end
      elsif KB.key_pressed?(@k[51]) # home
        @cur_node = 0
        if shift; @anchor2 = @cur_node
        else
          @anchor1 = nil
          @anchor2 = nil
        end
        set_cursor_visible
      elsif KB.key_pressed?(@k[52]) # end
        @cur_node = @nodes.size - 1
        if shift; @anchor2 = @cur_node
        else
          @anchor1 = nil
          @anchor2 = nil
        end
        set_cursor_visible
      end
    end
def update
      return unless @enabled and @visible

      ################################ Mouse ################################
      if Mouse.over? @x, @y, @w, @h
        if not @active and Mouse.button_pressed? :left
          focus
        end
      elsif Mouse.button_pressed? :left
        unfocus
      end

      return unless @active

      if Mouse.double_click? :left
        if @nodes.size > 1
          @anchor1 = 0
          @anchor2 = @nodes.size - 1
          @cur_node = @anchor2
          @double_clicked = true
        end
        set_cursor_visible
      elsif Mouse.button_pressed? :left
        set_node_by_mouse
        @anchor1 = @cur_node
        @anchor2 = nil
        @double_clicked = false
        set_cursor_visible
      elsif Mouse.button_down? :left
        if @anchor1 and not @double_clicked
          set_node_by_mouse
          if @cur_node != @anchor1; @anchor2 = @cur_node
          else; @anchor2 = nil; end
          set_cursor_visible
        end
      elsif Mouse.button_released? :left
        if @anchor1 and not @double_clicked
          if @cur_node != @anchor1; @anchor2 = @cur_node
          else; @anchor1 = nil; end
        end
      end

      @cursor_timer += 1
      if @cursor_timer >= 30
        @cursor_visible = (not @cursor_visible)
        @cursor_timer = 0
      end

      ############################### Keyboard ##############################
      shift = (KB.key_down?(@k[53]) or KB.key_down?(@k[54]))
      if KB.key_pressed?(@k[53]) or KB.key_pressed?(@k[54]) # shift
        @anchor1 = @cur_node if @anchor1.nil?
      elsif KB.key_released?(@k[53]) or KB.key_released?(@k[54])
        @anchor1 = nil if @anchor2.nil?
      end
      inserted = false
      for i in 0..46 # alnum
        if KB.key_pressed?(@k[i]) or KB.key_held?(@k[i])
          remove_interval true if @anchor1 and @anchor2
          if i < 26
            if shift
              insert_char @chars[i + 37]
            else
              insert_char @chars[i]
            end
          elsif i < 36
            if shift; insert_char @chars[i + 59]
            else; insert_char @chars[i]; end
          elsif shift
            insert_char(@chars[i + 49])
          else
            insert_char(@chars[i - 10])
          end
          inserted = true
          break
        end
      end

      return if inserted
      for i in 55..65 # special
        if KB.key_pressed?(@k[i]) or KB.key_held?(@k[i])
          remove_interval true if @anchor1 and @anchor2
          if shift; insert_char @chars[i + 19]
          else; insert_char @chars[i + 8]; end
          inserted = true
          break
        end
      end

      return if inserted
      for i in 66..69 # numpad operators
        if KB.key_pressed?(@k[i]) or KB.key_held?(@k[i])
          remove_interval true if @anchor1 and @anchor2
          insert_char @chars[i + 19]
          inserted = true
          break
        end
      end

      return if inserted
      if KB.key_pressed?(@k[47]) or KB.key_held?(@k[47]) # back
        if @anchor1 and @anchor2
          remove_interval
        elsif @cur_node > 0
          remove_char true
        end
      elsif KB.key_pressed?(@k[48]) or KB.key_held?(@k[48]) # del
        if @anchor1 and @anchor2
          remove_interval
        elsif @cur_node < @nodes.size - 1
          remove_char false
        end
      elsif KB.key_pressed?(@k[49]) or KB.key_held?(@k[49]) # left
        if @anchor1
          if shift
            if @cur_node > 0
              @cur_node -= 1
              @anchor2 = @cur_node
              set_cursor_visible
            end
          elsif @anchor2
            @cur_node = @anchor1 < @anchor2 ? @anchor1 : @anchor2
            @anchor1 = nil
            @anchor2 = nil
            set_cursor_visible
          end
        elsif @cur_node > 0
          @cur_node -= 1
          set_cursor_visible
        end
      elsif KB.key_pressed?(@k[50]) or KB.key_held?(@k[50]) # right
        if @anchor1
          if shift
            if @cur_node < @nodes.size - 1
              @cur_node += 1
              @anchor2 = @cur_node
              set_cursor_visible
            end
          elsif @anchor2
            @cur_node = @anchor1 > @anchor2 ? @anchor1 : @anchor2
            @anchor1 = nil
            @anchor2 = nil
            set_cursor_visible
          end
        elsif @cur_node < @nodes.size - 1
          @cur_node += 1
          set_cursor_visible
        end
      elsif KB.key_pressed?(@k[51]) # home
        @cur_node = 0
        if shift; @anchor2 = @cur_node
        else
          @anchor1 = nil
          @anchor2 = nil
        end
        set_cursor_visible
      elsif KB.key_pressed?(@k[52]) # end
        @cur_node = @nodes.size - 1
        if shift; @anchor2 = @cur_node
        else
          @anchor1 = nil
          @anchor2 = nil
        end
        set_cursor_visible
      end
    end
Creates a new text field.

 Parameters:
 [x] The x-coordinate where the text field will be drawn in the screen.
 [y] The y-coordinate where the text field will be drawn in the screen.
 [font] The <code>Gosu::Font</code> object that will be used to draw the
        text inside the field.
 [img] The image of the text field. For a good result, you would likely
       want something like a rectangle, horizontally wide, vertically
       short, and with a color that contrasts with the +text_color+.
 [cursor_img] An image for the blinking cursor that stands in the point
              where text will be inserted. If +nil+, a simple black line
              will be drawn instead.
 [disabled_img] Image for the text field when it's disabled. If +nil+,
                a darkened version of +img+ will be used.
 [text_color] Color of the button text, in hexadecimal RRGGBB format.
 [margin_x] The x offset, from the field x-coordinate, to draw the text.
 [margin_y] The y offset, from the field y-coordinate, to draw the text.
 [max_length] The maximum length of the text inside the field.
 [active] Whether the text field must be focused by default. If +false+,
          focus can be granted by clicking inside the text field or by
          calling the +focus+ method.
 [text] The starting text. Must not be +nil+.
 [allowed_chars] A string containing all characters that can be typed
                 inside the text field. The complete set of supported
                 characters is given by the string
                 <code>"abcdefghijklmnopqrstuvwxyz1234567890 ABCDEFGHIJKLMNOPQRSTUVWXYZ'-=/[]\\\\,.;\"_+?{}|<>:!@#$%¨&*()"</code>.
 [text_color] The color with which the text will be drawn, in hexadecimal
              RRGGBB format.
 [disabled_text_color] The color with which the text will be drawn, when
                       the text field is disabled, in hexadecimal RRGGBB
                       format.
 [selection_color] The color of the rectangle highlighting selected text,
                   in hexadecimal RRGGBB format. The rectangle will
                   always be drawn with 50% of opacity.
 [locale] The locale to be used when detecting keys. By now, only 'en-US'
          and 'pt-BR' are **partially** supported. Default is 'en-US'. If
          any different value is supplied, all typed characters will be
          mapped to '#'.
 [params] An object containing any parameters you want passed to the
          +on_text_changed+ block. When the text of the text field is
          changed, the following is called:
            @on_text_changed.call @text, @params
          Thus, +params+ will be the second parameter. Note that this
          doesn't force you to declare a block that takes parameters.
 [retro] Whether the images should be loaded with the 'retro' option set
         (see +Gosu::Image+ for details). If the value is omitted, the
         +Res.retro_images+ value will be used.
 [scale_x] Horizontal scale to draw the component with.
 [scale_y] Vertical scale to draw the component with.
 [anchor] See parameter with the same name in <code>Panel#initialize</code> for details.
 [on_text_changed] The block of code executed when the text in the text
                   field is changed, either by user input or by calling
                   +text=+. The new text is passed as a first parameter
                   to this block, followed by +params+. Can be +nil+.

 *Obs.:* This method accepts named parameters, but +x+, +y+, +font+ and
 +img+ are mandatory.
 Updates the text field, checking for mouse events and keyboard input.