246d4e1620
gratuitous differences from the C version. Make comment and indent style consistent. Don't use "this." where not needed. Override OnDeleteEvent rather than connecting one's own DeleteEvent signal. * sample/GtkDemo/DemoApplicationWindow.cs (static DemoApplicationWindow): register the Gtk logo icon with StockManager so it shows up correctly in the toolbar. (AddActions): Register the radio items as radio items so they work right. * sample/GtkDemo/DemoHyperText.cs (EventAfter): handle link-clicking from Widget.WidgetEventAfter (as in the C version), rather than ButtonRelease, now that WidgetEventAfter is wrapped. * sample/GtkDemo/DemoImages.cs (DemoImages): use Gtk.Image.LoadFromResource (particularly to make the animation work right). (OnDestroyed): handle clean up (remove the timeout, etc) * sample/GtkDemo/DemoMain.cs (LoadStream): Fix handling of blank lines and whitespace to match the C version. * sample/GtkDemo/DemoPixbuf.cs (Expose): Use System.Runtime.InteropServices.Marshal.Copy() to copy pixbuf.Pixels to pass to DrawRgbImageDithalign, to make this more like the C version (and probably faster?) (timeout): Remove the FIXME since it seems to work now * sample/GtkDemo/DemoStockBrowser.cs: Simplify a bunch. Use reflection to get the C# names of the stock icons rather than trying to correctly re-mangle the ids. Display the Label with the accelerator underlined. * sample/GtkDemo/DemoTextView.cs (AttachWidgets): use Gtk.Image.LoadFromResource, so the image is properly loaded as an animation, not a static image. Don't set the combobox's "Active" property (for consistency with the C version). (InsertText): Fix miscellaneous differences with the C version. Remove some leftover cruft from earlier workarounds for gtk# bugs. * sample/GtkDemo/DemoTreeStore.cs (AddColumns): Make this more like the C version so the checkboxes are sensitized and hidden correctly on a per-row basis. * sample/GtkDemo/DemoUIManager.cs: Make the radio menu items work. * sample/GtkDemo/README: * sample/GtkDemo/TODO: update svn path=/trunk/gtk-sharp/; revision=42481
218 lines
6.3 KiB
C#
218 lines
6.3 KiB
C#
/* Drawing Area
|
|
*
|
|
* GtkDrawingArea is a blank area where you can draw custom displays
|
|
* of various kinds.
|
|
*
|
|
* This demo has two drawing areas. The checkerboard area shows
|
|
* how you can just draw something; all you have to do is write
|
|
* a signal handler for ExposeEvent, as shown here.
|
|
*
|
|
* The "scribble" area is a bit more advanced, and shows how to handle
|
|
* events such as button presses and mouse motion. Click the mouse
|
|
* and drag in the scribble area to draw squiggles. Resize the window
|
|
* to clear the area.
|
|
*/
|
|
|
|
using System;
|
|
using Gtk;
|
|
using Gdk;
|
|
|
|
namespace GtkDemo
|
|
{
|
|
[Demo ("Drawing Area", "DemoDrawingArea.cs")]
|
|
public class DemoDrawingArea : Gtk.Window
|
|
{
|
|
private Pixmap pixmap = null;
|
|
|
|
public DemoDrawingArea () : base ("Drawing Area")
|
|
{
|
|
BorderWidth = 8;
|
|
|
|
VBox vbox = new VBox (false, 8);
|
|
vbox.BorderWidth = 8;
|
|
Add (vbox);
|
|
|
|
// Create the checkerboard area
|
|
Label label = new Label ("<u>Checkerboard pattern</u>");
|
|
label.UseMarkup = true;
|
|
vbox.PackStart (label, false, false, 0);
|
|
|
|
Frame frame = new Frame ();
|
|
frame.ShadowType = ShadowType.In;
|
|
vbox.PackStart (frame, true, true, 0);
|
|
|
|
DrawingArea da = new DrawingArea ();
|
|
// set a minimum size
|
|
da.SetSizeRequest (100,100);
|
|
frame.Add (da);
|
|
da.ExposeEvent += new ExposeEventHandler (CheckerboardExpose);
|
|
|
|
// Create the scribble area
|
|
label = new Label ("<u>Scribble area</u>");
|
|
label.UseMarkup = true;
|
|
vbox.PackStart (label, false, false, 0);
|
|
|
|
frame = new Frame ();
|
|
frame.ShadowType = ShadowType.In;
|
|
vbox.PackStart (frame, true, true, 0);
|
|
|
|
da = new DrawingArea ();
|
|
// set a minimum size
|
|
da.SetSizeRequest (100, 100);
|
|
frame.Add (da);
|
|
|
|
// Signals used to handle backing pixmap
|
|
da.ExposeEvent += new ExposeEventHandler (ScribbleExpose);
|
|
da.ConfigureEvent += new ConfigureEventHandler (ScribbleConfigure);
|
|
|
|
// Event signals
|
|
da.MotionNotifyEvent += new MotionNotifyEventHandler (ScribbleMotionNotify);
|
|
da.ButtonPressEvent += new ButtonPressEventHandler (ScribbleButtonPress);
|
|
|
|
|
|
// Ask to receive events the drawing area doesn't normally
|
|
// subscribe to
|
|
da.Events |= EventMask.LeaveNotifyMask | EventMask.ButtonPressMask |
|
|
EventMask.PointerMotionMask | EventMask.PointerMotionHintMask;
|
|
|
|
ShowAll ();
|
|
}
|
|
|
|
protected override bool OnDeleteEvent (Gdk.Event evt)
|
|
{
|
|
Destroy ();
|
|
return true;
|
|
}
|
|
|
|
private void CheckerboardExpose (object o, ExposeEventArgs args)
|
|
{
|
|
const int CheckSize = 10;
|
|
const int Spacing = 2;
|
|
|
|
DrawingArea da = o as DrawingArea;
|
|
|
|
// It would be a bit more efficient to keep these
|
|
// GC's around instead of recreating on each expose, but
|
|
// this is the lazy/slow way.
|
|
Gdk.GC gc1 = new Gdk.GC (da.GdkWindow);
|
|
gc1.RgbFgColor = new Gdk.Color (117, 0, 117);
|
|
|
|
Gdk.GC gc2 = new Gdk.GC (da.GdkWindow);
|
|
gc2.RgbFgColor = new Gdk.Color (255, 255, 255);
|
|
|
|
int i, j, xcount, ycount;
|
|
Gdk.Rectangle alloc = da.Allocation;
|
|
|
|
// Start redrawing the Checkerboard
|
|
xcount = 0;
|
|
i = Spacing;
|
|
while (i < alloc.Width) {
|
|
j = Spacing;
|
|
ycount = xcount % 2; // start with even/odd depending on row
|
|
while (j < alloc.Height) {
|
|
Gdk.GC gc;
|
|
if (ycount % 2 != 0)
|
|
gc = gc1;
|
|
else
|
|
gc = gc2;
|
|
da.GdkWindow.DrawRectangle (gc, true, i, j,
|
|
CheckSize, CheckSize);
|
|
|
|
j += CheckSize + Spacing;
|
|
++ycount;
|
|
}
|
|
i += CheckSize + Spacing;
|
|
++xcount;
|
|
}
|
|
|
|
// return true because we've handled this event, so no
|
|
// further processing is required.
|
|
args.RetVal = true;
|
|
}
|
|
|
|
private void ScribbleExpose (object o, ExposeEventArgs args)
|
|
{
|
|
Widget widget = o as Widget;
|
|
Gdk.Window window = widget.GdkWindow;
|
|
Rectangle area = args.Event.Area;
|
|
|
|
// We use the "ForegroundGC" for the widget since it already exists,
|
|
// but honestly any GC would work. The only thing to worry about
|
|
// is whether the GC has an inappropriate clip region set.
|
|
window.DrawDrawable (widget.Style.ForegroundGC (StateType.Normal),
|
|
pixmap,
|
|
area.X, area.Y,
|
|
area.X, area.Y,
|
|
area.Width, area.Height);
|
|
}
|
|
|
|
// Create a new pixmap of the appropriate size to store our scribbles
|
|
private void ScribbleConfigure (object o, ConfigureEventArgs args)
|
|
{
|
|
Widget widget = o as Widget;
|
|
Rectangle allocation = widget.Allocation;
|
|
|
|
pixmap = new Pixmap (widget.GdkWindow, allocation.Width, allocation.Height, -1);
|
|
|
|
// Initialize the pixmap to white
|
|
pixmap.DrawRectangle (widget.Style.WhiteGC, true, 0, 0,
|
|
allocation.Width, allocation.Height);
|
|
|
|
// We've handled the configure event, no need for further processing.
|
|
args.RetVal = true;
|
|
}
|
|
|
|
private void ScribbleMotionNotify (object o, MotionNotifyEventArgs args)
|
|
{
|
|
|
|
// paranoia check, in case we haven't gotten a configure event
|
|
if (pixmap == null)
|
|
return;
|
|
|
|
// This call is very important; it requests the next motion event.
|
|
// If you don't call Window.GetPointer() you'll only get a single
|
|
// motion event. The reason is that we specified PointerMotionHintMask
|
|
// in widget.Events. If we hadn't specified that, we could just use
|
|
// args.Event.X, args.Event.Y as the pointer location. But we'd also
|
|
// get deluged in events. By requesting the next event as we handle
|
|
// the current one, we avoid getting a huge number of events faster
|
|
// than we can cope.
|
|
|
|
int x, y;
|
|
ModifierType state;
|
|
args.Event.Window.GetPointer (out x, out y, out state);
|
|
|
|
if ((state & ModifierType.Button1Mask) != 0)
|
|
DrawBrush (o as Widget, x, y);
|
|
|
|
// We've handled it, stop processing
|
|
args.RetVal = true;
|
|
}
|
|
|
|
// Draw a rectangle on the screen
|
|
private void DrawBrush (Widget widget, double x, double y)
|
|
{
|
|
Rectangle update_rect = new Rectangle ((int)x - 3, (int)y - 3, 6, 6);
|
|
|
|
// Paint to the pixmap, where we store our state
|
|
pixmap.DrawRectangle (widget.Style.BlackGC, true,
|
|
update_rect.X, update_rect.Y,
|
|
update_rect.Width, update_rect.Height);
|
|
widget.GdkWindow.InvalidateRect (update_rect, false);
|
|
}
|
|
|
|
private void ScribbleButtonPress (object o, ButtonPressEventArgs args)
|
|
{
|
|
// paranoia check, in case we haven't gotten a configure event
|
|
if (pixmap == null)
|
|
return;
|
|
|
|
EventButton ev = args.Event;
|
|
if (ev.Button == 1)
|
|
DrawBrush (o as Widget, ev.X, ev.Y);
|
|
|
|
// We've handled the event, stop processing
|
|
args.RetVal = true;
|
|
}
|
|
}
|
|
}
|