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 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: []