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/matrix.rb ADDED
@@ -0,0 +1,1176 @@
1
+ require_relative 'cdk_objs'
2
+
3
+ module CDK
4
+ class MATRIX < CDK::CDKOBJS
5
+ attr_accessor :info
6
+ attr_reader :colvalues, :row, :col, :colwidths, :filler
7
+ attr_reader :crow, :ccol
8
+ MAX_MATRIX_ROWS = 1000
9
+ MAX_MATRIX_COLS = 1000
10
+
11
+ @@g_paste_buffer = ''
12
+
13
+ def initialize(cdkscreen, xplace, yplace, rows, cols, vrows, vcols,
14
+ title, rowtitles, coltitles, colwidths, colvalues, rspace, cspace,
15
+ filler, dominant, box, box_cell, shadow)
16
+ super()
17
+ parent_width = cdkscreen.window.maxx
18
+ parent_height = cdkscreen.window.maxy
19
+ box_height = 0
20
+ box_width = 0
21
+ max_row_title_width = 0
22
+ row_space = [0, rspace].max
23
+ col_space = [0, cspace].max
24
+ begx = 0
25
+ begy = 0
26
+ cell_width = 0
27
+ have_rowtitles = false
28
+ have_coltitles = false
29
+ bindings = {
30
+ CDK::FORCHAR => Curses::KEY_NPAGE,
31
+ CDK::BACKCHAR => Curses::KEY_PPAGE,
32
+ }
33
+
34
+ self.setBox(box)
35
+ borderw = if @box then 1 else 0 end
36
+
37
+ # Make sure that the number of rows/cols/vrows/vcols is not zero.
38
+ if rows <= 0 || cols <= 0 || vrows <= 0 || vcols <= 0
39
+ self.destroy
40
+ return nil
41
+ end
42
+
43
+ @cell = Array.new(rows + 1) { |i| Array.new(cols + 1)}
44
+ @info = Array.new(rows + 1) { |i| Array.new(cols + 1) { |i| '' }}
45
+
46
+ # Make sure the number of virtual cells is not larger than the
47
+ # physical size.
48
+ vrows = [vrows, rows].min
49
+ vcols = [vcols, cols].min
50
+
51
+ @rows = rows
52
+ @cols = cols
53
+ @colwidths = [0] * (cols + 1)
54
+ @colvalues = [0] * (cols + 1)
55
+ @coltitle = Array.new(cols + 1) {|i| []}
56
+ @coltitle_len = [0] * (cols + 1)
57
+ @coltitle_pos = [0] * (cols + 1)
58
+ @rowtitle = Array.new(rows + 1) {|i| []}
59
+ @rowtitle_len = [0] * (rows + 1)
60
+ @rowtitle_pos = [0] * (rows + 1)
61
+
62
+ # Count the number of lines in the title
63
+ temp = title.split("\n")
64
+ @title_lines = temp.size
65
+
66
+ # Determine the height of the box.
67
+ if vrows == 1
68
+ box_height = 6 + @title_lines
69
+ else
70
+ if row_space == 0
71
+ box_height = 6 + @title_lines + (vrows - 1) * 2
72
+ else
73
+ box_height = 3 + @title_lines + vrows * 3 +
74
+ (vrows - 1) * (row_space - 1)
75
+ end
76
+ end
77
+
78
+ # Determine the maximum row title width.
79
+ (1..rows).each do |x|
80
+ if !(rowtitles.nil?) && x < rowtitles.size && rowtitles[x].size > 0
81
+ have_rowtitles = true
82
+ end
83
+ rowtitle_len = []
84
+ rowtitle_pos = []
85
+ @rowtitle[x] = CDK.char2Chtype((rowtitles[x] || ''),
86
+ rowtitle_len, rowtitle_pos)
87
+ @rowtitle_len[x] = rowtitle_len[0]
88
+ @rowtitle_pos[x] = rowtitle_pos[0]
89
+ max_row_title_width = [max_row_title_width, @rowtitle_len[x]].max
90
+ end
91
+
92
+ if have_rowtitles
93
+ @maxrt = max_row_title_width + 2
94
+
95
+ # We need to rejustify the row title cell info.
96
+ (1..rows).each do |x|
97
+ @rowtitle_pos[x] = CDK.justifyString(@maxrt,
98
+ @rowtitle_len[x], @rowtitle_pos[x])
99
+ end
100
+ else
101
+ @maxrt = 0
102
+ end
103
+
104
+ # Determine the width of the matrix.
105
+ max_width = 2 + @maxrt
106
+ (1..vcols).each do |x|
107
+ max_width += colwidths[x] + 2 + col_space
108
+ end
109
+ max_width -= (col_space - 1)
110
+ box_width = [max_width, box_width].max
111
+ box_width = self.setTitle(title, box_width)
112
+
113
+ # Make sure the dimensions of the window didn't extend
114
+ # beyond the dimensions of the parent window
115
+ box_width = [box_width, parent_width].min
116
+ box_height = [box_height, parent_height].min
117
+
118
+ # Rejustify the x and y positions if we need to.
119
+ xtmp = [xplace]
120
+ ytmp = [yplace]
121
+ CDK.alignxy(cdkscreen.window, xtmp, ytmp, box_width, box_height)
122
+ xpos = xtmp[0]
123
+ ypos = ytmp[0]
124
+
125
+ # Make the pop-up window.
126
+ @win = Curses::Window.new(box_height, box_width, ypos, xpos)
127
+
128
+ if @win.nil?
129
+ self.destroy
130
+ return nil
131
+ end
132
+
133
+ # Make the subwindows in the pop-up.
134
+ begx = xpos
135
+ begy = ypos + borderw + @title_lines
136
+
137
+ # Make the 'empty' 0x0 cell.
138
+ @cell[0][0] = @win.subwin(3, @maxrt, begy, begx)
139
+
140
+ begx += @maxrt + 1
141
+
142
+ # Copy the titles into the structrue.
143
+ (1..cols).each do |x|
144
+ if !(coltitles.nil?) && x < coltitles.size && coltitles[x].size > 0
145
+ have_coltitles = true
146
+ end
147
+ coltitle_len = []
148
+ coltitle_pos = []
149
+ @coltitle[x] = CDK.char2Chtype(coltitles[x] || '',
150
+ coltitle_len, coltitle_pos)
151
+ @coltitle_len[x] = coltitle_len[0]
152
+ @coltitle_pos[x] = @border_size + CDK.justifyString(
153
+ colwidths[x], @coltitle_len[x], coltitle_pos[0])
154
+ @colwidths[x] = colwidths[x]
155
+ end
156
+
157
+ if have_coltitles
158
+ # Make the column titles.
159
+ (1..vcols).each do |x|
160
+ cell_width = colwidths[x] + 3
161
+ @cell[0][x] = @win.subwin(borderw, cell_width, begy, begx)
162
+ if @cell[0][x].nil?
163
+ self.destroy
164
+ return nil
165
+ end
166
+ begx += cell_width + col_space - 1
167
+ end
168
+ begy += 1
169
+ end
170
+
171
+ # Make the main cell body
172
+ (1..vrows).each do |x|
173
+ if have_rowtitles
174
+ # Make the row titles
175
+ @cell[x][0] = @win.subwin(3, @maxrt, begy, xpos + borderw)
176
+
177
+ if @cell[x][0].nil?
178
+ self.destroy
179
+ return nil
180
+ end
181
+ end
182
+
183
+ # Set the start of the x position.
184
+ begx = xpos + @maxrt + borderw
185
+
186
+ # Make the cells
187
+ (1..vcols).each do |y|
188
+ cell_width = colwidths[y] + 3
189
+ @cell[x][y] = @win.subwin(3, cell_width, begy, begx)
190
+
191
+ if @cell[x][y].nil?
192
+ self.destroy
193
+ return nil
194
+ end
195
+ begx += cell_width + col_space - 1
196
+ @cell[x][y].keypad(true)
197
+ end
198
+ begy += row_space + 2
199
+ end
200
+ @win.keypad(true)
201
+
202
+ # Keep the rest of the info.
203
+ @screen = cdkscreen
204
+ @accepts_focus = true
205
+ @input_window = @win
206
+ @parent = cdkscreen.window
207
+ @vrows = vrows
208
+ @vcols = vcols
209
+ @box_width = box_width
210
+ @box_height = box_height
211
+ @row_space = row_space
212
+ @col_space = col_space
213
+ @filler = filler.ord
214
+ @dominant = dominant
215
+ @row = 1
216
+ @col = 1
217
+ @crow = 1
218
+ @ccol = 1
219
+ @trow = 1
220
+ @lcol = 1
221
+ @oldcrow = 1
222
+ @oldccol = 1
223
+ @oldvrow = 1
224
+ @oldvcol = 1
225
+ @box_cell = box_cell
226
+ @shadow = shadow
227
+ @highlight = Curses::A_REVERSE
228
+ @shadow_win = nil
229
+ @callbackfn = lambda do |matrix, input|
230
+ disptype = matrix.colvalues[matrix.col]
231
+ plainchar = Display.filterByDisplayType(disptype, input)
232
+ charcount = matrix.info[matrix.row][matrix.col].size
233
+
234
+ if plainchar == Curses::Error
235
+ CDK.Beep
236
+ elsif charcount == matrix.colwidths[matrix.col]
237
+ CDK.Beep
238
+ else
239
+ # Update the screen.
240
+ matrix.CurMatrixCell.move(1,
241
+ matrix.info[matrix.row][matrix.col].size + 1)
242
+ matrix.CurMatrixCell.addch(
243
+ if Display.isHiddenDisplayType(disptype)
244
+ then matrix.filler
245
+ else plainchar
246
+ end)
247
+ matrix.CurMatrixCell.refresh
248
+
249
+ # Update the info string
250
+ matrix.info[matrix.row][matrix.col] =
251
+ matrix.info[matrix.row][matrix.col][0...charcount] +
252
+ plainchar.chr
253
+ end
254
+ end
255
+
256
+ # Make room for the cell information.
257
+ (1..rows).each do |x|
258
+ (1..cols).each do |y|
259
+ @colvalues[y] = colvalues[y]
260
+ @colwidths[y] = colwidths[y]
261
+ end
262
+ end
263
+
264
+ @colvalues = colvalues.clone
265
+ @colwidths = colwidths.clone
266
+
267
+ # Do we want a shadow?
268
+ if shadow
269
+ @shadow_win = Curses::Window.new(box_height, box_width,
270
+ ypos + 1, xpos + 1)
271
+ end
272
+
273
+ # Set up the key bindings.
274
+ bindings.each do |from, to|
275
+ self.bind(:MATRIX, from, :getc, to)
276
+ end
277
+
278
+ # Register this baby.
279
+ cdkscreen.register(:MATRIX, self)
280
+ end
281
+
282
+ # This activates the matrix.
283
+ def activate(actions)
284
+ self.draw(@box)
285
+
286
+ if actions.nil? || actions.size == 0
287
+ while true
288
+ @input_window = self.CurMatrixCell
289
+ @input_window.keypad(true)
290
+ input = self.getch([])
291
+
292
+ # Inject the character into the widget.
293
+ ret = self.inject(input)
294
+ if @exit_type != :EARLY_EXIT
295
+ return ret
296
+ end
297
+ end
298
+ else
299
+ # Inject each character one at a time.
300
+ actions.each do |action|
301
+ ret = self.inject(action)
302
+ if @exit_type != :EARLY_EXIT
303
+ return ret
304
+ end
305
+ end
306
+ end
307
+
308
+ # Set the exit type and exit.
309
+ self.setExitType(0)
310
+ return -1
311
+ end
312
+
313
+ # This injects a single character into the matrix widget.
314
+ def inject(input)
315
+ refresh_cells = false
316
+ moved_cell = false
317
+ charcount = @info[@row][@col].size
318
+ pp_return = 1
319
+ ret = -1
320
+ complete = false
321
+
322
+ # Set the exit type.
323
+ self.setExitType(0)
324
+
325
+ # Move the cursor to the correct position within the cell.
326
+ if @colwidths[@ccol] == 1
327
+ self.CurMatrixCell.move(1, 1)
328
+ else
329
+ self.CurMatrixCell.move(1, @info[@row][@col].size + 1)
330
+ end
331
+
332
+ # Put the focus on the current cell.
333
+ self.focusCurrent
334
+
335
+ # Check if there is a pre-process function to be called.
336
+ unless @pre_process_func.nil?
337
+ # Call the pre-process function.
338
+ pp_return = @pre_process_func.call(:MATRIX, self,
339
+ @pre_process_data, input)
340
+ end
341
+
342
+ # Should we continue?
343
+ if pp_return != 0
344
+ # Check the key bindings.
345
+ if self.checkBind(:MATRIX, input)
346
+ complete = true
347
+ else
348
+ case input
349
+ when CDK::TRANSPOSE
350
+ when Curses::KEY_HOME
351
+ when Curses::KEY_END
352
+ when Curses::KEY_BACKSPACE, Curses::KEY_DC
353
+ if @colvalues[@col] == :VIEWONLY || charcount <= 0
354
+ CDK.Beep
355
+ else
356
+ charcount -= 1
357
+ self.CurMatrixCell.mvwdelch(1, charcount + 1)
358
+ self.CurMatrixCell.mvwinsch(1, charcount + 1, @filler)
359
+
360
+ self.CurMatrixCell.refresh
361
+ @info[@row][@col] = @info[@row][@col][0...charcount]
362
+ end
363
+ when Curses::KEY_RIGHT, CDK::KEY_TAB
364
+ if @ccol != @vcols
365
+ # We are moving to the right...
366
+ @col += 1
367
+ @ccol += 1
368
+ moved_cell = true
369
+ else
370
+ # We have to shift the columns to the right.
371
+ if @col != @cols
372
+ @lcol += 1
373
+ @col += 1
374
+
375
+ # Redraw the column titles.
376
+ if @rows > @vrows
377
+ self.redrawTitles(false, true)
378
+ end
379
+ refresh_cells = true
380
+ moved_cell = true
381
+ else
382
+ # We are at the far right column, we need to shift
383
+ # down one row, if we can.
384
+ if @row == @rows
385
+ CDK.Beep
386
+ else
387
+ # Set up the columns info.
388
+ @col = 1
389
+ @lcol = 1
390
+ @ccol = 1
391
+
392
+ # Shift the rows...
393
+ if @crow != @vrows
394
+ @row += 1
395
+ @crow += 1
396
+ else
397
+ @row += 1
398
+ @trow += 1
399
+ end
400
+ self.redrawTitles(true, true)
401
+ refresh_cells = true
402
+ moved_cell = true
403
+ end
404
+ end
405
+ end
406
+ when Curses::KEY_LEFT, Curses::KEY_BTAB
407
+ if @ccol != 1
408
+ # We are moving to the left...
409
+ @col -= 1
410
+ @ccol -= 1
411
+ moved_cell = true
412
+ else
413
+ # Are we at the far left?
414
+ if @lcol != 1
415
+ @lcol -= 1
416
+ @col -= 1
417
+
418
+ # Redraw the column titles.
419
+ if @cols > @vcols
420
+ self.redrawTitles(false, true)
421
+ end
422
+ refresh_cells = true
423
+ moved_cell = true
424
+ else
425
+ # Shift up one line if we can...
426
+ if @row == 1
427
+ CDK.Beep
428
+ else
429
+ # Set up the columns info.
430
+ @col = @cols
431
+ @lcol = @cols - @vcols + 1
432
+ @ccol = @vcols
433
+
434
+ # Shift the rows...
435
+ if @crow != 1
436
+ @row -= 1
437
+ @crow -= 1
438
+ else
439
+ @row -= 1
440
+ @trow -= 1
441
+ end
442
+ self.redrawTitles(true, true)
443
+ refresh_cells = true
444
+ moved_cell = true
445
+ end
446
+ end
447
+ end
448
+ when Curses::KEY_UP
449
+ if @crow != 1
450
+ @row -= 1
451
+ @crow -= 1
452
+ moved_cell = true
453
+ else
454
+ if @trow != 1
455
+ @trow -= 1
456
+ @row -= 1
457
+
458
+ # Redraw the row titles.
459
+ if @rows > @vrows
460
+ self.redrawTitles(true, false)
461
+ end
462
+ refresh_cells = true
463
+ moved_cell = true
464
+ else
465
+ CDK.Beep
466
+ end
467
+ end
468
+ when Curses::KEY_DOWN
469
+ if @crow != @vrows
470
+ @row += 1
471
+ @crow += 1
472
+ moved_cell = true
473
+ else
474
+ if @trow + @vrows - 1 != @rows
475
+ @trow += 1
476
+ @row += 1
477
+
478
+ # Redraw the titles.
479
+ if @rows > @vrows
480
+ self.redrawTitles(true, false)
481
+ end
482
+ refresh_cells = true
483
+ moved_cell = true
484
+ else
485
+ CDK.Beep
486
+ end
487
+ end
488
+ when Curses::KEY_NPAGE
489
+ if @rows > @vrows
490
+ if @trow + (@vrows - 1) * 2 <= @rows
491
+ @trow += @vrows - 1
492
+ @row += @vrows - 1
493
+ self.redrawTitles(true, false)
494
+ refresh_cells = true
495
+ moved_cell = true
496
+ else
497
+ CDK.Beep
498
+ end
499
+ else
500
+ CDK.Beep
501
+ end
502
+ when Curses::KEY_PPAGE
503
+ if @rows > @vrows
504
+ if @trow - (@vrows - 1) * 2 >= 1
505
+ @trow -= @vrows - 1
506
+ @row -= @vrows - 1
507
+ self.redrawTitles(true, false)
508
+ refresh_cells = true
509
+ moved_cell = true
510
+ else
511
+ CDK.Beep
512
+ end
513
+ else
514
+ CDK.Beep
515
+ end
516
+ when CDK.CTRL('G')
517
+ self.jumpToCell(-1, -1)
518
+ self.draw(@box)
519
+ when CDK::PASTE
520
+ if @@g_paste_buffer.size == 0 ||
521
+ @@g_paste_buffer.size > @colwidths[@ccol]
522
+ CDK.Beep
523
+ else
524
+ self.CurMatrixInfo = @@g_paste_buffer.clone
525
+ self.drawCurCell
526
+ end
527
+ when CDK::COPY
528
+ @@g_paste_buffer = self.CurMatrixInfo.clone
529
+ when CDK::CUT
530
+ @@g_paste_buffer = self.CurMatrixInfo.clone
531
+ self.cleanCell(@trow + @crow - 1, @lcol + @ccol - 1)
532
+ self.drawCurCell
533
+ when CDK::ERASE
534
+ self.cleanCell(@trow + @crow - 1, @lcol + @ccol - 1)
535
+ self.drawCurCell
536
+ when Curses::KEY_ENTER, CDK::KEY_RETURN
537
+ if !@box_cell
538
+ Draw.attrbox(@cell[@oldcrow][@oldccol], ' '.ord, ' '.ord,
539
+ ' '.ord, ' '.ord, ' '.ord, ' '.ord, Curses::A_NORMAL)
540
+ else
541
+ self.drawOldCell
542
+ end
543
+ self.CurMatrixCell.refresh
544
+ self.setExitType(input)
545
+ ret = 1
546
+ complete = true
547
+ when Curses::Error
548
+ self.setExitType(input)
549
+ complete = true
550
+ when CDK::KEY_ESC
551
+ if !@box_cell
552
+ Draw.attrbox(@cell[@oldcrow][@oldccol], ' '.ord, ' '.ord,
553
+ ' '.ord, ' '.ord, ' '.ord, ' '.ord, Curses::A_NORMAL)
554
+ else
555
+ self.drawOldCell
556
+ end
557
+ self.CurMatrixCell.refresh
558
+ self.setExitType(input)
559
+ complete = true
560
+ when CDK::REFRESH
561
+ @screen.erase
562
+ @screen.refresh
563
+ else
564
+ @callbackfn.call(self, input)
565
+ end
566
+ end
567
+
568
+ if !complete
569
+ # Did we change cells?
570
+ if moved_cell
571
+ # un-highlight the old box
572
+ if !@box_cell
573
+ Draw.attrbox(@cell[@oldcrow][@oldccol], ' '.ord, ' '.ord,
574
+ ' '.ord, ' '.ord, ' '.ord, ' '.ord, Curses::A_NORMAL)
575
+ else
576
+ self.drawOldCell
577
+ end
578
+ @cell[@oldcrow][@oldccol].refresh
579
+
580
+ self.focusCurrent
581
+ end
582
+
583
+ # Redraw each cell
584
+ if refresh_cells
585
+ self.drawEachCell
586
+ self.focusCurrent
587
+ end
588
+
589
+ # Move to the correct position in the cell.
590
+ if refresh_cells || moved_cell
591
+ if @colwidths[@ccol] == 1
592
+ self.CurMatrixCell.move(1, 1)
593
+ else
594
+ self.CurMatrixCell.move(1, self.CurMatrixInfo.size + 1)
595
+ end
596
+ self.CurMatrixCell.refresh
597
+ end
598
+
599
+ # Should we call a post-process?
600
+ unless @post_process_func.nil?
601
+ @post_process_func.call(:MATRIX, self, @post_process_data, input)
602
+ end
603
+ end
604
+ end
605
+
606
+ if !complete
607
+ # Set the variables we need.
608
+ @oldcrow = @crow
609
+ @oldccol = @ccol
610
+ @oldvrow = @row
611
+ @oldvcol = @col
612
+
613
+ # Set the exit type and exit.
614
+ self.setExitType(0)
615
+ end
616
+
617
+ @result_data = ret
618
+ return ret
619
+ end
620
+
621
+ # Highlight the new field.
622
+ def highlightCell
623
+ disptype = @colvalues[@col]
624
+ highlight = @highlight
625
+ infolen = @info[@row][@col].size
626
+
627
+ # Given the dominance of the color/attributes, we need to set the
628
+ # current cell attribute.
629
+ if @dominant == CDK::ROW
630
+ highlight = (@rowtitle[@crow][0] || 0) & Curses::A_ATTRIBUTES
631
+ elsif @dominant == CDK::COL
632
+ highlight = (@coltitle[@ccol][0] || 0) & Curses::A_ATTRIBUTES
633
+ end
634
+
635
+ # If the column is only one char.
636
+ (1..@colwidths[@ccol]).each do |x|
637
+ ch = if x <= infolen && !Display.isHiddenDisplayType(disptype)
638
+ then CDK.CharOf(@info[@row][@col][x - 1])
639
+ else @filler
640
+ end
641
+ self.CurMatrixCell.mvwaddch(1, x, ch.ord | highlight)
642
+ end
643
+ self.CurMatrixCell.move(1, infolen + 1)
644
+ self.CurMatrixCell.refresh
645
+ end
646
+
647
+ # This moves the matrix field to the given location.
648
+ def move(xplace, yplace, relative, refresh_flag)
649
+ windows = [@win]
650
+
651
+ (0..@vrows).each do |x|
652
+ (0..@vcols).each do |y|
653
+ windows << @cell[x][y]
654
+ end
655
+ end
656
+
657
+ windows << @shadow_win
658
+ self.move_specific(xplace, yplace, relative, refresh_flag,
659
+ windows, [])
660
+ end
661
+
662
+ # This draws a cell within a matrix.
663
+ def drawCell(row, col, vrow, vcol, attr, box)
664
+ disptype = @colvalues[@col]
665
+ highlight = @filler & Curses::A_ATTRIBUTES
666
+ rows = @vrows
667
+ cols = @vcols
668
+ infolen = @info[vrow][vcol].size
669
+
670
+ # Given the dominance of the colors/attributes, we need to set the
671
+ # current cell attribute.
672
+ if @dominant == CDK::ROW
673
+ highlight = (@rowtitle[row][0] || 0) & Curses::A_ATTRIBUTES
674
+ elsif @dominant == CDK::COL
675
+ highlight = (@coltitle[col][0] || 0) & Curses::A_ATTRIBUTES
676
+ end
677
+
678
+ # Draw in the cell info.
679
+ (1..@colwidths[col]).each do |x|
680
+ ch = if x <= infolen && !Display.isHiddenDisplayType(disptype)
681
+ then CDK.CharOf(@info[vrow][vcol][x-1]).ord | highlight
682
+ else @filler
683
+ end
684
+ @cell[row][col].mvwaddch(1, x, ch.ord | highlight)
685
+ end
686
+
687
+ @cell[row][col].move(1, infolen + 1)
688
+ @cell[row][col].refresh
689
+
690
+ # Only draw the box iff the user asked for a box.
691
+ if !box
692
+ return
693
+ end
694
+
695
+ # If the value of the column spacing is greater than 0 then these
696
+ # are independent boxes
697
+ if @col_space != 0 && @row_space != 0
698
+ Draw.attrbox(@cell[row][col], CDK::ACS_ULCORNER,
699
+ CDK::ACS_URCORNER, CDK::ACS_LLCORNER,
700
+ CDK::ACS_LRCORNER, CDK::ACS_HLINE,
701
+ CDK::ACS_VLINE, attr)
702
+ return
703
+ end
704
+ if @col_space != 0 && @row_space == 0
705
+ if row == 1
706
+ Draw.attrbox(@cell[row][col], CDK::ACS_ULCORNER,
707
+ CDK::ACS_URCORNER, CDK::ACS_LTEE,
708
+ CDK::ACS_RTEE, CDK::ACS_HLINE,
709
+ CDK::ACS_VLINE, attr)
710
+ return
711
+ elsif row > 1 && row < rows
712
+ Draw.attrbox(@cell[row][col], CDK::ACS_LTEE, CDK::ACS_RTEE,
713
+ CDK::ACS_LTEE, CDK::ACS_RTEE, CDK::ACS_HLINE,
714
+ CDK::ACS_VLINE, attr)
715
+ return
716
+ elsif row == rows
717
+ Draw.attrbox(@cell[row][col], CDK::ACS_LTEE, CDK::ACS_RTEE,
718
+ CDK::ACS_LLCORNER, CDK::ACS_LRCORNER, CDK::ACS_HLINE,
719
+ CDK::ACS_VLINE, attr)
720
+ return
721
+ end
722
+ end
723
+ if @col_space == 0 && @row_space != 0
724
+ if col == 1
725
+ Draw.attrbox(@cell[row][col], CDK::ACS_ULCORNER,
726
+ CDK::ACS_TTEE, CDK::ACS_LLCORNER, CDK::ACS_BTEE,
727
+ CDK::ACS_HLINE, CDK::ACS_VLINE, attr)
728
+ return
729
+ elsif col > 1 && col < cols
730
+ Draw.attrbox(@cell[row][col], CDK::ACS_TTEE, CDK::ACS_TTEE,
731
+ CDK::ACS_BTEE, CDK::ACS_BTEE, CDK::ACS_HLINE,
732
+ CDK::ACS_VLINE, attr)
733
+ return
734
+ elsif col == cols
735
+ Draw.attrbox(@cell[row][col], CDK::ACS_TTEE,
736
+ CDK::ACS_URCORNER,CDK::ACS_BTEE, CDK::ACS_LRCORNER,
737
+ CDK::ACS_HLINE, CDK::ACS_VLINE, attr)
738
+ return
739
+ end
740
+ end
741
+
742
+ # Start drawing the matrix.
743
+ if row == 1
744
+ if col == 1
745
+ # Draw the top left corner
746
+ Draw.attrbox(@cell[row][col], CDK::ACS_ULCORNER,
747
+ CDK::ACS_TTEE, CDK::ACS_LTEE, CDK::ACS_PLUS,
748
+ CDK::ACS_HLINE, CDK::ACS_VLINE, attr)
749
+ elsif col > 1 && col < cols
750
+ # Draw the top middle box
751
+ Draw.attrbox(@cell[row][col], CDK::ACS_TTEE, CDK::ACS_TTEE,
752
+ CDK::ACS_PLUS, CDK::ACS_PLUS, CDK::ACS_HLINE,
753
+ CDK::ACS_VLINE, attr)
754
+ elsif col == cols
755
+ # Draw the top right corner
756
+ Draw.attrbox(@cell[row][col], CDK::ACS_TTEE,
757
+ CDK::ACS_URCORNER, CDK::ACS_PLUS, CDK::ACS_RTEE,
758
+ CDK::ACS_HLINE, CDK::ACS_VLINE, attr)
759
+ end
760
+ elsif row > 1 && row < rows
761
+ if col == 1
762
+ # Draw the middle left box
763
+ Draw.attrbox(@cell[row][col], CDK::ACS_LTEE, CDK::ACS_PLUS,
764
+ CDK::ACS_LTEE, CDK::ACS_PLUS, CDK::ACS_HLINE,
765
+ CDK::ACS_VLINE, attr)
766
+ elsif col > 1 && col < cols
767
+ # Draw the middle box
768
+ Draw.attrbox(@cell[row][col], CDK::ACS_PLUS, CDK::ACS_PLUS,
769
+ CDK::ACS_PLUS, CDK::ACS_PLUS, CDK::ACS_HLINE,
770
+ CDK::ACS_VLINE, attr)
771
+ elsif col == cols
772
+ # Draw the middle right box
773
+ Draw.attrbox(@cell[row][col], CDK::ACS_PLUS, CDK::ACS_RTEE,
774
+ CDK::ACS_PLUS, CDK::ACS_RTEE, CDK::ACS_HLINE,
775
+ CDK::ACS_VLINE, attr)
776
+ end
777
+ elsif row == rows
778
+ if col == 1
779
+ # Draw the bottom left corner
780
+ Draw.attrbox(@cell[row][col], CDK::ACS_LTEE, CDK::ACS_PLUS,
781
+ CDK::ACS_LLCORNER, CDK::ACS_BTEE, CDK::ACS_HLINE,
782
+ CDK::ACS_VLINE, attr)
783
+ elsif col > 1 && col < cols
784
+ # Draw the bottom middle box
785
+ Draw.attrbox(@cell[row][col], CDK::ACS_PLUS, CDK::ACS_PLUS,
786
+ CDK::ACS_BTEE, CDK::ACS_BTEE, CDK::ACS_HLINE,
787
+ CDK::ACS_VLINE, attr)
788
+ elsif col == cols
789
+ # Draw the bottom right corner
790
+ Draw.attrbox(@cell[row][col], CDK::ACS_PLUS, CDK::ACS_RTEE,
791
+ CDK::ACS_BTEE, CDK::ACS_LRCORNER, CDK::ACS_HLINE,
792
+ CDK::ACS_VLINE, attr)
793
+ end
794
+ end
795
+
796
+ self.focusCurrent
797
+ end
798
+
799
+ def drawEachColTitle
800
+ (1..@vcols).each do |x|
801
+ unless @cell[0][x].nil?
802
+ @cell[0][x].erase
803
+ Draw.writeChtype(@cell[0][x],
804
+ @coltitle_pos[@lcol + x - 1], 0,
805
+ @coltitle[@lcol + x - 1], CDK::HORIZONTAL, 0,
806
+ @coltitle_len[@lcol + x - 1])
807
+ @cell[0][x].refresh
808
+ end
809
+ end
810
+ end
811
+
812
+ def drawEachRowTitle
813
+ (1..@vrows).each do |x|
814
+ unless @cell[x][0].nil?
815
+ @cell[x][0].erase
816
+ Draw.writeChtype(@cell[x][0],
817
+ @rowtitle_pos[@trow + x - 1], 1,
818
+ @rowtitle[@trow + x - 1], CDK::HORIZONTAL, 0,
819
+ @rowtitle_len[@trow + x - 1])
820
+ @cell[x][0].refresh
821
+ end
822
+ end
823
+ end
824
+
825
+ def drawEachCell
826
+ # Fill in the cells.
827
+ (1..@vrows).each do |x|
828
+ (1..@vcols).each do |y|
829
+ self.drawCell(x, y, @trow + x - 1, @lcol + y - 1,
830
+ Curses::A_NORMAL, @box_cell)
831
+ end
832
+ end
833
+ end
834
+
835
+ def drawCurCell
836
+ self.drawCell(@crow, @ccol, @row, @col, Curses::A_NORMAL, @box_cell)
837
+ end
838
+
839
+ def drawOldCell
840
+ self.drawCell(@oldcrow, @oldccol, @oldvrow, @oldvcol,
841
+ Curses::A_NORMAL, @box_cell)
842
+ end
843
+
844
+ # This function draws the matrix widget.
845
+ def draw(box)
846
+ # Did we ask for a shadow?
847
+ unless @shadow_win.nil?
848
+ Draw.drawShadow(@shadow_win)
849
+ end
850
+
851
+ # Should we box the matrix?
852
+ if box
853
+ Draw.drawObjBox(@win, self)
854
+ end
855
+
856
+ self.drawTitle(@win)
857
+
858
+ @win.refresh
859
+
860
+ self.drawEachColTitle
861
+ self.drawEachRowTitle
862
+ self.drawEachCell
863
+ self.focusCurrent
864
+ end
865
+
866
+ # This function destroys the matrix widget.
867
+ def destroy
868
+ self.cleanTitle
869
+
870
+ # Clear the matrix windows.
871
+ CDK.deleteCursesWindow(@cell[0][0])
872
+ (1..@vrows).each do |x|
873
+ CDK.deleteCursesWindow(@cell[x][0])
874
+ end
875
+ (1..@vcols).each do |x|
876
+ CDK.deleteCursesWindow(@cell[0][x])
877
+ end
878
+ (1..@vrows).each do |x|
879
+ (1..@vcols).each do |y|
880
+ CDK.deleteCursesWindow(@cell[x][y])
881
+ end
882
+ end
883
+
884
+ CDK.deleteCursesWindow(@shadow_win)
885
+ CDK.deleteCursesWindow(@win)
886
+
887
+ # Clean the key bindings.
888
+ self.cleanBindings(:MATRIX)
889
+
890
+ # Unregister this object.
891
+ CDK::SCREEN.unregister(:MATRIX, self)
892
+ end
893
+
894
+ # This function erases the matrix widget from the screen.
895
+ def erase
896
+ if self.validCDKObject
897
+ # Clear the matrix cells.
898
+ CDK.eraseCursesWindow(@cell[0][0])
899
+ (1..@vrows).each do |x|
900
+ CDK.eraseCursesWindow(@cell[x][0])
901
+ end
902
+ (1..@vcols).each do |x|
903
+ CDK.eraseCursesWindow(@cell[0][x])
904
+ end
905
+ (1..@vrows).each do |x|
906
+ (1..@vcols).each do |y|
907
+ CDK.eraseCursesWindow(@cell[x][y])
908
+ end
909
+ end
910
+ CDK.eraseCursesWindow(@shadow_win)
911
+ CDK.eraseCursesWindow(@win)
912
+ end
913
+ end
914
+
915
+ # Set the callback function
916
+ def setCB(callback)
917
+ @callbackfn = callback
918
+ end
919
+
920
+ # This function sets the values of the matrix widget.
921
+ def setCells(info, rows, maxcols, sub_size)
922
+ if rows > @rows
923
+ rows = @rows
924
+ end
925
+
926
+ # Copy in the new info.
927
+ (1..rows).each do |x|
928
+ (1..@cols).each do |y|
929
+ if x <= rows && y <= sub_size[x]
930
+ @info[x][y] = @info[x][y][0..[@colwidths[y], @info[x][y].size].min]
931
+ else
932
+ self.cleanCell(x, y)
933
+ end
934
+ end
935
+ end
936
+ end
937
+
938
+ # This cleans out the information cells in the matrix widget.
939
+ def clean
940
+ (1..@rows).each do |x|
941
+ (1..@cols).each do |y|
942
+ self.cleanCell(x, y)
943
+ end
944
+ end
945
+ end
946
+
947
+ # This cleans one cell in the matrix widget.
948
+ def cleanCell(row, col)
949
+ if row > 0 && row <= @rows && col > col <= @cols
950
+ @info[row][col] = ''
951
+ end
952
+ end
953
+
954
+ # This allows us to hyper-warp to a cell
955
+ def jumpToCell(row, col)
956
+ new_row = row
957
+ new_col = col
958
+
959
+ # Only create the row scale if needed.
960
+ if (row == -1) || (row > @rows)
961
+ # Create the row scale widget.
962
+ scale = CDK::SCALE.new(@screen, CDK::CENTER, CDK::CENTER,
963
+ '<C>Jump to which row.', '</5/B>Row: ', Curses::A_NORMAL,
964
+ 5, 1, 1, @rows, 1, 1, true, false)
965
+
966
+ # Activate the scale and get the row.
967
+ new_row = scale.activate([])
968
+ scale.destroy
969
+ end
970
+
971
+ # Only create the column scale if needed.
972
+ if (col == -1) || (col > @cols)
973
+ # Create the column scale widget.
974
+ scale = CDK::SCALE.new(@screen, CDK::CENTER, CDK::CENTER,
975
+ '<C>Jump to which column', '</5/B>Col: ', Curses::A_NORMAL,
976
+ 5, 1, 1, @cols, 1, 1, true, false)
977
+
978
+ # Activate the scale and get the column.
979
+ new_col = scale.activate([])
980
+ scale.destroy
981
+ end
982
+
983
+ # Hyper-warp....
984
+ if new_row != @row || @new_col != @col
985
+ return self.moveToCell(new_row, new_col)
986
+ else
987
+ return 1
988
+ end
989
+ end
990
+
991
+ # This allows us to move to a given cell.
992
+ def moveToCell(newrow, newcol)
993
+ row_shift = newrow - @row
994
+ col_shift = newcol - @col
995
+
996
+ # Make sure we aren't asking to move out of the matrix.
997
+ if newrow > @rows || newcol > @cols || newrow <= 0 || newcol <= 0
998
+ return 0
999
+ end
1000
+
1001
+ # Did we move up/down?
1002
+ if row_shift > 0
1003
+ # We are moving down
1004
+ if @vrows == @cols
1005
+ @trow = 1
1006
+ @crow = newrow
1007
+ @row = newrow
1008
+ else
1009
+ if row_shift + @vrows < @rows
1010
+ # Just shift down by row_shift
1011
+ @trow += row_shift
1012
+ @crow = 1
1013
+ @row += row_shift
1014
+ else
1015
+ # We need to munge the values
1016
+ @trow = @rows - @vrows + 1
1017
+ @crow = row_shift + @vrows - @rows + 1
1018
+ @row = newrow
1019
+ end
1020
+ end
1021
+ elsif row_shift < 0
1022
+ # We are moving up.
1023
+ if @vrows == @rows
1024
+ @trow = 1
1025
+ @row = newrow
1026
+ @crow = newrow
1027
+ else
1028
+ if row_shift + @vrows > 1
1029
+ # Just shift up by row_shift...
1030
+ @trow += row_shift
1031
+ @row += row_shift
1032
+ @crow = 1
1033
+ else
1034
+ # We need to munge the values
1035
+ @trow = 1
1036
+ @crow = 1
1037
+ @row = 1
1038
+ end
1039
+ end
1040
+ end
1041
+
1042
+ # Did we move left/right?
1043
+ if col_shift > 0
1044
+ # We are moving right.
1045
+ if @vcols == @cols
1046
+ @lcol = 1
1047
+ @ccol = newcol
1048
+ @col = newcol
1049
+ else
1050
+ if col_shift + @vcols < @cols
1051
+ @lcol += col_shift
1052
+ @ccol = 1
1053
+ @col += col_shift
1054
+ else
1055
+ # We need to munge with the values
1056
+ @lcol = @cols - @vcols + 1
1057
+ @ccol = col_shift + @vcols - @cols + 1
1058
+ @col = newcol
1059
+ end
1060
+ end
1061
+ elsif col_shift < 0
1062
+ # We are moving left.
1063
+ if @vcols == @cols
1064
+ @lcol = 1
1065
+ @col = newcol
1066
+ @ccol = newcol
1067
+ else
1068
+ if col_shift + @vcols > 1
1069
+ # Just shift left by col_shift
1070
+ @lcol += col_shift
1071
+ @col += col_shift
1072
+ @ccol = 1
1073
+ else
1074
+ @lcol = 1
1075
+ @col = 1
1076
+ @ccol = 1
1077
+ end
1078
+ end
1079
+ end
1080
+
1081
+ # Keep the 'old' values around for redrawing sake.
1082
+ @oldcrow = @crow
1083
+ @oldccol = @ccol
1084
+ @oldvrow = @row
1085
+ @oldvcol = @col
1086
+
1087
+ return 1
1088
+ end
1089
+
1090
+ # This redraws the titles indicated...
1091
+ def redrawTitles(row_titles, col_titles)
1092
+ # Redraw the row titles.
1093
+ if row_titles
1094
+ self.drawEachRowTitle
1095
+ end
1096
+
1097
+ # Redraw the column titles.
1098
+ if col_titles
1099
+ self.drawEachColTitle
1100
+ end
1101
+ end
1102
+
1103
+ # This sets the value of a matrix cell.
1104
+ def setCell(row, col, value)
1105
+ # Make sure the row/col combination is within the matrix.
1106
+ if row > @rows || cols > @cols || row <= 0 || col <= 0
1107
+ return -1
1108
+ end
1109
+
1110
+ self.cleanCell(row, col)
1111
+ @info[row][col] = value[0...[@colwidths[col], value.size].min]
1112
+ return 1
1113
+ end
1114
+
1115
+ # This gets the value of a matrix cell.
1116
+ def getCell(row, col)
1117
+ # Make sure the row/col combination is within the matrix.
1118
+ if row > @rows || col > @cols || row <= 0 || col <= 0
1119
+ return 0
1120
+ end
1121
+ return @info[row][col]
1122
+ end
1123
+
1124
+ def CurMatrixCell
1125
+ return @cell[@crow][@ccol]
1126
+ end
1127
+
1128
+ def CurMatrixInfo
1129
+ return @info[@trow + @crow - 1][@lcol + @ccol - 1]
1130
+ end
1131
+
1132
+ def focusCurrent
1133
+ Draw.attrbox(self.CurMatrixCell, CDK::ACS_ULCORNER,
1134
+ CDK::ACS_URCORNER, CDK::ACS_LLCORNER,
1135
+ CDK::ACS_LRCORNER, CDK::ACS_HLINE,
1136
+ CDK::ACS_VLINE, Curses::A_BOLD)
1137
+ self.CurMatrixCell.refresh
1138
+ self.highlightCell
1139
+ end
1140
+
1141
+ # This returns the current row/col cell
1142
+ def getCol
1143
+ return @col
1144
+ end
1145
+
1146
+ def getRow
1147
+ return @row
1148
+ end
1149
+
1150
+ # This sets the background attribute of the widget.
1151
+ def setBKattr(attrib)
1152
+ @win.wbkgd(attrib)
1153
+ (0..@vrows).each do |x|
1154
+ (0..@vcols).each do |y|
1155
+ # wbkgd (MATRIX_CELL (widget, x, y), attrib);
1156
+ end
1157
+ end
1158
+ end
1159
+
1160
+ def focus
1161
+ self.draw(@box)
1162
+ end
1163
+
1164
+ def unfocus
1165
+ self.draw(@box)
1166
+ end
1167
+
1168
+ def position
1169
+ super(@win)
1170
+ end
1171
+
1172
+ def object_type
1173
+ :MATRIX
1174
+ end
1175
+ end
1176
+ end