Class: CDK::SCROLL

Inherits:
SCROLLER show all
Includes:
CommonControls
Defined in:
lib/cdk/components/scroll.rb

Instance Attribute Summary collapse

Attributes included from CommonControls

#quit_on_enter

Attributes included from HasTitle

#title_attrib

Attributes included from HasScreen

#is_visible, #screen, #screen_index

Attributes included from ExitConditions

#exit_type

Attributes included from Bindings

#binding_list

Attributes included from Focusable

#accepts_focus, #has_focus

Attributes included from Borders

#BXAttr, #HZChar, #LLChar, #LRChar, #ULChar, #URChar, #VTChar, #border_size, #box

Instance Method Summary collapse

Methods included from CommonControls

#quit_on_enter?

Methods inherited from SCROLLER

#KEY_DOWN, #KEY_END, #KEY_HOME, #KEY_LEFT, #KEY_NPAGE, #KEY_PPAGE, #KEY_RIGHT, #KEY_UP, #getCurrentItem, #maxViewSize, #setCurrentItem, #setPosition, #setViewSize

Methods inherited from CDKOBJS

#setBackgroundColor, #timeout, #validCDKObject, #validObjType

Methods included from WindowHooks

#refreshData, #saveData

Methods included from WindowInput

#getc, #getch, #setPostProcess, #setPreProcess

Methods included from HasTitle

#cleanTitle, #drawTitle, #init_title, #setTitle

Methods included from HasScreen

#SCREEN_XPOS, #SCREEN_YPOS, #init_screen, #wrefresh

Methods included from ExitConditions

#init_exit_conditions, #resetExitType, #setExitType

Methods included from Bindings

#bind, #bindableObject, #checkBind, #cleanBindings, #init_bindings, #isBind, #unbind

Methods included from Focusable

#init_focus

Methods included from Borders

#getBox, #init_borders, #setBXattr, #setBox, #setHZchar, #setLLchar, #setLRchar, #setULchar, #setURchar, #setVTchar

Methods included from Movement

#move_specific

Methods included from Converters

#char2Chtype, #charOf, #chtype2Char, #chtype2String, #decode_attribute, #encode_attribute

Methods included from Justifications

#justify_string

Methods included from Alignments

#alignxy

Constructor Details

#initialize(cdkscreen, xplace, yplace, splace, height, width, title, list, list_size, numbers, highlight, box, shadow) ⇒ SCROLL

Returns a new instance of SCROLL.



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
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
# File 'lib/cdk/components/scroll.rb', line 9

def initialize (cdkscreen, xplace, yplace, splace, height, width, title,
    list, list_size, numbers, highlight, box, shadow)
  super()
  parent_width = cdkscreen.window.getmaxx
  parent_height = cdkscreen.window.getmaxy
  box_width = width
  box_height = height
  xpos = xplace
  ypos = yplace
  scroll_adjust = 0
  bindings = {
    CDK::BACKCHAR => Ncurses::KEY_PPAGE,
    CDK::FORCHAR  => Ncurses::KEY_NPAGE,
    'g'           => Ncurses::KEY_HOME,
    '1'           => Ncurses::KEY_HOME,
    'G'           => Ncurses::KEY_END,
    '<'           => Ncurses::KEY_HOME,
    '>'           => Ncurses::KEY_END
  }

  self.setBox(box)

  # If the height is a negative value, the height will be ROWS-height,
  # otherwise the height will be the given height
  box_height = CDK.setWidgetDimension(parent_height, height, 0)

  # If the width is a negative value, the width will be COLS-width,
  # otherwise the width will be the given width
  box_width = CDK.setWidgetDimension(parent_width, width, 0)

  box_width = self.setTitle(title, box_width)

  # Set the box height.
  if @title_lines > box_height
    box_height = @title_lines + [list_size, 8].min + 2 * @border_size
  end

  # Adjust the box width if there is a scroll bar
  if splace == CDK::LEFT || splace == CDK::RIGHT
    @scrollbar = true
    box_width += 1
  else
    @scrollbar = false
  end

  # Make sure we didn't extend beyond the dimensions of the window.
  @box_width = if box_width > parent_width 
               then parent_width - scroll_adjust 
               else box_width 
               end
  @box_height = if box_height > parent_height
                then parent_height
                else box_height
                end

  self.setViewSize(list_size)

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

  # Make the scrolling window
  @win = Ncurses::WINDOW.new(@box_height, @box_width, ypos, xpos)

  # Is the scrolling window null?
  if @win.nil?
    return nil
  end

  # Turn the keypad on for the window
  @win.keypad(true)

  # Create the scrollbar window.
  if splace == CDK::RIGHT
    @scrollbar_win = @win.subwin(self.maxViewSize, 1,
        self.SCREEN_YPOS(ypos), xpos + box_width - @border_size - 1)
  elsif splace == CDK::LEFT
    @scrollbar_win = @win.subwin(self.maxViewSize, 1,
        self.SCREEN_YPOS(ypos), self.SCREEN_XPOS(xpos))
  else
    @scrollbar_win = nil
  end

  # create the list window
  @list_win = @win.subwin(self.maxViewSize,
      box_width - (2 * @border_size) - scroll_adjust,
      self.SCREEN_YPOS(ypos),
      self.SCREEN_XPOS(xpos) + (if splace == CDK::LEFT then 1 else 0 end))

  # Set the rest of the variables
  @screen = cdkscreen
  @parent = cdkscreen.window
  @shadow_win = nil
  @scrollbar_placement = splace
  @max_left_char = 0
  @left_char = 0
  @highlight = highlight
  # initExitType (scrollp);
  @accepts_focus = true
  @input_window = @win
  @shadow = shadow

  self.setPosition(0);

  # Create the scrolling list item list and needed variables.
  if self.createItemList(numbers, list, list_size) <= 0
    return nil
  end

  # Do we need to create a shadow?
  if shadow
    @shadow_win = Ncurses::WINDOW.new(@box_height, box_width,
        ypos + 1, xpos + 1)
  end

  # Set up the key bindings.
  bindings.each do |from, to|
    #self.bind(:SCROLL, from, getc_lambda, to)
    self.bind(:SCROLL, from, :getc, to)
  end

  cdkscreen.register(:SCROLL, self);
  
  return self
end

Instance Attribute Details

#current_itemObject (readonly)

Returns the value of attribute current_item.



7
8
9
# File 'lib/cdk/components/scroll.rb', line 7

def current_item
  @current_item
end

#highlightObject (readonly)

Returns the value of attribute highlight.



7
8
9
# File 'lib/cdk/components/scroll.rb', line 7

def highlight
  @highlight
end

#itemObject (readonly)

Returns the value of attribute item.



7
8
9
# File 'lib/cdk/components/scroll.rb', line 7

def item
  @item
end

#list_sizeObject (readonly)

Returns the value of attribute list_size.



7
8
9
# File 'lib/cdk/components/scroll.rb', line 7

def list_size
  @list_size
end

Instance Method Details

#activate(actions) ⇒ Object

This actually does all the ‘real’ work of managing the scrolling list.



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
# File 'lib/cdk/components/scroll.rb', line 157

def activate(actions)
  # Draw the scrolling list
  self.draw(@box)

  if actions.nil? || actions.size == 0
    while true
      self.fixCursorPosition
      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 for the widget and return
  self.setExitType(0)
  return -1
end

#addItem(item) ⇒ Object

This adds a single item to a scrolling list, at the end of the list.



545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/cdk/components/scroll.rb', line 545

def addItem(item)
  item_number = @list_size
  widest_item = self.WidestItem
  temp = ''
  have = 0

  if self.allocListArrays(@list_size, @list_size + 1) &&
      self.allocListItem(item_number, temp, have,
      if @numbers then item_number + 1 else 0 end,
      item)
    # Determine the size of the widest item.
    widest_item = [@item_len[item_number], widest_item].max

    self.updateViewWidth(widest_item)
    self.setViewSize(@list_size + 1)
  end
end

#allocListArrays(old_size, new_size) ⇒ Object



403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'lib/cdk/components/scroll.rb', line 403

def allocListArrays(old_size, new_size)
  result = true
  new_list = Array.new(new_size)
  new_len = Array.new(new_size)
  new_pos = Array.new(new_size)

  (0...old_size).each do |n|
    new_list[n] = @item[n]
    new_len[n] = @item_len[n]
    new_pos[n] = @item_pos[n]
  end

  @item = new_list
  @item_len = new_len
  @item_pos = new_pos

  return result
end

#allocListItem(which, work, used, number, value) ⇒ Object



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/cdk/components/scroll.rb', line 422

def allocListItem(which, work, used, number, value)
  if number > 0
    value = "%4d. %s" % [number, value]
  end

  item_len = []
  item_pos = []
  @item[which] = char2Chtype(value, item_len, item_pos)
  @item_len[which] = item_len[0]
  @item_pos[which] = item_pos[0]

  @item_pos[which] = justify_string(@box_width,
      @item_len[which], @item_pos[which])
  return true
end

#AvailableWidthObject



616
617
618
# File 'lib/cdk/components/scroll.rb', line 616

def AvailableWidth
  @box_width - (2 * @border_size)
end

#createItemList(numbers, list, list_size) ⇒ Object

This function creates the scrolling list information and sets up the needed variables for the scrolling list to work correctly.



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
# File 'lib/cdk/components/scroll.rb', line 440

def createItemList(numbers, list, list_size)
  status = 0
  if list_size > 0
    widest_item = 0
    x = 0
    have = 0
    temp = ''
    if allocListArrays(0, list_size)
      # Create the items in the scrolling list.
      status = 1
      (0...list_size).each do |x|
        number = if numbers then x + 1 else 0 end
        if !self.allocListItem(x, temp, have, number, list[x])
          status = 0
          break
        end

        widest_item = [@item_len[x], widest_item].max
      end

      if status
        self.updateViewWidth(widest_item);

        # Keep the boolean flag 'numbers'
        @numbers = numbers
      end
    end
  else
    status = 1  # null list is ok - for a while
  end

  return status
end

#deleteItem(position) ⇒ Object

This removes a single item from a scrolling list.



584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
# File 'lib/cdk/components/scroll.rb', line 584

def deleteItem(position)
  if position >= 0 && position < @list_size
    # Adjust the list
    @item = @item[0...position] + @item[position+1..-1]
    @item_len = @item_len[0...position] + @item_len[position+1..-1]
    @item_pos = @item_pos[0...position] + @item_pos[position+1..-1]

    self.setViewSize(@list_size - 1)

    if @list_size > 0
      self.resequence
    end

    if @list_size < self.maxViewSize
      @win.werase  # force the next redraw to be complete
    end

    # do this to update the view size, etc
    self.setPosition(@current_item)
  end
end

#destroyObject

This function destroys



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/cdk/components/scroll.rb', line 381

def destroy
  self.cleanTitle

  # Clean up the windows.
  CDK.deleteCursesWindow(@scrollbar_win)
  CDK.deleteCursesWindow(@shadow_win)
  CDK.deleteCursesWindow(@list_win)
  CDK.deleteCursesWindow(@win)

  # Clean the key bindings.
  self.cleanBindings(:SCROLL)

  # Unregister this object
  CDK::SCREEN.unregister(:SCROLL, self)
end

#draw(box) ⇒ Object

This function draws the scrolling list widget.



291
292
293
294
295
296
297
298
299
300
301
# File 'lib/cdk/components/scroll.rb', line 291

def draw(box)
  # Draw in the shadow if we need to.
  unless @shadow_win.nil?
    Draw.drawShadow(@shadow_win)
  end

  self.drawTitle(@win)

  # Draw in the scrolling list items.
  self.drawList(box)
end

#drawCurrentObject



303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/cdk/components/scroll.rb', line 303

def drawCurrent
  # Rehighlight the current menu item.
  screen_pos = @item_pos[@current_item] - @left_char
  highlight = if self.has_focus
              then @highlight
              else Ncurses::A_NORMAL
              end

  Draw.writeChtypeAttrib(@list_win,
      if screen_pos >= 0 then screen_pos else 0 end,
      @current_high, @item[@current_item], highlight, CDK::HORIZONTAL,
      if screen_pos >= 0 then 0 else 1 - screen_pos end,
      @item_len[@current_item])
end

#drawList(box) ⇒ Object



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
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
# File 'lib/cdk/components/scroll.rb', line 318

def drawList(box)
  # If the list is empty, don't draw anything.
  if @list_size > 0
    # Redraw the list
    (0...@view_size).each do |j|
      k = j + @current_top

      Draw.writeBlanks(@list_win, 0, j, CDK::HORIZONTAL, 0,
        @box_width - (2 * @border_size))

      # Draw the elements in the scrolling list.
      if k < @list_size
        screen_pos = @item_pos[k] - @left_char
        ypos = j

        # Write in the correct line.
        Draw.writeChtype(@list_win,
            if screen_pos >= 0 then screen_pos else 1 end,
            ypos, @item[k], CDK::HORIZONTAL,
            if screen_pos >= 0 then 0 else 1 - screen_pos end,
            @item_len[k])
      end
    end

    self.drawCurrent

    # Determine where the toggle is supposed to be.
    unless @scrollbar_win.nil?
      @toggle_pos = (@current_item * @step).floor

      # Make sure the toggle button doesn't go out of bounds.
      
      if @toggle_pos >= @scrollbar_win.getmaxy
        @toggle_pos = @scrollbar_win.getmaxy - 1
      end

      # Draw the scrollbar
      @scrollbar_win.mvwvline(0, 0, Ncurses::ACS_CKBOARD,
          @scrollbar_win.getmaxy)
      @scrollbar_win.mvwvline(@toggle_pos, 0, ' '.ord | Ncurses::A_REVERSE,
          @toggle_size)
    end
  end

  # Box it if needed.
  if box
    Draw.drawObjBox(@win, self)
  end

  # Refresh the window
  wrefresh
end

#eraseObject

This function erases the scrolling list from the screen.



398
399
400
401
# File 'lib/cdk/components/scroll.rb', line 398

def erase
  CDK.eraseCursesWindow(@win)
  CDK.eraseCursesWindow(@shadow_win)
end

#fixCursorPositionObject

Put the cursor on the currently-selected item’s row.



147
148
149
150
151
152
153
154
# File 'lib/cdk/components/scroll.rb', line 147

def fixCursorPosition
  scrollbar_adj = if @scrollbar_placement == LEFT then 1 else 0 end
  ypos = self.SCREEN_YPOS(@current_item - @current_top)
  xpos = self.SCREEN_XPOS(0) + scrollbar_adj

  @input_window.wmove(ypos, xpos)
  wrefresh(@input_window)
end

#focusObject



606
607
608
609
# File 'lib/cdk/components/scroll.rb', line 606

def focus
  self.drawCurrent
  wrefresh(@list_win)
end

#getCurrentTopObject



268
269
270
# File 'lib/cdk/components/scroll.rb', line 268

def getCurrentTop
  return @current_top
end

#getHighlight(highlight) ⇒ Object



510
511
512
# File 'lib/cdk/components/scroll.rb', line 510

def getHighlight(highlight)
  return @highlight
end

#getItems(list) ⇒ Object



497
498
499
500
501
502
503
# File 'lib/cdk/components/scroll.rb', line 497

def getItems(list)
  (0...@list_size).each do |x|
    list << chtype2Char(@item[x])
  end

  return @list_size
end

#inject(input) ⇒ Object

This injects a single character into the widget.



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
# File 'lib/cdk/components/scroll.rb', line 188

def inject(input)
  pp_return = 1
  ret = -1
  @complete = false

  # Set the exit type for the widget.
  self.setExitType(0)

  # Draw the scrolling list
  self.drawList(@box)

  #Check if there is a pre-process function to be called.
  unless @pre_process_func.nil?
    pp_return = @pre_process_func.call(:SCROLL, self,
        @pre_process_data, input)
  end

  # Should we continue?
  if pp_return != 0
    # Check for a predefined key binding.
    if self.checkBind(:SCROLL, input) != false
      #self.checkEarlyExit
      @complete = true
    else
      case input
      when Ncurses::KEY_UP
        self.KEY_UP
      when Ncurses::KEY_DOWN
        self.KEY_DOWN
      when Ncurses::KEY_RIGHT
        self.KEY_RIGHT
      when Ncurses::KEY_LEFT
        self.KEY_LEFT
      when Ncurses::KEY_PPAGE
        self.KEY_PPAGE
      when Ncurses::KEY_NPAGE
        self.KEY_NPAGE
      when Ncurses::KEY_HOME
        self.KEY_HOME
      when Ncurses::KEY_END
        self.KEY_END
      when '$'
        @left_char = @max_left_char
      when '|'
        @left_char = 0
      when CDK::KEY_ESC
        self.setExitType(input)
        @complete = true
      when Ncurses::ERR
        self.setExitType(input)
        @complete = true
      when CDK::REFRESH
        @screen.erase
        @screen.refresh
      when CDK::KEY_TAB, Ncurses::KEY_ENTER, CDK::KEY_RETURN
        if quit_on_enter?
          self.setExitType(input)
          ret = @current_item
          @complete = true
        end
      end
    end

    if !@complete && !(@post_process_func.nil?)
      @post_process_func.call(:SCROLL, self, @post_process_data, input)
    end
  end

  if !@complete
    self.drawList(@box)
    self.setExitType(0)
  end

  self.fixCursorPosition
  @result_data = ret

  #return ret != -1
  return ret
end

#insertItem(item) ⇒ Object

This adds a single item to a scrolling list before the current item



564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/cdk/components/scroll.rb', line 564

def insertItem(item)
  widest_item = self.WidestItem
  temp = ''
  have = 0

  if self.allocListArrays(@list_size, @list_size + 1) &&
      self.insertListItem(@current_item) &&
      self.allocListItem(@current_item, temp, have,
      if @numbers then @current_item + 1 else 0 end,
      item)
    # Determine the size of the widest item.
    widest_item = [@item_len[@current_item], widest_item].max

    self.updateViewWidth(widest_item)
    self.setViewSize(@list_size + 1)
    self.resequence
  end
end

#insertListItem(item) ⇒ Object



537
538
539
540
541
542
# File 'lib/cdk/components/scroll.rb', line 537

def insertListItem(item)
  @item = @item[0..item] + @item[item..-1]
  @item_len = @item_len[0..item] + @item_len[item..-1]
  @item_pos = @item_pos[0..item] + @item_pos[item..-1]
  return true
end

#move(xplace, yplace, relative, refresh_flag) ⇒ Object

This moves the scroll field to the given location.



284
285
286
287
288
# File 'lib/cdk/components/scroll.rb', line 284

def move(xplace, yplace, relative, refresh_flag)
  windows = [@win, @list_win, @shadow_win, @scrollbar_win]
  self.move_specific(xplace, yplace, relative, refresh_flag,
      windows, [])
end

#object_typeObject



138
139
140
# File 'lib/cdk/components/scroll.rb', line 138

def object_type
  :SCROLL
end

#positionObject



142
143
144
# File 'lib/cdk/components/scroll.rb', line 142

def position
  super(@win)
end

#resequenceObject

Resequence the numbers after an insertion/deletion.



515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/cdk/components/scroll.rb', line 515

def resequence
  if @numbers
    (0...@list_size).each do |j|
      target = @item[j]

      source = "%4d. %s" % [j + 1, ""]

      k = 0
      while k < source.size
        # handle deletions that change the length of number
        if source[k] == "." && target[k] != "."
          source = source[0...k] + source[k+1..-1]
        end

        target[k] &= Ncurses::A_ATTRIBUTES
        target[k] |= source[k].ord
        k += 1
      end
    end
  end
end

#set(list, list_size, numbers, highlight, box) ⇒ Object

This sets certain attributes of the scrolling list.



475
476
477
478
479
# File 'lib/cdk/components/scroll.rb', line 475

def set(list, list_size, numbers, highlight, box)
  self.setItems(list, list_size, numbers)
  self.setHighlight(highlight)
  self.setBox(box)
end

#setBKattr(attrib) ⇒ Object

This sets the background attribute of the widget.



372
373
374
375
376
377
378
# File 'lib/cdk/components/scroll.rb', line 372

def setBKattr(attrib)
  @win.wbkgd(attrib)
  @list_win.wbkgd(attrib)
  unless @scrollbar_win.nil?
    @scrollbar_win.wbkgd(attrib)
  end
end

#setCurrentTop(item) ⇒ Object



272
273
274
275
276
277
278
279
280
281
# File 'lib/cdk/components/scroll.rb', line 272

def setCurrentTop(item)
  if item < 0
    item = 0
  elsif item > @max_top_item
    item = @max_top_item
  end
  @current_top = item

  self.setPosition(item);
end

#setHighlight(highlight) ⇒ Object

This sets the highlight of the scrolling list.



506
507
508
# File 'lib/cdk/components/scroll.rb', line 506

def setHighlight(highlight)
  @highlight = highlight
end

#setItems(list, list_size, numbers) ⇒ Object

This sets the scrolling list items



482
483
484
485
486
487
488
489
490
491
492
493
494
495
# File 'lib/cdk/components/scroll.rb', line 482

def setItems(list, list_size, numbers)
  if self.createItemList(numbers, list, list_size) <= 0
    return
  end

  # Clean up the display.
  (0...@view_size).each do |x|
    Draw.writeBlanks(@win, 1, x, CDK::HORIZONTAL, 0, @box_width - 2);
  end

  self.setViewSize(list_size)
  self.setPosition(0)
  @left_char = 0
end

#unfocusObject



611
612
613
614
# File 'lib/cdk/components/scroll.rb', line 611

def unfocus
  self.drawCurrent
  wrefresh(@list_win)
end

#updateViewWidth(widest) ⇒ Object



620
621
622
623
624
625
# File 'lib/cdk/components/scroll.rb', line 620

def updateViewWidth(widest)
  @max_left_char = if @box_width > widest
                   then 0
                   else widest - self.AvailableWidth
                   end
end

#WidestItemObject



627
628
629
# File 'lib/cdk/components/scroll.rb', line 627

def WidestItem
  @max_left_char + self.AvailableWidth
end