0

I am trying to understand example for multitouch in Tizen. I am having problem with following part (this method is called every time I move my finger over the canvas by one pixel or more):

result
MainForm::OnDraw(void)
{
    __pCanvas->Show();
    __pCanvas->
   Canvas* pCanvas = GetCanvasN();

   if (pCanvas)
   {
      pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),
                    *__pCanvas, GetClientAreaBounds());
      delete pCanvas;
   }
   // Do not call Show(); it is called automatically after OnDraw() callback

   return E_SUCCESS;
}

Here is example of touch method:

void
MainForm::OnTouchMoved(const Control& source, const Point& currentPosition, const TouchEventInfo& touchInfo)
{
    __pointCount++;
    __strokes[__strokeCount].push_back(currentPosition);
    DrawLine(__prevPosition, currentPosition, Color::GetColor(COLOR_ID_BLACK));
    Tizen::Base::String string;
    string.Append("...");
    string.Append((int)__pointCount);
    __pCanvas->DrawText(Point(50, 300), string);
    __prevPosition = currentPosition;
    Invalidate(false);
    AppLog("OnTouchMoved");
}

And my drawLine() method:

void
MainForm::DrawLine(const Tizen::Graphics::Point& prevPoint, const Tizen::Graphics::Point& point, const Tizen::Graphics::Color& color)
{
    if (__pCanvas)
    {
        __pCanvas->DrawLine(prevPoint, point);
    }
}

I don't understand why new canvas is created here (why old one is copied to new one). Why old canvas doesn't update after calling drawLine()? Can't we just refresh somehow the old canvas?

UPDATE:

After some editing, I managed to create two canvas. I want to be able to draw only in __pCanvas bounds, but now they are "blue" and I have problems setting them to "red".

enter image description here

Here is my code:

result
MainForm::OnInitializing(void)
{
    (...)
    AddTouchEventListener(*this);
    SetMultipointTouchEnabled(false);
    //SetMultipointTouchEnabled(true);

    __pCanvas = new (std::nothrow) Canvas();
    Rectangle rect = Rectangle(GetBounds().x, GetBounds().y, GetBounds().width, GetBounds().height);
    result r = __pCanvas->Construct(rect);

    __pInformationCanvas = new (std::nothrow) Canvas();
    r = __pInformationCanvas->Construct(Rectangle(0, 0, GetBounds().width, verticalDivider));
    if (r == E_SUCCESS)
    {
        __pCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_WHITE));
        __pCanvas->Clear();

        __pInformationCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_BLACK));
        __pInformationCanvas->Clear();

        Font font;
        font.Construct(FONT_STYLE_PLAIN, FONT_SIZE);
        __pCanvas->SetFont(font);

        Invalidate(false);
    }

    return E_SUCCESS;
}

And the onDraw method:

result
MainForm::OnDraw(void)
{
    Canvas* pCanvas = GetCanvasN();
    if (pCanvas != null)
    {
        pCanvas->Clear();
        pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),
                      *__pCanvas,
                      GetClientAreaBounds());

        // Copy the second Canvas to the center of the Form's Canvas
        pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),
                      *__pInformationCanvas,
                      __pInformationCanvas->GetBounds());

        delete pCanvas;
    }

    // Do not call Show(). It will be called automatically after OnDraw() callback.
    return E_SUCCESS;
}
Marek
  • 3,935
  • 10
  • 46
  • 70
  • So you don't change the original canvas. –  Jun 27 '13 at 00:33
  • But I would like to change original... I don't know how could I... And also in touch methods I change original canvas so I really don't understand why I create copy in onDraw method. I updated the code. – Marek Jun 27 '13 at 00:35

1 Answers1

1

You can draw directly to the Form's Canvas if you want to. Try removing everything in OnDraw except for the return statement, removing the Invalidate calls from OnTouchPressed and OnTouchMoved, and replacing MainForm::DrawCircle with this:

void
MainForm::DrawCircle(const Tizen::Graphics::Point& point, const Tizen::Graphics::Color& color)
{
    Canvas* pCanvas = GetCanvasN();
    if (pCanvas)
    {
        Rectangle rcCircle(Point(point.x - ELLIPSE_RADIUS, point.y - ELLIPSE_RADIUS), Dimension(ELLIPSE_RADIUS * 2, ELLIPSE_RADIUS * 2));
        pCanvas->FillEllipse(color, rcCircle);

        delete pCanvas;
    }
}

The method they suggest in the example application is to have a separate Canvas that they draw into, and then copy that Canvas into the Form's Canvas in OnDraw. I would guess that GetCanvasN just creates a new Canvas object describing the same underlying surface, but I could be wrong. Feel free to examine the Tizen source code.

As for why they suggest this method; there could be several reasons. For example, if your Form ever gets invalidated you lose whatever you've drawn on the Form's Canvas. Restoring the stuff you had drawn with a single copy command is obviously much easier than to repeat every single draw command that you had performed up until then.
There could also be performance reasons - i.e. that performing a single copy command in OnDraw is more efficient in some way when dealing with on-screen surfaces.
Or it could just be the personal preference of the people who wrote the example app.


Edit: Here's an example of using two Canvases:

Create another Canvas in MainForm::OnInitializing:

__pCanvas = new (std::nothrow) Canvas();
result r = __pCanvas->Construct(GetBounds());
__pAnotherCanvas = new (std::nothrow) Canvas();
r = __pAnotherCanvas->Construct(Rectangle(0, 0, 100, 64));
if (r == E_SUCCESS)
{
    __pCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_WHITE));
    __pCanvas->Clear();
    __pAnotherCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_WHITE));
    __pAnotherCanvas->Clear();
    Invalidate(false);
}

Modify OnDraw to copy both Canvases to the Form's Canvas:

result
MainForm::OnDraw(void)
{
    Canvas* pCanvas = GetCanvasN();
    if (pCanvas != null)
    {
        pCanvas->Clear();
        pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),*__pCanvas, GetClientAreaBounds());

        // Copy the second Canvas to the center of the Form's Canvas
        int cx = GetClientAreaBounds().x + GetClientAreaBounds().width / 2;
        int cy = GetClientAreaBounds().y + GetClientAreaBounds().height / 2;
        pCanvas->Copy(Point(cx - __pAnotherCanvas->GetBounds().width / 2, cy - __pAnotherCanvas->GetBounds().height / 2),
                  *__pAnotherCanvas,
                  __pAnotherCanvas->GetBounds());


         delete pCanvas;
    }
    // Do not call Show(). It will be called automatically after OnDraw() callback.
    return E_SUCCESS;
}

Draw to the second Canvas somewhere, for example in OnTouchDoublePressed:

void MainForm:: OnTouchDoublePressed(const Control& source, const Point& currentPosition, const TouchEventInfo& touchInfo)
{
    Point point(0, 0);
    String str; str.Format(10, L"x = %d", currentPosition.x);
    __pAnotherCanvas->Clear();
    __pAnotherCanvas->DrawText(point, str, str.GetLength());
    Invalidate(false);
} 

Everytime you double-click somewhere on the Form's client area this will print the x-coordinate where you clicked at the center of the Form, using a second Canvas that is shown on top of your doodles.

Michael
  • 57,169
  • 9
  • 80
  • 125
  • I think you know what you are talking about. Could you please tell me how can I implement to that example two canvas: one for drawing and above it one small for displaying some data every time I move my finger on canvas? Can I add onTouchListener just to the drawing canvas not to whole canvas? Any code example would be great. To sum um, I want to modify examply and have two canvas: one for writing with finger on it and second for displaying information – Marek Jun 28 '13 at 00:10
  • You should probably show a mock-up of what you want the end result to look like, because it's not entirely clear that you really need two separate canvases. In any case, I've updated my answer with an example of how you could use two canvases. – Michael Jun 28 '13 at 08:04
  • Information that you provided is very helpful. However, there is one more thing. I want to be able to draw only in the drawing area. Now, when I start drawing, and I hold the button - I can enter __pInformationCanvas area and draw beneath it (becaus drawing canvas size is the whole (blue) area. I want to make drawing canvas to have size of the second red area. In other words - when I enter other area than drawing area, drawing should stop (onTouchMoved shouldn't fire). Please see the image attached. – Marek Jul 01 '13 at 01:03