wxruby 1.9.10-universal-darwin-9 → 2.0.0-universal-darwin-9
Sign up to get free protection for your applications and to get access to all the features.
- data/INSTALL +254 -0
- data/README +184 -283
- data/lib/wx/accessors.rb +19 -7
- data/lib/wx/classes/bitmap.rb +3 -0
- data/lib/wx/classes/clipboard.rb +28 -4
- data/lib/wx/classes/image.rb +5 -0
- data/lib/wx/classes/toolbar.rb +7 -4
- data/lib/wx/classes/validator.rb +7 -0
- data/lib/wx/keyword_defs.rb +19 -2
- data/lib/wx/version.rb +1 -1
- data/lib/wxruby2.bundle +0 -0
- data/samples/aui/aui.rb +21 -21
- data/samples/calendar/calendar.rb +1 -1
- data/samples/drawing/{images.rb → bitmap.rb} +10 -3
- data/samples/drawing/bitmap_image.rb +92 -0
- data/samples/drawing/maths_images.rb +265 -0
- data/samples/drawing/ruby-logo.jpg +0 -0
- data/samples/drawing/wxruby-logo.png +0 -0
- data/samples/text/document-open.png +0 -0
- data/samples/text/document-save.png +0 -0
- data/samples/text/edit-copy.png +0 -0
- data/samples/text/edit-cut.png +0 -0
- data/samples/text/edit-paste.png +0 -0
- data/samples/text/edit-redo.png +0 -0
- data/samples/text/edit-undo.png +0 -0
- data/samples/text/preferences-desktop-font.png +0 -0
- data/samples/text/rich_textctrl.rb +234 -42
- metadata +17 -4
- data/samples/drawing/paperclip.png +0 -0
data/lib/wx/accessors.rb
CHANGED
@@ -5,16 +5,21 @@
|
|
5
5
|
# * get_position()
|
6
6
|
# * set_size(a_size)
|
7
7
|
# * is_checked()
|
8
|
+
# * can_undo()
|
9
|
+
# * has_style(a_style)
|
8
10
|
#
|
9
11
|
# and so on. Methods that retrieve set, or query attributes of an object
|
10
|
-
# are more normally in Ruby called simply by the attribute name
|
12
|
+
# are more normally in Ruby called simply by the attribute name, or, in
|
13
|
+
# other cases, with a predicate method:
|
11
14
|
#
|
12
|
-
# * position
|
13
|
-
# * size = a_size
|
14
|
-
# * checked?
|
15
|
+
# * pos = my_widget.position
|
16
|
+
# * my_widget.size = a_size
|
17
|
+
# * my_widget.checked?
|
18
|
+
# * my_widget.can_undo?
|
19
|
+
# * my_widget.has_style?
|
15
20
|
#
|
16
21
|
# This extension creates an alias for every WxRuby instance method that
|
17
|
-
# begins with +get_+, +set_+
|
22
|
+
# begins with +get_+, +set_+, +is_+, +can_+ and +has_+. Note that if you are calling a
|
18
23
|
# 'setter' method on self, you must explicitly send the message to self:
|
19
24
|
#
|
20
25
|
# # set's self size to be 100px by 100px
|
@@ -23,11 +28,18 @@
|
|
23
28
|
# size = Wx::Size.new
|
24
29
|
|
25
30
|
module WxRubyStyleAccessors
|
31
|
+
# Ruby-style method named are implemented by method-missing; if an
|
32
|
+
# unknown method is called, see if it is a rubyish name for a real
|
33
|
+
# method. In principle it would be possible to set up real aliases for
|
34
|
+
# them at start-up, but in practice this is far too slow for all the
|
35
|
+
# classes that need to be started up.
|
26
36
|
def method_missing(sym, *args)
|
27
37
|
case sym.to_s
|
28
|
-
when /^(
|
38
|
+
when /^(\w+)\=$/
|
29
39
|
meth = "set_#{$1}"
|
30
|
-
when /^(
|
40
|
+
when /^((?:has|can)\w+)\?$/
|
41
|
+
meth = $1
|
42
|
+
when /^(\w+)\?$/
|
31
43
|
meth = "is_#{$1}"
|
32
44
|
else
|
33
45
|
meth = "get_#{sym}"
|
data/lib/wx/classes/bitmap.rb
CHANGED
@@ -25,6 +25,9 @@ class Wx::Bitmap
|
|
25
25
|
new(img, depth)
|
26
26
|
end
|
27
27
|
|
28
|
+
# Ruby methods that switch class are conventionally named to_foo
|
29
|
+
alias :to_image :convert_to_image
|
30
|
+
|
28
31
|
# Redefine the initialize method so it raises an exception if a
|
29
32
|
# non-existent file is given to the constructor; otherwise, wx Widgets
|
30
33
|
# just carries on with an empty bitmap, which may cause faults
|
data/lib/wx/classes/clipboard.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
1
|
class Wx::Clipboard
|
2
|
-
# See if we like these better
|
3
|
-
alias :place :set_data
|
4
|
-
alias :fetch :get_data
|
5
|
-
|
6
2
|
class << self
|
7
3
|
# This is provided internally by the SWIG interface file, but all
|
8
4
|
# public access should be via Clipboard.open; see below
|
@@ -29,4 +25,32 @@ class Wx::Clipboard
|
|
29
25
|
clip.close if clip
|
30
26
|
end
|
31
27
|
end
|
28
|
+
|
29
|
+
# Need to do some internal record-keeping to protect data objects on
|
30
|
+
# the clipboard from garbage collection
|
31
|
+
@@__clip_data = []
|
32
|
+
|
33
|
+
# These methods affect the clipboard contents; each time, update the
|
34
|
+
# record with the changed data contents
|
35
|
+
wx_add_data = instance_method(:add_data)
|
36
|
+
define_method(:add_data) do | the_data |
|
37
|
+
@@__clip_data << the_data
|
38
|
+
wx_add_data.bind(self).call(the_data)
|
39
|
+
end
|
40
|
+
|
41
|
+
wx_clear = instance_method(:clear)
|
42
|
+
define_method(:clear) do
|
43
|
+
@@__clip_data.clear
|
44
|
+
wx_clear.bind(self).call
|
45
|
+
end
|
46
|
+
|
47
|
+
wx_set_data = instance_method(:set_data)
|
48
|
+
define_method(:set_data) do | the_data |
|
49
|
+
@@__clip_data = [ the_data ]
|
50
|
+
wx_set_data.bind(self).call(the_data)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Aliases, more clearly expressive?
|
54
|
+
alias :place :set_data
|
55
|
+
alias :fetch :get_data
|
32
56
|
end
|
data/lib/wx/classes/image.rb
CHANGED
@@ -17,6 +17,11 @@ class Wx::Image
|
|
17
17
|
bmp.convert_to_image
|
18
18
|
end
|
19
19
|
|
20
|
+
# Ruby methods that switch class are conventionally named to_foo
|
21
|
+
def to_bitmap
|
22
|
+
Wx::Bitmap.from_image(self)
|
23
|
+
end
|
24
|
+
|
20
25
|
# Redefine the initialize method so it raises an exception if a
|
21
26
|
# non-existent file is given to the constructor; otherwise, wx Widgets
|
22
27
|
# just carries on with an invalid image, which may cause faults
|
data/lib/wx/classes/toolbar.rb
CHANGED
@@ -2,20 +2,23 @@
|
|
2
2
|
class Wx::ToolBar
|
3
3
|
# Generic method to add items, supporting positional and named
|
4
4
|
# arguments
|
5
|
-
ADD_ITEM_PARAMS = [
|
5
|
+
ADD_ITEM_PARAMS = [
|
6
|
+
Wx::Parameter[ :bitmap2, Wx::NULL_BITMAP ],
|
7
|
+
Wx::Parameter[ :position, -1 ],
|
6
8
|
Wx::Parameter[ :id, -1 ],
|
7
9
|
Wx::Parameter[ :label, "" ],
|
8
|
-
Wx::Parameter[ :bitmap2, Wx::NULL_BITMAP ],
|
9
10
|
Wx::Parameter[ :kind, Wx::ITEM_NORMAL ],
|
10
11
|
Wx::Parameter[ :short_help, "" ],
|
11
12
|
Wx::Parameter[ :long_help, "" ],
|
12
13
|
Wx::Parameter[ :client_data, nil ] ]
|
13
14
|
|
14
|
-
def add_item(
|
15
|
+
def add_item(bitmap1, *mixed_args)
|
15
16
|
args = Wx::args_as_list(ADD_ITEM_PARAMS, *mixed_args)
|
16
17
|
|
18
|
+
bitmap2 = args.shift
|
17
19
|
pos = args.shift
|
18
|
-
args.insert(2,
|
20
|
+
args.insert(2, bitmap1)
|
21
|
+
args.insert(3, bitmap2)
|
19
22
|
|
20
23
|
# Call add_tool to append if default position
|
21
24
|
if pos == -1
|
data/lib/wx/keyword_defs.rb
CHANGED
@@ -246,8 +246,25 @@ Wx::define_keyword_ctors('FindReplaceDialog') do
|
|
246
246
|
wx_ctor_params :style
|
247
247
|
end
|
248
248
|
|
249
|
-
#
|
250
|
-
|
249
|
+
# Dialog to get one or more selections from a list
|
250
|
+
Wx::define_keyword_ctors('MultiChoiceDialog') do
|
251
|
+
wx_ctor_params :message => ''
|
252
|
+
wx_ctor_params :caption => ''
|
253
|
+
wx_ctor_params :choices => []
|
254
|
+
wx_ctor_params :style => Wx::DEFAULT_DIALOG_STYLE|Wx::RESIZE_BORDER|
|
255
|
+
Wx::OK|Wx::CANCEL|Wx::CENTRE
|
256
|
+
wx_ctor_params :pos
|
257
|
+
end
|
258
|
+
|
259
|
+
# Dialog to get a single selection from a list and return the string
|
260
|
+
Wx::define_keyword_ctors('SingleChoiceDialog') do
|
261
|
+
wx_ctor_params :message => ''
|
262
|
+
wx_ctor_params :caption => ''
|
263
|
+
wx_ctor_params :choices => []
|
264
|
+
wx_ctor_params :style => Wx::DEFAULT_DIALOG_STYLE|Wx::RESIZE_BORDER|
|
265
|
+
Wx::OK|Wx::CANCEL|Wx::CENTRE
|
266
|
+
wx_ctor_params :pos
|
267
|
+
end
|
251
268
|
|
252
269
|
# Dialog to get a single line of text from the user
|
253
270
|
Wx::define_keyword_ctors('TextEntryDialog') do
|
data/lib/wx/version.rb
CHANGED
data/lib/wxruby2.bundle
CHANGED
Binary file
|
data/samples/aui/aui.rb
CHANGED
@@ -169,37 +169,37 @@ class SettingsPanel < Wx::Panel
|
|
169
169
|
|
170
170
|
|
171
171
|
def update_colours()
|
172
|
-
art = @frame.
|
172
|
+
art = @frame.dock_art
|
173
173
|
|
174
|
-
col = art.
|
175
|
-
@bckg_colour.
|
174
|
+
col = art.colour(Wx::AUI_DOCKART_BACKGROUND_COLOUR)
|
175
|
+
@bckg_colour.bitmap_label = ( create_colour_bitmap(col) )
|
176
176
|
|
177
|
-
col = art.
|
178
|
-
@sash_colour.
|
177
|
+
col = art.colour(Wx::AUI_DOCKART_SASH_COLOUR)
|
178
|
+
@sash_colour.bitmap_label = ( create_colour_bitmap(col) )
|
179
179
|
|
180
|
-
col = art.
|
181
|
-
@capt_colour.
|
180
|
+
col = art.colour(Wx::AUI_DOCKART_INACTIVE_CAPTION_COLOUR)
|
181
|
+
@capt_colour.bitmap_label = ( create_colour_bitmap(col) )
|
182
182
|
|
183
|
-
col = art.
|
184
|
-
@capt_gradnt.
|
183
|
+
col = art.colour(Wx::AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR)
|
184
|
+
@capt_gradnt.bitmap_label = ( create_colour_bitmap(col) )
|
185
185
|
|
186
|
-
col = art.
|
187
|
-
@capt_text.
|
186
|
+
col = art.colour(Wx::AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR)
|
187
|
+
@capt_text.bitmap_label = ( create_colour_bitmap(col) )
|
188
188
|
|
189
|
-
col = art.
|
190
|
-
@acap_colour.
|
189
|
+
col = art.colour(Wx::AUI_DOCKART_ACTIVE_CAPTION_COLOUR)
|
190
|
+
@acap_colour.bitmap_label = ( create_colour_bitmap(col) )
|
191
191
|
|
192
|
-
col = art.
|
193
|
-
@acap_gradnt.
|
192
|
+
col = art.colour(Wx::AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR)
|
193
|
+
@acap_gradnt.bitmap_label = ( create_colour_bitmap(col) )
|
194
194
|
|
195
|
-
col = art.
|
196
|
-
@acap_text.
|
195
|
+
col = art.colour(Wx::AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR)
|
196
|
+
@acap_text.bitmap_label = ( create_colour_bitmap(col) )
|
197
197
|
|
198
|
-
col = art.
|
199
|
-
@brdr_colour.
|
198
|
+
col = art.colour(Wx::AUI_DOCKART_SASH_COLOUR)
|
199
|
+
@brdr_colour.bitmap_label = ( create_colour_bitmap(col) )
|
200
200
|
|
201
|
-
col = art.
|
202
|
-
@grip_colour.
|
201
|
+
col = art.colour(Wx::AUI_DOCKART_GRIPPER_COLOUR)
|
202
|
+
@grip_colour.bitmap_label = ( create_colour_bitmap(col) )
|
203
203
|
end
|
204
204
|
|
205
205
|
def on_pane_border_size(event)
|
@@ -11,14 +11,20 @@ require 'wx'
|
|
11
11
|
# This sample demonstrates how to draw an image from a file onto a
|
12
12
|
# window. This one uses a small PNG file, but other formats such as JPEG
|
13
13
|
# are supported - see documentation for more details.
|
14
|
+
#
|
15
|
+
# This sample uses the Wx::Bitmap class, which is a platform-specific
|
16
|
+
# representation of an image. This is the class that must be used to
|
17
|
+
# display an image, but see also Wx::Image, which allows a much wider
|
18
|
+
# range of manipulations (such as rescaling) and writing to files.
|
19
|
+
|
14
20
|
|
15
21
|
class ImageFrame < Wx::Frame
|
16
22
|
def initialize
|
17
23
|
super(nil, :title => 'Simple image demo')
|
18
24
|
|
19
25
|
# Load a PNG bitmap from a file for drawing
|
20
|
-
img_file = File.join( File.dirname(__FILE__), '
|
21
|
-
@bitmap = Wx::Bitmap.new(img_file
|
26
|
+
img_file = File.join( File.dirname(__FILE__), 'wxruby-logo.png')
|
27
|
+
@bitmap = Wx::Bitmap.new(img_file)
|
22
28
|
|
23
29
|
# Set up the drawing to be done when the frame needs re-painting
|
24
30
|
evt_paint :on_paint
|
@@ -26,7 +32,8 @@ class ImageFrame < Wx::Frame
|
|
26
32
|
|
27
33
|
def on_paint
|
28
34
|
paint do | dc |
|
29
|
-
|
35
|
+
# Draw the bitmap at offset 10px, 10px, with no transparency
|
36
|
+
dc.draw_bitmap(@bitmap, 10, 10, false)
|
30
37
|
end
|
31
38
|
end
|
32
39
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# wxRuby2 Sample Code. Copyright (c) 2004-2008 wxRuby development team
|
3
|
+
# Freely reusable code: see SAMPLES-LICENSE.TXT for details
|
4
|
+
begin
|
5
|
+
require 'rubygems'
|
6
|
+
rescue LoadError
|
7
|
+
end
|
8
|
+
require 'wx'
|
9
|
+
|
10
|
+
# Bitmap sample (rewritten by Chauk-Mean Proum)
|
11
|
+
|
12
|
+
# This sample demonstrates how to draw the same image in various forms
|
13
|
+
# (original, mirrored, greyscaled and blurred).
|
14
|
+
#
|
15
|
+
# This sample uses :
|
16
|
+
# - Wx::Image, which allows a wide range of manipulations such as rescaling
|
17
|
+
# and writing to files.
|
18
|
+
# - Wx::Bitmap, which is a platform-specific representation of an image.
|
19
|
+
# This is the class that must be used to actually display an image.
|
20
|
+
|
21
|
+
class ImageFrame < Wx::Frame
|
22
|
+
def initialize
|
23
|
+
super(nil, :title => 'Simple image demo', :size => [600, 600])
|
24
|
+
|
25
|
+
# Create the various images from the bitmap file
|
26
|
+
img_file = File.join( File.dirname(__FILE__), 'ruby-logo.jpg')
|
27
|
+
@image = Wx::Image.new(img_file)
|
28
|
+
@mirrored_image = Wx::Image.new(img_file).mirror
|
29
|
+
@greyscaled_image = Wx::Image.new(img_file).convert_to_greyscale
|
30
|
+
@blurred_image = Wx::Image.new(img_file).blur(15)
|
31
|
+
|
32
|
+
# Create the corresponding bitmaps
|
33
|
+
compute_bitmaps
|
34
|
+
|
35
|
+
# Set up event handling
|
36
|
+
evt_size :on_size
|
37
|
+
evt_idle :on_idle
|
38
|
+
evt_paint :on_paint
|
39
|
+
end
|
40
|
+
|
41
|
+
# Create a bitmap for the specified image and size
|
42
|
+
def compute_bitmap image, width, height
|
43
|
+
rescaled_image = Wx::Image.new(image).rescale(width, height)
|
44
|
+
rescaled_image.to_bitmap
|
45
|
+
end
|
46
|
+
|
47
|
+
# Create the bitmaps corresponding to the images and with half the size of the frame
|
48
|
+
def compute_bitmaps
|
49
|
+
width = client_size.x / 2
|
50
|
+
height = client_size.y / 2
|
51
|
+
@bitmap1 = compute_bitmap(@image, width, height)
|
52
|
+
@bitmap2 = compute_bitmap(@mirrored_image, width, height)
|
53
|
+
@bitmap3 = compute_bitmap(@greyscaled_image, width, height)
|
54
|
+
@bitmap4 = compute_bitmap(@blurred_image, width, height)
|
55
|
+
@done = true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Note to recompute the bitmaps on a resize
|
59
|
+
def on_size(event)
|
60
|
+
@done = false
|
61
|
+
event.skip
|
62
|
+
end
|
63
|
+
|
64
|
+
# Recompute the bitmaps if needed, then do a refresh
|
65
|
+
def on_idle
|
66
|
+
if not @done
|
67
|
+
compute_bitmaps
|
68
|
+
refresh
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Paint the frame with the bitmaps
|
73
|
+
def on_paint
|
74
|
+
paint do | dc |
|
75
|
+
|
76
|
+
if @done
|
77
|
+
width = client_size.x / 2
|
78
|
+
height = client_size.y / 2
|
79
|
+
dc.draw_bitmap(@bitmap1, 0, 0, false)
|
80
|
+
dc.draw_bitmap(@bitmap2, width, 0, false)
|
81
|
+
dc.draw_bitmap(@bitmap3, 0, height, false)
|
82
|
+
dc.draw_bitmap(@bitmap4, width, height, false)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Wx::App.run do
|
90
|
+
ImageFrame.new.show
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,265 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# wxRuby2 Sample Code. Copyright (c) 2004-2009 wxRuby development team
|
4
|
+
# Freely reusable code: see SAMPLES-LICENSE.TXT for details
|
5
|
+
|
6
|
+
require 'wx'
|
7
|
+
include Wx
|
8
|
+
include Math
|
9
|
+
|
10
|
+
# This sample was originally written by Alex Fenton as an answer to Ruby
|
11
|
+
# Quiz #191, which challenged entrants to create an application which
|
12
|
+
# could draw images based on mathematical functions:
|
13
|
+
#
|
14
|
+
# http://rubyquiz.strd6.com/quizzes/191/
|
15
|
+
#
|
16
|
+
# To use the application, enter functions which take input values of x
|
17
|
+
# and y from 0 to 1, and return intensities of red, green and blue. If a
|
18
|
+
# bad function is entered, a cross is displayed; hover over this to get
|
19
|
+
# a hint on the problem.
|
20
|
+
#
|
21
|
+
# The sample demonstrates some uses of the Wx::Image class, a
|
22
|
+
# platform-independent representation of an image which can be
|
23
|
+
# manipulated (for example, resizing) and written to files in various
|
24
|
+
# formats. It also shows how an image's data can be written directly, by
|
25
|
+
# using Array#pack.
|
26
|
+
|
27
|
+
# A canvas that draws and displays a mathematically generated image
|
28
|
+
class MathsDrawing < Window
|
29
|
+
# The functions which return the colour components at each pixel
|
30
|
+
attr_writer :red, :green, :blue
|
31
|
+
# The time taken to render, whether re-rendering is needed, and the
|
32
|
+
# source image
|
33
|
+
attr_reader :render_time, :done, :img
|
34
|
+
|
35
|
+
def initialize(parent)
|
36
|
+
super(parent)
|
37
|
+
# Create a dummy image
|
38
|
+
@default_image = Image.new(1, 1)
|
39
|
+
@default_image.data = [255, 255, 255].pack('CCC')
|
40
|
+
@img = @default_image
|
41
|
+
|
42
|
+
@red = lambda { | x, y | 1 }
|
43
|
+
@green = lambda { | x, y | 1 }
|
44
|
+
@blue = lambda { | x, y | 1 }
|
45
|
+
|
46
|
+
@done = true
|
47
|
+
|
48
|
+
evt_size :on_size
|
49
|
+
evt_paint :on_paint
|
50
|
+
evt_idle :on_idle
|
51
|
+
end
|
52
|
+
|
53
|
+
# Paint the image on the screen. The actual image rendering is done in
|
54
|
+
# idle time, so that the GUI is responsive whilst redrawing - eg, when
|
55
|
+
# resized. Painting is done by quickly rescaling the cached image.
|
56
|
+
def on_paint
|
57
|
+
paint do | dc |
|
58
|
+
draw_img = @img.scale(client_size.x, client_size.y)
|
59
|
+
dc.draw_bitmap(draw_img.convert_to_bitmap, 0, 0, true)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Regenerate the image if needed, then do a refresh
|
64
|
+
def on_idle
|
65
|
+
if not @done
|
66
|
+
@img = make_image
|
67
|
+
refresh
|
68
|
+
end
|
69
|
+
@done = true
|
70
|
+
end
|
71
|
+
|
72
|
+
# Note to regenerate the image if the canvas has been resized
|
73
|
+
def on_size(event)
|
74
|
+
@done = false
|
75
|
+
event.skip
|
76
|
+
end
|
77
|
+
|
78
|
+
# Call this to force a re-render - eg if the functions have changed
|
79
|
+
def redraw
|
80
|
+
@done = false
|
81
|
+
end
|
82
|
+
|
83
|
+
# Actually make the image
|
84
|
+
def make_image
|
85
|
+
size_x, size_y = client_size.x, client_size.y
|
86
|
+
if size_x < 1 or size_y < 1
|
87
|
+
return @default_image
|
88
|
+
end
|
89
|
+
|
90
|
+
start_time = Time.now
|
91
|
+
# The string holding raw image data
|
92
|
+
data = ''
|
93
|
+
x_factor = size_x.to_f
|
94
|
+
y_factor = size_y.to_f
|
95
|
+
|
96
|
+
# Input values from the range 0 to 1, with origin in the bottom left
|
97
|
+
(size_y - 1).downto(0) do | y |
|
98
|
+
the_y = y.to_f / y_factor
|
99
|
+
0.upto(size_x - 1) do | x |
|
100
|
+
the_x = x.to_f / x_factor
|
101
|
+
red = @red.call(the_x, the_y) * 255
|
102
|
+
green = @green.call(the_x, the_y) * 255
|
103
|
+
blue = @blue.call(the_x, the_y) * 255
|
104
|
+
data << [red, green, blue].pack("CCC")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
img = Image.new(size_x, size_y)
|
108
|
+
img.data = data
|
109
|
+
@render_time = Time.now - start_time
|
110
|
+
img
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# A helper dialog for saving the image to a file
|
115
|
+
class SaveImageDialog < FileDialog
|
116
|
+
# The image file formats on offer
|
117
|
+
TYPES = [ [ "PNG file (*.png)|*.png", BITMAP_TYPE_PNG ],
|
118
|
+
[ "TIF file (*.tif)|*.tif", BITMAP_TYPE_TIF ],
|
119
|
+
[ "BMP file (*.bmp)|*.bmp", BITMAP_TYPE_BMP ] ]
|
120
|
+
|
121
|
+
WILDCARD = TYPES.map { | type | type.first }.join("|")
|
122
|
+
|
123
|
+
def initialize(parent)
|
124
|
+
super(parent, :wildcard => WILDCARD,
|
125
|
+
:message => 'Save Image',
|
126
|
+
:style => FD_SAVE|FD_OVERWRITE_PROMPT)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns the Wx identifier for the selected image type.
|
130
|
+
def image_type
|
131
|
+
TYPES[filter_index].last
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# A Panel for displaying the image and controls to manipulate it
|
136
|
+
class MathsPanel < Panel
|
137
|
+
# Set functions to some nice initial values
|
138
|
+
RED_INITIAL = "cos(x)"
|
139
|
+
GREEN_INITIAL = "cos(y ** x)"
|
140
|
+
BLUE_INITIAL = "(x ** 4) + ( y ** 3 ) - (4.5 * x ** 2 ) + ( y * 2)"
|
141
|
+
|
142
|
+
# Symbols to show correct and incorrect functions
|
143
|
+
TICK = "\xE2\x9C\x94"
|
144
|
+
CROSS = "\xE2\x9C\x98"
|
145
|
+
|
146
|
+
attr_reader :drawing
|
147
|
+
|
148
|
+
def initialize(parent)
|
149
|
+
super(parent)
|
150
|
+
self.sizer = VBoxSizer.new
|
151
|
+
# The canvas
|
152
|
+
@drawing = MathsDrawing.new(self)
|
153
|
+
sizer.add @drawing, 1, GROW
|
154
|
+
|
155
|
+
sizer.add Wx::StaticLine.new(self)
|
156
|
+
|
157
|
+
# The text controls for entering functions
|
158
|
+
grid_sz = FlexGridSizer.new(3, 8, 8)
|
159
|
+
grid_sz.add_growable_col(1, 1)
|
160
|
+
|
161
|
+
grid_sz.add StaticText.new(self, :label => "Red")
|
162
|
+
@red_tx = TextCtrl.new(self, :value => RED_INITIAL)
|
163
|
+
grid_sz.add @red_tx, 0, GROW
|
164
|
+
@red_err = StaticText.new(self, :label => TICK)
|
165
|
+
grid_sz.add @red_err, 0, ALIGN_CENTRE
|
166
|
+
|
167
|
+
grid_sz.add StaticText.new(self, :label => "Green")
|
168
|
+
@green_tx = TextCtrl.new(self, :value => GREEN_INITIAL)
|
169
|
+
grid_sz.add @green_tx, 0, GROW
|
170
|
+
@green_err = StaticText.new(self, :label => TICK)
|
171
|
+
grid_sz.add @green_err, 0, ALIGN_CENTRE
|
172
|
+
|
173
|
+
grid_sz.add StaticText.new(self, :label => "Blue")
|
174
|
+
@blue_tx = TextCtrl.new(self, :value => BLUE_INITIAL)
|
175
|
+
grid_sz.add @blue_tx, 0, GROW
|
176
|
+
@blue_err = StaticText.new(self, :label => TICK)
|
177
|
+
grid_sz.add @blue_err, 0, ALIGN_CENTRE
|
178
|
+
|
179
|
+
# Buttons to save and render
|
180
|
+
grid_sz.add nil
|
181
|
+
butt_sz = HBoxSizer.new
|
182
|
+
render_bt = Button.new(self, :label => "Render")
|
183
|
+
butt_sz.add render_bt, 0, Wx::RIGHT, 8
|
184
|
+
evt_button render_bt, :on_render
|
185
|
+
|
186
|
+
save_bt = Button.new(self, :label => "Save Image")
|
187
|
+
butt_sz.add save_bt, 0, Wx::RIGHT, 8
|
188
|
+
evt_button save_bt, :on_save
|
189
|
+
|
190
|
+
# Disable the buttons whilst redrawing
|
191
|
+
evt_update_ui(render_bt) { | evt | evt.enable(@drawing.done) }
|
192
|
+
evt_update_ui(save_bt) { | evt | evt.enable(@drawing.done) }
|
193
|
+
grid_sz.add butt_sz
|
194
|
+
|
195
|
+
# Add the controls sizer to the whole thing
|
196
|
+
sizer.add grid_sz, 0, GROW|ALL, 10
|
197
|
+
|
198
|
+
on_render
|
199
|
+
end
|
200
|
+
|
201
|
+
# Update the functions that generate the image, then re-render it
|
202
|
+
def on_render
|
203
|
+
@drawing.red = make_a_function(@red_tx.value, @red_err)
|
204
|
+
@drawing.green = make_a_function(@green_tx.value, @green_err)
|
205
|
+
@drawing.blue = make_a_function(@blue_tx.value, @blue_err)
|
206
|
+
@drawing.redraw
|
207
|
+
end
|
208
|
+
|
209
|
+
# Display a dialog to save the image to a file
|
210
|
+
def on_save
|
211
|
+
dlg = SaveImageDialog.new(parent)
|
212
|
+
if dlg.show_modal == ID_OK
|
213
|
+
@drawing.img.save_file(dlg.path, dlg.image_type)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# A function which doesn't do anything
|
218
|
+
NULL_FUNC = lambda { | x, y | 1 }
|
219
|
+
|
220
|
+
# Takes a string source +source+, returns a lambda. If the string
|
221
|
+
# source isn't valid, flag this in the GUI static text +error_outlet+
|
222
|
+
def make_a_function(source, error_outlet)
|
223
|
+
return NULL_FUNC if source.empty?
|
224
|
+
func = nil
|
225
|
+
begin
|
226
|
+
# Create the function and test it, to check for wrong names
|
227
|
+
func = eval "lambda { | x, y | #{source} }"
|
228
|
+
func.call(0, 0)
|
229
|
+
rescue Exception => e
|
230
|
+
error_outlet.label = CROSS
|
231
|
+
error_outlet.tool_tip = e.class.name + ":\n" +
|
232
|
+
e.message.sub(/^\(eval\):\d+: /, '')
|
233
|
+
return NULL_FUNC
|
234
|
+
end
|
235
|
+
|
236
|
+
# Things are good, note this and return the function
|
237
|
+
error_outlet.label = TICK
|
238
|
+
error_outlet.tool_tip = ''
|
239
|
+
func
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class MathsFrame < Frame
|
244
|
+
def initialize
|
245
|
+
super(nil, :title => 'Maths drawing',
|
246
|
+
:size => [400, 500],
|
247
|
+
:pos => [50, 50])
|
248
|
+
sb = create_status_bar(1)
|
249
|
+
evt_update_ui sb, :on_update_status
|
250
|
+
@panel = MathsPanel.new(self)
|
251
|
+
end
|
252
|
+
|
253
|
+
def on_update_status
|
254
|
+
if @panel.drawing.done
|
255
|
+
pixels = @panel.drawing.client_size
|
256
|
+
msg = "[#{pixels.x} x #{pixels.y}] drawing completed in " +
|
257
|
+
"#{@panel.drawing.render_time}s"
|
258
|
+
status_bar.status_text = msg
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
App.run do
|
264
|
+
MathsFrame.new.show
|
265
|
+
end
|