Class: CDK::ALPHALIST

Inherits:
CDKOBJS show all
Defined in:
lib/cdk/alphalist.rb

Instance Attribute Summary collapse

Attributes inherited from CDKOBJS

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

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from CDKOBJS

#SCREEN_XPOS, #SCREEN_YPOS, #bind, #bindableObject, #checkBind, #cleanBindings, #cleanTitle, #drawTitle, #getBox, #getc, #getch, #isBind, #move_specific, #refreshData, #saveData, #setBXattr, #setBackgroundColor, #setBox, #setExitType, #setHZchar, #setLLchar, #setLRchar, #setTitle, #setULchar, #setURchar, #setVTchar, #unbind, #validCDKObject, #validObjType

Constructor Details

#initialize(cdkscreen, xplace, yplace, height, width, title, label, list, list_size, filler_char, highlight, box, shadow) ⇒ ALPHALIST

Returns a new instance of ALPHALIST.



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

def initialize(cdkscreen, xplace, yplace, height, width, title, label,
    list, list_size, filler_char, highlight, box, shadow)
  super()
  parent_width = cdkscreen.window.getmaxx
  parent_height = cdkscreen.window.getmaxy
  box_width = width
  box_height = height
  label_len = 0
  bindings = {
    CDK::BACKCHAR => Ncurses::KEY_PPAGE,
    CDK::FORCHAR  => Ncurses::KEY_NPAGE,
  }

  if !self.createList(list, list_size)
    self.destroy
    return nil
  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)

  # Translate the label string to a chtype array
  if label.size > 0
    lentmp = []
    chtype_label = CDK.char2Chtype(label, lentmp, [])
    label_len = lentmp[0]
  end

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

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

  if @win.nil?
    self.destroy
    return nil
  end
  @win.keypad(true)

  # Set some variables.
  @screen = cdkscreen
  @parent = cdkscreen.window
  @highlight = highlight
  @filler_char = filler_char
  @box_height = box_height
  @box_width = box_width
  @shadow = shadow
  @shadow_win = nil

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

  # Create the entry field.
  temp_width =  if CDK::ALPHALIST.isFullWidth(width)
                then CDK::FULL
                else box_width - 2 - label_len
                end
  @entry_field = CDK::ENTRY.new(cdkscreen, @win.getbegx, @win.getbegy,
      title, label, Ncurses::A_NORMAL, filler_char, :MIXED, temp_width,
      0, 512, box, false)
  if @entry_field.nil?
    self.destroy
    return nil
  end
  @entry_field.setLLchar(Ncurses::ACS_LTEE)
  @entry_field.setLRchar(Ncurses::ACS_RTEE)

  # Callback functions
  adjust_alphalist_cb = lambda do |object_type, object, alphalist, key|
    scrollp = alphalist.scroll_field
    entry = alphalist.entry_field

    if scrollp.list_size > 0
      # Adjust the scrolling list.
      alphalist.injectMyScroller(key)

      # Set the value in the entry field.
      current = CDK.chtype2Char(scrollp.item[scrollp.current_item])
      entry.setValue(current)
      entry.draw(entry.box)
      return true
    end
    CDK.Beep
    return false
  end

  complete_word_cb = lambda do |object_type, object, alphalist, key|
    entry = alphalist.entry_field
    scrollp = nil
    selected = -1
    ret = 0
    alt_words = []

    if entry.info.size == 0
      CDK.Beep
      return true
    end
    
    # Look for a unique word match.
    index = CDK.searchList(alphalist.list, alphalist.list.size, entry.info)

    # if the index is less than zero, return we didn't find a match
    if index < 0
      CDK.Beep
      return true
    end

    # Did we find the last word in the list?
    if index == alphalist.list.size - 1
      entry.setValue(alphalist.list[index])
      entry.draw(entry.box)
      return true
    end


    # Ok, we found a match, is the next item similar?
    len = [entry.info.size, alphalist.list[index + 1].size].min
    ret = alphalist.list[index + 1][0...len] <=> entry.info
    if ret == 0
      current_index = index
      match = 0
      selected = -1

      # Start looking for alternate words
      # FIXME(original): bsearch would be more suitable.
      while current_index < alphalist.list.size &&
          (alphalist.list[current_index][0...len] <=> entry.info) == 0
        alt_words << alphalist.list[current_index]
        current_index += 1
      end

      # Determine the height of the scrolling list.
      height = if alt_words.size < 8 then alt_words.size + 3 else 11 end

      # Create a scrolling list of close matches.
      scrollp = CDK::SCROLL.new(entry.screen,
          CDK::CENTER, CDK::CENTER, CDK::RIGHT, height, -30,
          "<C></B/5>Possible Matches.", alt_words, alt_words.size,
          true, Ncurses::A_REVERSE, true, false)

      # Allow them to select a close match.
      match = scrollp.activate([])
      selected = scrollp.current_item

      # Check how they exited the list.
      if scrollp.exit_type == :ESCAPE_HIT
        # Destroy the scrolling list.
        scrollp.destroy

        # Beep at the user.
        CDK.Beep

        # Redraw the alphalist and return.
        alphalist.draw(alphalist.box)
        return true
      end

      # Destroy the scrolling list.
      scrollp.destroy

      # Set the entry field to the selected value.
      entry.set(alt_words[match], entry.min, entry.max, entry.box)

      # Move the highlight bar down to the selected value.
      (0...selected).each do |x|
        alphalist.injectMyScroller(Ncurses::KEY_DOWN)
      end

      # Redraw the alphalist.
      alphalist.draw(alphalist.box)
    else
      # Set the entry field with the found item.
      entry.set(alphalist.list[index], entry.min, entry.max, entry.box)
      entry.draw(entry.box)
    end
    return true
  end

  pre_process_entry_field = lambda do |cdktype, object, alphalist, input|
    scrollp = alphalist.scroll_field
    entry = alphalist.entry_field
    info_len = entry.info.size
    result = 1
    empty = false

    if alphalist.isBind(:ALPHALIST, input)
      result = 1  # Don't try to use this key in editing
    elsif (CDK.isChar(input) &&
        input.chr.match(/^[[:alnum:][:punct:]]$/)) ||
        [Ncurses::KEY_BACKSPACE, Ncurses::KEY_DC].include?(input)
      index = 0
      curr_pos = entry.screen_col + entry.left_char
      pattern = entry.info.clone
      if [Ncurses::KEY_BACKSPACE, Ncurses::KEY_DC].include?(input)
        if input == Ncurses::KEY_BACKSPACE
          curr_pos -= 1
        end
        if curr_pos >= 0
          pattern.slice!(curr_pos)
        end
      else
        front = (pattern[0...curr_pos] or '')
        back = (pattern[curr_pos..-1] or '')
        pattern = front + input.chr + back
      end

      if pattern.size == 0
        empty = true
      elsif (index = CDK.searchList(alphalist.list,
          alphalist.list.size, pattern)) >= 0
        # XXX: original uses n scroll downs/ups for <10 positions change
          scrollp.setPosition(index)
        alphalist.drawMyScroller
      else
        CDK.Beep
        result = 0
      end
    end

    if empty
      scrollp.setPosition(0)
      alphalist.drawMyScroller
    end

    return result
  end

  # Set the key bindings for the entry field.
  @entry_field.bind(:ENTRY, Ncurses::KEY_UP, adjust_alphalist_cb, self)
  @entry_field.bind(:ENTRY, Ncurses::KEY_DOWN, adjust_alphalist_cb, self)
  @entry_field.bind(:ENTRY, Ncurses::KEY_NPAGE, adjust_alphalist_cb, self)
  @entry_field.bind(:ENTRY, Ncurses::KEY_PPAGE, adjust_alphalist_cb, self)
  @entry_field.bind(:ENTRY, CDK::KEY_TAB, complete_word_cb, self)

  # Set up the post-process function for the entry field.
  @entry_field.setPreProcess(pre_process_entry_field, self)

  # Create the scrolling list.  It overlaps the entry field by one line if
  # we are using box-borders.
  temp_height = @entry_field.win.getmaxy - @border_size
  temp_width = if CDK::ALPHALIST.isFullWidth(width)
               then CDK::FULL
               else box_width - 1
               end
  @scroll_field = CDK::SCROLL.new(cdkscreen, @win.getbegx,
      @entry_field.win.getbegy + temp_height, CDK::RIGHT,
      box_height - temp_height, temp_width, '', list, list_size,
      false, Ncurses::A_REVERSE, box, false)
  @scroll_field.setULchar(Ncurses::ACS_LTEE)
  @scroll_field.setURchar(Ncurses::ACS_RTEE)

  # Setup the key bindings.
  bindings.each do |from, to|
    self.bind(:ALPHALIST, from, :getc, to)
  end

  cdkscreen.register(:ALPHALIST, self)
end

Instance Attribute Details

#entry_fieldObject (readonly)

Returns the value of attribute entry_field.



5
6
7
# File 'lib/cdk/alphalist.rb', line 5

def entry_field
  @entry_field
end

#listObject (readonly)

Returns the value of attribute list.



5
6
7
# File 'lib/cdk/alphalist.rb', line 5

def list
  @list
end

#scroll_fieldObject (readonly)

Returns the value of attribute scroll_field.



5
6
7
# File 'lib/cdk/alphalist.rb', line 5

def scroll_field
  @scroll_field
end

Class Method Details

.isFullWidth(width) ⇒ Object



550
551
552
# File 'lib/cdk/alphalist.rb', line 550

def self.isFullWidth(width)
  width == CDK::FULL || (Ncurses.COLS != 0 && width >= Ncurses.COLS)
end

Instance Method Details

#activate(actions) ⇒ Object

This activates the alphalist



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/cdk/alphalist.rb', line 340

def activate(actions)
  ret = 0

  # Draw the widget.
  self.draw(@box)

  # Activate the widget.
  ret = @entry_field.activate(actions)

  # Copy the exit type from the entry field.
  @exit_type = @entry_field.exit_type

  # Determine the exit status.
  if @exit_type != :EARLY_EXIT
    return ret
  end
  return 0
end

#createList(list, list_size) ⇒ Object



516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
# File 'lib/cdk/alphalist.rb', line 516

def createList(list, list_size)
  if list_size >= 0
    newlist = []

    # Copy in the new information.
    status = true
    (0...list_size).each do |x|
      newlist << list[x]
      if newlist[x] == 0
        status = false
        break
      end
    end
    if status
      self.destroyInfo
      @list_size = list_size
      @list = newlist
      @list.sort!
    end
  else
    self.destroyInfo
    status = true
  end
  return status
end

#destroyObject

This destroys the alpha list



489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/cdk/alphalist.rb', line 489

def destroy
  self.destroyInfo

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

  @entry_field.destroy
  @scroll_field.destroy

  # Free up the window pointers.
  CDK.deleteCursesWindow(@shadow_win)
  CDK.deleteCursesWindow(@win)

  # Unregister the object.
  CDK::SCREEN.unregister(:ALPHALIST, self)
end

#destroyInfoObject



483
484
485
486
# File 'lib/cdk/alphalist.rb', line 483

def destroyInfo
  @list = ''
  @list_size = 0
end

#draw(box) ⇒ Object

This draws the alphalist widget.



326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/cdk/alphalist.rb', line 326

def draw(box)
  # Does this widget have a shadow?
  unless @shadow_win.nil?
    Draw.drawShadow(@shadow_win)
  end

  # Draw in the entry field.
  @entry_field.draw(@entry_field.box)

  # Draw in the scroll field.
  self.drawMyScroller
end

#drawMyScrollerObject



313
314
315
316
317
# File 'lib/cdk/alphalist.rb', line 313

def drawMyScroller
  self.saveFocus
  @scroll_field.draw(@scroll_field.box)
  self.restoreFocus
end

#eraseObject

This erases the alphalist from the screen.



282
283
284
285
286
287
288
289
290
# File 'lib/cdk/alphalist.rb', line 282

def erase
  if self.validCDKObject
    @scroll_field.erase
    @entry_field.erase

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

#focusObject



542
543
544
# File 'lib/cdk/alphalist.rb', line 542

def focus
  self.entry_field.focus
end

#getContents(size) ⇒ Object

This returns the contents of the widget.



409
410
411
412
# File 'lib/cdk/alphalist.rb', line 409

def getContents(size)
  size << @list_size
  return @list
end

#getCurrentItemObject

Get/set the current position in the scroll widget.



415
416
417
# File 'lib/cdk/alphalist.rb', line 415

def getCurrentItem
  return @scroll_field.getCurrentItem
end

#getFillerCharObject



432
433
434
# File 'lib/cdk/alphalist.rb', line 432

def getFillerChar
  return @filler_char
end

#getHighlightObject



441
442
443
# File 'lib/cdk/alphalist.rb', line 441

def getHighlight
  @highlight
end

#inject(input) ⇒ Object

This injects a single character into the alphalist.



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/cdk/alphalist.rb', line 360

def inject(input)
  ret = -1

  # Draw the widget.
  self.draw(@box)

  # Inject a character into the widget.
  ret = @entry_field.inject(input)

  # Copy the eixt type from the entry field.
  @exit_type = @entry_field.exit_type

  # Determine the exit status.
  if @exit_type == :EARLY_EXIT
    ret = -1
  end

  @result_data = ret
  return ret
end

#injectMyScroller(key) ⇒ Object



319
320
321
322
323
# File 'lib/cdk/alphalist.rb', line 319

def injectMyScroller(key)
  self.saveFocus
  @scroll_field.inject(key)
  self.restoreFocus
end

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

This moves the alphalist field to the given location.



293
294
295
296
297
298
# File 'lib/cdk/alphalist.rb', line 293

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

#object_typeObject



558
559
560
# File 'lib/cdk/alphalist.rb', line 558

def object_type
  :ALPHALIST
end

#positionObject



554
555
556
# File 'lib/cdk/alphalist.rb', line 554

def position
  super(@win)
end

#restoreFocusObject



309
310
311
# File 'lib/cdk/alphalist.rb', line 309

def restoreFocus
  @scroll_field.has_focus = @save
end

#saveFocusObject

The alphalist’s focus resides in the entry widget. But the scroll widget will not draw items highlighted unless it has focus. Temporarily adjust the focus of the scroll widget when drawing on it to get the right highlighting.



304
305
306
307
# File 'lib/cdk/alphalist.rb', line 304

def saveFocus
  @save = @scroll_field.has_focus
  @scroll_field.has_focus = @entry_field.has_focus
end

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

This sets multiple attributes of the widget.



382
383
384
385
386
387
# File 'lib/cdk/alphalist.rb', line 382

def set(list, list_size, filler_char, highlight, box)
  self.setContents(list, list_size)
  self.setFillerChar(filler_char)
  self.setHighlight(highlight)
  self.setBox(box)
end

#setBKattr(attrib) ⇒ Object

This sets the background attribute of the widget.



478
479
480
481
# File 'lib/cdk/alphalist.rb', line 478

def setBKattr(attrib)
  @entry_field.setBKattr(attrib)
  @scroll_field.setBKattr(attrib)
end

#setContents(list, list_size) ⇒ Object

This function sets the information inside the alphalist.



390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/cdk/alphalist.rb', line 390

def setContents(list, list_size)
  if !self.createList(list, list_size)
    return
  end

  # Set the information in the scrolling list.
  @scroll_field.set(@list, @list_size, false,
      @scroll_field.highlight, @scroll_field.box)

  # Clean out the entry field.
  self.setCurrentItem(0)
  @entry_field.clean

  # Redraw the widget.
  self.erase
  self.draw(@box)
end

#setCurrentItem(item) ⇒ Object



419
420
421
422
423
424
# File 'lib/cdk/alphalist.rb', line 419

def setCurrentItem(item)
  if @list_size != 0
    @scroll_field.setCurrentItem(item)
    @entry_field.setValue(@list[@scroll_field.getCurrentItem])
  end
end

#setFillerChar(filler_character) ⇒ Object

This sets the filler character of the entry field of the alphalist.



427
428
429
430
# File 'lib/cdk/alphalist.rb', line 427

def setFillerChar(filler_character)
  @filler_char = filler_character
  @entry_field.setFillerChar(filler_character)
end

#setHighlight(highlight) ⇒ Object

This sets the highlgith bar attributes



437
438
439
# File 'lib/cdk/alphalist.rb', line 437

def setHighlight(highlight)
  @highlight = highlight
end

#setMyBXattr(character) ⇒ Object



472
473
474
475
# File 'lib/cdk/alphalist.rb', line 472

def setMyBXattr(character)
  @entry_field.setBXattr(character)
  @scroll_field.setBXattr(character)
end

#setMyHZchar(character) ⇒ Object



467
468
469
470
# File 'lib/cdk/alphalist.rb', line 467

def setMyHZchar(character)
  @entry_field.setHZchar(character)
  @scroll_field.setHZchar(character)
end

#setMyLLchar(character) ⇒ Object



454
455
456
# File 'lib/cdk/alphalist.rb', line 454

def setMyLLchar(character)
  @scroll_field.setLLchar(character)
end

#setMyLRchar(character) ⇒ Object



458
459
460
# File 'lib/cdk/alphalist.rb', line 458

def setMyLRchar(character)
  @scroll_field.setLRchar(character)
end

#setMyULchar(character) ⇒ Object

These functions set the drawing characters of the widget.



446
447
448
# File 'lib/cdk/alphalist.rb', line 446

def setMyULchar(character)
  @entry_field.setULchar(character)
end

#setMyURchar(character) ⇒ Object



450
451
452
# File 'lib/cdk/alphalist.rb', line 450

def setMyURchar(character)
  @entry_field.setURchar(character)
end

#setMyVTchar(character) ⇒ Object



462
463
464
465
# File 'lib/cdk/alphalist.rb', line 462

def setMyVTchar(character)
  @entry_field.setVTchar(character)
  @scroll_field.setVTchar(character)
end

#setPostProcess(callback, data) ⇒ Object

This function sets the post-process function.



512
513
514
# File 'lib/cdk/alphalist.rb', line 512

def setPostProcess(callback, data)
  @entry_field.setPostProcess(callback, data)
end

#setPreProcess(callback, data) ⇒ Object

This function sets the pre-process function.



507
508
509
# File 'lib/cdk/alphalist.rb', line 507

def setPreProcess(callback, data)
  @entry_field.setPreProcess(callback, data)
end

#unfocusObject



546
547
548
# File 'lib/cdk/alphalist.rb', line 546

def unfocus
  self.entry_field.unfocus
end