wx_sugar 0.1.17 → 0.1.18
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/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: []
|