Class: CDK::ALPHALIST

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

Instance Attribute Summary collapse

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

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ListSupport

#search_list

Methods inherited from CDKOBJS

#setBackgroundColor, #timeout, #validCDKObject, #validObjType

Methods included from WindowHooks

#refreshData, #saveData

Methods included from WindowInput

#getc, #getch

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, height, width, title, label, list, list_size, filler_char, highlight, box, shadow) ⇒ ALPHALIST

Returns a new instance of ALPHALIST.



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
280
281
282
# File 'lib/cdk/components/alphalist.rb', line 10

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 = char2Chtype(label, lentmp, [])
    label_len = lentmp[0]
  end

  # Rejustify the x and y positions if we need to.
  xtmp = [xplace]
  ytmp = [yplace]
  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 = 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 = search_list(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 = search_list(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.



8
9
10
# File 'lib/cdk/components/alphalist.rb', line 8

def entry_field
  @entry_field
end

#listObject (readonly)

Returns the value of attribute list.



8
9
10
# File 'lib/cdk/components/alphalist.rb', line 8

def list
  @list
end

#scroll_fieldObject (readonly)

Returns the value of attribute scroll_field.



8
9
10
# File 'lib/cdk/components/alphalist.rb', line 8

def scroll_field
  @scroll_field
end

Class Method Details

.isFullWidth(width) ⇒ Object



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

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

Instance Method Details

#activate(actions) ⇒ Object

This activates the alphalist



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/cdk/components/alphalist.rb', line 343

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



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

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



492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/cdk/components/alphalist.rb', line 492

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



486
487
488
489
# File 'lib/cdk/components/alphalist.rb', line 486

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

#draw(box) ⇒ Object

This draws the alphalist widget.



329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/cdk/components/alphalist.rb', line 329

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



316
317
318
319
320
# File 'lib/cdk/components/alphalist.rb', line 316

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

#eraseObject

This erases the alphalist from the screen.



285
286
287
288
289
290
291
292
293
# File 'lib/cdk/components/alphalist.rb', line 285

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

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

#focusObject



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

def focus
  self.entry_field.focus
end

#getContents(size) ⇒ Object

This returns the contents of the widget.



412
413
414
415
# File 'lib/cdk/components/alphalist.rb', line 412

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

#getCurrentItemObject

Get/set the current position in the scroll widget.



418
419
420
# File 'lib/cdk/components/alphalist.rb', line 418

def getCurrentItem
  return @scroll_field.getCurrentItem
end

#getFillerCharObject



435
436
437
# File 'lib/cdk/components/alphalist.rb', line 435

def getFillerChar
  return @filler_char
end

#getHighlightObject



444
445
446
# File 'lib/cdk/components/alphalist.rb', line 444

def getHighlight
  @highlight
end

#inject(input) ⇒ Object

This injects a single character into the alphalist.



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

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



322
323
324
325
326
# File 'lib/cdk/components/alphalist.rb', line 322

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.



296
297
298
299
300
301
# File 'lib/cdk/components/alphalist.rb', line 296

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



561
562
563
# File 'lib/cdk/components/alphalist.rb', line 561

def object_type
  :ALPHALIST
end

#positionObject



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

def position
  super(@win)
end

#restoreFocusObject



312
313
314
# File 'lib/cdk/components/alphalist.rb', line 312

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.



307
308
309
310
# File 'lib/cdk/components/alphalist.rb', line 307

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.



385
386
387
388
389
390
# File 'lib/cdk/components/alphalist.rb', line 385

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.



481
482
483
484
# File 'lib/cdk/components/alphalist.rb', line 481

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.



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/cdk/components/alphalist.rb', line 393

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



422
423
424
425
426
427
# File 'lib/cdk/components/alphalist.rb', line 422

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.



430
431
432
433
# File 'lib/cdk/components/alphalist.rb', line 430

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

#setHighlight(highlight) ⇒ Object

This sets the highlgith bar attributes



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

def setHighlight(highlight)
  @highlight = highlight
end

#setMyBXattr(character) ⇒ Object



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

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

#setMyHZchar(character) ⇒ Object



470
471
472
473
# File 'lib/cdk/components/alphalist.rb', line 470

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

#setMyLLchar(character) ⇒ Object



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

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

#setMyLRchar(character) ⇒ Object



461
462
463
# File 'lib/cdk/components/alphalist.rb', line 461

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

#setMyULchar(character) ⇒ Object

These functions set the drawing characters of the widget.



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

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

#setMyURchar(character) ⇒ Object



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

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

#setMyVTchar(character) ⇒ Object



465
466
467
468
# File 'lib/cdk/components/alphalist.rb', line 465

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

#setPostProcess(callback, data) ⇒ Object

This function sets the post-process function.



515
516
517
# File 'lib/cdk/components/alphalist.rb', line 515

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

#setPreProcess(callback, data) ⇒ Object

This function sets the pre-process function.



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

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

#unfocusObject



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

def unfocus
  self.entry_field.unfocus
end