samples/draw.rb
# Creative Commons BY-SA : Regis d'Aubarede <regis.aubarede@gmail.com>
# LGPL
puts "Not terminted !!!!!"
require_relative '../lib/ruiby'
############################### Complete ruiby dsl for vector widget
module Ruiby_dsl
def vector(w,h,options={})
win=nil
stack {
win=Vector::VCanvas.new(self,w,h,options)
slot(win.widget)
}
win
end
def editable_vector(w,h,options={})
win=nil
stack {
win=Vector::VCanvas_editable.new(self,w,h,options)
slot(win.widget)
}
win
end
end
############################## define basic vector widget (not editable)
# end each vector type
module Vector
class Bbox
def initialize(*l)
@x0,@y0,@x1,@y1=999999,999999,-999999,-999999
if l.size==2 && Numeric===l[0]
@x0=@x1=l[0]
@y0=@y1=l[1]
elsif l.size==4 && Numeric===l[0]
add_point(l[0],l[1])
add_point(l[2],l[3])
end
end
def values() [@x0,@y0,@x1,@y1] end
def pvalues() [[@x0,@y0],[@x1,@y0],[@x1,@y1],[@x0,@y1]] end
def add_lpoints(l) l.each { |(x,y)| add_point(x,y) } ; self end
def <<(a,b=nil,c=nil,d=nil)
if b==nil
Bbox === a ? add_bbox(a) : Array===a ? add_point(*a) : raise("error param bbox << ...")
elsif c==nil
add_point(a,b)
else
add_point(a,b)
add_point(c,d)
end
self
end
def add_point(x,y)
@x0=x if x<@x0
@y0=x if y<@y0
@x1=x if x>@x1
@y1=y if y>@y1
self
end
def add_bbox(box)
a,b,a1,b1=*box.values
@x0=a if a<@x0
@y0=b if b<@y0
@x1=a1 if a1>@x1
@y1=b1 if b1>@y1
self
end
end
class VCanvas
def initialize(win,w,h,options)
@layers=[[],[]]
@mode=:nil
@cv=win.canvas(w,h,{
:expose => proc { |w,ctx| self.expose(w,ctx) },
:mouse_down => proc { |w,e| self.send(@mode.to_s+"_mouse_down",e) },
:mouse_move => proc { |w,e,o| self.send(@mode.to_s+"_mouse_move",e) },
:mouse_up => proc { |w,e,o| self.send(@mode.to_s+"_mouse_up",e) }
})
end
def prt(*txt) puts "%-80s | %s" % [txt.map { |o| String===o ? o : o.inspect}.join(", ")[0..79],caller[0].to_s.split(/\//)[-1]] end
def prt2(*txt) puts "%-80s | %s" % [txt.map { |o| String===o ? o : o.inspect}.join(", ")[0..79],caller[1].to_s.split(/\//)[-1]] end
def to_svg(out)
str=<<EEND
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
x-width="%W%"
x-height="%H%"
viewport="0 0 %W% %H%"
version="1.1"
sodipodi:docname="%NAME%">
EEND
x0,y0,x1,y1=bbox().values
out << str.gsub(/%[^%]+%/,{
"%W%" => x1.to_s,
"%H%" => y1.to_s,
"%NAME%" => "draw.svg"
})
@layers[1].each{ |v| v.to_svg(out) }
out << "\n</svg>"
end
def save_to_rdr(name)
File.open(name,"wb") { |f| Marshal.dump(@layers[1],f) }
end
def load_from_rdr(name)
File.open(name,"rb") { |f| @layers[1]=Marshal.load(f) }
end
def bbox()
@layers[1].inject(Bbox.new) { |bb,v| v.append_to_bbox(bb) }
end
def widget() @cv end
def clear
@layers=[[],[]]
@mode=:nil
redraw
end
def expose(w,ctx)
@layers.reverse.each { |l| l.each {|v| v.draw(w,ctx) } }
end
def rotate(x,y,r)
@layers.each { |l| l.each {|v| v.rotate(x,y,r) } }
redraw
end
def scale(x,y,rx,ry)
@layers.each { |l| l.each {|v| v.scale(x,y,rx,ry) } }
redraw
end
def redraw(e=nil)
if defined?($app) && e
$app.rstatus("#{e.x}, #{e.y}")
end
@cv.redraw()
end
#------------------ Query
def find_cover_bbox(x0,y0,x1,y1,nolayer=1)
@layers[nolayer].select { |v| v.cover_bbox?(x0,y0,x1,y1) }
end
def find_into_bbox(x0,y0,x1,y1,nolayer=1)
@layers[nolayer].select { |v| v.into_bbox?(x0,y0,x1,y1) }
end
def find_nearest(x0,y0,nolayer=1)
return nil if @layers[1].size==0
l=@layers[nolayer].map { |v| [v,v.distance(x0,y0)] }.sort { |a,b|
a[1] <=> b[1]
}
l[0][0]
end
def find_hoover(x0,y0,nolayer=1)
@layers[nolayer].select { |v| v.hoover_point?(x0,y0) }[0]
end
def nil_mouse_down(e) end
def nil_mouse_move(e) redraw(e) end
def nil_mouse_up(e) redraw(e) end
end
class VElem
def initialize() @lpoints=[];@style={} end
def bbox()
@lpoints.inject(Bbox.new){ |bb,p| bb << [p[0],p[1]] }
end
def append_to_bbox(box)
@lpoints.each { |p| box << [p[0],p[1]] }
box
end
def vclone()
n=self.clone
n.lpoints=lpoints.clone
n.set_style(@style.clone)
n
end
def to_svg(out)
out << " <#{self.svg_tag()} dr='#{self.class}' d='#{self.svg_path()}' style='#{self.svg_style}'/>\n"
end
def svg_tag() "path" end
def svg_path() "M"+lpoints.map {|p| "#{p[0]},#{p[1]}" }.join(" L") end
def svg_style() "fill:##{svgc(:fill_color)};fill-opacity:#{1};stroke:##{svgc(:stroke_color)};stroke-width:#{@style[:stroke_width]||"0"};" end
def svgc(name) @style[name] ? "%02X%02X%02X" % @style[name].map { |v| (v*255).round } : "000000" end
def lpoints() @lpoints end
def lpoints=(l) @lpoints=l end
def set_style(s) @style=s.clone end
def get_style(s) @style.clone end
def draw(w,ctx)
return if @lpoints.size==0
define_style_before(ctx)
render(ctx)
define_style_after(ctx)
end
def define_style_before(ctx)
ctx.set_line_width(@style[:stroke_width]) if @style[:stroke_width]
ctx.set_source_rgba(@style[:stroke_color][0], @style[:stroke_color][1], @style[:stroke_color][2], 1) if @style[:stroke_color]
end
def render() raise('abstract') end
def define_style_after(ctx)
end
def clone_empty() self.class.new() end
def rotate(x0,y0,r)
a=Math::PI*(r/180.0)
@lpoints.map! { |(x,y)| [x0+(x-x0)*Math.cos(a)+(y-y0)*Math.sin(a),y0-(x-x0)*Math.sin(a)+(y-y0)*Math.cos(a)] }
self
end
def deplace(dx,dy)
@lpoints.map! { |(x,y)| [x+dx,y+dy] }
self
end
def scale(x0,y0,rx,ry=nil)
ry=rx unless ry
@lpoints.map! { |(x,y)| [x0+(x-x0)*rx,y0+(y-y0)*ry] }
self
end
def distance(x0,y0)
return(2_999_999_999) if @lpoints.size==0
@lpoints.map { |(x1,y1)| Math.hypot(x1-x0,y1-y0)}.sort()[0]
end
def cover_bbox?(x0,y0,x1,y1)
@lpoints.select { |(x,y)| pt_in_bbox?(x,y, x0,y0,x1,y1)}.size>0
end
def into_bbox?(x0,y0,x1,y1)
return(false) if @lpoints.size==0
@lpoints.select { |(x,y)| pt_in_bbox?(x,y, x0,y0,x1,y1)}.size==@lpoints.size
end
def pt_in_bbox?(x,y, x0,y0,x1,y1)
(x>=x0 && x<= x1 && y>=y0 && y<=y1)
end
def hoover_point?(x,y)
distance(x,y)<10
end
end
class VElem_surface < VElem
def define_style_before(ctx)
ctx.set_line_width(@style[:stroke_width]) if @style[:stroke_width]
end
def svg_path() super()+" Z" end
def render() raise('abstract') end
def define_style_after(ctx)
if @style[:stroke_width]&&@style[:stroke_width]>0
ctx.set_source_rgba(@style[:fill_color][0], @style[:fill_color][1], @style[:stroke_color][2], 1) if @style[:fill_color]
ctx.fill_preserve
end
ctx.set_source_rgba(@style[:stroke_color][0], @style[:stroke_color][1], @style[:stroke_color][2], 1) if @style[:stroke_color]
ctx.stroke
end
end
class Group < VElem
def initialize(l) @lvector=l.dup end
def set_lvector(l) @lvector=l.dup end
def get_lvector() @lvector.dup end
def bbox()
@lvector.inject(Bbox.new){ |bb,p| p.append_to_bbox(bb) }
end
def append_to_bbox(box)
@lvector.inject(bbox) { |bb,p| p.append_to_bbox(bb) };
end
def vclone()
Group.new(@lvector.map { |v| v.vclone })
end
def to_svg(out)
out << " <g>\n"
@lvector.each{|v| v.to_svg(out)}
out << " </g>\n"
end
def lpoints() bbox().pvalues end
def lpoints=(l) end
def set_style(s) end
def get_style(s) {} end
def draw(w,ctx)
return if @lvector.size==0
@lvector.each{|v| v.draw(w,ctx)}
end
def render(ctx) end
def rotate(x0,y0,r) @lvector.each{|v| v.rotate(ctx)} ; self end
def deplace(dx,dy) @lvector.each{|v| v.deplace(dx,dy)} ; self end
def scale(x0,y0,rx,ry=nil) @lvector.each{|v| v.scale(x0,y0,rx,ry)} ; self end
def distance(x0,y0)
return(2_999_999_999) if @lvector.size==0
@lvector.map{|v| v.distance(x0,y0)}.sort[0]
end
def cover_bbox?(x0,y0,x1,y1)
return(false) if @lvector.size==0
@lvector.any?{|v| v.cover_bbox?(x0,y0,x1,y1) }
end
def into_bbox?(x0,y0,x1,y1)
return(false) if @lvector.size==0
@lvector.any?{|v| v.into_bbox?(x0,y0,x1,y1) }
end
def hoover_point?(x,y)
distance(x,y)<10
end
end
class Polyline < VElem
def render(ctx)
ctx.move_to(*@lpoints[0])
@lpoints[1..-1].each {|px| ctx.line_to(*px) }
ctx.stroke
end
end
class Polygone < VElem_surface
def render(ctx)
ctx.move_to(*@lpoints[0])
@lpoints[1..-1].each {|px| ctx.line_to(*px) }
ctx.close_path
end
end
class SelRectangle < VElem
def define_style_before(ctx)
ctx.set_line_width(2)
ctx.set_source_rgba(0.3,0.3,0.7,0.8)
end
def define_style_after(ctx)
ctx.set_source_rgba(0.3,0.3,0.7,0.3)
ctx.fill_preserve
ctx.set_source_rgba(0.3,0.3,0.7,0.8)
ctx.stroke
end
def render(ctx)
return if @lpoints.size!=2
x0,y0,x1,y1=*(@lpoints.flatten)
ctx.move_to(x0,y0)
ctx.line_to(x1,y0);ctx.line_to(x1,y1);ctx.line_to(x0,y1);ctx.line_to(x0,y0);
end
def order
return if @lpoints.size!=2
x0,y0,x1,y1=@lpoints.flatten
@lpoints=[
[[x0,x1].min,[y0,y1].min],
[[x0,x1].max,[y0,y1].max]
]
end
end
class SelMark < VElem
def initialize(sel_vector=nil,index=nil)
@sel_vector,@index=sel_vector,index
end
def deplace(dx,dy)
return(self) if @lpoints.size!=1
super
@sel_vector.lpoints[@index]=@lpoints[0] if @sel_vector && @index
self
end
def define_style_before(ctx)
ctx.set_line_width(1)
ctx.set_source_rgba(0.3,0.3,1,0.8)
end
def render(ctx)
return if @lpoints.size!=1
t=4
xc,yc=@lpoints[0]
x0,y0,x1,y1=*[xc-t,yc-t,xc+t,yc+t]
ctx.move_to(x0,y0)
ctx.line_to(x1,y0);ctx.line_to(x1,y1);ctx.line_to(x0,y1);ctx.line_to(x0,y0);
ctx.fill
end
end
class Oval < VElem_surface
def render(ctx)
return if @lpoints.size<4
x= (@lpoints[0][0]+@lpoints[2][0])/2.0
y= (@lpoints[0][1]+@lpoints[2][1])/2.0
r= ((@lpoints[2][0]-@lpoints[0][0])/2.0).abs
ctx.arc(x,y, r, 0, Math::PI*2)
end
end
class Text < VElem
def set_text(text)
@text=text
end
def to_svg(out)
out << " <text dr='#{self.class}' x='#{@lpoints[0][0]}' y='#{@lpoints[0][1]}' style='#{self.svg_style}'>#{@text}</text>\n"
end
def render(ctx)
return if @lpoints.size!=1
ctx.select_font_face(@style[:font] ,Cairo::FONT_SLANT_NORMAL,Cairo::FONT_WEIGHT_BOLD)
ctx.set_font_size(@style[:font_size])
ctx.move_to(@lpoints[0][0],@lpoints[0][1])
ctx.show_text(@text|| "unknown" )
ctx.fill
ctx.stroke
end
end
class Image < VElem
def set_image(filename)
@filename=filename
@pixbuf = $app.get_image_from(@filename).pixbuf
end
def render(ctx)
return if @lpoints.size!=1 || ! defined?(@pixbuf) || ! @pixbuf
ctx.set_source_pixbuf(@pixbuf, @lpoints[0][0],@lpoints[0][1])
ctx.paint
end
end
end
#####################################################################
# Vector canvas editable #
#####################################################################
module Vector
class VCanvas_editable < VCanvas
def initialize(win,w,h,options)
super
@current=nil
@select={}
@corbeill=[]
define_style({})
#------------------------ create one vector for easy test
@current=Polyline.new
@current.lpoints=[[100,200],[100,10],[200,300],[400,300],[200,200]]
define_style({})
complete_edition()
#------------------------
mode_selection()
end
def clear
@current=nil
super
end
def define_style(options)
if @current
@current.set_style(@cstyle)
redraw
end
if @select.size>0 && @select[:list] && @select[:list].size>0
@select[:list].each { |v| v.set_style(options) }
else
@cstyle={
:stroke_width=>options[:width] || 1,
:stroke_color=>conv_color(options[:fg] || [0,0,0,0]),
:fill_color=>conv_color(options[:bg] || [1,1,1]) ,
:font=>options[:font]|| "Sans",
:font_size=>options[:font_size]|| 10
}
end
end
def conv_color(color)
return color if Array === color
[color.red/65535.0,color.green/65535.0,color.blue/65535.0]
end
def expose(w,ctx)
super
@current.draw(w,ctx) if @current
end
def complete_edition()
if @current && @current.lpoints.size>0
@layers[1] << @current
@current=@current.clone_empty
end
end
def end_create_current()
complete_edition()
end
def mode_create_polyline()
complete_edition()
@current=Polyline.new
@current.set_style(@cstyle)
@mode=:cpoly
end
def mode_create_polygone()
complete_edition()
@current=Polygone.new
@current.set_style(@cstyle)
@mode=:cpoly
end
def mode_create_rect()
complete_edition()
@current=Polygone.new
@lpoints=[]
@current.set_style(@cstyle)
@mode=:crect
end
def mode_create_oval()
complete_edition()
@current=Oval.new
@lpoints=[]
@current.set_style(@cstyle)
@mode=:crect
end
def mode_create_text()
complete_edition()
@current=Text.new
@lpoints=[]
@current.set_style(@cstyle)
@mode=:cpoint
end
def mode_create_image()
complete_edition()
@current=Image.new
@lpoints=[]
@current.set_style(@cstyle)
@mode=:cpoint
end
def mode_modify()
complete_edition()
end
########################## Mouse Interaction for Poly___
def cpoly_mouse_down(e) @current.lpoints << [e.x,e.y] end
def cpoly_mouse_move(e)
if @current.lpoints.size==1
@current.lpoints << [e.x,e.y]
else
@current.lpoints.last[0]=e.x;@current.lpoints.last[1]=e.y
end
redraw(e)
end
def cpoly_mouse_up(e) @current.lpoints.last[0]=e.x;@current.lpoints.last[1]=e.y ; redraw(e) end
########################## Mouse Interaction for Rectangle/Oval
def crect_mouse_down(e)
if @lpoints.size==0
@lpoints << [e.x,e.y]
end
end
def crect_mouse_move(e)
if @lpoints.size==1
@lpoints << [e.x,e.y]
else
@lpoints.last[0]=e.x;@lpoints.last[1]=e.y
end
@current.lpoints=[
@lpoints[0],
[@lpoints[1][0],@lpoints[0][1]],
@lpoints[1],
[@lpoints[0][0],@lpoints[1][1]]
]
redraw(e)
end
def crect_mouse_up(e)
case @current
when Polygone then mode_create_rect()
when Oval then mode_create_oval()
end
redraw(e)
end
########################## Mouse Interaction for Text/Image
def cpoint_mouse_down(e) p(e) end
def cpoint_mouse_move(e) p(e) end
def cpoint_mouse_up(e)
@current.lpoints=[[e.x,e.y]]
case @current
when Text
$app.prompt("Text ?") {|t|
@current.set_text(t)
mode_create_rect()
redraw(e)
}
when Image
f=$app.ask_file_to_read(".","*.png")
return unless f
$app.prompt("Detail sur #{f} ? ([Col,Row]xSize}",f) { |fi|
@current.set_image(fi)
mode_create_image()
redraw(e)
}
end
end
################################################################
# Selection : mode, select voctor(s), interact with them
################################################################
def has_selection?() (@select && @select[:list] && @select[:list].size>0) end
def mode_selection()
complete_edition()
@current=nil
@select={}
@layers[0]=[]
@lasso=nil
@mode=:select
redraw
end
def selection_vector(lv)
@layers[0]=[]
@lasso=nil
@select[:list]= []
lv.each { |v|
if v.lpoints.size>0
v.lpoints.each_with_index { |(x,y),i| make_mark(v,i,x,y) }
else
end
@select[:list] << v
}
mode=:select
end
def make_mark(v,i,x,y)
m=SelMark.new(v,i)
m.lpoints=[[x,y]]
@layers[0]<<m
m
end
def make_lasso(x0,y0,x1,y1)
r=SelRectangle.new
r.lpoints=[[x0,y0],[x1,y1]]
@layers[0]<<r
@lasso=r
r
end
def cut()
return unless has_selection?()
@corbeill=[]
l=@select[:list]
mode_selection()
l.each { |sel|
a,b=@layers[1].partition { |v| v!=sel }
@corbeill += b
@layers[1]=a
}
prt "corbeill=",@corbeill
redraw
end
def copy()
return unless has_selection?()
@corbeill=[]
@select[:list].each { |sel|
@corbeill += @layers[1].select { |v| v==sel }
}
mode_selection()
prt "corbeill=",@corbeill
end
def past()
return if @corbeill.size==0
prt " << ",@corbeill
@layers[1] += @corbeill.map { |v| v.vclone.deplace(3,3) }
redraw
end
def copystyle()
return unless has_selection?()
copy()
@cstyle=@select[:list][0].get_style()
end
def edit()
str=to_svg("")
$app.edit(str)
end
def sel_top()
return unless has_selection?()
@select[:list].each { |v| @layers[1].delete(v) }
@layers[1].push(*@select[:list])
selection_vector(@select[:list])
redraw
end
def sel_bottom()
return unless has_selection?()
@select[:list].each { |v| @layers[1].delete(v) }
@layers[1]= @select[:list] + @layers[1]
selection_vector(@select[:list].dup)
redraw
end
def sel_group()
return unless has_selection?()
@select[:list].each { |v|
@layers[1].delete(v)
}
g=Group.new(@select[:list])
@layers[1].push(g)
selection_vector([g])
redraw
end
def sel_ungroup()
return unless has_selection?()
return unless @select[:list].size==1 && @select[:list][0].is_a?(Group)
v=@select[:list][0]
lv=v.get_lvector
@layers[1].delete(v)
lv.reverse.each { |v| @layers[1].unshift(v)}
selection_vector(lv)
redraw
end
def sel_align(direction,sens)
return unless has_selection?()
lv=@select[:list]
bx0,by0,bx1,by1=Group.new(lv).bbox.values
lv.each { |v|
x0,y0,x1,y1=v.bbox().values
v.deplace(direction==0? (sens==0 ? (bx0-x0):(bx1-x1)):0,
direction==1? (sens==1 ? (by0-y0):(by1-y1)):0
)
}
selection_vector(lv)
redraw
end
################################## Mouse Interaction for Selection
def select_mouse_down(e)
if r=find_hoover(e.x,e.y,0)
@select[:vector]=[r,r.lpoints[0].clone]
@mode=:mselect
else
@select[:pt0]=[e.x,e.y]
end
end
def select_mouse_move(e)
@select[:pt1]=[e.x,e.y]
if !@lasso
make_lasso(*@select[:pt0],*@select[:pt1])
else
@lasso.lpoints[1]=[e.x,e.y]
end
redraw(e)
end
def select_mouse_up(e)
if @lasso
@lasso.order
l=find_into_bbox(*@lasso.lpoints.flatten)
l=find_cover_bbox(*@lasso.lpoints.flatten) if l.size==0
l.size>0 ? selection_vector(l) : mode_selection()
else
v=find_nearest(*@select[:pt0])
v ? selection_vector([v]) : mode_selection()
end
redraw(e)
end
def mselect_mouse_move(e)
x0,y0=*@select[:vector][1]
@select[:vector][0].deplace(e.x-x0,e.y-y0)
@select[:vector][1]=[e.x,e.y]
redraw(e)
end
def mselect_mouse_up(e)
mode_selection()
end
end # fin class
end # fin module
################################### Drawer application #############################
class Application < Ruiby_gtk
def initialize()
@win=nil
@stroke_width=1
@fgcolor=Gdk::Color.new(0,0,0)
@bgcolor=Gdk::Color.new(1,1,1)
@filename=nil
@t=nil
super("Vector Draw",800,800)
end
def component()
stack do
################## Menu
menu_bar do
menu("File") {
menu_button("Open") { fopen() }
menu_button("Save") { fsave() }
menu_button("Save as...") { fsave_as() }
menu_button("Rename as...") { frename() }
menu_separator
menu_button("Export...") { fexport() }
menu_button("New") { fclear() }
menu_separator
menu_button("Exit") { ruiby_exit }
}
menu("Edit") {
menu_button("Cut") { cut() } ; menu_button("Copy") { copy() } ;menu_button("Past") { past() } ;menu_button("Copy style") { copystyle()}
}
end
############### Central zone
flow do
#------------------ Left menu
stack { stacki do
button("#apply"){ @win.end_create_current()}
separator
button("#media/draw.png[0,0]x22") { @win.mode_create_polyline() ; @labl.text="Create Polyline"}
button("#media/draw.png[1,0]x22") { @win.mode_create_polygone() ; @labl.text="Create Polygone"}
button("#media/draw.png[2,0]x22") { @win.mode_create_rect() ; @labl.text="Create rectangle"}
button("#media/draw.png[3,0]x22") { @win.mode_create_oval() ; @labl.text="Create oval"}
button("#italic") { @win.mode_create_text() ; @labl.text="Create text"}
button("#media/draw.png[4,0]x22") { @win.mode_create_image() ; @labl.text="Create image"}
end}
#------------------ Canvas
@win=editable_vector(700,700)
#------------------ Right menu
stack {space;stacki do
button("Sel.") { @win.mode_selection() }
button("#cut") { @win.cut() };button("#copy") { @win.copy() };button("#paste") { @win.past() }; space ; button("#edit") { @win.edit() }
end}
end
####################### Bottom zone : styles interaction
flow do
@labl=label("Left label...")
flow {
button("#media/draw.png[0,1]x22") { @win.sel_top() }
button("#media/draw.png[1,1]x22") { @win.sel_bottom() }
button("#media/draw.png[2,1]x22") { @win.sel_group() }
button("#media/draw.png[3,1]x22") { @win.sel_ungroup() }
button("#media/draw.png[4,1]x22") { @win.sel_align(0,0) }
button("#media/draw.png[5,1]x22") { @win.sel_align(0,1) }
button("#media/draw.png[6,1]x22") { @win.sel_align(1,1) }
button("#media/draw.png[7,1]x22") { @win.sel_align(1,1) }
color_choice("bg") { |c| @bgcolor=c ; define_style}
color_choice("fg") { |c| @fgcolor=c ; define_style}
label("Width :")
ientry(1,{:min=>1,:max=>100,:by=>1}) { |v|
@stroke_width=v.to_i
define_style
}
label("Rotate :")
ientry(0,{:min=>0,:max=>180,:by=>1}) { |v|
@win.rotate(400,400,v.to_i)
}
label("Scale :")
ientry(0,{:min=>-10,:max=>10,:by=>1}) { |v|
@win.scale(400,400,(v.to_i+10)/5.0,(v.to_i+10)/5.0)
}
label("Animation :")
@t=toggle_button("#play","#stop",false)
}
@labr=label("rigtht label...")
end
button("reload") {
puts "----------------------------------"
begin
load(__FILE__)
rescue Exception => e
error($!)
end
puts "----------------------------------"
}
end
$app=self
define_style
anim(10) {
@win.rotate(400,400,0.1) if @t && @t.active?
x= Time.now.to_i%2==0 ? 1 : -1
@win.scale(400,400,1.0+x*0.001,1.0+x*0.001) if @t && @t.active?
}
end # end component()
def define_style
@win.define_style({:fg=>@fgcolor,:bg=>@bgcolor,:width=>@stroke_width,:font=>"Arial",:font_size=>33})
end
def lstatus(text) @labl.text=text.to_s end
def rstatus(text) @labr.text=text.to_s end
def fopen()
fn=ask_file_to_read(".","*.rdr")
if fn
fclear()
(@win.load_from_rdr(fn);@filename=fn) rescue error($!)
end
end
def fsave()
@filename=ask_file_to_write(".","*.rdr") unless @filename
if @filename
(@win.save_to_rdr(@filename);alert("#{@filename} saved !")) rescue error($!)
end
end
def fsave_as()
fn=ask_file_to_write(".","*.rdr")
if fn
@filename=fn
fsave()
end
end
def fexport()
fn=ask_file_to_write(".","*.svg")
if fn
(File.open(fn,"w") { |f| @win.to_svg(f) };alert("#{fn} saved !")) rescue error($!)
end
end
def frename()
return unless @filename
fn=ask_file_to_write(".","*.svg")
if fn && File.exists?(@filename)
@filename,fn=fn,@filename
fsave()
File.delete(fn) if File.exists?(fn) && File.exists?(@filename)
end
end
def fclear() @win.clear ; @filename=nil end
end
Ruiby.start { Application.new }