To OP:
This is something I've been playing with, but tried to abstract the button code out into a standalone library. Feel free to play with the following code:-
GadgetTest.ino
#include <SSD1289.h>
#include <UTouch.h>
#include "Gadgets.h"
SSD1289 disp(38,39,40,41);
UTouch myTouch(6,5,4,3,2);
extern uint8_t SmallFont[];
Gadgets Gadgets;
boolean FirstPass = true;
void setup()
{
Gadgets::scr = & disp;
Gadgets::touch = & myTouch;
Serial.begin(9600);
}
Button but[8];
void loop()
{
int l;
if (FirstPass)
{
FirstPass = false;
disp.InitLCD();
disp.clrScr();
but[0].SetUp(20,20,100,40,"Test 1",STANDARD,SmallFont);
but[1].SetUp(20,80,100,40,"Test 2",STANDARD,SmallFont);
but[2].SetUp(20,140,100,40,"Test 3",STANDARD,SmallFont);
}
else
{
for (l=0; l<=2; l++)
{
if (but[l].Handle() == BUTTON_PRESSED)
{
Serial.print(but[l].label);
Serial.print(" pressed\n");
}
}
}
}
Gadgets.h:
#include <SSD1289.h>
#include <UTouch.h>
#ifndef Gadgets_H
#define Gadgets_H
class Gadgets
{
public:
static SSD1289 *scr;
static UTouch *touch;
Gadgets();
void Iterate();
int TouchX;
int TouchY;
boolean TouchPressed;
boolean LastTouchPressed;
private:
int LastSample;
boolean TouchFirstPass;
};
typedef enum tButtonMode {STANDARD};
typedef enum tAction { INITIAL, // Basic initialisation (parameters) set, needs to be rendered
INITIALISED}; // Initialised and rendered, needs to be managed on a cyclic basis
typedef enum tStatus { NO_ACTION,
BUTTON_PRESSED };
typedef enum tButtStatus { BUTT_NOT_PRESSED,
BUTT_PRESSED };
class Button : Gadgets
{
public:
Button();
Button(int XPosition, int YPosition, int Width, int Height, char *Label, tButtonMode Mode, uint8_t *Font);
void SetUp(int XPosition, int YPosition, int Width, int Height, char *Label, tButtonMode Mode, uint8_t *Font);
tStatus Handle();
char *label;
private:
void Render();
boolean defined;
tAction action;
tButtStatus buttstatus;
int x,y,w,h;
uint8_t * font;
tButtonMode mode;
word col_highlight, col_background, col_shadow;
boolean FirstPressedWithinButton;
};
#endif
and Gadgets.cpp
#include "Gadgets.h"
#include <SSD1289.h>
#include <UTouch.h>
SSD1289 *Gadgets::scr;
UTouch *Gadgets::touch;
//
//
// T O U C H S C R E E N
//
//
Gadgets::Gadgets()
{
LastSample = 0;
TouchFirstPass = true;
}
/*
Iterate()
---------
Provided this is called cyclically, this will ensure that the touch screen
controller is only scheduled every 100mS, or slower (depending on scheduling
rate).
*/
void Gadgets::Iterate()
{
unsigned long time;
if (TouchFirstPass)
{
TouchFirstPass = false;
LastSample = millis();
touch->InitTouch();
touch->setPrecision(PREC_MEDIUM);
}
time = millis();
if ((time - LastSample) >= 100)
{
LastTouchPressed = TouchPressed;
LastSample = time;
if (touch->dataAvailable() == true)
{
touch->read();
TouchX = touch->getX();
TouchY = touch->getY();
TouchPressed = true;
}
else
{
TouchPressed = false;
}
}
}
//
//
//
// B U T T O N
//
//
//
Button::Button()
{
defined = false;
}
Button::Button(int XPosition, int YPosition, int Width, int Height, char *Label, tButtonMode Mode, uint8_t *Font)
{
SetUp(XPosition, YPosition, Width, Height, Label, Mode, Font);
}
void Button::SetUp(int XPosition, int YPosition, int Width, int Height, char *Label, tButtonMode Mode, uint8_t *Font)
{
x = XPosition;
y = YPosition;
w = Width;
h = Height;
label = Label;
mode = Mode;
defined = true;
action = INITIAL;
buttstatus = BUTT_NOT_PRESSED;
col_highlight = 0xFFFF;//scr->RGBToWord(255,255,255);
col_background = 0xCCCC;//scr->RGBToWord(128,128,128);
col_shadow = 0x9999;//scr->RGBToWord(64,64,64);
font = Font;
}
void Button::Render()
{
int text_x, text_y;
if (defined)
{
switch (buttstatus)
{
case BUTT_NOT_PRESSED:
scr->setColor(col_highlight);
scr->drawLine(x,y,x+w-1,y);
scr->drawLine(x,y+1,x,y+h-1);
scr->setColor(col_background);
scr->fillRect(x+1,y+1,x+w-2,y+h-2);
scr->setColor(col_shadow);
scr->drawLine(x+1,y+h-1,x+w-1,y+h-1);
scr->drawLine(x+w-1,y+1,x+w-1,y+h-2);
break;
case BUTT_PRESSED:
scr->setColor(col_shadow);
scr->drawLine(x,y,x+w-1,y);
scr->drawLine(x,y+1,x,y+h-1);
scr->setColor(col_background);
scr->fillRect(x+1,y+1,x+w-2,y+h-2);
scr->setColor(col_highlight);
scr->drawLine(x+1,y+h-1,x+w-1,y+h-1);
scr->drawLine(x+w-1,y+1,x+w-1,y+h-2);
break;
}
scr->setBackColor(col_background);
scr->setColor(col_highlight);
scr->setFont(font);
text_x = x + w/2 - (scr->getFontXsize() * strlen (label) / 2) ;
text_y = y + h/2 - (scr->getFontYsize() /2 );
scr->print(label,text_x,text_y);
}
}
tStatus Button::Handle()
{
tStatus status = NO_ACTION ;
switch (action)
{
case INITIAL:
action = INITIALISED;
Render();
break;
case INITIALISED:
Iterate();
if (TouchPressed)
{
if (!LastTouchPressed)
{
// Action when the touch screen is FIRST pressed
if (TouchX >= x && TouchX <= x+w && TouchY >= y && TouchY <= y+h)
{
// touch screen was first pressed within the bounds of this button
FirstPressedWithinButton = true;
buttstatus = BUTT_PRESSED;
Render();
}
else
{
// touch screen was pressed outside the bounds of this button - ignore all future movements
FirstPressedWithinButton = false;
}
}
else
{
// Action whilst the screen is held
if (FirstPressedWithinButton)
{
// Only process if the screen was originally pressed within the button
if (TouchX >= x && TouchX <= x+w && TouchY >= y && TouchY <= y+h)
{
if (buttstatus != BUTT_PRESSED)
{
buttstatus = BUTT_PRESSED;
Render();
}
}
else
{
if (buttstatus != BUTT_NOT_PRESSED)
{
buttstatus = BUTT_NOT_PRESSED;
Render();
}
}
}
}
}
else
{
if (LastTouchPressed && FirstPressedWithinButton)
{
// Screen has just been released...
if (buttstatus == BUTT_PRESSED)
{
status = BUTTON_PRESSED;
}
buttstatus = BUTT_NOT_PRESSED;
Render();
}
}
break;
}
return status;
}
SSD1289 is simply an optimised version of UTFT - you can substitute that in it's place. The code is very much a work-in-progress and I don't pretend that it's elegant, but it does implement a button class that requires you to press, and release the screen within the button boundaries to be recognised as a valid button selection. Lots of things to improve, but maybe some ideas within