cdk 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,525 @@
1
+ require_relative 'cdk_objs'
2
+
3
+ module CDK
4
+ class SCALE < CDK::CDKOBJS
5
+ def initialize(cdkscreen, xplace, yplace, title, label, field_attr,
6
+ field_width, start, low, high, inc, fast_inc, box, shadow)
7
+ super()
8
+ parent_width = cdkscreen.window.getmaxx
9
+ parent_height = cdkscreen.window.getmaxy
10
+ bindings = {
11
+ 'u' => Ncurses::KEY_UP,
12
+ 'U' => Ncurses::KEY_PPAGE,
13
+ CDK::BACKCHAR => Ncurses::KEY_PPAGE,
14
+ CDK::FORCHAR => Ncurses::KEY_NPAGE,
15
+ 'g' => Ncurses::KEY_HOME,
16
+ '^' => Ncurses::KEY_HOME,
17
+ 'G' => Ncurses::KEY_END,
18
+ '$' => Ncurses::KEY_END,
19
+ }
20
+
21
+ self.setBox(box)
22
+
23
+ box_height = @border_size * 2 + 1
24
+ box_width = field_width + 2 * @border_size
25
+
26
+ # Set some basic values of the widget's data field.
27
+ @label = []
28
+ @label_len = 0
29
+ @label_win = nil
30
+
31
+ # If the field_width is a negative value, the field_width will
32
+ # be COLS-field_width, otherwise the field_width will be the
33
+ # given width.
34
+ field_width = CDK.setWidgetDimension(parent_width, field_width, 0)
35
+ box_width = field_width + 2 * @border_size
36
+
37
+ # Translate the label string to a chtype array
38
+ unless label.nil?
39
+ label_len = []
40
+ @label = CDK.char2Chtype(label, label_len, [])
41
+ @label_len = label_len[0]
42
+ box_width = @label_len + field_width + 2
43
+ end
44
+
45
+ old_width = box_width
46
+ box_width = self.setTitle(title, box_width)
47
+ horizontal_adjust = (box_width - old_width) / 2
48
+
49
+ box_height += @title_lines
50
+
51
+ # Make sure we didn't extend beyond the dimensions of the window.
52
+ box_width = [box_width, parent_width].min
53
+ box_height = [box_height, parent_height].min
54
+ field_width = [field_width,
55
+ box_width - @label_len - 2 * @border_size].min
56
+
57
+ # Rejustify the x and y positions if we need to.
58
+ xtmp = [xplace]
59
+ ytmp = [yplace]
60
+ CDK.alignxy(cdkscreen.window, xtmp, ytmp, box_width, box_height)
61
+ xpos = xtmp[0]
62
+ ypos = ytmp[0]
63
+
64
+ # Make the widget's window.
65
+ @win = Ncurses::WINDOW.new(box_height, box_width, ypos, xpos)
66
+
67
+ # Is the main window nil?
68
+ if @win.nil?
69
+ self.destroy
70
+ return nil
71
+ end
72
+
73
+ # Create the widget's label window.
74
+ if @label.size > 0
75
+ @label_win = @win.subwin(1, @label_len,
76
+ ypos + @title_lines + @border_size,
77
+ xpos + horizontal_adjust + @border_size)
78
+ if @label_win.nil?
79
+ self.destroy
80
+ return nil
81
+ end
82
+ end
83
+
84
+ # Create the widget's data field window.
85
+ @field_win = @win.subwin(1, field_width,
86
+ ypos + @title_lines + @border_size,
87
+ xpos + @label_len + horizontal_adjust + @border_size)
88
+
89
+ if @field_win.nil?
90
+ self.destroy
91
+ return nil
92
+ end
93
+ @field_win.keypad(true)
94
+ @win.keypad(true)
95
+
96
+ # Create the widget's data field.
97
+ @screen = cdkscreen
98
+ @parent = cdkscreen.window
99
+ @shadow_win = nil
100
+ @box_width = box_width
101
+ @box_height = box_height
102
+ @field_width = field_width
103
+ @field_attr = field_attr
104
+ @current = low
105
+ @low = low
106
+ @high = high
107
+ @current = start
108
+ @inc = inc
109
+ @fastinc = fast_inc
110
+ @accepts_focus = true
111
+ @input_window = @win
112
+ @shadow = shadow
113
+ @field_edit = 0
114
+
115
+ # Do we want a shadow?
116
+ if shadow
117
+ @shadow_win = Ncurses::WINDOW.new(box_height, box_width,
118
+ ypos + 1, xpos + 1)
119
+ if @shadow_win.nil?
120
+ self.destroy
121
+ return nil
122
+ end
123
+ end
124
+
125
+ # Setup the key bindings.
126
+ bindings.each do |from, to|
127
+ self.bind(self.object_type, from, :getc, to)
128
+ end
129
+
130
+ cdkscreen.register(self.object_type, self)
131
+ end
132
+
133
+ # This allows the person to use the widget's data field.
134
+ def activate(actions)
135
+ ret = -1
136
+ # Draw the widget.
137
+ self.draw(@box)
138
+
139
+ if actions.nil? || actions.size == 0
140
+ input = 0
141
+ while true
142
+ input = self.getch([])
143
+
144
+ # Inject the character into the widget.
145
+ ret = self.inject(input)
146
+ if @exit_type != :EARLY_EXIT
147
+ return ret
148
+ end
149
+ end
150
+ else
151
+ # Inject each character one at a time.
152
+ actions.each do |action|
153
+ ret = self.inject(action)
154
+ end
155
+ if @exit_type != :EARLY_EXIT
156
+ return ret
157
+ end
158
+ end
159
+
160
+ # Set the exit type and return.
161
+ self.setExitType(0)
162
+ return ret
163
+ end
164
+
165
+ # Check if the value lies outsid the low/high range. If so, force it in.
166
+ def limitCurrentValue
167
+ if @current < @low
168
+ @current = @low
169
+ CDK.Beep
170
+ elsif @current > @high
171
+ @current = @high
172
+ CDK.Beep
173
+ end
174
+ end
175
+
176
+ # Move the cursor to the given edit-position
177
+ def moveToEditPosition(new_position)
178
+ return @field_win.wmove(0, @field_width - new_position - 1)
179
+ end
180
+
181
+ # Check if the cursor is on a valid edit-position. This must be one of
182
+ # the non-blank cells in the field.
183
+ def validEditPosition(new_position)
184
+ if new_position <= 0 || new_position >= @field_width
185
+ return false
186
+ end
187
+ if self.moveToEditPosition(new_position) == Ncurses::ERR
188
+ return false
189
+ end
190
+ ch = @field_win.winch
191
+ if ch.chr != ' '
192
+ return true
193
+ end
194
+ if new_position > 1
195
+ # Don't use recursion - only one level is wanted
196
+ if self.moveToEditPosition(new_position - 1) == Ncurses::ERR
197
+ return false
198
+ end
199
+ ch = @field_win.winch
200
+ return ch.chr != ' '
201
+ end
202
+ return false
203
+ end
204
+
205
+ # Set the edit position. Normally the cursor is one cell to the right of
206
+ # the editable field. Moving it left over the field allows the user to
207
+ # modify cells by typing in replacement characters for the field's value.
208
+ def setEditPosition(new_position)
209
+ if new_position < 0
210
+ CDK.Beep
211
+ elsif new_position == 0
212
+ @field_edit = new_position
213
+ elsif self.validEditPosition(new_position)
214
+ @field_edit = new_position
215
+ else
216
+ CDK.Beep
217
+ end
218
+ end
219
+
220
+ # Remove the character from the string at the given column, if it is blank.
221
+ # Returns true if a change was made.
222
+ def self.removeChar(string, col)
223
+ result = false
224
+ if col >= 0 && string[col] != ' '
225
+ while col < string.size - 1
226
+ string[col] = string[col + 1]
227
+ col += 1
228
+ end
229
+ string.chop!
230
+ result = true
231
+ end
232
+ return result
233
+ end
234
+
235
+ # Perform an editing function for the field.
236
+ def performEdit(input)
237
+ result = false
238
+ modify = true
239
+ base = 0
240
+ need = @field_width
241
+ temp = ''
242
+ col = need - @field_edit - 1
243
+
244
+ @field_win.wmove(0, base)
245
+ @field_win.winnstr(temp, need)
246
+ temp << ' '
247
+ if CDK.isChar(input) # Replace the char at the cursor
248
+ temp[col] = input.chr
249
+ elsif input == Ncurses::KEY_BACKSPACE
250
+ # delete the char before the cursor
251
+ modify = CDK::SCALE.removeChar(temp, col - 1)
252
+ elsif input == Ncurses::KEY_DC
253
+ # delete the char at the cursor
254
+ modify = CDK::SCALE.removeChar(temp, col)
255
+ else
256
+ modify = false
257
+ end
258
+ if modify &&
259
+ ((value, test) = temp.scanf(self.SCAN_FMT)).size == 2 &&
260
+ test == ' ' &&
261
+ value >= @low && value <= @high
262
+ self.setValue(value)
263
+ result = true
264
+ end
265
+
266
+ return result
267
+ end
268
+
269
+ def self.Decrement(value, by)
270
+ if value - by < value
271
+ value - by
272
+ else
273
+ value
274
+ end
275
+ end
276
+
277
+ def self.Increment(value, by)
278
+ if value + by > value
279
+ value + by
280
+ else
281
+ value
282
+ end
283
+ end
284
+
285
+ # This function injects a single character into the widget.
286
+ def inject(input)
287
+ pp_return = 1
288
+ ret = -1
289
+ complete = false
290
+
291
+ # Set the exit type.
292
+ self.setExitType(0)
293
+
294
+ # Draw the field.
295
+ self.drawField
296
+
297
+ # Check if there is a pre-process function to be called.
298
+ unless @pre_process_func.nil?
299
+ # Call the pre-process function.
300
+ pp_return = @pre_process_func.call(self.object_type, self,
301
+ @pre_process_data, input)
302
+ end
303
+
304
+ # Should we continue?
305
+ if pp_return != 0
306
+ # Check for a key bindings.
307
+ if self.checkBind(self.object_type, input)
308
+ complete = true
309
+ else
310
+ case input
311
+ when Ncurses::KEY_LEFT
312
+ self.setEditPosition(@field_edit + 1)
313
+ when Ncurses::KEY_RIGHT
314
+ self.setEditPosition(@field_edit - 1)
315
+ when Ncurses::KEY_DOWN
316
+ @current = CDK::SCALE.Decrement(@current, @inc)
317
+ when Ncurses::KEY_UP
318
+ @current = CDK::SCALE.Increment(@current, @inc)
319
+ when Ncurses::KEY_PPAGE
320
+ @current = CDK::SCALE.Increment(@current, @fastinc)
321
+ when Ncurses::KEY_NPAGE
322
+ @current = CDK::SCALE.Decrement(@current, @fastinc)
323
+ when Ncurses::KEY_HOME
324
+ @current = @low
325
+ when Ncurses::KEY_END
326
+ @current = @high
327
+ when CDK::KEY_TAB, CDK::KEY_RETURN, Ncurses::KEY_ENTER
328
+ self.setExitType(input)
329
+ ret = @current
330
+ complete = true
331
+ when CDK::KEY_ESC
332
+ self.setExitType(input)
333
+ complete = true
334
+ when Ncurses::ERR
335
+ self.setExitType(input)
336
+ complete = true
337
+ when CDK::REFRESH
338
+ @screen.erase
339
+ @screen.refresh
340
+ else
341
+ if @field_edit != 0
342
+ if !self.performEdit(input)
343
+ CDK.Beep
344
+ end
345
+ else
346
+ # The cursor is not within the editable text. Interpret
347
+ # input as commands.
348
+ case input
349
+ when 'd'.ord, '-'.ord
350
+ return self.inject(Ncurses::KEY_DOWN)
351
+ when '+'.ord
352
+ return self.inject(Ncurses::KEY_UP)
353
+ when 'D'.ord
354
+ return self.inject(Ncurses::KEY_NPAGE)
355
+ when '0'.ord
356
+ return self.inject(Ncurses::KEY_HOME)
357
+ else
358
+ CDK.Beep
359
+ end
360
+ end
361
+ end
362
+ end
363
+ self.limitCurrentValue
364
+
365
+ # Should we call a post-process?
366
+ if !complete && !(@post_process_func).nil?
367
+ @post_process_func.call(self.object_type, self,
368
+ @post_process_data, input)
369
+ end
370
+ end
371
+
372
+ if !complete
373
+ self.drawField
374
+ self.setExitType(0)
375
+ end
376
+
377
+ @result_data = ret
378
+ return ret
379
+ end
380
+
381
+ # This moves the widget's data field to the given location.
382
+ def move(xplace, yplace, relative, refresh_flag)
383
+ windows = [@win, @label_win, @field_win, @shadow_win]
384
+ self.move_specific(xplace, yplace, relative, refresh_flag,
385
+ windows, [])
386
+ end
387
+
388
+ # This function draws the widget.
389
+ def draw(box)
390
+ # Draw the shadow.
391
+ unless @shadow_win.nil?
392
+ Draw.drawShadow(@shadow_win)
393
+ end
394
+
395
+ # Box the widget if asked.
396
+ if box
397
+ Draw.drawObjBox(@win, self)
398
+ end
399
+
400
+ self.drawTitle(@win)
401
+
402
+ # Draw the label.
403
+ unless @label_win.nil?
404
+ Draw.writeChtype(@label_win, 0, 0, @label, CDK::HORIZONTAL,
405
+ 0, @label_len)
406
+ @label_win.wrefresh
407
+ end
408
+ @win.wrefresh
409
+
410
+ # Draw the field window.
411
+ self.drawField
412
+ end
413
+
414
+ # This draws the widget.
415
+ def drawField
416
+ @field_win.werase
417
+
418
+ # Draw the value in the field.
419
+ temp = @current.to_s
420
+ Draw.writeCharAttrib(@field_win,
421
+ @field_width - temp.size - 1, 0, temp, @field_attr,
422
+ CDK::HORIZONTAL, 0, temp.size)
423
+
424
+ self.moveToEditPosition(@field_edit)
425
+ @field_win.wrefresh
426
+ end
427
+
428
+ # This sets the background attribute of teh widget.
429
+ def setBKattr(attrib)
430
+ @win.wbkgd(attrib)
431
+ @field_win.wbkgd(attrib)
432
+ unless @label_win.nil?
433
+ @label_win.wbkgd(attrib)
434
+ end
435
+ end
436
+
437
+ # This function destroys the widget.
438
+ def destroy
439
+ self.cleanTitle
440
+ @label = []
441
+
442
+ # Clean up the windows.
443
+ CDK.deleteCursesWindow(@field_win)
444
+ CDK.deleteCursesWindow(@label_win)
445
+ CDK.deleteCursesWindow(@shadow_win)
446
+ CDK.deleteCursesWindow(@win)
447
+
448
+ # Clean the key bindings.
449
+ self.cleanBindings(self.object_type)
450
+
451
+ # Unregister this object
452
+ CDK::SCREEN.unregister(self.object_type, self)
453
+ end
454
+
455
+ # This function erases the widget from the screen.
456
+ def erase
457
+ if self.validCDKObject
458
+ CDK.eraseCursesWindow(@label_win)
459
+ CDK.eraseCursesWindow(@field_win)
460
+ CDK.eraseCursesWindow(@win)
461
+ CDK.eraseCursesWindow(@shadow_win)
462
+ end
463
+ end
464
+
465
+ # This function sets the low/high/current values of the widget.
466
+ def set(low, high, value, box)
467
+ self.setLowHigh(low, high)
468
+ self.setValue(value)
469
+ self.setBox(box)
470
+ end
471
+
472
+ # This sets the widget's value
473
+ def setValue(value)
474
+ @current = value
475
+ self.limitCurrentValue
476
+ end
477
+
478
+ def getValue
479
+ return @current
480
+ end
481
+
482
+ # This function sets the low/high values of the widget.
483
+ def setLowHigh(low, high)
484
+ # Make sure the values aren't out of bounds.
485
+ if low <= high
486
+ @low = low
487
+ @high = high
488
+ elsif low > high
489
+ @low = high
490
+ @high = low
491
+ end
492
+
493
+ # Make sure the user hasn't done something silly.
494
+ self.limitCurrentValue
495
+ end
496
+
497
+ def getLowValue
498
+ return @low
499
+ end
500
+
501
+ def getHighValue
502
+ return @high
503
+ end
504
+
505
+ def focus
506
+ self.draw(@box)
507
+ end
508
+
509
+ def unfocus
510
+ self.draw(@box)
511
+ end
512
+
513
+ def position
514
+ super(@win)
515
+ end
516
+
517
+ def SCAN_FMT
518
+ '%d%c'
519
+ end
520
+
521
+ def object_type
522
+ :SCALE
523
+ end
524
+ end
525
+ end