reterm 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,22 @@
1
+ require 'json'
2
+
3
+ module RETerm
4
+ class Config
5
+ CONFIG_FILE = File.expand_path("~/.reterm")
6
+
7
+ def self.get
8
+ @config ||=
9
+ begin
10
+ return {} unless File.exist?(CONFIG_FILE)
11
+ JSON.parse(File.read(CONFIG_FILE))
12
+ end
13
+ end
14
+
15
+ def self.load_plugins
16
+ return unless get.key?("plugins")
17
+ get["plugins"].each { |p|
18
+ require p
19
+ }
20
+ end
21
+ end # class Config
22
+ end # module RETerm
data/lib/reterm/init.rb CHANGED
@@ -2,6 +2,10 @@ require 'ncursesw'
2
2
  require_relative './resize'
3
3
 
4
4
  module RETerm
5
+ SYNC_TIMEOUT = 150 # in milliseconds if enabled
6
+
7
+ ###############################
8
+
5
9
  # Initializes the RETerm subsystem before invoking block.
6
10
  # After block is finished regardless of execution state
7
11
  # (return, exception, etc) this will cleanup the terminal
@@ -17,6 +21,11 @@ module RETerm
17
21
  # }
18
22
  #
19
23
  def init_reterm(opts={}, &bl)
24
+ @@shutdown = false
25
+ @@reterm_opts = opts
26
+
27
+ err = nil
28
+
20
29
  begin
21
30
  Terminal.load # XXX: not sure why but loading terminal
22
31
  # info after changing terminal settings via
@@ -25,25 +34,43 @@ module RETerm
25
34
  # without a 'reset' (see below).
26
35
  # So just preload terminal info here.
27
36
 
37
+ # shorten up the esc delay time
38
+ ENV["ESCDELAY"] = 100.to_s
39
+
28
40
  stdscr = Ncurses::initscr
29
41
  Ncurses::start_color
30
42
  Ncurses::noecho
31
43
  Ncurses::cbreak
32
- Ncurses::curs_set(0)
44
+ disable_cursor! unless !!opts[:cursor]
33
45
  Ncurses::keypad(stdscr, true)
34
46
 
47
+ no_mouse = opts[:nomouse] || (opts.key?(:mouse) && !opts[:mouse])
48
+ Ncurses::mousemask(MouseInput::ALL_EVENTS, []) unless no_mouse
49
+
35
50
  track_resize if opts[:resize]
36
51
 
37
52
  bl.call
38
53
 
39
- #ensure
54
+ rescue => e
55
+ err = e
56
+
57
+ ensure
40
58
  stop_track_resize
41
59
  Ncurses.curs_set(1)
42
- Window.all.each { |w| w.finalize! }
60
+ Window.top.each { |w| w.finalize! }
43
61
  CDK::SCREEN.endCDK if cdk_enabled?
44
- Ncurses.endwin()
62
+ Ncurses.endwin
45
63
  #`reset -Q` # XXX only way to guarantee a full reset (see above)
46
64
  end
65
+
66
+ if err
67
+ puts "Unhandled error:"
68
+ puts " " + err.to_s
69
+ puts err.backtrace
70
+ .collect { |b|
71
+ " " + b
72
+ }.join("\n")
73
+ end
47
74
  end
48
75
 
49
76
  # This method resyncs the visible terminal with the internal
@@ -58,18 +85,74 @@ module RETerm
58
85
  # win.getch # wait for input
59
86
  # }
60
87
  #
61
- def update_reterm
62
- Window.top.each { |w| w.refresh }
88
+ def update_reterm(force_refresh=false)
89
+ if force_refresh
90
+ Window.top.each { |w|
91
+ w.erase
92
+ w.draw!
93
+ }
94
+ else
95
+ Window.top.each { |w| w.noutrefresh }
96
+ end
97
+
63
98
  Ncurses::Panel.update_panels
64
99
  Ncurses.doupdate
65
100
  end
66
101
 
102
+ # Return copy of options specified to init_reterm
103
+ def reterm_opts
104
+ @@_reterm_opts ||= Hash[@@reterm_opts]
105
+ end
106
+
67
107
  # XXX Ncurses is exposed so that users
68
108
  # may employ any constants if desired.
69
109
  # This should not be needed though and
70
110
  # is discouraged to maintain portability
71
111
  NC = Ncurses
72
112
 
113
+ ###
114
+
115
+ # Cursor
116
+
117
+ def cursor?
118
+ !(@@cursor_disabled ||= false)
119
+ end
120
+
121
+ def disable_cursor!
122
+ # store cursor state
123
+ o = cursor?
124
+
125
+ # set cursor state
126
+ @@cursor_disabled = true
127
+ Ncurses::curs_set(0)
128
+
129
+ # invoke block if given
130
+ return unless block_given?
131
+ yield
132
+
133
+ # restore cursor state after block
134
+ enable_cursor! if o
135
+ end
136
+
137
+ def enable_cursor!
138
+ # store cursor state
139
+ o = cursor?
140
+
141
+ # set cursor state
142
+ @@cursor_disabled = false
143
+ Ncurses::curs_set(1)
144
+
145
+ # invoke block if given
146
+ return unless block_given?
147
+ yield
148
+
149
+ # restore cursor state after block
150
+ disable_cursor! unless o
151
+ end
152
+
153
+
154
+ ###############################
155
+
73
156
  # Enable the CDK subsystem. Used by CDKbased components
74
157
  #
75
158
  # @see #cdk_enabled?
@@ -92,4 +175,46 @@ module RETerm
92
175
  def cdk_enabled?
93
176
  !!@cdk_enabled
94
177
  end
178
+
179
+ ###############################
180
+
181
+ # Enables the input timeout and component syncronization.
182
+ #
183
+ # Used internally by components that need to periodically
184
+ # be updated outside of user input.
185
+ def activate_sync!
186
+ @@sync_activated = true
187
+ Window.all.each { |w|
188
+ w.win.timeout(SYNC_TIMEOUT)
189
+ }
190
+ end
191
+
192
+ # Boonean indicating if component syncronization is
193
+ # enabled
194
+ def sync_enabled?
195
+ defined?(@@sync_activated) && !!@@sync_activated
196
+ end
197
+
198
+ # Run the sync process, used internally
199
+ def run_sync!
200
+ return unless sync_enabled?
201
+
202
+ Window.all.each { |w|
203
+ w.sync!
204
+ }
205
+
206
+ update_reterm
207
+ end
208
+
209
+ ###############################
210
+
211
+ # Use to halt all operation and cleanup.
212
+ def shutdown!
213
+ @@shutdown = true
214
+ end
215
+
216
+ # Boolean indicating if app in being halted
217
+ def shutdown?
218
+ !!@@shutdown
219
+ end
95
220
  end # module RETerm
data/lib/reterm/layout.rb CHANGED
@@ -7,57 +7,193 @@ module RETerm
7
7
  class Layout < Component
8
8
  include NavInput
9
9
 
10
- # TODO padding / margin support
10
+ # Flag indicating if layout should expand
11
+ # to be able to contain childen (if false
12
+ # error will be throw if trying to add
13
+ # child to layout that cannot contain it)
14
+ attr_accessor :expand
15
+
16
+ def expandable?
17
+ (!defined?(@expand) || !!@expand) &&
18
+ (!parent? || parent.expandable?)
19
+ end
20
+
21
+ def children
22
+ window.children.collect { |w| w.component }
23
+ end
24
+
25
+ def empty?
26
+ return true if window.nil?
27
+ window.children.empty?
28
+ end
29
+
30
+ def child_windows
31
+ window.children
32
+ end
33
+
34
+ def parent?
35
+ window.parent?
36
+ end
37
+
38
+ def parent
39
+ window.parent.component
40
+ end
11
41
 
12
- attr_accessor :children
42
+ # TODO padding / margin support
13
43
 
14
- def initialize(args={})
15
- @children ||= []
44
+ # Subclasses should override this method returning
45
+ # current rows in layout
46
+ def current_rows
47
+ raise "NotImplemented"
16
48
  end
17
49
 
18
50
  # Subclasses should override this method returning
19
- # boolean if child window exceeds bounds of layout
20
- def exceeds_bounds?(child)
51
+ # current cols in layout
52
+ def current_cols
21
53
  raise "NotImplemented"
22
54
  end
23
55
 
56
+ # Subclasses should overrid this method returning
57
+ # boolean indicating if boundries will be
58
+ # exceeded when child is added
59
+ def exceeds_bounds_with?(child)
60
+ raise "NotImplemented"
61
+ end
62
+
63
+ # Returns boolean indicating if current layout
64
+ # exceeds bounds of window
65
+ def exceeds_bounds?
66
+ current_cols > window.cols ||
67
+ current_rows > window.rows
68
+ end
69
+
70
+
71
+ # Return layout containing component
72
+ # If coordinates are contained in a child in current layout
73
+ def layout_containing(component)
74
+ return self if children.include?(component)
75
+
76
+ found = nil
77
+ children.each { |c|
78
+ next if found
79
+
80
+ if c.kind_of?(Layout)
81
+ found = c unless c.layout_containing(component).nil?
82
+ end
83
+ }
84
+
85
+ found
86
+ end
87
+
88
+ # Return boolean indicating if layout contains specified child
89
+ def contains?(child)
90
+ children.any? { |c|
91
+ (c.kind_of?(Layout) && c.contains?(child)) || c == child
92
+ }
93
+ end
94
+
24
95
  # Return boolean indicating if any child component
25
96
  # is activatable
26
97
  def activatable?
27
- children.any? { |c| c.component.activatable? }
98
+ return false if empty?
99
+ children.any? { |c| c.activatable? }
100
+ end
101
+
102
+ def highlight_focus?
103
+ false
28
104
  end
29
105
 
30
106
  # Create new child window and add it to layout
31
107
  def add_child(h={})
108
+ c = nil
109
+
110
+ if h.key?(:component)
111
+ c = h[:component]
112
+
113
+ h = {:rows => c.requested_rows + c.extra_padding,
114
+ :cols => c.requested_cols + c.extra_padding}.merge(h)
115
+ end
116
+
117
+ raise ArgumentError, "must specify x/y" unless h.key?(:x) &&
118
+ h.key?(:y)
119
+
120
+ raise ArgumentError, "must specify rows/cols" unless h.key?(:rows) &&
121
+ h.key?(:cols)
122
+
123
+ h[:rows], h[:cols] = *Window.adjust_proportional(window, h[:rows], h[:cols])
124
+ h[:x], h[:y] = *Window.align(window, h[:x], h[:y], h[:rows], h[:cols])
125
+ h[:rows], h[:cols] = *Window.fill_parent(parent? ? parent.window : Terminal,
126
+ h[:x], h[:y],
127
+ h[:rows], h[:cols]) if h[:fill]
128
+
129
+ if exceeds_bounds_with?(h)
130
+ if expandable? # ... && can_expand_to?(h)
131
+ expand(h)
132
+
133
+ else
134
+ raise ArgumentError, "child exceeds bounds"
135
+
136
+ end
137
+ end
138
+
32
139
  child = window.create_child(h)
33
140
 
141
+ # TODO need to reverse expansion if operation fails at any
142
+ # point on, or verify expandable before create_child but
143
+ # do not expand until after
144
+
34
145
  if child.win.nil?
35
146
  raise ArgumentError, "could not create child window"
36
147
  end
37
148
 
38
- if exceeds_bounds?(child)
149
+ if exceeds_bounds?
39
150
  window.del_child(child) unless child.win.nil?
40
151
  raise ArgumentError, "child exceeds bounds"
41
152
  end
42
153
 
43
- children << child
154
+ child.component = c unless c.nil?
155
+
44
156
  update_reterm
45
157
  child
46
158
  end
47
159
 
160
+ def expand(h)
161
+ nr = [current_rows, h[:y] + h[:rows]].max
162
+ nc = [current_cols, h[:x] + h[:cols]].max
163
+
164
+ # verify parent can contain expanded area and is expandable
165
+ if parent?
166
+ if parent.exceeds_bounds_with?(h)
167
+ raise ArgumentError, "cannot expand parent" unless parent.expandable?
168
+
169
+ # expand parent
170
+ parent.expand(h)
171
+ end
172
+ end
173
+
174
+ # perform actual window expansion
175
+ window.resize(nr+1, nc+1)
176
+
177
+ # FIXME need to expand children who are marked as 'fill'
178
+ end
179
+
48
180
  # Draw all layout children
49
181
  def draw!
50
182
  children.each { |c| c.draw! }
183
+ draw_focus!
51
184
  end
52
185
 
53
186
  # Activates layout by dispatching to navigation
54
187
  # input system.
55
188
  #
56
189
  # @see NavInput
57
- def activate!
190
+ def activate!(*input)
191
+ reactivate!
192
+
58
193
  draw!
59
194
  update_reterm
60
- handle_input
195
+ handle_input(*input)
196
+ deactivate!
61
197
  end
62
198
  end # class Layout
63
199
  end # module RETerm
@@ -14,3 +14,4 @@ end
14
14
  require 'reterm/layout'
15
15
  require 'reterm/layouts/horizontal'
16
16
  require 'reterm/layouts/vertical'
17
+ require 'reterm/layouts/grid'
@@ -0,0 +1,69 @@
1
+ module RETerm
2
+ module Layouts
3
+ # Layout which permits the user to arrainge items anywhere on screen
4
+ class Grid < Layout
5
+ def current_rows
6
+ return 1 if empty?
7
+ child_windows.max { |c1, c2| c1.rows <=> c2.rows }.rows + 1
8
+ end
9
+
10
+ def current_cols
11
+ return 1 if empty?
12
+ child_windows.max { |c1, c2| c1.cols <=> c2.cols }.cols + 1
13
+ end
14
+
15
+ def exceeds_bounds_with?(child)
16
+ x1 = child.is_a?(Hash) ? child[:x] : child.x
17
+ y1 = child.is_a?(Hash) ? child[:y] : child.y
18
+
19
+ x2 = child.is_a?(Hash) ?
20
+ [current_cols, x1 + child[:cols]].compact.max :
21
+ [current_cols, x1 + child.cols].max
22
+
23
+ y2 = child.is_a?(Hash) ?
24
+ [current_rows, y1 + child[:rows]].compact.max :
25
+ [current_rows, y1 + child.rows].max
26
+
27
+ x1 < window.x || y1 < window.y ||
28
+ x2 > window.cols || y2 > window.rows
29
+ end
30
+
31
+ def valid_input?(ch, from_parent)
32
+ if UP_CONTROLS.include?(ch)
33
+ return focusable.any? { |f| f.window.y < focused.window.y }
34
+
35
+ elsif DOWN_CONTROLS.include?(ch)
36
+ return focusable.any? { |f| f.window.y > focused.window.y }
37
+
38
+ elsif LEFT_CONTROLS.include?(ch)
39
+ focusable.any? { |f| f.window.x < focused.window.x }
40
+
41
+ elsif RIGHT_CONTROLS.include?(ch)
42
+ focusable.any? { |f| f.window.x > focused.window.x }
43
+ end
44
+ end
45
+
46
+ # Cycle through components child position on grid
47
+ def next_focus(ch)
48
+ f = nil
49
+ if UP_CONTROLS.include?(ch)
50
+ f = focusable.select { |f| f.window.y < focused.window.y }.first
51
+
52
+ elsif DOWN_CONTROLS.include?(ch)
53
+ f = focusable.select { |f| f.window.y > focused.window.y }.first
54
+
55
+ elsif LEFT_CONTROLS.include?(ch)
56
+ f = focusable.select { |f| f.window.x < focused.window.x }.first
57
+
58
+ elsif RIGHT_CONTROLS.include?(ch)
59
+ f = focusable.select { |f| f.window.x > focused.window.x }.first
60
+
61
+ else
62
+ return super
63
+ end
64
+
65
+ focusable.index(f)
66
+ end
67
+ end # class Grid
68
+ end # module Layouts
69
+ end # module RETerm