Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env ruby
- require 'gtk2'
- require 'rational'
- =begin
- A drawing area, which can be panned and zoomed.
- (requires rational)
- Panning is done with middle mouse drag, zooming is with the scrollwheel.
- To zoom only into x or y axis, hold down the shift or ctrl keys respectively.
- You must create the following method:
- expose_event event, cairo, coordinates
- where
- event is the expose event
- cairo is the cairo context
- coordinates is an array with the [xstart, ystart, xend, yend] coordinates
- =end
- class DragZoomDrawingArea < Gtk::DrawingArea
- type_register
- def initialize
- super
- @xscale = @yscale = 1.to_r
- @xoffset = @yoffset = 0.to_r
- @xscalestep = @yscalestep = 2.to_r
- @drag_sig_handlers = []
- signal_connect('expose-event') {|widget, event|
- cairo = window.create_cairo_context
- cairo.scale(@xscale, @yscale)
- cairo.translate(@xoffset, @yoffset)
- alloc = allocation
- width, height = alloc.width, alloc.height
- xstart = (0.to_r - @xoffset) / @xscale
- xend = (width.to_r - @xoffset) / @xscale
- ystart = (0.to_r - @yoffset) / @yscale
- yend = (height.to_r - @yoffset) / @yscale
- expose_event widget, event, cairo, [xstart, ystart, xend, yend]
- true
- }
- signal_connect('scroll-event') {|widget, event|
- do_xscale = do_yscale = true
- if event.state & Gdk::Window::ModifierType::SHIFT_MASK != 0
- do_yscale = false
- end
- if event.state & Gdk::Window::ModifierType::CONTROL_MASK != 0
- do_xscale = false
- end
- xscale_old, yscale_old = @xscale, @yscale
- case event.direction
- when Gdk::EventScroll::DOWN
- @xscale /= @xscalestep if do_xscale
- @yscale /= @yscalestep if do_yscale
- when Gdk::EventScroll::UP
- @xscale *= @xscalestep if do_xscale
- @yscale *= @yscalestep if do_yscale
- end
- @xoffset = event.x.to_i.to_r / @xscale - (event.x.to_i / xscale_old - @xoffset)
- @yoffset = event.y.to_i.to_r / @yscale - (event.y.to_i / yscale_old - @yoffset)
- queue_draw
- }
- @motion_cb = proc {|widget, event|
- deltax, deltay = event.x.to_i.to_r - @startx.to_i, event.y.to_i.to_r - @starty.to_i
- @xoffset += deltax / @xscale
- @yoffset += deltay / @yscale
- @startx, @starty = event.x, event.y
- queue_draw
- }
- signal_connect('button-press-event') {|widget, event|
- if(event.button == 2)
- @startx, @starty = event.x, event.y
- @drag_sig_handlers << signal_connect('motion-notify-event', &@motion_cb)
- end
- }
- signal_connect('button-release-event') {|widget, event|
- if(event.button == 2)
- @drag_sig_handlers.reject!{|s| signal_handler_disconnect(s); true}
- end
- }
- add_events(Gdk::Event::SCROLL_MASK |
- Gdk::Event::BUTTON_PRESS_MASK |
- Gdk::Event::BUTTON_RELEASE_MASK |
- Gdk::Event::POINTER_MOTION_MASK)
- end
- end
- class MyWindow < Gtk::Window
- def initialize
- super('interactive graph')
- set_size_request(500,500)
- signal_connect("delete-event") { Gtk.main_quit;true }
- drawing_area = DragZoomDrawingArea.new
- def drawing_area.expose_event widget, event, cairo, disp
- cairo.set_source_rgb(1,0,0)
- cairo.rectangle(100, 100, 50, 50)
- cairo.stroke
- end
- add(drawing_area)
- show_all
- end
- end
- app = MyWindow.new
- Gtk.main
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement