A basic graphics package for the LPC4088 Display Module.

Dependents:   lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI lpc4088_displaymodule_fs_aid ... more

Fork of DMBasicGUI by EmbeddedArtists AB

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Tue Feb 17 10:34:13 2015 +0100
Parent:
10:651861441108
Child:
12:53601973f7eb
Commit message:
- Replaced wait_ms with Thread::wait in SlideShow
- Fixed fade transition in SlideShow
- Added repeat/end buttons to AppSlideShow
- Added very basic transparent image rendering to SWIM
- Fixed errors in lpc_colors.h
- Added support for button captions to the ImageButton
- Added back buffering to the AppColorPicker
- Added basic_image_data.h/c with the ok/cancel/repeat buttons
- Moved the slideshow parameters to the constructor of AppSlideShow

Changed in this revision

Application/AppColorPicker.cpp Show annotated file Show diff for this revision Revisions of this file
Application/AppColorPicker.h Show annotated file Show diff for this revision Revisions of this file
Application/AppLauncher.cpp Show annotated file Show diff for this revision Revisions of this file
Application/AppLauncher.h Show annotated file Show diff for this revision Revisions of this file
Application/ImageButton.cpp Show annotated file Show diff for this revision Revisions of this file
Application/ImageButton.h Show annotated file Show diff for this revision Revisions of this file
Application/basic_image_data.c Show annotated file Show diff for this revision Revisions of this file
Application/basic_image_data.h Show annotated file Show diff for this revision Revisions of this file
SlideShow/AppSlideShow.cpp Show annotated file Show diff for this revision Revisions of this file
SlideShow/AppSlideShow.h Show annotated file Show diff for this revision Revisions of this file
SlideShow/SlideShow.cpp Show annotated file Show diff for this revision Revisions of this file
lpc_swim/lpc_colors.h Show annotated file Show diff for this revision Revisions of this file
lpc_swim/lpc_swim_image.c Show annotated file Show diff for this revision Revisions of this file
lpc_swim/lpc_swim_image.h Show annotated file Show diff for this revision Revisions of this file
--- a/Application/AppColorPicker.cpp	Mon Jan 26 10:06:58 2015 +0100
+++ b/Application/AppColorPicker.cpp	Tue Feb 17 10:34:13 2015 +0100
@@ -19,6 +19,7 @@
 #include "EthernetInterface.h"
 #include "AppColorPicker.h"
 #include "lpc_swim_font.h"
+#include "basic_image_data.h"
 
 /******************************************************************************
  * Defines and typedefs
@@ -49,7 +50,7 @@
     // Prepare fullscreen
     swim_window_open(_win, 
                    _disp->width(), _disp->height(),         // full size
-                   (COLOR_T*)_fb,
+                   _fb,
                    0,0,_disp->width()-1, _disp->height()-1, // window position and size
                    1,                                       // border
                    WHITE, WHITE, BLACK);                    // colors: pen, backgr, forgr
@@ -57,7 +58,7 @@
 
     swim_window_open(_colorwin, 
                      _disp->width(), _disp->height(),         // full size
-                     (COLOR_T*)_fb,
+                     _fb,
                      50,(_disp->height()-BOX_SIDE)/2,50+BOX_SIDE-1, BOX_SIDE+(_disp->height()-BOX_SIDE)/2,                 // window position and size
                      0,                                       // border
                      WHITE, WHITE, BLACK);                    // colors: pen, backgr, forgr
@@ -82,15 +83,20 @@
         }
     }
     
-    _btn = new Button("Done", _win->fb, _win->xpmax - BTN_OFF - BTN_WIDTH, _win->ypmax - BTN_OFF - BTN_HEIGHT, BTN_WIDTH, BTN_HEIGHT);
+    _btn = new ImageButton(_win->fb, _win->xpmax - BTN_OFF - BTN_WIDTH, _win->ypmax - BTN_OFF - BTN_HEIGHT, BTN_WIDTH, BTN_HEIGHT);
+    _btn->loadImages(img_ok, img_size_ok);
     _btn->draw();
+    
+    // Copy everything onto the back buffer
+    memcpy(_fb2, _fb, _disp->fbSize());
 }
 
 /******************************************************************************
  * Public functions
  *****************************************************************************/
 
-AppColorPicker::AppColorPicker() : _disp(NULL), _win(NULL), _colorwin(NULL), _fb(NULL), _btn(NULL)
+AppColorPicker::AppColorPicker() : _disp(NULL), _win(NULL), _colorwin(NULL), 
+  _fb(NULL), _fb2(NULL), _btn(NULL)
 {
 }
 
@@ -104,24 +110,26 @@
     _disp = DMBoard::instance().display();
     _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
     _colorwin = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
-    _fb = _disp->allocateFramebuffer();
+    _fb = (COLOR_T*)_disp->allocateFramebuffer();
+    _fb2 = (COLOR_T*)_disp->allocateFramebuffer();
 
-    return (_win != NULL && _colorwin != NULL && _fb != NULL);
+    return (_win != NULL && _colorwin != NULL && _fb != NULL && _fb2 != NULL);
 }
 
 void AppColorPicker::runToCompletion()
 {
-    // Alternative 1: use the calling thread's context to run in
     bool done = false;
     draw();
     _btn->setAction(buttonClicked, (uint32_t)&done);
-    void* oldFB = _disp->swapFramebuffer(_fb);
+    void* oldFB = _disp->swapFramebuffer(_fb2);
     
     // Wait for touches
     TouchPanel* touch = DMBoard::instance().touchPanel();
     touch_coordinate_t coord;
     char buf[10];
     swim_set_pen_color(_win, BLACK);
+    bool showingFB2 = true;
+    COLOR_T lastColor = WHITE;
     while(!done) {
       // wait for a new touch signal (signal is sent from AppLauncher,
       // which listens for touch events)
@@ -133,13 +141,27 @@
             int x = coord.x - _colorwin->xpmin;
             int y = coord.y - _colorwin->ypmin;
             COLOR_T c = ((x/(BOX_SIDE/32))<<11) | ((y/(BOX_SIDE/64))<<5) | ((0x1f-(x/(BOX_SIDE/32)))<<0);
+          if (c != lastColor) {
             swim_set_fill_color(_win, c);
             swim_put_box(_win, 350, 70, 430, 150);
             sprintf(buf, "0x%04x  ", c);
             swim_put_text_xy(_win, buf, 350, 160);
+                
+            // Swap what is shown and what is drawn on
+            if (showingFB2) {
+              _disp->setFramebuffer(_fb);
+              _win->fb = _fb2;
+            } else {
+              _disp->setFramebuffer(_fb2);
+              _win->fb = _fb;
+            }
+            Thread::wait(20);
+            showingFB2 = !showingFB2;
+            lastColor = c;
+          }
         }
         if (_btn->handle(coord.x, coord.y, coord.z > 0)) {
-            _btn->draw();
+            _btn->draw(showingFB2 ? _fb2 : _fb);
         }
       }
     }
@@ -164,6 +186,10 @@
         free(_fb);
         _fb = NULL;
     }
+    if (_fb2 != NULL) {
+        free(_fb2);
+        _fb2 = NULL;
+    }
     if (_btn != NULL) {
         delete _btn;
         _btn = NULL;
--- a/Application/AppColorPicker.h	Mon Jan 26 10:06:58 2015 +0100
+++ b/Application/AppColorPicker.h	Tue Feb 17 10:34:13 2015 +0100
@@ -20,7 +20,7 @@
 #include "App.h"
 #include "DMBoard.h"
 #include "lpc_swim.h"
-#include "Button.h"
+#include "ImageButton.h"
 
 /**
  * An App example. Lets the user pick a color from a colored area.
@@ -44,8 +44,9 @@
     Display* _disp;
     SWIM_WINDOW_T* _win;
     SWIM_WINDOW_T* _colorwin;
-    void* _fb;
-    Button* _btn;
+    COLOR_T* _fb;
+    COLOR_T* _fb2;
+    ImageButton* _btn;
 
     void draw();
 };
--- a/Application/AppLauncher.cpp	Mon Jan 26 10:06:58 2015 +0100
+++ b/Application/AppLauncher.cpp	Tue Feb 17 10:34:13 2015 +0100
@@ -84,7 +84,7 @@
     osSignalSet(appThread, APP_SIGID_TOUCH);
 }
 
-void onTimeoutEvent(void const* arg)
+static void onTimeoutEvent(void const* arg)
 {
     *((bool*)arg) = true;
     osSignalSet(appThread, APP_SIGID_TOUCH);
@@ -212,8 +212,8 @@
     }
     
     // restore old touch listener (get our listener in return)
-    fpOld = touch->setListener(fpOld);
-    delete fpOld;
+    //fpOld = touch->setListener(fpOld);
+    //delete fpOld;
 }
 
 bool AppLauncher::teardown()
@@ -258,14 +258,20 @@
 
 bool AppLauncher::addImageButton(uint32_t buttonID, const char* imgUp, const char* imgDown)
 {
+    return addImageButton(buttonID, NULL, BLACK, imgUp, imgDown);
+}
+
+bool AppLauncher::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const char* imgUp, const char* imgDown)
+{
     int idx = _usedButtons++;
     int xspace = ((_disp->width() - ButtonColumns * 64) / (ButtonColumns + 1));
     int yspace = ((_disp->height() - TitleHeight - ButtonRows * 64) / (ButtonRows + 1));
+    int yoff = (caption == NULL) ? 0 : -15; // compensate for caption taking up space
     
     ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
                               xspace + (64 + xspace)*(idx%ButtonColumns), 
-                              TitleHeight + yspace + (64 + yspace)*(idx/ButtonColumns), 
-                              64, 64);
+                              TitleHeight + yspace + (64 + yspace)*(idx/ButtonColumns) + yoff, 
+                              64, 64, caption, color);
     if (img->loadImages(imgUp, imgDown)) {
       _buttons[idx] = img;
       _buttons[idx]->setAction(buttonClicked, buttonID);
@@ -279,14 +285,20 @@
 
 bool AppLauncher::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 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)
+{
     int idx = _usedButtons++;
     int xspace = ((_disp->width() - ButtonColumns * 64) / (ButtonColumns + 1));
     int yspace = ((_disp->height() - TitleHeight - ButtonRows * 64) / (ButtonRows + 1));
+    int yoff = (caption == NULL) ? 0 : -15; // compensate for caption taking up space
     
     ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
                               xspace + (64 + xspace)*(idx%ButtonColumns), 
-                              TitleHeight + yspace + (64 + yspace)*(idx/ButtonColumns), 
-                              64, 64);
+                              TitleHeight + yspace + (64 + yspace)*(idx/ButtonColumns) + yoff, 
+                              64, 64, caption, color);
     if (img->loadImages(imgUp, imgUpSize, imgDown, imgDownSize)) {
       _buttons[idx] = img;
       _buttons[idx]->setAction(buttonClicked, buttonID);
--- a/Application/AppLauncher.h	Mon Jan 26 10:06:58 2015 +0100
+++ b/Application/AppLauncher.h	Tue Feb 17 10:34:13 2015 +0100
@@ -49,6 +49,8 @@
     bool addButton(uint32_t buttonID, const char* caption);
     bool addImageButton(uint32_t buttonID, const char* imgUp, const char* imgDown = 0);
     bool addImageButton(uint32_t buttonID, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown = 0, unsigned int imgDownSize = 0);
+    bool addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const char* imgUp, const char* imgDown = 0);
+    bool addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown = 0, unsigned int imgDownSize = 0);
 
 private:
     enum Constants {
--- a/Application/ImageButton.cpp	Mon Jan 26 10:06:58 2015 +0100
+++ b/Application/ImageButton.cpp	Tue Feb 17 10:34:13 2015 +0100
@@ -19,14 +19,27 @@
 #include "DMBoard.h"
 
 #include "lpc_swim_image.h"
+#include "lpc_swim_font.h"
+#include "lpc_colors.h"
 
-ImageButton::ImageButton(COLOR_T* fb, uint16_t x, uint16_t y, uint16_t width, uint16_t height) :
-  Clickable(fb, x, y, width, height)
+ImageButton::ImageButton(COLOR_T* fb, uint16_t x, uint16_t y, uint16_t width, uint16_t height,
+                         const char* caption, COLOR_T color) :
+  Clickable(fb, x, y, width, height+(caption==NULL?0:20))
 {
   _imgUp.pointerToFree = NULL;
   _imgUp.pixels = NULL;
   _imgDown.pointerToFree = NULL;
   _imgDown.pixels = NULL;
+  _caption = NULL;
+  _transparent = false;
+    
+  if (caption != NULL) {
+    _caption = (char*)malloc(strlen(caption)+1);
+    if (_caption != NULL) {
+      strcpy(_caption, caption);
+    }
+    _captionColor = color;
+  }
 }
 
 ImageButton::~ImageButton()
@@ -39,6 +52,10 @@
     free(_imgDown.pointerToFree);
     _imgDown.pointerToFree = NULL;
   }
+  if (_caption != NULL) {
+    free(_caption);
+    _caption = NULL;
+  }
 }
 
 bool ImageButton::loadImages(const char* imgUp, const char* imgDown)
@@ -88,19 +105,36 @@
   return true;
 }
 
+void ImageButton::setTransparency(COLOR_T tColor)
+{
+  _transparent = true;
+  _transparentColor = tColor;
+}
 
 void ImageButton::draw(COLOR_T* fb)
 {
   if (fb != NULL) {
     _win.fb = fb;
   }
+  if (_caption != NULL) {
+    _win.pen = _captionColor;
+    swim_put_text_centered_win(&_win, _caption, _imgUp.height+2);
+  }
   if (_pressed) {
     if (_imgDown.pixels != NULL) {
-      swim_put_image(&_win, _imgDown.pixels, _imgDown.width, _imgDown.height);
+      if (_transparent) {
+        swim_put_transparent_image_xy(&_win, _imgDown.pixels, _imgDown.width, _imgDown.height, 0, 0, _transparentColor);
+      } else {
+        swim_put_image(&_win, _imgDown.pixels, _imgDown.width, _imgDown.height);
+      }
     }
   } else {
     if (_imgUp.pixels != NULL) {
-      swim_put_image(&_win, _imgUp.pixels, _imgUp.width, _imgUp.height);
+      if (_transparent) {
+        swim_put_transparent_image_xy(&_win, _imgUp.pixels, _imgUp.width, _imgUp.height, 0, 0, _transparentColor);
+      } else {
+        swim_put_image(&_win, _imgUp.pixels, _imgUp.width, _imgUp.height);
+      }
     }
   }
 }
--- a/Application/ImageButton.h	Mon Jan 26 10:06:58 2015 +0100
+++ b/Application/ImageButton.h	Tue Feb 17 10:34:13 2015 +0100
@@ -36,8 +36,11 @@
      *  @param y       the upper left corner of the button
      *  @param width   the width of the button
      *  @param height  the height of the button
+     *  @param caption optional text to put below the image
+     *  @param color   text color
      */
-  ImageButton(COLOR_T* fb, uint16_t x, uint16_t y, uint16_t width, uint16_t height);
+  ImageButton(COLOR_T* fb, uint16_t x, uint16_t y, uint16_t width, uint16_t height, 
+              const char* caption=NULL, COLOR_T color=BLACK);
   virtual ~ImageButton();
 
     /** Loads the mandatory "normal" state image and the optional "pressed" state image
@@ -63,6 +66,11 @@
   bool loadImages(const unsigned char* imgUp, unsigned int imgUpSize, 
                   const unsigned char* imgDown = 0, unsigned int imgDownSize = 0);
 
+    /** Specifys a color that will be considered transparent (i.e. will not be drawn)
+     *  @param tColor  the transparent color
+     */
+  void setTransparency(COLOR_T tColor);
+
     /** Draws the button (on a new framebuffer if one is specified)
      *  @param fb      the frame buffer
      */
@@ -71,6 +79,10 @@
 private:
   Image::ImageData_t _imgUp;
   Image::ImageData_t _imgDown;
+  char* _caption;
+  COLOR_T _captionColor;
+  bool _transparent;
+  COLOR_T _transparentColor;
 };
 
 #endif /* IMAGEBUTTON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Application/basic_image_data.c	Tue Feb 17 10:34:13 2015 +0100
@@ -0,0 +1,162 @@
+#include "dm_board_config.h"
+
+#if defined(DM_BOARD_USE_BUILTIN_IMAGES)
+
+const unsigned char img_ok[] = {
+	0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52, 
+	0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x28,0x08,0x02,0x00,0x00,0x00,0x03,0x9C,0x2F, 
+	0x3A,0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,0x1C,0xE9,0x00,0x00, 
+	0x00,0x04,0x67,0x41,0x4D,0x41,0x00,0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00, 
+	0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,0xC3,0x01,0xC7, 
+	0x6F,0xA8,0x64,0x00,0x00,0x01,0xE1,0x49,0x44,0x41,0x54,0x58,0x47,0xED,0x92,0xCB, 
+	0x4A,0xC3,0x40,0x14,0x86,0xFB,0x42,0x0A,0xDD,0xB8,0x10,0xDC,0xB9,0xF2,0x11,0xDC, 
+	0x0A,0x22,0x22,0xDD,0x74,0xE1,0x42,0x70,0x2B,0x0A,0xDE,0x10,0x41,0xD1,0x55,0x51, 
+	0x4A,0x57,0x56,0x11,0x45,0xBC,0x80,0xE0,0x05,0x15,0x04,0x41,0x45,0xD1,0x85,0xE0, 
+	0x23,0x68,0x9A,0x26,0x93,0xA6,0x06,0x73,0xE6,0x27,0x9E,0xCC,0x24,0xAD,0x49,0x83, 
+	0x0B,0x7F,0xBE,0x45,0x66,0xE6,0x9F,0xF3,0xC1,0x90,0x5C,0xEE,0x24,0xDF,0x12,0xC7, 
+	0xA1,0x9D,0x84,0xF0,0x75,0x66,0xF0,0x75,0x66,0xE0,0xAB,0xD7,0x18,0xCE,0x00,0xE8, 
+	0xFE,0xC5,0x9D,0x06,0xBA,0x44,0xE2,0x7E,0xA3,0xD0,0x67,0x8C,0xF4,0x18,0x43,0x6C, 
+	0x3F,0x02,0xE8,0x12,0x89,0x07,0xCC,0x22,0xDB,0x89,0x05,0xBA,0x4E,0x3D,0xF5,0xA8, 
+	0x31,0x33,0x6D,0x96,0x72,0x1F,0xDD,0x6C,0x1F,0xBA,0xF4,0xC5,0x67,0xE2,0xAE,0x29, 
+	0xB3,0x58,0xAF,0xE4,0x8C,0xAE,0xE0,0x29,0x74,0x69,0x8A,0xAF,0x9C,0x07,0x12,0x7E, 
+	0xC7,0x76,0x05,0x2B,0x78,0x40,0x97,0x9A,0x98,0x6C,0x32,0x4F,0xCE,0x1B,0x2B,0xF8, 
+	0x40,0x97,0x82,0x78,0xDD,0xDE,0x21,0x9B,0xCC,0xAA,0x55,0x65,0x1D,0x00,0x5D,0x52, 
+	0x71,0x49,0xEC,0x93,0x4D,0x86,0x15,0x18,0xD0,0x25,0x15,0x93,0x4D,0x86,0x9D,0x86, 
+	0x81,0x2E,0x46,0xBC,0x20,0x2A,0x6C,0x27,0x08,0xD9,0x64,0xA6,0xAC,0x12,0x2B,0x84, 
+	0x81,0x4E,0x2B,0x2E,0x5A,0x4B,0x9F,0x6E,0xCD,0x9F,0x78,0xD9,0xB8,0x67,0xA7,0x1E, 
+	0x77,0x8D,0x57,0xFF,0xD4,0x4F,0xCD,0x35,0x59,0x41,0x09,0x74,0x6A,0xF1,0xA6,0x38, 
+	0xA0,0x79,0x32,0xA2,0xE9,0x04,0x0B,0x1E,0x74,0x20,0x33,0x6D,0x6D,0xB0,0x82,0x12, 
+	0xE8,0x14,0xE2,0x35,0x7B,0x9B,0x86,0xB1,0xB8,0xCD,0x31,0x6B,0xCE,0xEF,0x1C,0x3B, 
+	0x37,0xB4,0x29,0x83,0xEB,0xD1,0x40,0xA7,0x10,0x0B,0xD7,0xA1,0x61,0xAA,0x14,0xBE, 
+	0xDD,0x2E,0xAD,0x28,0x2F,0x8D,0x77,0x5C,0x8F,0x06,0x3A,0xF5,0x53,0xD3,0x3C,0x4D, 
+	0x66,0xED,0x32,0x7D,0xC9,0x1C,0x8A,0xEB,0xE0,0xF5,0x08,0xA0,0xD3,0xFE,0x5C,0xBB, 
+	0xE2,0x9C,0xA6,0xB6,0x90,0x2D,0x71,0xCA,0xAE,0xEB,0x80,0x4E,0x2B,0xF6,0xA1,0xC1, 
+	0x71,0xA9,0xA6,0x2E,0xF6,0xB8,0x75,0x9E,0x69,0xBC,0x3E,0x7B,0xE2,0x82,0xDD,0xD2, 
+	0x01,0x5D,0xBC,0xD8,0x87,0x0C,0x9A,0x1C,0x89,0x1B,0xD6,0xD7,0x01,0x5D,0xAB,0x62, 
+	0x0F,0x92,0xA8,0x92,0xE6,0xCF,0xA5,0x84,0x3C,0xA1,0x54,0xAC,0x23,0xD6,0xD4,0x01, 
+	0x5D,0x7B,0xE2,0xC1,0xDA,0x24,0xA9,0x7E,0x66,0xC2,0x5C,0x61,0x4D,0x1D,0xD0,0xB5, 
+	0x27,0xF6,0xB8,0x16,0x8F,0x64,0x0B,0x84,0x75,0x22,0x80,0xAE,0x6D,0xB1,0x07,0xD9, 
+	0x64,0xC6,0xCD,0x65,0x56,0x88,0x00,0xBA,0x44,0xE2,0xF9,0x7A,0x99,0x1D,0xC5,0x02, 
+	0xDD,0x6F,0xC4,0x49,0x80,0xEE,0x5F,0xDC,0x69,0xA0,0xFB,0x03,0xE2,0xAC,0xE1,0xEB, 
+	0xCC,0xE0,0xEB,0x6C,0x38,0xC9,0x7F,0x01,0x57,0x74,0xDC,0x0C,0x35,0x64,0x6D,0xA8, 
+	0x00,0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82
+};
+const unsigned int img_size_ok = sizeof(img_ok);
+
+const unsigned char img_cancel[] = {
+	0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52, 
+	0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x28,0x08,0x02,0x00,0x00,0x00,0x03,0x9C,0x2F, 
+	0x3A,0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,0x1C,0xE9,0x00,0x00, 
+	0x00,0x04,0x67,0x41,0x4D,0x41,0x00,0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00, 
+	0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,0xC3,0x01,0xC7, 
+	0x6F,0xA8,0x64,0x00,0x00,0x01,0xF8,0x49,0x44,0x41,0x54,0x58,0x47,0xED,0xD8,0x3D, 
+	0x6B,0xC2,0x50,0x18,0x05,0x60,0x13,0x13,0x93,0x76,0xF5,0x1F,0x74,0x11,0x1C,0x74, 
+	0x73,0x2D,0x1D,0xBA,0xB6,0x85,0xB6,0x8A,0x51,0x04,0x1D,0x1C,0x85,0x0E,0x5D,0x0A, 
+	0x45,0xEC,0x60,0x71,0x72,0x2F,0xD4,0xA1,0x9B,0x58,0x8A,0xBA,0x76,0x72,0xED,0x26, 
+	0xFE,0x8B,0x2E,0x05,0x11,0x12,0x3F,0xE2,0xED,0x6D,0x72,0xD2,0x26,0x7E,0xE5,0x0A, 
+	0x36,0x52,0xEA,0x33,0xE8,0x79,0x83,0x78,0xC2,0x8D,0x31,0x51,0xAE,0xE5,0xDB,0x0E, 
+	0x1E,0xCF,0x9E,0xDB,0x5A,0xF1,0xCF,0x52,0x1F,0x9F,0x9E,0x22,0xFD,0xA6,0xD7,0x16, 
+	0x0A,0xFF,0xDF,0x52,0xEF,0x8A,0x3D,0xF3,0x47,0x8A,0xC5,0x48,0x04,0x69,0x11,0xE1, 
+	0xF2,0xD2,0x7F,0x72,0x82,0xC1,0x0D,0x6B,0xB1,0xA4,0x28,0x72,0xBD,0x2E,0xDC,0xDD, 
+	0x49,0x37,0x37,0xD8,0x64,0x23,0x5E,0x5D,0xED,0x35,0x9B,0x62,0x2A,0x15,0xC8,0xE5, 
+	0xB0,0xC9,0x0D,0x53,0xB1,0x5C,0xA9,0xF0,0xF1,0x38,0x27,0x49,0x34,0xF3,0xB1,0x58, 
+	0x20,0x9D,0x36,0xB7,0x9B,0x68,0xA5,0x70,0x78,0x68,0x66,0x32,0x18,0x98,0xC1,0x95, 
+	0x7B,0xB1,0x9C,0x4A,0x71,0xA1,0x10,0x06,0x83,0xFF,0xE2,0x42,0x38,0x38,0xA0,0x81, 
+	0x1F,0x8D,0xE4,0x97,0x17,0x73,0xA3,0x49,0x73,0xEE,0xD3,0x0A,0xEE,0xC5,0x64,0x38, 
+	0x44,0xB2,0x11,0xEE,0xEF,0xBF,0x1E,0xAF,0xAF,0x39,0xFE,0xE7,0x1D,0xC6,0xED,0x36, 
+	0x12,0x03,0xF7,0xE2,0xE1,0xF3,0x33,0xE9,0x76,0x31,0x58,0xE8,0xB2,0xCB,0x8F,0x8F, 
+	0xFE,0xA3,0x23,0xCC,0xC6,0xFE,0x4D,0x6A,0x35,0x0C,0x0C,0x98,0x8E,0xB1,0x56,0x2C, 
+	0x92,0xF7,0x77,0x0C,0x16,0x2E,0x18,0x44,0x32,0x68,0x89,0x04,0x12,0x1B,0xA6,0x62, 
+	0x4A,0xCB,0xE7,0xC9,0xC7,0x07,0x86,0x39,0x7A,0xA7,0x83,0xC4,0x8C,0xB5,0x98,0xD2, 
+	0xB2,0x59,0xD2,0xEF,0x63,0x70,0x1A,0x55,0xAB,0x48,0xCC,0xD6,0x28,0xA6,0xB4,0x4C, 
+	0x06,0xC9,0x49,0x88,0xC7,0x91,0x98,0xAD,0x2A,0xE6,0x44,0x11,0xC9,0x66,0x7C,0x7B, 
+	0x8B,0x64,0x23,0x2A,0x0A,0x21,0x04,0x03,0x9B,0x55,0xC5,0xF4,0x83,0x6A,0x3F,0x5B, 
+	0x4C,0x93,0x5E,0x0F,0xC9,0x69,0xDF,0xBA,0xB5,0x60,0xB4,0x72,0xA9,0x79,0x9E,0x4C, 
+	0xA7,0xC8,0x16,0xA9,0x54,0x42,0x9A,0x13,0x58,0xF4,0x6D,0xBA,0xCC,0x7A,0xC7,0x98, 
+	0xE2,0xA3,0x51,0xA4,0x39,0xFE,0x58,0x8C,0x0B,0x87,0x31,0xB8,0x59,0xAF,0x98,0x7E, 
+	0x2D,0x23,0x19,0x88,0xAE,0x23,0x59,0xE4,0x72,0x19,0xC9,0xCD,0x1A,0xC5,0x33,0xAD, 
+	0x6A,0x32,0xA9,0x9D,0x9F,0x63,0xB0,0x91,0x9D,0x2F,0x5B,0x86,0xB5,0x58,0x6E,0x34, 
+	0x90,0x0C,0xEA,0xD9,0x99,0x4F,0x55,0x11,0x9C,0x38,0xBA,0xE6,0x0C,0x67,0x17,0x6B, 
+	0xF1,0xF7,0xA9,0x35,0xE9,0x74,0x66,0xCA,0xF4,0xB7,0x37,0x24,0x4B,0x40,0x51,0x90, 
+	0x96,0xDB,0xCC,0x0D,0xFD,0xCC,0x51,0x18,0x3D,0x3D,0xE9,0xCE,0xCB,0xE5,0xB7,0x0D, 
+	0xDF,0xD0,0xAB,0x85,0x02,0x12,0xBD,0x9A,0x3D,0x3C,0x2C,0x6B,0xB5,0xDB,0xFD,0x84, 
+	0xF1,0xCC,0xAE,0xD8,0x33,0x5B,0x2B,0xDE,0xFD,0xF9,0xE2,0x11,0x9F,0xEF,0x13,0x73, 
+	0x58,0x88,0xAC,0x57,0x96,0x5C,0x12,0x00,0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE, 
+	0x42,0x60,0x82
+};
+const unsigned int img_size_cancel = sizeof(img_cancel);
+
+const unsigned char img_repeat[] = {
+	0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52, 
+	0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x28,0x08,0x02,0x00,0x00,0x00,0x03,0x9C,0x2F, 
+	0x3A,0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,0x1C,0xE9,0x00,0x00, 
+	0x00,0x04,0x67,0x41,0x4D,0x41,0x00,0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00, 
+	0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,0xC3,0x01,0xC7, 
+	0x6F,0xA8,0x64,0x00,0x00,0x00,0x18,0x74,0x45,0x58,0x74,0x53,0x6F,0x66,0x74,0x77, 
+	0x61,0x72,0x65,0x00,0x70,0x61,0x69,0x6E,0x74,0x2E,0x6E,0x65,0x74,0x20,0x34,0x2E, 
+	0x30,0x2E,0x35,0x65,0x85,0x32,0x65,0x00,0x00,0x03,0xBC,0x49,0x44,0x41,0x54,0x58, 
+	0x47,0xC5,0x96,0xDB,0x4B,0x14,0x51,0x18,0xC0,0x8D,0xC8,0x6B,0x66,0xDE,0xD2,0x4C, 
+	0xCB,0x92,0x12,0xA9,0x28,0x33,0x0D,0x83,0x1E,0xA2,0x07,0xC9,0x0C,0xB2,0xE8,0x42, 
+	0x06,0x15,0x51,0x10,0x81,0x4A,0x51,0x16,0xDD,0xAC,0x97,0xDE,0x83,0x1E,0x24,0xF7, 
+	0x7E,0x71,0x35,0x6F,0x85,0x9A,0xE6,0x25,0xBB,0x78,0xB7,0xB0,0xB7,0xA8,0x99,0x33, 
+	0x33,0x8E,0xEB,0xAE,0xAB,0xDB,0x93,0x7F,0x40,0x9F,0x8E,0x7E,0xDA,0xD9,0xD9,0x99, 
+	0xDD,0x45,0x37,0xF8,0x31,0xEC,0x7C,0x67,0x66,0x7F,0xE7,0x32,0xE7,0xFB,0x4E,0xC8, 
+	0xCF,0x96,0xFF,0x03,0x7D,0x1F,0x34,0xE8,0xFB,0xA0,0xB1,0xF4,0x6B,0x76,0x36,0x27, 
+	0x08,0xA0,0x2E,0x00,0xF1,0xC1,0xD9,0xD9,0x5C,0x8F,0x20,0x90,0x37,0x0F,0x15,0xA4, 
+	0x41,0x5D,0x00,0x62,0x6F,0x1C,0x5A,0xEC,0x93,0x6C,0xB7,0x16,0x40,0xDD,0x0A,0x8A, 
+	0x25,0x24,0x3D,0x15,0x5C,0x02,0x75,0x2B,0x2E,0x56,0x01,0x75,0x0A,0x62,0xA5,0x8E, 
+	0x03,0x39,0xCD,0x22,0x15,0xF1,0x05,0xD4,0x29,0x88,0x95,0x28,0x6A,0x9F,0x8C,0xD4, 
+	0x32,0x54,0xD0,0x17,0x50,0x27,0x2B,0x56,0x19,0xEB,0xB9,0x2E,0xE7,0x76,0x1B,0xBF, 
+	0x5E,0xC7,0x16,0x77,0x3A,0x2B,0x86,0xDC,0xCF,0xBE,0xFF,0xA1,0x1E,0x50,0x00,0x75, 
+	0x7E,0x8B,0x8B,0xDA,0x1D,0x19,0x36,0x21,0xD6,0x48,0x92,0xCC,0x24,0xB5,0x86,0x4F, 
+	0xB7,0x09,0xDB,0x6D,0xC2,0xFE,0x46,0xB1,0xB0,0x7D,0xB2,0xAC,0xDF,0x45,0x3D,0xEC, 
+	0x09,0xEA,0x64,0xC5,0xF2,0xDC,0x1B,0x9E,0x81,0x81,0x46,0x69,0x49,0x92,0x89,0x4B, 
+	0xAF,0xE1,0x77,0xD8,0x78,0xB8,0xA6,0x59,0xB9,0xCD,0x66,0x6E,0x93,0x89,0xC4,0x1A, 
+	0x08,0xCC,0xC1,0x56,0x2B,0x7F,0xAB,0x6F,0x9A,0x7A,0x71,0x39,0xA8,0xF3,0x14,0x7B, 
+	0x4D,0x02,0x77,0x06,0x67,0x52,0x2C,0x5C,0x68,0x35,0x93,0x68,0x24,0x20,0x48,0xB5, 
+	0xCC,0xE9,0x81,0x2D,0x16,0x3E,0xC1,0xC8,0xC5,0xE8,0x49,0x94,0x8E,0x8D,0x31,0x90, 
+	0x9C,0x26,0xB1,0xB4,0xDF,0xAB,0x1B,0x75,0x9E,0x62,0xA5,0xED,0x5F,0xFC,0xC1,0xB1, 
+	0xB3,0x96,0x4F,0x31,0x73,0x89,0x26,0x98,0x6A,0xEE,0xF8,0x7B,0xFB,0xE5,0xDE,0xA9, 
+	0x92,0x9E,0xA9,0xC2,0x76,0x47,0x6E,0x93,0x08,0xA3,0x8F,0x33,0x92,0x78,0x23,0xD9, 
+	0x55,0x27,0x2C,0x7B,0x2B,0x7F,0xD9,0xEF,0x80,0xA6,0x5A,0xA2,0xBC,0x7F,0x3A,0xB3, 
+	0x96,0x0F,0xD7,0x30,0x20,0xA6,0x9A,0xF2,0xDF,0x8A,0xC9,0x66,0x2E,0x5A,0x47,0xE2, 
+	0x0C,0x24,0xBB,0x51,0x7E,0xB3,0xA1,0xCE,0x6F,0xB1,0x44,0x41,0x9B,0x3D,0x5C,0xC3, 
+	0x52,0x41,0xE0,0x68,0xAB,0x3D,0xD1,0xC4,0xC1,0x7A,0xC7,0x19,0xB8,0xDB,0x03,0x33, 
+	0x54,0x2B,0x80,0xBA,0x00,0xC5,0x40,0xBE,0x5C,0x02,0x79,0x38,0xE2,0x3E,0xD8,0x24, 
+	0x82,0x38,0xB4,0x9A,0x3D,0xD3,0xE9,0x5C,0x8C,0x2F,0x2D,0x1F,0xEA,0x02,0x17,0x7B, 
+	0x03,0x36,0x55,0x8C,0x81,0x8D,0xD0,0xB2,0xB9,0xCD,0x62,0xE5,0x37,0x37,0xD5,0x8A, 
+	0xBA,0x95,0x17,0x03,0xA9,0x56,0x7E,0xA3,0x81,0x64,0xD5,0x09,0xD7,0x3E,0x4D,0x51, 
+	0x4D,0xA8,0x5B,0x15,0x71,0x46,0xAD,0x00,0xDF,0x76,0x86,0x8D,0x3F,0xDB,0xE5,0xA0, 
+	0x9A,0x50,0xB7,0x4A,0x62,0x7E,0x4E,0x5C,0x2B,0x9C,0xEB,0xC6,0x65,0x5E,0x00,0x75, 
+	0xAB,0x22,0x86,0xF4,0x12,0xAD,0x27,0x7B,0x1B,0xC6,0xCB,0x07,0x26,0xE7,0x23,0x50, 
+	0xA4,0x17,0x9A,0x50,0xA7,0x22,0x2E,0x6C,0xB5,0xE7,0x37,0x89,0x25,0x1E,0x1D,0x57, 
+	0xE0,0xD1,0x88,0x3B,0xC1,0xC4,0xC1,0x66,0x3B,0xD6,0x6A,0xA7,0x9A,0x00,0xD4,0x29, 
+	0x89,0x5F,0xFE,0xE8,0x8A,0xAE,0xFA,0x1D,0xF2,0xEA,0x57,0xA6,0x8D,0xA7,0x9A,0x14, 
+	0x38,0xD9,0x31,0x19,0xA1,0x63,0xD7,0xBE,0x66,0xAF,0xF6,0xCA,0xD4,0x0C,0xD4,0x29, 
+	0x89,0x81,0x38,0x3D,0x1B,0x56,0xCD,0xA4,0x59,0xF8,0x82,0x36,0x69,0xD2,0x54,0xB8, 
+	0xD2,0xEB,0xDC,0x62,0xE1,0xA0,0x5A,0xC4,0x1B,0xB9,0x07,0xC3,0xD2,0x5E,0xFA,0x27, 
+	0x07,0xA3,0x4E,0x45,0x7C,0xA0,0x91,0x40,0x26,0x82,0x1A,0x00,0xEE,0xC7,0x23,0xF4, 
+	0xA6,0xF4,0x64,0x5F,0xC3,0x78,0x98,0x86,0x89,0xD5,0x93,0x13,0x1D,0xF2,0x1D,0x45, 
+	0x9D,0x8A,0xF8,0xEE,0xE0,0x58,0xD6,0x1B,0x01,0x46,0x00,0x64,0x37,0x8C,0xDF,0x1F, 
+	0x96,0xC9,0x82,0x12,0x15,0x43,0xD3,0xC9,0xE6,0xB9,0xCA,0x18,0xA9,0x65,0xB7,0x59, 
+	0xBC,0x2E,0x0D,0xEA,0x54,0xC4,0xC0,0xA9,0x8E,0x89,0x30,0x0D,0x1B,0xA3,0x67,0xA1, 
+	0x00,0xC0,0x80,0x2E,0x7D,0x74,0xBE,0x18,0xFB,0xE7,0xC8,0xF1,0x74,0xD4,0x0D,0x55, 
+	0x6B,0xF7,0x1B,0x61,0x83,0x9E,0x0D,0xD7,0xB2,0x7B,0xEA,0x85,0xB2,0x3E,0x5C,0x5D, 
+	0xFA,0x4C,0x81,0x3A,0x75,0x31,0x70,0xB4,0xC5,0x9E,0x68,0x84,0xB2,0xC3,0x42,0x12, 
+	0xDE,0x66,0xE5,0x8F,0xBC,0x9B,0x38,0xDF,0xED,0x28,0xED,0x73,0x5D,0xFF,0xEC,0x3A, 
+	0xFD,0x61,0xAE,0x20,0xC2,0x59,0x00,0x06,0x1A,0xA1,0x61,0xF2,0x9A,0xC5,0xBB,0x43, 
+	0x5E,0x67,0x05,0x40,0x9D,0x4F,0x62,0x60,0x5F,0xBD,0x98,0x3C,0x5F,0x76,0x20,0x33, 
+	0x6C,0xD0,0x13,0x48,0xC5,0xEB,0xAA,0x19,0x00,0xB6,0x0D,0x4C,0x2F,0x8C,0x15,0xD6, 
+	0x75,0xAB,0x99,0x7B,0xEE,0x91,0x9C,0x29,0x50,0xE7,0xAB,0x18,0x80,0x32,0x07,0x03, 
+	0x4A,0xB1,0x72,0x51,0x3A,0xB2,0xF6,0x35,0xB3,0xA6,0x8A,0x81,0x2B,0x58,0xE1,0x33, 
+	0x3E,0xFC,0x76,0xA2,0x54,0xF1,0xC4,0x83,0xA0,0xCE,0x0F,0xB1,0xC4,0x93,0x51,0xF7, 
+	0x8D,0x2F,0xAE,0x0B,0xDD,0xCE,0xB3,0x9D,0x8E,0x8B,0x3D,0xCE,0x9B,0x5F,0x5D,0x95, 
+	0xA3,0xEA,0x5F,0x3B,0x82,0x3A,0xBF,0xC5,0x6A,0xA8,0x1C,0x8D,0x51,0xE7,0x8B,0x58, 
+	0xE5,0xBF,0xFC,0x02,0x75,0xBE,0x88,0x01,0x70,0x43,0x02,0x92,0xED,0x01,0x04,0x25, 
+	0xA8,0xB8,0x3C,0xA8,0xF3,0x51,0xBC,0x62,0xA0,0x6E,0x49,0x1C,0x64,0xE8,0xFB,0xA0, 
+	0x41,0xDF,0x07,0x89,0x96,0x90,0xBF,0x89,0x72,0xE6,0x27,0x5C,0x0A,0x6C,0x17,0x00, 
+	0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82
+};
+const unsigned int img_size_repeat = sizeof(img_repeat);
+
+#endif /* if defined(DM_BOARD_USE_BUILTIN_IMAGES) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Application/basic_image_data.h	Tue Feb 17 10:34:13 2015 +0100
@@ -0,0 +1,8 @@
+extern const unsigned char img_ok[];
+extern const unsigned int img_size_ok;
+
+extern const unsigned char img_cancel[];
+extern const unsigned int img_size_cancel;
+
+extern const unsigned char img_repeat[];
+extern const unsigned int img_size_repeat;
--- a/SlideShow/AppSlideShow.cpp	Mon Jan 26 10:06:58 2015 +0100
+++ b/SlideShow/AppSlideShow.cpp	Tue Feb 17 10:34:13 2015 +0100
@@ -17,6 +17,7 @@
 
 #include "mbed.h"
 #include "AppSlideShow.h"
+#include "basic_image_data.h"
 
 /******************************************************************************
  * Defines and typedefs
@@ -24,6 +25,10 @@
 
 #define TICKER_RESOLUTION_IN_MS  10
 
+#define BTN_WIDTH  40
+#define BTN_HEIGHT 40
+#define BTN_OFF    20
+
 /******************************************************************************
  * Global variables
  *****************************************************************************/
@@ -44,12 +49,32 @@
   msTicks += TICKER_RESOLUTION_IN_MS;
 }
 
+static void buttonClicked(uint32_t x)
+{
+  bool* done = (bool*)x;
+  *done = true;
+}
+
 /******************************************************************************
  * Public functions
  *****************************************************************************/
 
-AppSlideShow::AppSlideShow() : _fb(NULL), _disp(NULL), _show(NULL), _rend(NULL), _fileMutex()
+AppSlideShow::AppSlideShow(const char* scriptFile, const char* pathPrefix, int xoff, int yoff) :
+    _fb(NULL), _disp(NULL), _show(NULL), _rend(NULL), 
+   _fileMutex(), _btnDone(NULL), _btnRepeat(NULL), _script(NULL), _path(NULL)
 {
+    _script = (char*)malloc(strlen(scriptFile)+1);
+    if (_script != NULL) {
+        strcpy(_script, scriptFile);
+    }
+    if (pathPrefix != NULL) {
+        _path = (char*)malloc(strlen(pathPrefix)+1);
+        if (_path != NULL) {
+            strcpy(_path, pathPrefix);
+        }
+    }
+    _xoff = xoff;
+    _yoff = yoff;
 }
 
 AppSlideShow::~AppSlideShow()
@@ -69,10 +94,15 @@
     } else {
         memset(_fb, 0xff, _disp->fbSize());
         _rend = new Renderer();
-        _show = new SlideShow(_rend, "/mci/elec14", NULL, 150, 95, 1, &_fileMutex);
-        err = _show->prepare("/mci/elec14/ea_logo.txt");
+        _show = new SlideShow(_rend, _path, NULL, _xoff, _yoff, 1, &_fileMutex);
+        err = _show->prepare(_script);
     }
 
+    _btnRepeat = new ImageButton((COLOR_T*)_fb, _disp->width() - 2*BTN_OFF - 2*BTN_WIDTH, _disp->height() - BTN_OFF - BTN_HEIGHT, BTN_WIDTH, BTN_HEIGHT);
+    _btnRepeat->loadImages(img_repeat, img_size_repeat);
+    _btnDone = new ImageButton((COLOR_T*)_fb, _disp->width() - BTN_OFF - BTN_WIDTH, _disp->height() - BTN_OFF - BTN_HEIGHT, BTN_WIDTH, BTN_HEIGHT);
+    _btnDone->loadImages(img_ok, img_size_ok);
+    
     return (err == SlideShow::Ok);
 }
 
@@ -81,6 +111,12 @@
     // Save existing frame buffer
     void* oldFB = _disp->swapFramebuffer(_fb);
     
+    bool done = false;
+    bool repeat = false;
+    _btnDone->setAction(buttonClicked, (uint32_t)&done);
+    _btnRepeat->setAction(buttonClicked, (uint32_t)&repeat);
+    
+    
     // Alternative 1: use the calling thread's context to run in
     Thread tr(tRender, _rend, osPriorityHigh);
     _rend->setRenderThread(&tr);
@@ -89,8 +125,32 @@
     RtosTimer rtosTimer(ticker, osTimerPeriodic);
     rtosTimer.start(TICKER_RESOLUTION_IN_MS);    
 
+    // Wait for touches
+    TouchPanel* touch = DMBoard::instance().touchPanel();
+    touch_coordinate_t coord;
+
+    do {
     // Wait for slideshow to complete
     _show->run();
+      
+      // Temporary ugly way to get current framebuffer
+      _btnDone->draw((COLOR_T*)LPC_LCD->UPBASE);
+      _btnRepeat->draw((COLOR_T*)LPC_LCD->UPBASE);
+       
+      done = repeat = false;
+      while (!done && !repeat) {
+        Thread::signal_wait(0x1);
+        if (touch->read(coord) == TouchPanel::TouchError_Ok) {
+          if (_btnDone->handle(coord.x, coord.y, coord.z > 0)) {
+            _btnDone->draw();
+          }
+          if (_btnRepeat->handle(coord.x, coord.y, coord.z > 0)) {
+            _btnRepeat->draw();
+          }
+        }
+      }
+        
+    } while(!done);
     
     tr.terminate();
     
@@ -112,6 +172,14 @@
         free(_fb);
         _fb = NULL;
     }
+    if (_script != NULL) {
+        free(_script);
+        _script = NULL;
+    }
+    if (_path != NULL) {
+        free(_path);
+        _path = NULL;
+    }
     return true;
 }
 
--- a/SlideShow/AppSlideShow.h	Mon Jan 26 10:06:58 2015 +0100
+++ b/SlideShow/AppSlideShow.h	Tue Feb 17 10:34:13 2015 +0100
@@ -21,6 +21,7 @@
 #include "DMBoard.h"
 #include "SlideShow.h"
 #include "rtos.h"
+#include "ImageButton.h"
 
 /**
  * An App example. Slideshow.
@@ -30,7 +31,7 @@
 class AppSlideShow : public App {
 public:
 
-	AppSlideShow();
+	AppSlideShow(const char* scriptFile, const char* pathPrefix=NULL, int xoff=0, int yoff=0);
 	virtual ~AppSlideShow();
 
     virtual bool setup();
@@ -43,6 +44,12 @@
     SlideShow* _show;
     Renderer* _rend;
     Mutex _fileMutex;
+    ImageButton* _btnDone;
+    ImageButton* _btnRepeat;
+    char* _script;
+    char* _path;
+    int _xoff;
+    int _yoff;
 };
 
 #endif
--- a/SlideShow/SlideShow.cpp	Mon Jan 26 10:06:58 2015 +0100
+++ b/SlideShow/SlideShow.cpp	Tue Feb 17 10:34:13 2015 +0100
@@ -189,7 +189,7 @@
           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
 
           // Sleep and do over again
-          wait_ms(LeftRight_DelayMs);
+          Thread::wait(LeftRight_DelayMs);
         }
 
         // Show final image
@@ -197,24 +197,26 @@
       }
       break;
 
-      case DownUp:  // TODO: Note that this transition is only implemented for fullscreen mode
+      case DownUp:
       {
+        int imgNumPixels = NewImage->width * NewImage->height;
+
         // Create a buffer with the two images after each other, NewImage below
         if (CurrentImage == NULL) {
-          memset(ss->ImageBackBuffer, 0, ss->screenBytes);
+          memset(ss->ImageBackBuffer, 0, imgNumPixels*2);
         } else {
-          memcpy(ss->ImageBackBuffer, CurrentImage->pixels, ss->screenBytes);
+          memcpy(ss->ImageBackBuffer, CurrentImage->pixels, imgNumPixels*2);
         }
-        memcpy(ss->ImageBackBuffer+ss->screenPixels, NewImage->pixels, ss->screenBytes);
+        memcpy(ss->ImageBackBuffer + imgNumPixels, NewImage->pixels, imgNumPixels*2);
 
         // We will be using a back buffer
-        for (int i = DownUp_LineSkip/2; i < (ss->screenHeight-1); i+=DownUp_LineSkip)
+        for (int i = DownUp_LineSkip/2; i < (NewImage->height - 1); i+=DownUp_LineSkip)
         {
           // Show image by advancing what is shown one line at a time
-          ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer + i*ss->screenWidth);
+          ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer + i * NewImage->width);
 
           // Sleep and do over again
-          wait_ms(DownUp_DelayMs);
+          Thread::wait(DownUp_DelayMs);
         }
 
         // show final image
@@ -222,24 +224,26 @@
       }
       break;
 
-      case TopDown:  // TODO: Note that this transition is only implemented for fullscreen mode
+      case TopDown:
       {
+        int imgNumPixels = NewImage->width * NewImage->height;
+
         // Create a buffer with the two images after each other, NewImage above
         if (CurrentImage == NULL) {
-          memset(ss->ImageBackBuffer+ss->screenPixels, 0, ss->screenBytes);
+          memset(ss->ImageBackBuffer + imgNumPixels, 0, imgNumPixels*2);
         } else {
-          memcpy(ss->ImageBackBuffer+ss->screenPixels, CurrentImage->pixels, ss->screenBytes);
+          memcpy(ss->ImageBackBuffer + imgNumPixels, CurrentImage->pixels, imgNumPixels*2);
         }
-        memcpy(ss->ImageBackBuffer, NewImage->pixels, ss->screenBytes);
+        memcpy(ss->ImageBackBuffer, NewImage->pixels, imgNumPixels*2);
 
         // We will be using a back buffer
-        for (int i = ss->screenHeight - TopDown_LineSkip/2; i > 0; i-=TopDown_LineSkip)
+        for (int i = NewImage->height - TopDown_LineSkip/2; i > 0; i-=TopDown_LineSkip)
         {
           // Show image by advancing what is shown one line at a time
-          ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer + i*ss->screenWidth);
+          ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer + i*NewImage->width);
 
           // Sleep and do over again
-          wait_ms(TopDown_DelayMs);
+          Thread::wait(TopDown_DelayMs);
         }
 
         // show final image
@@ -280,11 +284,11 @@
           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
 
           // Sleep and do over again
-          wait_ms(Blinds_DelayMs);
+          Thread::wait(Blinds_DelayMs);
         }
         memcpy(ss->ImageBackBuffer+i-blockNumPixels, bkgBlock, blockNumBytes);
         ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
-        wait_ms(Blinds_DelayMs);
+        Thread::wait(Blinds_DelayMs);
 
         for (i = 0; i < ss->screenPixels; i += blockNumPixels)
         {
@@ -300,7 +304,7 @@
           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
 
           // Sleep and do over again
-          wait_ms(Blinds_DelayMs);
+          Thread::wait(Blinds_DelayMs);
         }
 
         // show final image
@@ -362,7 +366,7 @@
           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
 
           // Sleep and do over again
-          wait_ms(Fade_DelayMs);
+          Thread::wait(Fade_DelayMs);
         }
 
         // show final image
@@ -758,7 +762,7 @@
 {
     int timeToWait = (lastTime + millis) - msTicks;
     if (timeToWait > 0) {
-        wait_ms(timeToWait);
+        Thread::wait(timeToWait);
     }
 }
 
--- a/lpc_swim/lpc_colors.h	Mon Jan 26 10:06:58 2015 +0100
+++ b/lpc_swim/lpc_colors.h	Tue Feb 17 10:34:13 2015 +0100
@@ -41,18 +41,18 @@
 
 /** @defgroup GUI_SWIM_COLORS SWIM color definitions
  * @ingroup GUI_SWIM
- * The Simple Windows Interface manager (SWIM) supports 8-bit RGB323,
+ * The Simple Windows Interface manager (SWIM) supports 8-bit RGB332,
  * 12-bit RGB 444 (in a 16-bit field), 15-bit RGB555, 16-bit RGB565,
  * and 24-bit RGB888 (in a 32-bit field) color.
  *
  * SWIM is configured for the color type at build-time based on the
  * the COLORS_DEF definitions. Select one of the following values to
  * configure SWIM.
- *  8-bit RGB323 : COLORS_DEF = 8
- *  12-bit RGB323: COLORS_DEF = 12
- *  15-bit RGB323: COLORS_DEF = 15
- *  16-bit RGB323: COLORS_DEF = 16
- *  24-bit RGB323: COLORS_DEF = 24
+ *  8-bit RGB332 : COLORS_DEF = 8
+ *  12-bit RGB444: COLORS_DEF = 12
+ *  15-bit RGB555: COLORS_DEF = 15
+ *  16-bit RGB565: COLORS_DEF = 16
+ *  24-bit RGB888: COLORS_DEF = 24
  * @{
  */
 
@@ -148,6 +148,13 @@
 /* Blue color, 565 mode */
 #define BLUE          0x001F
 
+/* Magenta color, 565 mode */
+#define MAGENTA       (RED | BLUE)
+/* Cyan color, 565 mode */
+#define CYAN          (GREEN | BLUE)
+/* Yellow color, 565 mode */
+#define YELLOW        (RED | GREEN)
+
 /* Light red color, 565 mode */
 #define LIGHTRED      0x7800
 /* Light green color, 565 mode */
@@ -309,50 +316,50 @@
 #endif
 
 #if COLORS_DEF == 8
-/* Black color, 323 mode */
+/* Black color, 332 mode */
 #define BLACK         0x00
-/* Light gray color, 323 mode */
+/* Light gray color, 332 mode */
 #define LIGHTGRAY     0x6E
-/* Dark gray color, 323 mode */
+/* Dark gray color, 332 mode */
 #define DARKGRAY      0x25
-/* White color, 323 mode */
+/* White color, 332 mode */
 #define WHITE         0xFF
-/* Red color, 323 mode */
+/* Red color, 332 mode */
 #define RED           0xE0
-/* Green color, 323 mode */
+/* Green color, 332 mode */
 #define GREEN         0x1C
-/* Blue color, 323 mode */
+/* Blue color, 332 mode */
 #define BLUE          0x03
-/* Magenta color, 323 mode */
+/* Magenta color, 332 mode */
 #define MAGENTA       (RED | BLUE)
-/* Cyan color, 323 mode */
+/* Cyan color, 332 mode */
 #define CYAN          (GREEN | BLUE)
-/* Yellow color, 323 mode */
+/* Yellow color, 332 mode */
 #define YELLOW        (RED | GREEN)
-/* Light red color, 323 mode */
+/* Light red color, 332 mode */
 #define LIGHTRED      0x60
-/* Light green color, 323 mode */
+/* Light green color, 332 mode */
 #define LIGHTGREEN    0x0C
-/* Light blue color, 323 mode */
+/* Light blue color, 332 mode */
 #define LIGHTBLUE     0x01
-/* Light magenta color, 323 mode */
+/* Light magenta color, 332 mode */
 #define LIGHTMAGENTA  (LIGHTRED | LIGHTBLUE)
-/* Light cyan color, 323 mode */
+/* Light cyan color, 332 mode */
 #define LIGHTCYAN     (LIGHTGREEN | LIGHTBLUE)
-/* Light yellow color, 323 mode */
+/* Light yellow color, 332 mode */
 #define LIGHTYELLOW   (LIGHTRED | LIGHTGREEN)
 
-/* Red color mask, 323 mode */
+/* Red color mask, 332 mode */
 #define REDMASK       0xE0
-/* Red shift value, 323 mode */
+/* Red shift value, 332 mode */
 #define REDSHIFT      5
-/* Green color mask, 323 mode */
+/* Green color mask, 332 mode */
 #define GREENMASK     0x1C
-/* Green shift value, 323 mode */
+/* Green shift value, 332 mode */
 #define GREENSHIFT    2
-/* Blue color mask, 323 mode */
+/* Blue color mask, 332 mode */
 #define BLUEMASK      0x3
-/* Blue shift value, 323 mode */
+/* Blue shift value, 332 mode */
 #define BLUESHIFT     0
 
 /* Number of colors in 332 mode */
@@ -360,9 +367,9 @@
 /* Number of red colors in 332 mode */
 #define RED_COLORS    0x08
 /* Number of green colors in 332 mode */
-#define GREEN_COLORS  0x08
+#define GREEN_COLORS  0x06
 /* Number of blue colors in 332 mode */
-#define BLUE_COLORS   0x08
+#define BLUE_COLORS   0x04
 
 /* Color type is a 8-bit value */
 typedef uint8_t COLOR_T;
--- a/lpc_swim/lpc_swim_image.c	Mon Jan 26 10:06:58 2015 +0100
+++ b/lpc_swim/lpc_swim_image.c	Tue Feb 17 10:34:13 2015 +0100
@@ -116,6 +116,44 @@
 	}
 }
 
+/* Puts a raw image into a window at a specific position, skipping all transparent pixels */
+void swim_put_transparent_image_xy(SWIM_WINDOW_T *win,                       
+					               const COLOR_T *image,
+					               int32_t xsize,
+					               int32_t ysize,
+                                   int32_t x1,
+                                   int32_t y1,
+								   COLOR_T tColor)
+{
+	int32_t x, y;
+
+	/* Unknown values of rtype will do no rotation */
+	y = win->ypvmin + y1;
+
+	xsize = xsize + win->xpvmin + x1;
+	ysize = ysize + win->ypvmin + y1;
+
+	/* Move image to window pixel by pixel */
+	while ((y <= win->ypvmax) && (y < ysize)) {
+		/* Set physical frame buffer address */
+		x = win->xpvmin + x1;
+
+		/* Render a single line */
+		while ((x <= win->xpvmax) && (x < xsize)) {
+			if (*image != tColor) {
+				swim_put_pixel_physical(win, x, y, *image);
+			}
+			image++;
+			x++;
+		}
+
+		/* Adjust to end of line if the image was clipped */
+		image = image + (xsize - x);
+
+		y++;
+	}
+}
+
 /* Puts a raw image into a window inverted */
 void swim_put_invert_image(SWIM_WINDOW_T *win,
 						   const COLOR_T *image,
--- a/lpc_swim/lpc_swim_image.h	Mon Jan 26 10:06:58 2015 +0100
+++ b/lpc_swim/lpc_swim_image.h	Tue Feb 17 10:34:13 2015 +0100
@@ -79,7 +79,7 @@
  * @param	x1	    : Virtual X position of pixel
  * @param	y1	    : Virtual Y position of pixel
  * @return	Nothing
- * @note	Places an image at the spcified position in the window.
+ * @note	Places an image at the specified position in the window.
  * Image is cropped to the window size.
  */
 void swim_put_image_xy(SWIM_WINDOW_T *win,                       
@@ -90,6 +90,27 @@
                        int32_t y1);
 
 /**
+ * @brief	Puts a raw transparent image at the virtual X, Y coordinate in the window
+ * @param	win		: Pointer to window data structure
+ * @param	image	: Pointer to raw image data
+ * @param	xsize	: Horizontal size of image data
+ * @param	ysize	: Vertical size of image data
+ * @param	x1	    : Virtual X position of pixel
+ * @param	y1	    : Virtual Y position of pixel
+ * @param	tColor  : Transparent color
+ * @return	Nothing
+ * @note	Places an image at the specified position in the window.
+ * Image is cropped to the window size. Pixels matching the tColor are not drawn.
+ */
+void swim_put_transparent_image_xy(SWIM_WINDOW_T *win,                       
+								   const COLOR_T *image,
+								   int32_t xsize,
+								   int32_t ysize,
+								   int32_t x1,
+								   int32_t y1,
+								   COLOR_T tColor);
+
+/**
  * @brief	Puts a raw image into a window inverted
  * @param	win		: Pointer to window data structure
  * @param	image	: Pointer to raw image data