SVG ScaleAndRotate (Example)
Jump to navigation
Jump to search
| GUI_SVG_ScaleAndRotate.c | |
|---|---|
| File(s) required |
|
| Runs in simulation | Yes |
| Runs on target | Yes |
| Display size | any |
| Download | GUI_SVG_ScaleAndRotate.c |
This example makes use of widgets and emWin's SVG module. The five buttons that allow selection of an SVG file, as well as the canvas window draw each draw an SVG file.
Using the sliders, you can change the scaling and rotation parameters of the SVG.
Furthermore, this sample utilizes the new layout feature of emWin which makes the UI fully scalable between different display sizes.
Demo
Code
This is an excerpt of the code, without the SVG files in binary form. You can download the full source code here.
/*********************************************************************
* SEGGER Microcontroller GmbH *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2025 SEGGER Microcontroller GmbH *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
**********************************************************************
** emWin V6.44 - Graphical user interface for embedded applications **
emWin is protected by international copyright laws. Knowledge of the
source code may not be used to write a similar product. This file may
only be used in accordance with a license and should not be re-
distributed in any way. We appreciate your understanding and fairness.
----------------------------------------------------------------------
File : GUI_SVG_ScaleAndRotate.c
Purpose : Demonstration of scaling and rotating SVGs within a
window.
Requirements: WindowManager - (x)
MemoryDevices - ( )
AntiAliasing - (x)
VNC-Server - ( )
PNG-Library - ( )
TrueTypeFonts - ( )
---------------------------END-OF-HEADER------------------------------
*/
#include <stdio.h>
#include <string.h>
#include "DIALOG.h"
#include "WM_Layout.h"
/*********************************************************************
*
* Resources
*
**********************************************************************
*/
// The five SVG files would be here ...
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
//
// Widget IDs
//
#define ID_WINDOW_0 (GUI_ID_USER + 0x00)
#define ID_TEXT_HEADER (GUI_ID_USER + 0x01)
#define ID_SLIDER_SCALE (GUI_ID_USER + 0x05)
#define ID_SLIDER_ANGLE (GUI_ID_USER + 0x06)
#define ID_SVG_BUTTON_SEGGER (GUI_ID_USER + 0x07)
#define ID_SVG_BUTTON_TIGER (GUI_ID_USER + 0x08)
#define ID_SVG_BUTTON_WEATHER (GUI_ID_USER + 0x09)
#define ID_SVG_BUTTON_DATAREPORT (GUI_ID_USER + 0x0A)
#define ID_SVG_BUTTON_CITY (GUI_ID_USER + 0x0B)
#define ID_WINDOW_CANVAS (GUI_ID_USER + 0x0C)
//
// Custom limitation to the scale factor so that scaled bitmap does not exceed LCD.
//
#define MIN_SCALE 100
#define MAX_SCALE 3000
#define START_SCALE 400
//
// Window related
//
#define FRAME_SIZE_BUTTON 3
#define WINDOW_PADDING 20
/*********************************************************************
*
* Types
*
**********************************************************************
*/
typedef struct {
int ButtonId;
const void * pSVG;
U32 NumBytesSVG;
} SVG_BUTTON_DATA;
typedef struct {
int xSize;
int ySizeShaft;
} SLIDER_SIZES;
/*********************************************************************
*
* Static const data
*
**********************************************************************
*/
/*********************************************************************
*
* _aSvgButtons
*/
static const SVG_BUTTON_DATA _aSvgButtons[] = {
{ ID_SVG_BUTTON_SEGGER, _acSEGGER_logo, sizeof(_acSEGGER_logo) },
{ ID_SVG_BUTTON_TIGER, _acTiger, sizeof(_acTiger) },
{ ID_SVG_BUTTON_WEATHER, _acWeather, sizeof(_acWeather) },
{ ID_SVG_BUTTON_DATAREPORT, _acDataReport, sizeof(_acDataReport) },
{ ID_SVG_BUTTON_CITY, _acCity, sizeof(_acCity) },
};
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static int _Mag;
static int _Angle;
static GUI_SVG_Handle _hSVG;
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _cbSkinSlider()
*/
static int _cbSkinSlider(const WIDGET_ITEM_DRAW_INFO * pDraw) {
GUI_RECT rThumb, r;
int xSizeWidget, ySizeWidget;
int yPosThumb;
const GUI_RECT * pClip;
int xSizeShaft, xSizeThumb;
int Radius;
switch (pDraw->Cmd) {
//
// Do everything in the thumb command because we need the thumb position
// for the shaft too.
//
case WIDGET_ITEM_DRAW_THUMB:
pClip = WM_SetUserClipRect(NULL);
rThumb.x0 = pDraw->x0;
rThumb.y0 = pDraw->y0;
rThumb.x1 = pDraw->x1;
rThumb.y1 = pDraw->y1;
yPosThumb = rThumb.y0 + ((rThumb.y1 - rThumb.y0 + 1) / 2);
xSizeWidget = WM_GetXSize(pDraw->hWin);
ySizeWidget = WM_GetYSize(pDraw->hWin);
//
// Draw upper half of shaft
//
GUI_SetColor(0xFF54B1F1);
xSizeThumb = rThumb.x1 - rThumb.x0 + 1;
xSizeShaft = (xSizeThumb / 3);
r.y0 = 0;
r.x0 = (xSizeWidget / 2) - (xSizeShaft / 2);
r.x1 = r.x0 + xSizeShaft - 1;
r.y1 = yPosThumb;
Radius = (r.x1 - r.x0) / 2;
GUI_AA_FillRoundedRectEx(&r, Radius);
//
// Draw lower part of shaft
//
GUI_SetColor(0xFFA3A4A6);
r.y0 = r.y1;
r.y1 = ySizeWidget - 1;
GUI_AA_FillRoundedRectEx(&r, Radius);
//
// Draw thumb
//
GUI_SetColor(0xFF4488D7);
GUI_AA_FillRoundedRectEx(&rThumb, Radius);
//
WM_SetUserClipRect(pClip);
break;
default:
return 0;
}
return 0;
}
/*********************************************************************
*
* _cbSvgCanvas
*/
static void _cbSvgCanvas(WM_MESSAGE * pMsg) {
float sc, a;
GUI_SVG_INFO Svg;
int xSize, ySize;
float x, y;
GUI_RECT r;
switch (pMsg->MsgId) {
case WM_PAINT:
WM_GetClientRect(&r);
GUI_SetBkColor(GUI_GRAY_D0);
GUI_ClearRectEx(&r);
//
// Move SVG to center of canvas.
//
xSize = WM_GetWindowSizeX(pMsg->hWin);
ySize = WM_GetWindowSizeY(pMsg->hWin);
GUI_SVG_GetInfoH(_hSVG, &Svg);
GUI_SVG_Identity(_hSVG);
x = ((float)xSize / 2.0f) - (Svg.xSize / 2);
y = ((float)ySize / 2.0f) - (Svg.ySize / 2);
GUI_SVG_Translate(_hSVG, x, y);
//
// Scale and rotate around SVG center point
//
sc = (float)_Mag / 1000.F;
GUI_SVG_ScaleEx(_hSVG, sc, sc, Svg.xSize / 2, Svg.ySize / 2);
a = (float)_Angle / 10.0f;
GUI_SVG_Rotate(_hSVG, a);
GUI_SVG_DrawH(_hSVG, 0, 0);
//
// Draw thin frame.
//
GUI_SetColor(GUI_BLACK);
GUI_DrawRectEx(&r);
break;
default:
WINDOW_Callback(pMsg);
break;
}
}
/*********************************************************************
*
* _UpdateSvgSize
*/
static void _UpdateSvgSize(BUTTON_Handle hButton) {
int xSize, ySize;
GUI_SVG_Handle hSVG;
float x, y;
GUI_SVG_INFO Svg;
//
// Update SVG size.
//
BUTTON_GetUserData(hButton, &hSVG, sizeof(hSVG));
xSize = WM_GetWindowSizeX(hButton);
ySize = WM_GetWindowSizeY(hButton);
GUI_SVG_Identity(hSVG);
GUI_SVG_ScaleToSize(hSVG, xSize - (FRAME_SIZE_BUTTON * 2), 0);
GUI_SVG_GetInfoH(hSVG, &Svg);
x = ((float)xSize / 2.0f) - (Svg.BBox.xMax / 2.0f);
y = ((float)ySize / 2.0f) - (Svg.BBox.yMax / 2.0f);
GUI_SVG_Translate(hSVG, x, y);
}
/*********************************************************************
*
* _cbButtonSvg
*/
static void _cbButtonSvg(WM_MESSAGE * pMsg) {
const SVG_BUTTON_DATA * pData = NULL;
GUI_RECT r;
GUI_SVG_Handle hSVG;
switch (pMsg->MsgId) {
case WM_SET_CALLBACK:
BUTTON_SetToggleMode(pMsg->hWin, 1);
_UpdateSvgSize(pMsg->hWin);
break;
case WM_PAINT:
WM_GetClientRectEx(pMsg->hWin, &r);
GUI_SetBkColor(GUI_WHITE);
GUI_Clear();
GUI_SetColor(GUI_GRAY_D0);
GUI_AA_FillRoundedRectEx(&r, FRAME_SIZE_BUTTON);
BUTTON_GetUserData(pMsg->hWin, &hSVG, sizeof(hSVG));
GUI_SVG_DrawH(hSVG, 0, 0);
if (BUTTON_IsPressed(pMsg->hWin)) {
GUI_SetColor(0xFFEA6256);
GUI_SetPenSize(FRAME_SIZE_BUTTON);
GUI_AA_DrawRoundedFrameEx(&r, FRAME_SIZE_BUTTON);
} else {
GUI_SetColor(GUI_BLACK);
GUI_AA_DrawRoundedFrameEx(&r, FRAME_SIZE_BUTTON);
}
break;
case WM_SIZE:
_UpdateSvgSize(pMsg->hWin);
break;
case WM_DELETE:
BUTTON_GetUserData(pMsg->hWin, &hSVG, sizeof(hSVG));
GUI_SVG_Delete(hSVG);
break;
default:
BUTTON_Callback(pMsg);
}
}
/*********************************************************************
*
* _CreateSvgButton
*/
static void _CreateSvgButton(const SVG_BUTTON_DATA * pData, WM_HWIN hParent) {
WM_HWIN hWin;
GUI_SVG_Handle hSVG;
hWin = BUTTON_CreateUser(0, 0, 1, 1, hParent, WM_CF_SHOW, 0, pData->ButtonId, sizeof(GUI_SVG_Handle));
hSVG = GUI_SVG_Create(pData->pSVG, pData->NumBytesSVG);
BUTTON_SetUserData(hWin, &hSVG, sizeof(hSVG));
WM_SetCallback(hWin, _cbButtonSvg);
}
/*********************************************************************
*
* _GetFont
*/
static const GUI_FONT * _GetFont(void) {
int ySize;
ySize = LCD_GetYSize();
if (ySize <= 160) {
return &GUI_Font12_ASCII_AA4;
} else if (ySize <= 272) {
return &GUI_Font24_ASCII_AA4;
} else if (ySize <= 480) {
return &GUI_Font32_ASCII_AA4;
} else if (ySize <= 720) {
return &GUI_Font48_ASCII_AA4;
} else {
return &GUI_Font64_ASCII_AA4;
}
}
/*********************************************************************
*
* _GetSliderSizes
*/
static void _GetSliderSizes(SLIDER_SIZES * pSizes) {
int xSize, ySize;
xSize = LCD_GetXSize();
ySize = LCD_GetYSize();
pSizes->xSize = 0.05f * xSize;
pSizes->ySizeShaft = 0.03125f * ySize;
}
/*********************************************************************
*
* _CreateWidgets
*/
static void _CreateWidgets(WM_HWIN hParent) {
WM_HWIN hWin;
int xDist;
const char * sHeader;
const GUI_FONT * pFont;
unsigned i;
SLIDER_SIZES Sizes;
//
// Create header
//
sHeader = "SVG Scale & Rotate Example";
pFont = _GetFont();
GUI_SetFont(pFont);
xDist = GUI_GetStringDistX(sHeader);
hWin = TEXT_CreateAsChild(0, 0, xDist, GUI_GetFontSizeY(), hParent, ID_TEXT_HEADER, WM_CF_SHOW, sHeader, GUI_TA_LEFT | GUI_TA_VCENTER);
TEXT_SetText(hWin, sHeader);
TEXT_SetFont(hWin, pFont);
//
// Create sliders
//
_GetSliderSizes(&Sizes);
hWin = SLIDER_CreateEx(0, 0, Sizes.xSize, 100, hParent, WM_CF_SHOW, SLIDER_CF_VERTICAL, ID_SLIDER_SCALE);
SLIDER_SetSkin(hWin, _cbSkinSlider);
SLIDER_EnableFocusRect(hWin, 0);
SLIDER_SetWidth(hWin, Sizes.ySizeShaft);
SLIDER_SetRange(hWin, MIN_SCALE, MAX_SCALE);
SLIDER_SetValue(hWin, START_SCALE); // Starting value is 1000 = 1x magnification.
//
hWin = SLIDER_CreateEx(0, 0, Sizes.xSize, 100, hParent, WM_CF_SHOW, SLIDER_CF_VERTICAL, ID_SLIDER_ANGLE);
SLIDER_SetSkin(hWin, _cbSkinSlider);
SLIDER_EnableFocusRect(hWin, 0);
SLIDER_SetWidth(hWin, Sizes.ySizeShaft);
SLIDER_SetRange(hWin, 0, 3599);
SLIDER_SetValue(hWin, 1);
SLIDER_SetValue(hWin, 0);
//
// Create SVG buttons
//
for (i = 0; i < GUI_COUNTOF(_aSvgButtons); i++) {
_CreateSvgButton(&_aSvgButtons[i], hParent);
}
//
// Create SVG canvas
//
hWin = WINDOW_CreateEx(0, 0, 100, 100, hParent, WM_CF_SHOW, 0, ID_WINDOW_CANVAS, NULL);
WM_SetCallback(hWin, _cbSvgCanvas);
}
/*********************************************************************
*
* _GetMargin
*/
static int _GetMargin(void) {
return 0.025f * LCD_GetXSize();
}
/*********************************************************************
*
* _CreateLayouts
*/
static void _CreateLayouts(WM_HWIN hParent) {
WM_HWIN hWin;
WM_HLAYOUT hMain, hLayout, hButtonLayout;
WM_HLAYOUT_ITEM hItem;
int m;
unsigned i, NumButtons;
int ySize;
WM_HLAYOUT_ITEM aButtonItems[GUI_COUNTOF(_aSvgButtons)];
WM_HLAYOUT_ITEM hvLayout;
m = _GetMargin();
hMain = WM_LAYOUT_CreateVBox();
WM_LAYOUT_SetMargin(hMain, m, m, m, m);
WM_SetLayout(hParent, hMain);
//
// Add header to layout
//
hWin = WM_GetDialogItem(hParent, ID_TEXT_HEADER);
hItem = WM_LAYOUT_AddWindowEx(hMain, hWin, 0, 0);
WM_LAYOUT_SetSpacing(hMain, m);
//
// Make horizontal layout for the rest
//
hLayout = WM_LAYOUT_CreateHBox();
hWin = WM_GetDialogItem(hParent, ID_SLIDER_SCALE);
hItem = WM_LAYOUT_AddWindowEx(hLayout, hWin, 1, 0);
WM_LAYOUT_SetItemWidthMax(hItem, WM_GetXSize(hWin));
WM_LAYOUT_SetSpacing(hLayout, m);
hWin = WM_GetDialogItem(hParent, ID_SLIDER_ANGLE);
hItem = WM_LAYOUT_AddWindowEx(hLayout, hWin, 1, 0);
WM_LAYOUT_SetItemWidthMax(hItem, WM_GetXSize(hWin));
//
// Make layout for the buttons
//
hButtonLayout = WM_LAYOUT_CreateVBox();
WM_LAYOUT_SetSpacing(hButtonLayout, m);
NumButtons = GUI_COUNTOF(_aSvgButtons);
for (i = 0; i < NumButtons; i++) {
hWin = WM_GetDialogItem(hParent, _aSvgButtons[i].ButtonId);
aButtonItems[i] = WM_LAYOUT_AddWindow(hButtonLayout, hWin);
}
hvLayout = WM_LAYOUT_AddLayout(hLayout, hButtonLayout, 0);
//
// Add canvas
//
hWin = WM_GetDialogItem(hParent, ID_WINDOW_CANVAS);
WM_LAYOUT_AddWindowEx(hLayout, hWin, 1, 0);
WM_LAYOUT_AddLayout(hMain, hLayout, 1);
//
// Set main layout to calculate positions...
//
WM_SetLayout(hParent, hMain);
//
// Get the calculated height of the SVG buttons
// and apply it to all buttons
//
hWin = WM_GetDialogItem(hParent, ID_SVG_BUTTON_TIGER);
ySize = WM_GetYSize(hWin);
for (i = 0; i < GUI_COUNTOF(_aSvgButtons); i++) {
WM_LAYOUT_SetItemWidthMin(aButtonItems[i], ySize);
}
WM_LAYOUT_SetItemWidthMin(hvLayout, ySize);
//
// Trigger resize.
//
WM_SetLayout(hParent, hMain);
}
/*********************************************************************
*
* _cbMainWin
*/
static void _cbMainWin(WM_MESSAGE * pMsg) {
static BUTTON_Handle hCurrentButton;
WM_HWIN hItem;
int NCode;
int Id;
U16 i, j;
const SVG_BUTTON_DATA * pData = NULL;
switch (pMsg->MsgId) {
case WM_CREATE:
_CreateWidgets(pMsg->hWin);
_CreateLayouts(pMsg->hWin);
//
// Set SEGGER SVG initally
//
hItem = WM_GetDialogItem(pMsg->hWin, ID_SVG_BUTTON_SEGGER);
BUTTON_Toggle(hItem);
break;
case WM_PAINT:
GUI_SetBkColor(GUI_WHITE);
GUI_Clear();
break;
case WM_DELETE:
GUI_SVG_Delete(_hSVG);
_hSVG = 0;
break;
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc);
NCode = pMsg->Data.v;
switch(Id) {
case ID_SLIDER_SCALE:
switch(NCode) {
case WM_NOTIFICATION_VALUE_CHANGED:
_Mag = SLIDER_GetValue(pMsg->hWinSrc);
hItem = WM_GetDialogItem(pMsg->hWin, ID_WINDOW_CANVAS);
WM_InvalidateWindow(hItem);
break;
}
break;
case ID_SLIDER_ANGLE:
switch(NCode) {
case WM_NOTIFICATION_VALUE_CHANGED:
_Angle = SLIDER_GetValue(pMsg->hWinSrc);
hItem = WM_GetDialogItem(pMsg->hWin, ID_WINDOW_CANVAS);
WM_InvalidateWindow(hItem);
break;
}
break;
case ID_SVG_BUTTON_SEGGER:
case ID_SVG_BUTTON_TIGER:
case ID_SVG_BUTTON_WEATHER:
case ID_SVG_BUTTON_DATAREPORT:
case ID_SVG_BUTTON_CITY:
switch(NCode) {
case WM_NOTIFICATION_RELEASED:
//
// Make sure button stays selected
//
if (!BUTTON_IsPressed(hCurrentButton)) {
BUTTON_SetPressed(hCurrentButton, 1);
}
break;
case WM_NOTIFICATION_CLICKED:
for (i = ID_SVG_BUTTON_SEGGER; i <= ID_SVG_BUTTON_CITY; i++) {
//
// Disable other SVG buttons.
//
hItem = WM_GetDialogItem(pMsg->hWin, i);
if (Id != i) {
BUTTON_SetPressed(hItem, 0);
}
//
// Set new SVG...
//
else {
for (j = 0; j < GUI_COUNTOF(_aSvgButtons); j++) {
if (_aSvgButtons[j].ButtonId == Id) {
pData = &_aSvgButtons[j];
break;
}
}
if (!pData) {
return;
}
hCurrentButton = hItem;
//
// Switch out SVG and update canvas.
//
GUI_SVG_Delete(_hSVG);
_hSVG = GUI_SVG_Create(pData->pSVG, pData->NumBytesSVG);
hItem = WM_GetDialogItem(pMsg->hWin, ID_WINDOW_CANVAS);
WM_InvalidateWindow(hItem);
}
}
break;
}
break;
}
break;
default:
WM_DefaultProc(pMsg);
break;
}
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* MainTask
*/
void MainTask(void) {
GUI_Init();
WM_MULTIBUF_Enable(1);
WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbMainWin, 0);
while (1) {
GUI_Delay(50);
}
}
/*************************** End of file ****************************/
