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,19 +1,40 @@
1
1
  module RETerm
2
2
  module Layouts
3
- # Layout which arrainges items horizontally across screen cols
3
+ # Layout which arainges items horizontally across screen cols
4
4
  class Horizontal < Layout
5
+ def current_rows
6
+ return 1 if empty?
7
+ child_windows.max { |w1, w2| w1.rows <=> w2.rows }.rows
8
+ end
9
+
5
10
  def current_cols
6
- children.sum { |c| c.cols } + 1
11
+ return 1 if empty?
12
+ child_windows.sum { |c| c.cols } + 1
7
13
  end
8
14
 
9
- def exceeds_bounds?(child)
10
- child.rows > window.rows || (current_cols + child.cols) > window.cols
15
+ def exceeds_bounds_with?(child)
16
+ rows = child.is_a?(Hash) ?
17
+ [current_rows, child[:rows]].compact.max :
18
+ [current_rows, child.rows].max
19
+
20
+ cols = child.is_a?(Hash) ?
21
+ current_cols + child[:cols] :
22
+ current_cols + child.cols
23
+
24
+ rows > window.rows ||
25
+ cols > window.cols
11
26
  end
12
27
 
13
28
  def add_child(h={})
14
29
  # set x/y to next appropriate location
15
30
  super(h.merge(:y => 1, :x => current_cols))
16
31
  end
32
+
33
+ def valid_input?(ch, from_parent)
34
+ return true unless from_parent
35
+ !((UP_CONTROLS.include?(ch) && window.first_child?) ||
36
+ (DOWN_CONTROLS.include?(ch) && window.last_child?))
37
+ end
17
38
  end # class Horizontal
18
39
  end # module Layouts
19
40
  end # module RETerm
@@ -1,19 +1,40 @@
1
1
  module RETerm
2
2
  module Layouts
3
- # Layout which arrainges items vertically down screen rows
3
+ # Layout which arainges items vertically down screen rows
4
4
  class Vertical < Layout
5
5
  def current_rows
6
- children.sum { |c| c.rows } + 1
6
+ return 1 if empty?
7
+ child_windows.sum { |c| c.rows } + 1
7
8
  end
8
9
 
9
- def exceeds_bounds?(child)
10
- child.cols > window.cols || (current_rows + child.rows) > window.rows
10
+ def current_cols
11
+ return 1 if empty?
12
+ child_windows.max { |w1, w2| w1.cols <=> w2.cols }.cols
13
+ end
14
+
15
+ def exceeds_bounds_with?(child)
16
+ cols = child.is_a?(Hash) ?
17
+ [current_cols, child[:cols]].compact.max :
18
+ [current_cols, child.cols].max
19
+
20
+ rows = child.is_a?(Hash) ?
21
+ current_rows + child[:rows] :
22
+ current_rows + child.rows
23
+
24
+ cols > window.cols ||
25
+ rows > window.rows
11
26
  end
12
27
 
13
28
  def add_child(h={})
14
29
  # set x/y to next appropriate location
15
30
  super(h.merge(:y => current_rows, :x => 1))
16
31
  end
17
- end # class Horizontal
32
+
33
+ def valid_input?(ch, from_parent)
34
+ return true unless from_parent
35
+ !((LEFT_CONTROLS.include?(ch) && window.first_child?) ||
36
+ (RIGHT_CONTROLS.include?(ch) && window.last_child?))
37
+ end
38
+ end # class Vertical
18
39
  end # module Layouts
19
40
  end # module RETerm
data/lib/reterm/loader.rb CHANGED
@@ -49,7 +49,7 @@ module RETerm
49
49
  parse_child(w, win)
50
50
 
51
51
  w.border! if win.key?('border') && !!win['border']
52
- w.colors = ColorPair.for(win['colors']) if win.key?('colors')
52
+ w.colors = ColorPair.for(win['colors']).first if win.key?('colors')
53
53
 
54
54
  w
55
55
  end
@@ -113,7 +113,7 @@ module RETerm
113
113
  :cols => cols
114
114
 
115
115
  cw.border! if child.key?('border') && !!child['border']
116
- cw.colors = ColorPair.for(child['colors']) if child.key?('colors')
116
+ cw.colors = ColorPair.for(child['colors']).first if child.key?('colors')
117
117
 
118
118
  cw.component = parse_child(cw, child)
119
119
  }
@@ -0,0 +1,7 @@
1
+ module RETerm
2
+ module ButtonHelpers
3
+ def total_button_size
4
+ @buttons.sum { |b| b.size }
5
+ end
6
+ end # module ButtonHelpers
7
+ end # module RETerm
@@ -1,6 +1,20 @@
1
1
  module RETerm
2
2
  # Mixin used by CDK based component defining cdk-specific helpers
3
3
  module CDKComponent
4
+ def init_cdk(args={})
5
+ self.title_attrib = args[:title_attrib] if args.key?(:title_attrib)
6
+ end
7
+
8
+ def title_attrib=(a)
9
+ @title_attrib = a
10
+ component.title_attrib = a if defined?(@component)
11
+ end
12
+
13
+ # Boolean indicating this component is a cdk component
14
+ def cdk?
15
+ true
16
+ end
17
+
4
18
  # Should be implemented in subclass to initialize component
5
19
  def _component
6
20
  raise "NotImplemented"
@@ -12,10 +26,28 @@ module RETerm
12
26
  @component ||= begin
13
27
  c = _component
14
28
  c.setBackgroundColor("</#{@colors.id}>") if colored?
29
+ c.timeout(SYNC_TIMEOUT) if sync_enabled? # XXX
30
+ c.title_attrib = @title_attrib if @title_attrib
15
31
  c
16
32
  end
17
33
  end
18
34
 
35
+ # Return boolean indicating if escape was hit
36
+ def escape_hit?
37
+ component.exit_type == :ESCAPE_HIT
38
+ end
39
+
40
+ # Return boolean indicating early exit occurred
41
+ def early_exit?
42
+ component.exit_type == :EARLY_EXIT
43
+ end
44
+
45
+ # Return boolean indicating if user selection made / normal
46
+ # exit was invoked
47
+ def normal_exit?
48
+ component.exit_type == :NORMAL
49
+ end
50
+
19
51
  # Assign {ColorPair} to component
20
52
  def colors=(c)
21
53
  super
@@ -27,19 +59,51 @@ module RETerm
27
59
  component.draw([])
28
60
  end
29
61
 
62
+ def erase
63
+ component.erase
64
+ end
65
+
30
66
  # CDK components may be activated
31
67
  def activatable?
32
68
  true
33
69
  end
34
70
 
35
71
  # Invoke CDK activation routine
36
- def activate!
37
- component.activate([])
72
+ def activate!(*input)
73
+ dispatch :activated
74
+ component.resetExitType
75
+
76
+ r = nil
77
+
78
+ while [:EARLY_EXIT, :NEVER_ACTIVATED, :TIMEOUT].include?(component.exit_type) &&
79
+ !shutdown?
80
+ r = component.activate(input)
81
+ run_sync! if sync_enabled?
82
+ end
83
+
84
+ dispatch :deactivated
85
+ r
86
+ end
87
+
88
+ def deactivate!
89
+ component.activate [CDK::KEY_ESC]
90
+ dispatch :deactivated
38
91
  end
39
92
 
40
93
  # Return stored value of cdk component
41
94
  def value
42
95
  component.getValue
43
96
  end
97
+
98
+ # Override bind_key to use cdk bindings mechanism
99
+ def bind_key(key, kcb=nil, &bl)
100
+ kcb = bl if kcb.nil? && !bl.nil?
101
+
102
+ cb = lambda do |cdktype, widget, component, key|
103
+ kcb.call component, key
104
+ end
105
+
106
+ component.bind(:ENTRY, key, cb, self)
107
+ end
44
108
  end # module CDKComponent
45
109
  end # module RETerm
@@ -0,0 +1,15 @@
1
+ module RETerm
2
+ # XXX copied from CDK
3
+ module CommonControls
4
+ attr_reader :quit_on_enter
5
+
6
+ def quit_on_enter=(v)
7
+ @quit_on_enter_set = true
8
+ @quit_on_enter = v
9
+ end
10
+
11
+ def quit_on_enter?
12
+ @quit_on_enter_set ? @quit_on_enter : true
13
+ end
14
+ end # module CommonControls
15
+ end # module CDK
@@ -0,0 +1,20 @@
1
+ module RETerm
2
+ module CommonKeys
3
+ # Key which if pressed cause the component to
4
+ # lose focus / become deactivated
5
+ QUIT_CONTROLS = [10, 27, Ncurses::KEY_ENTER] # 10 = enter, 27 = ESC,
6
+
7
+ # \033 = CDK::KEY_ESC
8
+ # 343 = NCURSES::KEY_ENTER
9
+
10
+ ENTER_CONTROLS = [10, Ncurses::KEY_ENTER] # quit controls with out esc
11
+
12
+ # Keys if pressed invoked the increment operation
13
+ INC_CONTROLS = ['+'.ord, Ncurses::KEY_UP, Ncurses::KEY_RIGHT]
14
+
15
+ # Keys if pressed invoked the decrement operation
16
+ DEC_CONTROLS = ['-'.ord, Ncurses::KEY_DOWN, Ncurses::KEY_LEFT]
17
+
18
+ # TODO add page/scroll controls
19
+ end # module CommonKeys
20
+ end # module CDK
@@ -3,35 +3,83 @@ module RETerm
3
3
  # components. 'In House' components included in the project
4
4
  # may used this to standarding their usage.
5
5
  module ComponentInput
6
- # Key which if pressed cause the component to
7
- # lose focus / become deactivated
8
- QUIT_CONTROLS = [10, 27] # 10 = enter, 27 = ESC
6
+ include CommonControls
7
+ include CommonKeys
9
8
 
10
- # Keys if pressed invoked the increment operation
11
- INC_CONTROLS = ['+'.ord, Ncurses::KEY_UP, Ncurses::KEY_RIGHT]
9
+ # TODO include / incorporate MouseInput mixin
10
+ # (scroll sliders/dials, click buttons, etc) ...
12
11
 
13
- # Keys if pressed invoked the decrement operation
14
- DEC_CONTROLS = ['-'.ord, Ncurses::KEY_DOWN, Ncurses::KEY_LEFT]
15
-
16
- # May be overrideen in subclass, invoked when the user requests
12
+ # May be overridden in subclass, invoked when the user requests
17
13
  # an 'increment'
18
14
  def on_inc
19
15
  end
20
16
 
21
- # May be overrideen in subclass, invoked when the user
17
+ # May be overridden in subclass, invoked when the user
22
18
  # requests a decrement
23
19
  def on_dec
24
20
  end
25
21
 
22
+ # May be overridden in subclass, invoked when the user inputs
23
+ # the enter key (unless quit_on_enter is true)
24
+ def on_enter
25
+ end
26
+
27
+ # May be overridden in subclass, invoked with every key entered
28
+ def on_key(ch)
29
+ end
30
+
26
31
  # Helper to be internally invoked by component on activation
27
- def handle_input
28
- while(!QUIT_CONTROLS.include?((ch = window.getch)))
29
- if INC_CONTROLS.include?(ch)
32
+ def handle_input(*input)
33
+ while ch = next_ch(input)
34
+ quit = QUIT_CONTROLS.include?(ch)
35
+ enter = ENTER_CONTROLS.include?(ch)
36
+ inc = INC_CONTROLS.include?(ch)
37
+ dec = DEC_CONTROLS.include?(ch)
38
+
39
+ break if shutdown? ||
40
+ (quit && (!enter || quit_on_enter?))
41
+
42
+ if enter
43
+ on_enter
44
+
45
+ elsif inc
30
46
  on_inc
31
- elsif DEC_CONTROLS.include?(ch)
47
+
48
+ elsif dec
32
49
  on_dec
33
50
  end
51
+
52
+ if key_bound?(ch)
53
+ invoke_key_bindings(ch)
54
+ end
55
+
56
+ on_key(ch)
34
57
  end
58
+
59
+ ch
60
+ end
61
+
62
+ def bind_key(key, kcb)
63
+ @bound_keys ||= {}
64
+ @bound_keys[key] ||= []
65
+ @bound_keys[key] << kcb
66
+ nil
67
+ end
68
+
69
+ def key_bound?(key)
70
+ @bound_keys ||= {}
71
+ @bound_keys.key?(key)
72
+ end
73
+
74
+ private
75
+
76
+ def next_ch(input)
77
+ return sync_getch if input.empty?
78
+ input.shift
79
+ end
80
+
81
+ def invoke_key_bindings(key)
82
+ @bound_keys[key].each { |b| b.call self, key }
35
83
  end
36
84
  end # module ComponentInput
37
85
  end # module RETerm
@@ -9,6 +9,8 @@ module RETerm
9
9
  @event_handlers[e].each { |eh|
10
10
  eh.call h
11
11
  } if @event_handlers.key?(e)
12
+
13
+ nil # return last handler return value or perhaps all ?
12
14
  end
13
15
 
14
16
  def handle(e, &bl)
@@ -0,0 +1,8 @@
1
+ module RETerm
2
+ module ItemHelpers
3
+ def max_item_size
4
+ return 0 if @items.empty?
5
+ @items.max { |i1, i2| i1.size <=> i2.size }.size
6
+ end
7
+ end # module ItemHelpers
8
+ end # module RETerm
@@ -0,0 +1,23 @@
1
+ module RETerm
2
+ # Similar to the bindings mixin in the CDK library
3
+ module KeyBindings
4
+ def key_bindings
5
+ @key_bindings ||= {}
6
+ end
7
+
8
+ def bind_key(key, kcb=nil, &bl)
9
+ key_bindings[key] ||= []
10
+ kcb = bl if kcb.nil? && !bl.nil?
11
+ key_bindings[key] << kcb
12
+ end
13
+
14
+ def key_bound?(key)
15
+ key_bindings.key?(key)
16
+ end
17
+
18
+ def invoke_key_bindings(key)
19
+ o = self
20
+ key_bindings[key].all? { |kcb| kcb.call(o, key) }
21
+ end
22
+ end # module ButtonBindings
23
+ end # module RETerm
@@ -0,0 +1,13 @@
1
+ module RETerm
2
+ # Helpers defin
3
+ module LogHelpers
4
+ LOG_FILE = './reterm.log'
5
+
6
+ def logger
7
+ require 'logger'
8
+ @@logger ||= Logger.new LOG_FILE
9
+ end
10
+
11
+ alias :log :logger
12
+ end # module LogHelpers
13
+ end # module RETerm
@@ -0,0 +1,58 @@
1
+ module RETerm
2
+ module MouseInput
3
+ ALL_EVENTS = Ncurses::ALL_MOUSE_EVENTS |
4
+ Ncurses::REPORT_MOUSE_POSITION
5
+
6
+ MOUSE_MAP = {
7
+ :PRESSED => :pressed,
8
+ :RELEASED => :released,
9
+ :CLICKED => :click,
10
+ :DOUBLE_CLICKED => :dclick,
11
+ :TRIPLE_CLICKED => :tclick,
12
+ }
13
+
14
+ def mouse_paste?
15
+ !!reterm_opts[:mouse_paste]
16
+ end
17
+
18
+ # May be overridden in subclass, invoked when
19
+ # the user interacts with a button.
20
+ #
21
+ # @param [Integer] b number of the button that was invoked
22
+ # @param [Symbol] evnt button event, may be :press, :release,
23
+ # :click, :dclick (double click), :tclick (triple click)
24
+ def on_button(b, evnt, coords)
25
+ #puts "B#{b} #{evnt}, #{coords}"
26
+ end
27
+
28
+ def process_mouse(ch)
29
+ return nil unless ch == Ncurses::KEY_MOUSE
30
+
31
+ mev = Ncurses::MEVENT.new
32
+ Ncurses.getmouse(mev)
33
+
34
+ if mev.bstate == Ncurses::BUTTON2_CLICKED && mouse_paste?
35
+ # TODO grab clipboard buffer & return character array
36
+ # (need to handle seperately in invoker)
37
+ #
38
+ # use https://github.com/janlelis/clipboard
39
+ # but note this requires external programs!
40
+ end
41
+
42
+ # TODO 5 button support (requiest "--enable-ext-mouse" ncurses flag
43
+ # which is not specified in many major distrubtions)
44
+ 1.upto(4).each { |b|
45
+ MOUSE_MAP.each { |n, e|
46
+ if mev.bstate == Ncurses.const_get("BUTTON#{b}_#{n}")
47
+ x,y,z = mev.x, mev.y, mev.z
48
+ on_button(b, e, [x,y,z])
49
+ end
50
+ }
51
+ }
52
+
53
+ # TODO wrap MEVENT w/ our own class,
54
+ # w/ high levels helpers for buttons, coords, etc
55
+ mev
56
+ end
57
+ end # module MouseInput
58
+ end # module RETerm