The out-of-the-box demo application flashed on all display modules before they are shipped.

Dependencies:   DMBasicGUI DMSupport

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers <title>AppLauncherSpecial.cpp Source File</title>

AppLauncherSpecial.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 "AppLauncherSpecial.h"
00020 #include "lpc_swim_image.h"
00021 #include "lpc_swim_font.h"
00022 #include "Button.h"
00023 #include "ImageButton.h"
00024 #include "image_data.h"
00025 
00026 /******************************************************************************
00027  * Defines and typedefs
00028  *****************************************************************************/
00029  
00030 #define APP_PREFIX  "[Launcher*] "
00031 
00032 #define NO_APPLICATION  (-1)
00033 
00034 #define APP_SIGID_TOUCH  0x1
00035 
00036 /******************************************************************************
00037  * Private variables
00038  *****************************************************************************/
00039 
00040 static int appToLaunch = NO_APPLICATION;
00041 static osThreadId appThread;
00042 
00043 /******************************************************************************
00044  * Private functions
00045  *****************************************************************************/
00046 
00047 static void buttonClicked(uint32_t x)
00048 {
00049     if (appToLaunch == NO_APPLICATION) {
00050         appToLaunch = (int)x;
00051     }
00052 }
00053 
00054 void AppLauncherSpecial::draw()
00055 {
00056     // Prepare fullscreen
00057     swim_window_open(_win, 
00058                      _disp->width(), _disp->height(),         // full size
00059                      (COLOR_T*)_fb,
00060                      0,0,_disp->width()-1, _disp->height()-1, // window position and size
00061                      0,                                     // border
00062                      BLACK, WHITE, /*WHITE, BLACK,*/ BLACK);                    // colors: pen, backgr, forgr
00063     //swim_set_title(_win, "Demo Program", WHITE);
00064 
00065     swim_put_image(_win, _bgImg.pixels, _bgImg.width, _bgImg.height);
00066     
00067     if (_supportsCalibration) {
00068       const char* msg = "(Press physical UserButton >2s to calibrate touch)";
00069       int w, h;
00070       swim_get_string_bounds(_win, msg, &w, &h);
00071       swim_set_font_transparency(_win, 0); // 0=Transparent, 1=Opaque
00072       swim_put_text_xy(_win, msg, (_disp->width()-w)/2, _disp->height()-(3*h)/2);
00073       swim_set_font_transparency(_win, 1); // 0=Transparent, 1=Opaque
00074     }
00075     
00076     for (int i = 0; i < _usedButtons; i++) {
00077         _buttons[i]->draw();
00078     }
00079 }
00080 
00081 void AppLauncherSpecial::onTouchEvent()
00082 {
00083     _newTouchEvent = true;
00084     osSignalSet(appThread, APP_SIGID_TOUCH);
00085 }
00086 
00087 void AppLauncherSpecial::onButtonEvent()
00088 {
00089     _newButtonEvent = true;
00090     osSignalSet(appThread, APP_SIGID_TOUCH);
00091 }
00092 
00093 static void onTimeoutEvent(void const* arg)
00094 {
00095     *((bool*)arg) = true;
00096     osSignalSet(appThread, APP_SIGID_TOUCH);
00097 }
00098 
00099 /******************************************************************************
00100  * Public functions
00101  *****************************************************************************/
00102 
00103 AppLauncherSpecial::AppLauncherSpecial(int iconWidth, int iconHeight) : 
00104     _disp(NULL), _win(NULL), _fb(NULL), _usedButtons(0), 
00105     _resBg(NULL), _iconWidth(iconWidth), _iconHeight(iconHeight)
00106 {
00107     _bgImg.pointerToFree = NULL;
00108     _bgImg.pixels = NULL;
00109     _currentTime[0] = '\0';
00110 
00111     for (int i = 0; i < NumberOfButtons; i++) {
00112         _buttons[i] = NULL;
00113     }
00114     bool r;
00115     int n;
00116     if (DMBoard::instance().touchPanel()->info(&r, &n, &_supportsCalibration) != TouchPanel::TouchError_Ok) {
00117       _supportsCalibration = false;
00118     }
00119 }
00120 
00121 AppLauncherSpecial::~AppLauncherSpecial()
00122 {
00123     teardown();
00124 }
00125 
00126 bool AppLauncherSpecial::setup()
00127 {
00128     RtosLog* log = DMBoard::instance().logger();
00129 
00130     _disp = DMBoard::instance().display();
00131     _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
00132     _fb = _disp->allocateFramebuffer();
00133     
00134     if (_win == NULL || _fb == NULL) {
00135         log->printf(APP_PREFIX"Failed to allocate memory for framebuffer\r\n");
00136         return false;
00137     }
00138     
00139     if (Image::decode(_resBg, Image::RES_16BIT, &_bgImg) != 0) {
00140         log->printf(APP_PREFIX"Failed to load background image\n");
00141         return false;
00142     }
00143     
00144     return true;
00145 }
00146 
00147 void AppLauncherSpecial::runToCompletion()
00148 {
00149     DMBoard* board = &DMBoard::instance();
00150     RtosLog* log = board->logger();
00151     
00152     appThread = osThreadGetId();
00153 
00154     // Draw something on the framebuffer before using it so that it doesn't look garbled
00155     draw();
00156     
00157     // Start display in default mode (16-bit)
00158     Display::DisplayError disperr = _disp->powerUp(_fb);
00159     if (disperr != Display::DisplayError_Ok) {
00160         log->printf(APP_PREFIX"Failed to initialize the display, got error %d\r\n", disperr);
00161         return;
00162     }
00163     
00164     // Render the current time in the upper right corner once every second
00165     bool updateClock = false;
00166     EventQueue updateClockTimer(4*EVENTS_EVENT_SIZE);
00167     int updateClockTimerId = updateClockTimer.call_in(1000, onTimeoutEvent, &updateClock);    
00168     int clockXOff, clockYOff;
00169     swim_get_string_bounds(_win, "Fri Mar 20 10:32:58 2015", &clockXOff, &clockYOff);
00170     clockXOff = _win->xpvmax - clockXOff - 20;
00171     clockYOff = 5;
00172     
00173     // To keep track of the button pushes
00174     bool buttonPressed = false;
00175     bool buttonTimeout = false;
00176     InterruptIn button(P2_10);
00177     button.rise(callback(this, &AppLauncherSpecial::onButtonEvent));
00178     button.fall(callback(this, &AppLauncherSpecial::onButtonEvent));
00179     
00180     EventQueue buttonTimer(4*EVENTS_EVENT_SIZE);
00181     int buttonTimerId = buttonTimer.call_in(2000, onTimeoutEvent, &buttonTimeout);
00182     
00183     // To prevent the "exit" click of a launched application to launch
00184     // a new application. This could happen on a multitouch display if
00185     // the launched applications' exit/ok/cancel button is located on
00186     // top of one of the buttons in the launcher.
00187     Timer tExit;
00188     tExit.start();
00189     
00190     // Wait for touches
00191     TouchPanel* touch = board->touchPanel();
00192     touch->setListener(callback(this, &AppLauncherSpecial::onTouchEvent));
00193     touch_coordinate_t coord;
00194     while (true) {
00195         ThisThread::flags_wait_all(APP_SIGID_TOUCH);
00196         if (_newTouchEvent) {
00197           if (buttonPressed) {
00198             // cancel
00199             buttonPressed = false;
00200             buttonTimer.cancel(buttonTimerId);
00201           }
00202           _newTouchEvent = false;
00203           if (touch->read(coord) != TouchPanel::TouchError_Ok) {
00204             log->printf("Failed to read touch coordinate\n");
00205             continue;
00206           }
00207           // Process the touch coordinate for each button
00208           for (int i = 0; i < NumberOfButtons; i++) {
00209             if (_buttons[i] != NULL) {
00210               if (_buttons[i]->handle(coord.x, coord.y, coord.z > 0)) {
00211                 _buttons[i]->draw();
00212               }
00213             }
00214           }
00215         } else if (buttonTimeout) {
00216           if (board->buttonPressed()) {
00217             appToLaunch = CalibrationApp;
00218           }
00219           buttonPressed = false;
00220           buttonTimeout = false;
00221         } else if (_newButtonEvent) {
00222           _newButtonEvent = false;
00223           if (board->buttonPressed()) {
00224             buttonPressed = true;
00225             buttonTimer.dispatch(0);
00226           } else {
00227             buttonPressed = false;
00228             buttonTimer.cancel(buttonTimerId);
00229           }
00230           continue;
00231         } else if (updateClock) {
00232           updateClock = false;
00233           time_t seconds = time(0);
00234           sprintf(_currentTime, "%-25s", ctime(&seconds));
00235           swim_put_text_xy(_win, _currentTime, clockXOff, clockYOff);
00236           continue;
00237         }
00238         
00239         if (appToLaunch != NO_APPLICATION) {
00240           if (tExit.read_ms() < 500) {
00241             appToLaunch = NO_APPLICATION;
00242             continue;
00243           }
00244           App* a = NULL;
00245           if (_callback != NULL) {
00246             a = _callback(appToLaunch);
00247           }
00248           if (a != NULL) {
00249             if (a->setup()) {
00250               a->runToCompletion();
00251               a->teardown();
00252             }
00253             delete a;            
00254           }
00255           tExit.reset();
00256           appToLaunch = NO_APPLICATION;
00257         }
00258     }
00259 }
00260 
00261 bool AppLauncherSpecial::teardown()
00262 {
00263     if (_win != NULL) {
00264         free(_win);
00265         _win = NULL;
00266     }
00267     if (_fb != NULL) {
00268         free(_fb);
00269         _fb = NULL;
00270     }
00271     for (int i = 0; i < NumberOfButtons; i++) {
00272         _buttons[i] = NULL;
00273         if (_buttons[i] != NULL) {
00274             delete _buttons[i];
00275             _buttons[i] = NULL;
00276         }
00277     }
00278     if (_bgImg.pointerToFree != NULL) {
00279         free(_bgImg.pointerToFree);
00280         _bgImg.pointerToFree = NULL;
00281     }    
00282     return true;
00283 }
00284 
00285 void AppLauncherSpecial::setAppCreatorFunc(App*(*callback)(uint32_t buttonID))
00286 {
00287     _callback = callback;
00288 }
00289 
00290 bool AppLauncherSpecial::addButton(uint32_t buttonID, const char* caption)
00291 {
00292     int idx = _usedButtons++;
00293     int xspace = ((_disp->width() - ButtonColumns * ButtonWidth) / (ButtonColumns + 1));
00294     int yspace = ((_disp->height() - TitleHeight - ButtonRows * ButtonHeight) / (ButtonRows + 1));
00295     
00296     _buttons[idx] = new Button(caption, (COLOR_T*)_fb, 
00297                               xspace + (ButtonWidth + xspace)*(idx%ButtonColumns), 
00298                               TitleHeight + yspace + (ButtonHeight + yspace)*(idx/ButtonColumns), 
00299                               ButtonWidth, ButtonHeight);
00300     _buttons[idx]->setAction(buttonClicked, buttonID);
00301     //_buttons[idx]->draw();
00302     return true;
00303 }
00304 
00305 bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* imgUp, const char* imgDown)
00306 {
00307     return addImageButton(buttonID, NULL, BLACK, imgUp, imgDown);
00308 }
00309 
00310 bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const char* imgUp, const char* imgDown)
00311 {
00312     int idx = _usedButtons++;
00313     int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1));
00314     int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1));
00315     
00316     ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
00317                               xspace + (_iconWidth + xspace)*(idx%ButtonColumns), 
00318                               TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), 
00319                               _iconWidth, _iconHeight, caption, color);
00320     if (img->loadImages(imgUp, imgDown)) {
00321       _buttons[idx] = img;
00322       _buttons[idx]->setAction(buttonClicked, buttonID);
00323       //_buttons[idx]->draw();
00324       return true;
00325     } else {
00326       //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
00327       return false;
00328     }
00329 }
00330 
00331 bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown, unsigned int imgDownSize)
00332 {
00333     return addImageButton(buttonID, NULL, BLACK, imgUp, imgUpSize, imgDown, imgDownSize);
00334 }
00335 
00336 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)
00337 {
00338     int idx = _usedButtons++;
00339     int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1));
00340     int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1));
00341     
00342     ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
00343                               xspace + (_iconWidth + xspace)*(idx%ButtonColumns), 
00344                               TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), 
00345                               _iconWidth, _iconHeight, caption, color);
00346     img->setTransparency(RED);
00347     if (img->loadImages(imgUp, imgUpSize, imgDown, imgDownSize)) {
00348       _buttons[idx] = img;
00349       _buttons[idx]->setAction(buttonClicked, buttonID);
00350       //_buttons[idx]->draw();
00351       return true;
00352     } else {
00353       //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
00354       return false;
00355     }
00356 }
00357 
00358 bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, Resource* resUp, Resource* resDown)
00359 {
00360     int idx = _usedButtons++;
00361     int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1));
00362     int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1));
00363     
00364     ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
00365                               xspace + (_iconWidth + xspace)*(idx%ButtonColumns), 
00366                               TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), 
00367                               _iconWidth, _iconHeight, caption, color);
00368     if (img->loadImages(resUp, resDown)) {
00369       _buttons[idx] = img;
00370       _buttons[idx]->setAction(buttonClicked, buttonID);
00371       //_buttons[idx]->draw();
00372       return true;
00373     } else {
00374       //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
00375       return false;
00376     }
00377 }
00378 
00379 void AppLauncherSpecial::addResource(Resources id, Resource* res)
00380 {
00381     _resBg = res;
00382 }
00383