0111: A Scale Widget to Control Graphic Placement
Last time, we did the simple version of a Scale
button. If you didn’t read that—depending on your skill level—it might be helpful in understanding what’s going on in today’s post. So, no mucky about, let’s get down to it…
The Scale-v-DrawingArea Demo
Okay, because we’re doing a bit of graphic work this time, we’ll need to import the usual graphical culprits:
import cairo.Context;
import gtk.DrawingArea;
And in the AppBox
class, we’ll be setting up two widgets, the Scale
and a DrawingArea
:
class AppBox : Box
{
MyScale myScale;
int localPadding = 0, globalPadding = 10;
bool expand = false, fill = false;
MyDrawingArea myDrawingArea;
this()
{
super(Orientation.VERTICAL, globalPadding);
myDrawingArea = new MyDrawingArea();
myScale = new MyScale(myDrawingArea);
packStart(myScale, expand, fill, localPadding);
packStart(myDrawingArea, true, true, 0); // LEFT justify
} // this()
} // class AppBox
We went over all this stuff in the Cairo drawing series (which started in blog post 0057 and continued to blog post 0064), so let’s move on to the more relevant details…
The MyScale Callback Function
This is where the action is:
void valueChanged(Range range)
{
double scaleValue = getValue();
ballDisplay.setBallPosition(cast(int)scaleValue);
} // valueChanged()
The callback hook-up is the same as the previous example, so no need to go over it again here. If you need to refresh your memory on this point, take a look at the previous post.
Breaking it down, we:
- call the inherited function
Scale.getValue()
, - so we can set the function-local variable
scaleValue
, - which is then passed to
ballDisplay
’ssetBallPosition()
function.
What’s ballDisplay
? That’s how the MyScale
class refers to the DrawingArea
we stuffed into the AppBox
. Here’s what I mean…
MyScale’s Constructor
Take a look at the constructor’s argument:
this(MyDrawingArea myDrawingArea)
{
super(Orientation.HORIZONTAL, minimum, maximum, step);
ballDisplay = myDrawingArea;
addOnValueChanged(&valueChanged);
} // this()
The AppBox
passes in a pointer to the DrawingArea
which is then renamed as ballDisplay
to put it into context for the coming operations. Not Context
as in Cairo Context
, but context as in circumstances… specifically, the circumstances of accessing the DrawingArea
from the Scale
button.
The MyDrawingArea Class
Let’s break this class down a bit…
The Class Preamble
class MyDrawingArea : DrawingArea
{
int ballX;
This variable keeps track of where the ball’s position… where it is at any given moment at runtime. We’ll see how that works momentarily.
The Constructor
this()
{
ballX = 30;
addOnDraw(&onDraw);
} // this()
We set an initial position for the graphic—a ball—and hook up the callback function which we’ll talk about now…
The Callback
As is usual with a DrawingArea
callback, all we do is draw:
bool onDraw(Scoped!Context context, Widget w)
{
context.setLineWidth(3); // prepare the context
context.arc(ballX, 50, 10, 0, 2 * 3.1415); // define the circle as an arc
context.stroke(); // and draw
return(true);
} // onDraw()
We set a line width, define the ball shape, draw it, and we’re out of there. Responding to changes in the Scale
’s slider happens in a different function:
The setBallPosition() Function
And this function is called directly from MyScale’s callback (the callback being the function which reacts to movement of the Scale
slider):
void setBallPosition(int x)
{
x *= 15; // move the ball a noticeable distance
ballX = x + 30;
queueDraw();
} // setBallPosition()
Now, because the Scale
’s Range
is from 0
to 10
, using a one-to-one ratio for moving the ball isn’t going to be that noticeable, so the first thing we do is take the value passed in from MyScale
’s callback and multiply it by 15
. That way we don’t have to squint to see the ball move.
Next, we update the value of ballX
, the ball’s position, and finally, force the DrawingArea
to do a redraw.
And that, ladies and gents, is that.
Conclusion
It’s fairly straightforward to control the position of a graphic in a DrawingArea
using a Scale
button (or, in fact, a ScaleButton
, but that I’ll leave as an exercise for you if you’re so inclined).
Until next time, be brave, code well, and don’t let the bugs bite.
Comments? Questions? Observations?
Did we miss a tidbit of information that would make this post even more informative? Let's talk about it in the comments.
- come on over to the D Language Forum and look for one of the gtkDcoding announcement posts,
- drop by the GtkD Forum,
- follow the link below to email me, or
- go to the gtkDcoding Facebook page.
You can also subscribe via RSS so you won't miss anything. Thank you very much for dropping by.
© Copyright 2024 Ron Tarrant