wx_sugar 0.1.17 → 0.1.18
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/xrcise +128 -0
- data/lib/wx_sugar/delayed_constructors.rb +4 -0
- data/lib/wx_sugar/event_connector.rb +1 -0
- data/lib/wx_sugar/layout.rb +7 -5
- data/lib/wx_sugar/version.rb +1 -1
- data/lib/wx_sugar/xrc/outputter.rb +111 -0
- data/lib/wx_sugar/xrc/xml_class.rb +74 -0
- data/lib/wx_sugar/xrc/xml_resource.rb +19 -0
- data/lib/wx_sugar/xrc.rb +8 -0
- metadata +10 -4
data/bin/xrcise
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# == Synopsis
|
2
|
+
#
|
3
|
+
# xrc-tool : Generates ruby code from wxWidgets XML
|
4
|
+
#
|
5
|
+
# == Usage
|
6
|
+
#
|
7
|
+
# xrc-tool [OPTIONS] <FILE>
|
8
|
+
#
|
9
|
+
# == Arguments
|
10
|
+
#
|
11
|
+
# <FILE> should be a valid XRC file from where class definitions are
|
12
|
+
# extracted.
|
13
|
+
#
|
14
|
+
# == Options
|
15
|
+
#
|
16
|
+
# -a, --appname [NAME]
|
17
|
+
# Create a basic Wx::App wrapper to run a frame. Not valid if more
|
18
|
+
# than one frame is identified in this file
|
19
|
+
#
|
20
|
+
# -h, --help:
|
21
|
+
# Show this help
|
22
|
+
#
|
23
|
+
# -n, --namespace:
|
24
|
+
# Namespace module to wrap code in. If this is given, it will be
|
25
|
+
# used both to prefix generated subclasses, and extend subclassed
|
26
|
+
# controls contained in the windows.
|
27
|
+
#
|
28
|
+
# -o, --output:
|
29
|
+
# Location for generated code. If this is a file, write all the
|
30
|
+
# generated classes to this one file. If this is a directory, writes
|
31
|
+
# each class as a separate file in it.
|
32
|
+
#
|
33
|
+
|
34
|
+
require 'wx_sugar/xrc'
|
35
|
+
require 'getoptlong'
|
36
|
+
require 'rdoc/ri/ri_paths' # avoid a bug in Ruby 1.8.5 with rdoc/usage
|
37
|
+
require 'rdoc/usage'
|
38
|
+
|
39
|
+
# Hacked version of RDoc::usage that allows it to accept an argument
|
40
|
+
# specifying which file the usage comment source should be taken from;
|
41
|
+
# the standard version defaults to the main program file, and when
|
42
|
+
# installed via Rubygems, this points to the gem executable stub, which
|
43
|
+
# has not-very-enlightening comments
|
44
|
+
module RDoc
|
45
|
+
class << self
|
46
|
+
undef_method :usage
|
47
|
+
def usage(main_program_file = nil, exit_status = 0)
|
48
|
+
usage_no_exit(main_program_file)
|
49
|
+
exit(exit_status)
|
50
|
+
end
|
51
|
+
|
52
|
+
undef_method :usage_no_exit
|
53
|
+
def usage_no_exit(main_program_file = nil)
|
54
|
+
main_program_file ||= caller[-1].sub(/:\d+$/, '')
|
55
|
+
comment = File.open(main_program_file) do |file|
|
56
|
+
find_comment(file)
|
57
|
+
end
|
58
|
+
|
59
|
+
comment = comment.gsub(/^\s*#/, '')
|
60
|
+
|
61
|
+
markup = SM::SimpleMarkup.new
|
62
|
+
flow_convertor = SM::ToFlow.new
|
63
|
+
flow = markup.convert(comment, flow_convertor)
|
64
|
+
format = "plain"
|
65
|
+
|
66
|
+
options = RI::Options.instance
|
67
|
+
if args = ENV["RI"]
|
68
|
+
options.parse(args.split)
|
69
|
+
end
|
70
|
+
formatter = options.formatter.new(options, "")
|
71
|
+
formatter.display_flow(flow)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Back to the real program:
|
77
|
+
opts = GetoptLong.new( [ '--appname', '-a', GetoptLong::OPTIONAL_ARGUMENT ],
|
78
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
79
|
+
[ '--namespace', '-n', GetoptLong::REQUIRED_ARGUMENT ],
|
80
|
+
[ '--output', '-o', GetoptLong::REQUIRED_ARGUMENT ] )
|
81
|
+
|
82
|
+
options = {}
|
83
|
+
output = nil
|
84
|
+
|
85
|
+
opts.each do | opt, arg |
|
86
|
+
case opt
|
87
|
+
when '--help'
|
88
|
+
RDoc::usage(__FILE__)
|
89
|
+
when '--appname'
|
90
|
+
options[:app_name] = ( arg.empty? ? 'MyApp' : arg )
|
91
|
+
when '--namespace'
|
92
|
+
options[:namespace] = arg
|
93
|
+
when '--output'
|
94
|
+
output = arg
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
if ARGV.empty?
|
99
|
+
puts "Missing FILE argument (try --help)"
|
100
|
+
exit 1
|
101
|
+
end
|
102
|
+
|
103
|
+
xrc_file = ARGV.shift
|
104
|
+
|
105
|
+
|
106
|
+
resource = XRCResource.new(xrc_file)
|
107
|
+
if output
|
108
|
+
# Write to separate files in output directory
|
109
|
+
if File.directory?(output)
|
110
|
+
resource.classes.each do | kls |
|
111
|
+
outfile = File.join(output, "#{kls.sub_class.downcase}.rb")
|
112
|
+
File.open(outfile, 'w') do | f |
|
113
|
+
Outputter.new(kls, options).output(f)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
# Write all to one file
|
117
|
+
else
|
118
|
+
File.open(output, 'w') do | f |
|
119
|
+
resource.classes.each do | kls |
|
120
|
+
Outputter.new(kls, options).output(f)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
else
|
125
|
+
resource.classes.each do | kls |
|
126
|
+
Outputter.new(kls, options).output
|
127
|
+
end
|
128
|
+
end
|
@@ -15,6 +15,10 @@ win_classes.flatten.each do | klass |
|
|
15
15
|
# Returns a Proc object that when called with a single argument,
|
16
16
|
# +parent+, will return a new widget constructed according to +args+
|
17
17
|
def klass.[](*args)
|
18
|
+
# Deal with id parameter if none specified
|
19
|
+
if self.param_spec[0].name == :id and not args[0].kind_of?(Fixnum)
|
20
|
+
args.unshift(-1)
|
21
|
+
end
|
18
22
|
lambda { | parent | new(parent, *args) }
|
19
23
|
end
|
20
24
|
|
data/lib/wx_sugar/layout.rb
CHANGED
@@ -64,13 +64,15 @@ module Arranger
|
|
64
64
|
def current_sizer()
|
65
65
|
if @current_sizer
|
66
66
|
return @current_sizer
|
67
|
-
elsif sizer = self.get_sizer
|
68
|
-
return sizer
|
69
67
|
else
|
70
|
-
|
71
|
-
|
72
|
-
|
68
|
+
begin
|
69
|
+
return self.get_sizer
|
70
|
+
rescue RuntimeError
|
71
|
+
end
|
73
72
|
end
|
73
|
+
@current_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
74
|
+
self.set_sizer(@current_sizer)
|
75
|
+
@current_sizer
|
74
76
|
end
|
75
77
|
|
76
78
|
# Set the main or current sizer of this container window to be
|
data/lib/wx_sugar/version.rb
CHANGED
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
# Provides templated output of a Ruby subclass from an XRC specification
|
5
|
+
# of a ruby Frame, Dialog or Panel class.
|
6
|
+
class Outputter
|
7
|
+
# Valid options are :app_name and :module_name
|
8
|
+
attr_accessor :options, :klass
|
9
|
+
|
10
|
+
# Creates a new outputter from the XRCClass +xrc_class+
|
11
|
+
def initialize(xrc_class, options = {})
|
12
|
+
@klass = xrc_class
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
# Writes the ruby code to the file or stream +io+
|
17
|
+
def output(io = $stdout)
|
18
|
+
tpl = ERB.new(TEMPLATE)
|
19
|
+
io.puts( tpl.result(binding) )
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the fully-qualified (including module namespace prefix) for
|
23
|
+
# +name+.
|
24
|
+
def fq_name(name)
|
25
|
+
options[:namespace] ? "#{options[:namespace]}::#{name}" : name
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the options object
|
29
|
+
def opts
|
30
|
+
OpenStruct.new(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Utility function to format the attr_readers line so it doesn't wrap
|
34
|
+
# in editors
|
35
|
+
def clean_id_attr_readers(str, start_len = 15, one_per_line = false)
|
36
|
+
new_string = ''
|
37
|
+
|
38
|
+
if one_per_line
|
39
|
+
str.each(',') do | x |
|
40
|
+
new_string << x
|
41
|
+
new_string << "\n" + " " * (start_len-2)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
wanted_length = 72
|
45
|
+
current_line_length = start_len
|
46
|
+
str.each(',') do |x|
|
47
|
+
if (current_line_length + x.length) > wanted_length
|
48
|
+
new_string << "\n" + " " * (start_len-2)
|
49
|
+
current_line_length = start_len
|
50
|
+
end
|
51
|
+
new_string << x
|
52
|
+
current_line_length += x.length
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return new_string
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
Outputter::TEMPLATE = <<'TEMPLATE'
|
61
|
+
<% if opts.app_name %>
|
62
|
+
require 'wx'
|
63
|
+
<% if opts.namespace %>
|
64
|
+
module <%= opts.namespace %>
|
65
|
+
end
|
66
|
+
<% end %><% end %>
|
67
|
+
# This class was automatically generated from XRC source. It is not
|
68
|
+
# recommended that this file is edited directly; instead, inherit from
|
69
|
+
# this class and extend its behaviour there.
|
70
|
+
#
|
71
|
+
# Source file: <%= klass.file_name %>
|
72
|
+
# Generated at: <%= Time.now %>
|
73
|
+
|
74
|
+
class <%= fq_name(klass.sub_class) %> < <%= klass.superclass %>
|
75
|
+
<% if not klass.controls.empty? %><% ids = klass.controls.map { | ctrl | ":#{ctrl.name.downcase}" }.join(', ') %>
|
76
|
+
attr_reader <%= clean_id_attr_readers(ids) %>
|
77
|
+
<% end %>
|
78
|
+
def initialize(parent = nil)
|
79
|
+
super()
|
80
|
+
xml = Wx::XmlResource.get
|
81
|
+
xml.flags = 2 # Wx::XRC_NO_SUBCLASSING
|
82
|
+
xml.init_all_handlers
|
83
|
+
xml.load("<%= klass.file_name %>")
|
84
|
+
xml.<%= klass.load_func %>(self, parent, "<%= klass.base_id %>")
|
85
|
+
|
86
|
+
finder = lambda do | x |
|
87
|
+
int_id = Wx::xrcid(x)
|
88
|
+
begin
|
89
|
+
Wx::Window.find_window_by_id(int_id, self) || int_id
|
90
|
+
# Temporary hack to work around regression in 1.9.2; remove
|
91
|
+
# begin/rescue clause in later versions
|
92
|
+
rescue RuntimeError
|
93
|
+
int_id
|
94
|
+
end
|
95
|
+
end
|
96
|
+
<% klass.controls.each do | ctrl | %>
|
97
|
+
@<%= ctrl.name.downcase %> = finder.call("<%= ctrl.name %>")<% if ctrl.sub_class %>
|
98
|
+
@<%= ctrl.name.downcase %>.extend(<%= fq_name(ctrl.sub_class) %>)<% end %><% end %>
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
<% if opts.app_name %>
|
103
|
+
class <%= opts.app_name %> < Wx::App
|
104
|
+
def on_init
|
105
|
+
f = <%= opts.module_name %>::<%= fq_name(klass.sub_class) %>.new
|
106
|
+
f.show
|
107
|
+
end
|
108
|
+
end
|
109
|
+
<%= opts.app_name %>.new.main_loop
|
110
|
+
<% end %>
|
111
|
+
TEMPLATE
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Representation of a single GUI class defined in XRC. wxRuby permits
|
2
|
+
# subclasses of Frames, Dialog and Panels to be loaded from XRC.
|
3
|
+
class XRCClass
|
4
|
+
# Only these classes may be subclassed in Ruby
|
5
|
+
VALID_CLASSES = %|wxFrame wxDialog wxPanel|
|
6
|
+
|
7
|
+
# Simple struct to hold details of a individual named control
|
8
|
+
Control = Struct.new(:name, :sub_class)
|
9
|
+
|
10
|
+
# base_id : the Wx identifier of the main window
|
11
|
+
# wx_class : the Wx class which this window inherits from
|
12
|
+
# sub_class : the ruby class name of this window class
|
13
|
+
# controls : an array of identified controls within this window
|
14
|
+
# file_name : the XRC file from which this class can be loaded
|
15
|
+
attr_reader :base_id, :wx_class, :sub_class, :controls, :file_name
|
16
|
+
|
17
|
+
# Checks to see if a valid class can be created from +xml_elem+, and
|
18
|
+
# returns one if it can, or nil if it can't. To be a valid class, the
|
19
|
+
# window must inherit from Frame, Dialog or Window, and must define a
|
20
|
+
# subclass name.
|
21
|
+
def self.extract(xml_elem, xrc_file)
|
22
|
+
p_class = xml_elem.attributes['class']
|
23
|
+
if not VALID_CLASSES.include?(p_class)
|
24
|
+
warn "Cannot create wrapper for subclass of #{p_class}"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
if not xml_elem.attributes['subclass']
|
29
|
+
warn "Cannot create wrapper for class without 'subclass'
|
30
|
+
attribute"
|
31
|
+
return
|
32
|
+
end
|
33
|
+
new(xml_elem, xrc_file)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a new class from +xml_elem+
|
37
|
+
def initialize(xml_elem, xrc_file)
|
38
|
+
@xml_src = xml_elem
|
39
|
+
@file_name = xrc_file
|
40
|
+
|
41
|
+
@base_id = xml_elem.attributes['name']
|
42
|
+
@wx_class = xml_elem.attributes['class']
|
43
|
+
@sub_class = xml_elem.attributes['subclass']
|
44
|
+
@controls = []
|
45
|
+
read_controls
|
46
|
+
end
|
47
|
+
|
48
|
+
def superclass
|
49
|
+
wx_class.sub(/^wx/, "Wx::")
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_func
|
53
|
+
unadorned = wx_class.sub(/^wx/, '').downcase
|
54
|
+
"load_#{unadorned}_subclass"
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
# Scans the XRC definition of this class for named contained
|
59
|
+
# controls. Controls which are given a non-default name in the RAD
|
60
|
+
# tool are picked up, and will be given attribute readers in the Ruby
|
61
|
+
# class. Additionally, if a "subclass" attribute is specified for the
|
62
|
+
# control, the Ruby control will be extended with that class.
|
63
|
+
def read_controls
|
64
|
+
finder = "/resource/object[@name='#{base_id}']//*[@name]"
|
65
|
+
REXML::XPath.each(@xml_src, finder) do | elem |
|
66
|
+
ctrl_name = elem.attributes['name']
|
67
|
+
# skip default names
|
68
|
+
next if ctrl_name =~ /^wx/
|
69
|
+
next if ctrl_name =~ /^ID_/
|
70
|
+
ctrl_subclass = elem.attributes['subclass']
|
71
|
+
@controls << Control.new(ctrl_name, ctrl_subclass)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
# Parser for a complete wxWidgets XRC file. XRC files may contain one
|
3
|
+
# or more definitions of Wx Frames, Dialogs or Panels.
|
4
|
+
class XRCResource
|
5
|
+
attr_reader :xrc_file, :classes
|
6
|
+
|
7
|
+
# Read and seek for classes within the XML file +xrc_file+
|
8
|
+
def initialize(xrc_file)
|
9
|
+
@xrc_file = xrc_file
|
10
|
+
xml_content = File.read(xrc_file)
|
11
|
+
@xml_doc = REXML::Document.new(xml_content)
|
12
|
+
@classes = []
|
13
|
+
REXML::XPath.each(@xml_doc.root, "/resource/object") do | elem |
|
14
|
+
if xml_klass = XRCClass.extract(elem, @xrc_file)
|
15
|
+
@classes << xml_klass
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/wx_sugar/xrc.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# Tools for working with XRC via the xrcise script utility. These
|
2
|
+
# libraries are not intended to be used within an application; rather,
|
3
|
+
# they provide a framework for extracting class definitions from
|
4
|
+
# wxWidgets XML format, XRC, and creating ruby code that loads that XRC
|
5
|
+
|
6
|
+
require 'wx_sugar/xrc/xml_resource'
|
7
|
+
require 'wx_sugar/xrc/xml_class'
|
8
|
+
require 'wx_sugar/xrc/outputter'
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: wx_sugar
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.1.18
|
7
|
+
date: 2007-10-23 00:00:00 +01:00
|
8
8
|
summary: Syntax extensions for WxRuby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,9 +29,11 @@ post_install_message:
|
|
29
29
|
authors:
|
30
30
|
- Alex Fenton
|
31
31
|
files:
|
32
|
+
- bin/xrcise
|
32
33
|
- lib/wx_sugar
|
33
34
|
- lib/wx_sugar.rb
|
34
35
|
- lib/wx_sugar/wx_classes
|
36
|
+
- lib/wx_sugar/xrc
|
35
37
|
- lib/wx_sugar/layout.rb
|
36
38
|
- lib/wx_sugar/delayed_constructors.rb
|
37
39
|
- lib/wx_sugar/class_definitions.rb
|
@@ -41,6 +43,7 @@ files:
|
|
41
43
|
- lib/wx_sugar/itemdata.rb
|
42
44
|
- lib/wx_sugar/event_connector.rb
|
43
45
|
- lib/wx_sugar/wx_classes.rb
|
46
|
+
- lib/wx_sugar/xrc.rb
|
44
47
|
- lib/wx_sugar/version.rb
|
45
48
|
- lib/wx_sugar/wx_classes/listctrl.rb
|
46
49
|
- lib/wx_sugar/wx_classes/colour.rb
|
@@ -48,6 +51,9 @@ files:
|
|
48
51
|
- lib/wx_sugar/wx_classes/window.rb
|
49
52
|
- lib/wx_sugar/wx_classes/size.rb
|
50
53
|
- lib/wx_sugar/wx_classes/control_with_items.rb
|
54
|
+
- lib/wx_sugar/xrc/xml_class.rb
|
55
|
+
- lib/wx_sugar/xrc/xml_resource.rb
|
56
|
+
- lib/wx_sugar/xrc/outputter.rb
|
51
57
|
- samples/sugar-sample.rb
|
52
58
|
- LICENCE
|
53
59
|
test_files: []
|
@@ -56,8 +62,8 @@ rdoc_options: []
|
|
56
62
|
|
57
63
|
extra_rdoc_files: []
|
58
64
|
|
59
|
-
executables:
|
60
|
-
|
65
|
+
executables:
|
66
|
+
- xrcise
|
61
67
|
extensions: []
|
62
68
|
|
63
69
|
requirements: []
|