// // AlphaPainter: Paint pictures by changing the alpha channel // of boxes in a grid // // Author: // Eric Butler // // To Compile: // mcs -debug AlphaPainter.cs -pkg:gtk-sharp-2.0 -pkg:mono-cairo // using System; using Cairo; using GLib; using Gtk; public class AlphaPainter { public static void Main () { Application.Init (); new AlphaPainter (); Application.Run (); } public AlphaPainter () { Window window = new Window ("Alpha Painter"); window.AppPaintable = true; window.SetSizeRequest (400, 400); on_alpha_screen_changed (window, null, null); AlphaPainterWidget painterWidget = new AlphaPainterWidget (); window.Add (painterWidget); window.ShowAll (); } private void on_alpha_screen_changed (Gtk.Widget pWidget, Gdk.Screen oldScreen, Widget label) { Gdk.Screen pScreen = pWidget.Screen; Gdk.Colormap pColormap = pScreen.RgbaColormap; if (pColormap == null) { //pColormap = pScreen.RgbColormap; throw new Exception ("screen does NOT support alpha - are you running Xgl/compmgr?"); } else Console.WriteLine ("screen supports alpha!"); pWidget.Colormap = pColormap; } } public class AlphaPainterWidget : DrawingArea { const int pixelCount = 10; double pixelWidth; double pixelHeight; double[,] pixels = new double[pixelCount, pixelCount]; bool leftButtonDown = false; bool rightButtonDown = false; double mouseX = 0; double mouseY = 0; PointD activePoint = new PointD (-1, -1); TimeoutHandler updateTimeout; double r = .2, g = .3, b = 0.4, a = 0.8; public AlphaPainterWidget () { for (int y = 0; y < pixelCount; y++) { for (int x = 0; x < pixelCount; x++) { pixels [x,y] = a; } } this.Events = this.Events | Gdk.EventMask.PointerMotionMask | Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask; updateTimeout = new TimeoutHandler (UpdateTick); GLib.Timeout.Add (200, updateTimeout); } private bool UpdateTick () { if (leftButtonDown | rightButtonDown) { ChangePixel (); } return true; } protected override bool OnButtonPressEvent (Gdk.EventButton eb) { if (eb.Button == 1) leftButtonDown = true; else if (eb.Button == 3) rightButtonDown = true; mouseX = eb.X; mouseY = eb.Y; ChangePixel (); return base.OnButtonPressEvent (eb); } protected override bool OnButtonReleaseEvent (Gdk.EventButton eb) { if (eb.Button == 1) leftButtonDown = false; else if (eb.Button == 3) rightButtonDown = false; return base.OnButtonReleaseEvent (eb); } protected override bool OnMotionNotifyEvent (Gdk.EventMotion em) { mouseX = em.X; mouseY = em.Y; ChangePixel (); return base.OnMotionNotifyEvent (em); } private void ChangePixel () { int x = (int)mouseX / (int)pixelWidth; int y = (int)mouseY / (int)pixelHeight; if (x <= pixelCount & y <= pixelCount & y >= 0 & x >= 0) activePoint = new PointD (x * pixelWidth, y * pixelHeight); else activePoint = new PointD (-1, -1); if (leftButtonDown | rightButtonDown) { if (x >= pixelCount | y >= pixelCount | y <= 0 | x <= 0) return; if (leftButtonDown) pixels [Convert.ToInt32 (x), Convert.ToInt32 (y)] -= 0.05f; else pixels [Convert.ToInt32 (x), Convert.ToInt32 (y)] += 0.05f; } this.QueueDraw (); } protected override bool OnExposeEvent (Gdk.EventExpose args) { Gdk.Window win = args.Window; Cairo.Context g = Gdk.CairoHelper.Create (win); g.Operator = Operator.Source; int x, y, w, h, d; win.GetGeometry (out x, out y, out w, out h, out d); Draw (g, w, h); (g as IDisposable).Dispose (); return true; } void Draw (Cairo.Context gr, int width, int height) { gr.Color = new Color (r, g, b, a); gr.Paint (); pixelWidth = Math.Floor ((double)width / (double)pixelCount); pixelHeight = Math.Floor ((double)height / (double)pixelCount); for (int y = 0; y < pixelCount; y++) { for (int x = 0; x < pixelCount; x++) { double rectX = (double)x * (double)pixelWidth; double rectY = (double)y * (double)pixelHeight; gr.Color = new Color (r, g, b, pixels[x,y]); gr.Rectangle (new Rectangle (rectX, rectY, pixelWidth, pixelHeight)); gr.Fill (); } } if (activePoint.X != -1 && activePoint.Y != -1) { gr.Color = new Color (1, 1, 1, 1); gr.Rectangle (activePoint.X, activePoint.Y, pixelWidth, pixelHeight); gr.Stroke (); } } }