Draw Surface Widget Documentation
Introduction
The Draw Surface Widget document covers:
- Creating and customizing Draw Surface widgets using Microchip Graphics Suite (MGS) Harmony Composer.
- Draw Surface widget properties.
- Handling Draw Surface widget properties and events through application code.
- Draw Surface widget example project.
- Application Programming Interfaces (APIs) specific to Draw Surface widgets.
Designing Draw Surface Widgets Using MGS Harmony Composer
Follow these steps to add a Draw Surface widget to your design:
In the Graphic Composer, locate the DrawSurfaceWidget within the Toolbox on the left panel. Drag and position this widget to your preferred location on the screen.
Enable the Draw Notification event:
Managing Draw Surface Widget Scheme
Schemes control the look and feel of a widget.
To learn how to set the scheme for Draw Surface widget, click on the ? (question mark) button next to the Scheme Property editor of the Object Editor.
This will launch the Draw Surface Scheme Helper window containing tips on how different sections of the scheme settings manipulate various elements of the Image Sequence widget.
By default, the border is set to none, making only the Base scheme color visible.
Figure 5 shows an example color scheme and the resulting Draw Surface appearance when border is set to line. In this case, the Shadow Dark color will represent the line color.
Figure 6 shows an example color scheme and the resulting Draw Surface appearance when the border is set to bevel.
The information from the Draw Surface Scheme helper and the example color scheme is summarized in Figure 7.
Draw Surface Properties
Name | This will be used to reference the Draw Surface widget by the application. Example - Screen0_DrawSurfaceWidget_0. |
Draw Notification | Enabling this will generate an event when the Draw Surface needs to paint. |
Table 1: Draw Surface Properties
Managing Draw Surface Widget Through Programming
Once the graphical design is completed using MGS Composer, MCC generates the required code for all the widgets based on the properties set in the Object Editor. To learn more about the process flow between designing a User Interface (UI) and developing application code, refer to the "Designing an Application with Microchip Graphics Suite (MGS)" page.
Let us suppose that a Draw Surface widget is created with the following properties in MGS Composer:
For the Draw Surface widget with the properties shown in Figure 8, MCC will automatically generate the following lines of code in src\confg\default\gfx\legato\generated\screen\le_gen_screen_Screen0.c:
- A new Draw Surface widget is created by the variable name Screen0_DrawSurfaceWidget_0:
Screen0_DrawSurfaceWidget_0 = leDrawSurfaceWidget_New();
- Its position is set to pixel location 20x40:
Screen0_DrawSurfaceWidget_0->fn->setPosition(Screen0_DrawSurfaceWidget_0, 20, 40);
- The drawing surface size is set to have a width of 760 pixels and a height of 400 pixels:
Screen0_DrawSurfaceWidget_0->fn->setSize(Screen0_DrawSurfaceWidget_0, 760, 400);
- Its scheme is set to WhiteScheme:
Screen0_DrawSurfaceWidget_0->fn->setScheme(Screen0_DrawSurfaceWidget_0, &WhiteScheme);
- The border type is set to line:
Screen0_DrawSurfaceWidget_0->fn->setBorderType(Screen0_DrawSurfaceWidget_0, LE_WIDGET_BORDER_LINE);
- The draw notification event is set to event_Screen0_DrawSurfaceWidget_0_OnDraw:
Screen0_DrawSurfaceWidget_0->fn->setDrawCallback(Screen0_DrawSurfaceWidget_0, event_Screen0_DrawSurfaceWidget_0_OnDraw);
- Finally, the Draw Surface Widget is added to the screen:
Screen0_DrawSurfaceWidget_0->fn->addChild(root0, (leWidget*)Screen0_DrawSurfaceWidget_0);
Application Code
The default code generated by MCC sets the initial state of the widget. The property or behavior of the widgets can be changed by using the APIs discussed above, in the application code. Additional application code information related to the Draw Surface widget is presented below.
Here is an example to draw a rectangle or a previously filled array when the draw notification event is triggered.
OnDraw event is called and using native APIs drawings can be done */
leBool event_Screen0_DrawSurfaceWidget_0_OnDraw(leDrawSurfaceWidget* sfc, leRect* bounds)
{
leBool retval = LE_TRUE;
switch(drawCmd)
{
case SCRN_DRAW_RECT:
{
leRenderer_FillArea(damagedRect.x,
damagedRect.y,
pointSize, pointSize,
clr,
255);
break;
}
case SCRN_DRAW_RAND:
{
/*WARNING - modifying pixel by pixel all the widget area may produce screen tearing on hardware devices
* - issue is not seen on simulator due to drawing speed
* - this method was only used here for demo purpose on how to modify each pixel
*/
for (int i = 0; i < DRAWSURFACE_ARRAY_X_SIZE; i++)
for (int j = 0; j < DRAWSURFACE_ARRAY_Y_SIZE; j++)
leRenderer_PutPixel_Safe(i + DRAWSURFACE_X_OFFSET,
j + DRAWSURFACE_Y_OFFSET,
(leColor)drawsurface[i][j]);
break;
}
case SCRN_DRAW_ERASE:
{
break;
}
default:
{
break;
}
}
return retval;
}
Draw Surface Widget Example Project
Refer to the Draw Surface widget example project in GitHub:
In this example, we show:
- How to configure Draw Surface widget.
- How to capture touch input using filter event.
- How to draw back the touched pixels on the Draw Surface widget.
- How to draw a random generated image on the Draw Surface widget.
- How to clear the Draw Surface area.
MGS Simulator Output
Callback functions for handling the screen events are defined in the app.c file.
- When the screen is shown, an event filter is installed to capture the touch coordinates. The same event filter is removed when the screen is changed.
{
Screen0_DrawSurfaceWidget_0->fn->installEventFilter(Screen0_DrawSurfaceWidget_0, DrawSurface_eventFilter);
}
void Screen0_OnHide(void)
{
Screen0_DrawSurfaceWidget_0->fn->removeEventFilter(Screen0_DrawSurfaceWidget_0, DrawSurface_eventFilter);
}
- The event filter will help to capture the touch. In this example, we only capture the touch down and move event. When a touch point is detected, it will be checked if it's in the Draw Surface area and a rectangle that will mark the damaged area is created.
Using the _damageArea() API will optimize the drawing process by only invalidating the area that needs to be updated. While using the widget, the invalidate API will redraw the complete widget (the previously drawn points will also be lost in this situation).
- The color buttons change color based on the release event, and the slider will change the line width based on the value change event. The color buttons and slider are shown in Figure 9, and the button for violet color and slider value change events are presented below.
{
clr = COLOR_VIOLET;
}
void event_Screen0_SliderWidget_0_OnValueChanged(leSliderWidget* scr)
{
pointSize = scr->fn->getValue(scr) * DEFAULT_POINT_SIZE;
}
- The rectangle that is created when a touch point is detected will mark the damaged area, and can also be used by the leRenderer_FillArea() API to draw back the expected area.
{
leRenderer_FillArea(damagedRect.x,
damagedRect.y,
pointSize, pointSize,
clr,
255);
break;
}
- Pressing the random button will create a 2D array of size 760x400 with a random color for each pixel, and will draw it on the Draw Surface widget using the leRenderer_PutPixel_Safe() API. The complete widget is invalidated in this situation, as all its surface needs to be updated.
{
int i,j;
// Create a matrix with random colors in it
for (i = 0; i < DRAWSURFACE_ARRAY_X_SIZE; i++)
for (j = 0; j < DRAWSURFACE_ARRAY_Y_SIZE; j++)
drawsurface[i][j] = (rand() * rand()) | 0x000000FF;
drawCmd = SCRN_DRAW_RAND;
Screen0_DrawSurfaceWidget_0->fn->invalidate(Screen0_DrawSurfaceWidget_0);
}
case SCRN_DRAW_RAND:
{
/*WARNING - modifying pixel by pixel all the widget area may produce screen tearing on hardware devices
* - issue is not seen on simulator due to drawing speed
* - this method was only used here for demo purpose on how to modify each pixel
*/
for (int i = 0; i < DRAWSURFACE_ARRAY_X_SIZE; i++)
for (int j = 0; j < DRAWSURFACE_ARRAY_Y_SIZE; j++)
leRenderer_PutPixel_Safe(i + DRAWSURFACE_X_OFFSET,
j + DRAWSURFACE_Y_OFFSET,
(leColor)drawsurface[i][j]);
break;
}
- In order to clear the Draw Surface area, it's enough to just invalidate the widget. This way the library will clear its area and nothing will be drawn again on it, as no specific case for this situation was created. One can also redraw the complete widget with a specific background if clear may require another background color.
{
drawCmd = SCRN_DRAW_ERASE;
//To show a clean drawing surface it's enough to invalidate the widget.
Screen0_DrawSurfaceWidget_0->fn->invalidate(Screen0_DrawSurfaceWidget_0);
}
Draw Surface Widget APIs Description
The Draw Surface widget does not have a specific API. For a description of APIs common to all widgets, refer to the "Base Widget Documentation" page.