cdk 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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