simple_gui_creator 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,8 +1,10 @@
1
+ 0.2.0
2
+ add checkboxes, dropdowns, allow for more than one type on a line.
1
3
 
2
4
  0.1.4 fix gemspec
3
5
 
4
6
  0.1.3
5
- same :)
7
+ same as 0.1.2 :)
6
8
 
7
9
  0.1.2
8
10
  better lookin' GUI :)
data/README CHANGED
@@ -1,81 +1,122 @@
1
- This gem is meant to make GUI development in Ruby easy, and even fun.
1
+ This gem is meant to make GUI development in Ruby apps trivial,
2
+ and easy to add to a project.
2
3
 
3
- You can specify "easy window layout" in ASCII text, example, if you have a layout like this:
4
+ Basically it allows you to design your window GUI layout using
5
+ ASCII art-like text:
4
6
 
5
- ---------- A Title ---------------------------
6
- | [a button:button1] [button text:button2] |
7
- | "some text2:text1" |
8
- ----------------------------------------------
7
+ ---------------My Window Title--------------------------
8
+ | [Click this button :button1] |
9
+ | [Click this button too! :button2] |
10
+ --------------------------------------------------------
9
11
 
10
- It will create a window that has buttons and text "like that," with reasonable spacing.
12
+ And then bind actions to ruby code, like this:
11
13
 
12
- Here's how:
13
- >> frame = SimpleGuiCreator::ParseTemplate.new # or optionally subclass this instead, and call super in your constructor
14
+ elements[:button1].on_clicked { puts 'you clicked button1' }
15
+
16
+ This makes the design part of the GUI much easier than trying to figure
17
+ it out by trial and error, or "guessing" what swing or shoes are going to actually
18
+ give for you in the end. It comes with its own experimental "GUI Editor" for
19
+ trying out designs on the fly.
20
+
21
+ How to get it:
22
+
23
+ # if you don't have jruby yet installed, for OS X or linux users (windows users use the jruby installer exe):
24
+ $ rvm install jruby
25
+ $ rvm use jruby
26
+
27
+ # now install the gem.
28
+ $ gem install simple_gui_creator
29
+
30
+ # now run the GUI design editor
31
+ $ jruby -S simple_gui_creator
32
+
33
+ Here's how to code it:
34
+
35
+ >> frame = SimpleGuiCreator::ParseTemplate.new # or optionally subclass this instead, and make sure to call super() in your constructor
14
36
  >> frame.parse_setup_filename 'some_filename'
15
37
 
16
- You can then program behaviors like this:
38
+ Set behaviors like this:
17
39
 
18
40
  >> frame.elements['button1'].on_clicked {
19
41
  SimpleGuiCreator.show_blocking_message_dialog "you clicked button1!"
20
42
  }
21
43
 
22
- This separates your views from your controllers, in this case, because you can store the layouts in
23
- an entirely separate file, or embedded in the code. "Normal humans" can then edit the design layout files, for instance.
24
44
 
25
- It also has helper methods for common GUI tasks, like the above show_blocking_message_dialog, and also:
45
+ Having the layout as ASCII text separates views from controllers, in this case, because you can store the layouts in
46
+ an entirely separate file (or embedded in the code). "Normal humans" can then edit the design layout files, for instance.
47
+ It has proven quite nice at separating concerns.
48
+
49
+ More complicated example:
50
+
51
+ ---------- Window Title ----------------------------------
52
+ | [a button:button1] [button text:button2] |
53
+ | "some text2:text1" |
54
+ | [An Editable Text Area with 4 rows:text_area] |
55
+ | [ ] |
56
+ | [ ] |
57
+ | [ ] |
58
+ | [Dropdown Default \/ :dropdown_name] |
59
+ | [✓:checkbox_name] "Some text" |
60
+ ----------------------------------------------------------
61
+
62
+ See the file spec/parse_template.spec.rb for examples of how to use each element.
63
+ The window borders are also optional.
64
+
65
+ The library also has helper methods for common GUI tasks, like:
66
+
67
+ SimpleGuiCreator.show_blocking_message_dialog "A message box"
26
68
  SimpleGuiCreator.new_nonexisting_filechooser_and_go # select file or filename for a "new file" (not yet existing)
27
69
  SimpleGuiCreator.new_existing_dir_chooser_and_go # select pre-existing directory
28
70
  SimpleGuiCreator.show_in_explorer(filename) # reveals file in Explorer for windows, Finder for OS X
29
71
  text_from_user = SimpleGuiCreator.get_user_input "Input your name:" # these raise an exception if the user cancels the dialog,
30
72
 
31
- A select-button prompt dialog:
32
-
73
+ Select-button prompt dialog:
33
74
  if(SimpleGuiCreator.show_select_buttons_prompt("message title", :yes => 'text for the yes button', :no => 'text for the no button', :cancel => 'text for the cancel button') == :yes)
34
75
  # they chose the "yes" equivalent button...
35
76
  end
36
77
 
37
78
  etc. ...
38
79
 
39
- It provies a few helper methods to the ParseTemplate::JFramer (and JFrame) class, like:
80
+ It provies a few helper methods to the SimpleGuiCreator::ParseTemplate (and JFrame) classes, like:
40
81
 
41
82
  #bring_to_front
42
83
  #minimize
84
+ #maximize
43
85
  #restore
44
86
  #after_closed { ... }
45
87
  #after_minimized { ... }
46
88
 
47
- It has helpers to control/playback audio, like mp3's or wave's, starting/stopping asynchronously (see the files in the 'lib/ruby-easy-gui-creator' directory.
89
+ See the files lib/simple_gui_creator/swing_helpers.rb and lib/simple_gui_creator/jframe_helper_methods.rb.
90
+
91
+ It has helpers to playback/control audio files, like mp3's or wave's, starting/stopping asynchronously (see the files in the 'lib/simple_gui_creator/*' directory.
48
92
  It has helpers to set/get system clipboard contents.
49
- It has helpers to control/query the mouse (I use this, but don't know why anybody else ever would want to LOL).
93
+ It has helpers to control/query the system mouse.
50
94
  It has helpers to query the current system for its DVD drives, be notified when disks are inserted/changed, etc.
51
95
 
52
96
  Feedback/feature requests welcome.
53
97
  http://groups.google.com/group/roger-projects, roger-projects@googlegroups.com
54
- I'd even be happy to wrap other gui frameworks (currently jruby/swing only) with the same helper functions, if anybody wanted it.
55
-
56
- Enjoy!
57
-
58
- To install/use:
59
-
60
- $ gem install simple-ruby-gui-creator
61
-
62
- >> require 'simple_gui_creator'
63
- >> ... [see other examples]
98
+ I'd even be happy to wrap other gui frameworks (currently jruby/swing only) with the same functionality,
99
+ if anybody wanted it.
64
100
 
65
101
  == GUI Editor ==
66
102
 
67
103
  It also comes with its own "test as you go" design builder helper GUI, programmed, appropriately enough, using simple gui creator.
68
104
  $ jruby -S simple_gui_creator
69
105
 
70
- This pulls up a window with some demo code, and some links that let you save it. It's almost more of a "demo of how it works" than a
106
+ This pulls up a window with some demo code, and some links that let you save it.
107
+ It's almost more of a "demo of how using it looks like" (the bin/simple_gui_creator file) than a
71
108
  real editing tool, but feature requests/suggestions wanted!
72
109
 
73
110
  == Documentation ==
74
111
 
75
- Basically, see this file, the examples folder, the "bin/*" files, and also the specs and lib files themselves.
112
+ Basically, see this README file, the examples folder, the "bin/*" file, and also the specs and lib files themselves.
76
113
  https://github.com/rdp/ruby_simple_gui_creator
77
114
 
78
115
  == Known problems ==
79
116
 
80
- Only allows single element types per line currently, like "all text" or "all buttons", but I'm working on it :)
81
- Only Jruby today, which can make loading time painful (hint: use splash screen).
117
+ Only Jruby today, which can make load times painful (hint: use splash screen).
118
+
119
+ = License ==
120
+
121
+ MIT license (which is quite open), see accompanying file license.mit.txt.
122
+ (C) 2012 Roger Pack
data/Rakefile CHANGED
@@ -10,6 +10,7 @@ Jeweler::Tasks.new do |gem|
10
10
  gem.homepage = "https://github.com/rdp/ruby_simple_gui_creator"
11
11
  gem.authors = ["rogerdpack"]
12
12
  gem.add_dependency 'sane'
13
+ gem.add_dependency 'andand'
13
14
  # gem.add_dependency 'launchy'
14
15
  end
15
16
 
data/TODO CHANGED
@@ -1,12 +1,33 @@
1
- if the window goes too low, they can't see it all?
1
+ see spec/parse_template.spec.rb for another (the real) TODO list
2
2
 
3
- gets h,w of trivial text areas *wrong* oh so wrong
3
+ = maybe =
4
+
5
+ # LODO allow internal sub-boxes LOL
6
+ # LODO should pass the button through to on_clicked [?] or button with frame, too?
7
+ # LODO should be able to clear everything a button does or used to do...
8
+ # LODO a 'title managing' object LOL
9
+ # LODO rel_width=+100 or some odd
10
+ # LODO real documentation LOL
11
+ # buttons should require a code name :P
12
+
13
+ if the window goes too low, they can't see it all, and it doesn't scroll?
14
+
15
+
16
+ use native file handlers, the swing ones shuck with default save filenames
4
17
 
5
18
  = never =
6
19
 
7
- Parsing failed on line " _ _\t \n" number: 5!
20
+ HTML linked version. what the woot! LOL.
21
+ serialize the object...to RAM for now LOL.
22
+ pull the object from a db based on ID
23
+ instance_exec the [saved in RAM] proc
24
+ this would mean you can never "wildly redefine" action for pages though clicks...hmm...
25
+ or you could just pass "self" through...hmm...
26
+ whatever would be first pass ideal, just make that happen
27
+
28
+ fix: Parsing failed on line " _ _\t \n" number: 5!
8
29
 
9
- use launchy for url's in linux [?]
30
+ use launchy for at least url's in linux
10
31
 
11
32
  ask_should_allow_on_minimize {
12
33
  }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.2.0
@@ -1,11 +1,13 @@
1
+ # encoding: UTF-8
1
2
  require 'java'
3
+ require 'andand'
2
4
 
3
5
  require File.dirname(__FILE__) + '/swing_helpers.rb' # for JButton#on_clicked, etc.,
4
6
 
5
7
  # for documentation, see the README file
6
8
  module SimpleGuiCreator
7
9
 
8
- include_package 'javax.swing'; [JFrame, JPanel, JButton, JTextArea, JLabel, UIManager, JScrollPane]
10
+ include_package 'javax.swing'; [JFrame, JPanel, JButton, JTextArea, JLabel, UIManager, JScrollPane, JCheckBox, JComboBox]
9
11
  java_import java.awt.Font
10
12
 
11
13
  class ParseTemplate < JFrame
@@ -16,193 +18,230 @@ module SimpleGuiCreator
16
18
  @elements = {}
17
19
  @panel.set_layout nil
18
20
  add @panel # why can't I just slap these down? panel? huh?
19
- show # this always bites me...I new it up an it just doesn't appear...
20
- end
21
-
22
- attr_reader :panel
23
- attr_reader :elements
24
- attr_accessor :original_title
25
- attr_accessor :frame
26
-
21
+ show # this always bites me...I new it up an it just doesn't appear...
22
+ end
23
+
24
+ attr_reader :panel
25
+ attr_reader :elements
26
+ attr_accessor :original_title
27
+ attr_accessor :frame
28
+
27
29
  def parse_setup_filename filename
28
30
  parse_setup_string File.read(filename)
29
- self
31
+ self
30
32
  end
31
33
 
32
34
  # "matches" whatever the template string looks like...
33
35
  def parse_setup_string string
34
36
  @frame = self # LODO refactor
35
- @current_y = 10
36
- @window_max_x = 100
37
- all_lines = string.lines.to_a
37
+ @current_y = 10
38
+ @window_max_x = 100
39
+ all_lines = string.lines.to_a
38
40
  all_lines.each_with_index{|line, idx|
39
- begin
40
- @current_x = 10
41
- if line =~ /\t/
42
- raise "sorry, tabs arent allowed, but you can request it"
43
- end
44
- button_line_regex = /\[(.*?)\]/
45
- #>> "| [Setup Preferences:preferences] [Start:start] [Stop:stop] |" .scan button_line_regex
46
- #=> [["Setup Preferences:preferences"], ["Start:start"], ["Stop:stop"]]
47
-
48
- text_regex = /"([^"]+)"/ # "some text:name"
49
- blank_line_regex = /^\s*(|\|)\s+(|\|)\s*$/ # " | | " or just empty...
50
- title_regex = /\s*[-]+([\w ]+)[-]+\s*$/ # ----(a Title)---
51
- @current_line_height = 25
52
-
53
- if line =~ title_regex
54
- @frame.set_title $1 # done :)
55
- @frame.original_title = $1.dup.freeze # freeze...LOL
56
- elsif line =~ blank_line_regex
57
- @current_y += @current_line_height
58
- elsif line =~ button_line_regex
59
- # button, or TextArea
60
- cur_x = 0
61
- while cur_spot = (line[cur_x..-1] =~ button_line_regex)
62
- cur_spot += cur_x# we had only acted on a partial line, above, so add in the part we didn't do
63
- name = $1
64
- end_spot = cur_spot + name.length
65
- count_lines_below = 0
66
- matching_blank_text_area_string = '[' + ' '*(end_spot-cur_spot) + ']'
67
- empty_it_out = matching_blank_text_area_string.gsub(/[\[\]]/, '_') # can't actually blank it out...
68
- for line2 in all_lines[idx+1..-1]
69
- if line2[cur_spot..(end_spot+1)] == matching_blank_text_area_string
70
- line2[cur_spot, end_spot-cur_spot+2] = empty_it_out # :)
71
- count_lines_below += 1
72
- else
73
- break
74
- end
75
- end
76
- if count_lines_below > 0
77
- rows = count_lines_below + 1
78
- text_area = JTextArea.new(rows, name.split(':')[0].length)
79
- text_area.text="\n"*rows
80
- # width?
81
- scrollPane = JScrollPane.new(text_area)
82
- setup_element(scrollPane, name, scrollPane.getPreferredSize.height, text_area)
83
- else
84
- button = JButton.new
85
- setup_element(button, name)
86
- end
87
- cur_x = end_spot # creep forward within this line...
88
- end
89
- @current_y += @current_line_height
90
- elsif line =~ text_regex
91
- for name in line.scan(text_regex)
92
- label = JLabel.new
93
- setup_element(label, name[0])
94
- end
95
- @current_y += @current_line_height
96
- end
97
- # build in realtime LOL
98
- @frame.set_size @window_max_x + 25, @current_y + 40
99
- rescue
100
- puts "Parsing failed on line #{line.inspect} number: #{idx+1}!"
101
- raise
102
- end
103
- }
41
+ begin
42
+ @current_x = 10
43
+ if line =~ /\t/
44
+ raise "sorry, tabs arent allowed, but you can request it"
45
+ end
46
+ button_line_regex = /\[(.*?)\]/
47
+ #>> "| [Setup Preferences:preferences] [Start:start] [Stop:stop] |" .scan button_line_regex
48
+ #=> [["Setup Preferences:preferences"], ["Start:start"], ["Stop:stop"]]
49
+
50
+ text_regex = /"([^"]+)"/ # "some text:name"
51
+ blank_line_regex = /^\s*(|\|)\s+(|\|)\s*$/ # matches " | | " or just empty...
52
+ title_regex = /\s*[-]+([\w ]+)[-]+\s*$/ # ----(a Title)---
53
+ @current_line_height = 25
54
+
55
+ if line =~ title_regex
56
+ @frame.set_title $1 # done :)
57
+ @frame.original_title = $1.dup.freeze # freeze...LOL
58
+ elsif line =~ blank_line_regex
59
+ @current_y += @current_line_height
60
+ else
61
+ # attempt an element line
62
+ cur_x = 0
63
+ while next_match = closest_next_regex_match([button_line_regex, text_regex], line[cur_x..-1])
64
+ cur_spot = line[cur_x..-1] =~ next_match
65
+ cur_spot += cur_x # we had only acted on a partial line, above, so add in the part we didn't do, to get the right offset number
66
+ captured = $1
67
+ end_spot = cur_spot + captured.length
68
+ if next_match == button_line_regex
69
+ handle_button_at_current captured, cur_spot, end_spot, all_lines, idx
70
+ elsif next_match == text_regex
71
+ label = JLabel.new
72
+ setup_element(label, captured)
73
+ end
74
+ cur_x = end_spot
75
+ end
76
+ @current_y += @current_line_height
77
+ end
78
+
79
+ # build in realtime LOL
80
+ @frame.set_size @window_max_x + 25, @current_y + 40
81
+ rescue
82
+ puts "Parsing failed on line #{line.inspect} number: #{idx+1}!"
83
+ raise
84
+ end
85
+ }
104
86
  self
105
87
  end
106
88
 
107
89
  private
108
90
 
91
+ def closest_next_regex_match options, line
92
+ mapped = options.map{|option| line =~ option}
93
+ best = 10000
94
+ mapped.each{|number| best = [best, number].min if number}
95
+ if best == 10000
96
+ return nil
97
+ else
98
+ return options[mapped.index(best)] # yikes that was hard
99
+ end
100
+ end
101
+
102
+ def handle_button_at_current captured, cur_spot, end_spot, all_lines, idx
103
+ count_lines_below = 0
104
+ matching_blank_text_area_string = '[' + ' '*(end_spot-cur_spot) + ']'
105
+ empty_it_out = matching_blank_text_area_string.gsub(/[\[]/, '_') # can't actually remove it...
106
+ for line2 in all_lines[idx+1..-1]
107
+ if line2[cur_spot..(end_spot+1)] == matching_blank_text_area_string
108
+ line2[cur_spot, end_spot-cur_spot+2] = empty_it_out # :)
109
+ count_lines_below += 1
110
+ else
111
+ break
112
+ end
113
+ end
114
+ text, code_name_with_attrs = split_int_text_name_and_code captured
115
+ text.strip! # hope we don't care for buttons...for now...
116
+ if count_lines_below > 0
117
+ rows = count_lines_below + 1 # at least 2...
118
+ text_area = JTextArea.new(rows, captured.split(':')[0].length)
119
+ text_area.text="\n"*rows
120
+ # width?
121
+ scrollPane = JScrollPane.new(text_area)
122
+ setup_element(scrollPane, captured, scrollPane.getPreferredSize.height, text_area)
123
+ elsif text == "✓"
124
+ check_box = JCheckBox.new
125
+ setup_element(check_box, ':' + code_name_with_attrs, nil, check_box, check_box.getPreferredSize.width)
126
+ elsif text.end_with?("\\/") || text.end_with?("▼") # dropdowns
127
+ drop_down = JComboBox.new
128
+ if text.end_with?("▼")
129
+ initial_value = text = text.gsub(/▼$/, '')
130
+ else
131
+ initial_value = text[0..-3].strip
132
+ end
133
+ if initial_value.present?
134
+ drop_down.add_item initial_value.strip # set the top line as default
135
+ end
136
+ setup_element drop_down, ':' + code_name_with_attrs, nil, drop_down, drop_down.getPreferredSize.width
137
+ else
138
+ # a "normal" button
139
+ button = JButton.new
140
+ setup_element(button, captured)
141
+ end
142
+ end
143
+
109
144
  def get_text_width text
110
145
  get_text_dimentia(text).width
111
146
  end
112
147
 
113
148
  def get_text_dimentia text
114
- font = UIManager.getFont("Label.font")
149
+ font = UIManager.getFont("Label.font")
115
150
  frc = java.awt.font.FontRenderContext.new(font.transform, true, true)
116
151
  textLayout = java.awt.font.TextLayout.new(text, font, frc)
117
152
  textLayout.bounds # has #height and #width
118
153
  end
119
154
 
120
- def setup_element element, name, height=nil, set_text_on_this = element
121
- abs_x = nil
122
- abs_y = nil
123
- #height = nil
124
- width = nil
125
- if name.include?(':') && !name.end_with?(':') # like "Start:start_button" or "start:button:code_name,attribs" but not "Hello:" let that through
126
- text = name.split(':')[0..-2].join(':') # only accept last colon, so they can have text with colons in it
127
- code_name_with_attrs = name.split(':')[-1]
128
- if code_name_with_attrs.split(',')[0] !~ /=/
129
- # like code_name,width=250,x=y
130
- code_name, *attributes = code_name_with_attrs.split(',')
131
- else
132
- code_name = nil
133
- attributes = code_name_with_attrs.split(',')
134
- end
135
- attributes_hashed = {}
136
- attributes.each{|attr|
137
- key, value = attr.split('=')
138
- attributes_hashed[key.strip] = value.strip
139
- }
140
- if type = attributes_hashed.delete('font')
141
- if type == "fixed_width"
142
- set_text_on_this.font=Font.new("Monospaced", Font::PLAIN, 14)
143
- else
144
- raise "all we support is fixed_width font as of yet #{type} #{name}"
145
- end
146
- end
147
-
148
- for name in ['abs_x', 'abs_y', 'width', 'height']
149
- var = attributes_hashed.delete(name)
150
- if var
151
- if var =~ /chars$/
152
- count = var[0..-5].to_i
153
- var = get_text_width('m'*count) # TODO fails for height 30chars
154
- elsif var =~ /px$/
155
- var = var[0..-3].to_i
156
- else
157
- #raise "need to specify like 10px #{var} #{name}"
158
- var = var.to_i # allow it to be clean :P
159
- end
160
- raise "#{var} has value of zero?" if var == 0
161
- eval("#{name} = #{var}") # ugh
162
- end
163
- end
164
- raise "unknown attributes found: #{attributes_hashed.keys.inspect} #{attributes_hashed.inspect} #{code_name}" if attributes_hashed.length > 0
165
- else
166
- # no code name
167
- text = name
168
- end
169
- if !width
170
- if text.blank?
171
- raise 'cannot have blank original text without some size specifier:' + name
172
- end
173
- if text.strip != text
174
- # let blank space count as "space" for now, but don't actually set it LOL
175
- # is this good for variable spaced fonts, though?
176
- width = get_text_width("|" + text + "|") + 35
177
- text.strip!
178
- else
155
+ def split_int_text_name_and_code name_and_code
156
+ if name_and_code.include?(':') && !name_and_code.end_with?(':') # like "Start:start_button" or "start:button:code_name,attribs" but not "Hello:" let that through
157
+ text = name_and_code.split(':')[0..-2].join(':') # only accept last colon, so they can have text with colons in it
158
+ code_name_with_attrs = name_and_code.split(':')[-1]
159
+ [text, code_name_with_attrs]
160
+ else
161
+ [name_and_code, nil]
162
+ end
163
+ end
164
+
165
+ def setup_element element, name_and_code, height=nil, set_text_on_this = element, width=nil
166
+ abs_x = nil
167
+ abs_y = nil
168
+ text, code_name_with_attrs = split_int_text_name_and_code name_and_code
169
+ if code_name_with_attrs
170
+ # extract attributes
171
+ if code_name_with_attrs.split(',')[0] !~ /=/
172
+ # then like code_name,width=250,x=y
173
+ code_name, *attributes = code_name_with_attrs.split(',')
174
+ else
175
+ code_name = nil
176
+ attributes = code_name_with_attrs.split(',')
177
+ end
178
+ attributes_hashed = {}
179
+ attributes.each{|attr|
180
+ key, value = attr.split('=')
181
+ attributes_hashed[key.strip] = value.strip
182
+ }
183
+ if type = attributes_hashed.delete('font')
184
+ if type == "fixed_width"
185
+ set_text_on_this.font = Font.new("Monospaced", Font::PLAIN, 14)
186
+ else
187
+ raise "all we support is fixed_width font as of yet #{type} #{name_and_code}"
188
+ end
189
+ end
190
+
191
+ for name2 in ['abs_x', 'abs_y', 'width', 'height']
192
+ var = attributes_hashed.delete(name2)
193
+ if var
194
+ if var =~ /chars$/
195
+ count = var[0..-5].to_i
196
+ var = get_text_width('m'*count) # TODO fails for height 30chars
197
+ elsif var =~ /px$/
198
+ var = var[0..-3].to_i
199
+ else
200
+ var = var.to_i # allow it to be clean :P
201
+ end
202
+ raise "#{var} has value of zero?" if var == 0
203
+ eval("#{name2} = #{var}") # ugh
204
+ end
205
+ end
206
+ raise "unknown attributes found: #{attributes_hashed.keys.inspect} #{attributes_hashed.inspect} #{code_name} #{name_and_code}" if attributes_hashed.length > 0
207
+ end
208
+ if !width
209
+ if text.blank?
210
+ raise 'cannot have blank original text without width specifier:' + name
211
+ end
212
+ if text.strip != text
213
+ # let blank space count as "space" for now, but don't actually set it LOL
214
+ # is this good for variable spaced fonts, though?
215
+ width = get_text_width("|" + text + "|") + 35
216
+ text.strip!
217
+ else
179
218
  width = get_text_width(text) + 35
180
- end
181
- end
182
- set_text_on_this.text=text
183
- abs_x ||= @current_x
184
- abs_y ||= @current_y
185
- height ||= 20
186
- element.set_bounds(abs_x, abs_y, width, height)
219
+ end
220
+ end
221
+ set_text_on_this.text=text if text.present?
222
+ abs_x ||= @current_x
223
+ abs_y ||= @current_y
224
+ height ||= 20
225
+ element.set_bounds(abs_x, abs_y, width, height)
187
226
  @frame.panel.add element
188
- if code_name
189
- code_name.rstrip!
190
- raise "double name not allowed #{name} #{code_name}" if @frame.elements[code_name.to_sym]
227
+ if code_name
228
+ code_name.strip!
229
+ raise "double name not allowed #{name} #{code_name}" if @frame.elements[code_name.to_sym]
191
230
  @frame.elements[code_name.to_sym] = set_text_on_this # just symbol access for now...
192
- end
193
- @current_x = [@current_x, abs_x + width + 5].max
194
- @current_line_height = [@current_line_height, (abs_y + height + 5)-@current_y].max # LODO + 5 magic number? 25 - 20 hard coded? hmm...
195
-
196
- @window_max_x = [@window_max_x, @current_x].max # have to track x, but not y
231
+ end
232
+ @current_x = [@current_x, abs_x + width + 5].max
233
+ @current_line_height = [@current_line_height, (abs_y + height + 5)-@current_y].max # LODO + 5 magic number? 25 - 20 hard coded? hmm...
234
+
235
+ @window_max_x = [@window_max_x, @current_x].max # have to track x, but not y
197
236
  end
198
237
 
199
238
  end
200
239
 
201
240
  private
202
241
  def _dgb
203
- require 'rubygems'
204
- require 'ruby-debug'
205
- debugger
242
+ require 'rubygems'
243
+ require 'ruby-debug'
244
+ debugger
206
245
  end
207
246
 
208
247
  end
@@ -6,7 +6,7 @@ module SimpleGuiCreator
6
6
  include_package 'javax.swing'
7
7
  # and use these constants (bug: http://jira.codehaus.org/browse/JRUBY-5107)
8
8
  [JProgressBar, JButton, JLabel, JPanel, JOptionPane,
9
- JFileChooser, JComboBox, JDialog, SwingUtilities, JSlider, JPasswordField, UIManager]
9
+ JFileChooser, JComboBox, JDialog, SwingUtilities, JSlider, JPasswordField, JCheckBox, UIManager]
10
10
 
11
11
  include_package 'java.awt'; [Font, FileDialog]
12
12
 
@@ -174,6 +174,19 @@ module SimpleGuiCreator
174
174
  alias close dispose # yikes
175
175
  end
176
176
 
177
+ class JComboBox
178
+ def on_select_new_element &block
179
+ add_item_listener { |e|
180
+ block.call(get_item_at(get_selected_index), get_selected_index)
181
+ }
182
+ end
183
+
184
+ def add_items items
185
+ for item in items
186
+ add_item item
187
+ end
188
+ end
189
+ end
177
190
 
178
191
  class DropDownSelector < JDialog # JDialog is blocking...
179
192
 
@@ -193,8 +206,8 @@ module SimpleGuiCreator
193
206
  end
194
207
 
195
208
  box.add_item @prompt = prompt_for_top_entry # put something in index 0
196
- options_array.each{|drive|
197
- box.add_item drive
209
+ options_array.each{|option|
210
+ box.add_item option
198
211
  }
199
212
  add box
200
213
  pack # how do you get this arbitrary size? what the...
@@ -218,4 +231,23 @@ module SimpleGuiCreator
218
231
 
219
232
  end
220
233
 
221
- end
234
+ class JCheckBox
235
+
236
+ def after_checked &block
237
+ add_action_listener {
238
+ if isSelected # they just 'added' a check mark
239
+ block.call
240
+ end
241
+ }
242
+ end
243
+
244
+ def after_unchecked &block
245
+ add_action_listener {
246
+ if !isSelected # they just "unchecked" it
247
+ block.call
248
+ end
249
+ }
250
+ end
251
+ end
252
+
253
+ end
@@ -0,0 +1,19 @@
1
+ Copyright (c) <year> <copyright holders>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -1,25 +1,26 @@
1
+ # encoding: UTF-8
1
2
  require File.dirname(__FILE__)+ '/common'
2
3
 
3
- describe ParseTemplate do
4
+ describe SimpleGuiCreator::ParseTemplate do
4
5
 
5
6
  def parse_string string
6
7
  @frame = SimpleGuiCreator::ParseTemplate.new
7
- @frame.parse_setup_string(string)
8
- @frame
8
+ @frame.parse_setup_string(string)
9
+ @frame
9
10
  end
10
11
 
11
12
  after do
12
13
  @frame.close if @frame
13
14
  end
14
15
 
15
- it "should parse titles" do
16
+ it "should parse title lines" do
16
17
  frame = parse_string " ------------A Title-------------------------------------------"
17
- frame.title.should == "A Title"
18
- frame.get_title.should == "A Title" # java method mapping :)
19
- frame.original_title.should == "A Title"
20
- frame.title= 'new title'
21
- frame.get_title.should == "new title"
22
- frame.original_title.should == "A Title"
18
+ frame.title.should == "A Title"
19
+ frame.get_title.should == "A Title" # java method mapping :)
20
+ frame.original_title.should == "A Title"
21
+ frame.title= 'new title'
22
+ frame.get_title.should == "new title"
23
+ frame.original_title.should == "A Title"
23
24
  end
24
25
 
25
26
  it "should parse button only lines, with several buttons same line" do
@@ -39,14 +40,23 @@ describe ParseTemplate do
39
40
  frame.get_size.width.should be > 0
40
41
  end
41
42
 
42
- # it "should parse drop down lines"
43
- # frame = parse_string "| [some dropdown lines:dropdowns \/] |"
44
- # end
43
+ it "should parse drop down lines" do
44
+ for string in ["[some dropdown lines \\/:dropdown_name]", "[some dropdown lines \\/ : dropdown_name]", "[some dropdown lines\\/: dropdown_name]", "[some dropdown lines ▼ : dropdown_name]"]
45
+ frame = parse_string string
46
+ frame.elements[:dropdown_name].class.should == Java::JavaxSwing::JComboBox
47
+ frame.elements[:dropdown_name].add_items ['a', 'b', 'c']
48
+ frame.elements[:dropdown_name].get_item_at(0).should == 'some dropdown lines'
49
+ frame.elements[:dropdown_name].on_select_new_element{|element, idx| p element, idx} # seems to work...
50
+ frame.close
51
+ end
52
+ frame = parse_string "[\\/:dropdown_name]"
53
+ frame.elements[:dropdown_name].get_item_at(0).should be_nil
54
+ end
45
55
 
46
56
  it "should parse text strings" do
47
57
  frame = parse_string '| "Temp Dir location:temp_dir" |'
48
- assert frame.elements.length == 1
49
- frame.elements[:temp_dir].should_not be nil
58
+ assert frame.elements.length == 1
59
+ frame.elements[:temp_dir].should_not be nil
50
60
  end
51
61
 
52
62
  it "should handle a string below buttons" do
@@ -61,7 +71,7 @@ describe ParseTemplate do
61
71
 
62
72
  it "should split escaped colons" do
63
73
  frame = parse_string "| \"some stuff ::my_name\""
64
- frame.elements[:my_name].text.should == 'some stuff :'
74
+ frame.elements[:my_name].text.should == 'some stuff :'
65
75
  end
66
76
 
67
77
  it "should not accept zero length strings without width spec" do
@@ -70,7 +80,7 @@ describe ParseTemplate do
70
80
 
71
81
  it "should accept zero length strings if they have a width spec" do
72
82
  frame = parse_string "| \":my_name,width=250\""
73
- frame.elements[:my_name].text.should == ''
83
+ frame.elements[:my_name].text.should == ''
74
84
  end
75
85
 
76
86
  it "should not add codeless items to elements" do
@@ -82,16 +92,20 @@ describe ParseTemplate do
82
92
  proc { parse_string " \" text:name,fake=fake \" "}.should raise_exception
83
93
  end
84
94
 
85
- # LODO allow internal sub-boxes LOL
86
- # TODO mixeds on the same line
87
- # LODO should pass the button through to on_clicked [?] or button with frame, too?
88
- # LODO should be able to clear everything a button does or used to do...
89
- # LODO a 'title managing' object LOL
90
- # LODO rel_width=+100 or some odd
91
- # buttons should require a code name :P
95
+ it "should allow mixed on the same line" do
96
+ frame = parse_string %! "text:text", [button:button] !
97
+ frame.elements.size.should == 2
98
+ frame.elements[:button].should_not be_nil
99
+ frame.elements[:text].should_not be_nil
100
+ end
101
+
102
+ # LODO gets h,w of trivial text areas *wrong* oh so wrong
103
+ # TODO you can line up stuff to get start coords for everything
104
+ # end sizes
92
105
  # allow prepropagation of textareas, for easier width detection...and/or separating out concerns...hmm...
106
+ # YAML-possible for the layout, in a separate file. Then it's still semi-separated LOL
93
107
  # parse_setup_string string, :text_area_to_use_text => string
94
- # parse_setup_string :default_font =>
108
+ # Make a GUI editor for editing YAML
95
109
 
96
110
  it "should accept height, width, abs_x, abs_y" do
97
111
  frame = parse_string ' [a:my_name,abs_x=1,abs_y=2,width=100,height=101] '
@@ -152,7 +166,15 @@ describe ParseTemplate do
152
166
  frame = parse_string string
153
167
  frame.elements[:text_area].class.should == Java::JavaxSwing::JTextArea
154
168
  frame.elements.length.should == 1 # not create fake empty buttons underneath :)
155
- get_dimentia(frame.elements[:text_area]).should == [0, 0, 32, 319]# it's "sub-contained" in a jscrollpane <sigh>
169
+ text_area_dimentia(frame.elements[:text_area]).should == [0, 0, 32, 319] # it's "sub-contained" in a jscrollpane so these numbers are relative to that <sigh>
170
+ end
171
+
172
+ def text_area_dimentia(element)
173
+ while(get_dimentia(element) == [0,0,0,0])
174
+ puts 'weird TextArea 0,0,0,0'
175
+ sleep 0.2
176
+ end
177
+ get_dimentia(element)
156
178
  end
157
179
 
158
180
  it "should let you use ending colons" do
@@ -166,7 +188,19 @@ describe ParseTemplate do
166
188
  get_dimentia(frame.elements[:text])[3].should == 200
167
189
  end
168
190
 
169
- it "should parse text areas that aren't first, also one right next to it both sides"
191
+ it "should allow for non symbol names" do
192
+ frame = parse_string "[button : button]"
193
+ frame.elements[:button].should_not be_nil
194
+ end
195
+
196
+ it "should parse text areas that aren't first, also one right next to it both sides" do
197
+ frame = parse_string <<-EOL
198
+ [button : button][textare : textarea]
199
+ [ ]
200
+ EOL
201
+ text_area_dimentia(frame.elements[:textarea]).should == [0, 0, 32, 88]
202
+
203
+ end
170
204
 
171
205
  it "should allow for blank lines to mean spacing" do
172
206
  frame = parse_string "| [ a button] |\n [ a button] \n[ a button]"
@@ -175,5 +209,16 @@ describe ParseTemplate do
175
209
  frame = parse_string "| [ a button] |\n [ a button] \n[ a button]\n| |"
176
210
  frame.size.height.should == 150
177
211
  end
212
+
213
+ it "should allow for checkboxes" do
214
+ for string in ["[✓:checkbox_name]", "[✓ : checkbox_name]", "[_:checkbox_name"] # UTF-8 <sigh>
215
+ f = parse_string string
216
+ f.elements[:checkbox_name].get_text.should == ""
217
+ f.elements[:checkbox_name].class.should == Java::JavaxSwing::JCheckBox
218
+ f.elements[:checkbox_name].after_checked { puts 'checked!' }
219
+ f.elements[:checkbox_name].after_unchecked { puts 'unchecked!' }
220
+ f.close
221
+ end
222
+ end
178
223
 
179
224
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: simple_gui_creator
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.4
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - rogerdpack
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-06-22 00:00:00 Z
13
+ date: 2012-06-29 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sane
@@ -24,7 +24,7 @@ dependencies:
24
24
  type: :runtime
25
25
  version_requirements: *id001
26
26
  - !ruby/object:Gem::Dependency
27
- name: sane
27
+ name: andand
28
28
  prerelease: false
29
29
  requirement: &id002 !ruby/object:Gem::Requirement
30
30
  none: false
@@ -34,6 +34,28 @@ dependencies:
34
34
  version: "0"
35
35
  type: :runtime
36
36
  version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: sane
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: andand
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :runtime
58
+ version_requirements: *id004
37
59
  description: Framework to ease in creation of ruby GUI apps. Makes designing windows a snap.
38
60
  email: rogerdpack@gmail.com
39
61
  executables:
@@ -44,6 +66,7 @@ extra_rdoc_files:
44
66
  - ChangeLog
45
67
  - README
46
68
  - TODO
69
+ - license.mit.txt
47
70
  files:
48
71
  - ChangeLog
49
72
  - README
@@ -64,6 +87,7 @@ files:
64
87
  - lib/simple_gui_creator/simple_gui_creator.rb
65
88
  - lib/simple_gui_creator/storage.rb
66
89
  - lib/simple_gui_creator/swing_helpers.rb
90
+ - license.mit.txt
67
91
  - spec/common.rb
68
92
  - spec/diesel.mp3
69
93
  - spec/drive_info.spec.rb