Want more features on Pastebin? Sign Up, it's FREE!
Guest

Gergely Kontra

By: a guest on Apr 29th, 2008  |  syntax: Ruby  |  size: 3.19 KB  |  views: 195  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
This paste has a previous version, view the difference. Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env ruby
  2.  
  3. require 'gtk2'
  4. require 'rational'
  5.  
  6. =begin
  7. A drawing area, which can be panned and zoomed.
  8. (requires rational)
  9. Panning is done with middle mouse drag, zooming is with the scrollwheel.
  10. To zoom only into x or y axis, hold down the shift or ctrl keys respectively.
  11. You must create the following method:
  12. expose_event event, cairo, coordinates
  13. where
  14. event is the expose event
  15. cairo is the cairo context
  16. coordinates is an array with the [xstart, ystart, xend, yend] coordinates
  17. =end
  18. class DragZoomDrawingArea < Gtk::DrawingArea
  19.         type_register
  20.  
  21.         def initialize
  22.                 super
  23.  
  24.                 @xscale = @yscale = 1.to_r
  25.                 @xoffset = @yoffset = 0.to_r
  26.                 @xscalestep = @yscalestep = 2.to_r
  27.                 @drag_sig_handlers = []
  28.  
  29.                 signal_connect('expose-event') {|widget, event|
  30.                         cairo = window.create_cairo_context
  31.                         cairo.scale(@xscale, @yscale)
  32.                         cairo.translate(@xoffset, @yoffset)
  33.  
  34.                         alloc = allocation
  35.                         width, height = alloc.width, alloc.height
  36.  
  37.                         xstart = (0.to_r - @xoffset) / @xscale
  38.                         xend = (width.to_r - @xoffset) / @xscale
  39.  
  40.                         ystart = (0.to_r - @yoffset) / @yscale
  41.                         yend = (height.to_r - @yoffset) / @yscale
  42.  
  43.                         expose_event widget, event, cairo, [xstart, ystart, xend, yend]
  44.                         true
  45.                 }
  46.  
  47.                 signal_connect('scroll-event') {|widget, event|
  48.                         do_xscale = do_yscale = true
  49.  
  50.                         if event.state & Gdk::Window::ModifierType::SHIFT_MASK != 0
  51.                                 do_yscale = false
  52.                         end
  53.                         if event.state & Gdk::Window::ModifierType::CONTROL_MASK != 0
  54.                                 do_xscale = false
  55.                         end
  56.  
  57.                         xscale_old, yscale_old = @xscale, @yscale
  58.                         case event.direction
  59.                         when Gdk::EventScroll::DOWN
  60.                                 @xscale /= @xscalestep if do_xscale
  61.                                 @yscale /= @yscalestep if do_yscale
  62.                         when Gdk::EventScroll::UP
  63.                                 @xscale *= @xscalestep if do_xscale
  64.                                 @yscale *= @yscalestep if do_yscale
  65.                         end
  66.  
  67.                         @xoffset = event.x.to_i.to_r / @xscale - (event.x.to_i / xscale_old - @xoffset)
  68.                         @yoffset = event.y.to_i.to_r / @yscale - (event.y.to_i / yscale_old - @yoffset)
  69.                         queue_draw
  70.                 }
  71.  
  72.                 @motion_cb = proc {|widget, event|
  73.                         deltax, deltay = event.x.to_i.to_r - @startx.to_i, event.y.to_i.to_r - @starty.to_i
  74.                         @xoffset += deltax / @xscale
  75.                         @yoffset += deltay / @yscale
  76.                         @startx, @starty = event.x, event.y
  77.                         queue_draw
  78.                 }
  79.  
  80.                 signal_connect('button-press-event') {|widget, event|
  81.                         if(event.button == 2)
  82.                                 @startx, @starty = event.x, event.y
  83.                                 @drag_sig_handlers << signal_connect('motion-notify-event', &@motion_cb)
  84.                         end
  85.                 }
  86.  
  87.                 signal_connect('button-release-event') {|widget, event|
  88.                         if(event.button == 2)
  89.                                 @drag_sig_handlers.reject!{|s| signal_handler_disconnect(s); true}
  90.                         end
  91.                 }
  92.  
  93.                 add_events(Gdk::Event::SCROLL_MASK |
  94.                         Gdk::Event::BUTTON_PRESS_MASK |
  95.                         Gdk::Event::BUTTON_RELEASE_MASK |
  96.                         Gdk::Event::POINTER_MOTION_MASK)
  97.         end
  98. end
  99.  
  100. class MyWindow < Gtk::Window
  101.         def initialize
  102.                 super('interactive graph')
  103.                 set_size_request(500,500)
  104.                 signal_connect("delete-event") { Gtk.main_quit;true }
  105.  
  106.  
  107.                 drawing_area = DragZoomDrawingArea.new
  108.                 def drawing_area.expose_event widget, event, cairo, disp
  109.                         cairo.set_source_rgb(1,0,0)
  110.                         cairo.rectangle(100, 100, 50, 50)
  111.                         cairo.stroke
  112.                 end
  113.                 add(drawing_area)
  114.                 show_all
  115.         end
  116. end
  117.  
  118. app = MyWindow.new
  119.  
  120. Gtk.main
clone this paste RAW Paste Data