Class: RNDK::Entry

Inherits:
Widget show all
Defined in:
lib/rndk/entry.rb

Overview

A text-entry box with a label and an entry field.

Keybindings

Left Arrow:: Moves the cursor to the left. CTRL-B:: Moves the cursor to the left. Right Arrow:: Moves the cursor to the right. CTRL-F:: Moves the cursor to the right. Delete:: Deletes the character at the cursor. Backspace:: Deletes the character before cursor, moves cursor left. CTRL-V:: Pastes from the paste buffer into the widget CTRL-X:: Cuts the contents from the widget into the paste buffer. CTRL-Y:: Copies the contents of the widget into the paste buffer. CTRL-U:: Erases the contents of the widget. CTRL-A:: Moves the cursor to the beginning of the entry field. CTRL-E:: Moves the cursor to the end of the entry field. CTRL-T:: Transposes the character under the cursor with the character to the right. Return:: Exits the widget and returns the text typed into the field. It also sets the widget data exitType to :NORMAL. Tab:: Exits the widget and returns the text typed into the field. It also sets the widget data exitType to :NORMAL. Escape:: Exits the widget and returns nil. It also sets the widget data exitType to :ESCAPE_HIT. Ctrl-L:: Refreshes the screen.

Behavior

When passing the disp_type argument to Entry#initialize, you can modify the Entry behavior when receiving chars from the user.

Send one of those for an action:

:CHAR:: Only accepts alphabetic characters. :LCHAR:: Only accepts alphabetic characters. Maps the character to lower case when a character has been accepted. :UCHAR:: Only accepts alphabetic characters. Maps the character to upper case when a character has been accepted. :HCHAR:: Only accepts alphabetic characters. Displays a period (.) when a character has been accepted. :UHCHAR:: Only accepts alphabetic characters. Displays a period (.) and maps the character to upper case when a character has been accepted. :LHCHAR:: Only accepts alphabetic characters. Displays a period (.) and maps the character to lower case when a character has been accepted. :INT:: Only accepts numeric characters. :HINT:: Only accepts numeric characters. Displays a period (.) when a character has been accepted. :MIXED:: Accepts any character types. :LMIXED:: Accepts any character types. Maps the char- acter to lower case when an alphabetic char- acter has been accepted. :UMIXED:: Accepts any character types. Maps the char- acter to upper case when an alphabetic char- acter has been accepted. :HMIXED:: Accepts any character types. Displays a period (.) when a character has been accepted. :LHMIXED:: Accepts any character types. Displays a period (.) and maps the character to lower case when a character has been accepted. :UHMIXED:: Accepts any character types. Displays a period (.) and maps the character to upper case when a character has been accepted. :VIEWONLY:: Uneditable field.

Instance Attribute Summary collapse

Attributes inherited from Widget

#BXAttr, #HZChar, #LLChar, #LRChar, #ULChar, #URChar, #VTChar, #accepts_focus, #binding_list, #border_size, #box, #exit_type, #has_focus, #is_visible, #screen, #screen_index, #supported_signals, #widget_type

Instance Method Summary collapse

Methods inherited from Widget

#Screen_XPOS, #Screen_YPOS, #after_processing, #before_processing, #bind_key, #bind_signal, #bindable_widget, #clean_bindings, #clean_title, #draw_title, #get_box, #getch, #is_bound?, #refresh_data, #run_key_binding, #run_signal_binding, #save_data, #setBXattr, #setHZchar, #setLLchar, #setLRchar, #setULchar, #setURchar, #setVTchar, #set_box, #set_exit_type, #set_title, #unbind_key, #valid?, #valid_type?

Constructor Details

#initialize(screen, config = {}) ⇒ Entry

Creates an Entry Widget.

Arguments

  • x is the x position - can be an integer or RNDK::LEFT, RNDK::RIGHT, RNDK::CENTER.
  • y is the y position - can be an integer or RNDK::TOP, RNDK::BOTTOM, RNDK::CENTER.
  • title can be more than one line - just split them with \ns.
  • label is the String that will appear on the label of the Entry field.
  • field_color is the attribute/color of the characters that are typed in.
  • filler_char is the character to display on the empty spaces in the entry field.
  • disp_type tells how the entry field will behave. See main Entry documentation.
  • field_width is the width of the field. It it's 0, will be created with full width of the screen. If it's a negative value, will create with full width minus that value.
  • min is the minimum number of characters the user must insert before can exit the entry field.
  • max is the maximum number of characters the user can enter on the entry field.
  • box if the Widget is drawn with a box outside it.
  • shadow turns on/off the shadow around the Widget.


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/rndk/entry.rb', line 116

def initialize(screen, config={})
  super()
  @widget_type = :entry
  @supported_signals += [:before_input, :after_input]

  x            = 0
  y            = 0
  title        = "entry"
  label        = "label"
  field_color  = RNDK::Color[:normal]
  filler       = '.'
  disp_type    = :MIXED
  field_width  = 0
  initial_text = ""
  min          = 0
  max          = 9001
  box          = true
  shadow       = false

  config.each do |key, val|
    x            = val if key == :x
    y            = val if key == :y
    title        = val if key == :title
    label        = val if key == :label
    field_color  = val if key == :field_color
    filler       = val if key == :filler
    disp_type    = val if key == :disp_type
    field_width  = val if key == :field_width
    initial_text = val if key == :initial_text
    min          = val if key == :min
    max          = val if key == :max
    box          = val if key == :box
    shadow       = val if key == :shadow
  end

  parent_width  = Ncurses.getmaxx screen.window
  parent_height = Ncurses.getmaxy screen.window

  field_width = field_width
  box_width   = 0

  xpos = x
  ypos = y

  self.set_box box
  box_height = @border_size*2 + 1

  # If the field_width is a negative value, the field_width
  # WILL be COLS-field_width, otherwise the field_width will
  # be the given width.
  field_width = RNDK.set_widget_dimension(parent_width, field_width, 0)
  box_width = field_width + 2*@border_size

  # Set some basic values of the entry field.
  @label = 0
  @label_len = 0
  @label_win = nil

  # Translate the label string to a chtype array
  if !(label.nil?) && label.size > 0
    label_len = [@label_len]
    @label = RNDK.char2Chtype(label, label_len, [])
    @label_len = label_len[0]
    box_width += @label_len
  end

  old_width = box_width
  box_width = self.set_title(title, box_width)
  horizontal_adjust = (box_width - old_width) / 2

  box_height += @title_lines

  # Make sure we didn't extend beyond the dimensinos of the window.
  box_width = [box_width, parent_width].min
  box_height = [box_height, parent_height].min
  field_width = [field_width,
      box_width - @label_len - 2 * @border_size].min

  # Rejustify the x and y positions if we need to.
  xtmp = [xpos]
  ytmp = [ypos]
  RNDK.alignxy(screen.window, xtmp, ytmp, box_width, box_height)
  xpos = xtmp[0]
  ypos = ytmp[0]

  # Make the label window.
  @win = Ncurses.subwin(screen.window, box_height, box_width, ypos, xpos)
  if @win.nil?
    self.destroy
    return nil
  end
  Ncurses.keypad(@win, true)

  # Make the field window.
  @field_win = Ncurses.subwin(@win,
                              1,
                              field_width,
                              ypos + @title_lines + @border_size,
                              xpos + @label_len + horizontal_adjust + @border_size)

  if @field_win.nil?
    self.destroy
    return nil
  end
  Ncurses.keypad(@field_win, true)

  # make the label win, if we need to
  if !(label.nil?) && label.size > 0
    @label_win = Ncurses.subwin(@win, 1, @label_len,
        ypos + @title_lines + @border_size,
        xpos + horizontal_adjust + @border_size)
  end

  # cleanChar (entry->info, max + 3, '\0');
  @info = ''
  @info_width = max + 3

  # Set up the rest of the structure.
  @screen = screen
  @parent = screen.window
  @shadow_win = nil
  @field_color = field_color
  @field_width = field_width
  @filler = filler
  @hidden = filler
  @input_window = @field_win
  @accepts_focus = true
  @data_ptr = nil
  @shadow = shadow
  @screen_col = 0
  @left_char = 0
  @min = min
  @max = max
  @box_width = box_width
  @box_height = box_height
  @disp_type = disp_type
  @callbackfn = lambda do |entry, character|
    plainchar = Display.filter_by_display_type(entry, character)

    if plainchar == Ncurses::ERR || entry.info.size >= entry.max
      RNDK.beep
    else
      # Update the screen and pointer
      if entry.screen_col != entry.field_width - 1
        front = (entry.info[0...(entry.screen_col + entry.left_char)] or '')
        back  = (entry.info[(entry.screen_col + entry.left_char)..-1] or '')

        entry.info = front + plainchar.chr + back
        entry.screen_col += 1

      else
        # Update the character pointer.
        entry.info << plainchar
        # Do not update the pointer if it's the last character
        entry.left_char += 1 if (entry.info.size < entry.max)
      end

      # Update the entry field.
      entry.drawField
    end
  end

  self.set_text initial_text

  # Do we want a shadow?
  if shadow
    @shadow_win = Ncurses.subwin(screen.window,
                                 box_height,
                                 box_width,
                                 ypos + 1,
                                 xpos + 1)
  end

  screen.register(:entry, self)
end

Instance Attribute Details

#box_heightObject (readonly)

Returns the value of attribute box_height.



84
85
86
# File 'lib/rndk/entry.rb', line 84

def box_height
  @box_height
end

#box_widthObject (readonly)

Returns the value of attribute box_width.



84
85
86
# File 'lib/rndk/entry.rb', line 84

def box_width
  @box_width
end

#field_widthObject (readonly)

Returns the value of attribute field_width.



84
85
86
# File 'lib/rndk/entry.rb', line 84

def field_width
  @field_width
end

#infoObject

Returns the value of attribute info.



83
84
85
# File 'lib/rndk/entry.rb', line 83

def info
  @info
end

#left_charObject

Returns the value of attribute left_char.



83
84
85
# File 'lib/rndk/entry.rb', line 83

def left_char
  @left_char
end

#maxObject (readonly)

Returns the value of attribute max.



84
85
86
# File 'lib/rndk/entry.rb', line 84

def max
  @max
end

#minObject (readonly)

Returns the value of attribute min.



85
86
87
# File 'lib/rndk/entry.rb', line 85

def min
  @min
end

#screen_colObject

Returns the value of attribute screen_col.



83
84
85
# File 'lib/rndk/entry.rb', line 83

def screen_col
  @screen_col
end

#winObject (readonly)

Returns the value of attribute win.



84
85
86
# File 'lib/rndk/entry.rb', line 84

def win
  @win
end

Instance Method Details

#activate(actions = []) ⇒ Object

Activates the Entry Widget, letting the user interact with it.

actions is an Array of characters. If it's non-null, will #inject each char on it into the Widget.

Returns:

  • The text currently inside the entry field (and exit_type will be :NORMAL) or nil (and exit_type will be :ESCAPE_HIT).



300
301
302
303
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
329
330
331
332
333
# File 'lib/rndk/entry.rb', line 300

def activate(actions=[])
  input = 0
  ret = 0

  # Draw the widget.
  self.draw

  if actions.nil? or actions.size == 0
    while true
      input = self.getch

      # Inject the character into the widget.
      ret = self.inject(input)
      if @exit_type != :EARLY_EXIT
        return ret
      end
    end
  else
    # Inject each character one at a time.
    actions.each do |action|
      ret = self.inject(action)
      if @exit_type != :EARLY_EXIT
        return ret
      end
    end
  end

  # Make sure we return the correct info.
  if @exit_type == :NORMAL
    return @info
  else
    return 0
  end
end

#cleanObject

Clears the text from the entry field.



515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
# File 'lib/rndk/entry.rb', line 515

def clean
  width = @field_width

  @info = ''

  # Clean the entry screen field.
  Ncurses.mvwhline(@field_win, 0, 0, @filler.ord, width)

  # Reset some variables
  @screen_col = 0
  @left_char = 0

  # Refresh the entry field.
  Ncurses.wrefresh @field_win
end

#destroyObject

See Also:



571
572
573
574
575
576
577
578
579
580
581
582
# File 'lib/rndk/entry.rb', line 571

def destroy
  self.clean_title

  RNDK.window_delete(@field_win)
  RNDK.window_delete(@label_win)
  RNDK.window_delete(@shadow_win)
  RNDK.window_delete(@win)

  self.clean_bindings

  @screen.unregister self
end

#drawObject

Draws the Widget on the Screen.

If box is true, it is drawn with a box.



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
# File 'lib/rndk/entry.rb', line 534

def draw
  # Did we ask for a shadow?
  Draw.drawShadow @shadow_win unless @shadow_win.nil?

  # Box the widget if asked.
  Draw.drawObjBox(@win, self) if @box

  self.draw_title @win
  Ncurses.wrefresh @win

  # Draw in the label to the widget.
  unless @label_win.nil?
    Draw.writeChtype(@label_win,
                     0,
                     0,
                     @label,
                     RNDK::HORIZONTAL,
                     0,
                     @label_len)

    Ncurses.wrefresh @label_win
  end

  self.drawField
end

#eraseObject

See Also:



561
562
563
564
565
566
567
568
# File 'lib/rndk/entry.rb', line 561

def erase
  if self.valid?
    RNDK.window_erase(@field_win)
    RNDK.window_erase(@label_win)
    RNDK.window_erase(@win)
    RNDK.window_erase(@shadow_win)
  end
end

#focusObject



676
677
678
679
# File 'lib/rndk/entry.rb', line 676

def focus
  Ncurses.wmove(@field_win, 0, @screen_col)
  Ncurses.wrefresh @field_win
end

#get_filler_charObject



640
641
642
# File 'lib/rndk/entry.rb', line 640

def get_filler_char
  @filler
end

#get_hidden_charObject



652
653
654
# File 'lib/rndk/entry.rb', line 652

def get_hidden_char
  @hidden
end

#get_maxObject



621
622
623
# File 'lib/rndk/entry.rb', line 621

def get_max
  @max
end

#get_minObject



631
632
633
# File 'lib/rndk/entry.rb', line 631

def get_min
  @min
end

#get_textObject

Returns the current text on the entry field.



611
612
613
# File 'lib/rndk/entry.rb', line 611

def get_text
  return @info
end

#inject(input) ⇒ Object

See Also:



336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
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
476
477
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
# File 'lib/rndk/entry.rb', line 336

def inject input
  pp_return = true
  ret = 1
  complete = false

  # Set the exit type
  self.set_exit_type(0)

  # Refresh the widget field.
  self.drawField

  # Check if there is a pre-process function to be called.
  keep_going = self.run_signal_binding(:before_input, input)

  if keep_going

    # Check a predefined binding
    if self.is_bound? input
      self.run_key_binding input
      #complete = true

    else
      curr_pos = @screen_col + @left_char

      case input
      when Ncurses::KEY_UP, Ncurses::KEY_DOWN
        RNDK.beep

      when Ncurses::KEY_HOME
        @left_char = 0
        @screen_col = 0
        self.drawField

      when RNDK::TRANSPOSE
        if curr_pos >= @info.size - 1
          RNDK.beep
        else
          holder = @info[curr_pos]
          @info[curr_pos] = @info[curr_pos + 1]
          @info[curr_pos + 1] = holder
          self.drawField
        end

      when Ncurses::KEY_END
        self.setPositionToEnd
        self.drawField

      when Ncurses::KEY_LEFT
        if curr_pos <= 0
          RNDK.beep
        elsif @screen_col == 0
          # Scroll left.
          @left_char -= 1
          self.drawField
        else
          @screen_col -= 1
          Ncurses.wmove(@field_win, 0, @screen_col)
        end

      when Ncurses::KEY_RIGHT
        if curr_pos >= @info.size
          RNDK.beep
        elsif @screen_col == @field_width - 1
          # Scroll to the right.
          @left_char += 1
          self.drawField
        else
          # Move right.
          @screen_col += 1
          Ncurses.wmove(@field_win, 0, @screen_col)
        end

      when Ncurses::KEY_BACKSPACE, Ncurses::KEY_DC
        if @disp_type == :VIEWONLY
          RNDK.beep
        else
          success = false
          if input == Ncurses::KEY_BACKSPACE
            curr_pos -= 1
          end

          if curr_pos >= 0 && @info.size > 0
            if curr_pos < @info.size
              @info = @info[0...curr_pos] + @info[curr_pos+1..-1]
              success = true
            elsif input == Ncurses::KEY_BACKSPACE
              @info = @info[0...-1]
              success = true
            end
          end

          if success
            if input == Ncurses::KEY_BACKSPACE
              if @screen_col > 0
                @screen_col -= 1
              else
                @left_char -= 1
              end
            end
            self.drawField
          else
            RNDK.beep
          end
        end
      when RNDK::KEY_ESC
        self.set_exit_type(input)
        complete = true

      when RNDK::ERASE
        if @info.size != 0
          self.clean
          self.drawField
        end

      when RNDK::CUT
        if @info.size != 0
          @@g_paste_buffer = @info.clone
          self.clean
          self.drawField
        else
          RNDK.beep
        end

      when RNDK::COPY
        if @info.size != 0
          @@g_paste_buffer = @info.clone
        else
          RNDK.beep
        end

      when RNDK::PASTE
        if @@g_paste_buffer != 0
          self.set_text(@@g_paste_buffer)
          self.drawField
        else
          RNDK.beep
        end

      when RNDK::KEY_TAB, RNDK::KEY_RETURN, Ncurses::KEY_ENTER
        if @info.size >= @min
          self.set_exit_type(input)
          ret = @info
          complete = true
        else
          RNDK.beep
        end

      when Ncurses::ERR
        self.set_exit_type(input)
        complete = true

      when RNDK::REFRESH
        @screen.erase
        @screen.refresh
      else
        @callbackfn.call(self, input)
      end
    end

    # Should we do a post-process?
    self.run_signal_binding(:after_input) if not complete
  end

  unless complete
    self.set_exit_type(0)
  end

  @result_data = ret
  return ret
end

#move(x, y, relative, refresh_flag) ⇒ Object

See Also:



508
509
510
511
512
# File 'lib/rndk/entry.rb', line 508

def move(x, y, relative, refresh_flag)
  windows = [@win, @field_win, @label_win, @shadow_win]

  self.move_specific(x, y, relative, refresh_flag, windows, [])
end

#positionObject

See Also:



687
688
689
# File 'lib/rndk/entry.rb', line 687

def position
  super @win
end

#set(text, min, max, box) ⇒ Object

Sets multiple attributes of the Widget.

See Entry#initialize.



587
588
589
590
591
592
593
594
# File 'lib/rndk/entry.rb', line 587

def set(text, min, max, box)
  self.set_text text
  self.set_min min
  self.set_max max

  ## FIXME TODO
  ## what about the `box`?
end

#set_bg_color(attrib) ⇒ Object

Sets the background attribute/color of the widget.



657
658
659
660
661
662
# File 'lib/rndk/entry.rb', line 657

def set_bg_color attrib
  Ncurses.wbkgd(@win, attrib)
  Ncurses.wbkgd(@field_win, attrib)

  @label_win.wbkgd(attrib) unless @label_win.nil?
end

#set_filler_char(filler_char) ⇒ Object

Sets the character to draw unused space on the field.



636
637
638
# File 'lib/rndk/entry.rb', line 636

def set_filler_char(filler_char)
  @filler = filler_char
end

#set_hidden_char(char) ⇒ Object

Sets the character to hide input when a hidden type is used.

See Entry#initialize



648
649
650
# File 'lib/rndk/entry.rb', line 648

def set_hidden_char char
  @hidden = char
end

#set_highlight(highlight, cursor) ⇒ Object

Sets the background attribute/color of the entry field.

cursor tells if we hide the blinking cursor or not. See Ncurses#curs_set.



668
669
670
671
672
673
674
# File 'lib/rndk/entry.rb', line 668

def set_highlight(highlight, cursor)
  Ncurses.wbkgd(@field_win, highlight)
  @field_color = highlight
  Ncurses.curs_set cursor

  # FIXME(original) - if (cursor) { move the cursor to this widget }
end

#set_max(max) ⇒ Object

Sets the maximum length of the string that will be accepted.



617
618
619
# File 'lib/rndk/entry.rb', line 617

def set_max max
  @max = max
end

#set_min(min) ⇒ Object

Sets the minimum length of the string that will be accepted.



627
628
629
# File 'lib/rndk/entry.rb', line 627

def set_min min
  @min = min
end

#set_text(new_value) ⇒ Object

Sets the current text on the entry field.



597
598
599
600
601
602
603
604
605
606
607
608
# File 'lib/rndk/entry.rb', line 597

def set_text new_value
  if new_value.nil?
    @info = ''

    @left_char = 0
    @screen_col = 0
  else
    @info = new_value.clone

    self.setPositionToEnd
  end
end

#setCB(callback) ⇒ Object

Note:

Unless you're very low-level and know what you're doing you shouldn't need this.

Allows the programmer to set a different widget input handler.



695
696
697
# File 'lib/rndk/entry.rb', line 695

def setCB(callback)
  @callbackfn = callback
end

#unfocusObject



681
682
683
684
# File 'lib/rndk/entry.rb', line 681

def unfocus
  self.draw
  Ncurses.wrefresh @field_win
end