Sample GUI for LPC4088. Base code to begin dev
Dependencies: DMBasicGUI DMSupport
Fork of lpc4088_displaymodule_shipped_demo by
Diff: AppLauncherSpecial.cpp
- Revision:
- 0:b94e330c98ac
- Child:
- 2:229f88d6f56b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AppLauncherSpecial.cpp Fri Mar 20 13:36:44 2015 +0000 @@ -0,0 +1,385 @@ +/* + * Copyright 2014 Embedded Artists AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "mbed.h" +#include "AppLauncherSpecial.h" +#include "lpc_swim_image.h" +#include "lpc_swim_font.h" +#include "Button.h" +#include "ImageButton.h" +#include "image_data.h" + +/****************************************************************************** + * Defines and typedefs + *****************************************************************************/ + +#define APP_PREFIX "[Launcher*] " + +#define NO_APPLICATION (-1) + +#define APP_SIGID_TOUCH 0x1 + +/****************************************************************************** + * Private variables + *****************************************************************************/ + +static int appToLaunch = NO_APPLICATION; +static osThreadId appThread; + +/****************************************************************************** + * Private functions + *****************************************************************************/ + +static void buttonClicked(uint32_t x) +{ + if (appToLaunch == NO_APPLICATION) { + appToLaunch = (int)x; + } +} + +void AppLauncherSpecial::draw() +{ + // Prepare fullscreen + swim_window_open(_win, + _disp->width(), _disp->height(), // full size + (COLOR_T*)_fb, + 0,0,_disp->width()-1, _disp->height()-1, // window position and size + 0, // border + BLACK, WHITE, /*WHITE, BLACK,*/ BLACK); // colors: pen, backgr, forgr + //swim_set_title(_win, "Demo Program", WHITE); + + swim_put_image(_win, _bgImg.pixels, _bgImg.width, _bgImg.height); + + if (_supportsCalibration) { + const char* msg = "(Press physical UserButton >2s to calibrate touch)"; + int w, h; + swim_get_string_bounds(_win, msg, &w, &h); + swim_set_font_transparency(_win, 0); // 0=Transparent, 1=Opaque + swim_put_text_xy(_win, msg, (_disp->width()-w)/2, _disp->height()-(3*h)/2); + swim_set_font_transparency(_win, 1); // 0=Transparent, 1=Opaque + } + + for (int i = 0; i < _usedButtons; i++) { + _buttons[i]->draw(); + } +} + +void AppLauncherSpecial::onTouchEvent() +{ + _newTouchEvent = true; + osSignalSet(appThread, APP_SIGID_TOUCH); +} + +void AppLauncherSpecial::onButtonEvent() +{ + _newButtonEvent = true; + osSignalSet(appThread, APP_SIGID_TOUCH); +} + +static void onTimeoutEvent(void const* arg) +{ + *((bool*)arg) = true; + osSignalSet(appThread, APP_SIGID_TOUCH); +} + +/****************************************************************************** + * Public functions + *****************************************************************************/ + +AppLauncherSpecial::AppLauncherSpecial(int iconWidth, int iconHeight) : + _disp(NULL), _win(NULL), _fb(NULL), _usedButtons(0), + _resBg(NULL), _iconWidth(iconWidth), _iconHeight(iconHeight) +{ + _bgImg.pointerToFree = NULL; + _bgImg.pixels = NULL; + _currentTime[0] = '\0'; + + for (int i = 0; i < NumberOfButtons; i++) { + _buttons[i] = NULL; + } + bool r; + int n; + if (DMBoard::instance().touchPanel()->info(&r, &n, &_supportsCalibration) != TouchPanel::TouchError_Ok) { + _supportsCalibration = false; + } +} + +AppLauncherSpecial::~AppLauncherSpecial() +{ + teardown(); +} + +bool AppLauncherSpecial::setup() +{ + RtosLog* log = DMBoard::instance().logger(); + + _disp = DMBoard::instance().display(); + _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T)); + _fb = _disp->allocateFramebuffer(); + + if (_win == NULL || _fb == NULL) { + log->printf(APP_PREFIX"Failed to allocate memory for framebuffer\r\n"); + return false; + } + + if (Image::decode(_resBg, Image::RES_16BIT, &_bgImg) != 0) { + log->printf(APP_PREFIX"Failed to load background image\n"); + return false; + } + + return true; +} + +void AppLauncherSpecial::runToCompletion() +{ + DMBoard* board = &DMBoard::instance(); + RtosLog* log = board->logger(); + + appThread = osThreadGetId(); + + // Draw something on the framebuffer before using it so that it doesn't look garbled + draw(); + + // Start display in default mode (16-bit) + Display::DisplayError disperr = _disp->powerUp(_fb); + if (disperr != Display::DisplayError_Ok) { + log->printf(APP_PREFIX"Failed to initialize the display, got error %d\r\n", disperr); + return; + } + + // Render the current time in the upper right corner once every second + bool updateClock = false; + RtosTimer updateClockTimer(onTimeoutEvent, osTimerPeriodic, &updateClock); + updateClockTimer.start(1000); + int clockXOff, clockYOff; + swim_get_string_bounds(_win, "Fri Mar 20 10:32:58 2015", &clockXOff, &clockYOff); + clockXOff = _win->xpvmax - clockXOff - 20; + clockYOff = 5; + + // To keep track of the button pushes + bool buttonPressed = false; + bool buttonTimeout = false; + InterruptIn button(P2_10); + button.rise(this, &AppLauncherSpecial::onButtonEvent); + button.fall(this, &AppLauncherSpecial::onButtonEvent); + RtosTimer buttonTimer(onTimeoutEvent, osTimerOnce, &buttonTimeout); + + // To prevent the "exit" click of a launched application to launch + // a new application. This could happen on a multitouch display if + // the launched applications' exit/ok/cancel button is located on + // top of one of the buttons in the launcher. + Timer tExit; + tExit.start(); + + // Wait for touches + TouchPanel* touch = board->touchPanel(); + FunctionPointer* fpOld = touch->setListener(new FunctionPointer(this, &AppLauncherSpecial::onTouchEvent)); + touch_coordinate_t coord; + while (true) { + Thread::signal_wait(APP_SIGID_TOUCH); + if (_newTouchEvent) { + if (buttonPressed) { + // cancel + buttonPressed = false; + buttonTimer.stop(); + } + _newTouchEvent = false; + if (touch->read(coord) != TouchPanel::TouchError_Ok) { + log->printf("Failed to read touch coordinate\n"); + continue; + } + // Process the touch coordinate for each button + for (int i = 0; i < NumberOfButtons; i++) { + if (_buttons[i] != NULL) { + if (_buttons[i]->handle(coord.x, coord.y, coord.z > 0)) { + _buttons[i]->draw(); + } + } + } + } else if (buttonTimeout) { + if (board->buttonPressed()) { + appToLaunch = CalibrationApp; + } + buttonPressed = false; + buttonTimeout = false; + } else if (_newButtonEvent) { + _newButtonEvent = false; + if (board->buttonPressed()) { + buttonPressed = true; + buttonTimer.start(2000); + } else { + buttonPressed = false; + buttonTimer.stop(); + } + continue; + } else if (updateClock) { + updateClock = false; + time_t seconds = time(0); + sprintf(_currentTime, "%-25s", ctime(&seconds)); + swim_put_text_xy(_win, _currentTime, clockXOff, clockYOff); + continue; + } + + if (appToLaunch != NO_APPLICATION) { + if (tExit.read_ms() < 500) { + appToLaunch = NO_APPLICATION; + continue; + } + App* a = NULL; + if (_callback != NULL) { + a = _callback(appToLaunch); + } + if (a != NULL) { + if (a->setup()) { + a->runToCompletion(); + a->teardown(); + } + delete a; + } + tExit.reset(); + appToLaunch = NO_APPLICATION; + } + } + + // restore old touch listener (get our listener in return) + fpOld = touch->setListener(fpOld); + delete fpOld; +} + +bool AppLauncherSpecial::teardown() +{ + if (_win != NULL) { + free(_win); + _win = NULL; + } + if (_fb != NULL) { + free(_fb); + _fb = NULL; + } + for (int i = 0; i < NumberOfButtons; i++) { + _buttons[i] = NULL; + if (_buttons[i] != NULL) { + delete _buttons[i]; + _buttons[i] = NULL; + } + } + if (_bgImg.pointerToFree != NULL) { + free(_bgImg.pointerToFree); + _bgImg.pointerToFree = NULL; + } + return true; +} + +void AppLauncherSpecial::setAppCreatorFunc(App*(*callback)(uint32_t buttonID)) +{ + _callback = callback; +} + +bool AppLauncherSpecial::addButton(uint32_t buttonID, const char* caption) +{ + int idx = _usedButtons++; + int xspace = ((_disp->width() - ButtonColumns * ButtonWidth) / (ButtonColumns + 1)); + int yspace = ((_disp->height() - TitleHeight - ButtonRows * ButtonHeight) / (ButtonRows + 1)); + + _buttons[idx] = new Button(caption, (COLOR_T*)_fb, + xspace + (ButtonWidth + xspace)*(idx%ButtonColumns), + TitleHeight + yspace + (ButtonHeight + yspace)*(idx/ButtonColumns), + ButtonWidth, ButtonHeight); + _buttons[idx]->setAction(buttonClicked, buttonID); + //_buttons[idx]->draw(); + return true; +} + +bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* imgUp, const char* imgDown) +{ + return addImageButton(buttonID, NULL, BLACK, imgUp, imgDown); +} + +bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const char* imgUp, const char* imgDown) +{ + int idx = _usedButtons++; + int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1)); + int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1)); + + ImageButton* img = new ImageButton((COLOR_T*)_fb, + xspace + (_iconWidth + xspace)*(idx%ButtonColumns), + TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), + _iconWidth, _iconHeight, caption, color); + if (img->loadImages(imgUp, imgDown)) { + _buttons[idx] = img; + _buttons[idx]->setAction(buttonClicked, buttonID); + //_buttons[idx]->draw(); + return true; + } else { + //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown); + return false; + } +} + +bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown, unsigned int imgDownSize) +{ + return addImageButton(buttonID, NULL, BLACK, imgUp, imgUpSize, imgDown, imgDownSize); +} + +bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown, unsigned int imgDownSize) +{ + int idx = _usedButtons++; + int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1)); + int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1)); + + ImageButton* img = new ImageButton((COLOR_T*)_fb, + xspace + (_iconWidth + xspace)*(idx%ButtonColumns), + TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), + _iconWidth, _iconHeight, caption, color); + img->setTransparency(RED); + if (img->loadImages(imgUp, imgUpSize, imgDown, imgDownSize)) { + _buttons[idx] = img; + _buttons[idx]->setAction(buttonClicked, buttonID); + //_buttons[idx]->draw(); + return true; + } else { + //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown); + return false; + } +} + +bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, Resource* resUp, Resource* resDown) +{ + int idx = _usedButtons++; + int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1)); + int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1)); + + ImageButton* img = new ImageButton((COLOR_T*)_fb, + xspace + (_iconWidth + xspace)*(idx%ButtonColumns), + TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), + _iconWidth, _iconHeight, caption, color); + if (img->loadImages(resUp, resDown)) { + _buttons[idx] = img; + _buttons[idx]->setAction(buttonClicked, buttonID); + //_buttons[idx]->draw(); + return true; + } else { + //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown); + return false; + } +} + +void AppLauncherSpecial::addResource(Resources id, Resource* res) +{ + _resBg = res; +} +