green_shoes 0.129.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/README.rdoc +23 -0
- data/README_old.md +132 -0
- data/lib/ext/bloops.rb +1 -0
- data/lib/ext/bloops/bloops.so +0 -0
- data/lib/ext/bloops/libportaudio-2.dll +0 -0
- data/lib/ext/bloops/songs/1901_by_Aanand_Prasad.rb +478 -0
- data/lib/ext/bloops/songs/bloopsaphone_theme_song_by_why.rb +31 -0
- data/lib/ext/bloops/songs/feepogram.rb +67 -0
- data/lib/ext/bloops/songs/simpsons_theme_song_by_why.rb +14 -0
- data/lib/ext/chipmunk.rb +34 -0
- data/lib/ext/chipmunk/chipmunk.so +0 -0
- data/lib/ext/projector.rb +1 -0
- data/lib/ext/projector/matrix3d.rb +73 -0
- data/lib/ext/projector/projector.rb +306 -0
- data/lib/green_shoes.rb +45 -0
- data/lib/shoes/anim.rb +19 -0
- data/lib/shoes/app.rb +591 -0
- data/lib/shoes/basic.rb +242 -0
- data/lib/shoes/colors.rb +150 -0
- data/lib/shoes/download.rb +26 -0
- data/lib/shoes/help.rb +171 -0
- data/lib/shoes/helper_methods.rb +308 -0
- data/lib/shoes/main.rb +99 -0
- data/lib/shoes/manual.rb +6 -0
- data/lib/shoes/mask.rb +29 -0
- data/lib/shoes/projector.rb +42 -0
- data/lib/shoes/ruby.rb +73 -0
- data/lib/shoes/slot.rb +68 -0
- data/lib/shoes/text.rb +44 -0
- data/lib/shoes/url.rb +14 -0
- data/lib/shoes/widget.rb +18 -0
- data/static/Coolvetica.ttf +0 -0
- data/static/Lacuna.ttf +0 -0
- data/static/downloading.png +0 -0
- data/static/gshoes-heading-icon.png +0 -0
- data/static/gshoes-icon.png +0 -0
- data/static/man-app.png +0 -0
- data/static/man-builds.png +0 -0
- data/static/man-builds1.png +0 -0
- data/static/man-editor-notepad.png +0 -0
- data/static/man-editor-osx.png +0 -0
- data/static/man-ele-background.png +0 -0
- data/static/man-ele-border.png +0 -0
- data/static/man-ele-button.png +0 -0
- data/static/man-ele-check.png +0 -0
- data/static/man-ele-editbox.png +0 -0
- data/static/man-ele-editline.png +0 -0
- data/static/man-ele-image.png +0 -0
- data/static/man-ele-listbox.png +0 -0
- data/static/man-ele-progress.png +0 -0
- data/static/man-ele-radio.png +0 -0
- data/static/man-ele-shape.png +0 -0
- data/static/man-ele-textblock.png +0 -0
- data/static/man-ele-video.png +0 -0
- data/static/man-intro-dmg.png +0 -0
- data/static/man-intro-exe.png +0 -0
- data/static/man-look-tiger.png +0 -0
- data/static/man-look-ubuntu.png +0 -0
- data/static/man-look-vista.png +0 -0
- data/static/man-run-osx.png +0 -0
- data/static/man-run-vista.png +0 -0
- data/static/man-run-xp.png +0 -0
- data/static/man-shot1.png +0 -0
- data/static/manual-en.txt +3523 -0
- data/static/manual-ja.txt +2825 -0
- data/static/shoes-manual-apps.png +0 -0
- metadata +146 -0
data/lib/green_shoes.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'pathname'
|
3
|
+
require 'cairo'
|
4
|
+
require 'pango'
|
5
|
+
require 'gdk_pixbuf2'
|
6
|
+
require 'gtk2'
|
7
|
+
|
8
|
+
STDOUT.sync = true
|
9
|
+
|
10
|
+
Types = module Shoes; self end
|
11
|
+
|
12
|
+
module Shoes
|
13
|
+
DIR = Pathname.new(__FILE__).realpath.dirname.to_s
|
14
|
+
TMP_PNG_FILE = File.join(Dir.tmpdir, '__green_shoes_temporary_file__')
|
15
|
+
HAND = Gdk::Cursor.new(Gdk::Cursor::HAND1)
|
16
|
+
ARROW = Gdk::Cursor.new(Gdk::Cursor::ARROW)
|
17
|
+
FONTS = Gtk::Invisible.new.pango_context.families.map(&:name).sort
|
18
|
+
LINK_DEFAULT = "<span underline='single' underline_color='#06E' foreground='#06E' weight='normal'>"
|
19
|
+
LINKHOVER_DEFAULT = "<span underline='single' underline_color='#039' foreground='#039' weight='normal'>"
|
20
|
+
ROTATE = [Gdk::Pixbuf::ROTATE_NONE, Gdk::Pixbuf::ROTATE_CLOCKWISE, Gdk::Pixbuf::ROTATE_UPSIDEDOWN, Gdk::Pixbuf::ROTATE_COUNTERCLOCKWISE]
|
21
|
+
end
|
22
|
+
|
23
|
+
class Object
|
24
|
+
remove_const :Shoes
|
25
|
+
end
|
26
|
+
|
27
|
+
require_relative 'shoes/ruby'
|
28
|
+
require_relative 'shoes/helper_methods'
|
29
|
+
require_relative 'shoes/colors'
|
30
|
+
require_relative 'shoes/basic'
|
31
|
+
require_relative 'shoes/main'
|
32
|
+
require_relative 'shoes/app'
|
33
|
+
require_relative 'shoes/anim'
|
34
|
+
require_relative 'shoes/slot'
|
35
|
+
require_relative 'shoes/text'
|
36
|
+
require_relative 'shoes/mask'
|
37
|
+
require_relative 'shoes/widget'
|
38
|
+
require_relative 'shoes/url'
|
39
|
+
require_relative 'shoes/projector'
|
40
|
+
require_relative 'shoes/download'
|
41
|
+
require_relative 'shoes/manual'
|
42
|
+
|
43
|
+
autoload :ChipMunk, File.join(Shoes::DIR, 'ext/chipmunk')
|
44
|
+
autoload :Bloops, File.join(Shoes::DIR, 'ext/bloops')
|
45
|
+
autoload :Projector, File.join(Shoes::DIR, 'ext/projector')
|
data/lib/shoes/anim.rb
ADDED
data/lib/shoes/app.rb
ADDED
@@ -0,0 +1,591 @@
|
|
1
|
+
class Shoes
|
2
|
+
class App
|
3
|
+
include Types
|
4
|
+
include Mod2
|
5
|
+
|
6
|
+
def initialize args={}
|
7
|
+
args.each do |k, v|
|
8
|
+
instance_variable_set "@#{k}", v
|
9
|
+
end
|
10
|
+
|
11
|
+
App.class_eval do
|
12
|
+
attr_accessor *(args.keys - [:width, :height, :title])
|
13
|
+
end
|
14
|
+
|
15
|
+
init_app_vars
|
16
|
+
@canvas, @win, @swin, @top_slot = nil
|
17
|
+
@cslot = (@app ||= self)
|
18
|
+
@width_pre, @height_pre = @width, @height
|
19
|
+
@link_style, @linkhover_style = LINK_DEFAULT, LINKHOVER_DEFAULT
|
20
|
+
@context_angle = @pixbuf_rotate = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :cslot, :cmask, :top_slot, :contents, :canvas, :app, :mccs, :mrcs, :mmcs,
|
24
|
+
:mhcs, :mlcs, :shcs, :mcs, :win, :swin, :width_pre, :height_pre, :order, :dics
|
25
|
+
attr_writer :mouse_button, :mouse_pos
|
26
|
+
attr_reader :link_style, :linkhover_style
|
27
|
+
|
28
|
+
def visit url
|
29
|
+
$urls.each do |k, v|
|
30
|
+
clear{init_app_vars; v.call self, $1} if k =~ url
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def stack args={}, &blk
|
35
|
+
args[:app] = self
|
36
|
+
Stack.new slot_attributes(args), &blk
|
37
|
+
end
|
38
|
+
|
39
|
+
def flow args={}, &blk
|
40
|
+
args[:app] = self
|
41
|
+
Flow.new slot_attributes(args), &blk
|
42
|
+
end
|
43
|
+
|
44
|
+
def mask &blk
|
45
|
+
Mask.new(self, &blk).tap{|m| @mcs << m}
|
46
|
+
end
|
47
|
+
|
48
|
+
def clear &blk
|
49
|
+
mcs.each &:clear
|
50
|
+
@top_slot.clear &blk
|
51
|
+
end
|
52
|
+
|
53
|
+
def style klass, args={}
|
54
|
+
if klass == Shoes::Link
|
55
|
+
@link_style = LINK_DEFAULT
|
56
|
+
@link_style.sub!('single', 'none') if args[:underline] == false
|
57
|
+
@link_style.sub!("foreground='#06E'", "foreground='#{args[:stroke]}'") if args[:stroke]
|
58
|
+
@link_style.sub!('>', " background='#{args[:fill]}'>") if args[:fill]
|
59
|
+
@link_style.sub!('normal', "#{args[:weight]}") if args[:weight]
|
60
|
+
elsif klass == Shoes::LinkHover
|
61
|
+
@linkhover_style = LINKHOVER_DEFAULT
|
62
|
+
@linkhover_style.sub!('single', 'none') if args[:underline] == false
|
63
|
+
@linkhover_style.sub!("foreground='#039'", "foreground='#{args[:stroke]}'") if args[:stroke]
|
64
|
+
@linkhover_style.sub!('>', " background='#{args[:fill]}'>") if args[:fill]
|
65
|
+
@linkhover_style.sub!('normal', "#{args[:weight]}") if args[:weight]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def textblock klass, font_size, *msg
|
70
|
+
args = msg.last.class == Hash ? msg.pop : {}
|
71
|
+
args = basic_attributes args
|
72
|
+
msg = msg.map{|s| s == self ? s.to_s.gsub('<', '[').gsub('>', ']') : s}
|
73
|
+
args[:markup] = msg.map(&:to_s).join
|
74
|
+
attr_list, dummy_text = Pango.parse_markup args[:markup].gsub('\u0026', '@')
|
75
|
+
dummy_attr_list, text = Pango.parse_markup args[:markup]
|
76
|
+
text = text.gsub('\u0026', '&')
|
77
|
+
args[:size] ||= font_size
|
78
|
+
args[:font] ||= (@font_family or 'sans')
|
79
|
+
args[:align] ||= 'left'
|
80
|
+
line_height = args[:size] * 2
|
81
|
+
|
82
|
+
args[:links] = make_link_index(msg) unless args[:links]
|
83
|
+
|
84
|
+
if !(args[:left].zero? and args[:top].zero?) and (args[:width].zero? or args[:height].zero?)
|
85
|
+
args[:nocontrol], args[:width], args[:height] = true, self.width, self.height
|
86
|
+
layout_control = false
|
87
|
+
else
|
88
|
+
layout_control = true
|
89
|
+
end
|
90
|
+
|
91
|
+
if args[:create_real] or !layout_control
|
92
|
+
surface = Cairo::ImageSurface.new Cairo::FORMAT_ARGB32, args[:width], args[:height]
|
93
|
+
context = Cairo::Context.new surface
|
94
|
+
layout = context.create_pango_layout
|
95
|
+
layout.width = args[:width] * Pango::SCALE
|
96
|
+
layout.wrap = Pango::WRAP_WORD
|
97
|
+
layout.spacing = 5 * Pango::SCALE
|
98
|
+
layout.text = text
|
99
|
+
layout.alignment = eval "Pango::ALIGN_#{args[:align].upcase}"
|
100
|
+
fd = Pango::FontDescription.new
|
101
|
+
fd.family = args[:font]
|
102
|
+
fd.size = args[:size] * Pango::SCALE
|
103
|
+
layout.font_description = fd
|
104
|
+
layout.attributes = attr_list
|
105
|
+
context.show_pango_layout layout
|
106
|
+
context.show_page
|
107
|
+
|
108
|
+
make_link_pos args[:links], layout, line_height
|
109
|
+
|
110
|
+
args[:height] = layout.line_count * line_height
|
111
|
+
img = create_tmp_png surface
|
112
|
+
@canvas.put img, args[:left], args[:top]
|
113
|
+
img.show_now
|
114
|
+
args[:real], args[:noorder] = img, layout_control
|
115
|
+
else
|
116
|
+
args[:real] = false
|
117
|
+
end
|
118
|
+
|
119
|
+
args[:app] = self
|
120
|
+
klass.new args
|
121
|
+
end
|
122
|
+
|
123
|
+
def banner *msg; textblock Banner, 48, *msg; end
|
124
|
+
def title *msg; textblock Title, 34, *msg; end
|
125
|
+
def subtitle *msg; textblock Subtitle, 26, *msg; end
|
126
|
+
def tagline *msg; textblock Tagline, 18, *msg; end
|
127
|
+
def caption *msg; textblock Caption, 14, *msg; end
|
128
|
+
def para *msg; textblock Para, 12, *msg; end
|
129
|
+
def inscription *msg; textblock Para, 10, *msg; end
|
130
|
+
|
131
|
+
def image name, args={}
|
132
|
+
args = basic_attributes args
|
133
|
+
if name =~ /^(http|https):\/\//
|
134
|
+
tmpname = File.join(Dir.tmpdir, "__green_shoes_#{Time.now.to_f}.png")
|
135
|
+
d = download name, save: tmpname
|
136
|
+
img = Gtk::Image.new File.join(DIR, '../static/downloading.png')
|
137
|
+
downloading = true
|
138
|
+
else
|
139
|
+
img = Gtk::Image.new name
|
140
|
+
downloading = false
|
141
|
+
end
|
142
|
+
if (!args[:width].zero? or !args[:height].zero?) and !downloading
|
143
|
+
w, h = imagesize(name)
|
144
|
+
args[:width] = w if args[:width].zero?
|
145
|
+
args[:height] = w if args[:height].zero?
|
146
|
+
img = Gtk::Image.new img.pixbuf.scale(args[:width], args[:height])
|
147
|
+
end
|
148
|
+
@canvas.put img, args[:left], args[:top]
|
149
|
+
img.show_now
|
150
|
+
args[:real], args[:app] = img, self
|
151
|
+
Image.new(args).tap{|s| @dics.push([s, d, tmpname]) if downloading}
|
152
|
+
end
|
153
|
+
|
154
|
+
def imagesize name
|
155
|
+
Gtk::Image.new(name).size_request
|
156
|
+
end
|
157
|
+
|
158
|
+
def button name, args={}, &blk
|
159
|
+
args = basic_attributes args
|
160
|
+
b = Gtk::Button.new name
|
161
|
+
b.set_size_request args[:width], args[:height] if args[:width] > 0 and args[:height] > 0
|
162
|
+
b.signal_connect "clicked", &blk if blk
|
163
|
+
@canvas.put b, args[:left], args[:top]
|
164
|
+
b.show_now
|
165
|
+
args[:real], args[:text], args[:app] = b, name, self
|
166
|
+
Button.new args
|
167
|
+
end
|
168
|
+
|
169
|
+
def edit_line args={}
|
170
|
+
args = basic_attributes args
|
171
|
+
args[:width] = 200 if args[:width].zero?
|
172
|
+
el = Gtk::Entry.new
|
173
|
+
el.text = args[:text].to_s
|
174
|
+
el.width_chars = args[:width] / 6
|
175
|
+
el.signal_connect "changed" do
|
176
|
+
yield el
|
177
|
+
end if block_given?
|
178
|
+
@canvas.put el, args[:left], args[:top]
|
179
|
+
el.show_now
|
180
|
+
args[:real], args[:app] = el, self
|
181
|
+
EditLine.new args
|
182
|
+
end
|
183
|
+
|
184
|
+
def edit_box args={}
|
185
|
+
args = basic_attributes args
|
186
|
+
args[:width] = 200 if args[:width].zero?
|
187
|
+
args[:height] = 200 if args[:height].zero?
|
188
|
+
tv = Gtk::TextView.new
|
189
|
+
tv.wrap_mode = Gtk::TextTag::WRAP_WORD
|
190
|
+
tv.buffer.text = args[:text].to_s
|
191
|
+
|
192
|
+
eb = Gtk::ScrolledWindow.new
|
193
|
+
eb.set_size_request args[:width], args[:height]
|
194
|
+
eb.set_policy Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC
|
195
|
+
eb.set_shadow_type Gtk::SHADOW_IN
|
196
|
+
eb.add tv
|
197
|
+
|
198
|
+
tv.buffer.signal_connect "changed" do
|
199
|
+
yield tv.buffer
|
200
|
+
end if block_given?
|
201
|
+
|
202
|
+
@canvas.put eb, args[:left], args[:top]
|
203
|
+
eb.show_now
|
204
|
+
args[:real], args[:app], args[:textview] = eb, self, tv
|
205
|
+
EditBox.new args
|
206
|
+
end
|
207
|
+
|
208
|
+
def list_box args={}, &blk
|
209
|
+
args = basic_attributes args
|
210
|
+
args[:width] = 200 if args[:width].zero?
|
211
|
+
cb = Gtk::ComboBox.new
|
212
|
+
args[:items] ||= []
|
213
|
+
args[:items].each{|item| cb.append_text item.to_s}
|
214
|
+
cb.active = args[:items].index(args[:choose]) if args[:choose]
|
215
|
+
cb.signal_connect("changed") do
|
216
|
+
blk.call args[:items][cb.active]
|
217
|
+
end if blk
|
218
|
+
@canvas.put cb, args[:left], args[:top]
|
219
|
+
cb.show_now
|
220
|
+
args[:real], args[:app] = cb, self
|
221
|
+
ListBox.new args
|
222
|
+
end
|
223
|
+
|
224
|
+
def animate n=10, repaint=true, &blk
|
225
|
+
n, i = 1000 / n, 0
|
226
|
+
a = Anim.new
|
227
|
+
GLib::Timeout.add n do
|
228
|
+
blk[i = a.pause? ? i : i+1]
|
229
|
+
Shoes.repaint_all_by_order self if repaint
|
230
|
+
a.continue?
|
231
|
+
end
|
232
|
+
a
|
233
|
+
end
|
234
|
+
|
235
|
+
def every n=1, &blk
|
236
|
+
animate 1.0/n, &blk
|
237
|
+
end
|
238
|
+
|
239
|
+
def timer n=1, &blk
|
240
|
+
GLib::Timeout.add 1000*n do
|
241
|
+
blk.call
|
242
|
+
Shoes.repaint_all_by_order self
|
243
|
+
false
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def motion &blk
|
248
|
+
@mmcs << blk
|
249
|
+
end
|
250
|
+
|
251
|
+
def keypress &blk
|
252
|
+
win.set_events Gdk::Event::BUTTON_PRESS_MASK | Gdk::Event::BUTTON_RELEASE_MASK | Gdk::Event::POINTER_MOTION_MASK | Gdk::Event::KEY_PRESS_MASK
|
253
|
+
win.signal_connect("key_press_event") do |w, e|
|
254
|
+
blk[Gdk::Keyval.to_name(e.keyval)]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def mouse
|
259
|
+
[@mouse_button, @mouse_pos[0], @mouse_pos[1]]
|
260
|
+
end
|
261
|
+
|
262
|
+
def oval *attrs
|
263
|
+
args = attrs.last.class == Hash ? attrs.pop : {}
|
264
|
+
case attrs.length
|
265
|
+
when 0, 1
|
266
|
+
when 2; args[:left], args[:top] = attrs
|
267
|
+
when 3; args[:left], args[:top], args[:radius] = attrs
|
268
|
+
else args[:left], args[:top], args[:width], args[:height] = attrs
|
269
|
+
end
|
270
|
+
args = basic_attributes args
|
271
|
+
args[:width].zero? ? (args[:width] = args[:radius] * 2) : (args[:radius] = args[:width]/2.0)
|
272
|
+
args[:height] = args[:width] if args[:height].zero?
|
273
|
+
args[:strokewidth] = ( args[:strokewidth] or strokewidth or 1 )
|
274
|
+
|
275
|
+
w, h, mx, my = set_rotate_angle(args)
|
276
|
+
my *= args[:width]/args[:height].to_f
|
277
|
+
|
278
|
+
surface = Cairo::ImageSurface.new Cairo::FORMAT_ARGB32, w, h
|
279
|
+
context = Cairo::Context.new surface
|
280
|
+
context.rotate @context_angle
|
281
|
+
context.scale(1, args[:height]/args[:width].to_f)
|
282
|
+
|
283
|
+
if pat = (args[:fill] or fill)
|
284
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
285
|
+
context.set_source gp
|
286
|
+
context.arc args[:radius]+mx, args[:radius]-my, args[:radius], 0, 2*Math::PI
|
287
|
+
context.fill
|
288
|
+
end
|
289
|
+
|
290
|
+
pat = (args[:stroke] or stroke)
|
291
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
292
|
+
context.set_source gp
|
293
|
+
context.set_line_width args[:strokewidth]
|
294
|
+
context.arc args[:radius]+mx, args[:radius]-my, args[:radius]-args[:strokewidth]/2.0, 0, 2*Math::PI
|
295
|
+
context.stroke
|
296
|
+
|
297
|
+
img = create_tmp_png surface
|
298
|
+
img = Gtk::Image.new img.pixbuf.rotate(ROTATE[@pixbuf_rotate])
|
299
|
+
@canvas.put img, args[:left], args[:top]
|
300
|
+
img.show_now
|
301
|
+
args[:real], args[:app] = img, self
|
302
|
+
Oval.new args
|
303
|
+
end
|
304
|
+
|
305
|
+
def rect *attrs
|
306
|
+
args = attrs.last.class == Hash ? attrs.pop : {}
|
307
|
+
case attrs.length
|
308
|
+
when 0, 1
|
309
|
+
when 2; args[:left], args[:top] = attrs
|
310
|
+
when 3; args[:left], args[:top], args[:width] = attrs
|
311
|
+
else args[:left], args[:top], args[:width], args[:height] = attrs
|
312
|
+
end
|
313
|
+
args[:height] = args[:width] unless args[:height]
|
314
|
+
sw = args[:strokewidth] = ( args[:strokewidth] or strokewidth or 1 )
|
315
|
+
|
316
|
+
w, h, mx, my = set_rotate_angle(args)
|
317
|
+
|
318
|
+
args = basic_attributes args
|
319
|
+
surface = Cairo::ImageSurface.new Cairo::FORMAT_ARGB32, w, h
|
320
|
+
context = Cairo::Context.new surface
|
321
|
+
|
322
|
+
context.rotate @context_angle
|
323
|
+
|
324
|
+
if pat = (args[:fill] or fill)
|
325
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
326
|
+
context.set_source gp
|
327
|
+
context.rounded_rectangle mx, -my, args[:width], args[:height], args[:curve]
|
328
|
+
context.fill
|
329
|
+
end
|
330
|
+
|
331
|
+
pat = (args[:stroke] or stroke)
|
332
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
333
|
+
context.set_source gp
|
334
|
+
context.set_line_width sw
|
335
|
+
context.rounded_rectangle sw/2.0+mx, sw/2.0-my, args[:width]-sw, args[:height]-sw, args[:curve]
|
336
|
+
context.stroke
|
337
|
+
|
338
|
+
img = create_tmp_png surface
|
339
|
+
img = Gtk::Image.new img.pixbuf.rotate(ROTATE[@pixbuf_rotate])
|
340
|
+
@canvas.put img, args[:left], args[:top]
|
341
|
+
img.show_now
|
342
|
+
args[:real], args[:app] = img, self
|
343
|
+
Rect.new args
|
344
|
+
end
|
345
|
+
|
346
|
+
def line *attrs
|
347
|
+
args = attrs.last.class == Hash ? attrs.pop : {}
|
348
|
+
case attrs.length
|
349
|
+
when 0, 1, 2
|
350
|
+
when 3; args[:sx], args[:sy], args[:ex] = attrs; args[:ey] = args[:ex]
|
351
|
+
else args[:sx], args[:sy], args[:ex], args[:ey] = attrs
|
352
|
+
end
|
353
|
+
sx, sy, ex, ey = args[:sx], args[:sy], args[:ex], args[:ey]
|
354
|
+
sw = args[:strokewidth] = ( args[:strokewidth] or strokewidth or 1 )
|
355
|
+
hsw = sw*0.5
|
356
|
+
args[:width], args[:height] = (sx - ex).abs, (sy - ey).abs
|
357
|
+
|
358
|
+
args = basic_attributes args
|
359
|
+
surface = Cairo::ImageSurface.new Cairo::FORMAT_ARGB32, args[:width]+sw, args[:height]+sw
|
360
|
+
context = Cairo::Context.new surface
|
361
|
+
|
362
|
+
pat = (args[:stroke] or stroke)
|
363
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
364
|
+
context.set_source gp
|
365
|
+
context.set_line_width args[:strokewidth]
|
366
|
+
|
367
|
+
if ((sx - ex) < 0 and (sy - ey) < 0) or ((sx - ex) > 0 and (sy - ey) > 0)
|
368
|
+
context.move_to hsw, hsw
|
369
|
+
context.line_to args[:width]+hsw, args[:height]+hsw
|
370
|
+
args[:left] = (sx - ex) < 0 ? sx - hsw : ex - hsw
|
371
|
+
args[:top] = (sy - ey) < 0 ? sy - hsw : ey - hsw
|
372
|
+
elsif ((sx - ex) < 0 and (sy - ey) > 0) or ((sx - ex) > 0 and (sy - ey) < 0)
|
373
|
+
context.move_to hsw, args[:height] + hsw
|
374
|
+
context.line_to args[:width]+hsw, hsw
|
375
|
+
args[:left] = (sx - ex) < 0 ? sx - hsw : ex - hsw
|
376
|
+
args[:top] = (sy - ey) < 0 ? sy - hsw : ey - hsw
|
377
|
+
elsif !(sx - ex).zero? and (sy - ey).zero?
|
378
|
+
context.move_to 0, hsw
|
379
|
+
context.line_to args[:width], hsw
|
380
|
+
args[:left] = (sx - ex) < 0 ? sx : ex
|
381
|
+
args[:top] = (sy - ey) < 0 ? sy - hsw : ey - hsw
|
382
|
+
elsif (sx - ex).zero? and !(sy - ey).zero?
|
383
|
+
context.move_to hsw, 0
|
384
|
+
context.line_to hsw, args[:height]
|
385
|
+
args[:left] = (sx - ex) < 0 ? sx - hsw : ex - hsw
|
386
|
+
args[:top] = (sy - ey) < 0 ? sy : ey
|
387
|
+
else
|
388
|
+
context.move_to 0, 0
|
389
|
+
context.line_to 0, 0
|
390
|
+
args[:left] = sw
|
391
|
+
args[:top] = sy
|
392
|
+
end
|
393
|
+
|
394
|
+
context.stroke
|
395
|
+
img = create_tmp_png surface
|
396
|
+
@canvas.put img, args[:left], args[:top]
|
397
|
+
img.show_now
|
398
|
+
args[:real], args[:app] = img, self
|
399
|
+
Line.new args
|
400
|
+
end
|
401
|
+
|
402
|
+
def shapebase klass, args
|
403
|
+
blk = args[:block]
|
404
|
+
args[:width] ||= 300
|
405
|
+
args[:height] ||= 300
|
406
|
+
|
407
|
+
w, h, mx, my = set_rotate_angle(args)
|
408
|
+
|
409
|
+
args = basic_attributes args
|
410
|
+
surface = Cairo::ImageSurface.new Cairo::FORMAT_ARGB32, w, h
|
411
|
+
context = Cairo::Context.new surface
|
412
|
+
args[:strokewidth] = ( args[:strokewidth] or strokewidth or 1 )
|
413
|
+
context.set_line_width args[:strokewidth]
|
414
|
+
|
415
|
+
context.rotate @context_angle
|
416
|
+
|
417
|
+
mk_path = proc do |pat|
|
418
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
419
|
+
context.set_source gp
|
420
|
+
context.move_to 0, 0
|
421
|
+
klass == Shoes::Star ? context.instance_eval{blk[self, mx, -my]} : context.instance_eval(&blk)
|
422
|
+
end
|
423
|
+
|
424
|
+
if pat = (args[:fill] or fill)
|
425
|
+
mk_path.call pat
|
426
|
+
context.fill
|
427
|
+
end
|
428
|
+
|
429
|
+
mk_path.call (args[:stroke] or stroke)
|
430
|
+
context.stroke
|
431
|
+
|
432
|
+
img = create_tmp_png surface
|
433
|
+
img = Gtk::Image.new img.pixbuf.rotate(ROTATE[@pixbuf_rotate])
|
434
|
+
@canvas.put img, args[:left], args[:top]
|
435
|
+
img.show_now
|
436
|
+
args[:real], args[:app] = img, self
|
437
|
+
klass.new args
|
438
|
+
end
|
439
|
+
|
440
|
+
def shape args, &blk
|
441
|
+
args[:block] = blk
|
442
|
+
shapebase Shape, args
|
443
|
+
end
|
444
|
+
|
445
|
+
def star *attrs
|
446
|
+
args = attrs.last.class == Hash ? attrs.pop : {}
|
447
|
+
case attrs.length
|
448
|
+
when 2; args[:left], args[:top] = attrs
|
449
|
+
when 5; args[:left], args[:top], args[:points], args[:outer], args[:inner] = attrs
|
450
|
+
else
|
451
|
+
end
|
452
|
+
args[:points] ||= 10; args[:outer] ||= 100.0; args[:inner] ||= 50.0
|
453
|
+
args[:width] = args[:height] = args[:outer]*2.0
|
454
|
+
x = y = outer = args[:outer]
|
455
|
+
points, inner = args[:points], args[:inner]
|
456
|
+
|
457
|
+
args[:block] = proc do |s, mx, my|
|
458
|
+
x += mx; y += my
|
459
|
+
s.move_to x, y + outer
|
460
|
+
(1..points*2).each do |i|
|
461
|
+
angle = i * Math::PI / points
|
462
|
+
r = (i % 2 == 0) ? outer : inner
|
463
|
+
s.line_to x + r * Math.sin(angle), y + r * Math.cos(angle)
|
464
|
+
end
|
465
|
+
end
|
466
|
+
shapebase Star, args
|
467
|
+
end
|
468
|
+
|
469
|
+
def rotate angle
|
470
|
+
@pixbuf_rotate, angle = angle.divmod(90)
|
471
|
+
@pixbuf_rotate %= 4
|
472
|
+
@context_angle = Math::PI * angle / 180
|
473
|
+
end
|
474
|
+
|
475
|
+
def rgb r, g, b, l=1.0
|
476
|
+
(r < 1 and g < 1 and b < 1) ? [r, g, b, l] : [r/255.0, g/255.0, b/255.0, l]
|
477
|
+
end
|
478
|
+
|
479
|
+
%w[fill stroke strokewidth].each do |name|
|
480
|
+
eval "def #{name} #{name}=nil; #{name} ? @#{name}=#{name} : @#{name} end"
|
481
|
+
end
|
482
|
+
|
483
|
+
def nostroke
|
484
|
+
strokewidth 0
|
485
|
+
end
|
486
|
+
|
487
|
+
def nofill
|
488
|
+
@fill = false
|
489
|
+
end
|
490
|
+
|
491
|
+
def gradient pat, w, h, angle=0
|
492
|
+
pat = tr_color pat
|
493
|
+
color = case pat
|
494
|
+
when Range; [tr_color(pat.first), tr_color(pat.last)]
|
495
|
+
when Array; [pat, pat]
|
496
|
+
when String
|
497
|
+
sp = Cairo::SurfacePattern.new Cairo::ImageSurface.from_png(pat)
|
498
|
+
return sp.set_extend(Cairo::Extend::REPEAT)
|
499
|
+
else
|
500
|
+
[black, black]
|
501
|
+
end
|
502
|
+
dx, dy = w*angle/180.0, h*angle/180.0
|
503
|
+
lp = Cairo::LinearPattern.new w*0.5-dx, dy, w*0.5+dx, h-dy
|
504
|
+
lp.add_color_stop_rgba 0, *color[0]
|
505
|
+
lp.add_color_stop_rgba 1, *color[1]
|
506
|
+
lp
|
507
|
+
end
|
508
|
+
|
509
|
+
def tr_color pat
|
510
|
+
if pat.is_a?(String) and pat[0] == '#'
|
511
|
+
color = pat[1..-1]
|
512
|
+
color = color.gsub(/(.)/){$1 + '0'} if color.length == 3
|
513
|
+
rgb *color.gsub(/(..)/).map{$1.hex}
|
514
|
+
else
|
515
|
+
pat
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
def background pat, args={}
|
520
|
+
args[:pattern] = pat
|
521
|
+
args = basic_attributes args
|
522
|
+
|
523
|
+
if args[:create_real] and !args[:height].zero?
|
524
|
+
surface = Cairo::ImageSurface.new Cairo::FORMAT_ARGB32, args[:width], args[:height]
|
525
|
+
context = Cairo::Context.new surface
|
526
|
+
context.rounded_rectangle 0, 0, args[:width], args[:height], args[:curve]
|
527
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
528
|
+
context.set_source gp
|
529
|
+
context.fill
|
530
|
+
img = create_tmp_png surface
|
531
|
+
@canvas.put img, args[:left], args[:top]
|
532
|
+
img.show_now
|
533
|
+
args[:real] = img
|
534
|
+
else
|
535
|
+
args[:real] = false
|
536
|
+
end
|
537
|
+
|
538
|
+
args[:app] = self
|
539
|
+
Background.new args
|
540
|
+
end
|
541
|
+
|
542
|
+
def border pat, args={}
|
543
|
+
args[:pattern] = pat
|
544
|
+
args = basic_attributes args
|
545
|
+
sw = args[:strokewidth] = ( args[:strokewidth] or strokewidth or 1 )
|
546
|
+
|
547
|
+
if args[:create_real] and !args[:height].zero?
|
548
|
+
surface = Cairo::ImageSurface.new Cairo::FORMAT_ARGB32, args[:width], args[:height]
|
549
|
+
context = Cairo::Context.new surface
|
550
|
+
gp = gradient pat, args[:width], args[:height], args[:angle]
|
551
|
+
context.set_source gp
|
552
|
+
context.set_line_width sw
|
553
|
+
context.rounded_rectangle sw/2.0, sw/2.0, args[:width]-sw, args[:height]-sw, args[:curve]
|
554
|
+
context.stroke
|
555
|
+
|
556
|
+
img = create_tmp_png surface
|
557
|
+
@canvas.put img, args[:left], args[:top]
|
558
|
+
img.show_now
|
559
|
+
args[:real] = img
|
560
|
+
else
|
561
|
+
args[:real] = false
|
562
|
+
end
|
563
|
+
|
564
|
+
args[:app] = self
|
565
|
+
Border.new args
|
566
|
+
end
|
567
|
+
|
568
|
+
def progress args={}
|
569
|
+
args = basic_attributes args
|
570
|
+
args[:width] = 150 if args[:width] < 150
|
571
|
+
pb = Gtk::ProgressBar.new
|
572
|
+
pb.text = ' ' * (args[:width] / 4 - 2)
|
573
|
+
@canvas.put pb, args[:left], args[:top]
|
574
|
+
pb.show_now
|
575
|
+
args[:real], args[:app], args[:noorder], args[:nocontrol] = pb, self, true, true
|
576
|
+
Progress.new args
|
577
|
+
end
|
578
|
+
|
579
|
+
def download name, args={}, &blk
|
580
|
+
Download.new name, args, &blk
|
581
|
+
end
|
582
|
+
|
583
|
+
def nolayout
|
584
|
+
@nolayout = true
|
585
|
+
end
|
586
|
+
|
587
|
+
def scroll_top
|
588
|
+
@swin.vadjustment.value
|
589
|
+
end
|
590
|
+
end
|
591
|
+
end
|