Class: RNDK::Slider

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

Overview

Visual slider box with a label.

Keybindings

Down Arrow:: Decrements the field by the normal decrement value. Up Arrow:: Increments the field by the normal increment value. u:: Increments the field by the normal increment value. Prev Page:: Decrements the field by the accelerated decrement value. U:: Decrements the field by the accelerated decrement value. Ctrl-B:: Decrements the field by the accelerated decrement value. Next Page:: Increments the field by the accelerated increment value. D:: Increments the field by the accelerated increment value. Ctrl-F:: Increments the field by the accelerated increment value. Home:: Sets the value to the minimum value. g:: Sets the value to the minimum value. End:: Sets the value to the maximum value. G:: Sets the value to the maximum value. $:: Sets the value to the maximum value. Return:: Exits the widget and returns the current value. This also sets the widget data exit_type to :NORMAL. Tab:: Exits the widget and returns the current value. This also sets the widget data exit_type to :NORMAL. Escape:: Exits the widget and returns nil. Also sets the widget data exit_type to :ESCAPE_HIT. Ctrl-L:: Refreshes the screen.

If the cursor is not pointing to the field's value, the folminimuming key bindings apply.

You may use the left/right arrows to move the cursor onto the field's value and modify it by typing characters to replace the digits and sign.

Left Arrow:: Decrements the scale by the normal value. Right Arrow:: Increments the scale by the normal value. d:: Decrements the scale by the normal value. D:: Increments the scale by the accelerated value. -:: Decrements the scale by the normal value. +:: Increments the scale by the normal value. 0:: Sets the scale to the minimum value.

Direct Known Subclasses

Fslider

Instance Attribute Summary

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

Class Method Summary collapse

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 = {}) ⇒ Slider

Creates a new Slider Widget.

  • 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 label of the slider field.
  • filler is the character to draw the slider bar. You can combine it with colors too - use the pipe ('|') operator to combine Ncurses attributes with RNDK Colors.
  • 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.
  • start is the initial value of the widget.
  • minimum/maximum are the minimum and maximum values of the slider.
  • inc is the increment value.
  • fast_inc is the accelerated increment value.
  • box if the Widget is drawn with a box outside it.
  • shadow turns on/off the shadow around the Widget.


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

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

  x           = 0
  y           = 0
  title       = "slider"
  label       = "label"
  filler      = ' '.ord | RNDK::Color[:reverse]
  field_width = 0
  start       = 0
  minimum     = 0
  maximum     = 100
  increment   = 1
  fast_increment    = 5
  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
    filler      = val if key == :filler
    field_width = val if key == :field_width
    start       = val if key == :start
    minimum     = val if key == :minimum
    maximum     = val if key == :maximum
    increment   = val if key == :inc
    fast_increment    = val if key == :fast_inc
    box         = val if key == :box
    shadow      = val if key == :shadow
  end

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

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

  # Set some basic values of the widget's data field.
  @label = []
  @label_len = 0
  @label_win = nil
  maximum_value_len = self.formattedSize maximum

  # If the field_width is a negative will be COLS-field_width,
  # otherwise field_width will be the given width.
  field_width = RNDK.set_widget_dimension(parent_width, field_width, 0)

  # Translate the label string to a chtype array.
  if !(label.nil?) && label.size > 0
    label_len = []
    @label = RNDK.char2Chtype(label, label_len, [])
    @label_len = label_len[0]
    box_width = @label_len + field_width +
        maximum_value_len + 2 * @border_size
  else
    box_width = field_width + maximum_value_len + 2 * @border_size
  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 dimensions 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 - maximum_value_len - 1].min

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

  # Make the widget's window.
  @win = Ncurses.newwin(box_height, box_width, ypos, xpos)

  # Is the main window nil?
  if @win.nil?
    self.destroy
    return nil
  end

  # Create the widget's label window.
  if @label.size > 0
    @label_win = Ncurses.subwin(@win,
                                1,
                                @label_len,
                                ypos + @title_lines + @border_size,
                                xpos + horizontal_adjust + @border_size)
    if @label_win.nil?
      self.destroy
      return nil
    end
  end

  # Create the widget's data field window.
  @field_win = Ncurses.subwin(@win,
                              1,
                              field_width + maximum_value_len - 1,
                              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)
  Ncurses.keypad(@win, true)

  # Create the widget's data field.
  @screen = screen
  @window = screen.window
  @shadow_win = nil
  @box_width = box_width
  @box_height = box_height
  @field_width = field_width - 1
  @filler = filler
  @minimum = minimum
  @maximum = maximum
  @current = start
  @increment = increment
  @fast_increment = fast_increment
  @accepts_focus = true
  @input_window = @win
  @shadow = shadow
  @field_edit = 0

  # Set the start value.
  if start < minimum
    @current = minimum
  end

  # Do we want a shadow?
  if shadow
    @shadow_win = Ncurses.newwin(box_height,
                                 box_width,
                                 ypos + 1,
                                 xpos + 1)
    if @shadow_win.nil?
      self.destroy
      return nil
    end
  end

  # Setup the key bindings.
  self.bind_key('u') { self.increment @increment      }
  self.bind_key('U') { self.increment @fast_increment }
  self.bind_key('g') { @current = @minimum            }
  self.bind_key('^') { @current = @minimum            }
  self.bind_key('G') { @current = @maximum            }
  self.bind_key('$') { @current = @maximum            }

  screen.register(@widget_type, self)
end

Class Method Details

.Decrement(value, by) ⇒ Object



373
374
375
376
377
378
379
# File 'lib/rndk/slider.rb', line 373

def self.Decrement(value, by)
  if value - by < value
    value - by
  else
    value
  end
end

.Increment(value, by) ⇒ Object



381
382
383
384
385
386
387
# File 'lib/rndk/slider.rb', line 381

def self.Increment(value, by)
  if value + by > value
    value + by
  else
    value
  end
end

.removeChar(string, col) ⇒ Object

Remove the character from the string at the given column, if it is blank. Returns true if a change was made.



324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/rndk/slider.rb', line 324

def self.removeChar(string, col)
  result = false
  if col >= 0 && string[col] != ' '
    while col < string.size - 1
      string[col] = string[col + 1]
      col += 1
    end
    string.chop!
    result = true
  end
  return result
end

Instance Method Details

#activate(actions = []) ⇒ Object

Activates the 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 current value of the slider.



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

def activate(actions=[])
  self.draw

  if actions.nil? || 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

  # Set the exit type and return.
  self.set_exit_type(0)
  return nil
end

#decrement(by) ⇒ Object



626
627
628
# File 'lib/rndk/slider.rb', line 626

def decrement by
  @current = @current - by if (@current - by) < @current
end

#destroyObject

See Also:



539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/rndk/slider.rb', line 539

def destroy
  self.clean_title
  @label = []

  # Clean up the windows.
  RNDK.window_delete(@field_win)
  RNDK.window_delete(@label_win)
  RNDK.window_delete(@shadow_win)
  RNDK.window_delete(@win)

  # Clean the key bindings.
  self.clean_bindings

  # Unregister this widget.
  @screen.unregister self
end

#drawObject

Draws the Widget on the Screen.

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



486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/rndk/slider.rb', line 486

def draw

  # Draw the shadow.
  Draw.drawShadow(@shadow_win) unless @shadow_win.nil?

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

  self.draw_title @win

  # Draw the label.
  unless @label_win.nil?
    Draw.writeChtype(@label_win, 0, 0, @label, RNDK::HORIZONTAL,
        0, @label_len)
    Ncurses.wrefresh(@label_win)
  end
  Ncurses.wrefresh @win

  # Draw the field window.
  self.draw_field
end

#draw_fieldObject

This draws the widget.



509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
# File 'lib/rndk/slider.rb', line 509

def draw_field
  step = 1.0 * @field_width / (@maximum - @minimum)

  # Determine how many filler characters need to be drawn.
  filler_characters = (@current - @minimum) * step

  Ncurses.werase(@field_win)

  # Add the character to the window.
  (0...filler_characters).each do |x|
    Ncurses.mvwaddch(@field_win, 0, x, @filler)
  end

  # Draw the value in the field.
  Draw.writeCharAttrib(@field_win, @field_width, 0, @current.to_s,
      RNDK::Color[:normal], RNDK::HORIZONTAL, 0, @current.to_s.size)

  self.moveToEditPosition(@field_edit)
  Ncurses.wrefresh(@field_win)
end

#eraseObject

See Also:



557
558
559
560
561
562
563
564
# File 'lib/rndk/slider.rb', line 557

def erase
  if self.valid?
    RNDK.window_erase @label_win
    RNDK.window_erase @field_win
    RNDK.window_erase @lwin
    RNDK.window_erase @shadow_win
  end
end

#focusObject



610
611
612
# File 'lib/rndk/slider.rb', line 610

def focus
  self.draw
end

#formattedSize(value) ⇒ Object



566
567
568
# File 'lib/rndk/slider.rb', line 566

def formattedSize(value)
  return value.to_s.size
end

#get_valueObject



583
584
585
# File 'lib/rndk/slider.rb', line 583

def get_value
  return @current
end

#getMaximumValueObject



606
607
608
# File 'lib/rndk/slider.rb', line 606

def getMaximumValue
  return @maximum
end

#getMinimumValueObject



602
603
604
# File 'lib/rndk/slider.rb', line 602

def getMinimumValue
  return @minimum
end

#increment(by) ⇒ Object



630
631
632
# File 'lib/rndk/slider.rb', line 630

def increment by
  @current = @current + by if (@current + by) > @current
end

#inject(input) ⇒ Object

See Also:



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

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

  self.set_exit_type 0

  self.draw_field

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

  if keep_going

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

    else
      case input
      when Ncurses::KEY_LEFT
        self.setEditPosition(@field_edit + 1)
      when Ncurses::KEY_RIGHT
        self.setEditPosition(@field_edit - 1)
      when Ncurses::KEY_DOWN
        self.decrement @increment
      when Ncurses::KEY_UP
        self.increment @increment
      when Ncurses::KEY_PPAGE, RNDK::BACKCHAR
        self.increment @fast_increment
      when Ncurses::KEY_NPAGE, RNDK::FORCHAR
        self.decrement @fast_increment
      when Ncurses::KEY_HOME
        @current = @minimum
      when Ncurses::KEY_END
        @current = @maximum
      when RNDK::KEY_TAB, RNDK::KEY_RETURN, Ncurses::KEY_ENTER
        self.set_exit_type(input)
        ret = @current
        complete = true
      when RNDK::KEY_ESC
        self.set_exit_type(input)
        complete = true
      when Ncurses::ERR
        self.set_exit_type(input)
        complete = true
      when RNDK::REFRESH
        @screen.erase
        @screen.refresh
      else
        if @field_edit != 0
          if !self.performEdit(input)
            RNDK.beep
          end
        else
          # The cursor is not within the editable text. Interpret
          # input as commands.
        case input
        when 'd'.ord, '-'.ord
          return self.inject(Ncurses::KEY_DOWN)
        when '+'.ord
          return self.inject(Ncurses::KEY_UP)
        when 'D'.ord
          return self.inject(Ncurses::KEY_NPAGE)
        when '0'.ord
          return self.inject(Ncurses::KEY_HOME)
        else
          RNDK.beep
        end
        end
      end
    end
    self.limitCurrentValue
    self.run_signal_binding(:after_input) if not complete
  end

  if not complete
    self.draw_field
    self.set_exit_type 0
  end

  @return_data = 0
  return ret
end

#limitCurrentValueObject

Check if the value lies outside the minimum/maximum range. If so, force it in.



266
267
268
269
270
271
272
273
274
# File 'lib/rndk/slider.rb', line 266

def limitCurrentValue
  if @current < @minimum
    @current = @minimum
    RNDK.beep
  elsif @current > @maximum
    @current = @maximum
    RNDK.beep
  end
end

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

See Also:



477
478
479
480
481
# File 'lib/rndk/slider.rb', line 477

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

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

#moveToEditPosition(new_position) ⇒ Object

Move the cursor to the given edit-position.



277
278
279
280
281
# File 'lib/rndk/slider.rb', line 277

def moveToEditPosition(new_position)
  return Ncurses.wmove(@field_win,
                       0,
                       @field_width + self.formattedSize(@current) - new_position)
end

#performEdit(input) ⇒ Object

Perform an editing function for the field.



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

def performEdit(input)
  result = false
  modify = true
  base = @field_width
  need = self.formattedSize(@current)
  temp = ''
  col = need - @field_edit

  adj = if col < 0 then -col else 0 end
  if adj != 0
    temp  = ' ' * adj
  end
  Ncurses.wmove(@field_win, 0, base)
  Ncurses.winnstr(@field_win, temp, need)
  temp << ' '
  if RNDK.is_char?(input)  # Replace the char at the cursor
    temp[col] = input.chr
  elsif input == Ncurses::KEY_BACKSPACE
    # delete the char before the cursor
    modify = RNDK::Slider.removeChar(temp, col - 1)
  elsif input == Ncurses::KEY_DC
    # delete the char at the cursor
    modify = RNDK::Slider.removeChar(temp, col)
  else
    modify = false
  end
  if modify &&
      ((value, test) = temp.scanf(self.SCAN_FMT)).size == 2 &&
      test == ' ' && value >= @minimum && value <= @maximum
    self.set_value(value)
    result = true
  end
  return result
end

#positionObject



622
623
624
# File 'lib/rndk/slider.rb', line 622

def position
  super(@win)
end

#SCAN_FMTObject



618
619
620
# File 'lib/rndk/slider.rb', line 618

def SCAN_FMT
  '%d%c'
end

#set(minimum, maximum, value, box) ⇒ Object

This function sets the minimum/maximum/current values of the widget.



571
572
573
574
575
# File 'lib/rndk/slider.rb', line 571

def set(minimum, maximum, value, box)
  self.setMinimumMaximum(minimum, maximum)
  self.set_value(value)
  self.set_box(box)
end

#set_bg_color(attrib) ⇒ Object

This sets the background attribute of the widget.



531
532
533
534
535
536
# File 'lib/rndk/slider.rb', line 531

def set_bg_color(attrib)
  # Set the widget's background attribute.
  Ncurses.wbkgd(@win, attrib)
  Ncurses.wbkgd(@field_win, attrib)
  Ncurses.wbkgd(@label_win, attrib) unless @label_win.nil?
end

#set_value(value) ⇒ Object

This sets the widget's value.



578
579
580
581
# File 'lib/rndk/slider.rb', line 578

def set_value(value)
  @current = value
  self.limitCurrentValue
end

#setEditPosition(new_position) ⇒ Object

Set the edit position. Normally the cursor is one cell to the right of the editable field. Moving it left, over the field, alminimums the user to modify cells by typing in replacement characters for the field's value.



310
311
312
313
314
315
316
317
318
319
320
# File 'lib/rndk/slider.rb', line 310

def setEditPosition(new_position)
  if new_position < 0
    RNDK.beep
  elsif new_position == 0
    @field_edit = new_position
  elsif self.validEditPosition(new_position)
    @field_edit = new_position
  else
    RNDK.beep
  end
end

#setMinimumMaximum(minimum, maximum) ⇒ Object

This function sets the minimum/maximum values of the widget.



588
589
590
591
592
593
594
595
596
597
598
599
600
# File 'lib/rndk/slider.rb', line 588

def setMinimumMaximum(minimum, maximum)
  # Make sure the values aren't out of bounds.
  if minimum <= maximum
    @minimum = minimum
    @maximum = maximum
  elsif minimum > maximum
    @minimum = maximum
    @maximum = minimum
  end

  # Make sure the user hasn't done something silly.
  self.limitCurrentValue
end

#unfocusObject



614
615
616
# File 'lib/rndk/slider.rb', line 614

def unfocus
  self.draw
end

#validEditPosition(new_position) ⇒ Object

Check if the cursor is on a valid edit-position. This must be one of the non-blank cells in the field.



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/rndk/slider.rb', line 285

def validEditPosition(new_position)
  if new_position <= 0 || new_position >= @field_width
    return false
  end
  if self.moveToEditPosition(new_position) == Ncurses::ERR
    return false
  end
  ch = Ncurses.winch(@field_win)
  if RNDK.char_of(ch) != ' '
    return true
  end
  if new_position > 1
    # Don't use recursion - only one level is wanted
    if self.moveToEditPosition(new_position - 1) == Ncurses::ERR
      return false
    end
    ch = Ncurses.winch(@field_win)
    return RNDK.char_of(ch) != ' '
  end
  return false
end