Files
stw24/Middlewares/ST/touchgfx/framework/source/touchgfx/widgets/Keyboard.cpp

293 lines
9.5 KiB
C++

/******************************************************************************
* Copyright (c) 2018(-2023) STMicroelectronics.
* All rights reserved.
*
* This file is part of the TouchGFX 4.22.0 distribution.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
*******************************************************************************/
#include <touchgfx/Bitmap.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/Drawable.hpp>
#include <touchgfx/Font.hpp>
#include <touchgfx/FontManager.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/lcd/LCD.hpp>
#include <touchgfx/widgets/Keyboard.hpp>
namespace touchgfx
{
Keyboard::Keyboard()
: Container(), keyListener(0), buffer(0), bufferSize(0), bufferPosition(0), image(), enteredText(), layout(0), keyMappingList(0), highlightImage(), cancelIsEmitted(false)
{
setTouchable(true);
image.setXY(0, 0);
Keyboard::add(image);
highlightImage.setVisible(false);
Keyboard::add(highlightImage);
enteredText.setColor(Color::getColorFromRGB(0, 0, 0));
Keyboard::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)
{
const 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.
const uint16_t fontHeight = font->getHeight();
for (uint8_t i = 0; i < layout->numberOfKeys; i++)
{
const Key& key = layout->keyArray[i];
if (key.keyArea.intersect(invalidatedArea))
{
const uint8_t keyId = key.keyId;
const 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;
const 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& event)
{
const ClickEvent::ClickEventType type = event.getType();
if (type == ClickEvent::RELEASED && cancelIsEmitted)
{
cancelIsEmitted = false;
return;
}
const int16_t x = event.getX();
const int16_t y = event.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())
{
callbackArea.callback->execute();
if (keyListener)
{
keyListener->execute(0);
}
}
}
else
{
const Keyboard::Key key = getKeyForCoordinates(x, y);
if (type == ClickEvent::PRESSED)
{
if (key.keyId != 0)
{
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 (key.keyId != 0 && buffer)
{
const Unicode::UnicodeChar c = getCharForKey(key.keyId);
if (c != 0 && bufferPosition < (bufferSize - 1))
{
enteredText.invalidateContent();
buffer[bufferPosition++] = c;
buffer[bufferPosition] = 0;
enteredText.invalidateContent();
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& event)
{
if (highlightImage.isVisible() && (!highlightImage.getRect().intersect(static_cast<int16_t>(event.getNewX()), static_cast<int16_t>(event.getNewY()))) && (!cancelIsEmitted))
{
// Send a CANCEL click event, if user has dragged out of currently pressed/highlighted key.
const ClickEvent cancelEvent(ClickEvent::CANCEL, static_cast<int16_t>(event.getOldX()), static_cast<int16_t>(event.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