Wisegui learns to paint


BGE 1.2 can export the Painter Control

The Wisegui library has been updated to support the Painter Control, a canvas. The Painter Control can be exported by Bitwise Gui Editor 1.2


Using the Painter Control

In this episode, kPainter, the painter control, is used to display three circles. kAngle, a knob, rotates the picture.


Watch this movie:

The class DaVinci contains data and the logic to manipulate it. The view, MainView in this case, uses the data object as an extension. The view receives a pointer to data, &_davinci, through "SetData".

    
    View *view = new MainView(this);
    _gui = new Gui(this, GUI_WIDTH, GUI_HEIGHT);
    _gui->SetView(view);
    setEditor(_gui);

    view->SetData(&_davinci);
    

You draw on the Painter Control using its overlay, the overlay is a gdiplus bitmap. You retrieve the bitmap using "GetOverlay".

    
void MainView::OnLoad() 
{
	ControlPtr c = GetControl(kPainter);
	Painter *painter = (Painter *)c;
	DaVinci *davinci = (DaVinci *)GetData();
	davinci->Draw(painter->GetOverlay());
}
    

Gdiplus stuff. bmp is the overlay.

    
void DaVinci::Draw(Bitmap *bmp)
{
	double k = 3.1415 / 180;
	int ray = 32;
	int w2 = 200 / 2, h2 = 200 / 2;
	
	double a1 = (angle + 0) * k;
	double a2 = (angle + 120) * k;
	double a3 = (angle + 240) * k;

	PointF pts[] = 
	{
		PointF(w2 + 32 * cos(a1), w2 + 32 * sin(a1)),
		PointF(w2 + 32 * cos(a2), w2 + 32 * sin(a2)),
		PointF(w2 + 32 * cos(a3), w2 + 32 * sin(a3))
	};

	Graphics *g = Graphics::FromImage(bmp);
	g->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
	g->Clear(Color(0, 0, 0, 0));

	SolidBrush red(0xFFFF0000);
	SolidBrush green(0xFF00FF00);
	SolidBrush blue(0xFF0000FF);

	Rect r(0, 0, 12, 12);
	r.Offset((int)pts[0].X, (int)pts[0].Y);
	g->FillEllipse(&red, r);

	Rect r1(0, 0, 12, 12);
	r1.Offset((int)pts[1].X, (int)pts[1].Y);
	g->FillEllipse(&green, r1);

	Rect r2(0, 0, 12, 12);
	r2.Offset((int)pts[2].X, (int)pts[2].Y);
	g->FillEllipse(&blue, r2);

	delete g;
}    
    

After the knob is updated, OnUpdate is called. You have a chance to update the painter's overlay. The Painter control doesn't know that its overlay is changed, so explicitly "Redraw" it.

    
void MainView::OnUpdate(int index, double value) 
{
	if (index == kAngle)
	{
		ControlPtr c = GetControl(kAngle);
		double angle = c->GetValue();

		c = GetControl(kPainter);
		Painter *painter = (Painter *)c;
		DaVinci *davinci = (DaVinci *)GetData();
		davinci->SetAngle((int)(angle));
		davinci->Draw(painter->GetOverlay());
		Redraw(c);
	}
}    
    

WiseScope

In the previous episode, we have seen how a change in a control can trigger the update of the Painter Control. You may want to update the painter independently of other controls. A timed update may be the case. WiseScope is a minimal oscilloscope implementation that shows how.


Watch this movie:

At some point, in a thread, for instance, you can request a control update using RequestControlUpdate. RequestControlUpdate, now, has three request types.

  1. URT_INDIRECT: for hosted parameters.
  2. URT_DIRECT: see the Movie Control.
  3. URT_DIRECT2: for the Painter Control

pntScreen is the Painter Control, the oscilloscope screen, in this case.


    if (pw->buddy->IsGuiOpen())
        pw->buddy->GetGui()->RequestControlUpdate(
            pntScreen, (int)li, URT_DIRECT2);
    

URT_DIRECT2 requests an update and sends the control a value, but it DOESN'T redraw the control. When OnUpdate is called, you update the overlay and redraw the control.


// Called when a control's value needs to be updated
void ScopeView::OnUpdate(int index, double value) 
{
	if (index == pntScreen)
	{
		ControlPtr c = GetControl(pntScreen);
		Painter *painter = (Painter *)c;
		Engine *e = (Engine *)GetData();
		PLIST_ITEM li = (PLIST_ITEM)(int)c->GetValue();
		Bitmap *bmp = painter->GetOverlay();
		e->Display(bmp, li); // update the overlay
		Redraw(c); // redraw the control
	}
}
    

Mouse events

The View class in wisegui v1.3 fires mouse events by calling the OnMouse method. Override "OnMouse" to receive mouse events. Mouse events are: mouse down/up/move. Mouse move is actually a mouse drag. BGE 1.2 exports views that are "mouse events" enabled.

The following example uses mouse events and the Painter control to implement an ADSR control.


// MainView.cpp

#include "MainView.h"
#include "envelope.h"

void MainView::OnLoad() 
{
	ControlPtr c = GetControl(pntCanvas);
	Painter *p = (Painter *)c;
	Gdiplus::Bitmap *bmp = p->GetOverlay();

	Envelope *env = (Envelope *)GetData();
	env->SetBitmap(bmp);
	env->Draw();
}

void MainView::OnUpdate(int index, double value) {}

void MainView::OnMouse(int index, int event, int x, int y, int info)
{
	if (index == pntCanvas)
	{
		Envelope *env = (Envelope *)GetData();

		if (event == MOUSE_DOWN)
			env->MouseDown(x, y);		       
		if (event == MOUSE_UP)
			env->MouseUp(x, y);		
		if (event == MOUSE_MOVE)
			env->MouseDrag(x, y);

		ControlPtr c = GetControl(index);
		Redraw(c);
	}
}
    
Watch this movie: