Class: MiniGL::TextField

Inherits:
Component show all
Defined in:
lib/minigl/forms.rb

Overview

This class represents a text field (input).

Instance Attribute Summary collapse

Attributes inherited from Component

#anchor, #anchor_offset_x, #anchor_offset_y, #enabled, #h, #panel, #params, #text, #visible, #w, #x, #y

Instance Method Summary collapse

Constructor Details

#initialize(x, y = nil, font = nil, img = nil, cursor_img = nil, disabled_img = nil, margin_x = 0, margin_y = 0, max_length = 100, active = false, text = '', allowed_chars = nil, text_color = 0, disabled_text_color = 0, selection_color = 0, locale = 'en-us', params = nil, retro = nil, scale_x = 1, scale_y = 1, anchor = nil, &on_text_changed) ⇒ TextField

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 Gosu::Font 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 "abcdefghijklmnopqrstuvwxyz1234567890 ABCDEFGHIJKLMNOPQRSTUVWXYZ'-=/[]\\,.;\"_+?{}|<>:!@#$%¨&*()".

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 Panel#initialize 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.



608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
# File 'lib/minigl/forms.rb', line 608

def initialize(x, y = nil, font = nil, img = nil, cursor_img = nil, disabled_img = nil, margin_x = 0, margin_y = 0,
               max_length = 100, active = false, text = '', allowed_chars = nil,
               text_color = 0, disabled_text_color = 0, selection_color = 0, locale = 'en-us',
               params = nil, retro = nil, scale_x = 1, scale_y = 1, anchor = nil, &on_text_changed)
  if x.is_a? Hash
    y = x[:y]
    font = x[:font]
    img = x[:img]
    cursor_img = x.fetch(:cursor_img, nil)
    disabled_img = x.fetch(:disabled_img, nil)
    margin_x = x.fetch(:margin_x, 0)
    margin_y = x.fetch(:margin_y, 0)
    max_length = x.fetch(:max_length, 100)
    active = x.fetch(:active, false)
    text = x.fetch(:text, '')
    allowed_chars = x.fetch(:allowed_chars, nil)
    text_color = x.fetch(:text_color, 0)
    disabled_text_color = x.fetch(:disabled_text_color, 0)
    selection_color = x.fetch(:selection_color, 0)
    locale = x.fetch(:locale, 'en-us')
    params = x.fetch(:params, nil)
    retro = x.fetch(:retro, nil)
    scale_x = x.fetch(:scale_x, 1)
    scale_y = x.fetch(:scale_y, 1)
    anchor = x.fetch(:anchor, nil)
    x = x[:x]
  end

  retro = Res.retro_images if retro.nil?
  @scale_x = scale_x
  @scale_y = scale_y
  @img = Res.img img, false, false, '.png', retro
  @w = @img.width * @scale_x
  @h = @img.height * @scale_y

  @anchor_offset_x = x; @anchor_offset_y = y
  @anchor, x, y = FormUtils.check_anchor(anchor, x, y, @w, @h)

  super x, y, font, text, text_color, disabled_text_color
  @cursor_img = Res.img(cursor_img, false, false, '.png', retro) if cursor_img
  @disabled_img = Res.img(disabled_img, false, false, '.png', retro) if disabled_img
  @max_length = max_length
  @active = active
  @text_x = x + margin_x * @scale_x
  @text_y = y + margin_y * @scale_y
  @selection_color = selection_color

  @nodes = [@text_x]
  send(:text=, text, false) if text

  @cur_node = 0
  @cursor_visible = false
  @cursor_timer = 0

  @k = [
    Gosu::KbA, Gosu::KbB, Gosu::KbC, Gosu::KbD, Gosu::KbE, Gosu::KbF,
    Gosu::KbG, Gosu::KbH, Gosu::KbI, Gosu::KbJ, Gosu::KbK, Gosu::KbL,
    Gosu::KbM, Gosu::KbN, Gosu::KbO, Gosu::KbP, Gosu::KbQ, Gosu::KbR,
    Gosu::KbS, Gosu::KbT, Gosu::KbU, Gosu::KbV, Gosu::KbW, Gosu::KbX,
    Gosu::KbY, Gosu::KbZ, Gosu::Kb1, Gosu::Kb2, Gosu::Kb3, Gosu::Kb4,
    Gosu::Kb5, Gosu::Kb6, Gosu::Kb7, Gosu::Kb8, Gosu::Kb9, Gosu::Kb0,
    Gosu::KbNumpad1, Gosu::KbNumpad2, Gosu::KbNumpad3, Gosu::KbNumpad4,
    Gosu::KbNumpad5, Gosu::KbNumpad6, Gosu::KbNumpad7, Gosu::KbNumpad8,
    Gosu::KbNumpad9, Gosu::KbNumpad0, Gosu::KbSpace, Gosu::KbBackspace,
    Gosu::KbDelete, Gosu::KbLeft, Gosu::KbRight, Gosu::KbHome,
    Gosu::KbEnd, Gosu::KbLeftShift, Gosu::KbRightShift,
    Gosu::KbBacktick, Gosu::KbMinus, Gosu::KbEqual, Gosu::KbBracketLeft,
    Gosu::KbBracketRight, Gosu::KbBackslash, Gosu::KbSemicolon,
    Gosu::KbApostrophe, Gosu::KbComma, Gosu::KbPeriod, Gosu::KbSlash,
    Gosu::KbNumpadAdd, Gosu::KbNumpadSubtract,
    Gosu::KbNumpadMultiply, Gosu::KbNumpadDivide
  ]
  @user_allowed_chars = allowed_chars
  self.locale = locale

  @on_text_changed = on_text_changed
  @params = params
end

Instance Attribute Details

#localeObject

The current ‘locale’ used for detecting the keys. THIS FEATURE IS INCOMPLETE!



548
549
550
# File 'lib/minigl/forms.rb', line 548

def locale
  @locale
end

Instance Method Details

#draw(alpha = 0xff, z_index = 0, color = 0xffffff, disabled_color = 0x808080) ⇒ Object

Draws the text field in the screen.

Parameters:

alpha

The opacity with which the text field will be drawn. Allowed values vary between 0 (fully transparent) and 255 (fully opaque).

z_index

The z-order to draw the object. Objects with larger z-orders will be drawn on top of the ones with smaller z-orders.

color

Color to apply a filter to the image.

disabled_color

Color to apply a filter to the image when the field is disabled.



943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
# File 'lib/minigl/forms.rb', line 943

def draw(alpha = 0xff, z_index = 0, color = 0xffffff, disabled_color = 0x808080)
  return unless @visible

  color = (alpha << 24) | ((@enabled or @disabled_img) ? color : disabled_color)
  text_color = (alpha << 24) | (@enabled ? @text_color : @disabled_text_color)
  img = ((@enabled or @disabled_img.nil?) ? @img : @disabled_img)
  img.draw @x, @y, z_index, @scale_x, @scale_y, color
  @font.draw_text @text, @text_x, @text_y, z_index, @scale_x, @scale_y, text_color

  if @anchor1 and @anchor2
    selection_color = ((alpha / 2) << 24) | @selection_color
    G.window.draw_quad @nodes[@anchor1], @text_y, selection_color,
                       @nodes[@anchor2] + 1, @text_y, selection_color,
                       @nodes[@anchor2] + 1, @text_y + @font.height * @scale_y, selection_color,
                       @nodes[@anchor1], @text_y + @font.height * @scale_y, selection_color, z_index
  end

  if @cursor_visible
    if @cursor_img
      @cursor_img.draw @nodes[@cur_node] - (@cursor_img.width * @scale_x) / 2, @text_y, z_index, @scale_x, @scale_y
    else
      cursor_color = alpha << 24
      G.window.draw_quad @nodes[@cur_node], @text_y, cursor_color,
                         @nodes[@cur_node] + 1, @text_y, cursor_color,
                         @nodes[@cur_node] + 1, @text_y + @font.height * @scale_y, cursor_color,
                         @nodes[@cur_node], @text_y + @font.height * @scale_y, cursor_color, z_index
    end
  end
end

#enabled=(value) ⇒ Object

:nodoc:



973
974
975
976
# File 'lib/minigl/forms.rb', line 973

def enabled=(value) # :nodoc:
  @enabled = value
  unfocus unless @enabled
end

#focusObject

Grants focus to the text field, so that it allows keyboard input.



904
905
906
# File 'lib/minigl/forms.rb', line 904

def focus
  @active = true
end

#selected_textObject

Returns the currently selected text.



896
897
898
899
900
901
# File 'lib/minigl/forms.rb', line 896

def selected_text
  return '' if @anchor2.nil?
  min = @anchor1 < @anchor2 ? @anchor1 : @anchor2
  max = min == @anchor1 ? @anchor2 : @anchor1
  @text[min..max]
end

#set_position(x, y) ⇒ Object

Sets the position of the text field in the screen.

Parameters:

x

The new x-coordinate for the text field.

y

The new y-coordinate for the text field.



922
923
924
925
926
927
928
929
930
931
# File 'lib/minigl/forms.rb', line 922

def set_position(x, y)
  d_x = x - @x
  d_y = y - @y
  @x = x; @y = y
  @text_x += d_x
  @text_y += d_y
  @nodes.map! do |n|
    n + d_x
  end
end

#text=(value, trigger_changed = true) ⇒ Object

Sets the text of the text field to the specified value.

Parameters:

value

The new text to be set. If it’s longer than the max_length parameter used in the constructor, it will be truncated to max_length characters.



861
862
863
864
865
866
867
868
869
870
871
872
873
874
# File 'lib/minigl/forms.rb', line 861

def text=(value, trigger_changed = true)
  @text = value[0...@max_length]
  @nodes.clear; @nodes << @text_x
  x = @nodes[0]
  @text.chars.each { |char|
    x += @font.text_width(char) * @scale_x
    @nodes << x
  }
  @cur_node = @nodes.size - 1
  @anchor1 = nil
  @anchor2 = nil
  set_cursor_visible
  @on_text_changed.call @text, @params if trigger_changed && @on_text_changed
end

#unfocusObject

Removes focus from the text field, so that no keyboard input will be accepted.



910
911
912
913
914
915
# File 'lib/minigl/forms.rb', line 910

def unfocus
  @anchor1 = @anchor2 = nil
  @cursor_visible = false
  @cursor_timer = 0
  @active = false
end

#updateObject

Updates the text field, checking for mouse events and keyboard input.



688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
# File 'lib/minigl/forms.rb', line 688

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

#visible=(value) ⇒ Object

:nodoc:



978
979
980
981
# File 'lib/minigl/forms.rb', line 978

def visible=(value) # :nodoc:
  @visible = value
  unfocus unless @visible
end