simple_gui_creator 0.1.4 → 0.2.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.
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