Initial Commit

Blank working project
This commit is contained in:
William Miceli
2020-08-05 17:53:34 -04:00
commit c2f788aa3e
677 changed files with 244742 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/touch/SDL2TouchController.hpp>
#include <platform/hal/simulator/sdl2/HALSDL2.hpp>
namespace touchgfx
{
void touchgfx::SDL2TouchController::init()
{
}
bool touchgfx::SDL2TouchController::sampleTouch(int32_t& x, int32_t& y)
{
return static_cast<HALSDL2*>(HAL::getInstance())->doSampleTouch(x, y); //lint !e1774
}
} // namespace touchgfx

View File

@@ -0,0 +1,146 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/touch/ST1232TouchController.hpp>
#ifndef NO_USING_NAMESPACE_TOUCHGFX
using namespace touchgfx;
#endif
void touchgfx::ST1232TouchController::init()
{
}
/*
//This method does not allow us to return more than a single coordinate
//Should be enhanced to track multiple fingers. => HAL TYPES.
// Depending on TouchControl setup - allow tracking of
1) Coordinates for Fingers <= MAX NR OF FINGERS
2) Gestures for Fingers <= MAX NR OF FINGERS
*/
static Finger finger;
bool touchgfx::ST1232TouchController::sampleTouch(int32_t& x, int32_t& y)
{
//For each configured and valid finger, collect 1) Coordinates 2) Gestures (if configured)
uint8_t fingersOnDisplay = touchDetected();
if (fingersOnDisplay)
{
//Get sample for finger 1 and extract data
if (getSample(&finger))
{
x = finger.x;
y = finger.y;
//Apply transformations
transformTouchData(x, y);
return true;
}
}
return false;
}
void touchgfx::ST1232TouchController::transformTouchData(int32_t& x, int32_t& y)
{
/* Example of linear transformations for various touch controller configurations
Screen width in example is 480 and height is 272. */
/***************************************
X-axis is flipped
****************************************
* (0,272) (480,272)
*
*
*
* (0,0) (480,0)
***************************************/
// y = 272 - y;
/***************************************
Y-axis flipped
****************************************
* (480,0) (0,0)
*
*
*
* (480,272) (0,272)
***************************************/
//x = 480 - x
//If transformation is configured, apply it to sampled coordinates
switch (linearTransform)
{
case FLIP_X_AXIS:
y = displayHeight - y;
break;
case FLIP_Y_AXIS:
x = displayWidth - x;
break;
case NO_TRANSFORM:
//do nothing
break;
}
//If user defined a custom method for transformation elsewhere
if (transformFunc != 0)
{
transformFunc(x, y, finger);
}
}
uint8_t touchgfx::ST1232TouchController::touchDetected(void)
{
uint8_t touched = 0;
//Read 1 byte of REG_FINGERS_GESTURE register into touched
i2c.readRegister(I2C_ADDR, REG_FINGERS_GESTURE, (uint8_t*)&touched, 1);
//First 3 bytes define the number of fingers on display.
return touched & MASK_NR_OF_FINGERS;
}
bool touchgfx::ST1232TouchController::getSample(Finger* touchData)
{
uint8_t xy_low_byte, xy_high_byte;
//Read XY High byte and verify validty of data
i2c.readRegister(I2C_ADDR, REG_XY0_COORD_HIGH_BYTE, &xy_high_byte, 1);
//While one or more fingers return valid touchdata
if (xy_high_byte & MASK_MSB)
{
//Read the X low byte
i2c.readRegister(I2C_ADDR, REG_X0_COORD_LOW_BYTE, &xy_low_byte, 1);
//Add X high and low bytes. Located at the top 4 bits of register.
touchData->x = ((xy_high_byte & MASK_X0_COORD_LOW_BYTE) << (SIZE_BYTES / 2)) | xy_low_byte;
//Read the Y low byte
i2c.readRegister(I2C_ADDR, REG_Y0_COORD_LOW_BYTE, &xy_low_byte, 1);
//Add Y high and low bytes Located at the bottom 4 bits of register.
touchData->y = ((xy_high_byte & MASK_Y0_COORD_LOW_BYTE) << SIZE_BYTES) | xy_low_byte;
//Touchdata was valid
return true;
}
//Touchdata was valid
return false;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/hal/simulator/sdl2/HALSDL2.hpp>
namespace touchgfx
{
uint16_t HALSDL2::icon[] =
{
0x0000, 0x0AC1, 0x0AC9, 0x0ACD, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACE, 0x0ACD, 0x0AC9, 0x0AC1, 0x0000,
0x0AC1, 0x0ACE, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACE, 0x0AC1,
0x0AC9, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x09C9,
0x0ACD, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACD,
0x0ACE, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x6CDF, 0x7CEF, 0x7CEF, 0x7CEF, 0x5CDF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x5CDF, 0x7CEF, 0x7CEF, 0x7CEF, 0x6CDF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACD,
0x0ACE, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x5BDF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x4BDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEFFF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x09CD,
0x09CE, 0x09CF, 0x09CF, 0x09CF, 0x0ACF, 0x0ACF, 0x09CF, 0x6CDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDFFF, 0x0ACF, 0x0ACF, 0x0ACF, 0x0ACF, 0x09CF, 0x09CF, 0xCEFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7CEF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CD,
0x09CE, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x0ACF, 0xDEFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x6CDF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x5BDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEFFF, 0x0ACF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CD,
0x09CE, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x5BDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDFFF, 0x09CF, 0x09CF, 0x09CF, 0x0ACF, 0xDFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x6CDF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CD,
0x09CE, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0xCEFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBEEF, 0x09CF, 0x09CF, 0x09CF, 0x6CDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEFF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CD,
0x0ACE, 0x09CF, 0x09CF, 0x0ACF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x3BDF, 0xFFFF, 0xFFFF, 0xFFFF, 0x3ACF, 0x09CF, 0x09CF, 0x0ACF, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x4BDF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CD,
0x09CE, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0xBEEF, 0xFFFF, 0xADEF, 0x09CF, 0x09CF, 0x09CF, 0x7CDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xCEFF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CD,
0x09CE, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x2ACF, 0xFFFF, 0x2ACF, 0x09CF, 0x09CF, 0x1ACF, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x3BCF, 0x09CF, 0x09BF, 0x09BF, 0x09BF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CF, 0x09CD,
0x09CE, 0x09BF, 0x09BF, 0x09CF, 0x09CF, 0x09CF, 0x09BF, 0x09CF, 0x09BF, 0x09BF, 0x09CF, 0x09CF, 0x09BF, 0x09BF, 0x09BF, 0x8CEF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBDEF, 0x09CF, 0x09BF, 0x09BF, 0x09CF, 0x09CF, 0x09BF, 0x09CF, 0x09BF, 0x09BF, 0x09BF, 0x09CD,
0x09CE, 0x09BF, 0x09BF, 0x09BF, 0x09CF, 0x09CF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x1ACF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x2ACF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09CF, 0x09CF, 0x09BD,
0x09BE, 0x09BF, 0x09CF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x9DEF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xADEF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BD,
0x09BE, 0x09CF, 0x09CF, 0x09CF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x8CDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBEEF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BD,
0x09BE, 0x09BF, 0x09BF, 0x09BF, 0x09CF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x19BF, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x4BCF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BD,
0x09BE, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x3ACF, 0x09BF, 0x09BF, 0x09BF, 0x6CDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xCEFF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BD,
0x09BE, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x4BCF, 0xFFFF, 0x3ACF, 0x09BF, 0x09BF, 0x09BF, 0xDEFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x6BCF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BD,
0x09BE, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x08BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0xDEFF, 0xFFFF, 0xCEEF, 0x09BF, 0x09BF, 0x09BF, 0x4BCF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEFFF, 0x09BF, 0x08BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BD,
0x09BE, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x08BF, 0x09BF, 0x09BF, 0x6BDF, 0xFFFF, 0xFFFF, 0xFFFF, 0x5BCF, 0x09BF, 0x09BF, 0x09BF, 0xBEEF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7CDF, 0x09BF, 0x09BF, 0x08BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x09BD,
0x09BE, 0x09BF, 0x09BF, 0x09BF, 0x09BF, 0x08BF, 0x08BF, 0x09BF, 0x19BF, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDEFF, 0x09BF, 0x09BF, 0x09BF, 0x3ACF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x19BF, 0x08BF, 0x08BF, 0x08BF, 0x09BF, 0x08BF, 0x09BF, 0x09BF, 0x09BD,
0x08BE, 0x08BF, 0x08BF, 0x08BF, 0x08BF, 0x08BF, 0x09BF, 0x09BF, 0x8CDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xADEF, 0x08BF, 0x08BF, 0x09BF, 0x08BF, 0x9DEF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x9DEF, 0x08AF, 0x08AF, 0x08BF, 0x08BF, 0x08BF, 0x08BF, 0x08AF, 0x08AD,
0x08AE, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x29BF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x29BF, 0x08AF, 0x09BF, 0x08AF, 0x08AF, 0x19BF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x3ABF, 0x08BF, 0x08AF, 0x08AF, 0x08BF, 0x08AF, 0x08AF, 0x09BD,
0x09BE, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0xADEF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x9CDF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x8CDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBEEF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AD,
0x09BE, 0x09BF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x29BF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEFFF, 0x19BF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08BF, 0x08AF, 0xEFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x3ABF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AD,
0x09BE, 0x09BF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x29BF, 0x39BF, 0x39BF, 0x39BF, 0x19BF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08BF, 0x18AF, 0x3ABF, 0x3ABF, 0x39BF, 0x2ABF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AD,
0x09BD, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AD,
0x08A9, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08A9,
0x08A1, 0x08AE, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x089F, 0x089F, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x08AF, 0x079F, 0x079E, 0x0791,
0x0000, 0x07A1, 0x08A9, 0x08AD, 0x09BD, 0x08AD, 0x08AD, 0x079D, 0x079D, 0x079D, 0x079D, 0x08AD, 0x08AD, 0x08AD, 0x08AD, 0x089D, 0x079D, 0x079D, 0x08AD, 0x08AD, 0x08AD, 0x08AD, 0x08AD, 0x079D, 0x079D, 0x079D, 0x08AD, 0x08AD, 0x08AD, 0x0799, 0x0791, 0x0000
};
} // namespace touchgfx

View File

@@ -0,0 +1,47 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/hal/OSWrappers.hpp>
#include <SDL2/SDL.h>
namespace touchgfx
{
static SDL_mutex* s_FrameBufferLock;
void OSWrappers::initialize()
{
// Setup framebuffer lock
s_FrameBufferLock = SDL_CreateMutex();
}
void OSWrappers::takeFrameBufferSemaphore()
{
SDL_LockMutex(s_FrameBufferLock);
}
void OSWrappers::giveFrameBufferSemaphore()
{
SDL_UnlockMutex(s_FrameBufferLock);
}
void OSWrappers::waitForVSync()
{}
void OSWrappers::tryTakeFrameBufferSemaphore()
{}
void OSWrappers::giveFrameBufferSemaphoreFromISR()
{}
} // namespace touchgfx

View File

@@ -0,0 +1,93 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/CacheableContainer.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
void CacheableContainer::setCacheBitmap(BitmapId bitmapId)
{
Bitmap bitmap(bitmapId);
cachedBitmapId = BITMAP_INVALID;
/* Accept only dynamic bitmaps */
if (!Bitmap::dynamicBitmapGetAddress(bitmapId))
{
return;
}
/* Retrieve the auxiliary LCD implementation attached to HA */
LCD* auxLCD = HAL::getInstance()->getAuxiliaryLCD();
/* Dynamic bitmap and framebuffer should be of the same format */
if (bitmap.getFormat() == HAL::lcd().framebufferFormat()
|| (auxLCD && bitmap.getFormat() == auxLCD->framebufferFormat()))
{
cachedBitmapId = bitmapId;
cachedImage.setBitmap(Bitmap(cachedBitmapId));
}
}
void CacheableContainer::updateCache()
{
updateCache(Rect());
}
void CacheableContainer::updateCache(const Rect& invalidatedArea)
{
if (isCachedMode && (cachedBitmapId != BITMAP_INVALID))
{
/* will call Container::draw(invalidatedArea) to render all widgets into the dynamic bitmap */
HAL::getInstance()->drawDrawableInDynamicBitmap(*this, cachedBitmapId, invalidatedArea);
childWasInvalidated = false;
}
}
void CacheableContainer::enableCachedMode(bool enable)
{
isCachedMode = enable;
}
void CacheableContainer::invalidateRect(Rect& invalidatedArea) const
{
Container::invalidateRect(invalidatedArea);
if (isCachedMode && (cachedBitmapId != BITMAP_INVALID))
{
const_cast<CacheableContainer*>(this)->childWasInvalidated = true;
}
}
bool CacheableContainer::isChildInvalidated() const
{
return childWasInvalidated;
}
void CacheableContainer::setupDrawChain(const Rect& invalidatedArea, Drawable** nextPreviousElement)
{
if (isCachedMode && (cachedBitmapId != BITMAP_INVALID) && isVisible())
{
Rect r = getAbsoluteRect();
cachedImage.setPosition(r.x, r.y, r.width, r.height);
cachedImage.setupDrawChain(invalidatedArea, nextPreviousElement);
}
else
{
Container::setupDrawChain(invalidatedArea, nextPreviousElement);
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,276 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/Container.hpp>
#include <touchgfx/Screen.hpp>
namespace touchgfx
{
bool Container::contains(const Drawable& d)
{
bool found = false;
Drawable* head = firstChild;
while (head && !found)
{
found = (head == &d);
head = head->nextSibling;
}
return found;
}
void Container::add(Drawable& d)
{
assert(&d != this && "Cannot add Drawable to self");
assert(d.parent == 0 && "Cannot add Drawable multiple times");
// Initialize d to have this as parent and no sibling.
d.parent = this;
d.nextSibling = 0;
// Check if d is the first child to be added (container is empty)
if (!firstChild)
{
firstChild = &d;
}
else
{
Drawable* head = firstChild;
// Skip to end of currently added children
while (head->nextSibling)
{
assert(head != &d && "Cannot add Drawable multiple times");
head = head->nextSibling;
}
assert(head != &d && "Cannot add Drawable multiple times");
// Make last child now point to d.
head->nextSibling = &d;
}
}
void Container::remove(Drawable& d)
{
if (!firstChild)
{
// No children
return;
}
if (&d == firstChild)
{
// d is first child.
d.parent = 0;
if (!d.nextSibling)
{
// d was only child, so now this container is empty
firstChild = 0;
}
else
{
firstChild = d.nextSibling;
d.nextSibling = 0;
}
return;
}
Drawable* tmp = firstChild;
while (tmp)
{
if (tmp->nextSibling == &d)
{
tmp->nextSibling = d.nextSibling;
d.parent = 0;
d.nextSibling = 0;
return;
}
else
{
tmp = tmp->nextSibling;
}
}
}
void Container::removeAll()
{
while (firstChild)
{
Drawable* d = firstChild;
firstChild = firstChild->nextSibling;
d->parent = 0;
d->nextSibling = 0;
}
}
void Container::unlink()
{
firstChild = 0;
}
void Container::draw(const Rect& invalidatedArea) const
{
// The draw function of Container is not normally used. Containers do not per default
// appear in the draw chain, since they are normally invisible themselves. However,
// if someone decides to call draw on a container, at least do something useful (draw children).
if (!isVisible() || !firstChild)
{
// Nothing to draw
return;
}
Rect tmp = invalidatedArea;
Drawable* d = firstChild;
while (d)
{
if (d->isVisible())
{
Rect drawableRegion = tmp & d->getRect();
if (!drawableRegion.isEmpty())
{
// This child has a non-empty intersection with the invalidated area.
// Convert region to the Drawable's coordinate system and draw.
drawableRegion.x -= d->getX();
drawableRegion.y -= d->getY();
d->draw(drawableRegion);
}
}
d = d->nextSibling;
}
}
void Container::getLastChild(int16_t x, int16_t y, Drawable** last)
{
// This function is used to obtain the drawable that should receive a click/drag/gesture event.
// Find the last child (ie. the last child that was added, ie. the "front-most" drawable) covering
// the specified coords.
if (isTouchable())
{
// If the container itself is touchable, result so far is "this". Might be overridden by a child.
*last = this;
}
Drawable* d = firstChild;
while (d)
{
// Iterate over children.
if (d->isVisible() && d->getRect().intersect(x, y))
{
int16_t xadj = x - d->getX();
int16_t yadj = y - d->getY();
d->getLastChild(xadj, yadj, last);
}
d = d->nextSibling;
}
}
Rect Container::getSolidRect() const
{
return Rect(0, 0, 0, 0);
}
Rect Container::getContainedArea() const
{
Drawable* d = firstChild;
Rect contained(0, 0, 0, 0);
while (d)
{
contained.expandToFit(d->getRect());
d = d->nextSibling;
}
return contained;
}
void Container::moveChildrenRelative(int16_t deltaX, int16_t deltaY)
{
Drawable* d = firstChild;
while (d)
{
d->moveRelative(deltaX, deltaY);
d = d->nextSibling;
}
}
void Container::forEachChild(GenericCallback<Drawable&>* function)
{
Drawable* d = firstChild;
while (d)
{
function->execute(*d);
d = d->nextSibling;
}
}
void Container::insert(Drawable* previous, Drawable& d)
{
if (!firstChild)
{
// Insert as only element
add(d);
return;
}
else if (!previous)
{
// Insert as head element
d.nextSibling = firstChild;
firstChild = &d;
d.parent = this;
}
else
{
Drawable* tmp = firstChild;
while (tmp)
{
if (tmp == previous)
{
d.nextSibling = tmp->nextSibling;
tmp->nextSibling = &d;
d.parent = this;
return;
}
tmp = tmp->nextSibling;
}
}
}
void Container::setupDrawChain(const Rect& invalidatedArea, Drawable** nextPreviousElement)
{
// This function adds the children of this container to the list of drawables to draw.
if (!isVisible())
{
// If this container itself is not visible, do not add anyone to draw chain.
return;
}
if (!firstChild)
{
// If this container is empty, do not add anyone.
return;
}
Drawable* d = firstChild;
while (d)
{
if (d->isVisible())
{
// Only drawables intersecting with the specified invalidated area will be added.
Rect drawableRegion = invalidatedArea & d->getRect();
if (!drawableRegion.isEmpty())
{
drawableRegion.x -= d->getX();
drawableRegion.y -= d->getY();
d->setupDrawChain(drawableRegion, nextPreviousElement);
}
}
d = d->nextSibling;
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,247 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/ListLayout.hpp>
namespace touchgfx
{
class AdjustElements
{
public:
AdjustElements(Drawable* d, Direction dir) : insertedCoord(0),
newElementPassed(false),
newElement(d),
direction(dir) {}
void handleInsert(Drawable& d)
{
if (!newElementPassed)
{
if (newElement == &d)
{
newElementPassed = true;
}
else
{
if (direction == SOUTH)
{
insertedCoord = d.getY() + d.getHeight();
}
else if (direction == EAST)
{
insertedCoord = d.getX() + d.getWidth();
}
}
}
else
{
if (direction == SOUTH)
{
d.setY(d.getY() + newElement->getHeight());
}
else if (direction == EAST)
{
d.setX(d.getX() + newElement->getWidth());
}
}
}
void handleRemove(Drawable& d)
{
if (!newElementPassed)
{
if (newElement == &d)
{
newElementPassed = true;
}
}
else
{
if (direction == SOUTH)
{
d.setY(d.getY() - newElement->getHeight());
}
else if (direction == EAST)
{
d.setX(d.getX() - newElement->getWidth());
}
}
if (newElement != &d)
{
if (direction == SOUTH)
{
if (d.getWidth() > insertedCoord)
{
insertedCoord = d.getWidth();
}
}
else if (direction == EAST)
{
if (d.getHeight() > insertedCoord)
{
insertedCoord = d.getHeight();
}
}
}
}
int16_t insertedCoord;
bool newElementPassed;
private:
Drawable* newElement;
Direction direction;
}; //lint !e1712
void ListLayout::internalAddElementAt(Drawable& d, int16_t coord)
{
switch (direction)
{
case SOUTH:
if (rect.width < d.getWidth())
{
rect.width = d.getWidth();
}
rect.height += d.getHeight();
d.setXY(0, coord);
offset += d.getHeight();
break;
case EAST:
if (rect.height < d.getHeight())
{
rect.height = d.getHeight();
}
rect.width += d.getWidth();
d.setXY(coord, 0);
offset += d.getWidth();
break;
case NORTH:
case WEST:
default:
break;
}
}
void ListLayout::internalAddElement(Drawable& d)
{
internalAddElementAt(d, offset);
}
void ListLayout::internalRemoveElement(Drawable& d, int16_t coord)
{
switch (direction)
{
case SOUTH:
if (rect.width > coord)
{
rect.width = coord;
}
rect.height -= d.getHeight();
d.setX(0);
d.setY(0);
offset -= d.getHeight();
break;
case EAST:
if (rect.height > coord)
{
rect.height = coord;
}
rect.width -= d.getWidth();
d.setX(0);
d.setY(0);
offset -= d.getWidth();
break;
case NORTH:
case WEST:
default:
break;
}
}
void ListLayout::setDirection(const Direction d)
{
assert((d == SOUTH || d == EAST) && "Chosen direction not supported");
if (direction != d)
{
direction = d;
offset = 0;
setWidth(0);
setHeight(0);
Callback<ListLayout, Drawable&> function(this, &ListLayout::internalAddElement);
forEachChild(&function);
if (parent)
{
parent->childGeometryChanged();
}
}
}
void ListLayout::add(Drawable& d)
{
internalAddElement(d);
Container::add(d);
if (parent)
{
parent->childGeometryChanged();
}
}
void ListLayout::removeAll()
{
offset = 0;
setWidth(0);
setHeight(0);
Container::removeAll();
if (parent)
{
parent->childGeometryChanged();
}
}
void ListLayout::insert(Drawable* previous, Drawable& d)
{
if (!firstChild)
{
// List is empty, just add the new entry
add(d);
return;
}
Container::insert(previous, d);
AdjustElements tmp(&d, direction);
Callback<AdjustElements, Drawable&> function(&tmp, &AdjustElements::handleInsert);
forEachChild(&function);
internalAddElementAt(d, tmp.insertedCoord);
if (parent)
{
parent->childGeometryChanged();
}
}
void ListLayout::remove(Drawable& d)
{
AdjustElements tmp(&d, direction);
Callback<AdjustElements, Drawable&> function(&tmp, &AdjustElements::handleRemove);
forEachChild(&function);
if (tmp.newElementPassed)
{
internalRemoveElement(d, tmp.insertedCoord);
Container::remove(d);
}
if (parent)
{
parent->childGeometryChanged();
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,113 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/ModalWindow.hpp>
#include <touchgfx/Color.hpp>
namespace touchgfx
{
ModalWindow::ModalWindow() :
Container()
{
Container::setWidth(HAL::DISPLAY_WIDTH);
Container::setHeight(HAL::DISPLAY_HEIGHT);
int defaultShadeAlpha = 96;
colortype defaultShadeColor = Color::getColorFrom24BitRGB(0x0, 0x0, 0x0);
backgroundShade.setPosition(0, 0, getWidth(), getHeight());
backgroundShade.setColor(defaultShadeColor);
backgroundShade.setTouchable(true);
ModalWindow::setShadeAlpha(defaultShadeAlpha);
Container::add(backgroundShade);
Container::add(windowContainer);
windowContainer.add(windowBackground);
}
void ModalWindow::setBackground(const BitmapId& bmpId)
{
windowBackground.setBitmap(Bitmap(bmpId));
windowBackground.setXY(0, 0);
windowContainer.setPosition((getWidth() - windowBackground.getWidth()) / 2, (getHeight() - windowBackground.getHeight()) / 2, windowBackground.getWidth(), windowBackground.getHeight());
invalidate();
}
void ModalWindow::setBackground(const BitmapId& bmpId, int16_t backgroundX, int16_t backgroundY)
{
setBackground(bmpId);
windowContainer.setXY(backgroundX, backgroundY);
}
uint16_t ModalWindow::getBackgroundWidth() const
{
return windowBackground.getWidth();
}
uint16_t ModalWindow::getBackgroundHeight() const
{
return windowBackground.getHeight();
}
void ModalWindow::add(Drawable& d)
{
windowContainer.add(d);
}
void ModalWindow::remove(Drawable& d)
{
windowContainer.remove(d);
}
void ModalWindow::setShadeAlpha(uint8_t alpha)
{
backgroundShade.setAlpha(alpha);
backgroundShade.invalidate();
}
uint8_t ModalWindow::getShadeAlpha() const
{
return backgroundShade.getAlpha();
}
void ModalWindow::setShadeColor(colortype color)
{
backgroundShade.setColor(color);
backgroundShade.invalidate();
}
touchgfx::colortype ModalWindow::getShadeColor() const
{
return backgroundShade.getColor();
}
void ModalWindow::show()
{
setVisible(true);
invalidate();
}
void ModalWindow::hide()
{
setVisible(false);
invalidate();
}
bool ModalWindow::isShowing() const
{
return isVisible();
}
} // namespace touchgfx

View File

@@ -0,0 +1,729 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/ScrollableContainer.hpp>
#include <touchgfx/EasingEquations.hpp>
#include <touchgfx/Color.hpp>
namespace touchgfx
{
ScrollableContainer::ScrollableContainer()
: Container(),
scrollbarPadding(0),
scrollbarWidth(2),
scrollbarAlpha(120),
scrollbarColor(Color::getColorFrom24BitRGB(0xFF, 0xFF, 0xFF)),
accelDirection(GestureEvent::SWIPE_HORIZONTAL),
xSlider(0, 0, scrollbarColor, scrollbarAlpha),
ySlider(0, 0, scrollbarColor, scrollbarAlpha),
pressedDrawable(0),
lastDraggableChild(0),
scrolledXDistance(0),
scrolledYDistance(0),
scrollThreshold(5),
pressedX(0),
pressedY(0),
isPressed(false),
isScrolling(false),
scrollableX(true),
scrollableY(true),
scrollbarsVisible(true),
scrollbarsPermanentlyVisible(false),
scrollDuration(0),
beginningValue(0),
targetValue(0),
animationCounter(0),
animate(false),
fingerAdjustmentX(0),
fingerAdjustmentY(0),
hasIssuedCancelEvent(false),
scrollDurationSpeedup(7),
scrollDurationSlowdown(1)
{
xSlider.setVisible(false);
ySlider.setVisible(false);
maxVelocity = SCROLLBAR_MAX_VELOCITY;
setTouchable(true);
}
void ScrollableContainer::handleClickEvent(const ClickEvent& evt)
{
if (evt.getType() == ClickEvent::PRESSED)
{
isPressed = true;
if (animate)
{
// Stop scroll animation
animate = false;
animationCounter = 0;
Application::getInstance()->unregisterTimerWidget(this);
}
const int fingerSize = HAL::getInstance()->getFingerSize();
fingerAdjustmentX = 0;
fingerAdjustmentY = 0;
const int minimumDistance = 3;
if ((fingerSize - 1) >= minimumDistance)
{
pressedDrawable = 0;
const int maximumSquares = 3;
const int numberOfSquares = MIN(maximumSquares, (fingerSize - 1) / minimumDistance);
uint32_t bestDistance = 0xFFFFFFFF;
Drawable* last = 0;
Rect me(0, 0, getWidth(), getHeight());
Rect meAbs = me;
translateRectToAbsolute(meAbs);
for (int squareNumber = 1; squareNumber <= numberOfSquares; squareNumber++)
{
int distance = ((squareNumber * fingerSize) / numberOfSquares);
const int samplePoints[10][2] = { { 0, 0 }, { -1, -1 }, { 0, -1 }, { 1, -1 }, { -1, 0 }, { 0, 0 }, { 1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 } };
for (int sampleIndex = squareNumber - 1; sampleIndex < 10; sampleIndex += 2)
{
Drawable* d = 0;
int16_t deltaX = samplePoints[sampleIndex][0] * distance;
int16_t deltaY = samplePoints[sampleIndex][1] * distance;
if (me.intersect(evt.getX() + deltaX, evt.getY() + deltaY))
{
Container::getLastChild(evt.getX() + deltaX, evt.getY() + deltaY, &d);
if (d && d != last && d != this)
{
Rect absRect = d->getAbsoluteRect();
int x = meAbs.x + evt.getX() - (absRect.x + (absRect.width / 2));
int y = meAbs.y + evt.getY() - (absRect.y + (absRect.height / 2));
uint32_t dist = x * x + y * y;
if (dist < bestDistance)
{
last = d;
bestDistance = dist;
pressedDrawable = d;
fingerAdjustmentX = deltaX;
fingerAdjustmentY = deltaY;
}
}
}
}
}
}
else
{
Container::getLastChild(evt.getX(), evt.getY(), &pressedDrawable);
}
if (pressedDrawable == this)
{
pressedDrawable = 0;
}
if (pressedDrawable)
{
hasIssuedCancelEvent = false;
pressedX = evt.getX();
pressedY = evt.getY();
Rect r = pressedDrawable->getAbsoluteRect();
ClickEvent relative(evt.getType(), evt.getX() + rect.x + fingerAdjustmentX - r.x, evt.getY() + rect.y + fingerAdjustmentY - r.y);
pressedDrawable->handleClickEvent(relative);
lastDraggableChild = pressedDrawable;
}
}
else if (evt.getType() == ClickEvent::CANCEL)
{
return;
}
else // if (evt.getType() == ClickEvent::RELEASED)
{
if (pressedDrawable)
{
Rect r = pressedDrawable->getAbsoluteRect();
ClickEvent relative(evt.getType(), evt.getX() + rect.x + fingerAdjustmentX - r.x, evt.getY() + rect.y + fingerAdjustmentY - r.y);
pressedDrawable->handleClickEvent(relative);
}
pressedDrawable = 0;
lastDraggableChild = 0;
isPressed = false;
}
isScrolling = false;
// Redraw scrollbars.
xSlider.setVisible((isPressed && scrollbarsVisible) || scrollbarsPermanentlyVisible);
ySlider.setVisible((isPressed && scrollbarsVisible) || scrollbarsPermanentlyVisible);
invalidateScrollbars();
}
void ScrollableContainer::handleDragEvent(const DragEvent& evt)
{
DragEvent actualDrag = evt;
bool acceptInitialScroll = false;
bool canScrollX = false;
bool canScrollY = false;
isScrollableXY(canScrollX, canScrollY);
if ((pressedDrawable != 0) && (pressedDrawable != this))
{
// Also send this drag event to the appropriate child widget
Rect r = pressedDrawable->getAbsoluteRect();
int16_t oldX = evt.getOldX() + rect.x + fingerAdjustmentX - r.x;
int16_t oldY = evt.getOldY() + rect.y + fingerAdjustmentY - r.y;
int16_t newX = canScrollX ? oldX : evt.getNewX() + rect.x + fingerAdjustmentX - r.x;
int16_t newY = canScrollY ? oldY : evt.getNewY() + rect.y + fingerAdjustmentY - r.y;
// but only in the direction(s) where the scrollable container itself
// cannot scroll.
if ((!canScrollX && newX != oldX) || (!canScrollY && newY != oldY))
{
DragEvent relative(DragEvent::DRAGGED, oldX, oldY, newX, newY);
pressedDrawable->handleDragEvent(relative);
}
}
// If we are not currently scrolling, the drag event delta must
// be larger than the threshold value, otherwise the event is ignored.
if (!isScrolling)
{
// Only consider the delta in directions that are actually scrollable.
// Note: Do not use the delta from received evt since that only reflects
// change since last drag. What we want to check here is if the total
// delta from the point of click has now exceeded the threshold.
actualDrag = DragEvent(DragEvent::DRAGGED, pressedX + fingerAdjustmentX, pressedY + fingerAdjustmentY, evt.getNewX() + fingerAdjustmentX, evt.getNewY() + fingerAdjustmentY);
if (canScrollX)
{
// Can scroll in X.
if (abs(actualDrag.getDeltaX()) > scrollThreshold)
{
acceptInitialScroll = true;
}
}
if (canScrollY)
{
// Can scroll in Y.
if (abs(actualDrag.getDeltaY()) > scrollThreshold)
{
acceptInitialScroll = true;
}
}
if (acceptInitialScroll)
{
isScrolling = true;
}
else
{
// Discard this drag event. However, if the new coordinates no longer matches the drawable which received the PRESSED click event
// issue a CANCEL event to that drawable.
if (pressedDrawable && !hasIssuedCancelEvent)
{
Drawable* child = 0;
Container::getLastChild(evt.getNewX() + fingerAdjustmentX, evt.getNewY() + fingerAdjustmentY, &child);
if (pressedDrawable != child)
{
ClickEvent ce(ClickEvent::CANCEL, 0, 0);
pressedDrawable->handleClickEvent(ce);
hasIssuedCancelEvent = true;
}
}
return;
}
}
// Send cancel events to child in focus
if (pressedDrawable && !hasIssuedCancelEvent)
{
ClickEvent ce(ClickEvent::CANCEL, 0, 0);
pressedDrawable->handleClickEvent(ce);
hasIssuedCancelEvent = true;
}
int16_t deltaX = 0;
int16_t deltaY = 0;
if (scrollableX)
{
if (acceptInitialScroll)
{
// Initial drag which is past threshold, only scroll one pixel in initial event.
if (actualDrag.getDeltaX() > 0)
{
deltaX = 1;
}
else if (actualDrag.getDeltaX() < 0)
{
deltaX = -1;
}
}
else
{
// Scroll entire delta
deltaX = actualDrag.getDeltaX();
}
}
else
{
// Not scrollable
deltaX = 0;
}
if (scrollableY)
{
if (acceptInitialScroll)
{
// Initial drag which is past threshold, only scroll one pixel in initial event.
if (actualDrag.getDeltaY() > 0)
{
deltaY = 1;
}
else if (actualDrag.getDeltaY() < 0)
{
deltaY = -1;
}
}
else
{
// Scroll entire delta
deltaY = actualDrag.getDeltaY();
}
}
else
{
// Not scrollable
deltaY = 0;
}
doScroll(deltaX, deltaY);
}
void ScrollableContainer::handleGestureEvent(const GestureEvent& evt)
{
bool canScrollX = false;
bool canScrollY = false;
isScrollableXY(canScrollX, canScrollY);
if ((canScrollX && (evt.getType() == GestureEvent::SWIPE_HORIZONTAL)) ||
(canScrollY && (evt.getType() == GestureEvent::SWIPE_VERTICAL)))
{
int16_t velocityAbsolute = abs(evt.getVelocity());
// Ignore gestures with velocity lower than threshold
if (velocityAbsolute < scrollThreshold)
{
return;
}
// Force velocity within limits
velocityAbsolute = MAX(MIN(velocityAbsolute, maxVelocity), SCROLLBAR_MIN_VELOCITY);
// Try to set some reasonable values for how long the resulting scroll should be, and how many ticks is should take
scrollDuration = velocityAbsolute * scrollDurationSpeedup / scrollDurationSlowdown;
targetValue = ((evt.getVelocity() > 0) ? 1 : -1) * (velocityAbsolute - 4) * 72;
scrollDuration = MIN(scrollDuration, abs(targetValue));
// Get ready to animate scroll: Initialize values
beginningValue = (evt.getType() == GestureEvent::SWIPE_VERTICAL) ? getContainedArea().y : getContainedArea().x;
animate = true;
Application::getInstance()->registerTimerWidget(this);
accelDirection = evt.getType();
if (pressedDrawable && !hasIssuedCancelEvent)
{
ClickEvent ce(ClickEvent::CANCEL, 0, 0);
pressedDrawable->handleClickEvent(ce);
hasIssuedCancelEvent = true;
}
}
}
Rect ScrollableContainer::getXScrollbar() const
{
Rect res(0, 0, 0, 0);
if (scrollableX)
{
Rect contained = getContainedArea();
const int scrollSpace = (scrollableY && (contained.height > rect.height)) ? (2 * scrollbarPadding + scrollbarWidth + SCROLLBAR_LINE) : 0;
if (contained.width > rect.width)
{
int leftPadding = (-1 * contained.x * rect.width) / contained.width;
int rightPadding = ((contained.right() - rect.width) * rect.width) / contained.width;
const int startWidth = rect.width - 2 * scrollbarPadding - 2 * SCROLLBAR_LINE - scrollSpace;
int width = startWidth;
width -= (leftPadding + rightPadding);
if (width < scrollbarWidth * 2)
{
// If the contained area is very large, the scrollbar width may become zero or even negative.
int diff = scrollbarWidth * 2 - width;
width = scrollbarWidth * 2; // Force scrollbar width to a minimum
// Distribute the deviation error based on current scrollbar X position (the amount subtracted from scrollbar xpos increases gradually).
leftPadding -= (diff * leftPadding) / startWidth;
}
res = Rect(leftPadding + scrollbarPadding + SCROLLBAR_LINE, rect.height - scrollbarWidth - scrollbarPadding - SCROLLBAR_LINE, width, scrollbarWidth);
}
}
return res;
}
Rect ScrollableContainer::getYScrollbar() const
{
Rect res(0, 0, 0, 0);
if (scrollableY)
{
Rect contained = getContainedArea();
const int scrollSpace = (scrollableX && (contained.width > rect.width)) ? (2 * scrollbarPadding + scrollbarWidth + SCROLLBAR_LINE) : 0;
if (contained.height > rect.height)
{
int topPadding = (-1 * contained.y * rect.height) / contained.height;
int bottomPadding = ((contained.bottom() - rect.height) * rect.height) / contained.height;
const int startHeight = rect.height - 2 * scrollbarPadding - 2 * SCROLLBAR_LINE - scrollSpace;
int height = startHeight;
height -= (topPadding + bottomPadding);
if (height < scrollbarWidth * 2)
{
// If the contained area is very large, the scrollbar height may become zero or even negative.
int diff = scrollbarWidth * 2 - height;
height = scrollbarWidth * 2; // Force scrollbar height to a minimum
// Distribute the deviation error based on current scrollbar Y position (the amount subtracted from scrollbar ypos increases gradually).
topPadding -= (diff * topPadding) / startHeight;
}
res = Rect(rect.width - scrollbarWidth - scrollbarPadding - 2 * SCROLLBAR_LINE, topPadding + scrollbarPadding + SCROLLBAR_LINE, scrollbarWidth, height);
}
}
return res;
}
Rect ScrollableContainer::getXBorder(const Rect& xBar, const Rect& yBar) const
{
Rect border(0, 0, 0, 0);
if (!xBar.isEmpty())
{
const int scrollSpace = (!yBar.isEmpty()) ? (2 * scrollbarPadding + scrollbarWidth + SCROLLBAR_LINE) : 0;
border = Rect(scrollbarPadding, xBar.y - SCROLLBAR_LINE, rect.width - 2 * scrollbarPadding - scrollSpace, scrollbarWidth + 2 * SCROLLBAR_LINE);
}
return border;
}
Rect ScrollableContainer::getYBorder(const Rect& xBar, const Rect& yBar) const
{
Rect border(0, 0, 0, 0);
if (!yBar.isEmpty())
{
const int scrollSpace = (!xBar.isEmpty()) ? (2 * scrollbarPadding + scrollbarWidth + SCROLLBAR_LINE) : 0;
border = Rect(yBar.x - SCROLLBAR_LINE, scrollbarPadding, scrollbarWidth + 2 * SCROLLBAR_LINE, rect.height - 2 * scrollbarPadding - scrollSpace);
}
return border;
}
void ScrollableContainer::invalidateScrollbars()
{
Rect xBar = getXScrollbar();
Rect yBar = getYScrollbar();
Rect xBorder = getXBorder(xBar, yBar);
Rect yBorder = getYBorder(xBar, yBar);
// The two if statements ensure that the two sliders is invalidates thereby hides them, before they are set to size zero.
if (xSlider.getY() > xBorder.y)
{
xSlider.invalidate();
}
if (ySlider.getX() > yBorder.x)
{
ySlider.invalidate();
}
xSlider.setPosition(xBar.x, xBar.y, xBar.width, xBar.height);
ySlider.setPosition(yBar.x, yBar.y, yBar.width, yBar.height);
// x-/yBorder is given the coordinates zero and the witdh of the visiable area for the scrollable container,
// to ensure that the entire area where for the scrollable bars is and have been is invalidated correct.
xBorder.x = 0;
xBorder.width = rect.width;
yBorder.height = rect.height;
yBorder.y = 0;
if (!xBorder.isEmpty())
{
invalidateRect(xBorder);
}
if (!yBorder.isEmpty())
{
invalidateRect(yBorder);
}
}
bool ScrollableContainer::doScroll(int16_t deltaX, int16_t deltaY)
{
if (!deltaX && !deltaY)
{
return false;
}
bool couldScroll = false;
Rect contained = getContainedArea();
if (contained.width > rect.width)
{
if (deltaX > 0)
{
if (contained.x + deltaX > 0)
{
deltaX = -contained.x;
}
}
else if (deltaX < 0)
{
if (contained.right() + deltaX < rect.width)
{
deltaX = rect.width - contained.right();
}
}
}
else
{
deltaX = 0;
}
if (contained.height > rect.height)
{
if (deltaY > 0)
{
if (contained.y + deltaY > 0)
{
deltaY = -contained.y;
}
}
else if (deltaY < 0)
{
if (contained.bottom() + deltaY < rect.height)
{
deltaY = rect.height - contained.bottom();
}
}
}
else
{
deltaY = 0;
}
if (deltaX || deltaY)
{
scrolledXDistance += deltaX;
scrolledYDistance += deltaY;
moveChildrenRelative(deltaX, deltaY);
invalidateScrollbars();
couldScroll = true;
}
return couldScroll;
}
void ScrollableContainer::childGeometryChanged()
{
Rect contained = getContainedArea();
// If children are not aligned top left, make sure they are
if (contained.y > 0)
{
moveChildrenRelative(0, -contained.y);
}
if (contained.x > 0)
{
moveChildrenRelative(-contained.x, 0);
}
// Make sure we haven't scrolled below the bottom
if (contained.bottom() < rect.height)
{
int16_t deltaY = contained.bottom() - rect.height;
if (contained.y > deltaY)
{
deltaY = contained.y;
}
scrolledYDistance -= deltaY;
moveChildrenRelative(0, -deltaY);
}
// Make sure we haven't scrolled too far to the right
if (contained.right() < rect.width)
{
int deltaX = contained.right() - rect.width;
if (contained.x > deltaX)
{
deltaX = contained.x;
}
scrolledXDistance -= deltaX;
moveChildrenRelative(-deltaX, 0);
}
invalidateScrollbars();
}
void ScrollableContainer::add(Drawable& d)
{
remove(xSlider);
remove(ySlider);
Container::add(d);
Container::add(xSlider);
Container::add(ySlider);
}
Rect ScrollableContainer::getContainedArea() const
{
Drawable* d = firstChild;
Rect contained(0, 0, 0, 0);
Rect r(0, 0, rect.width, rect.height);
contained.expandToFit(r);
while (d)
{
if ((d != &xSlider) && (d != &ySlider) && (d->isVisible()))
{
contained.expandToFit(d->getRect());
}
d = d->getNextSibling();
}
return contained;
}
void ScrollableContainer::reset()
{
moveChildrenRelative(-scrolledXDistance, -scrolledYDistance);
scrolledXDistance = 0;
scrolledYDistance = 0;
invalidateScrollbars();
}
void ScrollableContainer::moveChildrenRelative(int16_t deltaX, int16_t deltaY)
{
Drawable* d = firstChild;
while (d)
{
if ((d != &xSlider) && (d != &ySlider))
{
d->moveRelative(deltaX, deltaY);
}
d = d->getNextSibling();
}
}
void ScrollableContainer::handleTickEvent()
{
if (animate)
{
// Calculate new position or stop animation
animationCounter++;
if (animationCounter <= scrollDuration)
{
// Calculate value in [beginningValue ; (beginningValue+targetValue)]
int16_t calculatedValue = EasingEquations::cubicEaseOut(animationCounter, beginningValue, targetValue, scrollDuration);
// Note: Result of "calculatedValue & 1" is compiler dependent for negative values of calculatedValue
if (calculatedValue % 2)
{
// Optimization: calculatedValue is odd, add 1/-1 to move drawables modulo 32 bits in framebuffer
calculatedValue += (calculatedValue > 0) ? 1 : -1;
}
// Convert to delta value relative to current X or Y
int16_t scrollX = (accelDirection == GestureEvent::SWIPE_VERTICAL) ? 0 : (calculatedValue - getContainedArea().x);
int16_t scrollY = (accelDirection == GestureEvent::SWIPE_HORIZONTAL) ? 0 : (calculatedValue - getContainedArea().y);
// Perform the actual animation step, stop animation if
// scrolling was not possible (doScroll invalidates children)
animate = doScroll(scrollX, scrollY);
}
else
{
animate = false;
}
if (!animate)
{
Application::getInstance()->unregisterTimerWidget(this);
animationCounter = 0;
}
}
}
void ScrollableContainer::setScrollbarsColor(colortype color)
{
scrollbarColor = color;
xSlider.setColor(scrollbarColor);
ySlider.setColor(scrollbarColor);
}
void ScrollableContainer::setScrollbarsAlpha(uint8_t alpha)
{
scrollbarAlpha = alpha;
xSlider.setAlpha(scrollbarAlpha);
ySlider.setAlpha(scrollbarAlpha);
}
void ScrollableContainer::setScrollbarPadding(uint8_t padding)
{
scrollbarPadding = padding;
}
void ScrollableContainer::setScrollbarWidth(uint8_t width)
{
scrollbarWidth = width;
}
void ScrollableContainer::setScrollbarsVisible(bool newVisible)
{
scrollbarsVisible = newVisible;
}
void ScrollableContainer::setScrollbarsPermanentlyVisible()
{
scrollbarsPermanentlyVisible = true;
xSlider.setVisible(true);
ySlider.setVisible(true);
invalidateScrollbars();
}
int16_t ScrollableContainer::getScrolledX() const
{
return scrolledXDistance;
}
int16_t ScrollableContainer::getScrolledY() const
{
return scrolledYDistance;
}
void ScrollableContainer::setScrollDurationSpeedup(uint16_t speedup)
{
scrollDurationSpeedup = MAX(1, speedup);
}
uint16_t ScrollableContainer::getScrollDurationSpeedup() const
{
return scrollDurationSpeedup;
}
void ScrollableContainer::setScrollDurationSlowdown(uint16_t slowdown)
{
scrollDurationSlowdown = MAX(1, slowdown);
}
uint16_t ScrollableContainer::getScrollDurationSlowdown() const
{
return scrollDurationSlowdown;
}
} // namespace touchgfx

View File

@@ -0,0 +1,404 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/SlideMenu.hpp>
namespace touchgfx
{
SlideMenu::SlideMenu() :
Container(),
onStateChangeButtonClicked(this, &SlideMenu::stateChangeButtonClickedHandler),
animationEndedCallback(this, &SlideMenu::animationEndedHandler),
stateChangedCallback(0),
stateChangedAnimationEndedCallback(0),
currentState(COLLAPSED),
expandDirection(EAST),
animationEquation(EasingEquations::cubicEaseInOut),
visiblePixelsWhenCollapsed(0),
hiddenPixelsWhenExpanded(0),
expandedStateTimeout(200),
expandedStateTimer(0),
animationDuration(10)
{
Application::getInstance()->registerTimerWidget(this);
stateChangeButton.setAction(onStateChangeButtonClicked);
menuContainer.setMoveAnimationEndedAction(animationEndedCallback);
Container::add(menuContainer);
menuContainer.add(background);
menuContainer.add(stateChangeButton);
}
SlideMenu::~SlideMenu()
{
Application::getInstance()->unregisterTimerWidget(this); //lint !e1551
}
void SlideMenu::setup(ExpandDirection newExpandDirection, const Bitmap& backgroundBMP, const Bitmap& stateChangeButtonBMP, const Bitmap& stateChangeButtonPressedBMP)
{
int16_t backgroundX = 0;
int16_t backgroundY = 0;
int16_t buttonX = 0;
int16_t buttonY = 0;
switch (newExpandDirection)
{
case touchgfx::SlideMenu::SOUTH:
backgroundX = 0;
backgroundY = 0;
buttonX = (backgroundBMP.getWidth() - stateChangeButtonBMP.getWidth()) / 2;
buttonY = backgroundBMP.getHeight();
setVisiblePixelsWhenCollapsed(stateChangeButtonBMP.getHeight());
break;
case touchgfx::SlideMenu::NORTH:
backgroundX = 0;
backgroundY = stateChangeButtonBMP.getHeight();
buttonX = (backgroundBMP.getWidth() - stateChangeButtonBMP.getWidth()) / 2;
buttonY = 0;
setVisiblePixelsWhenCollapsed(stateChangeButtonBMP.getHeight());
break;
case touchgfx::SlideMenu::EAST:
backgroundX = 0;
backgroundY = 0;
buttonX = backgroundBMP.getWidth();
buttonY = (backgroundBMP.getHeight() - stateChangeButtonBMP.getHeight()) / 2;
setVisiblePixelsWhenCollapsed(stateChangeButtonBMP.getWidth());
break;
case touchgfx::SlideMenu::WEST:
backgroundX = stateChangeButtonBMP.getWidth();
backgroundY = 0;
buttonX = 0;
buttonY = (backgroundBMP.getHeight() - stateChangeButtonBMP.getHeight()) / 2;
setVisiblePixelsWhenCollapsed(stateChangeButtonBMP.getWidth());
break;
default:
break;
}
setup(newExpandDirection, backgroundBMP, stateChangeButtonBMP, stateChangeButtonPressedBMP, backgroundX, backgroundY, buttonX, buttonY);
}
void SlideMenu::setup(ExpandDirection newExpandDirection, const Bitmap& backgroundBMP, int16_t backgroundX, int16_t backgroundY)
{
setExpandDirection(newExpandDirection);
background.setBitmap(backgroundBMP);
background.setXY(backgroundX, backgroundY);
Rect boundingRect = background.getRect();
// boundingRect.expandToFit(background.getRect());
menuContainer.setWidth(boundingRect.right());
menuContainer.setHeight(boundingRect.bottom());
setWidth(menuContainer.getWidth());
setHeight(menuContainer.getHeight());
setExpandDirection(expandDirection);
setState(currentState);
invalidate();
}
void SlideMenu::setup(ExpandDirection newExpandDirection, const Bitmap& backgroundBMP, const Bitmap& stateChangeButtonBMP, const Bitmap& stateChangeButtonPressedBMP, int16_t backgroundX, int16_t backgroundY, int16_t stateChangeButtonX, int16_t stateChangeButtonY)
{
setExpandDirection(newExpandDirection);
background.setBitmap(backgroundBMP);
background.setXY(backgroundX, backgroundY);
stateChangeButton.setBitmaps(stateChangeButtonBMP, stateChangeButtonPressedBMP);
stateChangeButton.setXY(stateChangeButtonX, stateChangeButtonY);
Rect boundingRect(0, 0, 0, 0);
boundingRect.expandToFit(background.getRect());
boundingRect.expandToFit(stateChangeButton.getRect());
menuContainer.setWidth(boundingRect.right());
menuContainer.setHeight(boundingRect.bottom());
setWidth(menuContainer.getWidth());
setHeight(menuContainer.getHeight());
setExpandDirection(expandDirection);
setState(currentState);
invalidate();
}
void SlideMenu::setExpandDirection(ExpandDirection newExpandDirection)
{
expandDirection = newExpandDirection;
setState(currentState);
}
touchgfx::SlideMenu::ExpandDirection SlideMenu::getExpandDirection() const
{
return expandDirection;
}
void SlideMenu::setVisiblePixelsWhenCollapsed(int16_t visiblePixels)
{
visiblePixelsWhenCollapsed = visiblePixels;
setState(currentState);
}
int16_t SlideMenu::getVisiblePixelsWhenCollapsed() const
{
return visiblePixelsWhenCollapsed;
}
void SlideMenu::setHiddenPixelsWhenExpanded(int16_t hiddenPixels)
{
hiddenPixelsWhenExpanded = hiddenPixels;
setState(currentState);
}
int16_t SlideMenu::getHiddenPixelsWhenExpanded() const
{
return hiddenPixelsWhenExpanded;
}
void SlideMenu::setExpandedStateTimeout(uint16_t timeout)
{
expandedStateTimeout = timeout;
}
uint16_t SlideMenu::getExpandedStateTimeout() const
{
return expandedStateTimeout;
}
void SlideMenu::setAnimationDuration(uint16_t duration)
{
animationDuration = duration;
}
uint16_t SlideMenu::getAnimationDuration() const
{
return animationDuration;
}
void SlideMenu::setAnimationEasingEquation(EasingEquation animationEasingEquation)
{
animationEquation = animationEasingEquation;
}
touchgfx::EasingEquation SlideMenu::getAnimationEasingEquation() const
{
return animationEquation;
}
void SlideMenu::setState(State newState)
{
if (newState == COLLAPSED)
{
menuContainer.moveTo(getCollapsedXCoordinate(), getCollapsedYCoordinate());
}
else
{
menuContainer.moveTo(getExpandedXCoordinate(), getExpandedYCoordinate());
}
currentState = newState;
}
void SlideMenu::animateToState(State newState)
{
if (animationDuration == 0)
{
setState(newState);
}
else if (newState != currentState)
{
if (currentState == COLLAPSED)
{
menuContainer.startMoveAnimation(getExpandedXCoordinate(), getExpandedYCoordinate(), animationDuration, animationEquation, animationEquation);
currentState = EXPANDED;
}
else
{
menuContainer.startMoveAnimation(getCollapsedXCoordinate(), getCollapsedYCoordinate(), animationDuration, animationEquation, animationEquation);
currentState = COLLAPSED;
}
// Disable stateChangeButton while animating
stateChangeButton.setTouchable(false);
}
}
touchgfx::SlideMenu::State SlideMenu::getState()
{
return currentState;
}
void SlideMenu::resetExpandedStateTimer()
{
expandedStateTimer = 0;
}
uint16_t SlideMenu::getExpandedStateTimer() const
{
return expandedStateTimer;
}
int16_t SlideMenu::getBackgroundX() const
{
return background.getX();
}
int16_t SlideMenu::getBackgroundY() const
{
return background.getY();
}
int16_t SlideMenu::getStateChangeButtonX() const
{
return stateChangeButton.getX();
}
int16_t SlideMenu::getStateChangeButtonY() const
{
return stateChangeButton.getY();
}
void SlideMenu::setStateChangedCallback(GenericCallback< const SlideMenu& >& callback)
{
stateChangedCallback = &callback;
}
void SlideMenu::setStateChangedAnimationEndedCallback(GenericCallback< const SlideMenu& >& callback)
{
stateChangedAnimationEndedCallback = &callback;
}
void SlideMenu::handleTickEvent()
{
if ((expandedStateTimeout != 0) && (currentState == EXPANDED) && !menuContainer.isMoveAnimationRunning())
{
expandedStateTimer++;
if (expandedStateTimer > expandedStateTimeout)
{
animateToState(COLLAPSED);
}
}
}
void SlideMenu::add(Drawable& d)
{
menuContainer.add(d);
}
void SlideMenu::remove(Drawable& d)
{
menuContainer.remove(d);
}
void SlideMenu::stateChangeButtonClickedHandler(const AbstractButton& /*button*/)
{
if (currentState == COLLAPSED)
{
animateToState(EXPANDED);
}
else
{
animateToState(COLLAPSED);
}
if ((stateChangedCallback != 0) && stateChangedCallback->isValid())
{
stateChangedCallback->execute(*this);
}
}
void SlideMenu::animationEndedHandler(const MoveAnimator<Container>& /*container*/)
{
resetExpandedStateTimer();
stateChangeButton.setTouchable(true);
if ((stateChangedAnimationEndedCallback != 0) && stateChangedAnimationEndedCallback->isValid())
{
stateChangedAnimationEndedCallback->execute(*this);
}
}
int16_t SlideMenu::getCollapsedXCoordinate()
{
switch (expandDirection)
{
case touchgfx::SlideMenu::EAST:
return -menuContainer.getWidth() + visiblePixelsWhenCollapsed;
case touchgfx::SlideMenu::WEST:
return getWidth() - visiblePixelsWhenCollapsed;
case touchgfx::SlideMenu::SOUTH:
case touchgfx::SlideMenu::NORTH:
default:
return 0;
}
}
int16_t SlideMenu::getCollapsedYCoordinate()
{
switch (expandDirection)
{
case touchgfx::SlideMenu::SOUTH:
return -menuContainer.getHeight() + visiblePixelsWhenCollapsed;
case touchgfx::SlideMenu::NORTH:
return getHeight() - visiblePixelsWhenCollapsed;
case touchgfx::SlideMenu::EAST:
case touchgfx::SlideMenu::WEST:
default:
return 0;
}
}
int16_t SlideMenu::getExpandedXCoordinate()
{
switch (expandDirection)
{
case touchgfx::SlideMenu::EAST:
return -hiddenPixelsWhenExpanded;
case touchgfx::SlideMenu::WEST:
return hiddenPixelsWhenExpanded;
case touchgfx::SlideMenu::SOUTH:
case touchgfx::SlideMenu::NORTH:
default:
return 0;
}
}
int16_t SlideMenu::getExpandedYCoordinate()
{
switch (expandDirection)
{
case touchgfx::SlideMenu::SOUTH:
return -hiddenPixelsWhenExpanded;
case touchgfx::SlideMenu::NORTH:
return hiddenPixelsWhenExpanded;
case touchgfx::SlideMenu::EAST:
case touchgfx::SlideMenu::WEST:
default:
return 0;
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,296 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/Slider.hpp>
namespace touchgfx
{
Slider::Slider() :
Container(),
sliderOrientation(HORIZONTAL),
currentValue(0),
valueRangeMin(0),
valueRangeMax(1),
indicatorMinPosition(0),
indicatorMaxPosition(1),
startValueCallback(0),
stopValueCallback(0),
newValueCallback(0)
{
setTouchable(true);
// The backgroundSelectedViewPort is a container into which the bitmap for the "filled" background
// is placed. Containers are viewports, so the dimensions of this container controls how
// much of the filled background is visible.
backgroundSelectedViewPort.add(backgroundSelected);
Container::add(background);
Container::add(backgroundSelectedViewPort);
Container::add(indicator);
// Default value range
Slider::setValueRange(0, 100);
}
void Slider::setBitmaps(const Bitmap& sliderBackground, const Bitmap& sliderBackgroundSelected, const Bitmap& indicatorBitmap)
{
assert(sliderBackground.getWidth() == sliderBackgroundSelected.getWidth() &&
sliderBackground.getHeight() == sliderBackgroundSelected.getHeight() &&
"Slider::setBitmaps - background and backgroundFilled must have same dimensions");
background.setBitmap(sliderBackground);
backgroundSelected.setBitmap(sliderBackgroundSelected);
indicator.setBitmap(indicatorBitmap);
backgroundSelectedViewPort.setWidth(backgroundSelected.getWidth());
backgroundSelectedViewPort.setHeight(backgroundSelected.getHeight());
}
void Slider::setBitmaps(const BitmapId sliderBackground, const BitmapId sliderBackgroundSelected, const BitmapId indicatorBitmap)
{
setBitmaps(Bitmap(sliderBackground), Bitmap(sliderBackgroundSelected), Bitmap(indicatorBitmap));
}
void Slider::setupHorizontalSlider(uint16_t backgroundX, uint16_t backgroundY, uint16_t indicatorY, uint16_t indicatorMinX, uint16_t indicatorMaxX)
{
assert(indicatorMinX < indicatorMaxX && "Slider::setupHorizontalSlider - indicatorMinX must be smaller than indicatorMaxX");
sliderOrientation = HORIZONTAL;
background.setXY(backgroundX, backgroundY);
backgroundSelectedViewPort.setXY(backgroundX, backgroundY);
backgroundSelected.setXY(0, 0);
indicator.setY(indicatorY);
uint16_t backgroundWidth = backgroundX + static_cast<uint16_t>(background.getWidth());
uint16_t indicatorWidth = indicatorMaxX + static_cast<uint16_t>(indicator.getWidth());
int16_t newWidth = static_cast<int16_t>(MAX(backgroundWidth, indicatorWidth));
uint16_t backgroundHeight = backgroundY + static_cast<uint16_t>(background.getHeight());
uint16_t indicatorHeight = indicatorY + static_cast<uint16_t>(indicator.getHeight());
int16_t newHeight = static_cast<int16_t>(MAX(backgroundHeight, indicatorHeight));
indicatorMinPosition = indicatorMinX;
indicatorMaxPosition = indicatorMaxX;
setWidth(newWidth);
setHeight(newHeight);
setValue(currentValue);
}
void Slider::setupVerticalSlider(uint16_t backgroundX, uint16_t backgroundY, uint16_t indicatorX, uint16_t indicatorMinY, uint16_t indicatorMaxY)
{
assert(indicatorMinY < indicatorMaxY && "Slider::setupVerticalSlider - indicatorMinY must be smaller than indicatorMaxY");
sliderOrientation = VERTICAL;
background.setXY(backgroundX, backgroundY);
backgroundSelectedViewPort.setXY(backgroundX, backgroundY);
indicator.setX(indicatorX);
uint16_t backgroundWidth = backgroundX + static_cast<uint16_t>(background.getWidth());
uint16_t indicatorWidth = indicatorX + static_cast<uint16_t>(indicator.getWidth());
int16_t newWidth = static_cast<int16_t>(MAX(backgroundWidth, indicatorWidth));
uint16_t backgroundHeight = backgroundY + static_cast<uint16_t>(background.getHeight());
uint16_t indicatorHeight = indicatorMaxY + static_cast<uint16_t>(indicator.getHeight());
int16_t newHeight = static_cast<int16_t>(MAX(backgroundHeight, indicatorHeight));
indicatorMinPosition = indicatorMinY;
indicatorMaxPosition = indicatorMaxY;
setWidth(newWidth);
setHeight(newHeight);
setValue(currentValue);
}
void Slider::setValue(int value)
{
updateIndicatorPosition(valueToPosition(value));
}
void Slider::handleClickEvent(const ClickEvent& evt)
{
if ((evt.getType() == ClickEvent::PRESSED) || (evt.getType() == ClickEvent::RELEASED))
{
// Communicate the start value if a listener is registered
if ((evt.getType() == ClickEvent::PRESSED) && (startValueCallback != 0) && startValueCallback->isValid())
{
startValueCallback->execute(*this, currentValue);
}
if (sliderOrientation == HORIZONTAL)
{
updateIndicatorPosition(evt.getX() - getIndicatorRadius());
}
else
{
updateIndicatorPosition(evt.getY() - getIndicatorRadius());
}
// Communicate the stop value if a listener is registered
if ((evt.getType() == ClickEvent::RELEASED) && (stopValueCallback != 0) && stopValueCallback->isValid())
{
stopValueCallback->execute(*this, currentValue);
}
}
}
void Slider::handleDragEvent(const DragEvent& evt)
{
if (sliderOrientation == HORIZONTAL)
{
updateIndicatorPosition(evt.getNewX() - getIndicatorRadius());
}
else
{
updateIndicatorPosition(evt.getNewY() - getIndicatorRadius());
}
}
int16_t Slider::valueToPosition(int value) const
{
value = MAX(MIN(valueRangeMax, value), valueRangeMin);
int coordinateOffset = ((value - valueRangeMin) * (getIndicatorPositionRangeSize() + 1)) / getValueRangeSize();
int result = indicatorMinPosition + coordinateOffset;
if (sliderOrientation == VERTICAL)
{
// Vertical slider grows as the position decreases so invert the coordinate
result = indicatorMinPosition + (indicatorMaxPosition - result);
}
return result;
}
int Slider::positionToValue(int16_t position) const
{
int result;
if (position == indicatorMinPosition)
{
// Ensure that min coordinate always results in min value
result = valueRangeMin;
}
else if (position == indicatorMaxPosition)
{
// Ensure that max coordinate always results in max value
result = valueRangeMax;
}
else
{
int rounding = getIndicatorPositionRangeSize() / 2;
int valueOffset = (((position - indicatorMinPosition) * getValueRangeSize()) + rounding) / getIndicatorPositionRangeSize();
result = valueRangeMin + valueOffset;
}
if (sliderOrientation == VERTICAL)
{
// Vertical slider grows as the position decreases so invert the value
result = valueRangeMin + (valueRangeMax - result);
}
return result;
}
void Slider::updateIndicatorPosition(int16_t position)
{
// Cut off positions outside the slider area
position = MIN(MAX(position, indicatorMinPosition), indicatorMaxPosition);
if (sliderOrientation == HORIZONTAL)
{
indicator.moveTo(position, indicator.getY());
backgroundSelectedViewPort.invalidate();
backgroundSelectedViewPort.setWidth((position - backgroundSelectedViewPort.getX()) + getIndicatorRadius());
backgroundSelectedViewPort.invalidate();
}
else
{
indicator.moveTo(indicator.getX(), position);
backgroundSelectedViewPort.invalidate();
int16_t newViewPortHeight = background.getRect().bottom() - (position + getIndicatorRadius());
backgroundSelectedViewPort.setPosition(backgroundSelectedViewPort.getX(), position + getIndicatorRadius(), backgroundSelectedViewPort.getWidth(), newViewPortHeight);
backgroundSelected.setY(-(backgroundSelected.getHeight() - newViewPortHeight));
backgroundSelectedViewPort.invalidate();
}
currentValue = positionToValue(position);
// Communicate the new value if a listener is registered
if ((newValueCallback != 0) && newValueCallback->isValid())
{
newValueCallback->execute(*this, currentValue);
}
}
uint16_t Slider::getIndicatorRadius() const
{
uint16_t result;
if (sliderOrientation == HORIZONTAL)
{
result = indicator.getWidth() / 2;
}
else
{
result = indicator.getHeight() / 2;
}
return result;
}
void Slider::setValueRange(int minValue, int maxValue, int newValue)
{
assert(minValue < maxValue && "Slider::setValueRange - minValue must be smaller than maxValue");
valueRangeMin = minValue;
valueRangeMax = maxValue;
setValue(newValue);
}
void Slider::setValueRange(int minValue, int maxValue)
{
int newValue = currentValue;
if (currentValue < minValue)
{
newValue = minValue;
}
else if (currentValue > maxValue)
{
newValue = maxValue;
}
setValueRange(minValue, maxValue, newValue);
}
int Slider::getIndicatorPositionRangeSize() const
{
return indicatorMaxPosition - indicatorMinPosition;
}
int Slider::getValueRangeSize() const
{
return valueRangeMax - valueRangeMin;
}
} // namespace touchgfx

View File

@@ -0,0 +1,398 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/SwipeContainer.hpp>
#include <touchgfx/EasingEquations.hpp>
namespace touchgfx
{
SwipeContainer::SwipeContainer() :
Container(),
currentState(NO_ANIMATION),
numberOfPages(0),
animationCounter(0),
swipeCutoff(80),
dragX(0),
animateDistance(0),
startX(0),
currentPage(0),
endElasticWidth(30),
pages(EAST),
pageIndicator()
{
touchgfx::Application::getInstance()->registerTimerWidget(this);
setTouchable(true);
Container::add(pages);
Container::add(pageIndicator);
}
SwipeContainer::~SwipeContainer()
{
touchgfx::Application::getInstance()->unregisterTimerWidget(this);
}
void SwipeContainer::add(Drawable& page)
{
pages.add(page);
numberOfPages++;
pageIndicator.setNumberOfPages(numberOfPages);
setWidth(page.getWidth());
setHeight(page.getHeight());
}
void SwipeContainer::remove(Drawable& page)
{
Drawable* tmp = pages.getFirstChild();
if (!numberOfPages)
{
return;
}
// looks for the child matching page
// to ensure that the page indicator only counts down if a page is removed
while (tmp)
{
if (tmp == &page)
{
pages.remove(page);
numberOfPages--;
if (!numberOfPages)
{
setWidth(0);
setHeight(0);
}
else
{
pageIndicator.setNumberOfPages(numberOfPages);
}
return;
}
else
{
tmp = tmp->getNextSibling();
}
}
}
void SwipeContainer::setEndSwipeElasticWidth(uint16_t width)
{
endElasticWidth = width;
}
void SwipeContainer::setSwipeCutoff(uint16_t cutoff)
{
swipeCutoff = cutoff;
}
void SwipeContainer::setPageIndicatorBitmaps(const touchgfx::Bitmap& normalPage, const touchgfx::Bitmap& highlightedPage)
{
pageIndicator.setBitmaps(normalPage, highlightedPage);
}
void SwipeContainer::setPageIndicatorXY(int16_t x, int16_t y)
{
pageIndicator.setXY(x, y);
}
void SwipeContainer::setPageIndicatorXYWithCenteredX(int16_t x, int16_t y)
{
pageIndicator.setXY(x - pageIndicator.getWidth() / 2, y);
}
void SwipeContainer::setSelectedPage(uint8_t pageIndex)
{
currentPage = pageIndex;
pageIndicator.setHighlightPosition(currentPage);
adjustPages();
}
void SwipeContainer::handleTickEvent()
{
if (currentState == ANIMATE_SWIPE_CANCELLED_LEFT)
{
animateSwipeCancelledLeft();
}
else if (currentState == ANIMATE_SWIPE_CANCELLED_RIGHT)
{
animateSwipeCancelledRight();
}
else if (currentState == ANIMATE_LEFT)
{
animateLeft();
}
else if (currentState == ANIMATE_RIGHT)
{
animateRight();
}
}
void SwipeContainer::handleClickEvent(const ClickEvent& evt)
{
// If an animation is already in progress do not
// react to clicks
if (currentState != NO_ANIMATION)
{
return;
}
if (evt.getType() == ClickEvent::RELEASED)
{
// Save current position for use during animation
animateDistance = dragX;
startX = pages.getX();
if (dragX < 0)
{
if (currentPage == getNumberOfPages() - 1 || dragX > -swipeCutoff)
{
currentState = ANIMATE_SWIPE_CANCELLED_LEFT;
}
else
{
currentState = ANIMATE_LEFT;
}
}
else if (dragX > 0)
{
if (currentPage == 0 || dragX < swipeCutoff)
{
currentState = ANIMATE_SWIPE_CANCELLED_RIGHT;
}
else
{
currentState = ANIMATE_RIGHT;
}
}
}
}
void SwipeContainer::handleDragEvent(const DragEvent& evt)
{
// If an animation is already in progress do not
// react to drags
if (currentState != NO_ANIMATION)
{
return;
}
dragX += evt.getDeltaX();
// Do not show too much background next to end pages
if (currentPage == 0 && dragX > endElasticWidth)
{
dragX = static_cast<int16_t>(endElasticWidth);
}
else if (currentPage == getNumberOfPages() - 1 && dragX < -endElasticWidth)
{
dragX = -static_cast<int16_t>(endElasticWidth);
}
adjustPages();
}
void SwipeContainer::handleGestureEvent(const GestureEvent& evt)
{
// Do not accept gestures while animating
if (currentState != NO_ANIMATION)
{
return;
}
if (evt.getType() == GestureEvent::SWIPE_HORIZONTAL)
{
// Save current position for use during animation
animateDistance = dragX;
startX = pages.getX();
if (evt.getVelocity() < 0 && currentPage < getNumberOfPages() - 1)
{
currentState = ANIMATE_LEFT;
}
else if (evt.getVelocity() > 0 && currentPage > 0)
{
currentState = ANIMATE_RIGHT;
}
}
}
void SwipeContainer::adjustPages()
{
pages.moveTo(-static_cast<int16_t>(currentPage * getWidth()) + dragX, 0);
}
void SwipeContainer::animateSwipeCancelledLeft()
{
uint8_t duration = 14;
if (animationCounter <= duration)
{
int16_t delta = EasingEquations::backEaseOut(animationCounter, 0, -animateDistance, duration);
dragX = animateDistance + delta;
adjustPages();
}
else
{
// Final step: stop the animation
currentState = NO_ANIMATION;
animationCounter = 0;
dragX = 0;
adjustPages();
}
animationCounter++;
}
void SwipeContainer::animateSwipeCancelledRight()
{
uint8_t duration = 14;
if (animationCounter <= duration)
{
int16_t delta = EasingEquations::backEaseOut(animationCounter, 0, animateDistance, duration);
dragX = animateDistance - delta;
adjustPages();
}
else
{
// Final step: stop the animation
currentState = NO_ANIMATION;
animationCounter = 0;
dragX = 0;
adjustPages();
}
animationCounter++;
}
void SwipeContainer::animateLeft()
{
uint8_t duration = 10;
if (animationCounter <= duration)
{
int16_t delta = EasingEquations::cubicEaseOut(animationCounter, 0, getWidth() + animateDistance, duration);
dragX = animateDistance - delta;
adjustPages();
}
else
{
// Final step: stop the animation
currentState = NO_ANIMATION;
animationCounter = 0;
currentPage++;
dragX = 0;
adjustPages();
pageIndicator.goRight();
}
animationCounter++;
}
void SwipeContainer::animateRight()
{
uint8_t duration = 10;
if (animationCounter <= duration)
{
int16_t delta = EasingEquations::cubicEaseOut(animationCounter, 0, getWidth() - animateDistance, duration);
dragX = animateDistance + delta;
adjustPages();
}
else
{
// Final step: stop the animation
currentState = NO_ANIMATION;
animationCounter = 0;
currentPage--;
dragX = 0;
adjustPages();
pageIndicator.goLeft();
}
animationCounter++;
}
SwipeContainer::PageIndicator::PageIndicator() :
Container(),
numberOfPages(0),
currentPage(0)
{
unselectedPages.setXY(0, 0);
selectedPage.setXY(0, 0);
Container::add(unselectedPages);
Container::add(selectedPage);
}
void SwipeContainer::PageIndicator::setNumberOfPages(uint8_t size)
{
numberOfPages = size;
assert(numberOfPages > 0 && "At least one dot is needed");
numberOfPages = size;
if (unselectedPages.getBitmap() != BITMAP_INVALID)
{
int dotWidth = Bitmap(unselectedPages.getBitmap()).getWidth();
unselectedPages.setWidth(dotWidth * size);
// adjust size of container according to the actual bitmaps
setWidth(unselectedPages.getWidth());
setHeight(unselectedPages.getHeight());
setHighlightPosition(currentPage = 0);
invalidate();
}
}
void SwipeContainer::PageIndicator::setBitmaps(const touchgfx::Bitmap& normalPage, const touchgfx::Bitmap& highlightedPage)
{
selectedPage.setBitmap(highlightedPage);
unselectedPages.setBitmap(normalPage);
if (numberOfPages > 0)
{
setNumberOfPages(numberOfPages);
}
}
void SwipeContainer::PageIndicator::goRight()
{
setHighlightPosition(currentPage = (currentPage + 1) % numberOfPages);
}
void SwipeContainer::PageIndicator::goLeft()
{
setHighlightPosition(currentPage = (currentPage + numberOfPages - 1) % numberOfPages);
}
void SwipeContainer::PageIndicator::setHighlightPosition(uint8_t index)
{
currentPage = index;
// note that index is unsigned
if (index < numberOfPages)
{
int dotWidth = Bitmap(unselectedPages.getBitmap()).getWidth();
selectedPage.setX(index * dotWidth);
}
invalidate();
}
} // namespace touchgfx

View File

@@ -0,0 +1,307 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/ZoomAnimationImage.hpp>
namespace touchgfx
{
ZoomAnimationImage::ZoomAnimationImage() :
Container(),
currentState(NO_ANIMATION),
animationCounter(0),
zoomAnimationDelay(0),
currentZoomMode(FIXED_LEFT_AND_TOP),
zoomAnimationStartWidth(0),
zoomAnimationStartHeight(0),
zoomAnimationEndWidth(0),
zoomAnimationEndHeight(0),
zoomAnimationStartX(0),
zoomAnimationStartY(0),
zoomAnimationDeltaX(0),
zoomAnimationDeltaY(0),
moveAnimationEndX(0),
moveAnimationEndY(0),
animationDuration(0),
zoomAnimationWidthEquation(EasingEquations::linearEaseNone),
zoomAnimationHeightEquation(EasingEquations::linearEaseNone),
moveAnimationXEquation(EasingEquations::linearEaseNone),
moveAnimationYEquation(EasingEquations::linearEaseNone),
animationEndedAction(0)
{
image.setXY(0, 0);
image.setVisible(false);
scalableImage.setScalingAlgorithm(ScalableImage::NEAREST_NEIGHBOR);
scalableImage.setXY(0, 0);
scalableImage.setVisible(false);
Container::add(image);
Container::add(scalableImage);
}
void ZoomAnimationImage::startZoomAnimation(int16_t endWidth, int16_t endHeight, uint16_t duration, ZoomMode zoomMode, EasingEquation widthProgressionEquation, EasingEquation heightProgressionEquation)
{
setCurrentState(ANIMATE_ZOOM);
startTimerAndSetParameters(endWidth, endHeight, duration, zoomMode, widthProgressionEquation, heightProgressionEquation);
}
void ZoomAnimationImage::startZoomAndMoveAnimation(int16_t endX, int16_t endY, int16_t endWidth, int16_t endHeight, uint16_t duration, ZoomMode zoomMode, EasingEquation xProgressionEquation, EasingEquation yProgressionEquation, EasingEquation widthProgressionEquation, EasingEquation heightProgressionEquation)
{
moveAnimationEndX = endX;
moveAnimationEndY = endY;
moveAnimationXEquation = xProgressionEquation;
moveAnimationYEquation = yProgressionEquation;
setCurrentState(ANIMATE_ZOOM_AND_MOVE);
startTimerAndSetParameters(endWidth, endHeight, duration, zoomMode, widthProgressionEquation, heightProgressionEquation);
}
void ZoomAnimationImage::cancelZoomAnimation()
{
touchgfx::Application::getInstance()->unregisterTimerWidget(this);
setCurrentState(NO_ANIMATION);
}
void ZoomAnimationImage::handleTickEvent()
{
if ((currentState == ANIMATE_ZOOM) || (currentState == ANIMATE_ZOOM_AND_MOVE))
{
if (animationCounter < zoomAnimationDelay)
{
// Just wait for the delay time to pass
animationCounter++;
}
else if (animationCounter <= (uint32_t)(zoomAnimationDelay + animationDuration))
{
// Adjust the used animationCounter for the startup delay
uint32_t actualAnimationCounter = animationCounter - zoomAnimationDelay;
int16_t deltaWidth = zoomAnimationWidthEquation(actualAnimationCounter, 0, zoomAnimationEndWidth - zoomAnimationStartWidth, animationDuration);
int16_t deltaHeight = zoomAnimationHeightEquation(actualAnimationCounter, 0, zoomAnimationEndHeight - zoomAnimationStartHeight, animationDuration);
setDimension(zoomAnimationStartWidth + deltaWidth, zoomAnimationStartHeight + deltaHeight);
int16_t deltaX;
int16_t deltaY;
if (currentState == ANIMATE_ZOOM_AND_MOVE)
{
deltaX = moveAnimationXEquation(actualAnimationCounter, 0, (moveAnimationEndX - zoomAnimationStartX) + zoomAnimationDeltaX, animationDuration);
deltaY = moveAnimationYEquation(actualAnimationCounter, 0, (moveAnimationEndY - zoomAnimationStartY) + zoomAnimationDeltaY, animationDuration);
}
else
{
deltaX = zoomAnimationWidthEquation(actualAnimationCounter, 0, zoomAnimationDeltaX, animationDuration);
deltaY = zoomAnimationHeightEquation(actualAnimationCounter, 0, zoomAnimationDeltaY, animationDuration);
}
moveTo(zoomAnimationStartX + deltaX, zoomAnimationStartY + deltaY);
animationCounter++;
}
else
{
cancelZoomAnimation();
if (animationEndedAction && animationEndedAction->isValid())
{
animationEndedAction->execute(*this);
}
}
}
}
void ZoomAnimationImage::setBitmaps(const Bitmap& smallBitmap, const Bitmap& largeBitmap)
{
smallBmp = smallBitmap;
largeBmp = largeBitmap;
scalableImage.setBitmap(largeBmp);
touchgfx::Container::setWidth(largeBmp.getWidth());
touchgfx::Container::setHeight(largeBmp.getHeight());
updateRenderingMethod();
}
void ZoomAnimationImage::setPosition(int16_t x, int16_t y, int16_t width, int16_t height)
{
invalidate();
touchgfx::Container::setPosition(x, y, width, height);
updateRenderingMethod();
}
void ZoomAnimationImage::setWidth(int16_t width)
{
setDimension(width, getHeight());
}
void ZoomAnimationImage::setHeight(int16_t height)
{
setDimension(getWidth(), height);
}
void ZoomAnimationImage::setDimension(int16_t width, int16_t height)
{
invalidate();
touchgfx::Container::setWidth(width);
touchgfx::Container::setHeight(height);
updateRenderingMethod();
}
void ZoomAnimationImage::setScalingMode(ScalableImage::ScalingAlgorithm mode)
{
scalableImage.setScalingAlgorithm(mode);
}
ScalableImage::ScalingAlgorithm ZoomAnimationImage::getScalingMode()
{
return scalableImage.getScalingAlgorithm();
}
void ZoomAnimationImage::setAlpha(const uint8_t alpha)
{
image.setAlpha(alpha);
scalableImage.setAlpha(alpha);
}
uint8_t ZoomAnimationImage::getAlpha() const
{
return image.getAlpha();
}
void ZoomAnimationImage::setAnimationDelay(uint16_t delay)
{
zoomAnimationDelay = delay;
}
uint16_t ZoomAnimationImage::getAnimationDelay() const
{
return zoomAnimationDelay;
}
bool ZoomAnimationImage::isRunning()
{
return isZoomAnimationRunning();
}
bool ZoomAnimationImage::isZoomAnimationRunning() const
{
return currentState != NO_ANIMATION;
}
void ZoomAnimationImage::updateRenderingMethod()
{
if ((smallBmp.getWidth() == getWidth()) && (smallBmp.getHeight() == getHeight()))
{
image.setVisible(true);
scalableImage.setVisible(false);
image.setBitmap(smallBmp);
image.invalidate();
scalableImage.invalidate();
}
else if ((largeBmp.getWidth() == getWidth()) && (largeBmp.getHeight() == getHeight()))
{
image.setVisible(true);
scalableImage.setVisible(false);
image.setBitmap(largeBmp);
image.invalidate();
scalableImage.invalidate();
}
else
{
image.setVisible(false);
image.invalidate();
scalableImage.setVisible(true);
scalableImage.setWidth(getWidth());
scalableImage.setHeight(getHeight());
scalableImage.invalidate();
}
}
void ZoomAnimationImage::setCurrentState(States state)
{
currentState = state;
animationCounter = 0;
}
void ZoomAnimationImage::startTimerAndSetParameters(int16_t endWidth, int16_t endHeight, uint16_t duration, ZoomMode zoomMode, EasingEquation widthProgressionEquation, EasingEquation heightProgressionEquation)
{
touchgfx::Application::getInstance()->registerTimerWidget(this);
currentZoomMode = zoomMode;
zoomAnimationStartX = getX();
zoomAnimationStartY = getY();
zoomAnimationStartWidth = getWidth();
zoomAnimationStartHeight = getHeight();
zoomAnimationEndWidth = endWidth;
zoomAnimationEndHeight = endHeight;
animationDuration = duration;
zoomAnimationWidthEquation = widthProgressionEquation;
zoomAnimationHeightEquation = heightProgressionEquation;
updateZoomAnimationDeltaXY();
if (zoomAnimationDelay == 0 && animationDuration == 0)
{
handleTickEvent(); // Finish the zoom and move operation immediately
}
}
void ZoomAnimationImage::updateZoomAnimationDeltaXY()
{
zoomAnimationDeltaX = zoomAnimationStartWidth - zoomAnimationEndWidth;
zoomAnimationDeltaY = zoomAnimationStartHeight - zoomAnimationEndHeight;
switch (currentZoomMode)
{
case ZoomAnimationImage::FIXED_CENTER:
zoomAnimationDeltaX /= 2;
zoomAnimationDeltaY /= 2;
break;
case ZoomAnimationImage::FIXED_LEFT:
zoomAnimationDeltaX = 0;
zoomAnimationDeltaY /= 2;
break;
case ZoomAnimationImage::FIXED_RIGHT:
zoomAnimationDeltaY /= 2;
break;
case ZoomAnimationImage::FIXED_TOP:
zoomAnimationDeltaX /= 2;
zoomAnimationDeltaY = 0;
break;
case ZoomAnimationImage::FIXED_BOTTOM:
zoomAnimationDeltaX /= 2;
break;
case ZoomAnimationImage::FIXED_LEFT_AND_TOP:
zoomAnimationDeltaX = 0;
zoomAnimationDeltaY = 0;
break;
case ZoomAnimationImage::FIXED_RIGHT_AND_TOP:
zoomAnimationDeltaY = 0;
break;
case ZoomAnimationImage::FIXED_LEFT_AND_BOTTOM:
zoomAnimationDeltaX = 0;
break;
case ZoomAnimationImage::FIXED_RIGHT_AND_BOTTOM:
break;
default:
break;
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,56 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/clock/AbstractClock.hpp>
namespace touchgfx
{
AbstractClock::AbstractClock() :
Container(),
currentHour(0),
currentMinute(0),
currentSecond(0)
{
}
void AbstractClock::setTime24Hour(uint8_t hour, uint8_t minute, uint8_t second)
{
currentHour = hour % 24;
currentMinute = minute % 60;
currentSecond = second % 60;
updateClock();
}
void AbstractClock::setTime12Hour(uint8_t hour, uint8_t minute, uint8_t second, bool am)
{
setTime24Hour((hour % 12) + (am ? 0 : 12), minute, second);
}
uint8_t AbstractClock::getCurrentHour() const
{
return currentHour;
}
uint8_t AbstractClock::getCurrentMinute() const
{
return currentMinute;
}
uint8_t AbstractClock::getCurrentSecond() const
{
return currentSecond;
}
}

View File

@@ -0,0 +1,234 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/clock/AnalogClock.hpp>
namespace touchgfx
{
AnalogClock::AnalogClock() :
AbstractClock(),
animationEquation(EasingEquations::linearEaseNone),
animationDuration(0),
clockRotationCenterX(0),
clockRotationCenterY(0),
lastHour(0),
lastMinute(0),
lastSecond(0),
hourHandMinuteCorrectionActive(false),
minuteHandSecondCorrectionActive(false)
{
Container::add(background);
hourHand.updateZAngle(0.f);
minuteHand.updateZAngle(0.f);
secondHand.updateZAngle(0.f);
hourHand.setVisible(false);
minuteHand.setVisible(false);
secondHand.setVisible(false);
}
void AnalogClock::setBackground(const BitmapId backgroundBitmapId)
{
setBackground(backgroundBitmapId, Bitmap(backgroundBitmapId).getWidth() / 2, Bitmap(backgroundBitmapId).getHeight() / 2);
}
void AnalogClock::setBackground(const BitmapId backgroundBitmapId, const int16_t rotationCenterX, const int16_t rotationCenterY)
{
background.setBitmap(Bitmap(backgroundBitmapId));
clockRotationCenterX = rotationCenterX;
clockRotationCenterY = rotationCenterY;
setWidth(background.getWidth());
setHeight(background.getHeight());
}
void AnalogClock::setRotationCenter(int16_t rotationCenterX, int16_t rotationCenterY)
{
clockRotationCenterX = rotationCenterX;
clockRotationCenterY = rotationCenterY;
}
void AnalogClock::setupHourHand(const BitmapId hourHandBitmapId, int16_t rotationCenterX, int16_t rotationCenterY)
{
setupHand(hourHand, hourHandBitmapId, rotationCenterX, rotationCenterY);
}
void AnalogClock::setupMinuteHand(const BitmapId minuteHandBitmapId, int16_t rotationCenterX, int16_t rotationCenterY)
{
setupHand(minuteHand, minuteHandBitmapId, rotationCenterX, rotationCenterY);
}
void AnalogClock::setupSecondHand(const BitmapId secondHandBitmapId, int16_t rotationCenterX, int16_t rotationCenterY)
{
setupHand(secondHand, secondHandBitmapId, rotationCenterX, rotationCenterY);
}
void AnalogClock::setupHand(TextureMapper& hand, const BitmapId bitmapId, int16_t rotationCenterX, int16_t rotationCenterY)
{
remove(hand);
hand.setBitmap(Bitmap(bitmapId));
hand.setWidth(getWidth());
hand.setHeight(getHeight());
hand.setXY(0, 0);
hand.setBitmapPosition(clockRotationCenterX - rotationCenterX, clockRotationCenterY - rotationCenterY);
hand.setCameraDistance(300.0f);
hand.setOrigo((float)clockRotationCenterX, (float)clockRotationCenterY, hand.getCameraDistance());
hand.setCamera(hand.getOrigoX(), hand.getOrigoY());
hand.setRenderingAlgorithm(TextureMapper::BILINEAR_INTERPOLATION);
add(hand);
hand.setVisible(true);
}
void AnalogClock::initializeTime24Hour(uint8_t hour, uint8_t minute, uint8_t second)
{
lastHour = 255;
lastMinute = 255;
lastSecond = 255;
// Disable animation and set time
uint16_t tempAnimationDuration = animationDuration;
animationDuration = 1;
setTime24Hour(hour, minute, second);
animationDuration = tempAnimationDuration;
}
void AnalogClock::initializeTime12Hour(uint8_t hour, uint8_t minute, uint8_t second, bool am)
{
initializeTime24Hour((hour % 12) + (am ? 0 : 12), minute, second);
}
void AnalogClock::updateClock()
{
// Make sure that animating to 0 will move from left to right
if (lastHour != 0 && currentHour == 0)
{
hourHand.updateZAngle(hourHand.getZAngle() - (2 * PI));
}
if (lastMinute != 0 && currentMinute == 0)
{
minuteHand.updateZAngle(minuteHand.getZAngle() - (2 * PI));
}
if (lastSecond != 0 && currentSecond == 0)
{
secondHand.updateZAngle(secondHand.getZAngle() - (2 * PI));
}
float newHandAngle;
// Move hour hand
if (hourHand.isVisible() && ((currentHour != lastHour) || (hourHandMinuteCorrectionActive && (currentMinute != lastMinute))))
{
newHandAngle = convertHandValueToAngle(12, currentHour, hourHandMinuteCorrectionActive ? currentMinute : 0);
if (animationEnabled() && !hourHand.isTextureMapperAnimationRunning())
{
hourHand.setupAnimation(AnimationTextureMapper::Z_ROTATION, newHandAngle, animationDuration, 0, animationEquation);
hourHand.startAnimation();
}
else
{
if (animationEnabled())
{
hourHand.cancelAnimationTextureMapperAnimation();
}
hourHand.updateZAngle(newHandAngle);
}
}
// Move minute hand
if (minuteHand.isVisible() && ((currentMinute != lastMinute) || (minuteHandSecondCorrectionActive && (currentSecond != lastSecond))))
{
newHandAngle = convertHandValueToAngle(60, currentMinute, minuteHandSecondCorrectionActive ? currentSecond : 0);
if (animationEnabled() && !minuteHand.isTextureMapperAnimationRunning())
{
minuteHand.setupAnimation(AnimationTextureMapper::Z_ROTATION, newHandAngle, animationDuration, 0, animationEquation);
minuteHand.startAnimation();
}
else
{
if (animationEnabled())
{
minuteHand.cancelAnimationTextureMapperAnimation();
}
minuteHand.updateZAngle(newHandAngle);
}
}
// Move second hand
if (secondHand.isVisible() && (currentSecond != lastSecond))
{
newHandAngle = convertHandValueToAngle(60, currentSecond);
if (animationEnabled() && !secondHand.isTextureMapperAnimationRunning())
{
secondHand.setupAnimation(AnimationTextureMapper::Z_ROTATION, newHandAngle, animationDuration, 0, animationEquation);
secondHand.startAnimation();
}
else
{
if (animationEnabled())
{
secondHand.cancelAnimationTextureMapperAnimation();
}
secondHand.updateZAngle(newHandAngle);
}
}
lastHour = currentHour;
lastMinute = currentMinute;
lastSecond = currentSecond;
}
float AnalogClock::convertHandValueToAngle(uint8_t steps, uint8_t handValue, uint8_t secondHandValue /*= 0*/) const
{
return ((handValue / (float)steps) + (secondHandValue / (steps * 60.f))) * 2 * PI;
}
void AnalogClock::setHourHandMinuteCorrection(bool active)
{
hourHandMinuteCorrectionActive = active;
setTime24Hour(getCurrentHour(), getCurrentMinute(), getCurrentSecond());
}
bool AnalogClock::getHourHandMinuteCorrection() const
{
return hourHandMinuteCorrectionActive;
}
void AnalogClock::setMinuteHandSecondCorrection(bool active)
{
minuteHandSecondCorrectionActive = active;
setTime24Hour(getCurrentHour(), getCurrentMinute(), getCurrentSecond());
}
bool AnalogClock::getMinuteHandSecondCorrection() const
{
return minuteHandSecondCorrectionActive;
}
bool AnalogClock::animationEnabled() const
{
return animationDuration > 1;
}
void AnalogClock::setAnimation(uint16_t duration, EasingEquation animationProgressionEquation)
{
animationDuration = duration;
animationEquation = animationProgressionEquation;
}
}

View File

@@ -0,0 +1,102 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/clock/DigitalClock.hpp>
namespace touchgfx
{
DigitalClock::DigitalClock() :
AbstractClock(),
displayMode(DISPLAY_24_HOUR),
useLeadingZeroForHourIndicator(false)
{
buffer[0] = '\0';
text.setXY(0, 0);
text.setWildcard(buffer);
Container::add(text);
}
void DigitalClock::setWidth(int16_t width)
{
Container::setWidth(width);
text.setWidth(width);
}
void DigitalClock::setHeight(int16_t height)
{
Container::setHeight(height);
text.setHeight(height);
}
void DigitalClock::setBaselineY(int16_t baselineY)
{
if (text.getTypedText().hasValidId())
{
moveTo(getX(), baselineY - text.getTypedText().getFont()->getFontHeight());
}
}
void DigitalClock::displayLeadingZeroForHourIndicator(bool displayLeadingZero)
{
useLeadingZeroForHourIndicator = displayLeadingZero;
}
void DigitalClock::setAlpha(uint8_t newAlpha)
{
text.setAlpha(newAlpha);
}
uint8_t DigitalClock::getAlpha() const
{
return text.getAlpha();
}
void DigitalClock::setTypedText(TypedText typedText)
{
text.setTypedText(typedText);
text.invalidate();
}
void DigitalClock::setColor(colortype color)
{
text.setColor(color);
text.invalidate();
}
void DigitalClock::updateClock()
{
if (displayMode == DISPLAY_12_HOUR_NO_SECONDS)
{
const char* format = useLeadingZeroForHourIndicator ? "%02d:%02d %cM" : "%d:%02d %cM";
Unicode::snprintf(buffer, BUFFER_SIZE, format, ((currentHour + 11) % 12) + 1, currentMinute, currentHour < 12 ? 'A' : 'P');
}
else if (displayMode == DISPLAY_24_HOUR_NO_SECONDS)
{
const char* format = useLeadingZeroForHourIndicator ? "%02d:%02d" : "%d:%02d";
Unicode::snprintf(buffer, BUFFER_SIZE, format, currentHour, currentMinute);
}
else if (displayMode == DISPLAY_12_HOUR)
{
const char* format = useLeadingZeroForHourIndicator ? "%02d:%02d:%02d %cM" : "%d:%02d:%02d %cM";
Unicode::snprintf(buffer, BUFFER_SIZE, format, ((currentHour + 11) % 12) + 1, currentMinute, currentSecond, currentHour < 12 ? 'A' : 'P');
}
else if (displayMode == DISPLAY_24_HOUR)
{
const char* format = useLeadingZeroForHourIndicator ? "%02d:%02d:%02d" : "%d:%02d:%02d";
Unicode::snprintf(buffer, BUFFER_SIZE, format, currentHour, currentMinute, currentSecond);
}
text.invalidate();
}
} // namespace touchgfx

View File

@@ -0,0 +1,37 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/progress_indicators/AbstractDirectionProgress.hpp>
namespace touchgfx
{
AbstractDirectionProgress::AbstractDirectionProgress()
: AbstractProgressIndicator()
{
AbstractDirectionProgress::setDirection(RIGHT);
}
void AbstractDirectionProgress::setDirection(DirectionType direction)
{
progressDirection = direction;
progressIndicatorContainer.invalidate();
setValue(getValue());
}
touchgfx::AbstractDirectionProgress::DirectionType AbstractDirectionProgress::getDirection() const
{
return progressDirection;
}
} // namespace touchgfx

View File

@@ -0,0 +1,135 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/progress_indicators/AbstractProgressIndicator.hpp>
namespace touchgfx
{
AbstractProgressIndicator::AbstractProgressIndicator()
: Container(), rangeMin(0), rangeMax(100), currentValue(0), rangeSteps(100), rangeStepsMin(0)
{
background.setXY(0, 0);
Container::add(background);
Container::add(progressIndicatorContainer);
}
void AbstractProgressIndicator::setBackground(const Bitmap& bmpBackground)
{
background.setBitmap(bmpBackground);
Drawable::setWidth(background.getWidth());
Drawable::setHeight(background.getHeight());
}
void AbstractProgressIndicator::setProgressIndicatorPosition(int16_t x, int16_t y, int16_t width, int16_t height)
{
progressIndicatorContainer.setPosition(x, y, width, height);
if (getWidth() < x + width)
{
AbstractProgressIndicator::setWidth(x + width);
}
if (getHeight() < y + height)
{
AbstractProgressIndicator::setHeight(y + height);
}
}
int16_t AbstractProgressIndicator::getProgressIndicatorX() const
{
return progressIndicatorContainer.getX();
}
int16_t AbstractProgressIndicator::getProgressIndicatorY() const
{
return progressIndicatorContainer.getY();
}
int16_t AbstractProgressIndicator::getProgressIndicatorWidth() const
{
return progressIndicatorContainer.getWidth();
}
int16_t AbstractProgressIndicator::getProgressIndicatorHeight() const
{
return progressIndicatorContainer.getHeight();
}
void AbstractProgressIndicator::setRange(int16_t min, int16_t max, uint16_t steps /*= 0*/, uint16_t minStep /*= 0*/)
{
assert(min < max);
rangeMin = min;
rangeMax = max;
setValue(currentValue);
if (steps == 0)
{
rangeSteps = max - min;
}
else
{
rangeSteps = steps;
}
rangeStepsMin = minStep;
assert(rangeStepsMin < rangeSteps);
}
void AbstractProgressIndicator::getRange(int16_t& min, int16_t& max, uint16_t& steps, uint16_t& minStep) const
{
min = rangeMin;
max = rangeMax;
steps = rangeSteps;
minStep = rangeStepsMin;
}
void AbstractProgressIndicator::getRange(int16_t& min, int16_t& max, uint16_t& steps) const
{
min = rangeMin;
max = rangeMax;
steps = rangeSteps;
}
void AbstractProgressIndicator::getRange(int16_t& min, int16_t& max) const
{
min = rangeMin;
max = rangeMax;
}
void AbstractProgressIndicator::setValue(int value)
{
int newValue = MAX(value, rangeMin);
newValue = MIN(newValue, rangeMax);
currentValue = newValue;
}
int AbstractProgressIndicator::getValue() const
{
return currentValue;
}
uint16_t AbstractProgressIndicator::getProgress(uint16_t range /*= 100*/) const
{
if (range == 0)
{
return 0;
}
int32_t remainder; // Not used here
// Find out at what step the current value is.
int32_t step = rangeStepsMin + muldiv(currentValue - rangeMin, rangeSteps - rangeStepsMin, rangeMax - rangeMin, remainder);
// Scale the step up to [0..range]
int32_t prog = muldiv(step, range, rangeSteps, remainder);
return (uint16_t)prog;
}
} // namespace touchgfx

View File

@@ -0,0 +1,108 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/progress_indicators/BoxProgress.hpp>
namespace touchgfx
{
BoxProgress::BoxProgress()
: AbstractDirectionProgress(), box()
{
progressIndicatorContainer.add(box);
}
void BoxProgress::setProgressIndicatorPosition(int16_t x, int16_t y, int16_t width, int16_t height)
{
box.setPosition(0, 0, width, height);
AbstractProgressIndicator::setProgressIndicatorPosition(x, y, width, height);
}
void BoxProgress::setColor(colortype color)
{
box.setColor(color);
}
touchgfx::colortype BoxProgress::getColor() const
{
return box.getColor();
}
void BoxProgress::setAlpha(uint8_t newAlpha)
{
box.setAlpha(newAlpha);
}
uint8_t BoxProgress::getAlpha() const
{
return box.getAlpha();
}
void BoxProgress::setValue(int value)
{
AbstractProgressIndicator::setValue(value);
int16_t progress = 0;
switch (progressDirection)
{
case AbstractDirectionProgress::RIGHT:
case AbstractDirectionProgress::LEFT:
progress = AbstractProgressIndicator::getProgress(progressIndicatorContainer.getWidth());
break;
case AbstractDirectionProgress::DOWN:
case AbstractDirectionProgress::UP:
progress = AbstractProgressIndicator::getProgress(progressIndicatorContainer.getHeight());
break;
}
switch (progressDirection)
{
case AbstractDirectionProgress::RIGHT:
{
int16_t oldWidth = box.getWidth();
box.setPosition(0, 0, progress, progressIndicatorContainer.getHeight());
int16_t newWidth = box.getWidth();
Rect rect(MIN(oldWidth, newWidth), 0, abs(oldWidth - newWidth), box.getHeight());
progressIndicatorContainer.invalidateRect(rect);
break;
}
case AbstractDirectionProgress::LEFT:
{
int16_t oldX = box.getX();
box.setPosition(getWidth() - progress, 0, progress, progressIndicatorContainer.getHeight());
int16_t newX = box.getX();
Rect rect(MIN(oldX, newX), 0, abs(oldX - newX), box.getHeight());
progressIndicatorContainer.invalidateRect(rect);
break;
}
case AbstractDirectionProgress::DOWN:
{
int16_t oldHeight = box.getHeight();
box.setPosition(0, 0, progressIndicatorContainer.getWidth(), progress);
int16_t newHeight = box.getHeight();
Rect rect(0, MIN(oldHeight, newHeight), box.getWidth(), abs(oldHeight - newHeight));
progressIndicatorContainer.invalidateRect(rect);
break;
}
case AbstractDirectionProgress::UP:
{
int16_t oldY = box.getY();
box.setPosition(0, progressIndicatorContainer.getHeight() - progress, progressIndicatorContainer.getWidth(), progress);
int16_t newY = box.getY();
Rect rect(0, MIN(oldY, newY), box.getWidth(), abs(oldY - newY));
progressIndicatorContainer.invalidateRect(rect);
break;
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,124 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/progress_indicators/CircleProgress.hpp>
namespace touchgfx
{
CircleProgress::CircleProgress()
: AbstractProgressIndicator(), circle()
{
progressIndicatorContainer.add(circle);
circle.setPosition(0, 0, getWidth(), getHeight());
CircleProgress::setStartEndAngle(0, 360);
}
void CircleProgress::setProgressIndicatorPosition(int16_t x, int16_t y, int16_t width, int16_t height)
{
circle.setPosition(0, 0, width, height);
AbstractProgressIndicator::setProgressIndicatorPosition(x, y, width, height);
}
void CircleProgress::setPainter(AbstractPainter& painter)
{
circle.setPainter(painter);
}
void CircleProgress::setCenter(int x, int y)
{
circle.setCenter(x, y);
}
void CircleProgress::getCenter(int& x, int& y) const
{
circle.getCenter(x, y);
}
void CircleProgress::setRadius(int r)
{
circle.setRadius(r);
}
int CircleProgress::getRadius() const
{
int radius;
circle.getRadius(radius);
return radius;
}
void CircleProgress::setLineWidth(int width)
{
circle.setLineWidth(width);
}
int CircleProgress::getLineWidth() const
{
int width;
circle.getLineWidth(width);
return width;
}
void CircleProgress::setCapPrecision(int precision)
{
circle.setCapPrecision(precision);
}
void CircleProgress::setStartEndAngle(int startAngle, int endAngle)
{
assert(startAngle != endAngle);
circle.setArc(startAngle, endAngle);
circleEndAngle = endAngle;
CircleProgress::setValue(CircleProgress::getValue());
}
int CircleProgress::getStartAngle() const
{
return circle.getArcStart();
}
int CircleProgress::getEndAngle() const
{
return circleEndAngle;
}
void CircleProgress::setAlpha(uint8_t alpha)
{
circle.setAlpha(alpha);
}
uint8_t CircleProgress::getAlpha() const
{
return circle.getAlpha();
}
void CircleProgress::setValue(int value)
{
CWRUtil::Q5 startAngle;
CWRUtil::Q5 endAngle = CWRUtil::toQ5(circleEndAngle);
circle.getArcStart<CWRUtil::Q5>(startAngle);
AbstractProgressIndicator::setValue(value);
uint16_t rangeAngleSteps = endAngle < startAngle ? (int)(startAngle - endAngle) : (int)(endAngle - startAngle);
CWRUtil::Q5 progress = CWRUtil::Q5(AbstractProgressIndicator::getProgress(rangeAngleSteps));
if (endAngle < startAngle)
{
circle.updateArcEnd<CWRUtil::Q5>(startAngle - progress);
}
else
{
circle.updateArcEnd<CWRUtil::Q5>(startAngle + progress);
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,149 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/progress_indicators/ImageProgress.hpp>
namespace touchgfx
{
ImageProgress::ImageProgress()
: AbstractDirectionProgress(), image(), fixedPosition(true)
{
container.add(image);
progressIndicatorContainer.add(container);
}
void ImageProgress::setProgressIndicatorPosition(int16_t x, int16_t y, int16_t width, int16_t height)
{
container.setPosition(0, 0, width, height);
AbstractProgressIndicator::setProgressIndicatorPosition(x, y, width, height);
}
void ImageProgress::setAnchorAtZero(bool anchorAtZero)
{
fixedPosition = anchorAtZero;
setValue(getValue());
}
bool ImageProgress::getAnchorAtZero() const
{
return fixedPosition;
}
void ImageProgress::setBitmap(touchgfx::BitmapId bitmapId)
{
image.setBitmap(Bitmap(bitmapId));
}
touchgfx::BitmapId ImageProgress::getBitmap() const
{
return image.getBitmap();
}
void ImageProgress::setAlpha(uint8_t newAlpha)
{
image.setAlpha(newAlpha);
}
uint8_t ImageProgress::getAlpha() const
{
return image.getAlpha();
}
void ImageProgress::setValue(int value)
{
AbstractProgressIndicator::setValue(value);
uint16_t maxProgress = 0;
if (progressDirection == AbstractDirectionProgress::RIGHT || progressDirection == AbstractDirectionProgress::LEFT)
{
maxProgress = progressIndicatorContainer.getWidth();
}
else
{
maxProgress = progressIndicatorContainer.getHeight();
}
int16_t progress = AbstractProgressIndicator::getProgress(maxProgress);
if (fixedPosition)
{
switch (progressDirection)
{
case AbstractDirectionProgress::RIGHT:
{
int16_t oldWidth = container.getWidth();
container.setPosition(0, 0, progress, progressIndicatorContainer.getHeight());
image.setPosition(0, 0, progress, progressIndicatorContainer.getHeight());
int16_t newWidth = container.getWidth();
Rect rect(MIN(oldWidth, newWidth), 0, abs(oldWidth - newWidth), container.getHeight());
progressIndicatorContainer.invalidateRect(rect);
break;
}
case AbstractDirectionProgress::LEFT:
{
int16_t oldX = container.getX();
container.setPosition(getWidth() - progress, 0, progress, progressIndicatorContainer.getHeight());
image.setPosition(-container.getX(), 0, progressIndicatorContainer.getWidth(), progressIndicatorContainer.getHeight());
int16_t newX = container.getX();
Rect rect(MIN(oldX, newX), 0, abs(oldX - newX), container.getHeight());
progressIndicatorContainer.invalidateRect(rect);
break;
}
case AbstractDirectionProgress::DOWN:
{
int16_t oldHeight = container.getHeight();
container.setPosition(0, 0, progressIndicatorContainer.getWidth(), progress);
image.setPosition(0, 0, progressIndicatorContainer.getWidth(), progress);
int16_t newHeight = container.getHeight();
Rect rect(0, MIN(oldHeight, newHeight), container.getWidth(), abs(oldHeight - newHeight));
progressIndicatorContainer.invalidateRect(rect);
break;
}
case AbstractDirectionProgress::UP:
{
int16_t oldY = container.getY();
container.setPosition(0, progressIndicatorContainer.getHeight() - progress, progressIndicatorContainer.getWidth(), progress);
image.setPosition(0, -container.getY(), progressIndicatorContainer.getWidth(), progressIndicatorContainer.getHeight());
int16_t newY = container.getY();
Rect rect(0, MIN(oldY, newY), container.getWidth(), abs(oldY - newY));
progressIndicatorContainer.invalidateRect(rect);
break;
}
}
}
else
{
container.invalidate();
switch (progressDirection)
{
case AbstractDirectionProgress::RIGHT:
container.setPosition(0, 0, progress, getHeight());
image.setPosition(progress - progressIndicatorContainer.getWidth(), 0, progressIndicatorContainer.getWidth(), getHeight());
break;
case AbstractDirectionProgress::LEFT:
container.setPosition(progressIndicatorContainer.getWidth() - progress, 0, progress, progressIndicatorContainer.getHeight());
image.setPosition(0, 0, progress, progressIndicatorContainer.getHeight());
break;
case AbstractDirectionProgress::DOWN:
container.setPosition(0, 0, progressIndicatorContainer.getWidth(), progress);
image.setPosition(0, progress - progressIndicatorContainer.getHeight(), progressIndicatorContainer.getWidth(), progressIndicatorContainer.getHeight());
break;
case AbstractDirectionProgress::UP:
container.setPosition(0, progressIndicatorContainer.getHeight() - progress, progressIndicatorContainer.getWidth(), progress);
image.setPosition(0, 0, progressIndicatorContainer.getWidth(), progress);
break;
}
container.invalidate();
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,109 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/progress_indicators/LineProgress.hpp>
namespace touchgfx
{
LineProgress::LineProgress()
: AbstractProgressIndicator(), line(), endX(0), endY(0)
{
progressIndicatorContainer.add(line);
line.setPosition(0, 0, getWidth(), getHeight());
}
void LineProgress::setProgressIndicatorPosition(int16_t x, int16_t y, int16_t width, int16_t height)
{
line.setPosition(0, 0, width, height);
AbstractProgressIndicator::setProgressIndicatorPosition(x, y, width, height);
}
void LineProgress::setPainter(AbstractPainter& painter)
{
line.setPainter(painter);
}
void LineProgress::setStart(int x, int y)
{
startX = CWRUtil::toQ5<int>(x);
startY = CWRUtil::toQ5<int>(y);
line.setStart(x, y);
}
void LineProgress::getStart(int& x, int& y) const
{
x = startX.to<int>();
y = startY.to<int>();
}
void LineProgress::setEnd(int x, int y)
{
endX = CWRUtil::toQ5<int>(x);
endY = CWRUtil::toQ5<int>(y);
}
void LineProgress::getEnd(int& x, int& y) const
{
x = endX.to<int>();
y = endY.to<int>();
}
void LineProgress::setLineWidth(int width)
{
line.setLineWidth(width);
}
int LineProgress::getLineWidth() const
{
int width;
line.getLineWidth(width);
return width;
}
void LineProgress::setLineEndingStyle(Line::LINE_ENDING_STYLE lineEndingStyle)
{
line.setLineEndingStyle(lineEndingStyle);
}
touchgfx::Line::LINE_ENDING_STYLE LineProgress::getLineEndingStyle() const
{
return line.getLineEndingStyle();
}
void LineProgress::setAlpha(uint8_t newAlpha)
{
line.setAlpha(newAlpha);
}
uint8_t LineProgress::getAlpha() const
{
return line.getAlpha();
}
void LineProgress::setValue(int value)
{
if (rangeSteps > 0)
{
AbstractProgressIndicator::setValue(value);
int progress = (int)AbstractProgressIndicator::getProgress(rangeSteps);
CWRUtil::Q5 r(rangeSteps);
CWRUtil::Q5 p(progress);
CWRUtil::Q5 x = startX + (endX - startX) / r * p;
CWRUtil::Q5 y = startY + (endY - startY) / r * p;
line.updateEnd(x, y);
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,93 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/progress_indicators/TextProgress.hpp>
namespace touchgfx
{
TextProgress::TextProgress() :
AbstractProgressIndicator(),
textArea(),
decimals(0)
{
textBuffer[0] = 0;
progressIndicatorContainer.add(textArea);
}
void TextProgress::setProgressIndicatorPosition(int16_t x, int16_t y, int16_t width, int16_t height)
{
textArea.setPosition(0, 0, width, height);
AbstractProgressIndicator::setProgressIndicatorPosition(x, y, width, height);
}
void TextProgress::setTypedText(const TypedText& t)
{
textArea.setTypedText(t);
}
touchgfx::TypedText TextProgress::getTypedText() const
{
return textArea.getTypedText();
}
void TextProgress::setColor(colortype color)
{
textArea.setColor(color);
}
touchgfx::colortype TextProgress::getColor() const
{
return textArea.getColor();
}
void TextProgress::setAlpha(uint8_t alpha)
{
textArea.setAlpha(alpha);
}
uint8_t TextProgress::getAlpha() const
{
return textArea.getAlpha();
}
void TextProgress::setValue(int value)
{
AbstractProgressIndicator::setValue(value);
int range[3] = { 1, 10, 100 };
uint16_t progress = AbstractProgressIndicator::getProgress(100 * range[decimals]);
if (decimals > 0)
{
Unicode::snprintf(textBuffer, 8, "%d.%0*d", progress / range[decimals], decimals, progress % range[decimals]);
}
else
{
Unicode::snprintf(textBuffer, 8, "%d", progress);
}
textArea.setWildcard(textBuffer);
textArea.invalidate();
}
void TextProgress::setNumberOfDecimals(uint16_t numberOfDecimals)
{
decimals = MIN(2, numberOfDecimals);
setValue(getValue());
}
uint16_t TextProgress::getNumberOfDecimals() const
{
return decimals;
}
} // namespace touchgfx

View File

@@ -0,0 +1,385 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/scrollers/DrawableList.hpp>
namespace touchgfx
{
DrawableList::DrawableList()
: Container(),
isHorizontal(false),
isCircular(false),
offset(0),
itemSize(0),
itemMargin(0),
numItems(0),
numDrawables(0),
firstItem(0),
firstDrawable(0),
drawablesInitialized(false),
firstDrawableIndex(0),
drawableItems(0),
updateDrawable(0)
{
}
void DrawableList::setWidth(int16_t width)
{
Container::setWidth(width);
refreshDrawables();
}
void DrawableList::setHeight(int16_t height)
{
Container::setHeight(height);
refreshDrawables();
}
void DrawableList::setHorizontal(bool horizontal)
{
if ((horizontal && !isHorizontal) || (!horizontal && isHorizontal))
{
isHorizontal = horizontal;
refreshDrawables();
}
}
bool DrawableList::getHorizontal() const
{
return isHorizontal;
}
void DrawableList::setCircular(bool circular)
{
if ((circular && !isCircular) || (!circular && isCircular))
{
isCircular = circular;
refreshDrawables();
}
}
bool DrawableList::getCircular() const
{
return isCircular;
}
void DrawableList::setDrawableSize(int16_t drawableSize, int16_t drawableMargin)
{
itemSize = drawableSize + 2 * drawableMargin;
itemMargin = drawableMargin;
}
void DrawableList::setDrawables(DrawableListItemsInterface& drawableListItems,
int16_t drawableItemIndexOffset,
GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback)
{
drawableItems = &drawableListItems;
firstDrawableIndex = drawableItemIndexOffset;
updateDrawable = &updateDrawableCallback;
refreshDrawables();
}
int16_t DrawableList::getNumberOfDrawables() const
{
return numDrawables;
}
int16_t DrawableList::getItemSize() const
{
return itemSize;
}
int16_t DrawableList::getDrawableSize() const
{
return itemSize - 2 * itemMargin;
}
int16_t DrawableList::getDrawableMargin() const
{
return itemMargin;
}
void DrawableList::setNumberOfItems(int16_t numberOfItems)
{
numItems = numberOfItems;
refreshDrawables();
}
int16_t DrawableList::getNumberOfItems() const
{
return numItems;
}
int16_t DrawableList::getRequiredNumberOfDrawables() const
{
if (drawableItems == 0 || itemSize <= 0)
{
return 0;
}
// Calculate number of required drawables. Worst case is one pixel visible of drawable at top and rest stacked tightly
int16_t requiredDrawables = 1 + (((isHorizontal ? getWidth() : getHeight()) - 1) + (itemSize - 1)) / itemSize;
if (!isCircular)
{
// We never require more drawables than the number of elements on non-circular list.
if (requiredDrawables > numItems)
{
requiredDrawables = numItems;
}
}
int16_t numberOfDrawables = drawableItems->getNumberOfDrawables();
return MIN((numberOfDrawables - firstDrawableIndex), requiredDrawables);
}
void DrawableList::setOffset(int32_t ofs)
{
offset = ofs;
if (numDrawables == 0 || numItems == 0 || itemSize == 0)
{
return;
}
if (!updateDrawable || !updateDrawable->isValid())
{
return;
}
// ofs is the offset of item[0]
// 0 => item[0] is perfectly selected, -itemSize => item[1] is perfectly selected, itemSize => item[N-1] is perfectly selected etc.
int16_t newFirstItem = 0;
if (ofs > 0)
{
int numberOfItems = ofs / itemSize + 1;
newFirstItem -= numberOfItems;
ofs -= numberOfItems * itemSize;
}
if (ofs <= -itemSize)
{
int numberOfItems = ofs / itemSize;
newFirstItem -= numberOfItems;
ofs -= numberOfItems * itemSize;
}
if (isCircular)
{
// Make sure that firstIndex is "in range"
newFirstItem %= numItems;
newFirstItem = (newFirstItem + numItems) % numItems;
}
else
{
if (newFirstItem < 0)
{
ofs -= newFirstItem * itemSize;
newFirstItem = 0;
}
else if (newFirstItem + numDrawables > numItems)
{
int x = numItems - (newFirstItem + numDrawables);
ofs += x * itemSize;
newFirstItem += x;
}
}
int drawableDelta = 0;
if (drawablesInitialized && firstItem != newFirstItem)
{
drawableDelta = numDrawables;
for (int i = 1; i < numDrawables; i++)
{
int fi = (firstItem + i);
int nfi = (newFirstItem + i);
if (isCircular)
{
fi %= numItems;
nfi %= numItems;
}
if (fi == newFirstItem)
{
drawableDelta = -i;
break;
}
if (nfi == firstItem)
{
drawableDelta = i;
break;
}
}
}
firstDrawable = ((firstDrawable - drawableDelta) + numDrawables) % numDrawables;
firstItem = newFirstItem;
for (int i = 0; i < numDrawables; i++)
{
int drawableIndex = (firstDrawable + i) % numDrawables;
Drawable* drawable = drawableItems->getDrawable(drawableIndex + firstDrawableIndex);
if (isHorizontal)
{
drawable->moveTo(ofs + i * itemSize + itemMargin, 0);
}
else
{
drawable->moveTo(0, ofs + i * itemSize + itemMargin);
}
int itemIndex = i + firstItem;
if (isCircular)
{
itemIndex %= numItems;
}
else
{
if (itemIndex < 0 || itemIndex >= numItems)
{
itemIndex = -1;
}
}
if (itemIndex < 0)
{
drawable->setVisible(false);
}
else
{
drawable->setVisible(true);
// Only fill if first time or outside old range
if (!drawablesInitialized || (i < drawableDelta || i >= numDrawables + drawableDelta))
{
if (updateDrawable->isValid())
{
updateDrawable->execute(drawableItems, drawableIndex + firstDrawableIndex, itemIndex);
drawable->invalidate();
}
}
}
}
drawablesInitialized = true;
}
int32_t DrawableList::getOffset() const
{
return offset;
}
int16_t DrawableList::getItemIndex(int16_t drawableIndex) const
{
if (drawableIndex < 0 || drawableIndex >= numDrawables || numDrawables == 0 || numItems == 0)
{
return -1;
}
int16_t itemNumber = ((drawableIndex + numDrawables - firstDrawable) % numDrawables) + firstItem;
if (isCircular)
{
itemNumber %= numItems;
}
if (itemNumber < 0 || itemNumber >= numItems)
{
return -1;
}
return itemNumber;
}
int16_t DrawableList::getDrawableIndices(int16_t itemIndex, int16_t* drawableIndexArray, int16_t arraySize) const
{
int16_t numFound = 0;
int16_t drawableIndex = -1;
while ((drawableIndex = getDrawableIndex(itemIndex, drawableIndex)) >= 0)
{
if (numFound < arraySize)
{
drawableIndexArray[numFound] = drawableIndex;
numFound++;
}
}
return numFound;
}
int16_t DrawableList::getDrawableIndex(int16_t itemIndex, int16_t prevDrawableIndex /*= -1*/) const
{
if (prevDrawableIndex < -1 || prevDrawableIndex >= numDrawables || numDrawables == 0 || numItems == 0)
{
return -1;
}
if (prevDrawableIndex >= 0)
{
prevDrawableIndex = (prevDrawableIndex - firstDrawable + numDrawables) % numDrawables;
}
for (int16_t i = prevDrawableIndex + 1; i < numDrawables; i++)
{
int16_t currentItemIndex = firstItem + i;
if (isCircular)
{
currentItemIndex %= numItems;
}
if (itemIndex == currentItemIndex)
{
int16_t drawableIndex = (firstDrawable + i) % numDrawables;
return drawableIndex;
}
}
return -1;
}
void DrawableList::refreshDrawables()
{
numDrawables = 0;
if (drawableItems == 0)
{
return;
}
numDrawables = getRequiredNumberOfDrawables();
// Remove everything
Container::removeAll();
// Add the itemDrawables
for (int drawableIndex = 0; drawableIndex < numDrawables; drawableIndex++)
{
Drawable* drawable = drawableItems->getDrawable(drawableIndex + firstDrawableIndex);
// Resize the drawables, X/Y ignored for now.
if (isHorizontal)
{
drawable->setPosition(0, 0, itemSize - 2 * itemMargin, getHeight());
}
else
{
drawable->setPosition(0, 0, getWidth(), itemSize - 2 * itemMargin);
}
// Add each drawable for later positioning
if (drawable->getParent() != 0)
{
// Remove drawable from the current parent
Container* parent = static_cast<Container*>(drawable->getParent());
parent->remove(*drawable);
}
Container::add(*drawable);
}
drawablesInitialized = false;
firstItem = 0;
firstDrawable = 0;
setOffset(offset);
}
void DrawableList::itemChanged(int16_t itemIndex)
{
if (updateDrawable && updateDrawable->isValid())
{
int16_t drawableIndex = -1;
while ((drawableIndex = getDrawableIndex(itemIndex, drawableIndex)) != -1)
{
updateDrawable->execute(drawableItems, drawableIndex + firstDrawableIndex, itemIndex);
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,336 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/scrollers/ScrollBase.hpp>
namespace touchgfx
{
ScrollBase::ScrollBase()
: Container(),
numberOfDrawables(0),
distanceBeforeAlignedItem(0),
itemSize(0),
swipeAcceleration(10),
dragAcceleration(10),
maxSwipeItems(0),
easingEquation(&EasingEquations::backEaseOut),
defaultAnimationSteps(30),
itemSelectedCallback(0),
itemLockedInCallback(0),
animationEndedCallback(0),
itemPressedCallback(0),
currentAnimationState(NO_ANIMATION),
gestureStep(0),
gestureStepsTotal(0),
gestureStart(0),
gestureEnd(0),
xClick(0),
yClick(0),
initialSwipeOffset(0),
draggableX(false),
draggableY(false)
{
Container::add(list);
list.setXY(0, 0);
list.setHorizontal(false);
list.setCircular(false);
setTouchable(true);
}
void ScrollBase::setWidth(int16_t width)
{
Container::setWidth(width);
list.setWidth(width);
}
void ScrollBase::setHeight(int16_t height)
{
Container::setHeight(height);
list.setHeight(height);
}
void ScrollBase::setHorizontal(bool horizontal)
{
allowVerticalDrag(horizontal);
allowHorizontalDrag(!horizontal);
list.setHorizontal(horizontal);
}
bool ScrollBase::getHorizontal() const
{
return list.getHorizontal();
}
void ScrollBase::setCircular(bool circular)
{
list.setCircular(circular);
}
bool ScrollBase::getCircular() const
{
return list.getCircular();
}
void ScrollBase::setDrawableSize(int16_t drawableSize, int16_t drawableMargin)
{
itemSize = drawableSize + drawableMargin * 2;
list.setDrawableSize(drawableSize, drawableMargin);
}
int16_t ScrollBase::getDrawableSize() const
{
return list.getDrawableSize();
}
int16_t ScrollBase::getDrawableMargin() const
{
return list.getDrawableMargin();
}
void ScrollBase::setNumberOfItems(int16_t numberOfItems)
{
if (numberOfItems != getNumberOfItems())
{
list.setNumberOfItems(numberOfItems);
if (!getCircular())
{
animateToPosition(keepOffsetInsideLimits(getOffset(), 0));
}
}
}
int16_t ScrollBase::getNumberOfItems() const
{
return list.getNumberOfItems();
}
void ScrollBase::setEasingEquation(EasingEquation equation)
{
easingEquation = equation;
}
void ScrollBase::setAnimationSteps(int16_t steps)
{
defaultAnimationSteps = steps;
}
uint16_t ScrollBase::getAnimationSteps() const
{
return defaultAnimationSteps;
}
void ScrollBase::setSwipeAcceleration(uint16_t acceleration)
{
swipeAcceleration = acceleration;
}
uint16_t ScrollBase::getSwipeAcceleration() const
{
return swipeAcceleration;
}
void ScrollBase::setMaxSwipeItems(uint16_t maxItems)
{
maxSwipeItems = maxItems;
}
uint16_t ScrollBase::getMaxSwipeItems() const
{
return maxSwipeItems;
}
void ScrollBase::setDragAcceleration(uint16_t acceleration)
{
dragAcceleration = acceleration;
}
uint16_t ScrollBase::getDragAcceleration() const
{
return dragAcceleration;
}
void ScrollBase::allowHorizontalDrag(bool enable)
{
draggableX = enable;
}
void ScrollBase::allowVerticalDrag(bool enable)
{
draggableY = enable;
}
void ScrollBase::animateToItem(int16_t itemIndex, int16_t animationSteps /*= -1*/)
{
int32_t position = getPositionForItem(itemIndex);
animateToPosition(position, animationSteps);
}
void ScrollBase::setItemSelectedCallback(GenericCallback<int16_t>& callback)
{
itemSelectedCallback = &callback;
}
void ScrollBase::setAnimationEndedCallback(GenericCallback<>& callback)
{
animationEndedCallback = &callback;
}
void ScrollBase::setItemPressedCallback(GenericCallback<int16_t>& callback)
{
itemPressedCallback = &callback;
}
bool ScrollBase::isAnimating() const
{
return currentAnimationState != NO_ANIMATION;
}
void ScrollBase::stopAnimation()
{
if (currentAnimationState == ANIMATING_GESTURE)
{
Application::getInstance()->unregisterTimerWidget(this);
setOffset(gestureEnd);
}
currentAnimationState = NO_ANIMATION;
}
void ScrollBase::handleDragEvent(const DragEvent& evt)
{
stopAnimation();
currentAnimationState = ANIMATING_DRAG;
int32_t newOffset = getOffset() + (getHorizontal() ? evt.getDeltaX() : evt.getDeltaY()) * dragAcceleration / 10;
newOffset = keepOffsetInsideLimits(newOffset, itemSize * 3 / 4);
setOffset(newOffset);
}
void ScrollBase::handleGestureEvent(const GestureEvent& evt)
{
if (evt.getType() == (getHorizontal() ? GestureEvent::SWIPE_HORIZONTAL : GestureEvent::SWIPE_VERTICAL))
{
int16_t velocity = abs(evt.getVelocity());
int16_t direction = evt.getVelocity() < 0 ? -1 : 1;
int16_t steps = MAX(1, velocity - 4) * 7;
int32_t newOffset = getOffset() + direction * steps * swipeAcceleration / 10;
if (maxSwipeItems > 0)
{
int32_t maxDistance = maxSwipeItems * itemSize;
newOffset = MIN(newOffset, initialSwipeOffset + maxDistance);
newOffset = MAX(newOffset, initialSwipeOffset - maxDistance);
}
newOffset = keepOffsetInsideLimits(newOffset, 0);
steps = MIN(steps, defaultAnimationSteps);
animateToPosition(newOffset, steps);
}
}
void ScrollBase::handleTickEvent()
{
if (currentAnimationState == ANIMATING_GESTURE)
{
gestureStep++;
int newPosition = gestureStart + easingEquation(gestureStep, 0, gestureEnd - gestureStart, gestureStepsTotal);
setOffset(newPosition);
if (gestureStep > gestureStepsTotal)
{
currentAnimationState = NO_ANIMATION;
gestureStep = 0;
Application::getInstance()->unregisterTimerWidget(this);
setOffset(getNormalizedOffset(gestureEnd));
// Also adjust initialSwipeOffset in case it is being used.
initialSwipeOffset += getOffset() - gestureEnd;
//Item has settled, call back
if (animationEndedCallback && animationEndedCallback->isValid())
{
animationEndedCallback->execute();
}
}
}
}
void ScrollBase::itemChanged(int itemIndex)
{
list.itemChanged(itemIndex);
}
void ScrollBase::setOffset(int32_t offset)
{
list.setOffset(offset + distanceBeforeAlignedItem);
}
int32_t ScrollBase::getOffset() const
{
return list.getOffset() - distanceBeforeAlignedItem;
}
int ScrollBase::getNormalizedOffset(int offset) const
{
int16_t numItems = getNumberOfItems();
if (numItems == 0 || itemSize == 0)
{
return offset;
}
int32_t listSize = numItems * itemSize;
offset %= listSize;
return offset > 0 ? offset - listSize : offset;
}
int32_t ScrollBase::getNearestAlignedOffset(int32_t offset) const
{
if (itemSize == 0)
{
return offset;
}
if (getCircular())
{
if (offset < 0)
{
return (((offset - (itemSize / 2)) / itemSize) * itemSize);
}
return ((offset + (itemSize / 2)) / itemSize) * itemSize;
}
offset = keepOffsetInsideLimits(offset, 0);
return ((offset - (itemSize / 2)) / itemSize) * itemSize;
}
void ScrollBase::animateToPosition(int32_t position, int16_t steps)
{
int32_t currentPosition = getOffset();
position = getNearestAlignedOffset(position);
if (steps < 0)
{
steps = defaultAnimationSteps;
}
steps = MIN(steps, abs(position - currentPosition));
if (steps < 1)
{
setOffset(position);
currentAnimationState = NO_ANIMATION;
}
else
{
gestureStart = currentPosition;
gestureEnd = position;
gestureStep = 0;
gestureStepsTotal = steps;
if (currentAnimationState != ANIMATING_GESTURE)
{
Application::getInstance()->registerTimerWidget(this);
currentAnimationState = ANIMATING_GESTURE;
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,231 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/scrollers/ScrollList.hpp>
namespace touchgfx
{
ScrollList::ScrollList()
: ScrollBase(),
paddingAfterLastItem(0),
snapping(false),
windowSize(1)
{
}
void ScrollList::setDrawables(DrawableListItemsInterface& drawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback)
{
stopAnimation();
numberOfDrawables = drawableListItems.getNumberOfDrawables();
list.setDrawables(drawableListItems, 0, updateDrawableCallback);
setOffset(0);
}
void ScrollList::setWindowSize(int16_t items)
{
windowSize = MAX(1, items);
animateToPosition(keepOffsetInsideLimits(getOffset(), 0));
}
void ScrollList::setPadding(int16_t paddingBefore, int16_t paddingAfter)
{
int32_t currentOffset = getOffset();
distanceBeforeAlignedItem = paddingBefore;
paddingAfterLastItem = paddingAfter;
setOffset(currentOffset);
list.refreshDrawables();
}
int16_t ScrollList::getPaddingBefore() const
{
return distanceBeforeAlignedItem;
}
int16_t ScrollList::getPaddingAfter() const
{
return paddingAfterLastItem;
}
void ScrollList::setSnapping(bool snap)
{
snapping = snap;
if (snapping)
{
setOffset(getNearestAlignedOffset(getOffset()));
}
}
bool ScrollList::getSnapping() const
{
return snapping;
}
int32_t ScrollList::getPositionForItem(int16_t itemIndex)
{
int32_t currentOffset = getNormalizedOffset(getOffset());
if (itemIndex < 0 || itemIndex >= list.getNumberOfItems() || itemSize == 0)
{
return currentOffset;
}
int32_t itemOffset = -itemIndex * itemSize;
// Get the visible size
int16_t widgetSize = getHorizontal() ? getWidth() : getHeight();
int16_t activeWidgetSize = widgetSize - (distanceBeforeAlignedItem + paddingAfterLastItem);
if (list.getCircular())
{
int32_t offset = currentOffset;
// Important this is a do-while of visibleSize < itemSize in which case we need to check at least one time
do
{
int16_t i = (-getNormalizedOffset(offset)) / itemSize; // Item index of first
if (itemIndex == i)
{
return currentOffset;
}
offset -= itemSize;
}
while (offset >= currentOffset - (activeWidgetSize - itemSize));
int32_t allItemsSize = list.getNumberOfItems() * itemSize;
// Either scroll left from the first item or right from the last item. Find out which is closest
int32_t leftScrollDistance = itemOffset - currentOffset;
int32_t leftScrollDistance2 = (itemOffset + allItemsSize) - currentOffset;
int32_t rightItemOffset = getNormalizedOffset(currentOffset - (activeWidgetSize - itemSize));
int32_t rightScrollDistance = rightItemOffset - itemOffset;
int32_t rightScrollDistance2 = rightItemOffset - (itemOffset - allItemsSize);
if (abs(leftScrollDistance2) < abs(leftScrollDistance))
{
leftScrollDistance = leftScrollDistance2;
}
if (abs(rightScrollDistance2) < abs(rightScrollDistance))
{
rightScrollDistance = rightScrollDistance2;
}
if (abs(rightScrollDistance) < abs(leftScrollDistance))
{
return currentOffset - rightScrollDistance;
}
return currentOffset + leftScrollDistance;
}
else
{
if (itemOffset > currentOffset) // First item on screen is higher than the itemIndex. Scroll itemIndex to top position
{
return itemOffset;
}
int16_t numberOfVisibleItems = activeWidgetSize / itemSize;
int32_t itemOffsetAtEnd = itemOffset;
if (numberOfVisibleItems > 0)
{
if (snapping)
{
itemOffsetAtEnd = itemOffset + (numberOfVisibleItems - 1) * itemSize;
}
else
{
itemOffsetAtEnd = itemOffset + activeWidgetSize - itemSize;
}
}
if (itemOffsetAtEnd < currentOffset)
{
return itemOffsetAtEnd;
}
}
return currentOffset;
}
void ScrollList::handleClickEvent(const ClickEvent& evt)
{
ScrollBase::handleClickEvent(evt);
if (evt.getType() == ClickEvent::PRESSED)
{
xClick = evt.getX();
yClick = evt.getY();
initialSwipeOffset = getOffset();
setOffset(getNearestAlignedOffset(initialSwipeOffset));
if (itemPressedCallback && itemPressedCallback->isValid())
{
int16_t click = (getHorizontal() ? xClick : yClick);
int32_t offset = click - getOffset();
int32_t listSize = getNumberOfItems() * itemSize;
if (getCircular())
{
offset += listSize;
offset %= listSize;
}
if (offset >= 0 && offset < listSize)
{
int16_t item = offset / itemSize;
itemPressedCallback->execute(item);
}
}
}
else if (evt.getType() == ClickEvent::RELEASED)
{
if (currentAnimationState == NO_ANIMATION)
{
// For a tiny drag, start by re-aligning (no animation(!))
setOffset(getNearestAlignedOffset(getOffset()));
if (itemSelectedCallback && itemSelectedCallback->isValid())
{
int16_t click = (getHorizontal() ? xClick : yClick);
int32_t offset = click - getOffset();
int32_t listSize = getNumberOfItems() * itemSize;
if (getCircular())
{
offset += listSize;
offset %= listSize;
}
else
{
offset -= distanceBeforeAlignedItem;
}
if (offset >= 0 && offset < listSize)
{
int16_t item = offset / itemSize;
itemSelectedCallback->execute(item);
}
}
}
else if (currentAnimationState == ANIMATING_DRAG)
{
// click + drag + release. Find best Y to scroll to
animateToPosition(getNearestAlignedOffset(getOffset()));
}
}
}
int32_t ScrollList::getNearestAlignedOffset(int32_t offset) const
{
if (snapping)
{
// ScrollBase implementation will snap
return ScrollBase::getNearestAlignedOffset(offset);
}
return keepOffsetInsideLimits(offset, 0);
}
int32_t ScrollList::keepOffsetInsideLimits(int32_t newOffset, int16_t overShoot) const
{
if (!getCircular())
{
newOffset = MIN(newOffset, overShoot);
int maxOffToTheStart = windowSize < getNumberOfItems() ? getNumberOfItems() - windowSize : 0;
newOffset = MAX(newOffset, -(itemSize * maxOffToTheStart) - overShoot);
}
return newOffset;
}
} // namespace touchgfx

View File

@@ -0,0 +1,29 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/scrollers/ScrollWheel.hpp>
namespace touchgfx
{
void ScrollWheel::setDrawables(DrawableListItemsInterface& drawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback)
{
stopAnimation();
numberOfDrawables = drawableListItems.getNumberOfDrawables();
list.setDrawables(drawableListItems, 0, updateDrawableCallback);
setOffset(0);
}
} // namespace touchgfx

View File

@@ -0,0 +1,178 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/scrollers/ScrollWheelBase.hpp>
namespace touchgfx
{
ScrollWheelBase::ScrollWheelBase()
: ScrollBase(),
animateToCallback(0)
{
ScrollWheelBase::setHorizontal(false);
setTouchable(true);
}
void ScrollWheelBase::setSelectedItemOffset(int16_t offset)
{
int32_t currentOffset = getOffset();
distanceBeforeAlignedItem = offset;
setOffset(currentOffset);
}
int16_t ScrollWheelBase::getSelectedItemOffset() const
{
return distanceBeforeAlignedItem;
}
int32_t ScrollWheelBase::getPositionForItem(int16_t itemIndex)
{
int32_t newOffset = -itemIndex * itemSize;
if (getCircular())
{
// Check if it is closer to scroll backwards
int32_t otherOffset = newOffset + getNumberOfItems() * itemSize;
int32_t offset = getOffset();
if (abs(otherOffset - offset) < abs(newOffset - offset))
{
newOffset = otherOffset;
}
}
return newOffset;
}
void ScrollWheelBase::animateToPosition(int32_t position, int16_t steps)
{
if (itemSize == 0)
{
return;
}
if (animateToCallback && animateToCallback->isValid() && itemSize > 0)
{
position = getNearestAlignedOffset(position);
int16_t itemIndex = (-position) / itemSize;
animateToCallback->execute(itemIndex);
}
ScrollBase::animateToPosition(position, steps);
}
int ScrollWheelBase::getSelectedItem() const
{
if (itemSize == 0)
{
return 0;
}
if (currentAnimationState == ANIMATING_GESTURE)
{
// Scroll in progress, get the destination value
return (-getNormalizedOffset(gestureEnd)) / itemSize;
}
return (-getNormalizedOffset(getOffset())) / itemSize;
}
int32_t ScrollWheelBase::keepOffsetInsideLimits(int32_t newOffset, int16_t overShoot) const
{
if (!getCircular())
{
newOffset = MIN(newOffset, overShoot);
int16_t numberOfItems = getNumberOfItems();
newOffset = MAX(newOffset, -(itemSize * (numberOfItems - 1)) - overShoot);
}
return newOffset;
}
void ScrollWheelBase::handleClickEvent(const ClickEvent& evt)
{
if (itemSize == 0)
{
return;
}
int32_t offset = getOffset();
if (evt.getType() == ClickEvent::PRESSED)
{
xClick = evt.getX();
yClick = evt.getY();
initialSwipeOffset = offset;
if (itemPressedCallback && itemPressedCallback->isValid())
{
itemPressedCallback->execute(getSelectedItem());
}
}
else if (evt.getType() == ClickEvent::RELEASED)
{
if (currentAnimationState == NO_ANIMATION)
{
int16_t click = getHorizontal() ? xClick : yClick;
// Click => move to clicked position
if (click < distanceBeforeAlignedItem)
{
animateToPosition(offset + ((distanceBeforeAlignedItem - click) / itemSize + 1) * itemSize);
}
else if (click > distanceBeforeAlignedItem + itemSize)
{
animateToPosition(offset - ((click - distanceBeforeAlignedItem) / itemSize) * itemSize);
}
else
{
animateToPosition(offset);
}
}
else if (currentAnimationState == ANIMATING_DRAG)
{
// click + drag + release. Find best Y to scroll to
animateToPosition(offset);
}
if (itemSelectedCallback && itemSelectedCallback->isValid())
{
itemSelectedCallback->execute(getSelectedItem());
}
}
}
void ScrollWheelBase::handleDragEvent(const DragEvent& evt)
{
currentAnimationState = ANIMATING_DRAG;
int newOffset = getOffset() + (getHorizontal() ? evt.getDeltaX() : evt.getDeltaY()) * dragAcceleration / 10;
if (!getCircular())
{
newOffset = MIN(newOffset, itemSize * 3 / 4);
int16_t numberOfItems = getNumberOfItems();
newOffset = MAX(newOffset, -(itemSize * (numberOfItems - 1)) - itemSize * 3 / 4);
}
setOffset(newOffset);
}
void ScrollWheelBase::handleGestureEvent(const GestureEvent& evt)
{
if (evt.getType() == (getHorizontal() ? GestureEvent::SWIPE_HORIZONTAL : GestureEvent::SWIPE_VERTICAL))
{
int32_t newOffset = getOffset() + evt.getVelocity() * swipeAcceleration / 10;
if (maxSwipeItems > 0)
{
int32_t maxDistance = maxSwipeItems * itemSize;
newOffset = MIN(newOffset, initialSwipeOffset + maxDistance);
newOffset = MAX(newOffset, initialSwipeOffset - maxDistance);
}
animateToPosition(newOffset);
}
}
void ScrollWheelBase::setAnimateToCallback(GenericCallback<int16_t>& callback)
{
animateToCallback = &callback;
}
} // namespace touchgfx

View File

@@ -0,0 +1,203 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/containers/scrollers/ScrollWheelWithSelectionStyle.hpp>
namespace touchgfx
{
ScrollWheelWithSelectionStyle::ScrollWheelWithSelectionStyle()
: ScrollWheelBase(),
drawablesInFirstList(0),
extraSizeBeforeSelectedItem(0),
extraSizeAfterSelectedItem(0),
marginBeforeSelectedItem(0),
marginAfterSelectedItem(0),
drawables(0),
centerDrawables(0),
originalUpdateDrawableCallback(0),
originalUpdateCenterDrawableCallback(0)
{
ScrollWheelBase::add(list2);
ScrollWheelBase::add(list1); // Put center list at top of the first/last list.
}
void ScrollWheelWithSelectionStyle::setWidth(int16_t width)
{
ScrollWheelBase::setWidth(width);
if (getHorizontal())
{
refreshDrawableListsLayout();
}
}
void ScrollWheelWithSelectionStyle::setHeight(int16_t height)
{
ScrollWheelBase::setHeight(height);
if (!getHorizontal())
{
refreshDrawableListsLayout();
}
}
void ScrollWheelWithSelectionStyle::setHorizontal(bool horizontal)
{
ScrollWheelBase::setHorizontal(horizontal);
list1.setHorizontal(horizontal);
list2.setHorizontal(horizontal);
refreshDrawableListsLayout();
}
void ScrollWheelWithSelectionStyle::setCircular(bool circular)
{
ScrollWheelBase::setCircular(circular);
list1.setCircular(circular);
list2.setCircular(circular);
}
void ScrollWheelWithSelectionStyle::setNumberOfItems(int16_t numberOfItems)
{
if (numberOfItems != getNumberOfItems())
{
ScrollWheelBase::setNumberOfItems(numberOfItems);
list1.setNumberOfItems(numberOfItems);
list2.setNumberOfItems(numberOfItems);
}
}
void ScrollWheelWithSelectionStyle::setSelectedItemOffset(int16_t offset)
{
ScrollWheelBase::setSelectedItemOffset(offset);
refreshDrawableListsLayout();
}
void ScrollWheelWithSelectionStyle::setSelectedItemExtraSize(int16_t extraSizeBefore, int16_t extraSizeAfter)
{
extraSizeBeforeSelectedItem = extraSizeBefore;
extraSizeAfterSelectedItem = extraSizeAfter;
refreshDrawableListsLayout();
}
int16_t ScrollWheelWithSelectionStyle::getSelectedItemExtraSizeBefore() const
{
return extraSizeBeforeSelectedItem;
}
int16_t ScrollWheelWithSelectionStyle::getSelectedItemExtraSizeAfter() const
{
return extraSizeAfterSelectedItem;
}
void ScrollWheelWithSelectionStyle::setSelectedItemMargin(int16_t marginBefore, int16_t marginAfter)
{
marginBeforeSelectedItem = marginBefore;
marginAfterSelectedItem = marginAfter;
refreshDrawableListsLayout();
}
int16_t ScrollWheelWithSelectionStyle::getSelectedItemMarginBefore() const
{
return marginBeforeSelectedItem;
}
int16_t ScrollWheelWithSelectionStyle::getSelectedItemMarginAfter() const
{
return marginAfterSelectedItem;
}
void ScrollWheelWithSelectionStyle::setSelectedItemPosition(int16_t offset, int16_t extraSizeBefore, int16_t extraSizeAfter, int16_t marginBefore, int16_t marginAfter)
{
setSelectedItemOffset(offset);
setSelectedItemExtraSize(extraSizeBefore, extraSizeAfter);
setSelectedItemMargin(marginBefore, marginAfter);
}
void ScrollWheelWithSelectionStyle::setDrawableSize(int16_t drawableSize, int16_t drawableMargin)
{
ScrollWheelBase::setDrawableSize(drawableSize, drawableMargin);
list1.setDrawableSize(drawableSize, drawableMargin);
list2.setDrawableSize(drawableSize, drawableMargin);
// Resize the three lists
setSelectedItemOffset(distanceBeforeAlignedItem);
// Changing the drawable size alters number of required drawables, so refresh this
refreshDrawableListsLayout();
}
void ScrollWheelWithSelectionStyle::setDrawables(DrawableListItemsInterface& drawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback,
DrawableListItemsInterface& centerDrawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateCenterDrawableCallback)
{
drawables = &drawableListItems;
centerDrawables = &centerDrawableListItems;
currentAnimationState = NO_ANIMATION;
originalUpdateDrawableCallback = &updateDrawableCallback;
originalUpdateCenterDrawableCallback = &updateCenterDrawableCallback;
refreshDrawableListsLayout();
setOffset(0);
}
void ScrollWheelWithSelectionStyle::setOffset(int32_t offset)
{
ScrollWheelBase::setOffset(offset);
list1.setOffset((distanceBeforeAlignedItem - (distanceBeforeAlignedItem - extraSizeBeforeSelectedItem)) + offset);
list2.setOffset((distanceBeforeAlignedItem - (distanceBeforeAlignedItem + itemSize + extraSizeAfterSelectedItem + marginAfterSelectedItem)) + offset);
}
void ScrollWheelWithSelectionStyle::itemChanged(int itemIndex)
{
ScrollWheelBase::itemChanged(itemIndex);
list1.itemChanged(itemIndex);
list2.itemChanged(itemIndex);
}
void ScrollWheelWithSelectionStyle::refreshDrawableListsLayout()
{
if (drawables != 0 && centerDrawables != 0)
{
int32_t currentOffset = getOffset();
int16_t list1Pos = distanceBeforeAlignedItem - extraSizeBeforeSelectedItem;
int16_t list2Pos = distanceBeforeAlignedItem + itemSize + (extraSizeAfterSelectedItem + marginAfterSelectedItem);
int16_t list0Size = list1Pos - marginBeforeSelectedItem;
int16_t list1Size = itemSize + extraSizeBeforeSelectedItem + extraSizeAfterSelectedItem;
if (getHorizontal())
{
int16_t list2Size = getWidth() - list2Pos;
list.setPosition(0, 0, list0Size, getHeight());
list1.setPosition(list1Pos, 0, list1Size, getHeight());
list2.setPosition(list2Pos, 0, list2Size, getHeight());
}
else
{
int16_t list2Size = getHeight() - list2Pos;
list.setPosition(0, 0, getWidth(), list0Size);
list1.setPosition(0, list1Pos, getWidth(), list1Size);
list2.setPosition(0, list2Pos, getWidth(), list2Size);
}
list.setDrawables(*drawables, 0, *originalUpdateDrawableCallback);
drawablesInFirstList = list.getNumberOfDrawables();
list1.setDrawables(*centerDrawables, 0, *originalUpdateCenterDrawableCallback);
list2.setDrawables(*drawables, drawablesInFirstList, *originalUpdateDrawableCallback);
setOffset(keepOffsetInsideLimits(currentOffset, 0));
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,38 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/AbstractButton.hpp>
namespace touchgfx
{
void AbstractButton::handleClickEvent(const ClickEvent& event)
{
bool wasPressed = pressed;
pressed = (event.getType() == ClickEvent::PRESSED);
if ((pressed && !wasPressed) || (!pressed && wasPressed))
{
// Pressed state changed, so invalidate
invalidate();
}
if (wasPressed && (event.getType() == ClickEvent::RELEASED) && action)
{
// This is a click. Fire callback.
if (action->isValid())
{
action->execute(*this);
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,140 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/AnimatedImage.hpp>
namespace touchgfx
{
void AnimatedImage::handleTickEvent()
{
if (running)
{
++ticksSinceUpdate;
if (ticksSinceUpdate != updateTicksInterval)
{
return;
}
ticksSinceUpdate = 0;
BitmapId currentId = getBitmap();
if (((currentId == endId) && !reverse) || ((currentId == startId) && reverse))
{
if (!loopAnimation)
{
Application::getInstance()->unregisterTimerWidget(this);
running = false;
}
if (animationDoneAction && animationDoneAction->isValid())
{
animationDoneAction->execute(*this);
}
if (running && loopAnimation)
{
if (reverse)
{
Image::setBitmap(Bitmap(endId));
}
else
{
Image::setBitmap(Bitmap(startId));
}
invalidate();
}
}
else
{
if (reverse)
{
--currentId;
}
else
{
++currentId;
}
Image::setBitmap(Bitmap(currentId));
invalidate();
}
}
}
void AnimatedImage::startAnimation(const bool& rev, const bool& reset, const bool& loop)
{
if ((startId != BITMAP_INVALID) && (endId != BITMAP_INVALID))
{
reverse = rev;
loopAnimation = loop;
if (reverse && reset)
{
Image::setBitmap(Bitmap(endId));
invalidate();
}
else if (!reverse && reset)
{
Image::setBitmap(Bitmap(startId));
invalidate();
}
Application::getInstance()->registerTimerWidget(this);
running = true;
}
}
void AnimatedImage::stopAnimation()
{
if (running)
{
Application::getInstance()->unregisterTimerWidget(this);
running = false;
}
if (reverse)
{
Image::setBitmap(Bitmap(endId));
}
else
{
Image::setBitmap(Bitmap(startId));
}
invalidate();
}
void AnimatedImage::pauseAnimation()
{
if (running)
{
Application::getInstance()->unregisterTimerWidget(this);
running = false;
}
else
{
Application::getInstance()->registerTimerWidget(this);
running = true;
}
}
void AnimatedImage::setBitmaps(BitmapId start, BitmapId end)
{
startId = start;
endId = end;
Image::setBitmap(Bitmap(startId));
}
void AnimatedImage::setUpdateTicksInterval(uint8_t updateInterval)
{
updateTicksInterval = updateInterval;
ticksSinceUpdate = 0;
}
} // namespace touchgfx

View File

@@ -0,0 +1,182 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/AnimationTextureMapper.hpp>
namespace touchgfx
{
AnimationTextureMapper::AnimationTextureMapper() :
TextureMapper(),
textureMapperAnimationStepCallback(0),
textureMapperAnimationEndedCallback(0),
animationCounter(0),
animationRunning(false)
{
for (int i = 0; i < NUMBER_OF_ANIMATION_PARAMETERS; i++)
{
animations[i].animationActive = false;
}
}
void AnimationTextureMapper::setTextureMapperAnimationStepAction(GenericCallback<const AnimationTextureMapper&>& callback)
{
textureMapperAnimationStepCallback = &callback;
}
void AnimationTextureMapper::setTextureMapperAnimationEndedAction(GenericCallback<const AnimationTextureMapper&>& callback)
{
textureMapperAnimationEndedCallback = &callback;
}
bool AnimationTextureMapper::isTextureMapperAnimationRunning() const
{
return animationRunning;
}
void AnimationTextureMapper::setupAnimation(AnimationParameter parameter, float endValue, uint16_t duration, uint16_t delay, EasingEquation progressionEquation /*= &EasingEquations::linearEaseNone*/)
{
animations[parameter].animationActive = true;
animations[parameter].animationEnd = endValue;
animations[parameter].animationDuration = duration;
animations[parameter].animationDelay = delay;
animations[parameter].animationProgressionEquation = progressionEquation;
}
void AnimationTextureMapper::startAnimation()
{
Application::getInstance()->registerTimerWidget(this);
animationCounter = 0;
animations[X_ROTATION].animationStart = xAngle;
animations[Y_ROTATION].animationStart = yAngle;
animations[Z_ROTATION].animationStart = zAngle;
animations[SCALE].animationStart = scale;
animationRunning = true;
}
void AnimationTextureMapper::cancelAnimationTextureMapperAnimation()
{
Application::getInstance()->unregisterTimerWidget(this);
animationRunning = false;
for (int i = 0; i < NUMBER_OF_ANIMATION_PARAMETERS; i++)
{
animations[i].animationActive = false;
}
}
uint16_t AnimationTextureMapper::getAnimationStep()
{
return animationCounter;
}
void AnimationTextureMapper::handleTickEvent()
{
if (animationRunning)
{
AnimationState activeAnimation = ANIMATION_FINISHED;
float newXAngle = xAngle;
float newYAngle = yAngle;
float newZAngle = zAngle;
float newScale = scale;
for (int i = 0; i < NUMBER_OF_ANIMATION_PARAMETERS; i++)
{
if (!(animations[i].animationActive))
{
continue;
}
if (animationCounter < animations[i].animationDelay && activeAnimation < ANIMATION_DELAYED)
{
activeAnimation = ANIMATION_DELAYED;
}
if ((animationCounter >= animations[i].animationDelay) &&
(animationCounter <= (uint32_t)(animations[i].animationDelay + animations[i].animationDuration)))
{
activeAnimation = ANIMATION_RUNNING;
// Adjust the used animationCounter for the startup delay
uint32_t actualAnimationCounter = animationCounter - animations[i].animationDelay;
int directionModifier;
int16_t distance;
if (animations[i].animationEnd > animations[i].animationStart)
{
directionModifier = 1;
distance = (int16_t)((animations[i].animationEnd - animations[i].animationStart) * 1000);
}
else
{
directionModifier = -1;
distance = (int16_t)((animations[i].animationStart - animations[i].animationEnd) * 1000);
}
float delta = directionModifier * (animations[i].animationProgressionEquation(actualAnimationCounter, 0, distance, animations[i].animationDuration) / 1000.f);
switch ((AnimationParameter)i)
{
case X_ROTATION:
newXAngle = animations[X_ROTATION].animationStart + delta;
break;
case Y_ROTATION:
newYAngle = animations[Y_ROTATION].animationStart + delta;
break;
case Z_ROTATION:
newZAngle = animations[Z_ROTATION].animationStart + delta;
break;
case SCALE:
newScale = animations[SCALE].animationStart + delta;
break;
default:
break;
}
}
}
if (activeAnimation == ANIMATION_RUNNING)
{
updateAngles(newXAngle, newYAngle, newZAngle);
setScale(newScale);
if (textureMapperAnimationStepCallback && textureMapperAnimationStepCallback->isValid())
{
textureMapperAnimationStepCallback->execute(*this);
}
animationCounter++;
}
else if (activeAnimation == ANIMATION_DELAYED)
{
animationCounter++;
}
else
{
// End of animation
cancelAnimationTextureMapperAnimation();
if (textureMapperAnimationEndedCallback && textureMapperAnimationEndedCallback->isValid())
{
textureMapperAnimationEndedCallback->execute(*this);
}
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,38 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/Box.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
Rect Box::getSolidRect() const
{
Rect solidRect(0, 0, 0, 0);
if (reportAsSolid || alpha == 255)
{
solidRect.width = rect.width;
solidRect.height = rect.height;
}
return solidRect;
}
void Box::draw(const Rect& area) const
{
Rect dirty = area;
translateRectToAbsolute(dirty);
HAL::lcd().fillRect(dirty, color, alpha);
}
} // namespace touchgfx

View File

@@ -0,0 +1,59 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/BoxWithBorder.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
Rect BoxWithBorder::getSolidRect() const
{
Rect solidRect(0, 0, 0, 0);
if (alpha == 255)
{
solidRect.width = rect.width;
solidRect.height = rect.height;
}
return solidRect;
}
void BoxWithBorder::draw(const Rect& area) const
{
Rect dirty = area & Rect(borderSize, borderSize, getWidth() - (2 * borderSize), getHeight() - (2 * borderSize));
translateRectToAbsolute(dirty);
HAL::lcd().fillRect(dirty, color, alpha);
if (borderSize > 0)
{
Rect borders[4] =
{
Rect(0, 0, getWidth(), borderSize), // Upper
Rect(0, getHeight() - borderSize, getWidth(), borderSize), // lower
Rect(0, borderSize, borderSize, getHeight() - (2 * borderSize)), // left
Rect(getWidth() - borderSize, borderSize, borderSize, getHeight() - (2 * borderSize)) // right
};
for (int i = 0; i < 4; i++)
{
Rect borderDirty = borders[i] & area;
if (!borderDirty.isEmpty())
{
translateRectToAbsolute(borderDirty);
HAL::lcd().fillRect(borderDirty, borderColor, alpha);
}
}
}
}
}

View File

@@ -0,0 +1,53 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/Button.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
void Button::draw(const Rect& invalidatedArea) const
{
Bitmap bmp(AbstractButton::pressed ? down : up);
Rect dirty(0, 0, bmp.getWidth(), bmp.getHeight());
dirty &= invalidatedArea;
if ((bmp.getId() != BITMAP_INVALID) && !dirty.isEmpty())
{
Rect r;
translateRectToAbsolute(r);
HAL::lcd().drawPartialBitmap(bmp, r.x, r.y, dirty, alpha);
}
}
void Button::setBitmaps(const Bitmap& bmpReleased, const Bitmap& bmpPressed)
{
up = bmpReleased;
down = bmpPressed;
// Adjust width and height of this widget to match bitmap. It is assumed
// that the two bitmaps have same dimensions.
Drawable::setWidth(down.getWidth());
Drawable::setHeight(down.getHeight());
}
Rect Button::getSolidRect() const
{
if (alpha < 255)
{
return Rect(0, 0, 0, 0);
}
return (AbstractButton::pressed ? down.getSolidRect() : up.getSolidRect());
}
} // namespace touchgfx

View File

@@ -0,0 +1,56 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/ButtonWithIcon.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
ButtonWithIcon::ButtonWithIcon() :
Button(),
iconX(0),
iconY(0)
{
}
void ButtonWithIcon::setBitmaps(const Bitmap& newBackgroundReleased, const Bitmap& newBackgroundPressed,
const Bitmap& newIconReleased, const Bitmap& newIconPressed)
{
Button::setBitmaps(newBackgroundReleased, newBackgroundPressed);
iconReleased = newIconReleased;
iconPressed = newIconPressed;
iconX = (getWidth() / 2) - (newIconPressed.getWidth() / 2);
iconY = (getHeight() / 2) - (newIconPressed.getHeight() / 2);
}
void ButtonWithIcon::draw(const Rect& invalidatedArea) const
{
Button::draw(invalidatedArea);
Bitmap bmp((pressed ? iconPressed : iconReleased));
Rect iconRect(iconX, iconY, bmp.getWidth(), bmp.getHeight());
Rect dirty = invalidatedArea & iconRect;
if ((bmp.getId() != BITMAP_INVALID) && !dirty.isEmpty())
{
Rect r;
translateRectToAbsolute(r);
dirty.x -= iconX;
dirty.y -= iconY;
HAL::lcd().drawPartialBitmap(bmp, r.x + iconX, r.y + iconY, dirty, alpha);
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,63 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/ButtonWithLabel.hpp>
#include <touchgfx/FontManager.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
ButtonWithLabel::ButtonWithLabel()
: Button(), color(0), colorPressed(0), rotation(TEXT_ROTATE_0), textHeightIncludingSpacing(0)
{
}
void ButtonWithLabel::draw(const Rect& area) const
{
Button::draw(area);
if (typedText.hasValidId())
{
const Font* fontToDraw = typedText.getFont(); //never return 0
uint8_t height = textHeightIncludingSpacing;
int16_t offset;
Rect labelRect;
switch (rotation)
{
default:
case TEXT_ROTATE_0:
case TEXT_ROTATE_180:
offset = (this->getHeight() - height) / 2;
labelRect = Rect(0, offset, this->getWidth(), height);
break;
case TEXT_ROTATE_90:
case TEXT_ROTATE_270:
offset = (this->getWidth() - height) / 2;
labelRect = Rect(offset, 0, height, this->getHeight());
break;
}
Rect dirty = labelRect & area;
if (!dirty.isEmpty())
{
dirty.x -= labelRect.x;
dirty.y -= labelRect.y;
translateRectToAbsolute(labelRect);
LCD::StringVisuals visuals(fontToDraw, pressed ? colorPressed : color, alpha, typedText.getAlignment(), 0, rotation, typedText.getTextDirection(), 0, WIDE_TEXT_NONE);
HAL::lcd().drawString(labelRect, dirty, visuals, typedText.getText());
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,53 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/Image.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
void Image::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
// When setting bitmap, adjust size of this widget to match.
setWidth(bitmap.getWidth());
setHeight(bitmap.getHeight());
}
void Image::draw(const Rect& invalidatedArea) const
{
Rect meAbs;
translateRectToAbsolute(meAbs); //To find our x and y coords in absolute.
// Calculate intersection between bitmap rect and invalidated area.
Rect dirtyBitmapArea = bitmap.getRect() & invalidatedArea;
if (!dirtyBitmapArea.isEmpty())
{
HAL::lcd().drawPartialBitmap(bitmap, meAbs.x, meAbs.y, dirtyBitmapArea, alpha);
}
}
Rect Image::getSolidRect() const
{
// If alpha is less than solid, we have an empty solid rect.
if (alpha < 255)
{
return Rect(0, 0, 0, 0);
}
// Return solid rect from bitmap (precalculated).
return bitmap.getSolidRect();
}
} // namespace touchgfx

View File

@@ -0,0 +1,308 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/hal/Types.hpp>
#include <touchgfx/widgets/Keyboard.hpp>
namespace touchgfx
{
Keyboard::Keyboard()
: Container(), keyListener(0), bufferSize(0), bufferPosition(0), highlightImage(), cancelIsEmitted(false)
{
setTouchable(true);
keyMappingList = static_cast<KeyMappingList*>(0);
buffer = static_cast<Unicode::UnicodeChar*>(0);
layout = static_cast<Layout*>(0);
image.setXY(0, 0);
Container::add(image);
highlightImage.setVisible(false);
Container::add(highlightImage);
enteredText.setColor(Color::getColorFrom24BitRGB(0, 0, 0));
Container::add(enteredText);
}
void Keyboard::setBuffer(Unicode::UnicodeChar* newBuffer, uint16_t newBufferSize)
{
buffer = newBuffer;
bufferSize = newBufferSize;
enteredText.setWildcard(buffer);
// Place cursor at end of string if we already have something
// in the edit buffer.
bufferPosition = Unicode::strlen(buffer);
}
void Keyboard::setLayout(const Layout* newLayout)
{
layout = newLayout;
if (newLayout != 0)
{
image.setBitmap(Bitmap(newLayout->bitmap));
enteredText.setTypedText(newLayout->textAreaFont);
enteredText.setColor(newLayout->textAreaFontColor);
enteredText.setPosition(newLayout->textAreaPosition.x, newLayout->textAreaPosition.y,
newLayout->textAreaPosition.width, newLayout->textAreaPosition.height);
}
invalidate();
}
void Keyboard::setTextIndentation()
{
if (layout != 0)
{
uint8_t indentation = layout->textAreaFont.getFont()->getMaxPixelsLeft();
enteredText.setPosition(layout->textAreaPosition.x - indentation, layout->textAreaPosition.y,
layout->textAreaPosition.width + indentation * 2, layout->textAreaPosition.height);
enteredText.setIndentation(indentation);
}
}
Keyboard::Key Keyboard::getKeyForCoordinates(int16_t x, int16_t y) const
{
Key key;
key.keyId = 0; // No key
if (layout != 0)
{
for (uint8_t i = 0; i < layout->numberOfKeys; i++)
{
if (layout->keyArray[i].keyArea.intersect(x, y))
{
key = layout->keyArray[i];
break;
}
}
}
return key;
}
Keyboard::CallbackArea Keyboard::getCallbackAreaForCoordinates(int16_t x, int16_t y) const
{
CallbackArea area;
area.callback = reinterpret_cast<GenericCallback<>*>(0);
if (layout != 0)
{
for (uint8_t i = 0; i < layout->numberOfCallbackAreas; i++)
{
if (layout->callbackAreaArray[i].keyArea.intersect(x, y))
{
area = layout->callbackAreaArray[i];
break;
}
}
}
return area;
}
void Keyboard::draw(const Rect& invalidatedArea) const
{
assert(layout && "No layout configured for Keyboard");
if (layout != 0)
{
Font* font = FontManager::getFont(layout->keyFont);
assert(font && "Keyboard::draw: Unable to find font, is font db initialized?");
if (font != 0)
{
// Setup visuals for h-center of "string"
LCD::StringVisuals visuals;
visuals.font = font;
visuals.alignment = CENTER;
visuals.color = layout->keyFontColor;
// String with room for a single character
Unicode::UnicodeChar character[2] = { 0, 0 }; // The last is important as string terminator.
uint16_t fontHeight = font->getMinimumTextHeight();
for (uint8_t i = 0; i < layout->numberOfKeys; i++)
{
const Key& key = layout->keyArray[i];
if (key.keyArea.intersect(invalidatedArea))
{
uint8_t keyId = key.keyId;
Unicode::UnicodeChar c = getCharForKey(keyId);
if (c != 0)
{
// Get a copy of the keyArea and v-center the area for the character
Rect keyArea = key.keyArea;
uint16_t offset = (keyArea.height - fontHeight) / 2;
keyArea.y += offset;
keyArea.height -= offset;
// Calculate the invalidated area relative to the key
Rect invalidatedAreaRelative = key.keyArea & invalidatedArea;
invalidatedAreaRelative.x -= keyArea.x;
invalidatedAreaRelative.y -= keyArea.y;
// Set up string with one character
character[0] = c;
translateRectToAbsolute(keyArea);
HAL::lcd().drawString(keyArea, invalidatedAreaRelative, visuals, character);
}
}
}
}
}
}
void Keyboard::handleClickEvent(const ClickEvent& evt)
{
ClickEvent::ClickEventType type = evt.getType();
int16_t x = evt.getX();
int16_t y = evt.getY();
Rect toDraw;
Keyboard::CallbackArea callbackArea = getCallbackAreaForCoordinates(x, y);
if (callbackArea.callback != 0)
{
if (type == ClickEvent::PRESSED)
{
highlightImage.setXY(callbackArea.keyArea.x, callbackArea.keyArea.y);
highlightImage.setBitmap(Bitmap(callbackArea.highlightBitmapId));
highlightImage.setVisible(true);
toDraw = highlightImage.getRect();
invalidateRect(toDraw);
}
if ((type == ClickEvent::RELEASED) && callbackArea.callback->isValid())
{
if (cancelIsEmitted)
{
cancelIsEmitted = false;
}
else
{
callbackArea.callback->execute();
if (keyListener)
{
keyListener->execute(0);
}
}
}
}
else
{
Keyboard::Key key = getKeyForCoordinates(x, y);
if (key.keyId != 0)
{
if (type == ClickEvent::PRESSED)
{
highlightImage.setXY(key.keyArea.x, key.keyArea.y);
highlightImage.setBitmap(Bitmap(key.highlightBitmapId));
highlightImage.setVisible(true);
toDraw = highlightImage.getRect();
invalidateRect(toDraw);
}
if (type == ClickEvent::RELEASED)
{
if (cancelIsEmitted)
{
cancelIsEmitted = false;
}
else
{
if (buffer)
{
Unicode::UnicodeChar c = getCharForKey(key.keyId);
if (c != 0)
{
uint16_t prevBufferPosition = bufferPosition;
if (bufferPosition < (bufferSize - 1))
{
buffer[bufferPosition++] = c;
buffer[bufferPosition] = 0;
}
if (prevBufferPosition != bufferPosition)
{
enteredText.invalidate();
if (keyListener)
{
keyListener->execute(c);
}
}
}
}
}
}
}
}
if (type == ClickEvent::RELEASED || type == ClickEvent::CANCEL)
{
toDraw = highlightImage.getRect();
highlightImage.setVisible(false);
invalidateRect(toDraw);
if (type == ClickEvent::CANCEL)
{
cancelIsEmitted = true;
}
}
}
void Keyboard::handleDragEvent(const DragEvent& evt)
{
if (highlightImage.isVisible() && (!highlightImage.getRect().intersect(static_cast<int16_t>(evt.getNewX()), static_cast<int16_t>(evt.getNewY()))) && (!cancelIsEmitted))
{
// Send a CANCEL click event, if user has dragged out of currently pressed/highlighted key.
touchgfx::ClickEvent cancelEvent(touchgfx::ClickEvent::CANCEL, static_cast<int16_t>(evt.getOldX()), static_cast<int16_t>(evt.getOldY()));
handleClickEvent(cancelEvent);
}
}
Unicode::UnicodeChar Keyboard::getCharForKey(uint8_t keyId) const
{
Unicode::UnicodeChar ch = 0;
if (keyMappingList != 0)
{
for (uint8_t i = 0; i < keyMappingList->numberOfKeys; i++)
{
if (keyMappingList->keyMappingArray[i].keyId == keyId)
{
ch = keyMappingList->keyMappingArray[i].keyValue;
break;
}
}
}
return ch;
}
void Keyboard::setupDrawChain(const Rect& invalidatedArea, Drawable** nextPreviousElement)
{
// Keyboard is a Container, and they do not normally appear in the draw chain (they just draw children).
// But this particular container actually has a draw() function implementation, so we must change default
// behavior.
// First, add children
Container::setupDrawChain(invalidatedArea, nextPreviousElement);
// Then add yourself
Drawable::setupDrawChain(invalidatedArea, nextPreviousElement);
}
void Keyboard::setBufferPosition(uint16_t newPos)
{
bufferPosition = newPos;
enteredText.invalidate();
}
void Keyboard::setKeymappingList(const KeyMappingList* newKeyMappingList)
{
keyMappingList = newKeyMappingList;
invalidate();
}
} // namespace touchgfx

View File

@@ -0,0 +1,91 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/widgets/PixelDataWidget.hpp>
namespace touchgfx
{
PixelDataWidget::PixelDataWidget()
: Widget(),
buffer(0),
format(Bitmap::RGB888),
alpha(255)
{
}
void PixelDataWidget::setPixelData(uint8_t* const data)
{
buffer = data;
}
void PixelDataWidget::setBitmapFormat(Bitmap::BitmapFormat f)
{
format = f;
}
void PixelDataWidget::setAlpha(uint8_t newAlpha)
{
alpha = newAlpha;
}
uint8_t PixelDataWidget::getAlpha() const
{
return alpha;
}
void PixelDataWidget::draw(const touchgfx::Rect& invalidatedArea) const
{
if (buffer != 0)
{
//convert to lcd coordinates
const touchgfx::Rect absolute = getAbsoluteRect();
//copy to LCD
HAL::lcd().blitCopy(buffer, format, absolute, invalidatedArea, alpha, false);
}
}
touchgfx::Rect PixelDataWidget::getSolidRect() const
{
Rect solidRect(0, 0, 0, 0);
if (alpha == 255)
{
// There are at least some solid pixels
switch (format)
{
case Bitmap::BW: ///< 1-bit, black / white, no alpha channel
case Bitmap::BW_RLE: ///< 1-bit, black / white, no alpha channel compressed with horizontal RLE
case Bitmap::GRAY2: ///< 2-bit, gray scale, no alpha channel
case Bitmap::GRAY4: ///< 4-bit, gray scale, no alpha channel
case Bitmap::RGB565: ///< 16-bit, 5 bits for red, 6 bits for green, 5 bits for blue, no alpha channel
case Bitmap::RGB888: ///< 16-bit, 5 bits for red, 6 bits for green, 5 bits for blue, no alpha channel
//All solid pixels
solidRect.width = getWidth();
solidRect.height = getHeight();
break;
case Bitmap::ARGB8888: ///< 32-bit, 8 bits for each of red, green, blue and alpha channel
case Bitmap::ARGB2222: ///< 8-bit color
case Bitmap::ABGR2222: ///< 8-bit color
case Bitmap::RGBA2222: ///< 8-bit color
case Bitmap::BGRA2222: ///< 8-bit color
case Bitmap::L8: ///< 8-bit indexed color
case Bitmap::A4: ///< 4-bit alpha level
//No knowledge about solid pixels
break;
}
}
return solidRect;
}
} // namespace touchgfx

View File

@@ -0,0 +1,99 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/RadioButton.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
void RadioButton::draw(const Rect& invalidatedArea) const
{
Bitmap bmp = getCurrentlyDisplayedBitmap();
Rect dirty(0, 0, bmp.getWidth(), bmp.getHeight());
dirty &= invalidatedArea;
if ((bmp.getId() != BITMAP_INVALID) && !dirty.isEmpty())
{
Rect r;
translateRectToAbsolute(r);
HAL::lcd().drawPartialBitmap(bmp, r.x, r.y, dirty, alpha);
}
}
void RadioButton::handleClickEvent(const ClickEvent& event)
{
bool wasPressed = pressed;
pressed = (event.getType() == ClickEvent::PRESSED);
if ((pressed && !wasPressed) || (!pressed && wasPressed))
{
invalidate();
}
if (wasPressed && (event.getType() == ClickEvent::RELEASED))
{
if (deselectionEnabled)
{
setSelected(!getSelected());
}
else if (!getSelected())
{
setSelected(true);
}
}
}
void RadioButton::setBitmaps(const Bitmap& bmpUnselected, const Bitmap& bmpUnselectedPressed, const Bitmap& bmpSelected, const Bitmap& bmpSelectedPressed)
{
bitmapUnselected = bmpUnselected;
bitmapUnselectedPressed = bmpUnselectedPressed;
bitmapSelected = bmpSelected;
bitmapSelectedPressed = bmpSelectedPressed;
Drawable::setWidth(bitmapUnselected.getWidth());
Drawable::setHeight(bitmapUnselected.getHeight());
}
Rect RadioButton::getSolidRect() const
{
if (alpha < 255)
{
return Rect(0, 0, 0, 0);
}
return getCurrentlyDisplayedBitmap().getSolidRect();
}
void RadioButton::setSelected(bool newSelected)
{
bool wasSelected = selected;
selected = newSelected;
if (wasSelected && !newSelected)
{
if (deselectedAction && deselectedAction->isValid())
{
deselectedAction->execute(*this);
}
}
if (!wasSelected && newSelected)
{
if (action && action->isValid())
{
action->execute(*this);
}
}
invalidate();
}
} // namespace touchgfx

View File

@@ -0,0 +1,87 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/RepeatButton.hpp>
namespace touchgfx
{
RepeatButton::RepeatButton() : Button(), ticksDelay(30), ticksInterval(15), ticks(0), ticksBeforeContinuous(0)
{
}
void RepeatButton::setDelay(int delay)
{
ticksDelay = delay;
}
int RepeatButton::getDelay()
{
return ticksDelay;
}
void RepeatButton::setInterval(int interval)
{
ticksInterval = interval;
}
int RepeatButton::getInterval()
{
return ticksInterval;
}
void RepeatButton::handleClickEvent(const touchgfx::ClickEvent& event)
{
pressed = false; // To prevent AbstractButton from calling action->execute().
invalidate(); // Force redraw after forced state change
Button::handleClickEvent(event);
if (event.getType() == touchgfx::ClickEvent::PRESSED)
{
if (action && action->isValid())
{
action->execute(*this);
}
ticks = 0;
ticksBeforeContinuous = ticksDelay;
touchgfx::Application::getInstance()->registerTimerWidget(this);
}
else
{
touchgfx::Application::getInstance()->unregisterTimerWidget(this);
}
}
void RepeatButton::handleTickEvent()
{
Button::handleTickEvent();
if (pressed)
{
if (ticks == ticksBeforeContinuous)
{
if (action && action->isValid())
{
action->execute(*this);
}
ticks = 0;
ticksBeforeContinuous = ticksInterval;
}
else
{
ticks++;
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,210 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/TextureMapTypes.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/transforms/DisplayTransformation.hpp>
#include <touchgfx/widgets/ScalableImage.hpp>
namespace touchgfx
{
ScalableImage::ScalableImage()
: Widget(),
currentScalingAlgorithm(BILINEAR_INTERPOLATION),
alpha(255)
{
}
void ScalableImage::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
setWidth(bitmap.getWidth());
setHeight(bitmap.getHeight());
}
void ScalableImage::setScalingAlgorithm(ScalingAlgorithm algorithm)
{
currentScalingAlgorithm = algorithm;
}
ScalableImage::ScalingAlgorithm ScalableImage::getScalingAlgorithm()
{
return currentScalingAlgorithm;
}
void ScalableImage::drawTriangle(const Rect& invalidatedArea, uint16_t* fb, const float* triangleXs, const float* triangleYs, const float* triangleZs, const float* triangleUs, const float* triangleVs) const
{
// Area to redraw. Relative to the scalableImage.
Rect dirtyArea = Rect(0, 0, getWidth(), getHeight()) & invalidatedArea;
// Absolute position of the scalableImage.
Rect dirtyAreaAbsolute = dirtyArea;
translateRectToAbsolute(dirtyAreaAbsolute);
Rect absoluteRect = getAbsoluteRect();
DisplayTransformation::transformDisplayToFrameBuffer(absoluteRect);
// Transform rects to match framebuffer coordinates
// This is needed if the display is rotated compared to the framebuffer
DisplayTransformation::transformDisplayToFrameBuffer(dirtyArea, this->getRect());
DisplayTransformation::transformDisplayToFrameBuffer(dirtyAreaAbsolute);
// Get a pointer to the bitmap data, return if no bitmap found
const uint16_t* textmap = (const uint16_t*)bitmap.getData();
if (!textmap)
{
return;
}
float x0 = triangleXs[0];
float x1 = triangleXs[1];
float x2 = triangleXs[2];
float y0 = triangleYs[0];
float y1 = triangleYs[1];
float y2 = triangleYs[2];
DisplayTransformation::transformDisplayToFrameBuffer(x0, y0, this->getRect());
DisplayTransformation::transformDisplayToFrameBuffer(x1, y1, this->getRect());
DisplayTransformation::transformDisplayToFrameBuffer(x2, y2, this->getRect());
Point3D vertices[3];
Point3D point0 = { floatToFixed28_4(x0), floatToFixed28_4(y0), (float)(triangleZs[0]), (float)(triangleUs[0]), (float)(triangleVs[0]) };
Point3D point1 = { floatToFixed28_4(x1), floatToFixed28_4(y1), (float)(triangleZs[1]), (float)(triangleUs[1]), (float)(triangleVs[1]) };
Point3D point2 = { floatToFixed28_4(x2), floatToFixed28_4(y2), (float)(triangleZs[2]), (float)(triangleUs[2]), (float)(triangleVs[2]) };
vertices[0] = point0;
vertices[1] = point1;
vertices[2] = point2;
DrawingSurface dest = { fb, HAL::FRAME_BUFFER_WIDTH };
TextureSurface src = { textmap, bitmap.getExtraData(), bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth() };
HAL::lcd().drawTextureMapTriangle(dest, vertices, src, absoluteRect, dirtyAreaAbsolute, lookupRenderVariant(), alpha, 0xFFFF);
}
RenderingVariant ScalableImage::lookupRenderVariant() const
{
RenderingVariant renderVariant;
if (currentScalingAlgorithm == NEAREST_NEIGHBOR)
{
renderVariant = lookupNearestNeighborRenderVariant(bitmap);
}
else
{
renderVariant = lookupBilinearRenderVariant(bitmap);
}
return renderVariant;
}
void ScalableImage::draw(const Rect& invalidatedArea) const
{
if (!alpha)
{
return;
}
uint16_t* fb = HAL::getInstance()->lockFrameBuffer();
float triangleXs[3];
float triangleYs[3];
float triangleZs[3];
float triangleUs[3];
float triangleVs[3];
float imageX0 = 0;
float imageY0 = 0;
float imageX1 = imageX0 + getWidth();
float imageY1 = imageY0;
float imageX2 = imageX1;
float imageY2 = imageY0 + getHeight();
float imageX3 = imageX0;
float imageY3 = imageY2;
triangleZs[0] = 100.f;
triangleZs[1] = 100.f;
triangleZs[2] = 100.f;
// Setup texture coordinates
float right = (float)(bitmap.getWidth());
float bottom = (float)(bitmap.getHeight());
float textureU0 = 0.0f;
float textureV0 = 0.0f;
float textureU1 = right;
float textureV1 = 0.0f;
float textureU2 = right;
float textureV2 = bottom;
float textureU3 = 0.0f;
float textureV3 = bottom;
if (HAL::DISPLAY_ROTATION == rotate90)
{
textureU0 = 0.0f;
textureV0 = right;
textureU1 = 0.0f;
textureV1 = 0.0f;
textureU2 = bottom;
textureV2 = 0.0f;
textureU3 = bottom;
textureV3 = right;
}
triangleXs[0] = imageX0;
triangleXs[1] = imageX1;
triangleXs[2] = imageX2;
triangleYs[0] = imageY0;
triangleYs[1] = imageY1;
triangleYs[2] = imageY2;
triangleUs[0] = textureU0;
triangleUs[1] = textureU1;
triangleUs[2] = textureU2;
triangleVs[0] = textureV0;
triangleVs[1] = textureV1;
triangleVs[2] = textureV2;
drawTriangle(invalidatedArea, fb, triangleXs, triangleYs, triangleZs, triangleUs, triangleVs);
triangleXs[0] = imageX0;
triangleXs[1] = imageX2;
triangleXs[2] = imageX3;
triangleYs[0] = imageY0;
triangleYs[1] = imageY2;
triangleYs[2] = imageY3;
triangleUs[0] = textureU0;
triangleUs[1] = textureU2;
triangleUs[2] = textureU3;
triangleVs[0] = textureV0;
triangleVs[1] = textureV2;
triangleVs[2] = textureV3;
drawTriangle(invalidatedArea, fb, triangleXs, triangleYs, triangleZs, triangleUs, triangleVs);
HAL::getInstance()->unlockFrameBuffer();
}
Rect ScalableImage::getSolidRect() const
{
if (alpha < 255)
{
return Rect(0, 0, 0, 0);
}
// If original image is completely solid the scaled image will also be
if ((bitmap.getSolidRect().width == bitmap.getWidth()) && (bitmap.getSolidRect().height == bitmap.getHeight()))
{
return bitmap.getSolidRect();
}
return Rect(0, 0, 0, 0);
}
} // namespace touchgfx

View File

@@ -0,0 +1,61 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/SnapshotWidget.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
SnapshotWidget::SnapshotWidget() : Widget(), bitmapId(BITMAP_INVALID), alpha(255)
{
}
void SnapshotWidget::draw(const Rect& invalidatedArea) const
{
if (alpha == 0 || bitmapId == BITMAP_INVALID)
{
return;
}
Rect absRect(0, 0, Bitmap(bitmapId).getWidth(), rect.height);
translateRectToAbsolute(absRect);
HAL::lcd().blitCopy((const uint16_t*)Bitmap(bitmapId).getData(), absRect, invalidatedArea, alpha, false);
}
Rect SnapshotWidget::getSolidRect() const
{
if (alpha < 255 || bitmapId == BITMAP_INVALID)
{
return Rect(0, 0, 0, 0);
}
else
{
return Rect(0, 0, getWidth(), getHeight());
}
}
void SnapshotWidget::makeSnapshot()
{
makeSnapshot(BITMAP_ANIMATION_STORAGE);
}
void SnapshotWidget::makeSnapshot(const BitmapId bmp)
{
Rect visRect(0, 0, rect.width, rect.height);
getVisibleRect(visRect);
Rect absRect = getAbsoluteRect();
bitmapId = (HAL::lcd().copyFrameBufferRegionToMemory(visRect, absRect, bmp)) ? bmp : BITMAP_INVALID;
}
} // namespace touchgfx

View File

@@ -0,0 +1,171 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/TextArea.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
int16_t TextArea::getTextHeight()
{
return typedText.hasValidId() ? calculateTextHeight(typedText.getText(), 0, 0) : 0;
}
uint16_t TextArea::getTextWidth() const
{
return typedText.hasValidId() ? typedText.getFont()->getStringWidth(typedText.getTextDirection(), typedText.getText(), 0, 0) : 0;
}
void TextArea::draw(const Rect& area) const
{
if (typedText.hasValidId())
{
const Font* fontToDraw = typedText.getFont();
if (fontToDraw != 0)
{
LCD::StringVisuals visuals(fontToDraw, color, alpha, typedText.getAlignment(), linespace, rotation, typedText.getTextDirection(), indentation, wideTextAction);
HAL::lcd().drawString(getAbsoluteRect(), area, visuals, typedText.getText(), 0, 0);
}
}
}
void TextArea::setTypedText(TypedText t)
{
typedText = t;
// If this TextArea does not yet have a width and height,
// just assign the smallest possible size to fit current text.
if ((getWidth() == 0) && (getHeight() == 0))
{
resizeToCurrentText();
}
}
void TextArea::resizeToCurrentText()
{
if (typedText.hasValidId())
{
uint16_t w = getTextWidth();
uint16_t h = getTextHeight();
if (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180)
{
setWidth(w);
setHeight(h);
}
else
{
setWidth(h);
setHeight(w);
}
}
}
void TextArea::resizeToCurrentTextWithAlignment()
{
if (typedText.hasValidId())
{
Alignment alignment = typedText.getAlignment();
uint16_t text_width = getTextWidth();
uint16_t text_height = getTextHeight();
if (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180)
{
// (rotate-0 && left-align) or (rotate-180 && right-align) places text to the left
if (!((rotation == TEXT_ROTATE_0 && alignment == LEFT) || (rotation == TEXT_ROTATE_180 && alignment == RIGHT)))
{
uint16_t old_width = getWidth();
uint16_t old_x = getX();
if (alignment == CENTER)
{
setX(old_x + (old_width - text_width) / 2);
}
else
{
setX(old_x + (old_width - text_width));
}
}
if (rotation == TEXT_ROTATE_180)
{
uint16_t old_height = getHeight();
uint16_t old_y = getY();
setY(old_y + (old_height - text_height));
}
setWidth(text_width);
setHeight(text_height);
}
else
{
// 90+left or 270+right places text at the same y coordinate
if (!((rotation == TEXT_ROTATE_90 && alignment == LEFT) || (rotation == TEXT_ROTATE_270 && alignment == RIGHT)))
{
uint16_t old_height = getHeight();
uint16_t old_y = getY();
if (alignment == CENTER)
{
setY(old_y + (old_height - text_width) / 2);
}
else
{
setY(old_y + (old_height - text_width));
}
}
if (rotation == TEXT_ROTATE_90)
{
uint16_t old_width = getWidth();
uint16_t old_x = getX();
setX(old_x + (old_width - text_height));
}
setWidth(text_height);
setHeight(text_width);
}
}
}
void TextArea::resizeHeightToCurrentText()
{
if (typedText.hasValidId())
{
uint16_t h = getTextHeight();
if (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180)
{
setHeight(h);
}
else
{
setWidth(h);
}
}
}
int16_t TextArea::calculateTextHeight(const Unicode::UnicodeChar* format, ...) const
{
if (!typedText.hasValidId())
{
return 0;
}
va_list pArg;
va_start(pArg, format);
const Font* fontToDraw = typedText.getFont();
int16_t textHeight = fontToDraw->getMinimumTextHeight();
TextProvider textProvider;
textProvider.initialize(format, pArg, fontToDraw->getGSUBTable());
int16_t numLines = LCD::getNumLines(textProvider, wideTextAction, typedText.getTextDirection(), typedText.getFont(), getWidth());
va_end(pArg);
return (textHeight + linespace > 0) ? (numLines * textHeight + (numLines - 1) * linespace) : (numLines > 0) ? (textHeight) : 0;
}
} // namespace touchgfx

View File

@@ -0,0 +1,46 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/TextAreaWithWildcard.hpp>
namespace touchgfx
{
void TextAreaWithOneWildcard::draw(const Rect& area) const
{
if (typedText.hasValidId())
{
const Font* fontToDraw = typedText.getFont();
if (fontToDraw != 0)
{
LCD::StringVisuals visuals(fontToDraw, color, alpha, typedText.getAlignment(), linespace, rotation, typedText.getTextDirection(), indentation, wideTextAction);
HAL::lcd().drawString(getAbsoluteRect(), area, visuals, typedText.getText(), wildcard, 0);
}
}
}
void TextAreaWithTwoWildcards::draw(const Rect& area) const
{
if (typedText.hasValidId())
{
const Font* fontToDraw = typedText.getFont();
if (fontToDraw != 0)
{
LCD::StringVisuals visuals(fontToDraw, color, alpha, typedText.getAlignment(), linespace, rotation, typedText.getTextDirection(), indentation, wideTextAction);
HAL::lcd().drawString(getAbsoluteRect(), area, visuals, typedText.getText(), wc1, wc2);
}
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,381 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Math3D.hpp>
#include <touchgfx/TextureMapTypes.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/transforms/DisplayTransformation.hpp>
#include <touchgfx/widgets/TextureMapper.hpp>
namespace touchgfx
{
TextureMapper::TextureMapper()
: Widget(),
currentRenderingAlgorithm(NEAREST_NEIGHBOR),
alpha(255),
xBitmapPosition(0.0f),
yBitmapPosition(0.0f),
xAngle(0.0f),
yAngle(0.0f),
zAngle(0.0f),
scale(1.0f),
xOrigo(0.0f),
yOrigo(0.0f),
zOrigo(1000.0f),
xCamera(0.0f),
yCamera(0.0f),
cameraDistance(1000.0f),
imageX0(0.0f),
imageY0(0.0f),
imageZ0(1.0f),
imageX1(0.0f),
imageY1(0.0f),
imageZ1(1.0f),
imageX2(0.0f),
imageY2(0.0f),
imageZ2(1.0f),
imageX3(0.0f),
imageY3(0.0f),
imageZ3(1.0f),
subDivisionSize(12)
{
}
void TextureMapper::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
setWidth(bitmap.getWidth());
setHeight(bitmap.getHeight());
applyTransformation();
}
void TextureMapper::applyTransformation()
{
const uint8_t n = 4;
int imgWidth = Bitmap(bitmap).getWidth() + 1;
int imgHeight = Bitmap(bitmap).getHeight() + 1;
touchgfx::Point4 vertices[n] =
{
touchgfx::Point4(xBitmapPosition - 1, yBitmapPosition - 1, cameraDistance),
touchgfx::Point4(xBitmapPosition - 1 + imgWidth, yBitmapPosition - 1, cameraDistance),
touchgfx::Point4(xBitmapPosition - 1 + imgWidth, yBitmapPosition - 1 + imgHeight, cameraDistance),
touchgfx::Point4(xBitmapPosition - 1, yBitmapPosition - 1 + imgHeight, cameraDistance),
};
touchgfx::Point4 transformed[n];
Vector4 center(xOrigo, yOrigo, zOrigo);
Matrix4x4 translateToCenter;
translateToCenter.concatenateXTranslation(-center.getX()).concatenateYTranslation(-center.getY()).concatenateZTranslation(-center.getZ());
Matrix4x4 rotateAroundCenter;
rotateAroundCenter.concatenateXRotation(xAngle).concatenateYRotation(yAngle).concatenateZRotation(zAngle);
Matrix4x4 scaleAroundCenter;
scaleAroundCenter.concatenateXScale(scale).concatenateYScale(scale).concatenateZScale(scale);
Matrix4x4 translateFromCenter;
translateFromCenter.concatenateXTranslation(center.getX()).concatenateYTranslation(center.getY()).concatenateZTranslation(center.getZ());
Matrix4x4 transform = translateFromCenter * scaleAroundCenter * rotateAroundCenter * translateToCenter;
Matrix4x4 translateToCamera;
translateToCamera.concatenateXTranslation(-xCamera);
translateToCamera.concatenateYTranslation(-yCamera);
Matrix4x4 perspectiveProject;
perspectiveProject.setViewDistance(cameraDistance);
Matrix4x4 translateFromCamera;
translateFromCamera.concatenateXTranslation(xCamera).concatenateYTranslation(yCamera);
transform = translateFromCamera * perspectiveProject * translateToCamera * transform;
for (int i = 0; i < n; i++)
{
transformed[i] = transform * vertices[i];
}
imageX0 = ((float)transformed[0].getX() * cameraDistance / (float)transformed[0].getZ());
imageY0 = ((float)transformed[0].getY() * cameraDistance / (float)transformed[0].getZ());
imageZ0 = ((float)transformed[0].getZ());
imageX1 = ((float)transformed[1].getX() * cameraDistance / (float)transformed[1].getZ());
imageY1 = ((float)transformed[1].getY() * cameraDistance / (float)transformed[1].getZ());
imageZ1 = ((float)transformed[1].getZ());
imageX2 = ((float)transformed[2].getX() * cameraDistance / (float)transformed[2].getZ());
imageY2 = ((float)transformed[2].getY() * cameraDistance / (float)transformed[2].getZ());
imageZ2 = ((float)transformed[2].getZ());
imageX3 = ((float)transformed[3].getX() * cameraDistance / (float)transformed[3].getZ());
imageY3 = ((float)transformed[3].getY() * cameraDistance / (float)transformed[3].getZ());
imageZ3 = ((float)transformed[3].getZ());
}
Rect TextureMapper::getBoundingRect() const
{
// MIN and MAX are macros so do not insert them into each other
float minXf = MIN(imageX0, imageX1);
minXf = MIN(minXf, imageX2);
minXf = floorf(MIN(minXf, imageX3));
int16_t minX = (int16_t)(MAX(0, minXf));
float maxXf = MAX(imageX0, imageX1);
maxXf = MAX(maxXf, imageX2);
maxXf = ceilf(MAX(maxXf, imageX3));
int16_t maxX = getWidth();
maxX = (int16_t)(MIN(maxX, maxXf));
float minYf = MIN(imageY0, imageY1);
minYf = MIN(minYf, imageY2);
minYf = floorf(MIN(minYf, imageY3));
int16_t minY = (int16_t)(MAX(0, minYf));
float maxYf = MAX(imageY0, imageY1);
maxYf = MAX(maxYf, imageY2);
maxYf = ceilf(MAX(maxYf, imageY3));
int16_t maxY = getHeight();
maxY = (int16_t)(MIN(maxY, maxYf));
return Rect(minX, minY, maxX - minX, maxY - minY);
}
void TextureMapper::updateAngles(float newXAngle, float newYAngle, float newZAngle)
{
Rect rBefore = getBoundingRect();
this->xAngle = newXAngle;
this->yAngle = newYAngle;
this->zAngle = newZAngle;
applyTransformation();
Rect rAfter = getBoundingRect();
rAfter.expandToFit(rBefore);
invalidateRect(rAfter);
}
void TextureMapper::setScale(float _scale)
{
this->scale = _scale;
applyTransformation();
}
void TextureMapper::draw(const Rect& invalidatedArea) const
{
if (!alpha)
{
return;
}
uint16_t* fb = HAL::getInstance()->lockFrameBuffer();
// Setup texture coordinates
float right = (float)(bitmap.getWidth());
float bottom = (float)(bitmap.getHeight());
float textureU0 = -1.0f;
float textureV0 = -1.0f;
float textureU1 = right;
float textureV1 = -1.0f;
float textureU2 = right;
float textureV2 = bottom;
float textureU3 = -1.0f;
float textureV3 = bottom;
if (HAL::DISPLAY_ROTATION == rotate90)
{
textureU0 = -1.0f;
textureV0 = right;
textureU1 = -1.0f;
textureV1 = -1.0f;
textureU2 = bottom;
textureV2 = -1.0f;
textureU3 = bottom;
textureV3 = right;
}
float triangleXs[3];
float triangleYs[3];
float triangleZs[3];
float triangleUs[3];
float triangleVs[3];
// Determine winding order
Vector4 zeroToOne(imageX1 - imageX0, imageY1 - imageY0, imageZ1 - imageZ0);
Vector4 zeroToTwo(imageX2 - imageX0, imageY2 - imageY0, imageZ2 - imageZ0);
Vector4 normal = zeroToOne.crossProduct(zeroToTwo);
if (normal.getZ() > 0)
{
triangleXs[0] = imageX0;
triangleXs[1] = imageX1;
triangleXs[2] = imageX2;
triangleYs[0] = imageY0;
triangleYs[1] = imageY1;
triangleYs[2] = imageY2;
triangleZs[0] = imageZ0;
triangleZs[1] = imageZ1;
triangleZs[2] = imageZ2;
triangleUs[0] = textureU0;
triangleUs[1] = textureU1;
triangleUs[2] = textureU2;
triangleVs[0] = textureV0;
triangleVs[1] = textureV1;
triangleVs[2] = textureV2;
}
else
{
// invert due to the triangles winding order (showing backface of the triangle)
triangleXs[1] = imageX0;
triangleXs[0] = imageX1;
triangleXs[2] = imageX2;
triangleYs[1] = imageY0;
triangleYs[0] = imageY1;
triangleYs[2] = imageY2;
triangleZs[1] = imageZ0;
triangleZs[0] = imageZ1;
triangleZs[2] = imageZ2;
triangleUs[1] = textureU0;
triangleUs[0] = textureU1;
triangleUs[2] = textureU2;
triangleVs[1] = textureV0;
triangleVs[0] = textureV1;
triangleVs[2] = textureV2;
}
drawTriangle(invalidatedArea, fb, triangleXs, triangleYs, triangleZs, triangleUs, triangleVs);
if (normal.getZ() > 0)
{
triangleXs[0] = imageX0;
triangleXs[1] = imageX2;
triangleXs[2] = imageX3;
triangleYs[0] = imageY0;
triangleYs[1] = imageY2;
triangleYs[2] = imageY3;
triangleZs[0] = imageZ0;
triangleZs[1] = imageZ2;
triangleZs[2] = imageZ3;
triangleUs[0] = textureU0;
triangleUs[1] = textureU2;
triangleUs[2] = textureU3;
triangleVs[0] = textureV0;
triangleVs[1] = textureV2;
triangleVs[2] = textureV3;
}
else
{
triangleXs[1] = imageX0;
triangleXs[0] = imageX2;
triangleXs[2] = imageX3;
triangleYs[1] = imageY0;
triangleYs[0] = imageY2;
triangleYs[2] = imageY3;
triangleZs[1] = imageZ0;
triangleZs[0] = imageZ2;
triangleZs[2] = imageZ3;
triangleUs[1] = textureU0;
triangleUs[0] = textureU2;
triangleUs[2] = textureU3;
triangleVs[1] = textureV0;
triangleVs[0] = textureV2;
triangleVs[2] = textureV3;
}
drawTriangle(invalidatedArea, fb, triangleXs, triangleYs, triangleZs, triangleUs, triangleVs);
HAL::getInstance()->unlockFrameBuffer();
}
void TextureMapper::drawTriangle(const Rect& invalidatedArea, uint16_t* fb, const float* triangleXs, const float* triangleYs, const float* triangleZs, const float* triangleUs, const float* triangleVs) const
{
// Area to redraw. Relative to the TextureMapper.
Rect dirtyArea = Rect(0, 0, getWidth(), getHeight()) & invalidatedArea;
// Absolute position of the TextureMapper.
Rect dirtyAreaAbsolute = dirtyArea;
translateRectToAbsolute(dirtyAreaAbsolute);
Rect absoluteRect = getAbsoluteRect();
DisplayTransformation::transformDisplayToFrameBuffer(absoluteRect);
// Transform rects to match framebuffer coordinates
// This is needed if the display is rotated compared to the framebuffer
DisplayTransformation::transformDisplayToFrameBuffer(dirtyArea, this->getRect());
DisplayTransformation::transformDisplayToFrameBuffer(dirtyAreaAbsolute);
// Get a pointer to the bitmap data, return if no bitmap found
const uint16_t* textmap = (const uint16_t*)bitmap.getData();
if (!textmap)
{
return;
}
float x0 = triangleXs[0];
float x1 = triangleXs[1];
float x2 = triangleXs[2];
float y0 = triangleYs[0]; //lint !e578
float y1 = triangleYs[1]; //lint !e578
float y2 = triangleYs[2];
DisplayTransformation::transformDisplayToFrameBuffer(x0, y0, this->getRect());
DisplayTransformation::transformDisplayToFrameBuffer(x1, y1, this->getRect());
DisplayTransformation::transformDisplayToFrameBuffer(x2, y2, this->getRect());
Point3D vertices[3];
Point3D point0 = { floatToFixed28_4(x0), floatToFixed28_4(y0), (float)(triangleZs[0]), (float)(triangleUs[0]), (float)(triangleVs[0]) };
Point3D point1 = { floatToFixed28_4(x1), floatToFixed28_4(y1), (float)(triangleZs[1]), (float)(triangleUs[1]), (float)(triangleVs[1]) };
Point3D point2 = { floatToFixed28_4(x2), floatToFixed28_4(y2), (float)(triangleZs[2]), (float)(triangleUs[2]), (float)(triangleVs[2]) };
vertices[0] = point0;
vertices[1] = point1;
vertices[2] = point2;
DrawingSurface dest = { fb, HAL::FRAME_BUFFER_WIDTH };
TextureSurface src = { textmap, bitmap.getExtraData(), bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth() };
uint16_t subDivs = subDivisionSize;
if (point0.Z == point1.Z && point1.Z == point2.Z)
{
subDivs = 0xFFFF; // Max: One sweep
}
HAL::lcd().drawTextureMapTriangle(dest, vertices, src, absoluteRect, dirtyAreaAbsolute, lookupRenderVariant(), alpha, subDivs);
}
RenderingVariant TextureMapper::lookupRenderVariant() const
{
RenderingVariant renderVariant;
if (currentRenderingAlgorithm == NEAREST_NEIGHBOR)
{
renderVariant = lookupNearestNeighborRenderVariant(bitmap);
}
else
{
renderVariant = lookupBilinearRenderVariant(bitmap);
}
return renderVariant;
}
Rect TextureMapper::getSolidRect() const
{
return Rect(0, 0, 0, 0);
}
} // namespace touchgfx

View File

@@ -0,0 +1,155 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/TiledImage.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
void TiledImage::setBitmap(const Bitmap& bmp)
{
Image::setBitmap(bmp);
// Make sure the xOffset and yOffset are correct
setOffset(xOffset, yOffset);
}
void TiledImage::setOffset(int16_t x, int16_t y)
{
setXOffset(x);
setYOffset(y);
}
void TiledImage::setXOffset(int16_t x)
{
xOffset = x;
if (bitmap.getWidth() != 0)
{
xOffset = ((xOffset % bitmap.getWidth()) + bitmap.getWidth()) % bitmap.getWidth();
}
}
void TiledImage::setYOffset(int16_t y)
{
yOffset = y;
if (bitmap.getHeight() != 0)
{
yOffset = ((yOffset % bitmap.getHeight()) + bitmap.getHeight()) % bitmap.getHeight();
}
}
void TiledImage::getOffset(int16_t& x, int16_t& y)
{
x = getXOffset();
y = getYOffset();
}
int16_t TiledImage::getXOffset()
{
return xOffset;
}
int16_t TiledImage::getYOffset()
{
return yOffset;
}
void TiledImage::draw(const Rect& invalidatedArea) const
{
uint16_t bitmapWidth = bitmap.getWidth();
uint16_t bitmapHeight = bitmap.getHeight();
if (bitmapWidth == 0 || bitmapHeight == 0)
{
return;
}
Rect meAbs;
translateRectToAbsolute(meAbs);
const int16_t minX = ((invalidatedArea.x + xOffset) / bitmapWidth) * bitmapWidth - xOffset;
const int16_t maxX = (((invalidatedArea.right() + xOffset) - 1) / bitmapWidth) * bitmapWidth;
const int16_t minY = ((invalidatedArea.y + yOffset) / bitmapHeight) * bitmapHeight - yOffset;
const int16_t maxY = (((invalidatedArea.bottom() + yOffset) - 1) / bitmapHeight) * bitmapHeight;
for (int16_t x = minX; x <= maxX; x += bitmapWidth)
{
for (int16_t y = minY; y <= maxY; y += bitmapHeight)
{
Rect dirty = Rect(x, y, bitmapWidth, bitmapHeight) & invalidatedArea;
dirty.x -= x;
dirty.y -= y;
HAL::lcd().drawPartialBitmap(bitmap, meAbs.x + x, meAbs.y + y, dirty, alpha);
}
}
}
Rect TiledImage::getSolidRect() const
{
if (alpha < 255)
{
return Rect(0, 0, 0, 0);
}
Rect solidRect = bitmap.getSolidRect();
if (solidRect.width == bitmap.getWidth())
{
solidRect.width = getWidth();
}
else
{
solidRect.x -= xOffset;
Rect solidRect2 = solidRect;
solidRect2.x += bitmap.getWidth();
if (solidRect.x < 0)
{
int16_t right = solidRect.right();
solidRect.width = MAX(right, 0);
solidRect.x = 0;
}
if (solidRect2.right() > getWidth())
{
solidRect2.width = solidRect2.right() - getWidth();
}
if (solidRect2.width > solidRect.width)
{
solidRect = solidRect2;
}
}
if (solidRect.height == bitmap.getHeight())
{
solidRect.height = getHeight();
}
else
{
solidRect.y -= yOffset;
Rect solidRect2 = solidRect;
solidRect2.y += bitmap.getHeight();
if (solidRect.y < 0)
{
int16_t bottom = solidRect.bottom();
solidRect.height = MAX(bottom, 0);
solidRect.y = 0;
}
if (solidRect2.bottom() > getHeight())
{
solidRect2.height = solidRect2.bottom() - getHeight();
}
if (solidRect2.height > solidRect.height)
{
solidRect = solidRect2;
}
}
return solidRect;
}
} // namespace touchgfx

View File

@@ -0,0 +1,52 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/ToggleButton.hpp>
namespace touchgfx
{
void ToggleButton::forceState(bool activeState)
{
if (activeState)
{
// up should equal originalPressed
if (up.getId() != originalPressed.getId())
{
down = up;
up = originalPressed;
}
}
else
{
// down should equal originalPressed
if (down.getId() != originalPressed.getId())
{
up = down;
down = originalPressed;
}
}
}
void ToggleButton::handleClickEvent(const ClickEvent& event)
{
if (pressed && (event.getType() == ClickEvent::RELEASED))
{
Bitmap tmp = up;
up = down;
down = tmp;
}
Button::handleClickEvent(event);
}
} // namespace touchgfx

View File

@@ -0,0 +1,28 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/TouchArea.hpp>
namespace touchgfx
{
void TouchArea::handleClickEvent(const ClickEvent& event)
{
AbstractButton::handleClickEvent(event);
if (pressedAction && pressedAction->isValid() && pressed)
{
pressedAction->execute(*this);
}
}
} // namespace touchgfx

View File

@@ -0,0 +1,70 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterABGR2222.hpp>
namespace touchgfx
{
void AbstractPainterABGR2222::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (renderInit())
{
do
{
uint8_t red, green, blue, alpha;
if (renderNext(red, green, blue, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
renderPixel(p, red, green, blue);
}
else
{
uint8_t ialpha = 0xFF - combinedAlpha;
uint8_t p_red = LCD8bpp_ABGR2222::getRedFromColor(*p);
uint8_t p_green = LCD8bpp_ABGR2222::getGreenFromColor(*p);
uint8_t p_blue = LCD8bpp_ABGR2222::getBlueFromColor(*p);
renderPixel(p,
LCD::div255(red * combinedAlpha + p_red * ialpha),
LCD::div255(green * combinedAlpha + p_green * ialpha),
LCD::div255(blue * combinedAlpha + p_blue * ialpha));
}
}
p++;
currentX++;
}
while (--count != 0);
}
}
void AbstractPainterABGR2222::renderPixel(uint8_t* p, uint8_t red, uint8_t green, uint8_t blue)
{
*p = LCD8bpp_ABGR2222::getColorFromRGB(red, green, blue);
}
} // namespace touchgfx

View File

@@ -0,0 +1,70 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterARGB2222.hpp>
namespace touchgfx
{
void AbstractPainterARGB2222::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (renderInit())
{
do
{
uint8_t red, green, blue, alpha;
if (renderNext(red, green, blue, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=255 on "*covers" and max alpha=255 on "widgetAlpha"
{
// Render a solid pixel
renderPixel(p, red, green, blue);
}
else
{
uint8_t ialpha = 0xFF - combinedAlpha;
uint8_t p_red = LCD8bpp_ARGB2222::getRedFromColor(*p);
uint8_t p_green = LCD8bpp_ARGB2222::getGreenFromColor(*p);
uint8_t p_blue = LCD8bpp_ARGB2222::getBlueFromColor(*p);
renderPixel(p,
LCD::div255(red * combinedAlpha + p_red * ialpha),
LCD::div255(green * combinedAlpha + p_green * ialpha),
LCD::div255(blue * combinedAlpha + p_blue * ialpha));
}
}
p++;
currentX++;
}
while (--count != 0);
}
}
void AbstractPainterARGB2222::renderPixel(uint8_t* p, uint8_t red, uint8_t green, uint8_t blue)
{
*p = LCD8bpp_ARGB2222::getColorFromRGB(red, green, blue);
}
} // namespace touchgfx

View File

@@ -0,0 +1,81 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterARGB8888.hpp>
namespace touchgfx
{
void AbstractPainterARGB8888::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + ((x + xAdjust) * 4);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (renderInit())
{
do
{
uint8_t red, green, blue, alpha;
if (renderNext(red, green, blue, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
renderPixel(reinterpret_cast<uint16_t*>(p), red, green, blue);
}
else
{
uint8_t ialpha = 0xFF - combinedAlpha;
uint8_t p_blue = p[0];
uint8_t p_green = p[1];
uint8_t p_red = p[2];
uint8_t p_alpha = p[3];
renderPixel(reinterpret_cast<uint16_t*>(p),
LCD::div255(red * combinedAlpha + p_red * ialpha),
LCD::div255(green * combinedAlpha + p_green * ialpha),
LCD::div255(blue * combinedAlpha + p_blue * ialpha),
p_alpha + combinedAlpha - LCD::div255(p_alpha * combinedAlpha));
}
}
p += 4;
currentX++;
}
while (--count != 0);
}
}
void AbstractPainterARGB8888::renderPixel(uint16_t* p, uint8_t red, uint8_t green, uint8_t blue)
{
renderPixel(p, red, green, blue, 0xFF);
}
void AbstractPainterARGB8888::renderPixel(uint16_t* p, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
{
uint8_t* p8 = reinterpret_cast<uint8_t*>(p);
p8[0] = blue;
p8[1] = green;
p8[2] = red;
p8[3] = alpha;
}
} // namespace touchgfx

View File

@@ -0,0 +1,70 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterBGRA2222.hpp>
namespace touchgfx
{
void AbstractPainterBGRA2222::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (renderInit())
{
do
{
uint8_t red, green, blue, alpha;
if (renderNext(red, green, blue, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=255 on "*covers" and max alpha=255 on "widgetAlpha"
{
// Render a solid pixel
renderPixel(p, red, green, blue);
}
else
{
uint8_t ialpha = 0xFF - combinedAlpha;
uint8_t p_red = LCD8bpp_BGRA2222::getRedFromColor(*p);
uint8_t p_green = LCD8bpp_BGRA2222::getGreenFromColor(*p);
uint8_t p_blue = LCD8bpp_BGRA2222::getBlueFromColor(*p);
renderPixel(p,
LCD::div255(red * combinedAlpha + p_red * ialpha),
LCD::div255(green * combinedAlpha + p_green * ialpha),
LCD::div255(blue * combinedAlpha + p_blue * ialpha));
}
}
p++;
currentX++;
}
while (--count != 0);
}
}
void AbstractPainterBGRA2222::renderPixel(uint8_t* p, uint8_t red, uint8_t green, uint8_t blue)
{
*p = LCD8bpp_BGRA2222::getColorFromRGB(red, green, blue);
}
} // namespace touchgfx

View File

@@ -0,0 +1,60 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/AbstractPainterBW.hpp>
namespace touchgfx
{
void AbstractPainterBW::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* /*covers*/)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
unsigned char* p = ptr + (x / 8);
if (!renderInit())
{
return;
}
do
{
uint8_t color;
if (renderNext(color))
{
unsigned pixel = 1 << (7 - (x % 8));
if (!color)
{
*p &= ~pixel;
}
else
{
*p |= pixel;
}
}
if (((++x) % 8) == 0)
{
p++;
}
currentX++;
}
while (--count);
}
} // namespace touchgfx

View File

@@ -0,0 +1,65 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD2bpp.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterGRAY2.hpp>
namespace touchgfx
{
void AbstractPainterGRAY2::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
if (renderInit())
{
do
{
uint8_t gray, alpha;
if (renderNext(gray, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
renderPixel(ptr, x, gray);
}
else
{
uint8_t p_gray = LCD2getPixel(ptr, x) * 0x55;
uint8_t ialpha = 0xFF - combinedAlpha;
renderPixel(ptr, x, LCD::div255((gray * combinedAlpha + p_gray * ialpha) * 0x55) >> 6);
}
}
currentX++;
x++;
}
while (--count != 0);
}
}
void AbstractPainterGRAY2::renderPixel(uint8_t* p, uint16_t offset, uint8_t gray)
{
LCD2setPixel(p, offset, gray);
}
} // namespace touchgfx

View File

@@ -0,0 +1,65 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD4bpp.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterGRAY4.hpp>
namespace touchgfx
{
void AbstractPainterGRAY4::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
if (renderInit())
{
do
{
uint8_t gray, alpha;
if (renderNext(gray, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
renderPixel(ptr, x, gray);
}
else
{
uint8_t p_gray = LCD4getPixel(ptr, x);
uint8_t ialpha = 0xFF - combinedAlpha;
renderPixel(ptr, x, LCD::div255((gray * combinedAlpha + p_gray * ialpha) * 0x11) >> 4);
}
}
currentX++;
x++;
}
while (--count != 0);
}
}
void AbstractPainterGRAY4::renderPixel(uint8_t* p, uint16_t offset, uint8_t gray)
{
LCD4setPixel(p, offset, gray & 0x0F);
}
} // namespace touchgfx

View File

@@ -0,0 +1,70 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterRGB565.hpp>
namespace touchgfx
{
void AbstractPainterRGB565::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint16_t* p = reinterpret_cast<uint16_t*>(ptr) + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (renderInit())
{
do
{
uint8_t red, green, blue, alpha;
if (renderNext(red, green, blue, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
renderPixel(p, red, green, blue);
}
else
{
uint8_t ialpha = 0xFF - combinedAlpha;
uint8_t p_red = (*p & RMASK) >> 8;
uint8_t p_green = (*p & GMASK) >> 3;
uint8_t p_blue = (*p & BMASK) << 3;
renderPixel(p,
LCD::div255(red * combinedAlpha + p_red * ialpha),
LCD::div255(green * combinedAlpha + p_green * ialpha),
LCD::div255(blue * combinedAlpha + p_blue * ialpha));
}
}
p++;
currentX++;
}
while (--count != 0);
}
}
void AbstractPainterRGB565::renderPixel(uint16_t* p, uint8_t red, uint8_t green, uint8_t blue)
{
*p = ((red << 8) & RMASK) | ((green << 3) & GMASK) | ((blue >> 3) & BMASK);
}
} // namespace touchgfx

View File

@@ -0,0 +1,73 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterRGB888.hpp>
namespace touchgfx
{
void AbstractPainterRGB888::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + ((x + xAdjust) * 3);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (renderInit())
{
do
{
uint8_t red, green, blue, alpha;
if (renderNext(red, green, blue, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
renderPixel(reinterpret_cast<uint16_t*>(p), red, green, blue);
}
else
{
uint8_t ialpha = 0xFF - combinedAlpha;
uint8_t p_blue = p[0];
uint8_t p_green = p[1];
uint8_t p_red = p[2];
renderPixel(reinterpret_cast<uint16_t*>(p),
LCD::div255(red * combinedAlpha + p_red * ialpha),
LCD::div255(green * combinedAlpha + p_green * ialpha),
LCD::div255(blue * combinedAlpha + p_blue * ialpha));
}
}
p += 3;
currentX++;
}
while (--count != 0);
}
}
void AbstractPainterRGB888::renderPixel(uint16_t* p, uint8_t red, uint8_t green, uint8_t blue)
{
uint8_t* p8 = reinterpret_cast<uint8_t*>(p);
p8[0] = blue;
p8[1] = green;
p8[2] = red;
}
} // namespace touchgfx

View File

@@ -0,0 +1,70 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/AbstractPainterRGBA2222.hpp>
namespace touchgfx
{
void AbstractPainterRGBA2222::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (renderInit())
{
do
{
uint8_t red, green, blue, alpha;
if (renderNext(red, green, blue, alpha))
{
uint8_t combinedAlpha = LCD::div255((*covers) * LCD::div255(alpha * widgetAlpha));
covers++;
if (combinedAlpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
renderPixel(p, red, green, blue);
}
else
{
uint8_t ialpha = 0xFF - combinedAlpha;
uint8_t p_red = LCD8bpp_RGBA2222::getRedFromColor(*p);
uint8_t p_green = LCD8bpp_RGBA2222::getGreenFromColor(*p);
uint8_t p_blue = LCD8bpp_RGBA2222::getBlueFromColor(*p);
renderPixel(p,
LCD::div255(red * combinedAlpha + p_red * ialpha),
LCD::div255(green * combinedAlpha + p_green * ialpha),
LCD::div255(blue * combinedAlpha + p_blue * ialpha));
}
}
p++;
currentX++;
}
while (--count != 0);
}
}
void AbstractPainterRGBA2222::renderPixel(uint8_t* p, uint8_t red, uint8_t green, uint8_t blue)
{
*p = LCD8bpp_RGBA2222::getColorFromRGB(red, green, blue);
}
} // namespace touchgfx

View File

@@ -0,0 +1,88 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/AbstractShape.hpp>
#include <touchgfx/widgets/canvas/Canvas.hpp>
namespace touchgfx
{
AbstractShape::AbstractShape() : CanvasWidget(),
dx(0), dy(0), shapeAngle(0),
xScale(CWRUtil::toQ10<int>(1)), yScale(CWRUtil::toQ10<int>(1)),
minimalRect(Rect())
{
Drawable::setWidth(0);
Drawable::setHeight(0);
}
bool AbstractShape::drawCanvasWidget(const Rect& invalidatedArea) const
{
Canvas canvas(this, invalidatedArea);
int numPoints = getNumPoints();
if (numPoints == 0)
{
return true;
}
canvas.moveTo(getCacheX(0), getCacheY(0));
for (int i = 1; i < numPoints; i++)
{
canvas.lineTo(getCacheX(i), getCacheY(i));
}
return canvas.render();
}
void AbstractShape::updateAbstractShapeCache()
{
int numPoints = getNumPoints();
int xMin = 0;
int xMax = 0;
int yMin = 0;
int yMax = 0;
for (int i = 0; i < numPoints; i++)
{
CWRUtil::Q5 xCorner = getCornerX(i);
CWRUtil::Q5 yCorner = getCornerY(i);
CWRUtil::Q5 xCache = dx + ((CWRUtil::mulQ5(xCorner, xScale) * CWRUtil::cosine(shapeAngle))) - ((CWRUtil::mulQ5(yCorner, yScale) * CWRUtil::sine(shapeAngle)));
if (i == 0 || xCache.to<int>() > xMax)
{
xMax = xCache.to<int>();
}
if (i == 0 || xCache.to<int>() < xMin)
{
xMin = xCache.to<int>();
}
CWRUtil::Q5 yCache = dy + ((CWRUtil::mulQ5(yCorner, yScale) * CWRUtil::cosine(shapeAngle))) + ((CWRUtil::mulQ5(xCorner, xScale) * CWRUtil::sine(shapeAngle)));
if (i == 0 || yCache.to<int>() > yMax)
{
yMax = yCache.to<int>();
}
if (i == 0 || yCache.to<int>() < yMin)
{
yMin = yCache.to<int>();
}
setCache(i, xCache, yCache);
}
minimalRect = Rect(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);
}
Rect AbstractShape::getMinimalRect() const
{
return minimalRect;
}
} // namespace touchgfx

View File

@@ -0,0 +1,275 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/Canvas.hpp>
namespace touchgfx
{
Canvas::Canvas(const CanvasWidget* _widget, const Rect& invalidatedArea)
: widget(_widget),
enoughMemory(false), penUp(true), penHasBeenDown(false), previousOutside(0), penDownOutside(0)
{
assert(CanvasWidgetRenderer::hasBuffer() && "No buffer allocated for CanvasWidgetRenderer drawing");
assert(Rasterizer::POLY_BASE_SHIFT == 5 && "CanvasWidget assumes Q5 but Rasterizer uses a different setting");
// Area to redraw (relative coordinates)
Rect dirtyArea = Rect(0, 0, widget->getWidth(), widget->getHeight()) & invalidatedArea;
// Absolute position of the scalableImage.
Rect dirtyAreaAbsolute = dirtyArea;
widget->translateRectToAbsolute(dirtyAreaAbsolute);
// Transform rects to match framebuffer coordinates
// This is needed if the display is rotated compared to the framebuffer
DisplayTransformation::transformDisplayToFrameBuffer(dirtyArea, widget->getRect());
DisplayTransformation::transformDisplayToFrameBuffer(dirtyAreaAbsolute);
// Re-size buffers for optimum memory buffer layout.
enoughMemory = CanvasWidgetRenderer::setScanlineWidth(dirtyArea.width);
ras.reset();
offsetX = dirtyArea.x;
offsetY = dirtyArea.y;
invalidatedAreaX = CWRUtil::toQ5<int>(dirtyArea.x);
invalidatedAreaY = CWRUtil::toQ5<int>(dirtyArea.y);
invalidatedAreaWidth = CWRUtil::toQ5<int>(dirtyArea.width);
invalidatedAreaHeight = CWRUtil::toQ5<int>(dirtyArea.height);
// Create the rendering buffer
uint8_t* RESTRICT buf = reinterpret_cast<uint8_t*>(HAL::getInstance()->lockFrameBuffer());
int stride = HAL::lcd().framebufferStride();
uint8_t offset = 0;
switch (HAL::lcd().framebufferFormat())
{
case Bitmap::BW:
buf += (dirtyAreaAbsolute.x / 8) + dirtyAreaAbsolute.y * stride;
offset = dirtyAreaAbsolute.x % 8;
break;
case Bitmap::GRAY2:
buf += (dirtyAreaAbsolute.x / 4) + dirtyAreaAbsolute.y * stride;
offset = dirtyAreaAbsolute.x % 4;
break;
case Bitmap::GRAY4:
buf += (dirtyAreaAbsolute.x / 2) + dirtyAreaAbsolute.y * stride;
offset = dirtyAreaAbsolute.x % 2;
break;
case Bitmap::RGB565:
buf += dirtyAreaAbsolute.x * 2 + dirtyAreaAbsolute.y * stride;
break;
case Bitmap::RGB888:
buf += dirtyAreaAbsolute.x * 3 + dirtyAreaAbsolute.y * stride;
break;
case Bitmap::RGBA2222:
case Bitmap::BGRA2222:
case Bitmap::ARGB2222:
case Bitmap::ABGR2222:
case Bitmap::L8:
buf += dirtyAreaAbsolute.x + dirtyAreaAbsolute.y * stride;
break;
case Bitmap::ARGB8888:
buf += dirtyAreaAbsolute.x * 4 + dirtyAreaAbsolute.y * stride;
break;
case Bitmap::BW_RLE:
case Bitmap::A4:
assert(0 && "Unsupported bit depth");
break;
}
ras.setMaxRenderY(dirtyAreaAbsolute.height);
rbuf.attach(buf, offset, dirtyAreaAbsolute.width, dirtyAreaAbsolute.height, stride);
}
Canvas::~Canvas()
{
HAL::getInstance()->unlockFrameBuffer(); //lint !e1551
}
void Canvas::moveTo(CWRUtil::Q5 x, CWRUtil::Q5 y)
{
if (!enoughMemory)
{
return;
}
if (!penUp)
{
close();
}
transformFrameBufferToDisplay(x, y);
x = x - invalidatedAreaX;
y = y - invalidatedAreaY;
uint8_t outside = isOutside(x, y, invalidatedAreaWidth, invalidatedAreaHeight);
if (outside)
{
penUp = true;
}
else
{
penDownOutside = outside;
ras.moveTo(x, y);
penUp = false;
penHasBeenDown = true;
}
initialX = x;
initialY = y;
previousX = x;
previousY = y;
previousOutside = outside;
}
void Canvas::lineTo(CWRUtil::Q5 x, CWRUtil::Q5 y)
{
if (!enoughMemory)
{
return;
}
transformFrameBufferToDisplay(x, y);
x = x - invalidatedAreaX;
y = y - invalidatedAreaY;
uint8_t outside = isOutside(x, y, invalidatedAreaWidth, invalidatedAreaHeight);
if (!previousOutside)
{
ras.lineTo(x, y);
}
else
{
if (!outside || !(previousOutside & outside))
{
// x,y is inside, or on another side compared to previous
if (penUp)
{
penDownOutside = previousOutside;
ras.moveTo(previousX, previousY);
penUp = false;
penHasBeenDown = true;
}
else
{
ras.lineTo(previousX, previousY);
}
ras.lineTo(x, y);
}
else
{
// Restrict "outside" to the same side as previous point.
outside &= previousOutside;
}
}
previousX = x;
previousY = y;
previousOutside = outside;
}
bool Canvas::render()
{
// If the invalidated rect is too wide compared to the allocated buffer for CWR,
// redrawing will not help. The CanvasWidget needs to know about this situation
// and maybe try to divide the area vertically instead, but this has not been
// implemented. And probably should not.
if (!enoughMemory)
{
return true; // Redrawing a rect with fewer scanlines will not help, fake "ok" to move on
}
if (ras.wasOutlineTooComplex())
{
return false; // Try again with fewer scanlines
}
if (!penHasBeenDown)
{
return true; // Nothing drawn. Done
}
if (widget->getAlpha() == 0)
{
return true; // Invisible. Done
}
close();
widget->getPainter().setOffset(offsetX /*+widget->getX()*/, offsetY /*+widget->getY()*/);
widget->getPainter().setWidgetAlpha(widget->getAlpha());
Renderer renderer(rbuf, widget->getPainter());
return ras.render(renderer);
}
uint8_t Canvas::isOutside(const CWRUtil::Q5& x, const CWRUtil::Q5& y, const CWRUtil::Q5& width, const CWRUtil::Q5& height) const
{
uint8_t outside = 0;
// Find out if (x,y) is above/below of current area
if (y < 0)
{
outside = POINT_IS_ABOVE;
}
else if (y >= height)
{
outside = POINT_IS_BELOW;
}
// Find out if (x,y) is left/right of current area
if (x < 0)
{
outside |= POINT_IS_LEFT;
}
else if (x >= width)
{
outside |= POINT_IS_RIGHT;
}
return outside;
}
void Canvas::transformFrameBufferToDisplay(CWRUtil::Q5& x, CWRUtil::Q5& y) const
{
switch (HAL::DISPLAY_ROTATION)
{
case rotate0:
break;
case rotate90:
CWRUtil::Q5 tmpY = y;
y = CWRUtil::toQ5<int>(widget->getWidth()) - x;
x = tmpY;
break;
}
}
void Canvas::close()
{
if (!penUp)
{
if (previousOutside & penDownOutside)
{
// We are outside on the same side as we started. No need
// to close the path, CWR will do this for us.
//lineTo(penDownX, penDownY);
}
else
{
if (previousOutside)
{
ras.lineTo(previousX, previousY);
}
ras.lineTo(initialX, initialY);
}
}
penUp = false;
}
} // namespace touchgfx

View File

@@ -0,0 +1,141 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/CanvasWidget.hpp>
namespace touchgfx
{
CanvasWidget::CanvasWidget() :
Widget(),
canvasPainter(0),
maxRenderLines(0x7FFF),
alpha(255)
{
}
void CanvasWidget::setPainter(AbstractPainter& painter)
{
canvasPainter = &painter;
}
AbstractPainter& CanvasWidget::getPainter() const
{
assert(canvasPainter != 0 && "No painter set");
return *canvasPainter; //lint !e613
} //lint !e1763
void CanvasWidget::draw(const Rect& invalidatedArea) const
{
Rect area = invalidatedArea;
int16_t* offset;
int16_t* lines;
int16_t* width;
int16_t* height;
int16_t wantedRenderLines;
switch (HAL::DISPLAY_ROTATION)
{
default:
case rotate0:
offset = &area.y;
lines = &area.height;
width = &area.width;
height = &wantedRenderLines;
break;
case rotate90:
offset = &area.x;
lines = &area.width;
width = &wantedRenderLines;
height = &area.height;
break;
}
Rect minimalRect = getMinimalRect();
bool failedAtLeastOnce = false;
while (*lines)
{
wantedRenderLines = MIN(maxRenderLines, *lines);
while (wantedRenderLines > 0)
{
Rect smallArea(area.x, area.y, *width, *height);
if (!smallArea.intersect(minimalRect))
{
break;
}
if (drawCanvasWidget(smallArea))
{
break;
}
#ifdef SIMULATOR
if (CanvasWidgetRenderer::getWriteMemoryUsageReport())
{
if (wantedRenderLines > 1)
{
touchgfx_printf("CWR will split draw into multiple draws due to limited memory.\n");
}
else
{
touchgfx_printf("CWR was unable to complete a draw operation due to limited memory.\n");
}
}
#endif
wantedRenderLines >>= 1;
failedAtLeastOnce = true;
}
if (wantedRenderLines == 0)
{
// We did not manage to draw anything. Set wantedHeight to
// one to skip a single raster line and try to render the
// rest of the CanvasWidget.
wantedRenderLines = 1;
}
else
{
if (failedAtLeastOnce && maxRenderLines == 0x7FFF)
{
// Only adjust maxRenderLines if it is the first draw for the CanvasWidget
maxRenderLines = wantedRenderLines;
}
}
*offset += wantedRenderLines;
*lines -= wantedRenderLines;
}
if (maxRenderLines == 0x7FFF)
{
maxRenderLines--; // 0x7FFF means first draw
}
}
void CanvasWidget::invalidate() const
{
Rect minimalRect = getMinimalRect();
minimalRect.intersect(CanvasWidget::getMinimalRect());
invalidateRect(minimalRect);
}
Rect CanvasWidget::getMinimalRect() const
{
return Rect(0, 0, getWidth(), getHeight());
}
Rect CanvasWidget::getSolidRect() const
{
return Rect(0, 0, 0, 0);
}
}

View File

@@ -0,0 +1,436 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/Circle.hpp>
namespace touchgfx
{
Circle::Circle() : CanvasWidget(),
circleCenterX(0), circleCenterY(0), circleRadius(0),
circleArcAngleStart(CWRUtil::toQ5<int>(0)), circleArcAngleEnd(CWRUtil::toQ5<int>(360)),
circleLineWidth(0), circleArcIncrement(5),
circleCapArcIncrement(180)
{
Drawable::setWidth(0);
Drawable::setHeight(0);
}
void Circle::setPrecision(int precision)
{
if (precision < 1)
{
precision = 1;
}
if (precision > 120)
{
precision = 120;
}
circleArcIncrement = precision;
}
int Circle::getPrecision() const
{
return circleArcIncrement;
}
void Circle::setCapPrecision(int precision)
{
if (precision < 1)
{
precision = 1;
}
if (precision > 180)
{
precision = 180;
}
circleCapArcIncrement = precision;
}
int Circle::getCapPrecision() const
{
return circleCapArcIncrement;
}
bool Circle::drawCanvasWidget(const Rect& invalidatedArea) const
{
CWRUtil::Q5 arcStart = circleArcAngleStart;
CWRUtil::Q5 arcEnd = circleArcAngleEnd;
CWRUtil::Q5 _360 = CWRUtil::toQ5<int>(360);
// Put start before end by swapping
if (arcStart > arcEnd)
{
CWRUtil::Q5 tmp = arcStart;
arcStart = arcEnd;
arcEnd = tmp;
}
if ((arcEnd - arcStart) >= _360)
{
// The entire circle has to be drawn
arcStart = CWRUtil::toQ5<int>(0);
arcEnd = _360;
}
if (circleLineWidth != 0)
{
// Check if invalidated area is completely inside the circle
int32_t x1 = int(CWRUtil::toQ5(invalidatedArea.x)); // Take the corners of the invalidated area
int32_t x2 = int(CWRUtil::toQ5(invalidatedArea.right()));
int32_t y1 = int(CWRUtil::toQ5(invalidatedArea.y));
int32_t y2 = int(CWRUtil::toQ5(invalidatedArea.bottom()));
int32_t dx1 = abs(int(circleCenterX) - x1); // Find distances between each corner and circle center
int32_t dx2 = abs(int(circleCenterX) - x2);
int32_t dy1 = abs(int(circleCenterY) - y1);
int32_t dy2 = abs(int(circleCenterY) - y2);
int32_t dx = CWRUtil::Q5(MAX(dx1, dx2)).to<int>() + 1; // Largest hor/vert distance (round up)
int32_t dy = CWRUtil::Q5(MAX(dy1, dy2)).to<int>() + 1;
int32_t dsqr = (dx * dx) + (dy * dy); // Pythagoras
// From https://www.mathopenref.com/polygonincircle.html
int32_t rmin = ((circleRadius - (circleLineWidth / 2)) * CWRUtil::cosine((circleArcIncrement + 1) / 2)).to<int>();
// Check if invalidatedArea is completely inside circle
if (dsqr < rmin * rmin)
{
return true;
}
}
Canvas canvas(this, invalidatedArea);
CWRUtil::Q5 radius = circleRadius;
CWRUtil::Q5 lineWidth = circleLineWidth;
if (circleLineWidth > circleRadius * 2)
{
lineWidth = (circleRadius + circleLineWidth / 2);
radius = lineWidth / 2;
}
CWRUtil::Q5 arc = arcStart;
CWRUtil::Q5 circleArcIncrementQ5 = CWRUtil::toQ5<int>(circleArcIncrement);
moveToAR2(canvas, arc, (radius * 2) + lineWidth);
CWRUtil::Q5 nextArc = CWRUtil::Q5(ROUNDUP((int)(arc + CWRUtil::toQ5<int>(1)), (int)circleArcIncrementQ5));
while (nextArc <= arcEnd)
{
arc = nextArc;
lineToAR2(canvas, arc, (radius * 2) + lineWidth);
nextArc = nextArc + circleArcIncrementQ5;
}
if (arc < arcEnd)
{
// "arc" is not updated. It is the last arc in steps of "circleArcIncrement"
lineToAR2(canvas, arcEnd, (radius * 2) + lineWidth);
}
if (lineWidth == CWRUtil::toQ5<int>(0))
{
// Draw a filled circle / pie / pacman
if (arcEnd - arcStart < _360)
{
// Not a complete circle, line to center
canvas.lineTo(circleCenterX, circleCenterY);
}
}
else
{
CWRUtil::Q5 circleCapArcIncrementQ5 = CWRUtil::toQ5<int>(circleCapArcIncrement);
CWRUtil::Q5 _180 = CWRUtil::toQ5<int>(180);
if (arcEnd - arcStart < _360)
{
// Draw the circle cap
CWRUtil::Q5 capX = circleCenterX + (radius * CWRUtil::sine(arcEnd));
CWRUtil::Q5 capY = circleCenterY - (radius * CWRUtil::cosine(arcEnd));
for (CWRUtil::Q5 capAngle = arcEnd + circleCapArcIncrementQ5; capAngle < arcEnd + _180; capAngle = capAngle + circleCapArcIncrementQ5)
{
lineToXYAR2(canvas, capX, capY, capAngle, lineWidth);
}
}
// Not a filled circle, draw the path on the inside of the circle
if (arc < arcEnd)
{
lineToAR2(canvas, arcEnd, (radius * 2) - lineWidth);
}
nextArc = arc;
while (nextArc >= arcStart)
{
arc = nextArc;
lineToAR2(canvas, arc, (radius * 2) - lineWidth);
nextArc = nextArc - circleArcIncrementQ5;
}
if (arc > arcStart)
{
lineToAR2(canvas, arcStart, (radius * 2) - lineWidth);
}
if (arcEnd - arcStart < _360)
{
// Draw the circle cap
CWRUtil::Q5 capX = circleCenterX + (radius * CWRUtil::sine(arcStart));
CWRUtil::Q5 capY = circleCenterY - (radius * CWRUtil::cosine(arcStart));
for (CWRUtil::Q5 capAngle = arcStart - _180 + circleCapArcIncrementQ5; capAngle < arcStart; capAngle = capAngle + circleCapArcIncrementQ5)
{
lineToXYAR2(canvas, capX, capY, capAngle, lineWidth);
}
}
}
return canvas.render();
}
Rect Circle::getMinimalRect() const
{
return getMinimalRect(circleArcAngleStart, circleArcAngleEnd);
}
Rect Circle::getMinimalRect(int16_t arcStart, int16_t arcEnd) const
{
return getMinimalRect(CWRUtil::toQ5<int>(arcStart), CWRUtil::toQ5<int>(arcEnd));
}
Rect Circle::getMinimalRect(CWRUtil::Q5 arcStart, CWRUtil::Q5 arcEnd) const
{
CWRUtil::Q5 xMin = CWRUtil::toQ5<int>(getWidth());
CWRUtil::Q5 xMax = CWRUtil::toQ5<int>(0);
CWRUtil::Q5 yMin = CWRUtil::toQ5<int>(getHeight());
CWRUtil::Q5 yMax = CWRUtil::toQ5<int>(0);
calculateMinimalRect(arcStart, arcEnd, xMin, xMax, yMin, yMax);
return Rect(xMin.to<int>() - 1, yMin.to<int>() - 1,
xMax.to<int>() - xMin.to<int>() + 2, yMax.to<int>() - yMin.to<int>() + 2);
}
void Circle::moveToAR2(Canvas& canvas, const CWRUtil::Q5& angle, const CWRUtil::Q5& r2) const
{
canvas.moveTo(circleCenterX + ((r2 * CWRUtil::sine(angle)) / 2), circleCenterY - ((r2 * CWRUtil::cosine(angle)) / 2));
}
void Circle::lineToAR2(Canvas& canvas, const CWRUtil::Q5& angle, const CWRUtil::Q5& r2) const
{
lineToXYAR2(canvas, circleCenterX, circleCenterY, angle, r2);
}
void Circle::lineToXYAR2(Canvas& canvas, const CWRUtil::Q5& x, const CWRUtil::Q5& y, const CWRUtil::Q5& angle, const CWRUtil::Q5& r2) const
{
canvas.lineTo(x + ((r2 * CWRUtil::sine(angle)) / 2), y - ((r2 * CWRUtil::cosine(angle)) / 2));
}
void Circle::updateMinMaxAR(const CWRUtil::Q5& a, const CWRUtil::Q5& r2, CWRUtil::Q5& xMin, CWRUtil::Q5& xMax, CWRUtil::Q5& yMin, CWRUtil::Q5& yMax) const
{
CWRUtil::Q5 xNew = circleCenterX + ((r2 * CWRUtil::sine(a)) / 2);
CWRUtil::Q5 yNew = circleCenterY - ((r2 * CWRUtil::cosine(a)) / 2);
updateMinMaxXY(xNew, yNew, xMin, xMax, yMin, yMax);
}
void Circle::updateMinMaxXY(const CWRUtil::Q5& xNew, const CWRUtil::Q5& yNew, CWRUtil::Q5& xMin, CWRUtil::Q5& xMax, CWRUtil::Q5& yMin, CWRUtil::Q5& yMax) const
{
if (xNew < xMin)
{
xMin = xNew;
}
if (xNew > xMax)
{
xMax = xNew;
}
if (yNew < yMin)
{
yMin = yNew;
}
if (yNew > yMax)
{
yMax = yNew;
}
}
void Circle::calculateMinimalRect(CWRUtil::Q5 arcStart, CWRUtil::Q5 arcEnd, CWRUtil::Q5& xMin, CWRUtil::Q5& xMax, CWRUtil::Q5& yMin, CWRUtil::Q5& yMax) const
{
// Put start before end by swapping
if (arcStart > arcEnd)
{
CWRUtil::Q5 tmp = arcStart;
arcStart = arcEnd;
arcEnd = tmp;
}
CWRUtil::Q5 _90 = CWRUtil::toQ5<int>(90);
CWRUtil::Q5 _360 = CWRUtil::toQ5<int>(360);
if ((arcEnd - arcStart) >= _360)
{
// The entire circle has to be drawn
arcStart = CWRUtil::toQ5<int>(0);
arcEnd = _360;
}
// Check start angle
updateMinMaxAR(arcStart, (circleRadius * 2) + circleLineWidth, xMin, xMax, yMin, yMax);
// Here we have a up to 4 approximation steps on angles divisible by 90
CWRUtil::Q5 i;
for (i = CWRUtil::Q5(ROUNDUP((int)(arcStart + CWRUtil::toQ5<int>(1)), (int)_90)); i <= arcEnd; i = i + _90)
{
updateMinMaxAR(i, (circleRadius * 2) + circleLineWidth, xMin, xMax, yMin, yMax);
}
// Check end angle
if ((i - _90) < arcEnd)
{
updateMinMaxAR(arcEnd, (circleRadius * 2) + circleLineWidth, xMin, xMax, yMin, yMax);
}
if (circleLineWidth == CWRUtil::toQ5<int>(0))
{
// A filled circle / pie / pacman
if ((arcEnd - arcStart) < _360)
{
// Not a complete circle, check center
updateMinMaxAR(CWRUtil::toQ5<int>(0), CWRUtil::toQ5<int>(0), xMin, xMax, yMin, yMax);
}
}
else
{
// Not a filled circle, check the inside of the circle. Only start and/or end can cause new min/max values
updateMinMaxAR(arcStart, (circleRadius * 2) - circleLineWidth, xMin, xMax, yMin, yMax);
updateMinMaxAR(arcEnd, (circleRadius * 2) - circleLineWidth, xMin, xMax, yMin, yMax);
}
// Check if circle cap extends the min/max further
if ((circleCapArcIncrement < 180) && (arcEnd - arcStart < _360))
{
// Round caps
CWRUtil::Q5 capX = circleCenterX + (circleRadius * CWRUtil::sine(arcStart));
CWRUtil::Q5 capY = circleCenterY - (circleRadius * CWRUtil::cosine(arcStart));
updateMinMaxXY(capX - (circleLineWidth / 2), capY - (circleLineWidth / 2), xMin, xMax, yMin, yMax);
updateMinMaxXY(capX + (circleLineWidth / 2), capY + (circleLineWidth / 2), xMin, xMax, yMin, yMax);
capX = circleCenterX + (circleRadius * CWRUtil::sine(arcEnd));
capY = circleCenterY - (circleRadius * CWRUtil::cosine(arcEnd));
updateMinMaxXY(capX - (circleLineWidth / 2), capY - (circleLineWidth / 2), xMin, xMax, yMin, yMax);
updateMinMaxXY(capX + (circleLineWidth / 2), capY + (circleLineWidth / 2), xMin, xMax, yMin, yMax);
}
}
touchgfx::Rect Circle::getMinimalRectForUpdatedStartAngle(const CWRUtil::Q5& startAngleQ5) const
{
CWRUtil::Q5 minAngle = CWRUtil::Q5(0); // Unused default value
CWRUtil::Q5 maxAngle = CWRUtil::Q5(0); // Unused default value
int circleArcIncrementQ5int = (int)CWRUtil::toQ5<int>(circleArcIncrement);
if (circleArcAngleStart < circleArcAngleEnd)
{
// start is smaller than end
if (startAngleQ5 < circleArcAngleStart)
{
// start moved even lower
minAngle = startAngleQ5;
maxAngle = CWRUtil::Q5(ROUNDUP((int)circleArcAngleStart, circleArcIncrementQ5int));
maxAngle = MIN(maxAngle, circleArcAngleEnd); // No need to go higher than end
}
else if (startAngleQ5 < circleArcAngleEnd)
{
// start moved higher, but not higher than end
minAngle = circleArcAngleStart;
maxAngle = CWRUtil::Q5(ROUNDUP((int)startAngleQ5, circleArcIncrementQ5int));
maxAngle = MIN(maxAngle, circleArcAngleEnd); // No need to go higher than end
}
else
{
// start moved past end
minAngle = circleArcAngleStart;
maxAngle = startAngleQ5;
}
}
else
{
// start is higher than end
if (startAngleQ5 > circleArcAngleStart)
{
// start moved even higher
minAngle = CWRUtil::Q5(ROUNDDOWN((int)circleArcAngleStart, circleArcIncrementQ5int));
minAngle = MAX(minAngle, circleArcAngleEnd); // No need to go lower then end
maxAngle = startAngleQ5;
}
else if (startAngleQ5 > circleArcAngleEnd)
{
// start moved lower, but not lower than end
minAngle = CWRUtil::Q5(ROUNDDOWN((int)startAngleQ5, circleArcIncrementQ5int));
minAngle = MAX(minAngle, circleArcAngleEnd); // No need to go lower than end
maxAngle = circleArcAngleStart;
}
else
{
// start moved lower past end
minAngle = startAngleQ5;
maxAngle = circleArcAngleStart;
}
}
return getMinimalRect(minAngle, maxAngle);
}
touchgfx::Rect Circle::getMinimalRectForUpdatedEndAngle(const CWRUtil::Q5& endAngleQ5) const
{
CWRUtil::Q5 minAngle = CWRUtil::Q5(0); // Unused default value
CWRUtil::Q5 maxAngle = CWRUtil::Q5(0); // Unused default value
int circleArcIncrementQ5int = (int)CWRUtil::toQ5<int>(circleArcIncrement);
if (circleArcAngleStart < circleArcAngleEnd)
{
// start is smaller than end
if (endAngleQ5 > circleArcAngleEnd)
{
// end moved even higher
minAngle = CWRUtil::Q5(ROUNDDOWN((int)circleArcAngleEnd, circleArcIncrementQ5int));
minAngle = MAX(minAngle, circleArcAngleStart);
maxAngle = endAngleQ5;
}
else if (endAngleQ5 > circleArcAngleStart)
{
// end moved lower, but not past start
minAngle = CWRUtil::Q5(ROUNDDOWN((int)endAngleQ5, circleArcIncrementQ5int));
minAngle = MAX(minAngle, circleArcAngleStart); // No need to go lower than start
maxAngle = circleArcAngleEnd;
}
else
{
// end move past start
minAngle = endAngleQ5;
maxAngle = circleArcAngleEnd;
}
}
else
{
// start is higher than end
if (endAngleQ5 < circleArcAngleEnd)
{
// end moved even lower
minAngle = endAngleQ5;
maxAngle = CWRUtil::Q5(ROUNDUP((int)circleArcAngleEnd, circleArcIncrementQ5int));
maxAngle = MIN(maxAngle, circleArcAngleStart); // No need to go higher than start
}
else if (endAngleQ5 < circleArcAngleStart)
{
// end moved higher, but not higher than start
minAngle = circleArcAngleEnd;
maxAngle = CWRUtil::Q5(ROUNDUP((int)endAngleQ5, circleArcIncrementQ5int));
maxAngle = MIN(maxAngle, circleArcAngleStart);
}
else
{
// end moved past start
minAngle = circleArcAngleEnd;
maxAngle = endAngleQ5;
}
}
return getMinimalRect(minAngle, maxAngle);
}
} // namespace touchgfx

View File

@@ -0,0 +1,285 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/Line.hpp>
namespace touchgfx
{
Line::Line() : CanvasWidget(),
x1(0), y1(0), x2(0), y2(0),
lineWidth(CWRUtil::toQ5<int>(1)),
lineEnding(BUTT_CAP_ENDING),
lineCapArcIncrement(18)
{
Drawable::setWidth(0);
Drawable::setHeight(0);
}
void Line::setStart(CWRUtil::Q5 xQ5, CWRUtil::Q5 yQ5)
{
if (x1 == xQ5 && y1 == yQ5)
{
return;
}
x1 = xQ5;
y1 = yQ5;
updateCachedShape();
}
void Line::updateStart(CWRUtil::Q5 xQ5, CWRUtil::Q5 yQ5)
{
if (x1 == xQ5 && y1 == yQ5)
{
return;
}
Rect rectBefore = getMinimalRect();
x1 = xQ5;
y1 = yQ5;
updateCachedShape();
Rect rectAfter = getMinimalRect();
rectBefore.expandToFit(rectAfter);
invalidateRect(rectBefore);
}
void Line::setEnd(CWRUtil::Q5 xQ5, CWRUtil::Q5 yQ5)
{
if (x2 == xQ5 && y2 == yQ5)
{
return;
}
x2 = xQ5;
y2 = yQ5;
updateCachedShape();
}
void Line::updateEnd(CWRUtil::Q5 xQ5, CWRUtil::Q5 yQ5)
{
if (x2 == xQ5 && y2 == yQ5)
{
return;
}
Rect rectBefore = getMinimalRect();
x2 = xQ5;
y2 = yQ5;
updateCachedShape();
Rect rectAfter = getMinimalRect();
rectBefore.expandToFit(rectAfter);
invalidateRect(rectBefore);
}
void Line::setLineEndingStyle(Line::LINE_ENDING_STYLE lineEndingStyle)
{
lineEnding = lineEndingStyle;
updateCachedShape();
}
Line::LINE_ENDING_STYLE Line::getLineEndingStyle() const
{
return lineEnding;
}
void Line::setCapPrecision(int precision)
{
if (precision < 1)
{
precision = 1;
}
if (precision > 180)
{
precision = 180;
}
lineCapArcIncrement = precision;
}
bool Line::drawCanvasWidget(const Rect& invalidatedArea) const
{
Canvas canvas(this, invalidatedArea);
CWRUtil::Q5 radius;
int angleInDegrees = CWRUtil::angle(xCorner[0] - x1, yCorner[0] - y1, radius);
canvas.moveTo(xCorner[0], yCorner[0]);
canvas.lineTo(xCorner[1], yCorner[1]);
if (lineEnding == ROUND_CAP_ENDING)
{
// Fixed 10 steps (steps 0 and 9 are at Corner[1] and [2])
for (int i = lineCapArcIncrement; i < 180; i += lineCapArcIncrement)
{
canvas.lineTo(x2 + radius * CWRUtil::sine(angleInDegrees - i), y2 - radius * CWRUtil::cosine(angleInDegrees - i));
}
}
canvas.lineTo(xCorner[2], yCorner[2]);
canvas.lineTo(xCorner[3], yCorner[3]);
if (lineEnding == ROUND_CAP_ENDING)
{
// Fixed 10 steps (steps 0 and 9 are at Corner[3] and [0])
for (int i = 180 - lineCapArcIncrement; i > 0; i -= lineCapArcIncrement)
{
canvas.lineTo(x1 + radius * CWRUtil::sine(angleInDegrees + i), y1 - radius * CWRUtil::cosine(angleInDegrees + i));
}
}
return canvas.render();
}
void Line::updateCachedShape()
{
CWRUtil::Q5 dx = x2 - x1;
CWRUtil::Q5 dy = y2 - y1;
CWRUtil::Q5 d = CWRUtil::toQ5<int>(0);
// Look for horizontal, vertical or no-line
if ((int32_t)dx == 0)
{
if ((int32_t)dy == 0)
{
xCorner[0] = xCorner[1] = xCorner[2] = xCorner[3] = x1;
yCorner[0] = yCorner[1] = yCorner[2] = yCorner[3] = y1;
return;
}
d = abs(dy);
}
else if ((int32_t)dy == 0)
{
d = abs(dx);
}
else
{
// We want to hit as close to the limit inside 32bits.
// sqrt(0x7FFFFFFF / 2) = 46340, which is roughly toQ5(1448)
static const int32_t MAXVAL = 46340;
int32_t common_divisor = gcd(abs((int32_t)dx), abs((int32_t)dy));
// First try to scale down
if (common_divisor != 1)
{
dx = CWRUtil::Q5((int32_t)dx / common_divisor);
dy = CWRUtil::Q5((int32_t)dy / common_divisor);
}
// Neither dx or dy is zero, find the largest multiplier / smallest divisor to stay within limit
if (abs((int32_t)dx) <= MAXVAL || abs((int32_t)dy) <= MAXVAL)
{
// Look for largest multiplier
int32_t mulx = MAXVAL / abs((int32_t)dx);
int32_t muly = MAXVAL / abs((int32_t)dy);
int32_t mult = MIN(mulx, muly);
dx = CWRUtil::Q5(mult * (int32_t)dx);
dy = CWRUtil::Q5(mult * (int32_t)dy);
}
else
{
// Look for smallest divisor
int32_t divx = abs((int32_t)dx) / MAXVAL;
int32_t divy = abs((int32_t)dy) / MAXVAL;
int32_t divi = MAX(divx, divy) + 1;
dx = CWRUtil::Q5((int32_t)dx / divi);
dy = CWRUtil::Q5((int32_t)dy / divi);
}
d = CWRUtil::sqrtQ10(dy * dy + dx * dx);
}
dy = CWRUtil::muldivQ5(lineWidth, dy, d) / 2;
dx = CWRUtil::muldivQ5(lineWidth, dx, d) / 2;
switch (lineEnding)
{
case BUTT_CAP_ENDING:
xCorner[0] = x1 - dy;
yCorner[0] = y1 + dx;
xCorner[1] = x2 - dy;
yCorner[1] = y2 + dx;
xCorner[2] = x2 + dy;
yCorner[2] = y2 - dx;
xCorner[3] = x1 + dy;
yCorner[3] = y1 - dx;
break;
case ROUND_CAP_ENDING:
// Nothing cached, calculated on each draw, but extremes are same as SQUARE_CAP_ENDING, so
// Fall Through (for calculations)
default:
case SQUARE_CAP_ENDING:
xCorner[0] = x1 - dy - dx;
yCorner[0] = y1 + dx - dy;
xCorner[1] = x2 - dy + dx;
yCorner[1] = y2 + dx + dy;
xCorner[2] = x2 + dy + dx;
yCorner[2] = y2 - dx + dy;
xCorner[3] = x1 + dy - dx;
yCorner[3] = y1 - dx - dy;
break;
}
CWRUtil::Q5 xMin = xCorner[0];
CWRUtil::Q5 xMax = xCorner[0];
CWRUtil::Q5 yMin = yCorner[0];
CWRUtil::Q5 yMax = yCorner[0];
for (int i = 1; i < 4; i++)
{
if (xCorner[i] < xMin)
{
xMin = xCorner[i];
}
if (xCorner[i] > xMax)
{
xMax = xCorner[i];
}
if (yCorner[i] < yMin)
{
yMin = yCorner[i];
}
if (yCorner[i] > yMax)
{
yMax = yCorner[i];
}
}
int16_t minX = xMin.to<int16_t>();
int16_t minY = yMin.to<int16_t>();
int16_t maxX = xMax.to<int16_t>();
int16_t maxY = yMax.to<int16_t>();
minimalRect = Rect(minX, minY, maxX - minX + 1, maxY - minY + 1);
if (lineEnding == ROUND_CAP_ENDING)
{
xCorner[0] = x1 - dy;
yCorner[0] = y1 + dx;
xCorner[1] = x2 - dy;
yCorner[1] = y2 + dx;
xCorner[2] = x2 + dy;
yCorner[2] = y2 - dx;
xCorner[3] = x1 + dy;
yCorner[3] = y1 - dx;
}
}
Rect Line::getMinimalRect() const
{
return minimalRect;
}
void Line::updateLengthAndAngle(CWRUtil::Q5 length, CWRUtil::Q5 angle)
{
updateEnd(x1 + length * CWRUtil::sine(angle), y1 - length * CWRUtil::cosine(angle));
}
} // namespace touchgfx

View File

@@ -0,0 +1,72 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD8bpp_ABGR2222.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/PainterABGR2222.hpp>
namespace touchgfx
{
void PainterABGR2222::render(uint8_t* ptr, int x, int xAdjust, int /*y*/, unsigned count, const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers;
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
}
bool PainterABGR2222::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
red = painterRed;
green = painterGreen;
blue = painterBlue;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,143 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterABGR2222Bitmap.hpp>
namespace touchgfx
{
void PainterABGR2222Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::ABGR2222) && "The chosen painter only works with ABGR2222 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterABGR2222Bitmap::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
const uint8_t* src = bitmapABGR2222Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t srcAlpha = ((*src) >> 6) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p = *src;
}
else if (alpha)
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t srcAlpha = ((*src) >> 6) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha) // This can never get to max=0xFF*0xFF as totalAlpha<255
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
}
bool PainterABGR2222Bitmap::renderInit()
{
bitmapABGR2222Pointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::ABGR2222)
{
bitmapABGR2222Pointer = bitmap.getData();
if (!bitmapABGR2222Pointer)
{
return false;
}
bitmapABGR2222Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
return false;
}
bool PainterABGR2222Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
else if (bitmapABGR2222Pointer != 0)
{
uint16_t abgr2222 = *bitmapABGR2222Pointer++;
red = LCD8bpp_ABGR2222::getRedFromColor(abgr2222);
green = LCD8bpp_ABGR2222::getGreenFromColor(abgr2222);
blue = LCD8bpp_ABGR2222::getBlueFromColor(abgr2222);
alpha = (abgr2222 >> 6) * 0x55; // To get full range 0-0xFF
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,72 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD8bpp_ARGB2222.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/PainterARGB2222.hpp>
namespace touchgfx
{
void PainterARGB2222::render(uint8_t* ptr, int x, int xAdjust, int /*y*/, unsigned count, const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers;
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
}
bool PainterARGB2222::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
red = painterRed;
green = painterGreen;
blue = painterBlue;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,143 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterARGB2222Bitmap.hpp>
namespace touchgfx
{
void PainterARGB2222Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::ARGB2222) && "The chosen painter only works with ARGB2222 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterARGB2222Bitmap::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
const uint8_t* src = bitmapARGB2222Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t srcAlpha = ((*src) >> 6) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p = *src;
}
else if (alpha)
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t srcAlpha = ((*src) >> 6) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha) // This can never get to max=0xFF*0xFF as totalAlpha<255
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
}
bool PainterARGB2222Bitmap::renderInit()
{
bitmapARGB2222Pointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::ARGB2222)
{
bitmapARGB2222Pointer = bitmap.getData();
if (!bitmapARGB2222Pointer)
{
return false;
}
bitmapARGB2222Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
return false;
}
bool PainterARGB2222Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
else if (bitmapARGB2222Pointer != 0)
{
uint16_t ARGB2222 = *bitmapARGB2222Pointer++;
red = LCD8bpp_ARGB2222::getRedFromColor(ARGB2222);
green = LCD8bpp_ARGB2222::getGreenFromColor(ARGB2222);
blue = LCD8bpp_ARGB2222::getBlueFromColor(ARGB2222);
alpha = (ARGB2222 >> 6) * 0x55; // To get full range 0-0xFF
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterARGB8888.hpp>
namespace touchgfx
{
void PainterARGB8888::render(uint8_t* ptr, int x, int xAdjust, int /*y*/, unsigned count, const uint8_t* covers)
{
uint8_t* p = reinterpret_cast<uint8_t*>(ptr) + ((x + xAdjust) * 4);
uint8_t pByte;
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
*p++ = painterBlue;
*p++ = painterGreen;
*p++ = painterRed;
*p++ = 0xff;
}
else
{
uint8_t ialpha = 0xFF - alpha;
pByte = *p;
*p++ = LCD::div255(painterBlue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterGreen * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterRed * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
}
while (--count != 0);
}
else if (totalAlpha != 0)
{
do
{
uint8_t alpha = LCD::div255(*covers++ * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
pByte = *p;
*p++ = LCD::div255(painterBlue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterGreen * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterRed * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
while (--count != 0);
}
}
bool PainterARGB8888::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
red = painterRed;
green = painterGreen;
blue = painterBlue;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,350 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterARGB8888Bitmap.hpp>
namespace touchgfx
{
void PainterARGB8888Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::RGB565 || bitmap.getFormat() == Bitmap::RGB888 || bitmap.getFormat() == Bitmap::ARGB8888) && "The chosen painter only works with RGB565, RGB888 and ARGB8888 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterARGB8888Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
uint8_t* RESTRICT p = ptr + ((x + xAdjust) * 4);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (bitmap.getFormat() == Bitmap::ARGB8888)
{
const uint32_t* RESTRICT src = bitmapARGB8888Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t srcAlpha = (*src) >> 24;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = (*src); // Blue
*p++ = (*src) >> 8; // Green
*p++ = (*src) >> 16; // Red
*p++ = 0xff; // Alpha
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
uint8_t cByte = (*src);
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 8;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 16;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 24;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t srcAlpha = (*src) >> 24;
uint8_t alpha = LCD::div255((*covers) * LCD::div255(srcAlpha * totalAlpha));
covers++;
if (alpha)
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
uint8_t cByte = (*src);
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 8;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 16;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 24;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
else
{
p += 4;
}
src++;
}
while (--count != 0);
}
}
else if (bitmap.getFormat() == Bitmap::RGB888)
{
const uint8_t* RESTRICT src = bitmapRGB888Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = *src++; // Blue
*p++ = *src++; // Green
*p++ = *src++; // Red
*p++ = 0xff; // Alpha
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
uint8_t cByte = *src++;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = *src++;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = *src++;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
if (alpha)
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
uint8_t cByte = *src++;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = *src++;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = *src++;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
else
{
p += 4;
src += 3;
}
}
while (--count != 0);
}
}
else if (bitmap.getFormat() == Bitmap::RGB565)
{
const uint16_t* RESTRICT src = bitmapRGB565Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers++;
uint16_t srcpix = *src++;
uint16_t red = (srcpix & 0xF800) >> 11;
uint16_t green = (srcpix & 0x07E0) >> 5;
uint16_t blue = srcpix & 0x001F;
red = (red * 527 + 23) >> 6;
green = (green * 259 + 33) >> 6;
blue = (blue * 527 + 23) >> 6;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = (uint8_t)blue;
*p++ = (uint8_t)green;
*p++ = (uint8_t)red;
*p++ = 0xff;
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255(blue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(green * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(red * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
uint16_t srcpix = *src++;
uint16_t red = (srcpix & 0xF800) >> 11;
uint16_t green = (srcpix & 0x07E0) >> 5;
uint16_t blue = srcpix & 0x001F;
red = (red * 527 + 23) >> 6;
green = (green * 259 + 33) >> 6;
blue = (blue * 527 + 23) >> 6;
if (alpha)
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255(blue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(green * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(red * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
else
{
p += 4;
}
}
while (--count != 0);
}
}
}
bool PainterARGB8888Bitmap::renderInit()
{
bitmapARGB8888Pointer = 0;
bitmapRGB565Pointer = 0;
bitmapRGB888Pointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::ARGB8888)
{
bitmapARGB8888Pointer = (const uint32_t*)bitmap.getData();
if (!bitmapARGB8888Pointer)
{
return false;
}
bitmapARGB8888Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
if (bitmap.getFormat() == Bitmap::RGB888)
{
bitmapRGB888Pointer = (const uint8_t*)bitmap.getData();
if (!bitmapRGB888Pointer)
{
return false;
}
bitmapRGB888Pointer += (currentX + currentY * bitmapRectToFrameBuffer.width) * 3;
return true;
}
if (bitmap.getFormat() == Bitmap::RGB565)
{
bitmapRGB565Pointer = (const uint16_t*)bitmap.getData();
if (!bitmapRGB565Pointer)
{
return false;
}
bitmapRGB565Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
return false;
}
bool PainterARGB8888Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
if (bitmapARGB8888Pointer != 0)
{
uint32_t argb8888 = *bitmapARGB8888Pointer++;
alpha = (argb8888 >> 24) & 0xFF;
red = (argb8888 >> 16) & 0xFF;
green = (argb8888 >> 8) & 0xFF;
blue = (argb8888) & 0xFF;
}
else if (bitmapRGB888Pointer != 0)
{
blue = *bitmapRGB888Pointer++;
green = *bitmapRGB888Pointer++;
red = *bitmapRGB888Pointer++;
alpha = 0xff;
}
else if (bitmapRGB565Pointer != 0)
{
uint16_t srcpix = *bitmapRGB565Pointer++;
red = (srcpix & 0xF800) >> 11;
green = (srcpix & 0x07E0) >> 5;
blue = srcpix & 0x001F;
red = (red * 527 + 23) >> 6;
green = (green * 259 + 33) >> 6;
blue = (blue * 527 + 23) >> 6;
alpha = 0xff;
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,321 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterARGB8888L8Bitmap.hpp>
namespace touchgfx
{
void PainterARGB8888L8Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::L8) && "The chosen painter only works with L8 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterARGB8888L8Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
uint8_t* RESTRICT p = ptr + ((x + xAdjust) * 4);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
switch ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2])
{
case Bitmap::CLUT_FORMAT_L8_RGB565:
if (totalAlpha == 0xFF)
{
do
{
const uint16_t srcpix = ((const uint16_t*)bitmapExtraPointer)[*bitmapPointer++];
uint8_t alpha = *covers++;
uint16_t red = (srcpix & 0xF800) >> 11;
uint16_t green = (srcpix & 0x07E0) >> 5;
uint16_t blue = srcpix & 0x001F;
red = (red * 527 + 23) >> 6;
green = (green * 259 + 33) >> 6;
blue = (blue * 527 + 23) >> 6;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = (uint8_t)blue;
*p++ = (uint8_t)green;
*p++ = (uint8_t)red;
*p++ = 0xff;
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255(blue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(green * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(red * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
}
while (--count != 0);
}
else
{
do
{
const uint16_t srcpix = ((const uint16_t*)bitmapExtraPointer)[*bitmapPointer++];
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
uint16_t red = (srcpix & 0xF800) >> 11;
uint16_t green = (srcpix & 0x07E0) >> 5;
uint16_t blue = srcpix & 0x001F;
red = (red * 527 + 23) >> 6;
green = (green * 259 + 33) >> 6;
blue = (blue * 527 + 23) >> 6;
if (alpha)
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255(blue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(green * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(red * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
else
{
p += 4;
}
}
while (--count != 0);
}
break;
case Bitmap::CLUT_FORMAT_L8_RGB888:
if (totalAlpha == 0xFF)
{
do
{
const uint8_t* src = bitmapExtraPointer + *bitmapPointer++ * 3;
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = *src++; // Blue
*p++ = *src++; // Green
*p++ = *src; // Red
*p++ = 0xff; // Alpha
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
if (alpha)
{
const uint8_t* src = bitmapExtraPointer + *bitmapPointer++ * 3;
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
else
{
p += 4;
}
}
while (--count != 0);
}
break;
case Bitmap::CLUT_FORMAT_L8_ARGB8888:
if (totalAlpha == 0xFF)
{
do
{
uint32_t src = ((const uint32_t*)bitmapExtraPointer)[*bitmapPointer++];
uint8_t srcAlpha = src >> 24;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = src; // Blue
*p++ = src >> 8; // Green
*p++ = src >> 16; // Red
*p++ = 0xff; // Alpha
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255((src & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 8) & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 16) & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
}
while (--count != 0);
}
else
{
do
{
uint32_t src = ((const uint32_t*)bitmapExtraPointer)[*bitmapPointer++];
uint8_t srcAlpha = src >> 24;
uint8_t alpha = LCD::div255((*covers) * LCD::div255(srcAlpha * totalAlpha));
covers++;
if (alpha)
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255((src & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 8) & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 16) & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = pByte + alpha - LCD::div255(pByte * alpha);
}
else
{
p += 4;
}
}
while (--count != 0);
}
break;
}
}
bool PainterARGB8888L8Bitmap::renderInit()
{
bitmapPointer = 0;
bitmapExtraPointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::L8)
{
bitmapPointer = bitmap.getData();
if (!bitmapPointer)
{
return false;
}
bitmapPointer += currentX + currentY * bitmapRectToFrameBuffer.width;
bitmapExtraPointer = bitmap.getExtraData();
assert((bitmapExtraPointer != 0 && (*(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_RGB565 || *(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_RGB888 || *(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_ARGB8888)));
bitmapExtraPointer += 4; // Skip header
return true;
}
return false;
}
bool PainterARGB8888L8Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
switch ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2])
{
case Bitmap::CLUT_FORMAT_L8_RGB565:
{
uint16_t srcpix = ((const uint16_t*)bitmapExtraPointer)[*bitmapPointer++];
red = (srcpix & 0xF800) >> 11;
green = (srcpix & 0x07E0) >> 5;
blue = srcpix & 0x001F;
red = (red * 527 + 23) >> 6;
green = (green * 259 + 33) >> 6;
blue = (blue * 527 + 23) >> 6;
alpha = 0xff;
}
break;
case Bitmap::CLUT_FORMAT_L8_RGB888:
{
const uint8_t* clut = bitmapExtraPointer + *bitmapPointer++ * 3;
blue = *clut++;
green = *clut++;
red = *clut;
alpha = 0xff;
}
break;
case Bitmap::CLUT_FORMAT_L8_ARGB8888:
{
uint32_t argb8888 = ((const uint32_t*)bitmapExtraPointer)[*bitmapPointer++];
alpha = (argb8888 >> 24) & 0xFF;
red = (argb8888 >> 16) & 0xFF;
green = (argb8888 >> 8) & 0xFF;
blue = (argb8888) & 0xFF;
}
break;
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,72 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD8bpp_BGRA2222.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/PainterBGRA2222.hpp>
namespace touchgfx
{
void PainterBGRA2222::render(uint8_t* ptr, int x, int xAdjust, int /*y*/, unsigned count, const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers;
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
}
bool PainterBGRA2222::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
red = painterRed;
green = painterGreen;
blue = painterBlue;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,143 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterBGRA2222Bitmap.hpp>
namespace touchgfx
{
void PainterBGRA2222Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::BGRA2222) && "The chosen painter only works with BGRA2222 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterBGRA2222Bitmap::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
const uint8_t* src = bitmapBGRA2222Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t srcAlpha = ((*src) & 0x03) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p = *src;
}
else if (alpha)
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t srcAlpha = ((*src) & 0x03) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha) // This can never get to max=0xFF*0xFF as totalAlpha<255
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
}
bool PainterBGRA2222Bitmap::renderInit()
{
bitmapBGRA2222Pointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::BGRA2222)
{
bitmapBGRA2222Pointer = bitmap.getData();
if (!bitmapBGRA2222Pointer)
{
return false;
}
bitmapBGRA2222Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
return false;
}
bool PainterBGRA2222Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
else if (bitmapBGRA2222Pointer != 0)
{
uint16_t BGRA2222 = *bitmapBGRA2222Pointer++;
red = LCD8bpp_BGRA2222::getRedFromColor(BGRA2222);
green = LCD8bpp_BGRA2222::getGreenFromColor(BGRA2222);
blue = LCD8bpp_BGRA2222::getBlueFromColor(BGRA2222);
alpha = (BGRA2222 & 0x03) * 0x55; // To get full range 0-0xFF
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,52 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterBW.hpp>
namespace touchgfx
{
void PainterBW::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* /*covers*/)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
unsigned char* p = ptr + (x / 8);
do
{
unsigned pixel = 1 << (7 - (x % 8));
if (!painterColor)
{
*p &= ~pixel;
}
else
{
*p |= pixel;
}
if (((++x) % 8) == 0)
{
p++;
}
currentX++;
}
while (--count);
}
bool PainterBW::renderNext(uint8_t& color)
{
color = painterColor;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,210 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterBWBitmap.hpp>
namespace touchgfx
{
void PainterBWBitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::BW || bitmap.getFormat() == Bitmap::BW_RLE) && "The chosen painter only works with BW and BW_RLE bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
// Found in LCD1bpp
void fillBits(uint8_t* fb, uint16_t startX, uint16_t startY, uint16_t stride, uint32_t count, uint8_t color);
void PainterBWBitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* /*covers*/)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
if (bitmap.getFormat() == Bitmap::BW_RLE)
{
while (count)
{
uint32_t length = bw_rle.getLength();
uint32_t bitsToDraw = MIN(length, (uint32_t)count);
fillBits(ptr, x, 0, 0 /* not used */, bitsToDraw, bw_rle.getColor());
x += bitsToDraw;
count -= bitsToDraw;
bw_rle.skipNext(bitsToDraw);
}
}
else
{
unsigned char* p = ptr + (x / 8);
const uint8_t* src = bitmapBWPointer + currentX / 8;
uint8_t* RESTRICT dst = p;
uint16_t srcBitX = currentX % 8; // & 7
uint16_t dstBitX = x % 8; // & 7
uint16_t remainingBits = count;
if (dstBitX > 0)
{
// Start by getting (dst-)aligned for faster transfer
uint16_t neededBits = 8 - dstBitX;
if (neededBits > remainingBits)
{
neededBits = remainingBits; // Very narrow src inside same word
}
uint16_t availableBits = 8 - srcBitX;
uint8_t mask = (1u << neededBits) - 1u;
uint8_t dstShift = static_cast<uint8_t>(8u - (dstBitX + neededBits));
mask <<= dstShift;
uint8_t word = *src;
if (availableBits > neededBits)
{
word >>= availableBits - neededBits;
}
else if (availableBits < neededBits)
{
// Get the last required bits from src[1]
word <<= neededBits - availableBits;
word |= src[1] >> (8u - (neededBits - availableBits));
}
word <<= dstShift;
*dst = (*dst & ~mask) | (word & mask);
srcBitX = (srcBitX + neededBits) % 8; // & 7
if (availableBits <= neededBits)
{
src++;
}
dst++;
remainingBits -= neededBits;
}
// dstX is now word aligned (or we have transferred everything of a narrow image and remainingBits==0)
if (remainingBits >= 8)
{
uint16_t bytesPerLine = remainingBits / 8;
if (srcBitX == 0)
{
touchgfx::HAL::getInstance()->blockCopy(dst, src, bytesPerLine);
src += bytesPerLine;
dst += bytesPerLine;
}
else
{
uint16_t _remainingBits = remainingBits;
remainingBits = _remainingBits;
while (remainingBits >= 8)
{
uint8_t word = *src++;
word <<= srcBitX;
word |= (*src) >> (8 - srcBitX);
*dst++ = word;
remainingBits -= 8;
}
}
remainingBits %= 8; // &= 7
}
// Take the last bits, again we need to mask dst
if (remainingBits > 0)
{
uint8_t word = *src;
if (srcBitX != 0)
{
word <<= srcBitX;
word |= src[1] >> (8u - srcBitX);
}
uint8_t mask = ((1u << remainingBits) - 1u) << (8u - remainingBits);
*dst = (*dst & ~mask) | (word & mask);
}
}
}
bool PainterBWBitmap::renderInit()
{
bw_rle = 0; // Used to remember if format is BW or BW_RLE
bitmapBWPointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if (currentX >= bitmapRectToFrameBuffer.width || currentY >= bitmapRectToFrameBuffer.height)
{
// Outside bitmap area, do not draw anything
return false;
}
// Common for BW and BW_RLE
bitmapBWPointer = (const uint8_t*)bitmap.getData();
if (!bitmapBWPointer)
{
return false;
}
if (bitmap.getFormat() == Bitmap::BW_RLE)
{
bw_rle.init(bitmapBWPointer);
uint32_t skip = (int32_t)currentY * (int32_t)bitmapRectToFrameBuffer.width + (int32_t)currentX;
bw_rle.skipNext(skip);
return true;
}
if (bitmap.getFormat() == Bitmap::BW)
{
bitmapBWPointer += currentY * ((bitmapRectToFrameBuffer.width + 7) / 8);
return true;
}
return false;
}
bool PainterBWBitmap::renderNext(uint8_t& color)
{
if (currentX >= bitmapRectToFrameBuffer.width || bitmapBWPointer == 0)
{
return false;
}
if (bitmap.getFormat() == Bitmap::BW_RLE)
{
color = bw_rle.getColor();
bw_rle.skipNext(1);
}
else
{
const uint8_t* src = bitmapBWPointer + currentX / 8;
color = ((*src) >> (7 - (currentX % 8))) & 1;
}
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD2bpp.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/PainterGRAY2.hpp>
namespace touchgfx
{
void PainterGRAY2::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers;
covers++;
if (alpha == 0xFF)
{
// Render a solid pixel
LCD2setPixel(ptr, x, painterGray);
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint8_t p_gray = LCD2getPixel(ptr, x);
LCD2setPixel(ptr, x, LCD::div255((painterGray * alpha + p_gray * ialpha) * 0x55) >> 6);
}
currentX++;
x++;
}
while (--count != 0);
}
else if (totalAlpha != 0)
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
covers++;
uint8_t p_gray = LCD2getPixel(ptr, x);
LCD2setPixel(ptr, x, LCD::div255((painterGray * alpha + p_gray * ialpha) * 0x55) >> 6);
currentX++;
x++;
}
while (--count != 0);
}
}
bool PainterGRAY2::renderNext(uint8_t& gray, uint8_t& alpha)
{
gray = painterGray;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,193 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD2bpp.hpp>
#include <touchgfx/widgets/canvas/PainterGRAY2Bitmap.hpp>
namespace touchgfx
{
void PainterGRAY2Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::GRAY2) && "The chosen painter only works with GRAY2 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterGRAY2Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (bitmapAlphaPointer)
{
if (totalAlpha == 0xFF)
{
do
{
uint8_t gray = LCD2getPixel(bitmapGRAY2Pointer, currentX);
uint8_t alpha = LCD::div255((*covers) * (LCD2getPixel(bitmapAlphaPointer, currentX) * 0x55));
covers++;
if (alpha == 0xFF)
{
// Render a solid pixel
LCD2setPixel(ptr, x, gray);
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint8_t p_gray = LCD2getPixel(ptr, x);
LCD2setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x55) >> 6);
}
currentX++;
x++;
}
while (--count != 0);
}
else
{
do
{
uint8_t gray = LCD2getPixel(bitmapGRAY2Pointer, currentX);
uint8_t alpha = LCD::div255((*covers) * LCD::div255(totalAlpha * (LCD2getPixel(bitmapAlphaPointer, currentX) * 0x55)));
uint8_t ialpha = 0xFF - alpha;
covers++;
uint8_t p_gray = LCD2getPixel(ptr, x);
LCD2setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x55) >> 6);
currentX++;
x++;
}
while (--count != 0);
}
}
else
{
if (totalAlpha == 255)
{
do
{
uint8_t gray = LCD2getPixel(bitmapGRAY2Pointer, currentX);
uint8_t alpha = (*covers);
covers++;
if (alpha == 255)
{
// Render a solid pixel
LCD2setPixel(ptr, x, gray);
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint8_t p_gray = LCD2getPixel(ptr, x);
LCD2setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x55) >> 6);
}
currentX++;
x++;
}
while (--count != 0);
}
else
{
do
{
uint8_t gray = LCD2getPixel(bitmapGRAY2Pointer, currentX);
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
covers++;
uint8_t p_gray = LCD2getPixel(ptr, x);
LCD2setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x55) >> 6);
currentX++;
x++;
}
while (--count != 0);
}
}
}
bool PainterGRAY2Bitmap::renderInit()
{
bitmapGRAY2Pointer = 0;
bitmapAlphaPointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
return false;
}
if (bitmap.getFormat() == Bitmap::GRAY2)
{
bitmapGRAY2Pointer = (const uint8_t*)bitmap.getData();
if (!bitmapGRAY2Pointer)
{
return false;
}
bitmapGRAY2Pointer += currentY * ((bitmapRectToFrameBuffer.width + 3) / 4);
bitmapAlphaPointer = (const uint8_t*)bitmap.getExtraData();
if (bitmapAlphaPointer)
{
bitmapAlphaPointer += currentY * ((bitmapRectToFrameBuffer.width + 3) / 4);
}
return true;
}
return false;
}
bool PainterGRAY2Bitmap::renderNext(uint8_t& gray, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
if (bitmapGRAY2Pointer != 0)
{
gray = LCD2getPixel(bitmapGRAY2Pointer, currentX);
if (bitmapAlphaPointer)
{
alpha = LCD2getPixel(bitmapAlphaPointer, currentX);
alpha *= 0x55; // Upscale from 00-03 to 00-FF
}
else
{
alpha = 0xFF; // No alpha per pixel in the image, it is solid
}
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,72 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD4bpp.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/PainterGRAY4.hpp>
namespace touchgfx
{
void PainterGRAY4::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers;
covers++;
if (alpha == 0xFF) // max alpha=0xFF on "*covers" and max alpha=0xFF on "widgetAlpha"
{
// Render a solid pixel
LCD4setPixel(ptr, x, painterGray);
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint8_t p_gray = LCD4getPixel(ptr, x);
LCD4setPixel(ptr, x, LCD::div255((painterGray * alpha + p_gray * ialpha) * 0x11) >> 4);
}
currentX++;
x++;
}
while (--count != 0);
}
else if (totalAlpha != 0)
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
covers++;
uint8_t p_gray = LCD4getPixel(ptr, x);
LCD4setPixel(ptr, x, LCD::div255((painterGray * alpha + p_gray * ialpha) * 0x11) >> 4);
currentX++;
x++;
}
while (--count != 0);
}
}
bool PainterGRAY4::renderNext(uint8_t& gray, uint8_t& alpha)
{
gray = painterGray;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,194 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD4bpp.hpp>
#include <touchgfx/widgets/canvas/PainterGRAY4Bitmap.hpp>
namespace touchgfx
{
void PainterGRAY4Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::GRAY4) && "The chosen painter only works with GRAY4 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterGRAY4Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
x += xAdjust;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
// Get alpha data (GRAY4 format)
if (bitmapAlphaPointer)
{
if (totalAlpha == 0xFF)
{
do
{
uint8_t gray = LCD4getPixel(bitmapGRAY4Pointer, currentX);
uint8_t alpha = LCD::div255((*covers) * (LCD4getPixel(bitmapAlphaPointer, currentX) * 0x11));
covers++;
if (alpha == 0xFF)
{
// Render a solid pixel
LCD4setPixel(ptr, x, gray);
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint8_t p_gray = LCD4getPixel(ptr, x);
LCD4setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x11) >> 4);
}
currentX++;
x++;
}
while (--count != 0);
}
else
{
do
{
uint8_t gray = LCD4getPixel(bitmapGRAY4Pointer, currentX);
uint8_t alpha = LCD::div255((*covers) * LCD::div255(totalAlpha * (LCD4getPixel(bitmapAlphaPointer, currentX) * 0x11)));
uint8_t ialpha = 0xFF - alpha;
covers++;
uint8_t p_gray = LCD4getPixel(ptr, x);
LCD4setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x11) >> 4);
currentX++;
x++;
}
while (--count != 0);
}
}
else
{
if (totalAlpha == 255)
{
do
{
uint8_t gray = LCD4getPixel(bitmapGRAY4Pointer, currentX);
uint8_t alpha = (*covers);
covers++;
if (alpha == 0xFF)
{
// Render a solid pixel
LCD4setPixel(ptr, x, gray);
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint8_t p_gray = LCD4getPixel(ptr, x);
LCD4setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x11) >> 4);
}
currentX++;
x++;
}
while (--count != 0);
}
else
{
do
{
uint8_t gray = LCD4getPixel(bitmapGRAY4Pointer, currentX);
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
covers++;
uint8_t p_gray = LCD4getPixel(ptr, x);
LCD4setPixel(ptr, x, LCD::div255((gray * alpha + p_gray * ialpha) * 0x11) >> 4);
currentX++;
x++;
}
while (--count != 0);
}
}
}
bool PainterGRAY4Bitmap::renderInit()
{
bitmapGRAY4Pointer = 0;
bitmapAlphaPointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
return false;
}
if (bitmap.getFormat() == Bitmap::GRAY4)
{
bitmapGRAY4Pointer = (const uint8_t*)bitmap.getData();
if (!bitmapGRAY4Pointer)
{
return false;
}
bitmapGRAY4Pointer += currentY * ((bitmapRectToFrameBuffer.width + 1) / 2);
bitmapAlphaPointer = (const uint8_t*)bitmap.getExtraData();
if (bitmapAlphaPointer)
{
bitmapAlphaPointer += currentY * ((bitmapRectToFrameBuffer.width + 1) / 2);
}
return true;
}
return false;
}
bool PainterGRAY4Bitmap::renderNext(uint8_t& gray, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
if (bitmapGRAY4Pointer != 0)
{
gray = LCD4getPixel(bitmapGRAY4Pointer, currentX);
if (bitmapAlphaPointer)
{
alpha = LCD4getPixel(bitmapAlphaPointer, currentX);
alpha |= alpha << 4; // Upscale from 0-15 to 0-255
}
else
{
alpha = 0xFF; // No alpha per pixel in the image, it is solid
}
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,71 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/PainterRGB565.hpp>
namespace touchgfx
{
void PainterRGB565::render(uint8_t* ptr, int x, int xAdjust, int /*y*/, unsigned count, const uint8_t* covers)
{
uint16_t* p = reinterpret_cast<uint16_t*>(ptr) + (x + xAdjust);
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers;
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
}
bool PainterRGB565::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
red = painterRed >> 8;
green = painterGreen >> 3;
blue = painterBlue << 3;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,271 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterRGB565Bitmap.hpp>
namespace touchgfx
{
void PainterRGB565Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::RGB565 || bitmap.getFormat() == Bitmap::ARGB8888) && "The chosen painter only works with RGB565 and ARGB8888 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterRGB565Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
uint16_t* p = reinterpret_cast<uint16_t*>(ptr) + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (bitmap.getFormat() == Bitmap::RGB565)
{
const uint16_t* src = bitmapRGB565Pointer;
const uint8_t* srcAlpha = bitmapAlphaPointer;
if (srcAlpha)
{
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = LCD::div255((*covers) * (*srcAlpha));
covers++;
srcAlpha++;
if (alpha == 0xFF)
{
// Solid pixel
*p = *src;
}
else if (alpha)
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * LCD::div255((*srcAlpha) * totalAlpha));
covers++;
srcAlpha++;
if (alpha) // This can never get to max=0XFF as totalAlpha<0xFF
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
}
else
{
if (totalAlpha == 0xFF)
{
do
{
//use alpha from covers directly
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p = *src;
}
else
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
*p = mixColors(*src, *p, alpha);
p++;
src++;
}
while (--count != 0);
}
}
}
else if (bitmap.getFormat() == Bitmap::ARGB8888)
{
const uint32_t* src = bitmapARGB8888Pointer;
if (totalAlpha == 0xFF)
{
uint32_t newpix;
do
{
uint8_t srcAlpha = (*src) >> 24;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
newpix = *src;
if (alpha == 0xFF)
{
// Solid pixel
*p = ((newpix >> 8) & RMASK) | ((newpix >> 5) & GMASK) | ((newpix >> 3) & BMASK);
}
else if (alpha)
{
// Non-Transparent pixel
*p = mixColors((newpix >> 8) & RMASK, (newpix >> 5) & GMASK, (newpix >> 3) & BMASK, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
uint32_t newpix;
do
{
uint8_t srcAlpha = (*src) >> 24;
uint8_t alpha = LCD::div255((*covers) * LCD::div255(srcAlpha * totalAlpha));
covers++;
if (alpha)
{
// Non-Transparent pixel
newpix = *src;
*p = mixColors((newpix >> 8) & RMASK, (newpix >> 5) & GMASK, (newpix >> 3) & BMASK, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
}
}
bool PainterRGB565Bitmap::renderInit()
{
bitmapARGB8888Pointer = 0;
bitmapRGB565Pointer = 0;
bitmapAlphaPointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::ARGB8888)
{
bitmapARGB8888Pointer = (const uint32_t*)bitmap.getData();
if (!bitmapARGB8888Pointer)
{
return false;
}
bitmapARGB8888Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
if (bitmap.getFormat() == Bitmap::RGB565)
{
bitmapRGB565Pointer = (const uint16_t*)bitmap.getData();
if (!bitmapRGB565Pointer)
{
return false;
}
bitmapRGB565Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
// Get alpha data (RGB565 format)
bitmapAlphaPointer = (const uint8_t*)bitmap.getExtraData();
if (bitmapAlphaPointer)
{
bitmapAlphaPointer += currentX + currentY * bitmapRectToFrameBuffer.width;
}
return true;
}
return false;
}
bool PainterRGB565Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
if (bitmapARGB8888Pointer != 0)
{
uint32_t argb8888 = *bitmapARGB8888Pointer++;
alpha = (argb8888 >> 24) & 0xFF;
red = (argb8888 >> 16) & 0xF8;
red |= red >> 5; // To get full range 0-0xFF, not just 0-0xF8
green = (argb8888 >> 8) & 0xFC;
green |= green >> 6; // To get full range 0-0xFF, not just 0-0xFC
blue = argb8888 & 0xF8;
blue |= blue >> 5; // To get full range 0-0xFF, not just 0-0xF8
}
else if (bitmapRGB565Pointer != 0)
{
uint16_t rgb565 = *bitmapRGB565Pointer++;
red = (rgb565 & RMASK) >> 8;
red |= red >> 5; // To get full range 0-0xFF, not just 0-0xF8
green = (rgb565 & GMASK) >> 3;
green |= green >> 6; // To get full range 0-0xFF, not just 0-0xFC
blue = (rgb565 & BMASK) << 3;
blue |= blue >> 5; // To get full range 0-0xFF, not just 0-0xF8
if (bitmapAlphaPointer)
{
alpha = *bitmapAlphaPointer++;
}
else
{
alpha = 0xFF; // No alpha per pixel in the image, it is solid
}
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,269 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterRGB565L8Bitmap.hpp>
namespace touchgfx
{
void PainterRGB565L8Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::L8) && "The chosen painter only works with appropriate L8 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterRGB565L8Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
uint16_t* p = reinterpret_cast<uint16_t*>(ptr) + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2] == Bitmap::CLUT_FORMAT_L8_RGB565)
{
const uint8_t* src = bitmapPointer;
if (totalAlpha == 0xFF)
{
do
{
//use alpha from covers directly
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p = ((const uint16_t*)bitmapExtraPointer)[*src];
}
else
{
// Non-Transparent pixel
*p = mixColors(((const uint16_t*)bitmapExtraPointer)[*src], *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
*p = mixColors(((const uint16_t*)bitmapExtraPointer)[*src], *p, alpha);
p++;
src++;
}
while (--count != 0);
}
}
else if ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2] == Bitmap::CLUT_FORMAT_L8_RGB888)
{
if (totalAlpha == 0xFF)
{
do
{
const uint8_t* src = &bitmapExtraPointer[*bitmapPointer++ * 3];
// Use alpha from covers directly
uint8_t alpha = *covers++;
uint8_t blue = *src++;
uint8_t green = *src++;
uint8_t red = *src;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = ((red << 8) & RMASK) | ((green << 3) & GMASK) | ((blue >> 3) & BMASK);
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint16_t bufpix = *p;
uint8_t fbr = (bufpix & RMASK) >> 11;
uint8_t fbg = (bufpix & GMASK) >> 5;
uint8_t fbb = bufpix & BMASK;
fbr = (fbr * 527 + 23) >> 6;
fbg = (fbg * 259 + 33) >> 6;
fbb = (fbb * 527 + 23) >> 6;
*p++ = ((LCD::div255(red * alpha + fbr * ialpha) << 8) & RMASK) | ((LCD::div255(green * alpha + fbg * ialpha) << 3) & GMASK) | ((LCD::div255(blue * alpha + fbb * ialpha) >> 3) & BMASK);
}
}
while (--count != 0);
}
else
{
do
{
const uint8_t* src = &bitmapExtraPointer[*bitmapPointer++ * 3];
uint8_t blue = *src++;
uint8_t green = *src++;
uint8_t red = *src;
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
covers++;
uint16_t bufpix = *p;
uint8_t fbr = (bufpix & RMASK) >> 11;
uint8_t fbg = (bufpix & GMASK) >> 5;
uint8_t fbb = bufpix & BMASK;
fbr = (fbr * 527 + 23) >> 6;
fbg = (fbg * 259 + 33) >> 6;
fbb = (fbb * 527 + 23) >> 6;
*p++ = ((LCD::div255(red * alpha + fbr * ialpha) << 8) & RMASK) | ((LCD::div255(green * alpha + fbg * ialpha) << 3) & GMASK) | ((LCD::div255(blue * alpha + fbb * ialpha) >> 3) & BMASK);
}
while (--count != 0);
}
}
else // Bitmap::CLUT_FORMAT_L8_ARGB8888
{
const uint8_t* src = bitmapPointer;
if (totalAlpha == 0xFF)
{
do
{
uint32_t newpix = ((const uint32_t*)bitmapExtraPointer)[*src];
uint8_t srcAlpha = newpix >> 24;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p = ((newpix >> 8) & RMASK) | ((newpix >> 5) & GMASK) | ((newpix >> 3) & BMASK);
}
else if (alpha)
{
// Non-Transparent pixel
*p = mixColors((newpix >> 8) & RMASK, (newpix >> 5) & GMASK, (newpix >> 3) & BMASK, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint32_t newpix = ((const uint32_t*)bitmapExtraPointer)[*src];
uint8_t srcAlpha = newpix >> 24;
uint8_t alpha = LCD::div255((*covers) * LCD::div255(srcAlpha * totalAlpha));
covers++;
if (alpha)
{
// Non-Transparent pixel
*p = mixColors((newpix >> 8) & RMASK, (newpix >> 5) & GMASK, (newpix >> 3) & BMASK, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
}
}
bool PainterRGB565L8Bitmap::renderInit()
{
bitmapPointer = 0;
bitmapExtraPointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::L8)
{
bitmapPointer = bitmap.getData();
if (!bitmapPointer)
{
return false;
}
bitmapPointer += currentX + currentY * bitmapRectToFrameBuffer.width;
bitmapExtraPointer = bitmap.getExtraData();
assert((bitmapExtraPointer != 0 && (*(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_RGB565 || *(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_ARGB8888 || *(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_RGB888)));
bitmapExtraPointer += 4; // Skip header
return true;
}
return false;
}
bool PainterRGB565L8Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
if ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2] == Bitmap::CLUT_FORMAT_L8_RGB565)
{
const uint16_t* clut = ((const uint16_t*)bitmapExtraPointer) + (*bitmapPointer++);
uint16_t rgb565 = *clut;
red = (rgb565 & RMASK) >> 8;
red |= red >> 5; // To get full range 0-0xFF, not just 0-0xF8
green = (rgb565 & GMASK) >> 3;
green |= green >> 6; // To get full range 0-0xFF, not just 0-0xFC
blue = (rgb565 & BMASK) << 3;
blue |= (blue >> 5); // To get full range 0-0xFF, not just 0-0xF8
alpha = 0xFF;
}
else if ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2] == Bitmap::CLUT_FORMAT_L8_RGB888)
{
const uint8_t* clut = ((const uint8_t*)bitmapExtraPointer) + (*bitmapPointer++) * 3;
alpha = 0xFF;
blue = *clut++ & 0xF8;
blue |= (blue >> 5); // To get full range 0-0xFF, not just 0-0xF8
green = *clut++ & 0xFC;
green |= green >> 6; // To get full range 0-0xFF, not just 0-0xFC
red = *clut & 0xF8;
red |= red >> 5; // To get full range 0-0xFF, not just 0-0xF8
}
else // Bitmap::CLUT_FORMAT_L8_ARGB8888
{
const uint32_t* clut = ((const uint32_t*)bitmapExtraPointer) + (*bitmapPointer++);
uint32_t argb8888 = *(const uint32_t*)clut;
alpha = (argb8888 >> 24) & 0xFF;
red = (argb8888 >> 16) & 0xF8;
red |= red >> 5; // To get full range 0-0xFF, not just 0-0xF8
green = (argb8888 >> 8) & 0xFC;
green |= green >> 6; // To get full range 0-0xFF, not just 0-0xFC
blue = argb8888 & 0xF8;
blue |= (blue >> 5); // To get full range 0-0xFF, not just 0-0xF8
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,74 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterRGB888.hpp>
namespace touchgfx
{
void PainterRGB888::render(uint8_t* ptr, int x, int xAdjust, int /*y*/, unsigned count, const uint8_t* covers)
{
uint8_t* p = reinterpret_cast<uint8_t*>(ptr) + ((x + xAdjust) * 3);
uint8_t pByte;
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
*p++ = painterBlue;
*p++ = painterGreen;
*p++ = painterRed;
}
else
{
uint8_t ialpha = 0xFF - alpha;
pByte = *p;
*p++ = LCD::div255(painterBlue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterGreen * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterRed * alpha + pByte * ialpha);
}
}
while (--count != 0);
}
else if (totalAlpha != 0)
{
do
{
uint8_t alpha = LCD::div255(*covers++ * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
pByte = *p;
*p++ = LCD::div255(painterBlue * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterGreen * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(painterRed * alpha + pByte * ialpha);
}
while (--count != 0);
}
}
bool PainterRGB888::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
red = painterRed;
green = painterGreen;
blue = painterBlue;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,229 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterRGB888Bitmap.hpp>
namespace touchgfx
{
void PainterRGB888Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::RGB888 || bitmap.getFormat() == Bitmap::ARGB8888) && "The chosen painter only works with RGB888 and ARGB8888 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterRGB888Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
uint8_t* p = ptr + ((x + xAdjust) * 3);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (bitmapRGB888Pointer)
{
const uint8_t* src = bitmapRGB888Pointer;
uint8_t pByte;
if (totalAlpha == 0xFF)
{
do
{
// Use alpha from covers directly
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = *src++;
*p++ = *src++;
*p++ = *src++;
}
else
{
uint8_t ialpha = 0xFF - alpha;
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
}
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
covers++;
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
}
while (--count != 0);
}
}
else if (bitmapARGB8888Pointer)
{
const uint32_t* src = bitmapARGB8888Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t srcAlpha = (*src) >> 24;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = (*src); // Blue
*p++ = (*src) >> 8; // Green
*p++ = (*src) >> 16; // Red
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
uint8_t cByte = (*src);
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 8;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 16;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
}
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t srcAlpha = (*src) >> 24;
uint8_t alpha = LCD::div255((*covers) * LCD::div255(srcAlpha * totalAlpha));
covers++;
if (alpha)
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
uint8_t cByte = (*src);
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 8;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
pByte = *p;
cByte = (*src) >> 16;
*p++ = LCD::div255(cByte * alpha + pByte * ialpha);
}
else
{
p += 3;
}
src++;
}
while (--count != 0);
}
}
}
bool PainterRGB888Bitmap::renderInit()
{
bitmapARGB8888Pointer = 0;
bitmapRGB888Pointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::ARGB8888)
{
bitmapARGB8888Pointer = (const uint32_t*)bitmap.getData();
if (!bitmapARGB8888Pointer)
{
return false;
}
bitmapARGB8888Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
if (bitmap.getFormat() == Bitmap::RGB888)
{
bitmapRGB888Pointer = bitmap.getData();
if (!bitmapRGB888Pointer)
{
return false;
}
bitmapRGB888Pointer += (currentX + currentY * bitmapRectToFrameBuffer.width) * 3;
return true;
}
return false;
}
bool PainterRGB888Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
if (bitmapARGB8888Pointer != 0)
{
uint32_t argb8888 = *bitmapARGB8888Pointer++;
alpha = (argb8888 >> 24) & 0xFF;
red = (argb8888 >> 16) & 0xFF;
green = (argb8888 >> 8) & 0xFF;
blue = (argb8888) & 0xFF;
}
else if (bitmapRGB888Pointer != 0)
{
blue = *bitmapRGB888Pointer++;
green = *bitmapRGB888Pointer++;
red = *bitmapRGB888Pointer++;
alpha = 0xFF; // No alpha per pixel in the image, it is solid
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,216 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterRGB888L8Bitmap.hpp>
namespace touchgfx
{
void PainterRGB888L8Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::L8) && "The chosen painter only works with appropriate L8 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterRGB888L8Bitmap::render(uint8_t* ptr, int x, int xAdjust, int y, unsigned count, const uint8_t* covers)
{
uint8_t* p = ptr + ((x + xAdjust) * 3);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2] == Bitmap::CLUT_FORMAT_L8_RGB888)
{
if (totalAlpha == 0xFF)
{
do
{
const uint8_t* src = &bitmapExtraPointer[*bitmapPointer++ * 3];
// Use alpha from covers directly
uint8_t alpha = *covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = *src++;
*p++ = *src++;
*p++ = *src;
}
else
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src * alpha + pByte * ialpha);
}
}
while (--count != 0);
}
else
{
do
{
const uint8_t* src = &bitmapExtraPointer[*bitmapPointer++ * 3];
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
uint8_t ialpha = 0xFF - alpha;
covers++;
uint8_t pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src++ * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(*src * alpha + pByte * ialpha);
}
while (--count != 0);
}
}
else // Bitmap::CLUT_FORMAT_L8_ARGB8888
{
if (totalAlpha == 0xFF)
{
do
{
uint32_t src = ((const uint32_t*)bitmapExtraPointer)[*bitmapPointer++];
uint8_t srcAlpha = src >> 24;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p++ = src; // Blue
*p++ = src >> 8; // Green
*p++ = src >> 16; // Red
}
else
{
// Non-Transparent pixel
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255((src & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 8) & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 16) & 0xFF) * alpha + pByte * ialpha);
}
}
while (--count != 0);
}
else
{
do
{
uint32_t src = ((const uint32_t*)bitmapExtraPointer)[*bitmapPointer++];
uint8_t srcAlpha = src >> 24;
uint8_t alpha = LCD::div255((*covers) * LCD::div255(srcAlpha * totalAlpha));
covers++;
if (alpha)
{
uint8_t ialpha = 0xFF - alpha;
uint8_t pByte = *p;
*p++ = LCD::div255((src & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 8) & 0xFF) * alpha + pByte * ialpha);
pByte = *p;
*p++ = LCD::div255(((src >> 16) & 0xFF) * alpha + pByte * ialpha);
}
else
{
p += 3;
}
}
while (--count != 0);
}
}
}
bool PainterRGB888L8Bitmap::renderInit()
{
bitmapPointer = 0;
bitmapExtraPointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::L8)
{
bitmapPointer = bitmap.getData();
if (!bitmapPointer)
{
return false;
}
bitmapPointer += currentX + currentY * bitmapRectToFrameBuffer.width;
bitmapExtraPointer = bitmap.getExtraData();
assert((bitmapExtraPointer != 0 && (*(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_RGB888 || *(const uint16_t*)bitmapExtraPointer == Bitmap::CLUT_FORMAT_L8_ARGB8888)));
bitmapExtraPointer += 4; // Skip header
return true;
}
return false;
}
bool PainterRGB888L8Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
if ((Bitmap::ClutFormat)((const uint16_t*)bitmapExtraPointer)[-2] == Bitmap::CLUT_FORMAT_L8_RGB888)
{
const uint8_t* clut = bitmapExtraPointer + (*bitmapPointer++) * 3;
blue = *clut++;
green = *clut++;
red = *clut;
alpha = 0xFF; // No alpha per pixel in the image, it is solid
}
else // L8_ARGB8888
{
const uint32_t* clut = ((const uint32_t*)bitmapExtraPointer) + (*bitmapPointer++);
uint32_t argb8888 = *(const uint32_t*)clut;
alpha = (argb8888 >> 24) & 0xFF;
red = (argb8888 >> 16) & 0xFF;
green = (argb8888 >> 8) & 0xFF;
blue = (argb8888) & 0xFF;
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,72 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <platform/driver/lcd/LCD8bpp_RGBA2222.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/canvas/PainterRGBA2222.hpp>
namespace touchgfx
{
void PainterRGBA2222::render(uint8_t* ptr, int x, int xAdjust, int /*y*/, unsigned count, const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
if (totalAlpha == 0xFF)
{
do
{
uint8_t alpha = *covers;
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
else
{
do
{
uint8_t alpha = LCD::div255((*covers) * totalAlpha);
covers++;
if (alpha == 0xFF)
{
*p = painterColor;
}
else
{
*p = mixColors(painterRed, painterGreen, painterBlue, *p, alpha);
}
p++;
}
while (--count != 0);
}
}
bool PainterRGBA2222::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
red = painterRed;
green = painterGreen;
blue = painterBlue;
alpha = painterAlpha;
return true;
}
} // namespace touchgfx

View File

@@ -0,0 +1,143 @@
/**
******************************************************************************
* This file is part of the TouchGFX 4.14.0 distribution.
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include <touchgfx/widgets/canvas/PainterRGBA2222Bitmap.hpp>
namespace touchgfx
{
void PainterRGBA2222Bitmap::setBitmap(const Bitmap& bmp)
{
bitmap = bmp;
assert((bitmap.getId() == BITMAP_INVALID || bitmap.getFormat() == Bitmap::RGBA2222) && "The chosen painter only works with RGBA2222 bitmaps");
bitmapRectToFrameBuffer = bitmap.getRect();
DisplayTransformation::transformDisplayToFrameBuffer(bitmapRectToFrameBuffer);
}
void PainterRGBA2222Bitmap::render(uint8_t* ptr,
int x,
int xAdjust,
int y,
unsigned count,
const uint8_t* covers)
{
uint8_t* p = ptr + (x + xAdjust);
currentX = x + areaOffsetX;
currentY = y + areaOffsetY;
if (!renderInit())
{
return;
}
if (currentX + (int)count > bitmapRectToFrameBuffer.width)
{
count = bitmapRectToFrameBuffer.width - currentX;
}
uint8_t totalAlpha = LCD::div255(widgetAlpha * painterAlpha);
const uint8_t* src = bitmapRGBA2222Pointer;
if (totalAlpha == 0xFF)
{
do
{
uint8_t srcAlpha = ((*src) & 0x03) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha == 0xFF)
{
// Solid pixel
*p = *src;
}
else if (alpha)
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
else
{
do
{
uint8_t srcAlpha = ((*src) & 0x03) * 0x55;
uint8_t alpha = LCD::div255((*covers) * srcAlpha);
covers++;
if (alpha) // This can never get to max=0xFF*0xFF as totalAlpha<255
{
// Non-Transparent pixel
*p = mixColors(*src, *p, alpha);
}
p++;
src++;
}
while (--count != 0);
}
}
bool PainterRGBA2222Bitmap::renderInit()
{
bitmapRGBA2222Pointer = 0;
if (bitmap.getId() == BITMAP_INVALID)
{
return false;
}
if ((currentX >= bitmapRectToFrameBuffer.width) || (currentY >= bitmapRectToFrameBuffer.height))
{
// Outside bitmap area, do not draw anything
// Consider the following instead of "return" to get a tiled image:
// currentX %= bitmapRectToFrameBuffer.width
// currentY %= bitmapRectToFrameBuffer.height
return false;
}
if (bitmap.getFormat() == Bitmap::RGBA2222)
{
bitmapRGBA2222Pointer = bitmap.getData();
if (!bitmapRGBA2222Pointer)
{
return false;
}
bitmapRGBA2222Pointer += currentX + currentY * bitmapRectToFrameBuffer.width;
return true;
}
return false;
}
bool PainterRGBA2222Bitmap::renderNext(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha)
{
if (currentX >= bitmapRectToFrameBuffer.width)
{
return false;
}
else if (bitmapRGBA2222Pointer != 0)
{
uint16_t RGBA2222 = *bitmapRGBA2222Pointer++;
red = LCD8bpp_RGBA2222::getRedFromColor(RGBA2222);
green = LCD8bpp_RGBA2222::getGreenFromColor(RGBA2222);
blue = LCD8bpp_RGBA2222::getBlueFromColor(RGBA2222);
alpha = (RGBA2222 & 0x03) * 0x55; // To get full range 0-0xFF
}
// Apply given alpha from setAlpha()
alpha = LCD::div255(alpha * painterAlpha);
return true;
}
} // namespace touchgfx