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

#enabled, #h, #params, #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, &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.

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.



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/minigl/forms.rb', line 412

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, &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)
    x = x[:x]
  end

  super x, y, font, text, text_color, disabled_text_color
  @img = Res.img img
  @w = @img.width
  @h = @img.height
  @cursor_img = Res.img(cursor_img) if cursor_img
  @disabled_img = Res.img(disabled_img) if disabled_img
  @max_length = max_length
  @active = active
  @text_x = x + margin_x
  @text_y = y + margin_y
  @selection_color = selection_color

  @nodes = [x + margin_x]
  @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!



358
359
360
# File 'lib/minigl/forms.rb', line 358

def locale
  @locale
end

#textObject

The current text inside the text field.



354
355
356
# File 'lib/minigl/forms.rb', line 354

def text
  @text
end

Instance Method Details

#draw(alpha = 0xff, z_index = 0) ⇒ 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.



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
# File 'lib/minigl/forms.rb', line 730

def draw(alpha = 0xff, z_index = 0)
  return unless @visible

  color = (alpha << 24) | ((@enabled or @disabled_img) ? 0xffffff : 0x808080)
  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, 1, 1, color
  @font.draw @text, @text_x, @text_y, z_index, 1, 1, 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, selection_color,
                       @nodes[@anchor1], @text_y + @font.height, selection_color, z_index
  end

  if @cursor_visible
    if @cursor_img
      @cursor_img.draw @nodes[@cur_node] - @cursor_img.width / 2, @text_y, z_index
    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, cursor_color,
                         @nodes[@cur_node], @text_y + @font.height, cursor_color, z_index
    end
  end
end

#enabled=(value) ⇒ Object

:nodoc:



760
761
762
763
# File 'lib/minigl/forms.rb', line 760

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

#focusObject

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



694
695
696
# File 'lib/minigl/forms.rb', line 694

def focus
  @active = true
end

#selected_textObject

Returns the currently selected text.



686
687
688
689
690
691
# File 'lib/minigl/forms.rb', line 686

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.



712
713
714
715
716
717
718
719
720
721
# File 'lib/minigl/forms.rb', line 712

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

#unfocusObject

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



700
701
702
703
704
705
# File 'lib/minigl/forms.rb', line 700

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.



478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
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
# File 'lib/minigl/forms.rb', line 478

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:



765
766
767
768
# File 'lib/minigl/forms.rb', line 765

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