Class: GlimR::TextInput

Inherits:
Label show all
Defined in:
lib/glimr/widgets/text_editor.rb

Overview

TextInput is a single-line text input widget.

Constant Summary collapse

@@xsel =
false

Constants included from Layoutable

Layoutable::DIMENSIONS

Instance Attribute Summary collapse

Attributes inherited from Image

#bound, #image

Attributes inherited from Widget

#focused, #hover

Attributes included from Layoutable

#align, #valign

Attributes inherited from Model

#geometry, #material, #shader, #texture, #transform

Attributes inherited from SceneObject

#children, #drawables, #mtime, #parent, #viewport

Attributes included from EventListener

#event_listeners, #listener_count

Instance Method Summary collapse

Methods inherited from Image

#create_colors, #create_normals, #create_texcoords, #create_vertices, #load, load, load_theme, #load_theme, #texture=, #update_geometry

Methods inherited from Widget

#activate, #blur, #focus, for, #key_down, #lock, #mouse_out, #mouse_over, #unlock

Methods included from Layoutable

#attach, #children_change, #constant_size?, #detach, #expand!, #expand?, #expand_height, #expand_to_max_height!, #expand_to_max_width!, #expand_width, #fit_height!, #fit_to_children!, #fit_width!, #free_height, #free_width, #full_depth, #full_height, #full_width, #inner_depth, #inner_height, #inner_width, #inspect, #layoutable_children, #margin, #margin=, #max_height=, #max_width=, #min_height=, #min_width=, #padding, #padding=, #parent=, #size_changing, size_changing_accessor, #tell_children_of_size_change, #x=, #y=

Methods inherited from Model

#absolute_transform, #apply, #inspect, #pop_state, #push_state

Methods inherited from SceneObject

#<<, #absolute_geometry, #absolute_material, #absolute_shader, #absolute_texture, #absolute_transform, #absolute_transform_for_drawing, #add_drawables, #apply, #attach, #clone, #detach, #detach_self, #inspect, #pop_state, #push_state, #remove_drawables, #render, #replace_node, #root, #touch!, #visible

Methods included from EventListener

#add_event_listener, #decrement_listener_count, #dispatch_event, #event_root, #increment_listener_count, #method_missing, #multicast_event, #process_event, #remove_event_listener

Constructor Details

#initialize(*a, &b) ⇒ TextInput

Returns a new instance of TextInput.



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
# File 'lib/glimr/widgets/text_editor.rb', line 68

def initialize(*a,&b)
  if a[0]
    txt = a[0][:text]
    a[0].delete(:text)
  end
  super(*a, &nil)
  @texture.pixels = "\000" * (@width*@height*4)
  @texture.width = @width
  @texture.height = @height
  @bound = @texture.bound
  update_geometry
  if a[0]
    self.text = txt if txt
  end
  @cursor.height = @height - 2
  @cursor.y = 1
  @cursor.z = -0.1
  attach @cursor
  @background.set_dimensions(@width, @height)
  @background.z = -0.2
  attach @background
  if block_given?
    self.submit_handler = b
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class GlimR::EventListener

Instance Attribute Details

#cursor_positionObject

Returns the value of attribute cursor_position.



48
49
50
# File 'lib/glimr/widgets/text_editor.rb', line 48

def cursor_position
  @cursor_position
end

#scroll_xObject

Returns the value of attribute scroll_x.



46
47
48
# File 'lib/glimr/widgets/text_editor.rb', line 46

def scroll_x
  @scroll_x
end

#scroll_yObject (readonly)

Returns the value of attribute scroll_y.



46
47
48
# File 'lib/glimr/widgets/text_editor.rb', line 46

def scroll_y
  @scroll_y
end

#selection_endObject

Returns the value of attribute selection_end.



48
49
50
# File 'lib/glimr/widgets/text_editor.rb', line 48

def selection_end
  @selection_end
end

#selection_startObject

Returns the value of attribute selection_start.



48
49
50
# File 'lib/glimr/widgets/text_editor.rb', line 48

def selection_start
  @selection_start
end

#submit_handlerObject

Returns the value of attribute submit_handler.



49
50
51
# File 'lib/glimr/widgets/text_editor.rb', line 49

def submit_handler
  @submit_handler
end

Instance Method Details

#as_alpha(pixels, alpha) ⇒ Object



330
331
332
333
334
335
336
337
# File 'lib/glimr/widgets/text_editor.rb', line 330

def as_alpha(pixels, alpha)
  i = 3
  while i < pixels.size
    pixels[i] = alpha[i-1]
    i += 4
  end
  pixels
end

#change!Object



251
252
253
254
# File 'lib/glimr/widgets/text_editor.rb', line 251

def change!
  dispatch_event(Event.new(:change, :text => @text))
  update_on_frame
end

#clear_selection(new_cursor_position = [@selection_start, @selection_end].min) ⇒ Object



226
227
228
229
230
231
# File 'lib/glimr/widgets/text_editor.rb', line 226

def clear_selection(new_cursor_position=[@selection_start, @selection_end].min)
  @selecting = false
  @text_selected = false
  @cursor.use_normal
  self.cursor_position = new_cursor_position
end

#click(o, e) ⇒ Object



161
162
163
164
165
166
167
168
169
170
# File 'lib/glimr/widgets/text_editor.rb', line 161

def click(o,e)
  if e.button == :left
    clear_selection if @text_selected
    self.cursor_position = cursor_position_closest_to(e.rx, e.ry)
  elsif e.button == :middle and @@xsel
    x_sel = IO.popen("#@@xsel -o", "r"){|f| f.read }
    replace_selection_with x_sel
    @cursor_position += x_sel.size
  end
end

#cursor_position_closest_to(cx, cy) ⇒ Object



233
234
235
236
237
238
239
240
241
242
243
# File 'lib/glimr/widgets/text_editor.rb', line 233

def cursor_position_closest_to(cx,cy)
  index = nil
  @text_offsets.each_with_index{|(x,y), i|
    if x + scroll_x > cx
      index = [i-1, 0].max
      break
    end
  }
  index ||= @text.size
  index
end

#default_configObject



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/glimr/widgets/text_editor.rb', line 51

def default_config
  super.merge(
    :fit_children => false,
    :align => :left,
    :text => "",
    :width => 150,
    :height => 16,
    :scroll_x => 0,
    :scroll_y => 0,
    :background => StretchableImage.load_theme("text_input_bg.png"),
    :cursor => TextCursor.new,
    :cursor_position => 0,
    :selection_start => 0,
    :selection_end => 0
  )
end

#draw_text(x_offset = @scroll_x, y_offset = @scroll_y) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/glimr/widgets/text_editor.rb', line 304

def draw_text x_offset=@scroll_x, y_offset=@scroll_y
  GC.disable
  w,h = @width, @height
  rmask = 0xff000000
  gmask = 0x00ff0000
  bmask = 0x0000ff00
  amask = 0x000000ff
  mask = SDL::Surface.new(
      SDL::SWSURFACE|SDL::SRCALPHA,
      w, h, 32,
      amask,bmask,gmask,rmask)
  mask.fill_rect(0,0, w,h, [0,0,0,255])
  @sdl_font.draw_blended_utf8(
    mask, text,
    x_offset, y_offset,
    255, 255, 255
  )
  image = SDL::Surface.new(
      SDL::SWSURFACE|SDL::SRCALPHA,
      w, h, 32,
      amask,bmask,gmask,rmask)
  image.fill_rect(0,0, w,h, color.map{|i|(i*255).to_i})
  texture.pixels = as_alpha(image.pixels, mask.pixels)
  GC.enable
end

#key_up(o, e) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/glimr/widgets/text_editor.rb', line 100

def key_up(o,e)
  return unless focused
  case e.key
  when :left
    clear_selection if @text_selected
    self.cursor_position -= 1
  when :right
    clear_selection if @text_selected
    self.cursor_position += 1
  when 8 # backspace
    if @text_selected
      replace_selection_with ""
    elsif self.cursor_position > 0
      @text[self.cursor_position-1] = ""
      self.text = @text
      @cursor_position -= 1
    end
  when 127 # delete
    if @text_selected
      replace_selection_with ""
    elsif self.cursor_position < @text.size
      @text[self.cursor_position] = ""
      self.text = @text
    end
  when 13 # enter
    submit
  else
    if @text_selected
      replace_selection_with e.key.chr
      cp = [@selection_start, @selection_end].min
    else
      cp = self.cursor_position
      @text.insert(cp, e.key.chr)
      self.text = @text
    end
    @cursor_position = cp + 1
  end
end

#layoutObject



280
281
# File 'lib/glimr/widgets/text_editor.rb', line 280

def layout
end

#mouse_down(o, e) ⇒ Object



172
173
174
175
176
177
178
# File 'lib/glimr/widgets/text_editor.rb', line 172

def mouse_down(o,e)
  if e.button == :left
    @sx, @sy = e.rx, e.ry
    @selection_start = @selection_end = cursor_position_closest_to(@sx, @sy)
  end
  super
end

#mouse_move(o, e) ⇒ Object



190
191
192
193
194
195
196
197
198
# File 'lib/glimr/widgets/text_editor.rb', line 190

def mouse_move(o,e)
  if @sx and @sy
    @selecting = true
    @sx += e.dx
    @sy += e.dy
    @selection_end = cursor_position_closest_to(@sx, @sy)
    update_selection
  end
end

#mouse_up(o, e) ⇒ Object



180
181
182
183
184
185
186
187
188
# File 'lib/glimr/widgets/text_editor.rb', line 180

def mouse_up(o,e)
  super unless @selecting
  if e.button == :left and @selecting
    @selecting = false
    @selection_end = cursor_position_closest_to(@sx, @sy)
    update_selection
  end
  @sx = @sy = false
end

#replace_selection_with(str) ⇒ Object



143
144
145
146
147
# File 'lib/glimr/widgets/text_editor.rb', line 143

def replace_selection_with str
  @text[selection_range] = str
  clear_selection
  self.text = @text
end

#selectionObject



157
158
159
# File 'lib/glimr/widgets/text_editor.rb', line 157

def selection
  @text[selection_range]
end

#selection_rangeObject



149
150
151
152
153
154
155
# File 'lib/glimr/widgets/text_editor.rb', line 149

def selection_range
  if @selection_start > @selection_end
    (@selection_end...@selection_start) # up until selection start
  else
    (@selection_start..@selection_end)
  end
end

#submitObject



139
140
141
# File 'lib/glimr/widgets/text_editor.rb', line 139

def submit
  dispatch_event(Event.new(:submit, :text => @text))
end

#text=(text) ⇒ Object



245
246
247
248
249
# File 'lib/glimr/widgets/text_editor.rb', line 245

def text= text
  @text = text
  @text_changed = true
  change!
end

#update_on_frameObject



256
257
258
259
260
# File 'lib/glimr/widgets/text_editor.rb', line 256

def update_on_frame
  if not @updater
    @updater = on_frame(:update_text)
  end
end

#update_selectionObject



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/glimr/widgets/text_editor.rb', line 200

def update_selection
  if @@xsel
    IO.popen("#@@xsel -i", "w"){|f| f.write selection }
  end
  ss = @text_offsets[@selection_start][0]
  se = @text_offsets[@selection_end][0]
  d = se - ss
  self.cursor_position = @selection_end
  ex = @cursor.x
  ew = @cursor.width
  if d > 0 # end is after beginning
    @cursor.x = [0, ex - d].max # ex - d is first character x of selection
    @cursor.width = ex + ew - @cursor.x # width is distance from right side of end char to current cursor.x
  else # end is before beginning
    # cursor.x is where it should be, width is -d
    @cursor.x = ex
    @cursor.width = [@width - ex, -d].min
  end
  @cursor.use_insert
  @text_selected = true
  dispatch_event(
    Event.new(
      :select, :selection => selection,
      :start => @selection_start, :end => @selection_end))
end

#update_text(o, e) ⇒ Object



283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/glimr/widgets/text_editor.rb', line 283

def update_text(o,e)
  if @text_changed
    @text_offsets = false
    @text_changed = false
  end
  update_text_offsets
  self.cursor_position = self.cursor_position
  update_selection if @selecting
  draw_text
  touch!
  remove_event_listener(:frame, @updater)
  @updater = false
end

#update_text_offsetsObject



297
298
299
300
301
302
# File 'lib/glimr/widgets/text_editor.rb', line 297

def update_text_offsets
  @sdl_font = SDL::TTF.open(font, size)
  @text_offsets ||= (0..text.size).map{|i|
    @sdl_font.text_size(text[0,i])
  }
end