I'm not having much luck figuring out Gestures. I did find a few C-lang examples, but I'm not sure how they translate into D.
The problem seems to be how to get access to Gesture events. Signals trigger, but in the Gesture-based callbacks, the Events are null.
I'm not even sure if I've associated the Gesture with the DrawingArea properly. I'm also starting to wonder if the whole thing isn't just redundant and unnecessary, especially considering that there isn't a phone-based version of D (not that I'm aware of, anyway).
Here's my code (the relevant code is the last two classes at the bottom):
// Cairo: Use the Mouse to Draw a Curve
import std.stdio;
import std.conv;
import gtk.MainWindow;
import gtk.Main;
import gtk.Box;
import gtk.Widget;
import gdk.Event;
import gtk.Gesture;
import gtk.GestureSingle;
import cairo.Context;
import gtk.DrawingArea;
import glib.Timeout;
void main(string[] args)
{
TestRigWindow testRigWindow;
Main.init(args);
testRigWindow = new TestRigWindow();
Main.run();
} // main()
class TestRigWindow : MainWindow
{
string title = "Cairo: Draw Cubic Bezier with Mouse";
AppBox appBox;
this()
{
super(title);
setSizeRequest(640, 360);
addOnDestroy(&quitApp);
appBox = new AppBox();
add(appBox);
showAll();
} // this() CONSTRUCTOR
void quitApp(Widget widget)
{
writeln("Bye.");
Main.quit();
} // quitApp()
} // class TestRigWindow
class AppBox : Box
{
MyDrawingArea myDrawingArea;
this()
{
super(Orientation.VERTICAL, 10);
myDrawingArea = new MyDrawingArea();
packStart(myDrawingArea, true, true, 0); // LEFT justify
} // this()
} // class AppBox
class NoodleGesture : GestureSingle
{
MyDrawingArea _myDrawingArea;
this(MyDrawingArea myDrawingArea)
{
super(myDrawingArea);
_myDrawingArea = myDrawingArea;
writeln("NoodleGesture built");
addOnUpdate(&onUpdate);
addOnBegin(&onBegin);
addOnEnd(&onEnd);
} // this()
public void onUpdate(Event event, Gesture gesture)
{
writeln("onUpdate()");
_myDrawingArea.updateCoordinates(event);
} // onUpdate()
public void onBegin(Event event, Gesture gesture)
{
writeln("onBegin(), event = ", event);
_myDrawingArea.beginDraw(event);
} // onBegin()
public void onEnd(Event event, Gesture gesture)
{
writeln("onEnd()");
_myDrawingArea.endDraw(event);
} // onEnd()
} // class NoodleGesture
class MyDrawingArea : DrawingArea
{
Timeout _timeout;
int fps = 1000 / 24; // 24 frames per second
bool dragAndDraw = false;
double xStart = 25, yStart = 128;
double controlPointX1 = 153, controlPointY1 = 230,
controlPointX2 = 25, controlPointY2 = 25,
xEnd, yEnd;
NoodleGesture noodleGesture;
this()
{
addOnDraw(&onDraw);
noodleGesture = new NoodleGesture(this);
} // this()
bool onDraw(Scoped!Context context, Widget w)
{
writeln("onDraw()");
if(_timeout is null)
{
_timeout = new Timeout(fps, &onFrameElapsed, false);
}
if(dragAndDraw == true)
{
// set up and draw a cubic Bezier
context.setLineWidth(3);
context.setSourceRgb(0.3, 0.2, 0.1);
context.moveTo(xStart, yStart);
context.curveTo(controlPointX1, controlPointY1, controlPointX2, controlPointY2, xEnd, yEnd);
context.stroke();
}
return(true);
} // onDraw()
bool onFrameElapsed()
{
GtkAllocation size;
getAllocation(size);
if(dragAndDraw == true)
{
queueDrawArea(size.x, size.y, size.width, size.height);
}
return(true);
} // onFrameElapsed()
void beginDraw(Event event)
{
writeln("beginDraw() event = ", event);
// Turn on context canvas redraw. Click-n-hold a mouse button to start
// drawing a cubic Bezier and as long as the mouse button is depressed,
// the end point of the curve will follow the mouse pointer. Let go, and
// the Bezier will freeze in place.
dragAndDraw = true;
GdkEventButton* mouseEvent = event.button;
xStart = event.button.x;
yStart = event.button.y;
} // beginDraw()
void updateCoordinates(Event event)
{
writeln("updateCoordinates()");
// get the curve's end point
xEnd = event.motion.x;
yEnd = event.motion.y;
// Recalculate the control points so we always have
// a nice-looking double curve.
controlPointX1 = xEnd;
controlPointY1 = yStart;
controlPointX2 = xStart;
controlPointY2 = yEnd;
} // updateCoordinates()
void endDraw(Event event)
{
writeln("endDraw()");
GdkEventButton* buttonEvent = event.button;
xEnd = event.button.x;
yEnd = event.button.y;
// When the mouse button is released, stop redrawing the context canvas.
dragAndDraw = false;
} // endDraw()
} // class MyDrawingArea