ppcurses 0.0.25 → 0.1.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 (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