require 'tk' class TkMove def initialize( canvas ) @x0, @y0 = 0, 0 @canvas = canvas @tag = 'item' end def bind TkRoot.new.cursor 'left_ptr' @canvas.dtag('selected') @canvas.itembind( @tag, '1', proc{|x, y| plotDown x, y},"%x %y") @canvas.itembind( @tag, 'B1-Motion', proc{|x, y| plotMove x, y},"%x %y") end def unbind @canvas.bind('1', proc{}) @canvas.bind('B1-Motion', proc{}) @canvas.bind('Double-1', proc{}) @canvas.itembind('item', '1', proc{}) @canvas.itembind('item', 'B1-Motion', proc{}) @canvas.itembind('item', 'Double-1', proc{}) @canvas.itembind('control', '1', proc{}) @canvas.itembind('control', 'B1-Motion', proc{}) @canvas.itembind('control', '3', proc{}) TkRoot.new.cursor 'left_ptr' end def plotDown(x, y) @canvas.dtag 'selected' tag = @canvas.gettags('current')[-2] if tag != 'item' @canvas.addtag_withtag 'selected', tag @canvas.raise tag @x0, @y0 = x, y end end def plotMove(x, y) @canvas.move 'selected', x - @x0, y - @y0 @x0, @y0 = x, y end end class TkdDraw def initialize( canvas ) @canvas = canvas @tag = 'item' @type = 'default' @x0, @y0 = 0, 0 @coord = [] end def bind TkRoot.new.cursor 'pencil' @canvas.bind('1', proc{|x, y| create_item(x, y)}, "%x %y") @canvas.bind('B1-Motion', proc{|x, y| adjust_item(x, y)}, "%x %y") end def unbind @TkRoot.new.cursor 'left_ptr' @canvas.bind('1', proc{}) @canvas.bind('B1-Motion', proc{}) @canvas.bind('Double-1', proc{}) @canvas.itembind('item', '1', proc{}) @canvas.itembind('item', 'B1-Motion', proc{}) @canvas.itembind('item', 'Double-1', proc{}) end def create_item(x, y) @item = new_item(x, y) @item.addtag( @tag ) @item.addtag( @item.id ) @canvas.dtag 'selected' @canvas.addtag_withtag 'selected', @item.id @x0, @y0 = x, y end def new_item(x, y) 'not defined' end def adjust_item(x, y) @item.coords( @x0, @y0, x, y ) @coord = [@x0, @y0, x, y] end def get @coord end end class TkdLine < TkdDraw def initialize( canvas ) super @type = 'line' end def new_item(x, y) TkcLine.new( @canvas, x, y, x, y, 'width'=>2 ) end end class TkdLines < TkdDraw def initialize( canvas ) super @type = 'line' @in = false @coord = [] end def bind TkRoot.new.cursor('pencil') @canvas.dtag('selected') @canvas.bind('B1-Motion', proc{|x, y| refresh_item(x, y)}, "%x %y" ) @canvas.bind('1', proc{|x, y| create_item(x, y)}, "%x %y") end def create_item(x, y) if @in == false super @coord = [x,y] @canvas.bind( 'Motion', proc{|x, y| refresh_item(x, y)}, "%x %y" ) @canvas.bind( 'Double-Button-1', proc{|x, y| exit_item(x, y)}, "%x %y") @in = true else @coord += [x, y] eval( '@item.coords(' + @coord.join(',') + ')' ) # end end def new_item(x, y) TkcLine.new( @canvas, x, y, x, y, 'width'=>2 ) end def refresh_item(x, y) temp = @coord + [x, y] eval( '@item.coords(' + temp.join(',') + ')' ) end def exit_item(x, y) # @coord += [x, y] eval( '@item.coords(' + @coord.join(',') + ')' ) @canvas.bind( 'Motion', proc{}) @canvas.bind( 'Double-Button-1', proc{}) @in = false end end class TkdBezier < TkdLines def new_item(x, y) TkcLine.new( @canvas, x, y, x, y, 'width'=>2, 'smooth'=>true ) end end class TkdPolygon < TkdLines def initialize( canvas ) super @type = 'polygone' end def exit_item(x, y) super @canvas.delete( @item.id ) eval( "@item = TkcPolygon.new(@canvas," + @coord.join(',') + ", 'outline'=>'black', 'fill'=>'white', 'width'=>2)") @item.addtag( @tag ) @item.addtag( @item.id ) end end class TkdBPolygon < TkdBezier def initialize( canvas ) super @type = 'polygone' end def exit_item(x, y) super @canvas.delete( @item.id ) eval( "@item = TkcPolygon.new(@canvas," + @coord.join(',') +", 'smooth'=>true, 'fill'=>'white', 'outline'=>'black', 'width'=>2)") @item.addtag( @tag ) @item.addtag( @item.id ) end end class TkdRectangle < TkdDraw def initialize( canvas ) super @type = 'rectangle' end def bind super TkRoot.new.cursor('crosshair') end def new_item(x, y) TkcRectangle.new( @canvas, x, y, x, y, 'fill'=>'white', 'width'=>2 ) end end class TkdOval < TkdDraw def initialize( canvas ) super @type = 'oval' end def bind super TkRoot.new.cursor('crosshair') end def new_item(x, y) TkcOval.new( @canvas, x, y, x, y, 'fill'=>'white', 'width'=>2 ) end end class TkdArea < TkdDraw def initialize( canvas ) super @type = 'area_select' end def bind super TkRoot.new.cursor('crosshair') end def create_item(x, y) @canvas.delete 'area_select' super @canvas.addtag_withtag 'area_select', @item.id end def new_item(x, y) TkcRectangle.new( @canvas, x, y, x, y ) # TkcRectangle.new( @canvas, x, y, x, y, 'dash'=>2 ) end def delete @canvas.delete 'area_select' end def get_coord @coord end end class TkdText < TkdDraw def initialize( canvas ) super @type = 'text' end def bind @canvas.bind('1', proc{|x, y| new_item(x, y)}, "%x %y") TKRoot.new.cursor('xterm') end def new_item(x, y) w = TkToplevel.new entry = TkEntry.new(w).pack('side'=>'left') TkButton.new(w, 'text'=>'Ok', 'command'=>proc{ text = entry.value item = TkcText.new(@canvas, x, y, 'text'=>text) item.addtag('item') item.addtag( item.id ) w.destroy }).pack end end class TkdDelete def initialize( canvas ) @canvas = canvas @tag = 'item' end def bind TkRoot.new.cursor('pirate') @canvas.dtag('selected') @canvas.itembind( @tag, '1', proc{ delete } ) @canvas.itembind( @tag, 'B1-Motion', proc{} ) end def delete tag = @canvas.gettags('current')[-2] @canvas.delete( tag ) end end class TkdGroup def initialize( canvas ) @canvas = canvas @@id = 1 @group_name = "group" @tag = @group_name + @@id.to_s end def bind @canvas.bind('1', proc{ break_up_current }) end def make_group( coord ) @tag = @group_name + @@id.to_s @@id += 1 if coord != [] eval("@canvas.addtag_enclosed('" + @tag + "', " + coord.join(',') + ")") end @tag end def break_up( item ) tags = @canvas.itemconfigure( item.id, 'tags' ) tag = tags.scan(/\group[0-9]*/).pop if tag != '' @canvas.dtag( tag ) end end def break_up_current item = @canvas.find_withtag('current').shift break_up( item ) end end class TkdCopy def initialize( canvas ) @@cid = 10000 @canvas = canvas end def bind TkRoot.new.cursor('hand2') @canvas.bind('B1-Motion', proc{}) @canvas.bind('1', proc{ item = @canvas.find_withtag('current') break if item[0] == nil @canvas.dtag('selected') @canvas.dtag('current') tags = item[0].gettags if tags[-1].kind_of? Numeric copy( item.shift, nil ) else copy_withtag( tags[-1] ) end }) end def copy( item, tag ) @item = item info = @canvas.itemconfiginfo( @item ) info_hash = {} info.each{|key| info_hash[ key[0] ] = key[4] if key[4] != "" info_hash[ key[0] ] = 'true' if key[4] == 'bezier' } info_hash.delete( 'tags' ) eval ( "@newitem = #{@item.type}.new(@canvas, #{@item.coords.join(',')})" ) @canvas.itemconfigure( @newitem, info_hash ) @newitem.addtag('item') @newitem.addtag( @newitem.id ) if tag != nil @newitem.addtag( tag ) if not tag == nil end @newitem.move( 2, 2 ) end def copy_withtag( tag ) items = @canvas.find_withtag( tag ) if tag == 'current' tags = items[-1].gettags indx = tags.index('current') - 1 tag = tags[indx] end if tag.kind_of? Numeric tag = nil else tag = 'group' + @@cid.to_s @@cid += 1 end items.each{|item| copy( item, tag ) } end end class TkdConfigure def initialize( canvas ) @c = canvas @info = [] @confighash = {} @frame = [] @label = [] @entry = [] end def bind TkRoot.new.cursor('hand2') @c.itembind('item', '1', proc{ item = @c.find_withtag( 'current' ).shift dialog( item ) }) end def apply( target ) @label.each_index{|i| @confighash[ @info[i][0] ] = @entry[i].value } @confighash.delete( 'tags' ) @c.itemconfigure( target, @confighash ) @confighash = {} end def dialog( target ) @info = @c.itemconfiginfo( target ) w = TkToplevel.new @info.each_index{|i| @frame[i] = TkFrame.new(w).pack @label[i] = TkLabel.new( @frame[i], 'text'=>@info[i][0], 'width'=>15) @entry[i] = TkEntry.new( @frame[i] ) @label[i].pack('side'=>'left') @entry[i].pack('side'=>'left') @info[i][-1] = 'true' if @info[i][-1] == 'bezier' @entry[i].insert(0, @info[i][-1]) } infomessage = TkMessage.new(w).pack fb = TkFrame.new(w).pack TkButton.new(fb, 'text'=>'info', 'command'=>proc{ infomessage.text( @c.itemconfiginfo( target ).inspect) }).pack('side'=>'left') TkButton.new(fb, 'text'=>'apply', 'command'=>proc{ apply( target ) }).pack('side'=>'left') TkButton.new(fb, 'text'=>'dismiss', 'command'=>proc{ w.destroy }).pack('side'=>'left') end end class TkdCoords def initialize( canvas ) @canvas = canvas end def bind TkRoot.new.cursor('hand2') @canvas.itembind('item', '1', proc{ item = @canvas.find_withtag( 'current' ).shift dialog( item ) }) end def dialog( item ) @coords = item.coords() w = TkToplevel.new TkLabel.new(w, 'text'=>'coords').pack f1 = TkFrame.new(w).pack('fill'=>'x') scr = TkScrollbar.new(f1).pack('side'=>'right', 'fill'=>'y') e = TkText.new(f1, 'width'=>30, 'height'=>6).pack('side'=>'right') e.yscrollbar( scr ) e.insert('1.0', @coords) f2 = TkFrame.new(w).pack('fill'=>'x') TkButton.new(f2, 'text'=>'apply', 'command'=>proc{ @coords = e.get('1.0', 'end').chop eval( "item.coords(" + @coords.gsub(/\s/,',') + ")" ) }).pack('side'=>'left') TkButton.new(f2,'text'=>'dismiss', 'command'=>proc{ w.destroy }).pack('side'=>'right') end end class TkdColor def initialize( canvas ) @canvas = canvas end def bind TkRoot.new.cursor('hand2') @canvas.bind('1', proc{}) @canvas.bind('B1-Motion', proc{}) @canvas.bind('Double-1', proc{}) @canvas.itembind('item', 'B1-Motion', proc{}) @canvas.itembind('item', 'Double-1', proc{}) @canvas.itembind('item', '1', proc{ item = @canvas.find_withtag('current').shift color = Tk.chooseColor item.fill( color ) if color != '' }) end end class TkdControl def initialize( canvas ) @canvas = canvas @item = nil @coords = [] @x0, @y0 = 0, 0 end attr_writer :item def get_coords @coords = [] a = @item.coords while( a != []) x = a.shift y = a.shift @coords.push( [x, y] ) end @coords end def set_coords eval( "@item.coords(" + @coords.flatten.join(',') + ")" ) end def make_control @coords.each_index{|i| x, y = @coords[i][0], @coords[i][1] cont = TkcRectangle.new(@canvas, x-2, y-2, x+2, y+2, 'fill'=>'white') cont.addtag('control') cont.addtag( i ) } end def remove_control @canvas.delete('control') end def plotDown(x, y) @canvas.dtag 'selected' @canvas.addtag_withtag 'selected', 'current' @canvas.raise 'current' @x0, @y0 = x, y end def plotMove(x, y) @canvas.move 'selected', x-@x0, y-@y0 @x0, @y0 = x, y i = @canvas.find_withtag('selected').shift.gettags[1] @coords[i][0], @coords[i][1] = x, y set_coords end def private_bind @canvas.bind('1', proc{}) @canvas.bind('B1-Motion', proc{}) @canvas.bind('3', proc{ remove_control }) @canvas.itembind('control', '1', proc{|x,y| plotDown x,y }, "%x %y" ) @canvas.itembind('control', 'B1-Motion', proc{|x,y| plotMove x, y }, "%x %y") end def get_item( item ) @item = item get_coords make_control private_bind end def get_item_with_cursor item = @canvas.find_withtag('current').shift get_item( item ) end def bind TkRoot.new.cursor('hand2') @canvas.itembind('item', '1', proc{ remove_control; get_item_with_cursor }) end end module TestBed def testbed( c ) m = TkMove.new( c ) l = TkdLine.new( c ) r = TkdRectangle.new( c ) o = TkdOval.new( c ) d = TkdDelete.new( c ) ls = TkdLines.new( c ) b = TkdBezier.new( c ) p = TkdPolygon.new( c ) bp = TkdBPolygon.new( c ) a = TkdArea.new( c ) g = TkdGroup.new( c ) copy = TkdCopy.new( c ) conf = TkdConfigure.new( c ) coord = TkdCoords.new( c ) col = TkdColor.new( c ) cntrl = TkdControl.new( c ) TkFrame.new{|f| TkButton.new(f, 'text'=>'Line', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; l.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'Rect', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; r.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'Oval', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; o.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'Del', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; d.bind }).pack('side'=>'right') TkButton.new(f, 'text'=>'Move', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; m.bind }).pack('side'=>'right') }.pack('fill'=>'x') TkFrame.new{|f| TkButton.new(f, 'text'=>'Lines', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; ls.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'Bezier', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; b.bind}).pack('side'=>'left') TkButton.new(f, 'text'=>'Gbk', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; g.bind}).pack('side'=>'right') TkButton.new(f, 'text'=>'Grp', 'command'=>proc{ cntrl.remove_control; coord = a.get_coord; g.make_group( coord ); a.delete }).pack('side'=>'right') TkButton.new(f, 'text'=>'Area', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; a.bind}).pack('side'=>'right') }.pack('fill'=>'x') TkFrame.new{|f| TkButton.new(f, 'text'=>'Polygon', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; p.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'BPolygon', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; bp.bind}).pack('side'=>'left') TkLabel.new(f, 'text'=>' ').pack('side'=>'left') TkButton.new(f, 'text'=>'Exit', 'command'=>proc{ exit }).pack('side'=>'right') }.pack('fill'=>'x') TkFrame.new{|f| TkButton.new(f, 'text'=>'copy', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; copy.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'color', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; col.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'config', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; conf.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'coords', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; coord.bind }).pack('side'=>'left') TkButton.new(f, 'text'=>'cntrl', 'command'=>proc{ cntrl.remove_control; a.delete; m.unbind; cntrl.bind }).pack('side'=>'left') }.pack('fill'=>'x') end end