-
Notifications
You must be signed in to change notification settings - Fork 0
/
TextInput.rb
111 lines (111 loc) · 4.27 KB
/
TextInput.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
require 'gosu'
class TextField < Gosu::TextInput
# Some constants that define our appearance.
INACTIVE_COLOR = 0xcc666666
ACTIVE_COLOR = 0xccff6666
SELECTION_COLOR = 0xcc0000ff
CARET_COLOR = 0xffffffff
PADDING = 5
attr_reader :x, :y
def initialize(window, font, x, y)
# TextInput's constructor doesn't expect any arguments.
super()
@window, @font, @x, @y = window, font, x, y
# Start with a self-explanatory text in each field.
self.text = "Click to change text"
end
# Example filter method. You can truncate the text to employ a length limit (watch out
# with Ruby 1.8 and UTF-8!), limit the text to certain characters etc.
def filter text
text.upcase
end
def draw
# Depending on whether this is the currently selected input or not, change the
# background's color.
if @window.text_input == self then
background_color = ACTIVE_COLOR
else
background_color = INACTIVE_COLOR
end
@window.draw_quad(x - PADDING, y - PADDING, background_color,
x + width + PADDING, y - PADDING, background_color,
x - PADDING, y + height + PADDING, background_color,
x + width + PADDING, y + height + PADDING, background_color, 0)
# Calculate the position of the caret and the selection start.
pos_x = x + @font.text_width(self.text[0...self.caret_pos])
sel_x = x + @font.text_width(self.text[0...self.selection_start])
# Draw the selection background, if any; if not, sel_x and pos_x will be
# the same value, making this quad empty.
@window.draw_quad(sel_x, y, SELECTION_COLOR,
pos_x, y, SELECTION_COLOR,
sel_x, y + height, SELECTION_COLOR,
pos_x, y + height, SELECTION_COLOR, 0)
# Draw the caret; again, only if this is the currently selected field.
if @window.text_input == self then
@window.draw_line(pos_x, y, CARET_COLOR,
pos_x, y + height, CARET_COLOR, 0)
end
# Finally, draw the text itself!
@font.draw(self.text, x, y, 0)
end
# This text field grows with the text that's being entered.
# (Usually one would use clip_to and scroll around on the text field.)
def width
@font.text_width(self.text)
end
def height
@font.height
end
# Hit-test for selecting a text field with the mouse.
def under_point?(mouse_x, mouse_y)
mouse_x > x - PADDING and mouse_x < x + width + PADDING and
mouse_y > y - PADDING and mouse_y < y + height + PADDING
end
# Tries to move the caret to the position specifies by mouse_x
def move_caret(mouse_x)
# Test character by character
1.upto(self.text.length) do |i|
if mouse_x < x + @font.text_width(text[0...i]) then
self.caret_pos = self.selection_start = i - 1;
return
end
end
# Default case: user must have clicked the right edge
self.caret_pos = self.selection_start = self.text.length
end
end
class TextInputWindow < Gosu::Window
def initialize
super(300, 200, false)
self.caption = "Text Input Example"
font = Gosu::Font.new(self, Gosu::default_font_name, 20)
# Set up an array of three text fields.
@text_fields = Array.new(3) { |index| TextField.new(self, font, 50, 30 + index * 50) }
@cursor = Gosu::Image.new(self, "media/tile.png", false)
end
def draw
@text_fields.each { |tf| tf.draw }
@cursor.draw(mouse_x, mouse_y, 0)
end
def button_down(id)
if id == Gosu::KbTab then
# Tab key will not be 'eaten' by text fields; use for switching through
# text fields.
index = @text_fields.index(self.text_input) || -1
self.text_input = @text_fields[(index + 1) % @text_fields.size]
elsif id == Gosu::KbEscape then
# Escape key will not be 'eaten' by text fields; use for deselecting.
if self.text_input then
self.text_input = nil
else
close
end
elsif id == Gosu::MsLeft then
# Mouse click: Select text field based on mouse position.
self.text_input = @text_fields.find { |tf| tf.under_point?(mouse_x, mouse_y) }
# Advanced: Move caret to clicked position
self.text_input.move_caret(mouse_x) unless self.text_input.nil?
end
end
end
TextInputWindow.new.show