fxruby-enhancement 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.semver +6 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +131 -0
- data/LICENSE.txt +20 -0
- data/README.org +861 -0
- data/Rakefile +68 -0
- data/build/scrape-rdoc.rb +120 -0
- data/examples/.ruby-version +1 -0
- data/examples/bounce.rb +158 -0
- data/examples/hello.rb +33 -0
- data/fxruby-enhancement.gemspec +112 -0
- data/lib/fxruby-enhancement.rb +12 -0
- data/lib/fxruby-enhancement/api-mapper.rb +11034 -0
- data/lib/fxruby-enhancement/api-mapper.rb.erb +93 -0
- data/lib/fxruby-enhancement/core-monkey.rb +26 -0
- data/lib/fxruby-enhancement/enhancement.rb +145 -0
- data/lib/fxruby-enhancement/ostruct-monkey.rb +38 -0
- data/spec/fxruby-enhancement_spec.rb +57 -0
- data/spec/spec_helper.rb +19 -0
- metadata +319 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 815c35e0699b8a7cb0bc90b27f21789751af71fd
|
4
|
+
data.tar.gz: c9cc4a024a7493888bc3e27ec96a319e1b8a1a63
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e6d8150e9bb259e6bf9b12c63a1e874e6ebcc9ead1594cfc5cf0fd0f12d307e712bdfbe6cd92ba0ec68cfb98c8b0847ddc0430c63fe1337b0c756436a0ce304
|
7
|
+
data.tar.gz: 36efe40ce1f47ab9d7a4623ede142171856c4648e45ba1a7c51bdfb67151774d7d35c615c0d7b57fa833a8fd4f0167f3ff637ed3ae3288cd17fc60e1c9230a41
|
data/.document
ADDED
data/.gitmodules
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.0
|
data/.semver
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "semver2", "~> 3"
|
4
|
+
gem "fxruby", "~> 1.6"
|
5
|
+
gem "awesome_print", ">= 1"
|
6
|
+
gem "json", "~> 2.0", ">= 2.0.2"
|
7
|
+
gem "queue_ding", "~> 0"
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem "rspec", "~> 3"
|
11
|
+
gem "yard", "~> 0.7"
|
12
|
+
gem "rdoc", "~> 5"
|
13
|
+
gem "bundler", "~> 1.0"
|
14
|
+
gem "juwelier", "~> 2"
|
15
|
+
gem "simplecov", ">= 0"
|
16
|
+
gem "pry", ">= 0"
|
17
|
+
gem "pry-byebug", ">= 3"
|
18
|
+
gem "pry-doc", ">= 0"
|
19
|
+
gem "pry-remote", ">= 0"
|
20
|
+
gem "pry-rescue", ">= 1"
|
21
|
+
gem "pry-stack_explorer", ">= 0"
|
22
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.4.0)
|
5
|
+
aquarium (0.5.1)
|
6
|
+
awesome_print (1.7.0)
|
7
|
+
binding_of_caller (0.7.2)
|
8
|
+
debug_inspector (>= 0.0.1)
|
9
|
+
builder (3.2.2)
|
10
|
+
byebug (9.0.6)
|
11
|
+
coderay (1.1.1)
|
12
|
+
debug_inspector (0.0.2)
|
13
|
+
descendants_tracker (0.0.4)
|
14
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
15
|
+
diff-lcs (1.2.5)
|
16
|
+
docile (1.1.5)
|
17
|
+
faraday (0.9.2)
|
18
|
+
multipart-post (>= 1.2, < 3)
|
19
|
+
fxruby (1.6.34)
|
20
|
+
mini_portile (~> 0.6)
|
21
|
+
git (1.3.0)
|
22
|
+
github_api (0.14.5)
|
23
|
+
addressable (~> 2.4.0)
|
24
|
+
descendants_tracker (~> 0.0.4)
|
25
|
+
faraday (~> 0.8, < 0.10)
|
26
|
+
hashie (>= 3.4)
|
27
|
+
oauth2 (~> 1.0)
|
28
|
+
hashie (3.4.6)
|
29
|
+
highline (1.7.8)
|
30
|
+
interception (0.5)
|
31
|
+
json (2.0.2)
|
32
|
+
juwelier (2.3.4)
|
33
|
+
builder
|
34
|
+
bundler (>= 1.13)
|
35
|
+
git (>= 1.2.5)
|
36
|
+
github_api
|
37
|
+
highline (>= 1.6.15)
|
38
|
+
nokogiri (>= 1.5.10)
|
39
|
+
psych (~> 2.2)
|
40
|
+
rake
|
41
|
+
rdoc
|
42
|
+
semver2
|
43
|
+
jwt (1.5.6)
|
44
|
+
method_source (0.8.2)
|
45
|
+
mini_portile (0.6.2)
|
46
|
+
mini_portile2 (2.1.0)
|
47
|
+
multi_json (1.12.1)
|
48
|
+
multi_xml (0.6.0)
|
49
|
+
multipart-post (2.0.0)
|
50
|
+
nokogiri (1.7.0.1)
|
51
|
+
mini_portile2 (~> 2.1.0)
|
52
|
+
oauth2 (1.3.0)
|
53
|
+
faraday (>= 0.8, < 0.11)
|
54
|
+
jwt (~> 1.0)
|
55
|
+
multi_json (~> 1.3)
|
56
|
+
multi_xml (~> 0.5)
|
57
|
+
rack (>= 1.2, < 3)
|
58
|
+
pry (0.10.4)
|
59
|
+
coderay (~> 1.1.0)
|
60
|
+
method_source (~> 0.8.1)
|
61
|
+
slop (~> 3.4)
|
62
|
+
pry-byebug (3.4.2)
|
63
|
+
byebug (~> 9.0)
|
64
|
+
pry (~> 0.10)
|
65
|
+
pry-doc (0.10.0)
|
66
|
+
pry (~> 0.9)
|
67
|
+
yard (~> 0.9)
|
68
|
+
pry-remote (0.1.8)
|
69
|
+
pry (~> 0.9)
|
70
|
+
slop (~> 3.0)
|
71
|
+
pry-rescue (1.4.4)
|
72
|
+
interception (>= 0.5)
|
73
|
+
pry
|
74
|
+
pry-stack_explorer (0.4.9.2)
|
75
|
+
binding_of_caller (>= 0.7)
|
76
|
+
pry (>= 0.9.11)
|
77
|
+
psych (2.2.2)
|
78
|
+
queue_ding (0.1.5)
|
79
|
+
aquarium (~> 0)
|
80
|
+
json (~> 2.0, >= 2.0.2)
|
81
|
+
semver2 (~> 3)
|
82
|
+
rack (2.0.1)
|
83
|
+
rake (12.0.0)
|
84
|
+
rdoc (5.0.0)
|
85
|
+
rspec (3.5.0)
|
86
|
+
rspec-core (~> 3.5.0)
|
87
|
+
rspec-expectations (~> 3.5.0)
|
88
|
+
rspec-mocks (~> 3.5.0)
|
89
|
+
rspec-core (3.5.4)
|
90
|
+
rspec-support (~> 3.5.0)
|
91
|
+
rspec-expectations (3.5.0)
|
92
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
93
|
+
rspec-support (~> 3.5.0)
|
94
|
+
rspec-mocks (3.5.0)
|
95
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
96
|
+
rspec-support (~> 3.5.0)
|
97
|
+
rspec-support (3.5.0)
|
98
|
+
semver2 (3.4.2)
|
99
|
+
simplecov (0.12.0)
|
100
|
+
docile (~> 1.1.0)
|
101
|
+
json (>= 1.8, < 3)
|
102
|
+
simplecov-html (~> 0.10.0)
|
103
|
+
simplecov-html (0.10.0)
|
104
|
+
slop (3.6.0)
|
105
|
+
thread_safe (0.3.5)
|
106
|
+
yard (0.9.7)
|
107
|
+
|
108
|
+
PLATFORMS
|
109
|
+
ruby
|
110
|
+
|
111
|
+
DEPENDENCIES
|
112
|
+
awesome_print (>= 1)
|
113
|
+
bundler (~> 1.0)
|
114
|
+
fxruby (~> 1.6)
|
115
|
+
json (~> 2.0, >= 2.0.2)
|
116
|
+
juwelier (~> 2)
|
117
|
+
pry
|
118
|
+
pry-byebug (>= 3)
|
119
|
+
pry-doc
|
120
|
+
pry-remote
|
121
|
+
pry-rescue (>= 1)
|
122
|
+
pry-stack_explorer
|
123
|
+
queue_ding (~> 0)
|
124
|
+
rdoc (~> 5)
|
125
|
+
rspec (~> 3)
|
126
|
+
semver2 (~> 3)
|
127
|
+
simplecov
|
128
|
+
yard (~> 0.7)
|
129
|
+
|
130
|
+
BUNDLED WITH
|
131
|
+
1.13.6
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2016 Fred Mitchell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.org
ADDED
@@ -0,0 +1,861 @@
|
|
1
|
+
#+OPTIONS: broken-links:mark
|
2
|
+
* Table of Contents :TOC_5_gh:
|
3
|
+
- [[#fxruby-enhancement][fxruby-enhancement]]
|
4
|
+
- [[#introduction][Introduction]]
|
5
|
+
- [[#installation][Installation]]
|
6
|
+
- [[#documentation][Documentation]]
|
7
|
+
- [[#in-general][In General]]
|
8
|
+
- [[#execution-phases-of-fxruby-enhancement][Execution Phases of fxruby-enhancement]]
|
9
|
+
- [[#declarative][Declarative]]
|
10
|
+
- [[#fxruby-instantiation][FXRuby Instantiation]]
|
11
|
+
- [[#fox-toolkit-instantiation][FOX Toolkit instantiation]]
|
12
|
+
- [[#events-from-other-threads][Events from other Threads]]
|
13
|
+
- [[#the-queue_ding-queues][The Queue_Ding Queues]]
|
14
|
+
- [[#enhancementingress][Enhancement.ingress]]
|
15
|
+
- [[#enhancementegress][Enhancement.egress]]
|
16
|
+
- [[#api--dsl][API & DSL]]
|
17
|
+
- [[#ref-refc-and-tagging-your-objects][ref(), refc() and tagging your objects]]
|
18
|
+
- [[#fox_component-and-fox_instance][fox_component and fox_instance]]
|
19
|
+
- [[#fx_app][fx_app]]
|
20
|
+
- [[#instance][instance]]
|
21
|
+
- [[#ingress_handler][ingress_handler]]
|
22
|
+
- [[#deferred_setup][deferred_setup]]
|
23
|
+
- [[#mapping-between-fx_-declarations-and-the-fx-fxruby-objects][Mapping between fx_* declarations and the FX* FXRuby objects]]
|
24
|
+
- [[#bindingfx][binding.fx]]
|
25
|
+
- [[#examples][Examples]]
|
26
|
+
- [[#hello-world-example-full-the-enhancement-way][Hello World example (full) the Enhancement Way]]
|
27
|
+
- [[#hello-world-the-old-fxruby-way][Hello World the old fxruby way:]]
|
28
|
+
- [[#bouncing-ball-example-full][Bouncing Ball example (full):]]
|
29
|
+
- [[#bouncing-ball-the-old-fxruby-way][Bouncing Ball the old fxruby way:]]
|
30
|
+
- [[#release-notes][Release Notes]]
|
31
|
+
- [[#known-issues][Known Issues]]
|
32
|
+
- [[#contributing-to-fxruby-enhancement][Contributing to fxruby-enhancement]]
|
33
|
+
- [[#copyright-and-licensing][Copyright and Licensing]]
|
34
|
+
- [[#the-junkyard--scratchpad][The Junkyard / Scratchpad]]
|
35
|
+
- [[#genesis-of-the-meta-meta-programming-whereby-brain-goes-boom][Genesis of the meta-meta programming, whereby brain goes boom]]
|
36
|
+
|
37
|
+
* fxruby-enhancement
|
38
|
+
** Introduction
|
39
|
+
The fxruby library is an excellent wrapper for the FOX toolkit.
|
40
|
+
However, it reflects the C++-ness of FOX, rather than being more
|
41
|
+
Ruby-like. As such, creating composed objects with it tends to be
|
42
|
+
rather ugly and cumbersome. For every new component you create with
|
43
|
+
fxruby, you are handed back a reference to that object, which you'll
|
44
|
+
need to store somewhere. And then all the subsequent child objects
|
45
|
+
will need to be passed pointers to the parent objects.
|
46
|
+
|
47
|
+
So, if you need to redo a layout, it becomes a messy exercise.
|
48
|
+
|
49
|
+
fxruby-enhancement makes this a snap to do. You simply declare
|
50
|
+
your GUI arrangement in a nested fashion. fxruby-enhancement will
|
51
|
+
take care of passing parents to the nested children, and other issues
|
52
|
+
as well. You can now focus on creating a good GUI layout that you
|
53
|
+
can change on the fly without much fuss and bother.
|
54
|
+
|
55
|
+
fxruby-enhancement is basically a DSL of sorts, and every effort has
|
56
|
+
been taken to make it intuitive to use. Once you get the hang of it,
|
57
|
+
you should be able to look at the FXRuby API documentation and infer
|
58
|
+
the DSL construct for fxruby-enhancement. Please also see the many
|
59
|
+
[[file:examples][examples]].
|
60
|
+
|
61
|
+
** Installation
|
62
|
+
To install the gem from commandline:
|
63
|
+
|
64
|
+
#+begin_src bash
|
65
|
+
gem install fxruby-enhancement
|
66
|
+
#+end_src
|
67
|
+
|
68
|
+
In your Gemfile:
|
69
|
+
|
70
|
+
#+begin_src ruby
|
71
|
+
gem "fxruby-enhancement", "~> 0"
|
72
|
+
#+end_src
|
73
|
+
|
74
|
+
fxruby-enhacement depends on fxruby version 1.6, and
|
75
|
+
will automatically include it. However fxruby has a c-extension
|
76
|
+
that must compile properly on your system. Normally, this is not
|
77
|
+
a concern, but it is something to be aware of.
|
78
|
+
|
79
|
+
** Documentation
|
80
|
+
*** In General
|
81
|
+
fxruby-enhancement (which we will refer to as "Enhancement" from time
|
82
|
+
to time) makes use of the singleton pattern in Ruby. There is basically
|
83
|
+
no need to declare subclases off of most FXRuby classes. This is a very
|
84
|
+
C++ish way, and the way the C++ Fox Toolkit works. It will make most
|
85
|
+
hard-core Rubyists gnash their teeth.
|
86
|
+
|
87
|
+
Here, we do away with all of it. Also, the SEL_x variables -- which maps
|
88
|
+
to the C++ #defines of the same -- is replaced with method declarations
|
89
|
+
of the nature of sel_x -- just the lowercase version of the same. For instance,
|
90
|
+
in the straight fxruby, you would have to do something like:
|
91
|
+
|
92
|
+
#+begin_src ruby
|
93
|
+
@canvas.connect(SEL_PAINT) { |sender, sel, evt|
|
94
|
+
FXDCWindow.new(sender, evt) { |dc|
|
95
|
+
dc.drawImage(@backBuffer, 0, 0)
|
96
|
+
}
|
97
|
+
#+end_srcv
|
98
|
+
|
99
|
+
but with Enhancement, you do it thusly:
|
100
|
+
|
101
|
+
#+begin_src ruby
|
102
|
+
instance { |c|
|
103
|
+
c.sel_paint { |sender, sel, event|
|
104
|
+
FXDCWindow.new(sender, event) { |dc|
|
105
|
+
dc.drawImage(ref(:back_buffer), 0, 0)
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
#+end_src
|
110
|
+
|
111
|
+
And here we illustrate something else, the instance declaration. Why do
|
112
|
+
we do it this way? Because Enhancement is multi-phase. First, we declare
|
113
|
+
the GUI layout with Enhancement. At this time, none of the underlying
|
114
|
+
FXRuby objects exist yet, but need to be referenced anyway. So we defer
|
115
|
+
that part where references need to be resolved to the instance claus,
|
116
|
+
which, as you can well imagine, means the FXRuby object instances have
|
117
|
+
been instantiated.
|
118
|
+
|
119
|
+
You will also note the use of the ref clause, as in:
|
120
|
+
#+begin_src ruby
|
121
|
+
dc.drawImage(ref(:back_buffer), 0, 0)
|
122
|
+
#+end_src
|
123
|
+
|
124
|
+
When the :back_buffer object was declared, it was done thusly:
|
125
|
+
#+begin_src ruby
|
126
|
+
fx_image(:back_buffer) { opts IMAGE_KEEP }
|
127
|
+
#+end_src
|
128
|
+
|
129
|
+
So when the actual FXImage object is instantiated, it is associated to
|
130
|
+
the :back_buffer tag, which then is found by ref() and can be used
|
131
|
+
anywhere in the instantiation phase.
|
132
|
+
*** Execution Phases of fxruby-enhancement
|
133
|
+
This represents the work flow, in the order stated:
|
134
|
+
| State | Description |
|
135
|
+
|---------------------------+------------------------------------------------------------------------------------------------------------------------------|
|
136
|
+
| Declarative | The basic GUI layout is declared by the DSL, but it is not instantiated yet. |
|
137
|
+
| FXRuby instantiation | All the basic underlying FXRuby object are instantiatied, but the foundational FOX Toolkit Objects are not instantiated yet. |
|
138
|
+
| FOX Toolkit instantiation | The FOX Toolkit C++-level objects are now alive and kicking. |
|
139
|
+
|
140
|
+
**** Declarative
|
141
|
+
This phase, under the proverbial hood, ceates the component objects,
|
142
|
+
which are just place-holders for the underlying FXRuby objects.
|
143
|
+
|
144
|
+
When the FXRuby object is created, it is assigned to its place holder
|
145
|
+
component object, and can be references as comp.inst. In most cases,
|
146
|
+
you will almost never need to touch the component objects directly.
|
147
|
+
**** FXRuby Instantiation
|
148
|
+
During the FXRuby instantiantion stage, all of the FXRuby
|
149
|
+
objects are instantiated and stored in their respective
|
150
|
+
component objects. If they are tagged, the instantiated
|
151
|
+
object may be referenced with ref(), and the component
|
152
|
+
object itself may be referenced via refc(). There is almost
|
153
|
+
never a case where you would need to go after the component
|
154
|
+
object directly.
|
155
|
+
**** FOX Toolkit instantiation
|
156
|
+
All of the FOX Toolkit C++ objects, resources, etc. that
|
157
|
+
correspond to the FXRuby objects are now set up, and activated.
|
158
|
+
With the all-important "show PLACEMENT_SCREEN" command, the
|
159
|
+
FOX GUI should now be visible.
|
160
|
+
*** Events from other Threads
|
161
|
+
In handling interfacing to databases, AMQPs like RabbitMQ,
|
162
|
+
network connections, or just about anything else that might otherwise
|
163
|
+
slow down the GUI (Fox) thread and make it non-responsive, there needs
|
164
|
+
to be a clean way to get data into and out of the GUI thread.
|
165
|
+
|
166
|
+
Fox provides some mechanisms specifically for sockets or system-level IO,
|
167
|
+
but these are too specific, and would require some awkard workarounds to
|
168
|
+
make them work in the general context.
|
169
|
+
|
170
|
+
And so we provide a means to accomplish that in a clean -- to you, anyway --
|
171
|
+
manner. We make use of queue_ding queues for passing messages into and out of
|
172
|
+
the FXRuby (and therefore FXRuby Enhancement) space. This will allow you to
|
173
|
+
keep the GUI thread responsive and also to maintain a seperation of concerns.
|
174
|
+
**** The Queue_Ding Queues
|
175
|
+
[[ttps://github.com/flajann2/queue_ding][Queue Ding]] is an enhancement for doing queing across threads in Ruby,
|
176
|
+
and we offer it here to allow external events to be funneled into and
|
177
|
+
out of the Fox GUI thread. Usage is easy and straightforard. When
|
178
|
+
removing entries from Queue Ding using #next, the queue will block until
|
179
|
+
the next entry arrives. Since Queue Ding is really derived from ::Array,
|
180
|
+
you may also do thing like #empty? to check to see if entries are availabe
|
181
|
+
to avoid blocking.
|
182
|
+
***** Enhancement.ingress
|
183
|
+
To get messages objects into fxruby_enhacement, simply #push or #<<
|
184
|
+
it into the queue as shown:
|
185
|
+
#+begin_src ruby
|
186
|
+
Enhancement.ingress << [:some_tag, some_payload]
|
187
|
+
#+end_src
|
188
|
+
|
189
|
+
In the DSL, you must set up a handler for the ingress,
|
190
|
+
#+begin_src ruby
|
191
|
+
ingress_handler :status do |tag, payload|
|
192
|
+
puts "received #{tag} => #{payload}"
|
193
|
+
end
|
194
|
+
#+end_src
|
195
|
+
|
196
|
+
And so your handler will most likely act as a dispatcher
|
197
|
+
for the payloads received. For example:
|
198
|
+
#+begin_src ruby
|
199
|
+
ingress_handler :status do |tag, logline|
|
200
|
+
puts "received #{tag} => #{payload}"
|
201
|
+
case tag
|
202
|
+
when :log_info
|
203
|
+
ref(:logging_info).appendItem logline
|
204
|
+
when :log_error
|
205
|
+
ref(:logging_error).appendItem logline
|
206
|
+
end
|
207
|
+
end
|
208
|
+
#+end_src
|
209
|
+
|
210
|
+
***** Enhancement.egress
|
211
|
+
Wnen your Fox application needs to send a message to other
|
212
|
+
listening threads, You simply push your payload onto the egress queue
|
213
|
+
thusly:
|
214
|
+
#+begin_src ruby
|
215
|
+
Enhancement.egress << [:button_clicked, "I was clicked!"]
|
216
|
+
#+end_src
|
217
|
+
|
218
|
+
and your Ruby thread external to Fox would simply do:
|
219
|
+
#+begin_src
|
220
|
+
#+end_src
|
221
|
+
|
222
|
+
**** API & DSL
|
223
|
+
***** ref(), refc() and tagging your objects
|
224
|
+
In an effort to eliminate the fuss and bother with
|
225
|
+
scoping issues and object reference, ref(:some_tag) will
|
226
|
+
retrive the FXRuby instance object so tagged with :some_tag.
|
227
|
+
|
228
|
+
You may have anonymous, i.e., untagged objects, and those will
|
229
|
+
not be findable by ref(). It is not necessary to tag all objects,
|
230
|
+
either.
|
231
|
+
|
232
|
+
refc() is similar to ref(), except it retrives the underlying
|
233
|
+
component object insted. Indeed, the following are equivalent
|
234
|
+
operations:
|
235
|
+
#+begin_src ruby
|
236
|
+
ref(:some_tag)
|
237
|
+
refc(:some_tag).inst
|
238
|
+
#+end_src
|
239
|
+
|
240
|
+
There may be some edge cases where you might want to
|
241
|
+
reference the underlying component ahead of FXRuby object
|
242
|
+
instaniation, but in the vast majority of the cases, it should
|
243
|
+
be unnecessary. My goal is to enable to do what you need, not
|
244
|
+
to restrict you. You may need it for debugging, etc.
|
245
|
+
|
246
|
+
Underlying, the component object is really a subclass of OpenScript.
|
247
|
+
While you may like to stuff some additional data there,
|
248
|
+
this is frowned upon because it might conflict with Enhancement.
|
249
|
+
If you have a need for this, please do a issue in GitHub.
|
250
|
+
|
251
|
+
***** fox_component and fox_instance
|
252
|
+
fox_component and fox_instance are roughly the
|
253
|
+
equivalent of refc() and ref(), respecively. The
|
254
|
+
difference mainly being that fox_component does no
|
255
|
+
sanity checking, and is therefore slightly faster.
|
256
|
+
|
257
|
+
At some point, they may be merged, but for now don't
|
258
|
+
count on it.
|
259
|
+
|
260
|
+
To initialize and run your app, you customairly do the
|
261
|
+
following:
|
262
|
+
#+begin_src ruby
|
263
|
+
fox_component :app do |app|
|
264
|
+
app.launch
|
265
|
+
end
|
266
|
+
#+end_src
|
267
|
+
|
268
|
+
Which presumes your fx_app declaration was tagged with
|
269
|
+
:app as follows:
|
270
|
+
#+begin_src ruby
|
271
|
+
fx_app :app do
|
272
|
+
app_name "Your Amazingly Cool Application"
|
273
|
+
vendor_name "YouDaMan"
|
274
|
+
...
|
275
|
+
end
|
276
|
+
#+end_src
|
277
|
+
|
278
|
+
This is the only time you will reference the component
|
279
|
+
object directly for the obvious reason that you must start
|
280
|
+
from someonere.
|
281
|
+
|
282
|
+
***** fx_app
|
283
|
+
To begin the declaration of your app, you must do the
|
284
|
+
following somewhere:
|
285
|
+
#+begin_src ruby
|
286
|
+
fx_app :app do
|
287
|
+
app_name "The Forbin Project"
|
288
|
+
vendor_name "Colossus"
|
289
|
+
...
|
290
|
+
end
|
291
|
+
#+end_src
|
292
|
+
|
293
|
+
Typeically you'd do this inside of a module, but you could do it also
|
294
|
+
in a class body. Please see the examples.
|
295
|
+
|
296
|
+
***** TODO instance
|
297
|
+
***** TODO ingress_handler
|
298
|
+
***** TODO deferred_setup
|
299
|
+
***** TODO Mapping between fx_* declarations and the FX* FXRuby objects
|
300
|
+
***** binding.fx
|
301
|
+
This is a way to split up your layouts into different .fx "modules", purely for
|
302
|
+
organizational reasons. For example,
|
303
|
+
|
304
|
+
#+begin_src ruby
|
305
|
+
binding.fx "overview"
|
306
|
+
#+end_src
|
307
|
+
|
308
|
+
will load the overview.fx portion of the GUI, which happens to be a tab contents
|
309
|
+
in the tab book, which in our case looks like:
|
310
|
+
|
311
|
+
#+begin_src ruby
|
312
|
+
# Overview Tab
|
313
|
+
|
314
|
+
fx_tab_item { text "&Overview" }
|
315
|
+
fx_horizontal_frame (:overview_info) {
|
316
|
+
opts STD_FRAME|LAYOUT_FILL_Y
|
317
|
+
|
318
|
+
fx_group_box (:ov_connections_group) {
|
319
|
+
text "Connections"
|
320
|
+
opts STD_GROUPBOX|LAYOUT_FILL_Y
|
321
|
+
|
322
|
+
fx_vertical_frame {
|
323
|
+
opts LAYOUT_FILL_Y|LAYOUT_FILL_X #|PACK_UNIFORM_HEIGHT
|
324
|
+
|
325
|
+
fx_group_box (:ov_conn_rabbitmq) {
|
326
|
+
...
|
327
|
+
#+end_src
|
328
|
+
|
329
|
+
*** Examples
|
330
|
+
Class-based enhancement (this has not been tested yet!!!):
|
331
|
+
#+begin_src ruby
|
332
|
+
class Main < FXMainWindow
|
333
|
+
compose :my_window do
|
334
|
+
title "RubyNEAT Panel"
|
335
|
+
show PLACEMENT_SCREEN
|
336
|
+
width 700
|
337
|
+
height 400
|
338
|
+
fx_tab_book :my_book do |tab_book_ob|
|
339
|
+
x 0
|
340
|
+
y 0
|
341
|
+
width 500
|
342
|
+
height 100
|
343
|
+
pad_bottom 10
|
344
|
+
fx_text :my_text1, :my_window { |text_ob|
|
345
|
+
width 200
|
346
|
+
height 100
|
347
|
+
text_ob.target my_window: :on_click
|
348
|
+
}
|
349
|
+
fx_text :my_text2, :my_window { |text_ob|
|
350
|
+
width 200
|
351
|
+
height 100
|
352
|
+
text_ob { |t| puts "called after object initialization" }
|
353
|
+
}
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def on_click
|
358
|
+
...
|
359
|
+
end
|
360
|
+
end
|
361
|
+
#+end_src
|
362
|
+
|
363
|
+
Class-free enhancement:
|
364
|
+
#+begin_src ruby
|
365
|
+
mw = fx_main_window :my_window do
|
366
|
+
title "RubyNEAT Panel"
|
367
|
+
width 700
|
368
|
+
height 400
|
369
|
+
opts DECOR_ALL
|
370
|
+
x 10
|
371
|
+
y 10
|
372
|
+
instance { show PLACEMENT_SCREEN }
|
373
|
+
fx_tab_book :my_book do |tab_book_ob|
|
374
|
+
x 0
|
375
|
+
y 0
|
376
|
+
width 500
|
377
|
+
height 100
|
378
|
+
pad_bottom 10
|
379
|
+
fx_text :my_text1, :my_window { |text_ob|
|
380
|
+
width 200
|
381
|
+
height 100
|
382
|
+
instance my_window: :on_click
|
383
|
+
}
|
384
|
+
fx_text :my_text2, :my_window {
|
385
|
+
width 200
|
386
|
+
height 100
|
387
|
+
instance { |t| puts "called after object initialization" }
|
388
|
+
}
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
def mw.on_click
|
393
|
+
...
|
394
|
+
end
|
395
|
+
end
|
396
|
+
#+end_src
|
397
|
+
|
398
|
+
**** [[file:examples/hello.rb][Hello World]] example (full) the Enhancement Way
|
399
|
+
#+begin_src ruby
|
400
|
+
#!/usr/bin/env ruby
|
401
|
+
require 'fxruby-enhancement'
|
402
|
+
|
403
|
+
include Fox
|
404
|
+
include Fox::Enhancement::Mapper
|
405
|
+
|
406
|
+
fx_app :app do
|
407
|
+
app_name "Hello"
|
408
|
+
vendor_name "Example"
|
409
|
+
|
410
|
+
fx_main_window(:main) {
|
411
|
+
title "Hello"
|
412
|
+
opts DECOR_ALL
|
413
|
+
|
414
|
+
fx_button {
|
415
|
+
text "&Hello, World"
|
416
|
+
selector FXApp::ID_QUIT
|
417
|
+
|
418
|
+
instance { |b|
|
419
|
+
b.target = ref(:app)
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
instance { |w|
|
424
|
+
w.show PLACEMENT_SCREEN
|
425
|
+
}
|
426
|
+
}
|
427
|
+
end
|
428
|
+
|
429
|
+
# alias for fox_component is fxc
|
430
|
+
fox_component :app do |app|
|
431
|
+
app.launch
|
432
|
+
end
|
433
|
+
#+end_src
|
434
|
+
|
435
|
+
**** Hello World the old fxruby way:
|
436
|
+
#+begin_src ruby
|
437
|
+
#!/usr/bin/env ruby
|
438
|
+
|
439
|
+
require 'fox16'
|
440
|
+
|
441
|
+
include Fox
|
442
|
+
|
443
|
+
application = FXApp.new("Hello", "FoxTest")
|
444
|
+
main = FXMainWindow.new(application, "Hello", nil, nil, DECOR_ALL)
|
445
|
+
FXButton.new(main, "&Hello, World!", nil, application, FXApp::ID_QUIT)
|
446
|
+
application.create()
|
447
|
+
main.show(PLACEMENT_SCREEN)
|
448
|
+
application.run()
|
449
|
+
#+end_src
|
450
|
+
|
451
|
+
Even though the old way has a slightly smaller line count, you can
|
452
|
+
see how messy it can be assigning each newly-created object to
|
453
|
+
a variable, and then having to pass that variable to the children.
|
454
|
+
Perhaps this example is too small, but perhaps the next one will
|
455
|
+
more illustrative.
|
456
|
+
|
457
|
+
**** [[file:examples/bounce.rb][Bouncing Ball]] example (full):
|
458
|
+
#+begin_src ruby
|
459
|
+
#!/usr/bin/env ruby
|
460
|
+
require 'fxruby-enhancement'
|
461
|
+
|
462
|
+
include Fox
|
463
|
+
include Fox::Enhancement::Mapper
|
464
|
+
|
465
|
+
ANIMATION_TIME = 20
|
466
|
+
|
467
|
+
class Ball
|
468
|
+
attr_reader :color
|
469
|
+
attr_reader :center
|
470
|
+
attr_reader :radius
|
471
|
+
attr_reader :dir
|
472
|
+
attr_reader :x, :y
|
473
|
+
attr_reader :w, :h
|
474
|
+
attr_accessor :worldWidth
|
475
|
+
attr_accessor :worldHeight
|
476
|
+
|
477
|
+
|
478
|
+
def initialize r
|
479
|
+
@radius = r
|
480
|
+
@w = 2*@radius
|
481
|
+
@h = 2*@radius
|
482
|
+
@center = FXPoint.new(50, 50)
|
483
|
+
@x = @center.x - @radius
|
484
|
+
@y = @center.y - @radius
|
485
|
+
@color = FXRGB(255, 0, 0) # red
|
486
|
+
@dir = FXPoint.new(-1, -1)
|
487
|
+
setWorldSize(1000, 1000)
|
488
|
+
end
|
489
|
+
|
490
|
+
# Draw the ball into this device context
|
491
|
+
def draw(dc)
|
492
|
+
dc.setForeground(color)
|
493
|
+
dc.fillArc(x, y, w, h, 0, 64*90)
|
494
|
+
dc.fillArc(x, y, w, h, 64*90, 64*180)
|
495
|
+
dc.fillArc(x, y, w, h, 64*180, 64*270)
|
496
|
+
dc.fillArc(x, y, w, h, 64*270, 64*360)
|
497
|
+
end
|
498
|
+
|
499
|
+
def bounce_x
|
500
|
+
@dir.x=-@dir.x
|
501
|
+
end
|
502
|
+
|
503
|
+
def bounce_y
|
504
|
+
@dir.y=-@dir.y
|
505
|
+
end
|
506
|
+
|
507
|
+
def collision_y?
|
508
|
+
(y<0 && dir.y<0) || (y+h>worldHeight && dir.y>0)
|
509
|
+
end
|
510
|
+
|
511
|
+
def collision_x?
|
512
|
+
(x<0 && dir.x<0) || (x+w>worldWidth && dir.x>0)
|
513
|
+
end
|
514
|
+
|
515
|
+
def setWorldSize(ww, wh)
|
516
|
+
@worldWidth = ww
|
517
|
+
@worldHeight = wh
|
518
|
+
end
|
519
|
+
|
520
|
+
def move(units)
|
521
|
+
dx = dir.x*units
|
522
|
+
dy = dir.y*units
|
523
|
+
center.x += dx
|
524
|
+
center.y += dy
|
525
|
+
@x += dx
|
526
|
+
@y += dy
|
527
|
+
if collision_x?
|
528
|
+
bounce_x
|
529
|
+
move(units)
|
530
|
+
end
|
531
|
+
if collision_y?
|
532
|
+
bounce_y
|
533
|
+
move(units)
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
fx_app :app do
|
539
|
+
app_name "Bounce"
|
540
|
+
vendor_name "Example"
|
541
|
+
|
542
|
+
fx_image(:back_buffer) { opts IMAGE_KEEP }
|
543
|
+
|
544
|
+
fx_main_window(:bounce_window) {
|
545
|
+
title "Bounce Demo"
|
546
|
+
opts DECOR_ALL
|
547
|
+
width 400
|
548
|
+
height 300
|
549
|
+
|
550
|
+
instance { |w|
|
551
|
+
def w.ball
|
552
|
+
@ball ||= Ball.new(20)
|
553
|
+
end
|
554
|
+
|
555
|
+
def w.drawScene(drawable)
|
556
|
+
FXDCWindow.new(drawable) { |dc|
|
557
|
+
dc.setForeground(FXRGB(255, 255, 255))
|
558
|
+
dc.fillRectangle(0, 0, drawable.width, drawable.height)
|
559
|
+
ball.draw(dc)
|
560
|
+
}
|
561
|
+
end
|
562
|
+
|
563
|
+
def w.updateCanvas
|
564
|
+
ball.move(10)
|
565
|
+
drawScene(ref(:back_buffer))
|
566
|
+
ref(:canvas).update
|
567
|
+
end
|
568
|
+
|
569
|
+
#
|
570
|
+
# Handle timeout events
|
571
|
+
#
|
572
|
+
def w.onTimeout(sender, sel, ptr)
|
573
|
+
# Move the ball and re-draw the scene
|
574
|
+
updateCanvas
|
575
|
+
|
576
|
+
# Re-register the timeout
|
577
|
+
ref(:app).addTimeout(ANIMATION_TIME, ref(:bounce_window).method(:onTimeout))
|
578
|
+
|
579
|
+
# Done
|
580
|
+
return 1
|
581
|
+
end
|
582
|
+
|
583
|
+
w.show PLACEMENT_SCREEN
|
584
|
+
ref(:app).addTimeout(ANIMATION_TIME, w.method(:onTimeout))
|
585
|
+
}
|
586
|
+
|
587
|
+
fx_canvas(:canvas) {
|
588
|
+
opts LAYOUT_FILL_X|LAYOUT_FILL_Y
|
589
|
+
|
590
|
+
instance { |c|
|
591
|
+
c.sel_paint { |sender, sel, event|
|
592
|
+
FXDCWindow.new(sender, event) { |dc|
|
593
|
+
dc.drawImage(ref(:back_buffer), 0, 0)
|
594
|
+
}
|
595
|
+
}
|
596
|
+
|
597
|
+
c.sel_configure{ |sender, sel, event|
|
598
|
+
bb = ref(:back_buffer)
|
599
|
+
bb.create unless bb.created?
|
600
|
+
bb.resize(sender.width, sender.height)
|
601
|
+
ref(:bounce_window) do |bw|
|
602
|
+
bw.ball.setWorldSize(sender.width, sender.height)
|
603
|
+
bw.drawScene(bb)
|
604
|
+
end
|
605
|
+
}
|
606
|
+
}
|
607
|
+
}
|
608
|
+
}
|
609
|
+
end
|
610
|
+
|
611
|
+
if __FILE__ == $0
|
612
|
+
# alias for fox_component is fxc
|
613
|
+
fox_component :app do |app|
|
614
|
+
app.launch
|
615
|
+
end
|
616
|
+
end
|
617
|
+
#+end_src
|
618
|
+
|
619
|
+
**** Bouncing Ball the old fxruby way:
|
620
|
+
#+begin_src ruby
|
621
|
+
require 'fox16'
|
622
|
+
|
623
|
+
include Fox
|
624
|
+
|
625
|
+
# How long to pause between updates (in milliseconds)
|
626
|
+
ANIMATION_TIME = 20
|
627
|
+
|
628
|
+
class Ball
|
629
|
+
|
630
|
+
attr_reader :color
|
631
|
+
attr_reader :center
|
632
|
+
attr_reader :radius
|
633
|
+
attr_reader :dir
|
634
|
+
attr_reader :x, :y
|
635
|
+
attr_reader :w, :h
|
636
|
+
attr_accessor :worldWidth
|
637
|
+
attr_accessor :worldHeight
|
638
|
+
|
639
|
+
# Returns an initialized ball
|
640
|
+
def initialize(r)
|
641
|
+
@radius = r
|
642
|
+
@w = 2*@radius
|
643
|
+
@h = 2*@radius
|
644
|
+
@center = FXPoint.new(50, 50)
|
645
|
+
@x = @center.x - @radius
|
646
|
+
@y = @center.y - @radius
|
647
|
+
@color = FXRGB(255, 0, 0) # red
|
648
|
+
@dir = FXPoint.new(-1, -1)
|
649
|
+
setWorldSize(1000, 1000)
|
650
|
+
end
|
651
|
+
|
652
|
+
# Draw the ball into this device context
|
653
|
+
def draw(dc)
|
654
|
+
dc.setForeground(color)
|
655
|
+
dc.fillArc(x, y, w, h, 0, 64*90)
|
656
|
+
dc.fillArc(x, y, w, h, 64*90, 64*180)
|
657
|
+
dc.fillArc(x, y, w, h, 64*180, 64*270)
|
658
|
+
dc.fillArc(x, y, w, h, 64*270, 64*360)
|
659
|
+
end
|
660
|
+
|
661
|
+
def bounce_x
|
662
|
+
@dir.x=-@dir.x
|
663
|
+
end
|
664
|
+
|
665
|
+
def bounce_y
|
666
|
+
@dir.y=-@dir.y
|
667
|
+
end
|
668
|
+
|
669
|
+
def collision_y?
|
670
|
+
(y<0 && dir.y<0) || (y+h>worldHeight && dir.y>0)
|
671
|
+
end
|
672
|
+
|
673
|
+
def collision_x?
|
674
|
+
(x<0 && dir.x<0) || (x+w>worldWidth && dir.x>0)
|
675
|
+
end
|
676
|
+
|
677
|
+
def setWorldSize(ww, wh)
|
678
|
+
@worldWidth = ww
|
679
|
+
@worldHeight = wh
|
680
|
+
end
|
681
|
+
|
682
|
+
def move(units)
|
683
|
+
dx = dir.x*units
|
684
|
+
dy = dir.y*units
|
685
|
+
center.x += dx
|
686
|
+
center.y += dy
|
687
|
+
@x += dx
|
688
|
+
@y += dy
|
689
|
+
if collision_x?
|
690
|
+
bounce_x
|
691
|
+
move(units)
|
692
|
+
end
|
693
|
+
if collision_y?
|
694
|
+
bounce_y
|
695
|
+
move(units)
|
696
|
+
end
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
class BounceWindow < FXMainWindow
|
701
|
+
|
702
|
+
include Responder
|
703
|
+
|
704
|
+
def initialize(app)
|
705
|
+
# Initialize base class first
|
706
|
+
super(app, "Bounce", :opts => DECOR_ALL, :width => 400, :height => 300)
|
707
|
+
|
708
|
+
# Set up the canvas
|
709
|
+
@canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
|
710
|
+
|
711
|
+
# Set up the back buffer
|
712
|
+
@backBuffer = FXImage.new(app, nil, IMAGE_KEEP)
|
713
|
+
|
714
|
+
# Handle expose events (by blitting the image to the canvas)
|
715
|
+
@canvas.connect(SEL_PAINT) { |sender, sel, evt|
|
716
|
+
FXDCWindow.new(sender, evt) { |dc|
|
717
|
+
dc.drawImage(@backBuffer, 0, 0)
|
718
|
+
}
|
719
|
+
}
|
720
|
+
|
721
|
+
# Handle resize events
|
722
|
+
@canvas.connect(SEL_CONFIGURE) { |sender, sel, evt|
|
723
|
+
@backBuffer.create unless @backBuffer.created?
|
724
|
+
@backBuffer.resize(sender.width, sender.height)
|
725
|
+
@ball.setWorldSize(sender.width, sender.height)
|
726
|
+
drawScene(@backBuffer)
|
727
|
+
}
|
728
|
+
|
729
|
+
@ball = Ball.new(20)
|
730
|
+
end
|
731
|
+
|
732
|
+
#
|
733
|
+
# Draws the scene into the back buffer
|
734
|
+
#
|
735
|
+
def drawScene(drawable)
|
736
|
+
FXDCWindow.new(drawable) { |dc|
|
737
|
+
dc.setForeground(FXRGB(255, 255, 255))
|
738
|
+
dc.fillRectangle(0, 0, drawable.width, drawable.height)
|
739
|
+
@ball.draw(dc)
|
740
|
+
}
|
741
|
+
end
|
742
|
+
|
743
|
+
def updateCanvas
|
744
|
+
@ball.move(10)
|
745
|
+
drawScene(@backBuffer)
|
746
|
+
@canvas.update
|
747
|
+
end
|
748
|
+
|
749
|
+
#
|
750
|
+
# Handle timeout events
|
751
|
+
#
|
752
|
+
def onTimeout(sender, sel, ptr)
|
753
|
+
# Move the ball and re-draw the scene
|
754
|
+
updateCanvas
|
755
|
+
|
756
|
+
# Re-register the timeout
|
757
|
+
getApp().addTimeout(ANIMATION_TIME, method(:onTimeout))
|
758
|
+
|
759
|
+
# Done
|
760
|
+
return 1
|
761
|
+
end
|
762
|
+
|
763
|
+
#
|
764
|
+
# Create server-side resources
|
765
|
+
#
|
766
|
+
def create
|
767
|
+
# Create base class
|
768
|
+
super
|
769
|
+
|
770
|
+
# Create the image used as the back-buffer
|
771
|
+
@backBuffer.create
|
772
|
+
|
773
|
+
# Draw the initial scene into the back-buffer
|
774
|
+
drawScene(@backBuffer)
|
775
|
+
|
776
|
+
# Register the timer used for animation
|
777
|
+
getApp().addTimeout(ANIMATION_TIME, method(:onTimeout))
|
778
|
+
|
779
|
+
# Show the main window
|
780
|
+
show(PLACEMENT_SCREEN)
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
if __FILE__ == $0
|
785
|
+
FXApp.new("Bounce", "FXRuby") do |theApp|
|
786
|
+
BounceWindow.new(theApp)
|
787
|
+
theApp.create
|
788
|
+
theApp.run
|
789
|
+
end
|
790
|
+
end
|
791
|
+
#+end_src
|
792
|
+
|
793
|
+
The Ball class is the same, but the actual Fox-related code
|
794
|
+
should clearly illustrate the power of Enhancement.
|
795
|
+
|
796
|
+
More examples can be found [[file:examples][HERE]].
|
797
|
+
|
798
|
+
** Release Notes
|
799
|
+
| Version | Date | Notes |
|
800
|
+
|---------+------------+-----------------|
|
801
|
+
| 0.0.2 | 2017-01-11 | Initial release |
|
802
|
+
|
803
|
+
** Known Issues
|
804
|
+
| Version | Date | Issues |
|
805
|
+
|---------+------------+----------------------------|
|
806
|
+
| 0.0.2 | 2017-01-11 | Not enough example code!!! |
|
807
|
+
|
808
|
+
** Contributing to fxruby-enhancement
|
809
|
+
|
810
|
+
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
811
|
+
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
812
|
+
- Fork the project.
|
813
|
+
- Start a feature/bugfix branch.
|
814
|
+
- Commit and push until you are happy with your contribution.
|
815
|
+
- Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
816
|
+
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
817
|
+
|
818
|
+
** Copyright and Licensing
|
819
|
+
Copyright (c) 2016-2017 Fred Mitchell. See [[file:LICENSE.txt][MIT License]] for
|
820
|
+
further details.
|
821
|
+
** The Junkyard / Scratchpad
|
822
|
+
These are my personal notes, not meant for anyone else.
|
823
|
+
You may see some interesting tidbits here, but I am not
|
824
|
+
gauranteeing anything to be useful or reliable in this
|
825
|
+
section. YOU HAVE BEEN WARNED.
|
826
|
+
*** Genesis of the meta-meta programming, whereby brain goes boom
|
827
|
+
#+begin_src ruby
|
828
|
+
class FXToolBar # monkey patch
|
829
|
+
include Enhancement
|
830
|
+
attr_accessor :_o
|
831
|
+
end
|
832
|
+
|
833
|
+
def fx_tool_bar name, &block # DSL
|
834
|
+
o = OStruct.new
|
835
|
+
o.title = "default title"
|
836
|
+
...
|
837
|
+
|
838
|
+
def o.title t
|
839
|
+
@title = t
|
840
|
+
end
|
841
|
+
|
842
|
+
def o.instance a, &block
|
843
|
+
o.instance_time_block = block
|
844
|
+
end
|
845
|
+
f = FXToolBar.new ...
|
846
|
+
f._o = o
|
847
|
+
end
|
848
|
+
|
849
|
+
<% for @class, @details in @api %>
|
850
|
+
#<%= @class %> < <%= @details[:class][1] %>
|
851
|
+
<% unless @details[:initialize].nil? %>
|
852
|
+
<% for @iniparams in @details[:initialize] %>
|
853
|
+
#<%= @iniparams %>
|
854
|
+
<% end %>
|
855
|
+
<% else %>
|
856
|
+
#No initializer
|
857
|
+
<% end %>
|
858
|
+
<% end %>
|
859
|
+
#+end_src
|
860
|
+
|
861
|
+
|