slithernix-cdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cdk/scale.rb ADDED
@@ -0,0 +1,529 @@
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.maxx
9
+ parent_height = cdkscreen.window.maxy
10
+ bindings = {
11
+ 'u' => Curses::KEY_UP,
12
+ 'U' => Curses::KEY_PPAGE,
13
+ CDK::BACKCHAR => Curses::KEY_PPAGE,
14
+ CDK::FORCHAR => Curses::KEY_NPAGE,
15
+ 'g' => Curses::KEY_HOME,
16
+ '^' => Curses::KEY_HOME,
17
+ 'G' => Curses::KEY_END,
18
+ '$' => Curses::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 = Curses::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 = Curses::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
+ # Once again, I cannot figure out why this move method is called
178
+ # and removing the call fixes the widget.
179
+ def moveToEditPosition(new_position)
180
+ #return @field_win.move(0, @field_width - new_position - 1)
181
+ #return @field_win.move(24, @field_width - new_position - 1)
182
+ @field_win
183
+ end
184
+
185
+ # Check if the cursor is on a valid edit-position. This must be one of
186
+ # the non-blank cells in the field.
187
+ def validEditPosition(new_position)
188
+ if new_position <= 0 || new_position >= @field_width
189
+ return false
190
+ end
191
+ if self.moveToEditPosition(new_position) == Curses::Error
192
+ return false
193
+ end
194
+ ch = @field_win.inch
195
+ if ch.chr != ' '
196
+ return true
197
+ end
198
+ if new_position > 1
199
+ # Don't use recursion - only one level is wanted
200
+ if self.moveToEditPosition(new_position - 1) == Curses::Error
201
+ return false
202
+ end
203
+ ch = @field_win.inch
204
+ return ch.chr != ' '
205
+ end
206
+ return false
207
+ end
208
+
209
+ # Set the edit position. Normally the cursor is one cell to the right of
210
+ # the editable field. Moving it left over the field allows the user to
211
+ # modify cells by typing in replacement characters for the field's value.
212
+ def setEditPosition(new_position)
213
+ if new_position < 0
214
+ CDK.Beep
215
+ elsif new_position == 0
216
+ @field_edit = new_position
217
+ elsif self.validEditPosition(new_position)
218
+ @field_edit = new_position
219
+ else
220
+ CDK.Beep
221
+ end
222
+ end
223
+
224
+ # Remove the character from the string at the given column, if it is blank.
225
+ # Returns true if a change was made.
226
+ def self.removeChar(string, col)
227
+ result = false
228
+ if col >= 0 && string[col] != ' '
229
+ while col < string.size - 1
230
+ string[col] = string[col + 1]
231
+ col += 1
232
+ end
233
+ string.chop!
234
+ result = true
235
+ end
236
+ return result
237
+ end
238
+
239
+ # Perform an editing function for the field.
240
+ def performEdit(input)
241
+ result = false
242
+ modify = true
243
+ base = 0
244
+ need = @field_width
245
+ temp = ''
246
+ col = need - @field_edit - 1
247
+
248
+ @field_win.move(0, base)
249
+ @field_win.winnstr(temp, need)
250
+ temp << ' '
251
+ if CDK.isChar(input) # Replace the char at the cursor
252
+ temp[col] = input.chr
253
+ elsif input == Curses::KEY_BACKSPACE
254
+ # delete the char before the cursor
255
+ modify = CDK::SCALE.removeChar(temp, col - 1)
256
+ elsif input == Curses::KEY_DC
257
+ # delete the char at the cursor
258
+ modify = CDK::SCALE.removeChar(temp, col)
259
+ else
260
+ modify = false
261
+ end
262
+ if modify &&
263
+ ((value, test) = temp.scanf(self.SCAN_FMT)).size == 2 &&
264
+ test == ' ' &&
265
+ value >= @low && value <= @high
266
+ self.setValue(value)
267
+ result = true
268
+ end
269
+
270
+ return result
271
+ end
272
+
273
+ def self.Decrement(value, by)
274
+ if value - by < value
275
+ value - by
276
+ else
277
+ value
278
+ end
279
+ end
280
+
281
+ def self.Increment(value, by)
282
+ if value + by > value
283
+ value + by
284
+ else
285
+ value
286
+ end
287
+ end
288
+
289
+ # This function injects a single character into the widget.
290
+ def inject(input)
291
+ pp_return = 1
292
+ ret = -1
293
+ complete = false
294
+
295
+ # Set the exit type.
296
+ self.setExitType(0)
297
+
298
+ # Draw the field.
299
+ self.drawField
300
+
301
+ # Check if there is a pre-process function to be called.
302
+ unless @pre_process_func.nil?
303
+ # Call the pre-process function.
304
+ pp_return = @pre_process_func.call(self.object_type, self,
305
+ @pre_process_data, input)
306
+ end
307
+
308
+ # Should we continue?
309
+ if pp_return != 0
310
+ # Check for a key bindings.
311
+ if self.checkBind(self.object_type, input)
312
+ complete = true
313
+ else
314
+ case input
315
+ when Curses::KEY_LEFT
316
+ self.setEditPosition(@field_edit + 1)
317
+ when Curses::KEY_RIGHT
318
+ self.setEditPosition(@field_edit - 1)
319
+ when Curses::KEY_DOWN
320
+ @current = CDK::SCALE.Decrement(@current, @inc)
321
+ when Curses::KEY_UP
322
+ @current = CDK::SCALE.Increment(@current, @inc)
323
+ when Curses::KEY_PPAGE
324
+ @current = CDK::SCALE.Increment(@current, @fastinc)
325
+ when Curses::KEY_NPAGE
326
+ @current = CDK::SCALE.Decrement(@current, @fastinc)
327
+ when Curses::KEY_HOME
328
+ @current = @low
329
+ when Curses::KEY_END
330
+ @current = @high
331
+ when CDK::KEY_TAB, CDK::KEY_RETURN, Curses::KEY_ENTER
332
+ self.setExitType(input)
333
+ ret = @current
334
+ complete = true
335
+ when CDK::KEY_ESC
336
+ self.setExitType(input)
337
+ complete = true
338
+ when Curses::Error
339
+ self.setExitType(input)
340
+ complete = true
341
+ when CDK::REFRESH
342
+ @screen.erase
343
+ @screen.refresh
344
+ else
345
+ if @field_edit != 0
346
+ if !self.performEdit(input)
347
+ CDK.Beep
348
+ end
349
+ else
350
+ # The cursor is not within the editable text. Interpret
351
+ # input as commands.
352
+ case input
353
+ when 'd', '-'
354
+ return self.inject(Curses::KEY_DOWN)
355
+ when '+'
356
+ return self.inject(Curses::KEY_UP)
357
+ when 'D'
358
+ return self.inject(Curses::KEY_NPAGE)
359
+ when '0'
360
+ return self.inject(Curses::KEY_HOME)
361
+ else
362
+ CDK.Beep
363
+ end
364
+ end
365
+ end
366
+ end
367
+ self.limitCurrentValue
368
+
369
+ # Should we call a post-process?
370
+ if !complete && !(@post_process_func).nil?
371
+ @post_process_func.call(self.object_type, self,
372
+ @post_process_data, input)
373
+ end
374
+ end
375
+
376
+ if !complete
377
+ self.drawField
378
+ self.setExitType(0)
379
+ end
380
+
381
+ @result_data = ret
382
+ return ret
383
+ end
384
+
385
+ # This moves the widget's data field to the given location.
386
+ def move(xplace, yplace, relative, refresh_flag)
387
+ windows = [@win, @label_win, @field_win, @shadow_win]
388
+ self.move_specific(xplace, yplace, relative, refresh_flag,
389
+ windows, [])
390
+ end
391
+
392
+ # This function draws the widget.
393
+ def draw(box)
394
+ # Draw the shadow.
395
+ unless @shadow_win.nil?
396
+ Draw.drawShadow(@shadow_win)
397
+ end
398
+
399
+ # Box the widget if asked.
400
+ if box
401
+ Draw.drawObjBox(@win, self)
402
+ end
403
+
404
+ self.drawTitle(@win)
405
+
406
+ # Draw the label.
407
+ unless @label_win.nil?
408
+ Draw.writeChtype(@label_win, 0, 0, @label, CDK::HORIZONTAL,
409
+ 0, @label_len)
410
+ @label_win.refresh
411
+ end
412
+ @win.refresh
413
+
414
+ # Draw the field window.
415
+ self.drawField
416
+ end
417
+
418
+ # This draws the widget.
419
+ def drawField
420
+ @field_win.erase
421
+
422
+ # Draw the value in the field.
423
+ temp = @current.to_s
424
+ Draw.writeCharAttrib(@field_win,
425
+ @field_width - temp.size - 1, 0, temp, @field_attr,
426
+ CDK::HORIZONTAL, 0, temp.size)
427
+
428
+ self.moveToEditPosition(@field_edit)
429
+ @field_win.refresh
430
+ end
431
+
432
+ # This sets the background attribute of teh widget.
433
+ def setBKattr(attrib)
434
+ @win.wbkgd(attrib)
435
+ @field_win.wbkgd(attrib)
436
+ unless @label_win.nil?
437
+ @label_win.wbkgd(attrib)
438
+ end
439
+ end
440
+
441
+ # This function destroys the widget.
442
+ def destroy
443
+ self.cleanTitle
444
+ @label = []
445
+
446
+ # Clean up the windows.
447
+ CDK.deleteCursesWindow(@field_win)
448
+ CDK.deleteCursesWindow(@label_win)
449
+ CDK.deleteCursesWindow(@shadow_win)
450
+ CDK.deleteCursesWindow(@win)
451
+
452
+ # Clean the key bindings.
453
+ self.cleanBindings(self.object_type)
454
+
455
+ # Unregister this object
456
+ CDK::SCREEN.unregister(self.object_type, self)
457
+ end
458
+
459
+ # This function erases the widget from the screen.
460
+ def erase
461
+ if self.validCDKObject
462
+ CDK.eraseCursesWindow(@label_win)
463
+ CDK.eraseCursesWindow(@field_win)
464
+ CDK.eraseCursesWindow(@win)
465
+ CDK.eraseCursesWindow(@shadow_win)
466
+ end
467
+ end
468
+
469
+ # This function sets the low/high/current values of the widget.
470
+ def set(low, high, value, box)
471
+ self.setLowHigh(low, high)
472
+ self.setValue(value)
473
+ self.setBox(box)
474
+ end
475
+
476
+ # This sets the widget's value
477
+ def setValue(value)
478
+ @current = value
479
+ self.limitCurrentValue
480
+ end
481
+
482
+ def getValue
483
+ return @current
484
+ end
485
+
486
+ # This function sets the low/high values of the widget.
487
+ def setLowHigh(low, high)
488
+ # Make sure the values aren't out of bounds.
489
+ if low <= high
490
+ @low = low
491
+ @high = high
492
+ elsif low > high
493
+ @low = high
494
+ @high = low
495
+ end
496
+
497
+ # Make sure the user hasn't done something silly.
498
+ self.limitCurrentValue
499
+ end
500
+
501
+ def getLowValue
502
+ return @low
503
+ end
504
+
505
+ def getHighValue
506
+ return @high
507
+ end
508
+
509
+ def focus
510
+ self.draw(@box)
511
+ end
512
+
513
+ def unfocus
514
+ self.draw(@box)
515
+ end
516
+
517
+ def position
518
+ super(@win)
519
+ end
520
+
521
+ def SCAN_FMT
522
+ '%d%c'
523
+ end
524
+
525
+ def object_type
526
+ :SCALE
527
+ end
528
+ end
529
+ end