reterm 0.4.2 → 0.5.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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/designer/src/ComponentParams.rb +89 -42
  3. data/designer/src/ComponentsList.rb +26 -25
  4. data/designer/src/CreatedList.rb +9 -0
  5. data/designer/src/Designer.rb +23 -1
  6. data/designer/src/ToggleArea.rb +20 -3
  7. data/designer/src/about.rb +35 -0
  8. data/designer/src/component_factory.rb +18 -0
  9. data/designer/src/component_map.rb +7 -0
  10. data/designer/src/file_chooser.rb +25 -0
  11. data/designer/src/glade/Designer.glade +1 -19
  12. data/designer/src/images/{slist.png → scroll_list.png} +0 -0
  13. data/lib/reterm.rb +10 -1
  14. data/lib/reterm/color_pair.rb +166 -10
  15. data/lib/reterm/component.rb +89 -2
  16. data/lib/reterm/components.rb +16 -1
  17. data/lib/reterm/components/alphalist.rb +45 -0
  18. data/lib/reterm/components/ascii_text.rb +14 -1
  19. data/lib/reterm/components/asciimator.rb +1 -0
  20. data/lib/reterm/components/button.rb +35 -5
  21. data/lib/reterm/components/button_box.rb +108 -0
  22. data/lib/reterm/components/close_button.rb +22 -0
  23. data/lib/reterm/components/cmd_output.rb +69 -0
  24. data/lib/reterm/components/dial.rb +11 -2
  25. data/lib/reterm/components/dialog.rb +41 -1
  26. data/lib/reterm/components/drop_down_menu.rb +140 -0
  27. data/lib/reterm/components/entry.rb +42 -14
  28. data/lib/reterm/components/histogram.rb +55 -0
  29. data/lib/reterm/components/hslider.rb +9 -0
  30. data/lib/reterm/components/image.rb +9 -0
  31. data/lib/reterm/components/isometric.rb +38 -0
  32. data/lib/reterm/components/label.rb +20 -3
  33. data/lib/reterm/components/matrix.rb +9 -0
  34. data/lib/reterm/components/multi_line_entry.rb +54 -0
  35. data/lib/reterm/components/password_entry.rb +15 -0
  36. data/lib/reterm/components/radio.rb +10 -0
  37. data/lib/reterm/components/revealing_label.rb +126 -0
  38. data/lib/reterm/components/rocker.rb +21 -11
  39. data/lib/reterm/components/scroll_list.rb +96 -0
  40. data/lib/reterm/components/scrolling_area.rb +50 -0
  41. data/lib/reterm/components/select_list.rb +67 -0
  42. data/lib/reterm/components/splash.rb +85 -0
  43. data/lib/reterm/components/template.rb +12 -1
  44. data/lib/reterm/components/treeview.rb +1 -0
  45. data/lib/reterm/components/vslider.rb +11 -2
  46. data/lib/reterm/components/youtube.rb +20 -0
  47. data/lib/reterm/config.rb +22 -0
  48. data/lib/reterm/init.rb +131 -6
  49. data/lib/reterm/layout.rb +147 -11
  50. data/lib/reterm/layouts.rb +1 -0
  51. data/lib/reterm/layouts/grid.rb +69 -0
  52. data/lib/reterm/layouts/horizontal.rb +25 -4
  53. data/lib/reterm/layouts/vertical.rb +26 -5
  54. data/lib/reterm/loader.rb +2 -2
  55. data/lib/reterm/mixins/button_helpers.rb +7 -0
  56. data/lib/reterm/mixins/cdk_component.rb +66 -2
  57. data/lib/reterm/mixins/common_controls.rb +15 -0
  58. data/lib/reterm/mixins/common_keys.rb +20 -0
  59. data/lib/reterm/mixins/component_input.rb +62 -14
  60. data/lib/reterm/mixins/event_dispatcher.rb +2 -0
  61. data/lib/reterm/mixins/item_helpers.rb +8 -0
  62. data/lib/reterm/mixins/key_bindings.rb +23 -0
  63. data/lib/reterm/mixins/log_helpers.rb +13 -0
  64. data/lib/reterm/mixins/mouse_input.rb +58 -0
  65. data/lib/reterm/mixins/nav_controls.rb +33 -0
  66. data/lib/reterm/mixins/nav_input.rb +161 -69
  67. data/lib/reterm/terminal.rb +6 -2
  68. data/lib/reterm/util.rb +121 -0
  69. data/lib/reterm/version.rb +1 -1
  70. data/lib/reterm/window.rb +295 -29
  71. metadata +33 -17
  72. data/designer/src/images/orig/Check.png +0 -0
  73. data/designer/src/images/orig/ascii_text.png +0 -0
  74. data/designer/src/images/orig/button.png +0 -0
  75. data/designer/src/images/orig/dial.png +0 -0
  76. data/designer/src/images/orig/entry.png +0 -0
  77. data/designer/src/images/orig/hslider.png +0 -0
  78. data/designer/src/images/orig/label.png +0 -0
  79. data/designer/src/images/orig/matrix.png +0 -0
  80. data/designer/src/images/orig/radio.png +0 -0
  81. data/designer/src/images/orig/rocker.png +0 -0
  82. data/designer/src/images/orig/slist.png +0 -0
  83. data/designer/src/images/orig/vslider.png +0 -0
  84. data/lib/reterm/components/slist.rb +0 -32
  85. data/lib/reterm/menu.rb +0 -81
@@ -1,3 +1,3 @@
1
1
  module RETerm
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0"
3
3
  end # module RETerm
data/lib/reterm/window.rb CHANGED
@@ -25,6 +25,9 @@ module RETerm
25
25
  #
26
26
  class Window
27
27
  include EventDispatcher
28
+ include LogHelpers
29
+
30
+ attr_reader :window_id
28
31
 
29
32
  attr_accessor :rows, :cols
30
33
  attr_accessor :x, :y
@@ -48,8 +51,10 @@ module RETerm
48
51
  # Assign component to window. This will autoassign local
49
52
  # window to component as well.
50
53
  def component=(c)
51
- c.window = self
52
- c.colors = @colors if colored?
54
+ clear!
55
+
56
+ c.window = self
57
+ c.colors = @colors if colored?
53
58
  @component = c
54
59
  end
55
60
 
@@ -58,12 +63,44 @@ module RETerm
58
63
  !!@parent
59
64
  end
60
65
 
66
+ # Return boolean indicating if this window has children
67
+ def children?
68
+ !@children.empty?
69
+ end
70
+
71
+ # Return boolean indicating if this window is the
72
+ # first child of its parent
73
+ def first_child?
74
+ return true unless parent?
75
+ parent.children.index(self) == 0
76
+ end
77
+
78
+ # Return boolean indicating if this window is the
79
+ # last child of its parent
80
+ def last_child?
81
+ return true unless parent?
82
+ parent.children.index(self) == (parent.children.size - 1)
83
+ end
84
+
85
+ # Return root window (recusively), self if parent is not set
86
+ def root
87
+ parent? ? parent.root : self
88
+ end
89
+
90
+ def total_x
91
+ @tx ||= parent? ? (parent.total_x + x) : x
92
+ end
93
+
94
+ def total_y
95
+ @ty ||= parent? ? (parent.total_y + y) : y
96
+ end
97
+
61
98
  # Instantiate Window with given args. None are required, but
62
99
  # unless :rows, :cols, :x, or :y is specified, window will be
63
100
  # created in it's default position.
64
101
  #
65
102
  # This method will generate a unique id for each window
66
- # and add it to a static registery for subsequent tracking.
103
+ # and add it to a static registry for subsequent tracking.
67
104
  #
68
105
  # @param [Hash] args arguments used to instantiate window
69
106
  # @option args [Integer] :rows number of rows to assign to window
@@ -76,13 +113,23 @@ module RETerm
76
113
  # @option args [Window] :parent parent to assign to window, if
77
114
  # set window will be created a a child, else it will be
78
115
  # independently created & tracked.
116
+ # @options args [Boolean] :expand bool indicating
117
+ # if window can be expanded on request
118
+ # @options args [Boolean] :must_expand bool indicating
119
+ # if window must be expanded when requested. Failure
120
+ # to expand will result in an error
121
+ # @options args [Boolean] :fill bool indicating
122
+ # if window should fill remaining space
79
123
  #
80
124
  def initialize(args={})
81
125
  @@registry ||= []
82
126
  @@registry << self
83
127
 
84
- @rows = args[:rows] || (Terminal.rows - 1)
85
- @cols = args[:cols] || (Terminal.cols - 1)
128
+ @@wid ||= 0
129
+ @@wid += 1
130
+ @window_id = @@wid
131
+
132
+ @children = []
86
133
 
87
134
  @x = args[:x] || 0
88
135
  @y = args[:y] || 0
@@ -90,38 +137,147 @@ module RETerm
90
137
  @vborder = args[:vborder] || 0
91
138
  @hborder = args[:hborder] || 0
92
139
 
93
- self.component = args[:component] if args.key?(:component)
140
+ component = args[:component]
141
+
142
+ @rows = args[:rows] ||
143
+ (component ?
144
+ (component.requested_rows + component.extra_padding) :
145
+ Terminal.rows)
146
+
147
+ @cols = args[:cols] ||
148
+ (component ?
149
+ (component.requested_cols + component.extra_padding) :
150
+ Terminal.cols)
94
151
 
95
152
  if args[:parent]
96
153
  @parent = args[:parent]
154
+
155
+ @rows, @cols = *Window.adjust_proportional(@parent, @rows, @cols)
156
+ @x, @y = *Window.align(@parent, @x, @y, @rows, @cols)
157
+
97
158
  @win = parent.win.derwin(@rows, @cols, @y, @x)
98
159
 
99
160
  else
100
161
  @parent = nil
162
+
163
+ @rows, @cols = *Window.adjust_proportional(Terminal, @rows, @cols)
164
+ @x, @y = *Window.align(Terminal, @x, @y, @rows, @cols)
165
+
101
166
  @win = Ncurses::WINDOW.new(@rows, @cols, @y, @x)
102
167
  end
103
168
 
169
+ self.component = component if !!component
170
+
104
171
  Ncurses::keypad(@win, true)
105
172
 
106
- @children = []
173
+ @win.timeout(SYNC_TIMEOUT) if @win && sync_enabled? # XXX
107
174
 
175
+ @expand = !!args[:expand]
176
+ @must_expand = !!args[:must_expand]
108
177
 
109
- @@wid ||= 0
110
- @@wid += 1
178
+ @fill = !!args[:fill]
179
+ end
111
180
 
112
- @window_id = @@wid
181
+ ###
182
+
183
+ # Adjusts rows/cols in a context dependent manner
184
+ # TODO should proporational percentage be of remaining area?
185
+ def self.adjust_proportional(parent, rows, cols)
186
+ nr = rows
187
+ nc = cols
188
+
189
+ nr = parent.rows * nr if rows < 1
190
+ nc = parent.cols * nc if cols < 1
191
+
192
+ return nr, nc
193
+ end
194
+
195
+ # Adjusts x/y in context dependent manner
196
+ def self.align(parent, x, y, rows, cols)
197
+ nx = x
198
+ ny = y
199
+
200
+ nx = 1 if x == :left
201
+ ny = 1 if y == :top
202
+
203
+ nx = parent.cols - cols - 1 if x == :right
204
+ ny = parent.rows - rows - 1 if y == :bottom
205
+
206
+ nx = parent.cols / 2 - cols / 2 if x == :center
207
+ ny = parent.rows / 2 - rows / 2 if y == :center
208
+
209
+ return nx, ny
210
+ end
211
+
212
+ # Adjusts rows / cols so as to fill parent
213
+ def self.fill_parent(parent, x, y, rows, cols)
214
+ if (y + rows) < parent.rows
215
+ rows = parent.rows - y - 1
216
+ end
217
+
218
+ if (x + cols) < parent.cols
219
+ cols = parent.cols - x - 1
220
+ end
221
+
222
+ return rows, cols
113
223
  end
114
224
 
225
+ ###
226
+
115
227
  # Invoke window finalization routine by destroying it
116
228
  # and all children
117
229
  def finalize!
230
+ erase
231
+ @@registry.delete(self)
232
+
118
233
  children.each { |c|
119
234
  del_child c
120
- cdk_scr.destroy if cdk?
121
- component.finalize! if component?
122
235
  }
236
+
237
+ cdk_scr.destroy if cdk?
238
+ component.finalize! if component?
239
+ end
240
+
241
+ ###
242
+
243
+ def expand?
244
+ !!@expand
245
+ end
246
+
247
+ def must_expand?
248
+ !!@must_expand
123
249
  end
124
250
 
251
+ def request_expansion(r, c)
252
+ h = {:rows => r,
253
+ :cols => c,
254
+ :x => x,
255
+ :y => y}
256
+
257
+ if parent?
258
+ if parent.component.exceeds_bounds_with?(h)
259
+ if parent.component.expandable?
260
+ parent.component.expand(h)
261
+
262
+ else
263
+ raise ArgumentError, "cannot expand" if must_expand?
264
+ return false
265
+ end
266
+ end
267
+
268
+ else
269
+ unless Terminal.contains?(h)
270
+ raise ArgumentError, "terminal too small" if must_expand?
271
+ return false
272
+ end
273
+ end
274
+
275
+ resize(r, c)
276
+ true
277
+ end
278
+
279
+ ###
280
+
125
281
  # Return cdk screen (only used by CDK components)
126
282
  def cdk_scr
127
283
  enable_cdk!
@@ -133,6 +289,8 @@ module RETerm
133
289
  !!@cdk_scr
134
290
  end
135
291
 
292
+ ###
293
+
136
294
  # Static method returning all tracked windows
137
295
  def self.all
138
296
  @@registry ||= []
@@ -145,6 +303,8 @@ module RETerm
145
303
  @@registry.select { |w| !w.parent? }
146
304
  end
147
305
 
306
+ ###
307
+
148
308
  # Create child window, this method should not be invoked
149
309
  # by end-user, rather it is is invoked the Layout#add_child
150
310
  # is called.
@@ -155,7 +315,7 @@ module RETerm
155
315
  c
156
316
  end
157
317
 
158
- # Remove child window, like #add_child, this is used internally
318
+ # Remove child window, like #create_child, this is used internally
159
319
  # and should not be invoked by the end user
160
320
  def del_child(child)
161
321
  @children.delete(child)
@@ -164,6 +324,41 @@ module RETerm
164
324
  child.win.delwin
165
325
  end
166
326
 
327
+ # Return child containing specified screen coordiantes, else nil
328
+ def child_containing(x, y, z)
329
+ found = nil
330
+ children.find { |c|
331
+ next if found
332
+
333
+ # recursively descend into layout children
334
+ if c.component.kind_of?(Layout)
335
+ found = c.child_containing(x, y, z)
336
+
337
+ else
338
+ found =
339
+ c.total_x <= x && c.total_y <= y && # c.z >= z
340
+ (c.total_x + c.cols) >= x && (c.total_y + c.rows) >= y
341
+ found = c if found
342
+ end
343
+ }
344
+
345
+ found
346
+ end
347
+
348
+ ###
349
+
350
+ def resize(rows, cols)
351
+ r = win.resize rows, cols
352
+ raise ArgumentError, "could not resize window" if r == -1
353
+
354
+ @rows = rows
355
+ @cols = cols
356
+
357
+ self
358
+ end
359
+
360
+ ###
361
+
167
362
  # Clear window by removing all children and reinitializing window space
168
363
  def clear!
169
364
  children.each { |c|
@@ -176,7 +371,20 @@ module RETerm
176
371
 
177
372
  # Erase window drawing area
178
373
  def erase
179
- @win.werase
374
+ children.each { |c|
375
+ c.erase
376
+ }
377
+
378
+ @win.werase if @win
379
+
380
+ component.component.erase if cdk?
381
+ end
382
+
383
+ # Erases window screen by overwriting it with blanks
384
+ def erase_scr
385
+ 0.upto(rows) { |r|
386
+ mvaddstr(r, 1, " " * cols)
387
+ }
180
388
  end
181
389
 
182
390
  # Refresh / resynchronize window and all children
@@ -185,6 +393,17 @@ module RETerm
185
393
  children.each { |c|
186
394
  c.refresh
187
395
  }
396
+
397
+ component.component.screen.refresh if cdk?
398
+ end
399
+
400
+ def noutrefresh
401
+ @win.noutrefresh
402
+ children.each { |c|
403
+ c.noutrefresh
404
+ }
405
+
406
+ component.component.screen.noutrefresh if cdk?
188
407
  end
189
408
 
190
409
  # Remove Border around window
@@ -202,11 +421,61 @@ module RETerm
202
421
  @win.getch
203
422
  end
204
423
 
424
+ # Normal getch unless sync enabled in which case,
425
+ # timeout will be checked & components synchronized
426
+ def sync_getch
427
+ return self.getch unless sync_enabled?
428
+
429
+ c = -1
430
+ while c == -1 && !shutdown?
431
+ c = self.getch
432
+ run_sync!
433
+ end
434
+
435
+ c
436
+ end
437
+
438
+ # Dispatch to component synchronization
439
+ def sync!
440
+ component.sync! if component?
441
+ children.each { |c|
442
+ c.sync!
443
+ }
444
+ end
445
+
205
446
  # Write string at specified loc
206
447
  def mvaddstr(*a)
207
448
  @win.mvaddstr(*a)
208
449
  end
209
450
 
451
+ # Enable bold formatting
452
+ def bold!
453
+ @win.attron(Ncurses::A_BOLD)
454
+ return unless block_given?
455
+
456
+ yield
457
+ @win.attroff(Ncurses::A_BOLD)
458
+ end
459
+
460
+ # Disable bold formatting
461
+ def no_bold!
462
+ @win.attroff(Ncurses::A_BOLD)
463
+ end
464
+
465
+ # Enable reverse formatting
466
+ def reverse!
467
+ @win.attron(Ncurses::A_REVERSE)
468
+ return unless block_given?
469
+
470
+ yield
471
+ @win.attroff(Ncurses::A_REVERSE)
472
+ end
473
+
474
+ # Disabled reverse formatting
475
+ def no_reverse!
476
+ @win.attroff(Ncurses::A_REVERSE)
477
+ end
478
+
210
479
  # Return bool indiciating if colors are set
211
480
  def colored?
212
481
  !!@colors
@@ -214,8 +483,8 @@ module RETerm
214
483
 
215
484
  # Set window color
216
485
  def colors=(c)
217
- @colors = c.is_a?(ColorPair) ? c : ColorPair.for(c)
218
- @win.bkgd(Ncurses.COLOR_PAIR(@colors.id))
486
+ @colors = c.is_a?(ColorPair) ? c : ColorPair.for(c).first
487
+ @win.bkgd(Ncurses.COLOR_PAIR(@colors.id)) unless @win.nil?
219
488
 
220
489
  component.colors = @colors if component?
221
490
 
@@ -226,24 +495,21 @@ module RETerm
226
495
 
227
496
  # Return window dimensions as an array containing rows & cols
228
497
  def dimensions
229
- @dimensions ||=
230
- begin
231
- rows = []
232
- cols = []
233
- @win.getmaxyx(rows, cols)
234
- rows = rows.first
235
- cols = cols.first
236
- [rows, cols]
237
- end
498
+ rows = []
499
+ cols = []
500
+ @win.getmaxyx(rows, cols)
501
+ rows = rows.first
502
+ cols = cols.first
503
+ [rows, cols]
238
504
  end
239
505
 
240
506
  # Return window rows
241
- def rows
507
+ def actual_rows
242
508
  dimensions[0]
243
509
  end
244
510
 
245
511
  # Return window cols
246
- def cols
512
+ def actual_cols
247
513
  dimensions[1]
248
514
  end
249
515
 
@@ -253,8 +519,8 @@ module RETerm
253
519
  end
254
520
 
255
521
  # Activate window component
256
- def activate!
257
- component.activate!
522
+ def activate!(*input)
523
+ component.activate!(*input)
258
524
  end
259
525
  end
260
526
  end # module RETerm