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 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
 
@@ -90,6 +90,7 @@ module EventConnector
90
90
  # end
91
91
  #
92
92
  def listen(evt, source = self, handler = nil, &block)
93
+ warn "listen is deprecated, use evt_xxx directly (#{caller[0]})"
93
94
 
94
95
  # get the WxWidget evt_xxx method that will be called for binding
95
96
  event = "evt_#{evt}"
@@ -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
- @current_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
71
- self.set_sizer(@current_sizer)
72
- @current_sizer
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
@@ -1,3 +1,3 @@
1
1
  module WxSugar
2
- VERSION = '0.1.17'
2
+ VERSION = '0.1.18'
3
3
  end
@@ -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
@@ -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.17
7
- date: 2007-09-11 00:00:00 +01:00
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: []