// // The Pimp The Pathetic Image Manipulation Program // Copyright (c) 2004-2008 Sam Hocevar // All Rights Reserved // // $Id$ // // This library is free software. It comes without any warranty, to // the extent permitted by applicable law. You can redistribute it // and/or modify it under the terms of the Do What The Fuck You Want // To Public License, Version 2, as published by Sam Hocevar. See // http://sam.zoy.org/wtfpl/COPYING for more details. // using System; using Gtk; using Pipi; namespace ThePimp { public class PictureArea : Gtk.DrawingArea { private Pipi.Picture _p; private Adjustment _hadj = null, _vadj = null; private bool _drag = false; private double _xdrag, _ydrag; void HAdjust(object sender, EventArgs args) { QueueDraw(); } void VAdjust(object sender, EventArgs args) { QueueDraw(); } protected override bool OnExposeEvent(Gdk.EventExpose e) { bool ret = base.OnExposeEvent(e); if(_hadj == null || _vadj == null) return ret; using (Gdk.GC gc = new Gdk.GC(GdkWindow)) { int w = e.Area.Width; int h = e.Area.Height; int x = (int)_hadj.Value + e.Area.X; int y = (int)_vadj.Value + e.Area.Y; if(x + w > _p.Width) w = _p.Width - x < 0 ? 0 : _p.Width - x; if(y + h > _p.Height) h = _p.Height - y < 0 ? 0 : _p.Height - y; byte[] a = _p.GetPixels(w, h, x, y); GdkWindow.DrawRgb32Image(gc, e.Area.X, e.Area.Y, w, h, 0 /* no dithering */, a, w * 4); } return ret; } protected override void OnRealized() { base.OnRealized(); } protected override bool OnButtonPressEvent(Gdk.EventButton e) { if(e.Button == 2) { GdkWindow.Cursor = new Gdk.Cursor(Gdk.CursorType.Hand1); _drag = true; _xdrag = e.X; _ydrag = e.Y; } return base.OnButtonPressEvent(e); } protected override bool OnButtonReleaseEvent(Gdk.EventButton e) { if(e.Button == 2) { GdkWindow.Cursor = null; _drag = false; } return base.OnButtonReleaseEvent(e); } protected override bool OnMotionNotifyEvent(Gdk.EventMotion e) { if(_drag) { if(_hadj != null && e.X != _xdrag) { _hadj.Value += _xdrag - e.X; _xdrag = e.X; if(_hadj.Value + Allocation.Width > _p.Width) _hadj.Value = _p.Width - Allocation.Width; _hadj.ChangeValue(); } if(_vadj != null && e.Y != _ydrag) { _vadj.Value += _ydrag - e.Y; _ydrag = e.Y; if(_vadj.Value + Allocation.Height > _p.Height) _vadj.Value = _p.Height - Allocation.Height; _vadj.ChangeValue(); } } return base.OnMotionNotifyEvent(e); } protected override void OnSetScrollAdjustments(Adjustment hadj, Adjustment vadj) { _hadj = hadj; _vadj = vadj; if(hadj != null) hadj.ValueChanged += HAdjust; if(vadj != null) vadj.ValueChanged += VAdjust; } protected override void OnSizeAllocated(Gdk.Rectangle alloc) { base.OnSizeAllocated(alloc); if(_hadj != null) { _hadj.SetBounds(0, _p.Width, 1, alloc.Width, alloc.Width); if(_hadj.Value + alloc.Width > _p.Width) { _hadj.Value = _p.Width - alloc.Width; _hadj.ChangeValue(); } } if(_vadj != null) { _vadj.SetBounds(0, _p.Height, 1, alloc.Height, alloc.Height); if(_vadj.Value + alloc.Height > _p.Height) { _vadj.Value = _p.Height - alloc.Height; _vadj.ChangeValue(); } } } protected override void OnDestroyed() { if(_hadj != null) { _hadj.ValueChanged -= HAdjust; _hadj = null; } if(_vadj != null) { _vadj.ValueChanged -= VAdjust; _vadj = null; } } public PictureArea(Picture p) { _p = p; AddEvents((int)Gdk.EventMask.ButtonPressMask); AddEvents((int)Gdk.EventMask.ButtonReleaseMask); AddEvents((int)Gdk.EventMask.PointerMotionMask); } } public partial class PictureView : Gtk.ScrolledWindow { public readonly Picture Picture; public PictureView(Picture p) { Picture = p; Add(new PictureArea(p)); ShowAll(); } } }