Chris Womack / DMBasicGUI

Fork of DMBasicGUI by Embedded Artists

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AppLauncher.cpp Source File

AppLauncher.cpp

00001 /*
00002  *  Copyright 2014 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 
00018 #include "mbed.h"
00019 #include "AppLauncher.h"
00020 #include "lpc_swim_font.h"
00021 #include "Button.h"
00022 #include "ImageButton.h"
00023  #include "lpc_winfreesystem14x16.h"
00024 
00025 /******************************************************************************
00026  * Defines and typedefs
00027  *****************************************************************************/
00028  
00029 #define APP_PREFIX  "[Launcher] "
00030 
00031 #define NO_APPLICATION  (-1)
00032 
00033 #define APP_SIGID_TOUCH  0x1
00034 
00035 /******************************************************************************
00036  * Private variables
00037  *****************************************************************************/
00038 
00039 static int appToLaunch = NO_APPLICATION;
00040 static osThreadId appThread;
00041 
00042 /******************************************************************************
00043  * Private functions
00044  *****************************************************************************/
00045 
00046 static void buttonClicked(uint32_t x)
00047 {
00048     if (appToLaunch == NO_APPLICATION) {
00049         appToLaunch = (int)x;
00050     }
00051 }
00052 
00053 void AppLauncher::draw()
00054 {
00055     // Prepare fullscreen
00056     swim_window_open(_win, 
00057                      _disp->width(), _disp->height(),         // full size
00058                      (COLOR_T*)_fb,
00059                      0,0,_disp->width()-1, _disp->height()-1, // window position and size
00060                      0,                                       // border
00061                      BLACK, WHITE, BLACK);                    // colors: pen, backgr, forgr
00062     swim_set_font(_win, (FONT_T*)&font_winfreesys14x16);
00063 
00064     if (_supportsCalibration) {
00065       const char* msg = "(Press physical UserButton >2s to calibrate touch)";
00066       int w, h;
00067       swim_get_string_bounds(_win, msg, &w, &h);
00068       //swim_put_text_xy(_win, msg, (_disp->width()-w)/2, _disp->height()-h*4);
00069     }
00070     
00071     for (int i = 0; i < _usedButtons; i++) {
00072         _buttons[i]->draw();
00073     }
00074 }
00075 
00076 void AppLauncher::onTouchEvent()
00077 {
00078     _newTouchEvent = true;
00079     osSignalSet(appThread, APP_SIGID_TOUCH);
00080 }
00081 
00082 void AppLauncher::onButtonEvent()
00083 {
00084     _newButtonEvent = true;
00085     osSignalSet(appThread, APP_SIGID_TOUCH);
00086 }
00087 
00088 static void onTimeoutEvent(void const* arg)
00089 {
00090     *((bool*)arg) = true;
00091     osSignalSet(appThread, APP_SIGID_TOUCH);
00092 }
00093 
00094 /******************************************************************************
00095  * Public functions
00096  *****************************************************************************/
00097 
00098 AppLauncher::AppLauncher() : _disp(NULL), _win(NULL), _fb(NULL), _usedButtons(0)
00099 {
00100     for (int i = 0; i < NumberOfButtons; i++) {
00101         _buttons[i] = NULL;
00102     }
00103     bool r;
00104     int n;
00105     if (DMBoard::instance().touchPanel()->info(&r, &n, &_supportsCalibration) != TouchPanel::TouchError_Ok) {
00106       _supportsCalibration = false;
00107     }
00108 }
00109 
00110 AppLauncher::~AppLauncher()
00111 {
00112     teardown();
00113 }
00114 
00115 bool AppLauncher::setup()
00116 {
00117     RtosLog* log = DMBoard::instance().logger();
00118 
00119     _disp = DMBoard::instance().display();
00120     _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
00121     _fb = _disp->allocateFramebuffer();
00122     
00123     if (_win == NULL || _fb == NULL) {
00124         log->printf(APP_PREFIX"Failed to allocate memory for framebuffer\r\n");
00125         return false;
00126     }
00127     
00128     return true;
00129 }
00130 
00131 void AppLauncher::runToCompletion()
00132 {
00133     DMBoard* board = &DMBoard::instance();
00134     RtosLog* log = board->logger();
00135     
00136     appThread = osThreadGetId();
00137 
00138     // Draw something on the framebuffer before using it so that it doesn't look garbled
00139     draw();
00140     
00141     // Start display in default mode (16-bit)
00142     Display::DisplayError disperr = _disp->powerUp(_fb);
00143     if (disperr != Display::DisplayError_Ok) {
00144         log->printf(APP_PREFIX"Failed to initialize the display, got error %d\r\n", disperr);
00145         return;
00146     }
00147     
00148     // To keep track of the button pushes
00149     bool buttonPressed = false;
00150     bool buttonTimeout = false;
00151     InterruptIn button(P2_10);
00152     button.rise(this, &AppLauncher::onButtonEvent);
00153     button.fall(this, &AppLauncher::onButtonEvent);
00154     RtosTimer  buttonTimer(onTimeoutEvent, osTimerOnce, &buttonTimeout);
00155     
00156     // Wait for touches
00157     TouchPanel* touch = board->touchPanel();
00158     FunctionPointer* fpOld = touch->setListener(new FunctionPointer(this, &AppLauncher::onTouchEvent));
00159     touch_coordinate_t coord;
00160     while (true) {
00161         Thread::signal_wait(APP_SIGID_TOUCH);
00162         if (_newTouchEvent) {
00163           if (buttonPressed) {
00164             // cancel
00165             buttonPressed = false;
00166             buttonTimer.stop();
00167           }
00168           _newTouchEvent = false;
00169           if (touch->read(coord) != TouchPanel::TouchError_Ok) {
00170             log->printf("Failed to read touch coordinate\n");
00171             continue;
00172           }
00173           // Process the touch coordinate for each button
00174           for (int i = 0; i < NumberOfButtons; i++) {
00175             if (_buttons[i] != NULL) {
00176               if (_buttons[i]->handle(coord.x, coord.y, coord.z > 0)) {
00177                 _buttons[i]->draw();
00178               }
00179             }
00180           }
00181         } else if (buttonTimeout) {
00182           if (board->buttonPressed()) {
00183             appToLaunch = CalibrationApp;
00184           }
00185           buttonPressed = false;
00186           buttonTimeout = false;
00187         } else if (_newButtonEvent) {
00188           _newButtonEvent = false;
00189           if (board->buttonPressed()) {
00190             buttonPressed = true;
00191             buttonTimer.start(2000);
00192           } else {
00193             buttonPressed = false;
00194             buttonTimer.stop();
00195           }
00196           continue;
00197         }
00198         
00199         if (appToLaunch != NO_APPLICATION) {
00200             App* a = NULL;
00201             if (_callback != NULL) {
00202                 a = _callback(appToLaunch);
00203             }
00204             if (a != NULL) {
00205                 if (a->setup()) {
00206                     a->runToCompletion();
00207                     a->teardown();
00208                 }
00209                 delete a;
00210             }
00211             appToLaunch = NO_APPLICATION;
00212         }
00213     }
00214     
00215     restore old touch listener (get our listener in return)
00216     fpOld = touch->setListener(fpOld);
00217     delete fpOld;
00218 }
00219 
00220 bool AppLauncher::teardown()
00221 {
00222     if (_win != NULL) {
00223         free(_win);
00224         _win = NULL;
00225     }
00226     if (_fb != NULL) {
00227         free(_fb);
00228         _fb = NULL;
00229     }
00230     for (int i = 0; i < NumberOfButtons; i++) {
00231         _buttons[i] = NULL;
00232         if (_buttons[i] != NULL) {
00233             delete _buttons[i];
00234             _buttons[i] = NULL;
00235         }
00236     }
00237     return true;
00238 }
00239 
00240 void AppLauncher::setAppCreatorFunc(App*(*callback)(uint32_t buttonID))
00241 {
00242     _callback = callback;
00243 }
00244 
00245 bool AppLauncher::addButton(uint32_t buttonID, const char* caption)
00246 {
00247     int idx = _usedButtons++;
00248     int xspace = ((_disp->width() - ButtonColumns * ButtonWidth) / (ButtonColumns + 1));
00249     int yspace = ((_disp->height() - TitleHeight - ButtonRows * ButtonHeight) / (ButtonRows + 1));
00250     
00251     _buttons[idx] = new Button(caption, (COLOR_T*)_fb, 
00252                               xspace + (ButtonWidth + xspace)*(idx%ButtonColumns), 
00253                               TitleHeight + yspace + (ButtonHeight + yspace)*(idx/ButtonColumns), 
00254                               ButtonWidth, ButtonHeight);
00255     _buttons[idx]->setAction(buttonClicked, buttonID);
00256     //_buttons[idx]->draw();
00257     return true;
00258 }
00259 
00260 bool AppLauncher::addImageButton(uint32_t buttonID, const char* imgUp, const char* imgDown)
00261 {
00262     return addImageButton(buttonID, NULL, BLACK, imgUp, imgDown);
00263 }
00264 
00265 bool AppLauncher::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const char* imgUp, const char* imgDown)
00266 {
00267     int idx = _usedButtons++;
00268     int xspace = ((_disp->width() - ButtonColumns * 128) / (ButtonColumns + 1));
00269     int yspace = ((_disp->height() - TitleHeight - ButtonRows * 128) / (ButtonRows + 1));
00270     int yoff = (caption == NULL) ? 0 : -15; // compensate for caption taking up space
00271     
00272     ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
00273                               xspace + (128 + xspace)*(idx%ButtonColumns), 
00274                               TitleHeight + yspace + (128 + yspace)*(idx/ButtonColumns) + yoff, 
00275                               128, 128, caption, color);
00276     if (img->loadImages(imgUp, imgDown)) {
00277       _buttons[idx] = img;
00278       _buttons[idx]->setAction(buttonClicked, buttonID);
00279       //_buttons[idx]->draw();
00280       return true;
00281     } else {
00282       //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
00283       return false;
00284     }
00285 }
00286 
00287 bool AppLauncher::addImageButton(uint32_t buttonID, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown, unsigned int imgDownSize)
00288 {
00289     return addImageButton(buttonID, NULL, BLACK, imgUp, imgUpSize, imgDown, imgDownSize);
00290 }
00291 
00292 bool AppLauncher::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown, unsigned int imgDownSize)
00293 {
00294     int idx = _usedButtons++;
00295     int xspace = ((_disp->width() - ButtonColumns * 128) / (ButtonColumns + 1));
00296     int yspace = ((_disp->height() - TitleHeight - ButtonRows * 128) / (ButtonRows + 1));
00297     int yoff = (caption == NULL) ? 0 : -15; // compensate for caption taking up space
00298     
00299     ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
00300                               xspace + (128 + xspace)*(idx%ButtonColumns),
00301                               TitleHeight + yspace + (128 + yspace)*(idx/ButtonColumns) + yoff, 
00302                               128, 128, caption, color);
00303     if (img->loadImages(imgUp, imgUpSize, imgDown, imgDownSize)) {
00304       _buttons[idx] = img;
00305       _buttons[idx]->setAction(buttonClicked, buttonID);
00306       //_buttons[idx]->draw();
00307       return true;
00308     } else {
00309       //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
00310       return false;
00311     }
00312 }