ppcurses 0.0.25 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +50 -11
  3. data/lib/ppcurses/Screen.rb +128 -15
  4. data/lib/ppcurses/actions/BaseAction.rb +1 -2
  5. data/lib/ppcurses/actions/GetBooleanAction.rb +6 -6
  6. data/lib/ppcurses/actions/GetDataAction.rb +4 -4
  7. data/lib/ppcurses/actions/GetEnumeratedStringAction.rb +6 -6
  8. data/lib/ppcurses/actions/GetIntegerAction.rb +2 -2
  9. data/lib/ppcurses/actions/GetStringAction.rb +2 -0
  10. data/lib/ppcurses/actions/PromptAction.rb +2 -2
  11. data/lib/ppcurses/application.rb +219 -0
  12. data/lib/ppcurses/date/meta_month.rb +139 -0
  13. data/lib/ppcurses/form/button.rb +120 -0
  14. data/lib/ppcurses/form/combo_box.rb +93 -0
  15. data/lib/ppcurses/form/date_picker.rb +86 -0
  16. data/lib/ppcurses/form/form.rb +96 -0
  17. data/lib/ppcurses/form/input_element.rb +189 -0
  18. data/lib/ppcurses/form/radio_button_group.rb +56 -0
  19. data/lib/ppcurses/geometry.rb +23 -0
  20. data/lib/ppcurses/menu/BaseMenu.rb +8 -14
  21. data/lib/ppcurses/menu/Menu.rb +5 -8
  22. data/lib/ppcurses/menu/RadioMenu.rb +2 -5
  23. data/lib/ppcurses/menu/choice_menu.rb +33 -0
  24. data/lib/ppcurses/menu/date_menu.rb +97 -0
  25. data/lib/ppcurses/menu_bar.rb +102 -0
  26. data/lib/ppcurses/table_view.rb +58 -0
  27. data/lib/ppcurses/view.rb +45 -0
  28. data/lib/ppcurses/window/pp_window.rb +42 -0
  29. data/lib/ppcurses.rb +57 -3
  30. data/test/application/create_application.rb +23 -0
  31. data/test/date/printMetaMonth.rb +30 -0
  32. data/test/form/menu_opens_form.rb +15 -0
  33. data/test/form/simple_form.rb +48 -0
  34. data/test/form/test_combo.rb +20 -0
  35. data/test/form/test_date_picker.rb +19 -0
  36. data/test/getBooleanAction.rb +1 -1
  37. data/test/getDataAction.rb +6 -6
  38. data/test/getEnumStringAction.rb +4 -4
  39. data/test/getIntegerAction.rb +4 -4
  40. data/test/menu/changeMenuBorder.rb +1 -1
  41. data/test/menu/compositeMenu.rb +2 -2
  42. data/test/menu/displayMenu.rb +1 -1
  43. data/test/raw_screen/display_colours.rb +69 -0
  44. data/test/raw_screen/press_a_key.rb +18 -0
  45. data/test/table_view/testTableView.rb +16 -0
  46. data/test/threads/block_test.rb +63 -0
  47. data/test/threads/handle_resize.rb +43 -0
  48. metadata +37 -12
  49. data/lib/ppcurses/Constants.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2f9ab141072907b3d6bc679c399c9e745e67222
4
- data.tar.gz: 9eda65b014ddc47fecacc8c75bc5211484532489
3
+ metadata.gz: 24ac08644952676975408eb133016f10f3a39825
4
+ data.tar.gz: 0f7536cf358e3e4fce9db59d7eb912a59891d23f
5
5
  SHA512:
6
- metadata.gz: a55ebcc9d419770924382099751371cacdb0b9fa9cd8a2d8e7fc6cc35d2d432eb2d29087ce907aafea22e00bc78b16c9024b9cc7b42ddcece2fda5390aba0083
7
- data.tar.gz: e0d8d21cdcb68e7699d2031e4ff3203c99275df40bbc7e745bf2e04b5e8a36edf7bc785e5ea414bb3efba8ace35021ecad1f17a5756eaf4159779ab0b4d3ed3d
6
+ metadata.gz: 206b4615b6471629bc3cd087f7bfa5c32e57a42c55db96df5ac6675fd803e3136dc77f087683dadb985fa674cac9bd76c8c006187d07c077cea540fb916ec307
7
+ data.tar.gz: f62bf00745e11818ab02a52283a81e5251c35e01aaac07d8ded82ac643133cb0c87fbd798987ac1e359dddd4ee4abd6e3fcf9fb5f08ba5724b16dd87421f5700
data/README.rdoc CHANGED
@@ -1,23 +1,62 @@
1
- = PPCurses
1
+ = PPCurses
2
2
 
3
3
  Some convenience code to initialize curses and some rudimentary GUI classes. See the **test** directory for example programs.
4
4
 
5
5
  == Install
6
- [sudo] gem install 'ppcurses'
6
+ gem install 'ppcurses'
7
+
8
+ To use ppcurses with a ruby > 2.1.5 you must install the curses gem.
9
+
10
+ gem install 'curses'
7
11
 
8
12
  == Usage
9
13
  require 'rubygems'
10
14
  require 'ppcurses'
11
15
 
12
- def displayMenu()
13
- mainMenu = PPCurses::Menu.new( [ "Press", "<ESCAPE>", "to Quit" ], nil )
14
- mainMenu.show()
15
- mainMenu.getMenuSelection()
16
- mainMenu.close()
16
+ def displayMenu
17
+ mainMenu = PPCurses::Menu.new( [ "Press", "<ESCAPE>", "to Quit" ])
18
+ mainMenu.show
19
+ mainMenu.menu_selection
20
+ mainMenu.close
17
21
  end
18
22
 
19
- screen = PPCurses::Screen.new()
20
- screen.run { displayMenu() }
23
+ screen = PPCurses::Screen.new
24
+ screen.run { displayMenu }
25
+
26
+ == Curses and Ruby
27
+
28
+ There are several curses implementations for Ruby.
29
+
30
+ [1. curses]
31
+
32
+ This is the implementation that PPCurses uses. It was originally part of the Ruby
33
+ standard library and later got pushed out of the standard libary into a gem.
34
+
35
+ * http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html
36
+ * http://www.ruby-doc.org/stdlib-2.0.0/libdoc/curses/rdoc/Curses.html
37
+ * http://www.ruby-doc.org/stdlib-2.1.0/libdoc/curses/rdoc/Curses.html
38
+ * https://rubygems.org/gems/curses
39
+ * https://github.com/ruby/curses
40
+
41
+ [2. ncurses-ruby]
42
+
43
+ The heir to ncurses gem. It is under active development.
44
+
45
+ * https://rubygems.org/gems/ncurses-ruby
46
+ * https://github.com/eclubb/ncurses-ruby
47
+
48
+ [3. ncurses]
49
+
50
+ Created by Earle Clubb this gem has been frozen at version 0.9.1 since 2004. You
51
+ probably don't want this gem, you probably want ncurses-ruby.
52
+
53
+ * https://rubygems.org/gems/ncurses
54
+
55
+ [4. ffi-curses]
56
+
57
+ A gem that makes curses available through FFI (foreign function interface), by
58
+ Sean O'Halpin. The latest version is from 2011 (0.4.0).
59
+
60
+ * https://github.com/seanohalpin/ffi-ncurses
61
+ * https://github.com/ffi/ffi
21
62
 
22
- == References
23
- http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html
@@ -1,17 +1,136 @@
1
- # Curses reference:
2
- # http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html
1
+ module OS
2
+ def OS.windows?
3
+ (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
4
+ end
5
+
6
+ def OS.mac?
7
+ (/darwin/ =~ RUBY_PLATFORM) != nil
8
+ end
9
+
10
+ def OS.unix?
11
+ !OS.windows?
12
+ end
13
+
14
+ def OS.linux?
15
+ OS.unix? and not OS.mac?
16
+ end
17
+ end
18
+
19
+
20
+
21
+ module Curses
22
+
23
+ #
24
+ # Add some methods that allow accessing a window by PPPoint.
25
+ #
26
+ class Window
27
+
28
+ def cur_point
29
+ PPCurses::Point.new(curx, cury)
30
+ end
31
+
32
+ def set_pos_by_point( p )
33
+ setpos(p.y, p.x)
34
+ end
35
+
36
+ def move_to_point( p )
37
+ move(p.y, p.x)
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
3
44
 
4
- require 'curses'
5
- include Curses
6
45
 
7
46
  module PPCurses
8
47
 
48
+
49
+
9
50
  # Screen initializes the Curses screen
10
51
  # Pass a code block to the run method to start things
11
52
  #
12
53
  # noinspection RubyResolve
13
54
  class Screen
14
55
 
56
+
57
+ def setup_curses
58
+ Curses.init_screen
59
+ Curses.raw
60
+
61
+ # Can't implement regardless as this can cause an unsupportedOperationException on some configurations
62
+ # like cygwin.
63
+ if OS.unix?
64
+ Curses.ESCDELAY=0
65
+ end
66
+
67
+
68
+ # Otherwise arrow keys, etc can't be read from the main screen and cause the
69
+ # program to stop.
70
+ Curses.stdscr.keypad(true)
71
+
72
+ Curses.clear
73
+ Curses.curs_set(INVISIBLE)
74
+ Curses.noecho
75
+ Curses.cbreak
76
+ Curses.start_color
77
+ end
78
+
79
+ def print_with_attribute( toPrint, attribute )
80
+ Curses.stdscr.attron( attribute )
81
+ Curses.stdscr.addstr( toPrint )
82
+ Curses.stdscr.attroff( attribute )
83
+ end
84
+
85
+ def get_ch
86
+ Curses.stdscr.getch
87
+ end
88
+
89
+ def width
90
+ Curses.cols
91
+ end
92
+
93
+ def height
94
+ Curses.lines
95
+ end
96
+
97
+ def set_pos_by_point( p )
98
+ setpos(p.y, p.x)
99
+ end
100
+
101
+ def setpos(y, x)
102
+ Curses.stdscr.setpos(y, x)
103
+ end
104
+
105
+ def attron(attributes)
106
+ Curses.stdscr.attron(attributes)
107
+ end
108
+
109
+ def attroff(attributes)
110
+ Curses.stdscr.attroff(attributes)
111
+ end
112
+
113
+ def addstr(string)
114
+ Curses.stdscr.addstr(string)
115
+ end
116
+
117
+ def getch
118
+ Curses.stdscr.getch
119
+ end
120
+
121
+ def cur_point
122
+ PPCurses::Point.new(Curses.stdscr.curx, Curses.stdscr.cury)
123
+ end
124
+
125
+ def curs_set(value)
126
+ Curses.curs_set(value)
127
+ end
128
+
129
+
130
+ def shutdown_curses
131
+ Curses.close_screen
132
+ end
133
+
15
134
  # Creates a curses session
16
135
  #
17
136
  # Example:
@@ -19,23 +138,17 @@ module PPCurses
19
138
  #
20
139
  def run
21
140
  begin
22
- init_screen
23
- Curses.raw
24
- clear
25
- curs_set(0) # Makes cursor invisible
26
- noecho
27
- cbreak
28
- start_color
29
-
30
- yield
141
+ setup_curses
142
+
143
+ return yield
31
144
 
32
145
  rescue SystemExit, Interrupt
33
146
  # Empty Catch block so ruby doesn't puke out
34
147
  # a stack trace when CTRL-C is used
35
148
  ensure
36
- close_screen
149
+ shutdown_curses
37
150
  end
38
- end
151
+ end
39
152
 
40
153
  end
41
154
  end
@@ -1,5 +1,3 @@
1
- require 'curses'
2
-
3
1
  #noinspection RubyResolve
4
2
  module PPCurses
5
3
  class BaseAction
@@ -16,6 +14,7 @@ module PPCurses
16
14
  2
17
15
  end
18
16
 
17
+ # TODO -- need abstraction layer.
19
18
  def win_width
20
19
  Curses.cols - win_padding
21
20
  end
@@ -25,17 +25,17 @@ module PPCurses
25
25
  # Enables reading arrow keys in getch
26
26
  @win.keypad(true)
27
27
  while 1
28
- noecho
28
+ Curses.noecho
29
29
  c = @win.getch
30
30
 
31
- if c == KEY_LEFT then @state = false end
32
- if c == KEY_RIGHT then @state = true end
33
- if c == 10 then break end
31
+ if c == Curses::KEY_LEFT then @state = false end
32
+ if c == Curses::KEY_RIGHT then @state = true end
33
+ if c == ESCAPE then break end
34
34
 
35
- echo
35
+ Curses.echo
36
36
  print_prompt
37
37
  end
38
- echo
38
+ Curses.echo
39
39
  end
40
40
 
41
41
  def data
@@ -46,7 +46,7 @@ class GetDataAction < BaseAction
46
46
 
47
47
  def execute
48
48
  create_window
49
- echo
49
+ Curses.echo
50
50
 
51
51
  @win.setpos(@win.cury, x_padding )
52
52
 
@@ -58,7 +58,7 @@ class GetDataAction < BaseAction
58
58
 
59
59
  self.after_actions
60
60
 
61
- noecho
61
+ Curses.noecho
62
62
  @win.clear
63
63
  @win.refresh
64
64
  @win.close
@@ -71,14 +71,14 @@ class GetDataAction < BaseAction
71
71
  end
72
72
 
73
73
  def print_success_line(string)
74
- init_pair(1, COLOR_GREEN, COLOR_BLACK)
74
+ Curses.init_pair(1, COLOR_GREEN, COLOR_BLACK)
75
75
  @win.attron(color_pair(1))
76
76
  self.print_line(string)
77
77
  @win.attroff(color_pair(1))
78
78
  end
79
79
 
80
80
  def print_error_line(string)
81
- init_pair(1, COLOR_RED, COLOR_BLACK)
81
+ Curses.init_pair(1, COLOR_RED, COLOR_BLACK)
82
82
  @win.attron(color_pair(1))
83
83
  self.print_line(string)
84
84
  @win.attroff(color_pair(1))
@@ -37,20 +37,20 @@ module PPCurses
37
37
  # Enables reading arrow keys in getch
38
38
  @win.keypad(true)
39
39
  while 1
40
- noecho
40
+ Curses.noecho
41
41
  c = @win.getch
42
42
 
43
- if c == KEY_LEFT then @current_option = @current_option-1 end
44
- if c == KEY_RIGHT then @current_option = @current_option+1 end
45
- if c == 10 then break end
43
+ if c == Curses::KEY_LEFT then @current_option = @current_option-1 end
44
+ if c == Curses::KEY_RIGHT then @current_option = @current_option+1 end
45
+ if c == ESCAPE then break end
46
46
 
47
47
  if @current_option < 0 then @current_option = @options.length-1 end
48
48
  if @current_option > @options.length-1 then @current_option = 0 end
49
49
 
50
- echo
50
+ Curses.echo
51
51
  print_prompt
52
52
  end
53
- echo
53
+ Curses.echo
54
54
  # Go to next line so that further actions to overwrite
55
55
  # the choice
56
56
  @win.setpos(@win.cury + 1, x_padding)
@@ -13,9 +13,9 @@ module PPCurses
13
13
  @win.clrtoeol
14
14
  @win.box('|', '-')
15
15
  @win.addstr(@prompt)
16
- echo
16
+ Curses.echo
17
17
  @data = @win.getstr
18
- noecho
18
+ Curses.noecho
19
19
  end until @data =~ /^\d+$/
20
20
  end
21
21
 
@@ -1,6 +1,8 @@
1
1
  require_relative 'PromptAction.rb'
2
2
 
3
3
  module PPCurses
4
+
5
+ # Deprecated: Use a form with an input_element.
4
6
  class GetStringAction < PromptAction
5
7
  end
6
8
  end
@@ -27,9 +27,9 @@ module PPCurses
27
27
 
28
28
  def execute
29
29
  print_prompt
30
- echo
30
+ Curses.echo
31
31
  @data = @win.getstr
32
- noecho
32
+ Curses.noecho
33
33
  end
34
34
 
35
35
  def data
@@ -0,0 +1,219 @@
1
+ module PPCurses
2
+
3
+ # Based on the Cocoa NSResponder
4
+ #
5
+ # Current link, which probably won't be valid in the future ...
6
+ #
7
+ # https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/index.html#//apple_ref/occ/instp/NSResponder/menu
8
+ #
9
+ class Responder
10
+
11
+ attr_accessor :next_responder
12
+
13
+ #
14
+ # Whether the responder accepts first responder status.
15
+ #
16
+ # As first responder, the receiver is the first object in the responder chain to be sent key events
17
+ # and action messages. By default, this property is NO. Subclasses set this property to YES if the
18
+ # receiver accepts first responder status.
19
+ #
20
+ def accepts_first_responder
21
+ NO
22
+ end
23
+
24
+ #
25
+ # Notifies the receiver that it’s about to become first responder
26
+ #
27
+ # The default implementation returns YES, accepting first responder status. Subclasses can override
28
+ # this method to update state or perform some action such as highlighting the selection, or to
29
+ # return NO, refusing first responder status.
30
+ #
31
+ def become_first_responder
32
+ YES
33
+ end
34
+
35
+ #
36
+ # Notifies the receiver that it’s been asked to relinquish its status as first responder in its window.
37
+ #
38
+ # The default implementation returns YES, resigning first responder status. Subclasses can override
39
+ # this method to update state or perform some action such as unhighlighting the selection, or to
40
+ # return NO, refusing to relinquish first responder status.
41
+ #
42
+ def resign_first_responder
43
+ YES
44
+ end
45
+
46
+ #
47
+ # Informs the receiver that the user has pressed a key.
48
+ #
49
+ # The default implementation simply passes this message to the next responder.
50
+ #
51
+ def key_down( key )
52
+ @next_responder.key_down(key) unless @next_responder.nil?
53
+ end
54
+
55
+ def Responder.isa( obj )
56
+ PPCurses.implements_protocol( obj, %w(accepts_first_responder become_first_responder resign_first_responder key_down))
57
+ end
58
+
59
+ end
60
+
61
+ #=======================================================================================================================
62
+ #
63
+ # Derived from methods defined in Cocoa NSWindow
64
+ #
65
+ # Current link, which probably won't be valid in the future ...
66
+ #
67
+ # https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSWindow_Class/index.html#//apple_ref/occ/instm/NSWindow
68
+ #
69
+ class ResponderManager < Responder
70
+
71
+ # The first responder is the first object in a responder chain to receive an event or action message.
72
+ attr_accessor :first_responder
73
+
74
+ def accepts_first_responder
75
+ YES
76
+ end
77
+
78
+ #
79
+ # Attempts to make a given responder the first responder
80
+ #
81
+ #
82
+ # If responder isn’t already the first responder, this method first sends a resign_first_responder message
83
+ # to the object that is the first responder. If that object refuses to resign, it remains the first responder,
84
+ # and this method immediately returns NO. If the current first responder resigns, this method sends a
85
+ # become_first_responder message to responder.
86
+ #
87
+ # If responder does not accept first responder status, the ResponderManager becomes first responder; in
88
+ # this case, the method returns YES even if the responder refused first responder status.
89
+ #
90
+ # If responder is nil, this method still sends resign_first_responder to the current first responder.
91
+ #
92
+ def make_first_responder( responder )
93
+
94
+ Responder.isa(responder) unless responder.nil?
95
+
96
+ if responder != @first_responder
97
+ will_resign = responder.resign_first_responder
98
+ unless will_resign
99
+ return NO
100
+ end
101
+ end
102
+
103
+ @first_responder = nil
104
+
105
+ accepted = NO
106
+ will_accept = responder.accepts_first_responder
107
+
108
+ if will_accept
109
+ accepted = responder.become_first_responder
110
+ end
111
+
112
+ unless accepted
113
+ @first_responder = self
114
+ return YES
115
+ end
116
+
117
+ @first_responder = responder
118
+
119
+ YES
120
+ end
121
+
122
+
123
+ end
124
+
125
+ #=======================================================================================================================
126
+
127
+ # noinspection RubyClassVariableUsageInspection
128
+ class Application < ResponderManager
129
+
130
+ @@shared_app
131
+
132
+ attr_accessor :main_menu
133
+
134
+ # Any object of type PPCurses:View
135
+ attr_accessor :content_view
136
+
137
+ def initialize
138
+ @screen = PPCurses::Screen.new
139
+
140
+ @main_menu = create_default_menubar
141
+ @next_responder = @main_menu
142
+
143
+ @@shared_app = self
144
+ @terminated = false
145
+ end
146
+
147
+
148
+ def content_view=(value)
149
+ @content_view=value
150
+ @main_menu.next_responder=@content_view
151
+ end
152
+
153
+ def create_default_menubar
154
+ menubar = PPCurses::MenuBar.new
155
+
156
+ quit_item = PPCurses::MenuBarItem.new('q', 'Quit')
157
+ quit_item.action = method(:terminate)
158
+ menubar.add_menu_item(quit_item)
159
+
160
+ menubar
161
+ end
162
+
163
+
164
+ # Informal protocol
165
+ # A delegate receives notifications if and only if a method is defined
166
+ #
167
+ # applicationDidFinishLaunching
168
+ # applicationShouldTerminate
169
+ #
170
+ def set_delegate (delegate)
171
+ @delegate = delegate
172
+ end
173
+
174
+
175
+ def launch
176
+ @screen.setup_curses
177
+ if @delegate.respond_to?(:applicationDidFinishLaunching)
178
+ @delegate.applicationDidFinishLaunching(self)
179
+ end
180
+
181
+ until @terminated
182
+ # TODO - switch show to display?
183
+ @main_menu.show(@screen) unless @main_menu.nil?
184
+
185
+ # TODO -- pass a subview of the screen.
186
+ @content_view.display(@screen) unless @content_view.nil?
187
+
188
+ c = @screen.get_ch
189
+ key_down(c)
190
+ end
191
+
192
+ @screen.shutdown_curses
193
+
194
+ end
195
+
196
+ def terminate
197
+
198
+ # Cocoa returns an NSApplicationTerminateReply which can
199
+ # be a cancel, now or later response. Simply support a boolean
200
+ # for now.
201
+ if @delegate.respond_to?(:applicationShouldTerminate)
202
+ should_terminate = @delegate.applicationShouldTerminate(self)
203
+ unless should_terminate
204
+ return
205
+ end
206
+ end
207
+
208
+ @terminated = true
209
+ end
210
+
211
+ def Application.sharedApplication
212
+ @@shared_app
213
+ end
214
+
215
+
216
+
217
+ end
218
+
219
+ end