mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Simple widget set for LiquidCrystal displays
This commit is contained in:
parent
500c6d6931
commit
4b2cdd3102
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
backup
|
60
Form/Form.pde
Normal file
60
Form/Form.pde
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
This example demonstrates how to use the Form and Field classes from the
|
||||
FreetronicsLCD library to provide a simple UI on the 16x2 LCD display.
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <FreetronicsLCD.h>
|
||||
#include <Form.h>
|
||||
#include <TextField.h>
|
||||
#include <TimeField.h>
|
||||
#include <IntField.h>
|
||||
#include <BoolField.h>
|
||||
|
||||
// Initialize the LCD
|
||||
FreetronicsLCD lcd;
|
||||
|
||||
// Note: if you are using the USBDroid and have reassigned pin D9 on the LCD shield to some
|
||||
// other pin (e.g. A1), then you will need to initialize the shield with something like:
|
||||
// FreetronicsLCD lcd(A1);
|
||||
// See also: http://www.freetronics.com/pages/combining-the-lcd-keypad-shield-and-the-usbdroid
|
||||
|
||||
// Create the main form and its fields.
|
||||
Form mainForm(lcd);
|
||||
TextField welcomeField(mainForm, "Form example", "v1.0");
|
||||
TimeField timeField(mainForm, "Time since reset", 24, TIMEFIELD_READ_ONLY);
|
||||
IntField volumeField(mainForm, "Volume", 0, 100, 5, 85, "%");
|
||||
BoolField ledField(mainForm, "Status LED", "On", "Off", true);
|
||||
TimeField durationField(mainForm, "Timer duration", 24, TIMEFIELD_READ_WRITE);
|
||||
|
||||
#define STATUS_LED 13
|
||||
|
||||
void setup() {
|
||||
// Status LED initially on.
|
||||
pinMode(STATUS_LED, OUTPUT);
|
||||
digitalWrite(STATUS_LED, HIGH);
|
||||
|
||||
// Enable the screen saver, which will automatically blank the screen after 10 seconds.
|
||||
// The screen will wake up again when a button is pressed or lcd.display() is called.
|
||||
lcd.enableScreenSaver();
|
||||
|
||||
// Show the main form for the first time.
|
||||
mainForm.show();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Update the number of seconds since reset:
|
||||
timeField.setValue(millis() / 1000);
|
||||
|
||||
// Dispatch button events to the main form.
|
||||
int button = lcd.getButton();
|
||||
if (mainForm.dispatch(button) == FORM_CHANGED) {
|
||||
if (mainForm.isCurrent(ledField)) {
|
||||
if (ledField.value())
|
||||
digitalWrite(STATUS_LED, HIGH);
|
||||
else
|
||||
digitalWrite(STATUS_LED, LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
83
libraries/FreetronicsLCD/BoolField.cpp
Normal file
83
libraries/FreetronicsLCD/BoolField.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include "BoolField.h"
|
||||
|
||||
BoolField::BoolField(const String &label)
|
||||
: Field(label)
|
||||
, _printLen(0)
|
||||
, _value(false)
|
||||
{
|
||||
}
|
||||
|
||||
BoolField::BoolField(Form &form, const String &label)
|
||||
: Field(form, label)
|
||||
, _printLen(0)
|
||||
, _value(false)
|
||||
{
|
||||
}
|
||||
|
||||
BoolField::BoolField(Form &form, const String &label, const String &trueLabel, const String &falseLabel, bool value)
|
||||
: Field(form, label)
|
||||
, _trueLabel(trueLabel)
|
||||
, _falseLabel(falseLabel)
|
||||
, _printLen(0)
|
||||
, _value(value)
|
||||
{
|
||||
}
|
||||
|
||||
int BoolField::dispatch(int event)
|
||||
{
|
||||
if (event == LCD_BUTTON_UP || event == LCD_BUTTON_DOWN ||
|
||||
event == LCD_BUTTON_SELECT) {
|
||||
setValue(!_value);
|
||||
return FORM_CHANGED;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void BoolField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
printValue();
|
||||
}
|
||||
|
||||
void BoolField::setValue(bool value)
|
||||
{
|
||||
if (value != _value) {
|
||||
_value = value;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
}
|
||||
|
||||
void BoolField::setTrueLabel(const String &trueLabel)
|
||||
{
|
||||
_trueLabel = trueLabel;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
|
||||
void BoolField::setFalseLabel(const String &falseLabel)
|
||||
{
|
||||
_falseLabel = falseLabel;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
|
||||
void BoolField::printValue()
|
||||
{
|
||||
unsigned int len;
|
||||
lcd()->setCursor(0, 1);
|
||||
if (_value) {
|
||||
lcd()->print(_trueLabel);
|
||||
len = _trueLabel.length();
|
||||
while (len++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = _trueLabel.length();
|
||||
} else {
|
||||
lcd()->print(_falseLabel);
|
||||
len = _falseLabel.length();
|
||||
while (len++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = _falseLabel.length();
|
||||
}
|
||||
}
|
34
libraries/FreetronicsLCD/BoolField.h
Normal file
34
libraries/FreetronicsLCD/BoolField.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef BoolField_h
|
||||
#define BoolField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class BoolField : public Field {
|
||||
public:
|
||||
explicit BoolField(const String &label);
|
||||
BoolField(Form &form, const String &label);
|
||||
BoolField(Form &form, const String &label, const String &trueLabel, const String &falseLabel, bool value);
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void enterField(bool reverse);
|
||||
|
||||
bool value() const { return _value; }
|
||||
void setValue(bool value);
|
||||
|
||||
String trueLabel() const { return _trueLabel; }
|
||||
void setTrueLabel(const String &trueLabel);
|
||||
|
||||
String falseLabel() const { return _falseLabel; }
|
||||
void setFalseLabel(const String &falseLabel);
|
||||
|
||||
private:
|
||||
String _trueLabel;
|
||||
String _falseLabel;
|
||||
int _printLen;
|
||||
bool _value;
|
||||
|
||||
void printValue();
|
||||
};
|
||||
|
||||
#endif
|
71
libraries/FreetronicsLCD/Field.cpp
Normal file
71
libraries/FreetronicsLCD/Field.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "Field.h"
|
||||
|
||||
Field::Field(const String &label)
|
||||
: _label(label)
|
||||
, _form(0)
|
||||
, next(0)
|
||||
, prev(0)
|
||||
{
|
||||
}
|
||||
|
||||
Field::Field(Form &form, const String &label)
|
||||
: _label(label)
|
||||
, _form(0)
|
||||
, next(0)
|
||||
, prev(0)
|
||||
{
|
||||
form.addField(this);
|
||||
}
|
||||
|
||||
Field::~Field()
|
||||
{
|
||||
if (_form)
|
||||
_form->removeField(this);
|
||||
}
|
||||
|
||||
int Field::dispatch(int event)
|
||||
{
|
||||
// Nothing to do here.
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Field::enterField(bool reverse)
|
||||
{
|
||||
// Print the label and then position the cursor on the second line.
|
||||
// We assume that the screen has just been cleared.
|
||||
lcd()->print(_label);
|
||||
lcd()->setCursor(0, 1);
|
||||
}
|
||||
|
||||
void Field::exitField()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
void Field::setLabel(const String &label)
|
||||
{
|
||||
if (isCurrent()) {
|
||||
unsigned int prevLen = _label.length();
|
||||
unsigned int newLen = label.length();
|
||||
_label = label;
|
||||
lcd()->setCursor(0, 0);
|
||||
lcd()->print(label);
|
||||
while (newLen++ < prevLen)
|
||||
lcd()->write(' ');
|
||||
updateCursor();
|
||||
} else {
|
||||
_label = label;
|
||||
}
|
||||
}
|
||||
|
||||
bool Field::isCurrent() const
|
||||
{
|
||||
if (!_form->isVisible())
|
||||
return false;
|
||||
return _form->currentField() == this;
|
||||
}
|
||||
|
||||
void Field::updateCursor()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
38
libraries/FreetronicsLCD/Field.h
Normal file
38
libraries/FreetronicsLCD/Field.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef Field_h
|
||||
#define Field_h
|
||||
|
||||
#include "Form.h"
|
||||
|
||||
class Field {
|
||||
public:
|
||||
explicit Field(const String &label);
|
||||
Field(Form &form, const String &label);
|
||||
~Field();
|
||||
|
||||
Form *form() const { return _form; }
|
||||
|
||||
virtual int dispatch(int event);
|
||||
|
||||
virtual void enterField(bool reverse);
|
||||
virtual void exitField();
|
||||
|
||||
String label() const { return _label; }
|
||||
void setLabel(const String &label);
|
||||
|
||||
bool isCurrent() const;
|
||||
|
||||
protected:
|
||||
LiquidCrystal *lcd() const { return _form->_lcd; }
|
||||
|
||||
virtual void updateCursor();
|
||||
|
||||
private:
|
||||
String _label;
|
||||
Form *_form;
|
||||
Field *next;
|
||||
Field *prev;
|
||||
|
||||
friend class Form;
|
||||
};
|
||||
|
||||
#endif
|
149
libraries/FreetronicsLCD/Form.cpp
Normal file
149
libraries/FreetronicsLCD/Form.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
#include "Form.h"
|
||||
#include "Field.h"
|
||||
|
||||
Form::Form(LiquidCrystal &lcd)
|
||||
: _lcd(&lcd)
|
||||
, first(0)
|
||||
, last(0)
|
||||
, current(0)
|
||||
{
|
||||
}
|
||||
|
||||
Form::~Form()
|
||||
{
|
||||
Field *field = first;
|
||||
Field *next;
|
||||
while (field != 0) {
|
||||
next = field->next;
|
||||
field->_form = 0;
|
||||
field->next = 0;
|
||||
field->prev = 0;
|
||||
field = next;
|
||||
}
|
||||
}
|
||||
|
||||
int Form::dispatch(int event)
|
||||
{
|
||||
if (current) {
|
||||
int exitval = current->dispatch(event);
|
||||
if (exitval >= 0)
|
||||
return exitval;
|
||||
}
|
||||
if (event == LCD_BUTTON_LEFT)
|
||||
prevField();
|
||||
else if (event == LCD_BUTTON_RIGHT)
|
||||
nextField();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Form::nextField()
|
||||
{
|
||||
Field *field = current;
|
||||
if (!field)
|
||||
field = first;
|
||||
if (field && field->next)
|
||||
field = field->next;
|
||||
else
|
||||
field = first;
|
||||
setCurrentField(field);
|
||||
}
|
||||
|
||||
void Form::prevField()
|
||||
{
|
||||
Field *field = current;
|
||||
if (!field)
|
||||
field = last;
|
||||
if (field && field->prev)
|
||||
field = field->prev;
|
||||
else
|
||||
field = last;
|
||||
setCurrentField(field);
|
||||
}
|
||||
|
||||
void Form::defaultField()
|
||||
{
|
||||
setCurrentField(first);
|
||||
}
|
||||
|
||||
void Form::addField(Field *field)
|
||||
{
|
||||
if (field->_form)
|
||||
return; // Already added to a form.
|
||||
field->_form = this;
|
||||
field->next = 0;
|
||||
field->prev = last;
|
||||
if (last)
|
||||
last->next = field;
|
||||
else
|
||||
first = field;
|
||||
last = field;
|
||||
}
|
||||
|
||||
void Form::removeField(Field *field)
|
||||
{
|
||||
if (field->_form != this)
|
||||
return; // Not a member of this form.
|
||||
if (current == field) {
|
||||
if (field->next)
|
||||
setCurrentField(field->next);
|
||||
else if (field->prev)
|
||||
setCurrentField(field->prev);
|
||||
else
|
||||
setCurrentField(0);
|
||||
}
|
||||
if (field->next)
|
||||
field->next->prev = field->prev;
|
||||
else
|
||||
last = field->prev;
|
||||
if (field->prev)
|
||||
field->prev->next = field->next;
|
||||
else
|
||||
first = field->next;
|
||||
field->_form = 0;
|
||||
field->next = 0;
|
||||
field->prev = 0;
|
||||
}
|
||||
|
||||
void Form::setCurrentField(Field *field)
|
||||
{
|
||||
if (field && field->_form != this)
|
||||
return; // Wrong form.
|
||||
if (visible) {
|
||||
bool reverse = false;
|
||||
if (current) {
|
||||
current->exitField();
|
||||
if (field->next == current)
|
||||
reverse = true;
|
||||
else if (!field->next && current == first)
|
||||
reverse = true;
|
||||
}
|
||||
current = field;
|
||||
_lcd->clear();
|
||||
if (current)
|
||||
current->enterField(reverse);
|
||||
} else {
|
||||
current = field;
|
||||
}
|
||||
}
|
||||
|
||||
void Form::show()
|
||||
{
|
||||
if (!visible) {
|
||||
if (!current)
|
||||
current = first;
|
||||
visible = true;
|
||||
_lcd->clear();
|
||||
if (current)
|
||||
current->enterField(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Form::hide()
|
||||
{
|
||||
if (visible) {
|
||||
if (current)
|
||||
current->exitField();
|
||||
visible = false;
|
||||
_lcd->clear();
|
||||
}
|
||||
}
|
43
libraries/FreetronicsLCD/Form.h
Normal file
43
libraries/FreetronicsLCD/Form.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef Form_h
|
||||
#define Form_h
|
||||
|
||||
#include "FreetronicsLCD.h"
|
||||
|
||||
class Field;
|
||||
|
||||
#define FORM_CHANGED 1
|
||||
|
||||
class Form {
|
||||
public:
|
||||
explicit Form(LiquidCrystal &lcd);
|
||||
~Form();
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void nextField();
|
||||
void prevField();
|
||||
void defaultField();
|
||||
|
||||
void addField(Field *field);
|
||||
void removeField(Field *field);
|
||||
|
||||
Field *currentField() const { return current; }
|
||||
void setCurrentField(Field *field);
|
||||
|
||||
bool isCurrent(Field &field) const { return current == &field; }
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
bool isVisible() const { return visible; }
|
||||
|
||||
private:
|
||||
LiquidCrystal *_lcd;
|
||||
Field *first;
|
||||
Field *last;
|
||||
Field *current;
|
||||
bool visible;
|
||||
|
||||
friend class Field;
|
||||
};
|
||||
|
||||
#endif
|
104
libraries/FreetronicsLCD/IntField.cpp
Normal file
104
libraries/FreetronicsLCD/IntField.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include "IntField.h"
|
||||
|
||||
IntField::IntField(const String &label)
|
||||
: Field(label)
|
||||
, _minValue(0)
|
||||
, _maxValue(100)
|
||||
, _stepValue(1)
|
||||
, _value(0)
|
||||
, _printLen(0)
|
||||
{
|
||||
}
|
||||
|
||||
IntField::IntField(Form &form, const String &label)
|
||||
: Field(form, label)
|
||||
, _minValue(0)
|
||||
, _maxValue(100)
|
||||
, _stepValue(1)
|
||||
, _value(0)
|
||||
, _printLen(0)
|
||||
{
|
||||
}
|
||||
|
||||
IntField::IntField(Form &form, const String &label, int minValue, int maxValue, int value)
|
||||
: Field(form, label)
|
||||
, _minValue(minValue)
|
||||
, _maxValue(maxValue)
|
||||
, _stepValue(1)
|
||||
, _value(value)
|
||||
, _printLen(0)
|
||||
{
|
||||
}
|
||||
|
||||
IntField::IntField(Form &form, const String &label, int minValue, int maxValue, int value, const String &suffix)
|
||||
: Field(form, label)
|
||||
, _minValue(minValue)
|
||||
, _maxValue(maxValue)
|
||||
, _stepValue(1)
|
||||
, _value(value)
|
||||
, _printLen(0)
|
||||
, _suffix(suffix)
|
||||
{
|
||||
}
|
||||
|
||||
IntField::IntField(Form &form, const String &label, int minValue, int maxValue, int stepValue, int value, const String &suffix)
|
||||
: Field(form, label)
|
||||
, _minValue(minValue)
|
||||
, _maxValue(maxValue)
|
||||
, _stepValue(stepValue)
|
||||
, _value(value)
|
||||
, _printLen(0)
|
||||
, _suffix(suffix)
|
||||
{
|
||||
}
|
||||
|
||||
int IntField::dispatch(int event)
|
||||
{
|
||||
if (event == LCD_BUTTON_UP) {
|
||||
setValue(_value + _stepValue);
|
||||
return FORM_CHANGED;
|
||||
} else if (event == LCD_BUTTON_DOWN) {
|
||||
setValue(_value - _stepValue);
|
||||
return FORM_CHANGED;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void IntField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
printValue();
|
||||
}
|
||||
|
||||
void IntField::setValue(int value)
|
||||
{
|
||||
if (value < _minValue)
|
||||
value = _minValue;
|
||||
else if (value > _maxValue)
|
||||
value = _maxValue;
|
||||
if (value != _value) {
|
||||
_value = value;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
}
|
||||
|
||||
void IntField::setSuffix(const String &suffix)
|
||||
{
|
||||
_suffix = suffix;
|
||||
if (isCurrent())
|
||||
printValue();
|
||||
}
|
||||
|
||||
void IntField::printValue()
|
||||
{
|
||||
String str(_value);
|
||||
if (_suffix.length())
|
||||
str += _suffix;
|
||||
lcd()->setCursor(0, 1);
|
||||
lcd()->print(str);
|
||||
unsigned int len = str.length();
|
||||
while (len++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = str.length();
|
||||
}
|
44
libraries/FreetronicsLCD/IntField.h
Normal file
44
libraries/FreetronicsLCD/IntField.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef IntField_h
|
||||
#define IntField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class IntField : public Field {
|
||||
public:
|
||||
explicit IntField(const String &label);
|
||||
IntField(Form &form, const String &label);
|
||||
IntField(Form &form, const String &label, int minValue, int maxValue, int value);
|
||||
IntField(Form &form, const String &label, int minValue, int maxValue, int value, const String &suffix);
|
||||
IntField(Form &form, const String &label, int minValue, int maxValue, int stepValue, int value, const String &suffix);
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void enterField(bool reverse);
|
||||
|
||||
int minValue() const { return _minValue; }
|
||||
void setMinValue(int value) { _minValue = value; }
|
||||
|
||||
int maxValue() const { return _maxValue; }
|
||||
void setMaxValue(int value) { _maxValue = value; }
|
||||
|
||||
int stepValue() const { return _stepValue; }
|
||||
void setStepValue(int value) { _stepValue = value; }
|
||||
|
||||
int value() const { return _value; }
|
||||
void setValue(int value);
|
||||
|
||||
String suffix() const { return _suffix; }
|
||||
void setSuffix(const String &suffix);
|
||||
|
||||
private:
|
||||
int _minValue;
|
||||
int _maxValue;
|
||||
int _stepValue;
|
||||
int _value;
|
||||
int _printLen;
|
||||
String _suffix;
|
||||
|
||||
void printValue();
|
||||
};
|
||||
|
||||
#endif
|
38
libraries/FreetronicsLCD/TextField.cpp
Normal file
38
libraries/FreetronicsLCD/TextField.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "TextField.h"
|
||||
|
||||
TextField::TextField(const String &label)
|
||||
: Field(label)
|
||||
{
|
||||
}
|
||||
|
||||
TextField::TextField(Form &form, const String &label)
|
||||
: Field(form, label)
|
||||
{
|
||||
}
|
||||
|
||||
TextField::TextField(Form &form, const String &label, const String &value)
|
||||
: Field(form, label)
|
||||
, _value(value)
|
||||
{
|
||||
}
|
||||
|
||||
void TextField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
lcd()->print(_value);
|
||||
}
|
||||
|
||||
void TextField::setValue(const String &value)
|
||||
{
|
||||
if (isCurrent()) {
|
||||
unsigned int prevLen = _value.length();
|
||||
unsigned int newLen = value.length();
|
||||
_value = value;
|
||||
lcd()->setCursor(0, 1);
|
||||
lcd()->print(value);
|
||||
while (newLen++ < prevLen)
|
||||
lcd()->write(' ');
|
||||
} else {
|
||||
_value = value;
|
||||
}
|
||||
}
|
21
libraries/FreetronicsLCD/TextField.h
Normal file
21
libraries/FreetronicsLCD/TextField.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef TextField_h
|
||||
#define TextField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class TextField : public Field {
|
||||
public:
|
||||
explicit TextField(const String &label);
|
||||
TextField(Form &form, const String &label);
|
||||
TextField(Form &form, const String &label, const String &value);
|
||||
|
||||
void enterField(bool reverse);
|
||||
|
||||
String value() const { return _value; }
|
||||
void setValue(const String &value);
|
||||
|
||||
private:
|
||||
String _value;
|
||||
};
|
||||
|
||||
#endif
|
209
libraries/FreetronicsLCD/TimeField.cpp
Normal file
209
libraries/FreetronicsLCD/TimeField.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
#include "TimeField.h"
|
||||
|
||||
#define EDIT_HOUR 0
|
||||
#define EDIT_MINUTE_TENS 1
|
||||
#define EDIT_MINUTE 2
|
||||
#define EDIT_SECOND_TENS 3
|
||||
#define EDIT_SECOND 4
|
||||
|
||||
TimeField::TimeField(const String &label)
|
||||
: Field(label)
|
||||
, _value(0)
|
||||
, _maxHours(24)
|
||||
, _printLen(0)
|
||||
, _readOnly(false)
|
||||
, editField(EDIT_HOUR)
|
||||
{
|
||||
}
|
||||
|
||||
TimeField::TimeField(Form &form, const String &label)
|
||||
: Field(form, label)
|
||||
, _value(0)
|
||||
, _maxHours(24)
|
||||
, _printLen(0)
|
||||
, _readOnly(false)
|
||||
, editField(EDIT_HOUR)
|
||||
{
|
||||
}
|
||||
|
||||
TimeField::TimeField(Form &form, const String &label, int maxHours, bool readOnly)
|
||||
: Field(form, label)
|
||||
, _value(0)
|
||||
, _maxHours(maxHours)
|
||||
, _printLen(0)
|
||||
, _readOnly(readOnly)
|
||||
, editField(EDIT_HOUR)
|
||||
{
|
||||
}
|
||||
|
||||
int TimeField::dispatch(int event)
|
||||
{
|
||||
unsigned long newValue;
|
||||
if (_readOnly)
|
||||
return -1;
|
||||
if (event == LCD_BUTTON_UP) {
|
||||
newValue = _value;
|
||||
if (editField == EDIT_HOUR) {
|
||||
newValue += 60 * 60;
|
||||
} else if (editField == EDIT_MINUTE_TENS) {
|
||||
if (((newValue / 60) % 60) >= 50)
|
||||
newValue -= 50 * 60;
|
||||
else
|
||||
newValue += 10 * 60;
|
||||
} else if (editField == EDIT_MINUTE) {
|
||||
if (((newValue / 60) % 60) == 59)
|
||||
newValue -= 59 * 60;
|
||||
else
|
||||
newValue += 60;
|
||||
} else if (editField == EDIT_SECOND_TENS) {
|
||||
if ((newValue % 60) >= 50)
|
||||
newValue -= 50;
|
||||
else
|
||||
newValue += 10;
|
||||
} else {
|
||||
if ((newValue % 60) == 59)
|
||||
newValue -= 59;
|
||||
else
|
||||
newValue += 1;
|
||||
}
|
||||
setValue(newValue);
|
||||
return FORM_CHANGED;
|
||||
} else if (event == LCD_BUTTON_DOWN) {
|
||||
newValue = _value;
|
||||
if (editField == EDIT_HOUR) {
|
||||
if (newValue < 60 * 60)
|
||||
newValue += ((unsigned long)(_maxHours - 1)) * 60 * 60;
|
||||
else
|
||||
newValue -= 60 * 60;
|
||||
} else if (editField == EDIT_MINUTE_TENS) {
|
||||
if (((newValue / 60) % 60) < 10)
|
||||
newValue += 50 * 60;
|
||||
else
|
||||
newValue -= 10 * 60;
|
||||
} else if (editField == EDIT_MINUTE) {
|
||||
if (((newValue / 60) % 60) == 0)
|
||||
newValue += 59 * 60;
|
||||
else
|
||||
newValue -= 60;
|
||||
} else if (editField == EDIT_SECOND_TENS) {
|
||||
if ((newValue % 60) < 10)
|
||||
newValue += 50;
|
||||
else
|
||||
newValue -= 10;
|
||||
} else {
|
||||
if ((newValue % 60) == 0)
|
||||
newValue += 59;
|
||||
else
|
||||
newValue -= 1;
|
||||
}
|
||||
setValue(newValue);
|
||||
return FORM_CHANGED;
|
||||
} else if (event == LCD_BUTTON_LEFT) {
|
||||
if (editField != EDIT_HOUR) {
|
||||
--editField;
|
||||
printTime();
|
||||
return 0;
|
||||
}
|
||||
} else if (event == LCD_BUTTON_RIGHT) {
|
||||
if (editField != EDIT_SECOND) {
|
||||
++editField;
|
||||
printTime();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TimeField::enterField(bool reverse)
|
||||
{
|
||||
Field::enterField(reverse);
|
||||
if (reverse)
|
||||
editField = EDIT_SECOND;
|
||||
else
|
||||
editField = EDIT_HOUR;
|
||||
printTime();
|
||||
if (!_readOnly)
|
||||
lcd()->cursor();
|
||||
}
|
||||
|
||||
void TimeField::exitField()
|
||||
{
|
||||
if (!_readOnly)
|
||||
lcd()->noCursor();
|
||||
Field::exitField();
|
||||
}
|
||||
|
||||
void TimeField::setValue(unsigned long value)
|
||||
{
|
||||
unsigned long maxSecs = ((unsigned long)_maxHours) * 60 * 60;
|
||||
value %= maxSecs;
|
||||
if (value != _value) {
|
||||
_value = value;
|
||||
if (isCurrent())
|
||||
printTime();
|
||||
}
|
||||
}
|
||||
|
||||
void TimeField::setReadOnly(bool value)
|
||||
{
|
||||
if (_readOnly != value) {
|
||||
_readOnly = value;
|
||||
printTime();
|
||||
if (isCurrent()) {
|
||||
if (value)
|
||||
lcd()->cursor();
|
||||
else
|
||||
lcd()->noCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimeField::printTime()
|
||||
{
|
||||
lcd()->setCursor(0, 1);
|
||||
int col = printField(_value / (60 * 60));
|
||||
int hourCol = col - 1;
|
||||
lcd()->write(':');
|
||||
++col;
|
||||
col += printField((_value / 60) % 60);
|
||||
int minuteCol = col - 1;
|
||||
lcd()->write(':');
|
||||
++col;
|
||||
col += printField(_value % 60);
|
||||
int secondCol = col - 1;
|
||||
int tempCol = col;
|
||||
while (tempCol++ < _printLen)
|
||||
lcd()->write(' ');
|
||||
_printLen = col;
|
||||
if (!_readOnly) {
|
||||
if (editField == EDIT_HOUR)
|
||||
lcd()->setCursor(hourCol, 1);
|
||||
else if (editField == EDIT_MINUTE_TENS)
|
||||
lcd()->setCursor(minuteCol - 1, 1);
|
||||
else if (editField == EDIT_MINUTE)
|
||||
lcd()->setCursor(minuteCol, 1);
|
||||
else if (editField == EDIT_SECOND_TENS)
|
||||
lcd()->setCursor(secondCol - 1, 1);
|
||||
else
|
||||
lcd()->setCursor(secondCol, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int TimeField::printField(unsigned long value)
|
||||
{
|
||||
if (value < 100) {
|
||||
lcd()->write('0' + (int)(value / 10));
|
||||
lcd()->write('0' + (int)(value % 10));
|
||||
return 2;
|
||||
}
|
||||
unsigned long divisor = 100;
|
||||
while ((value / divisor) >= 10)
|
||||
divisor *= 10;
|
||||
int digits = 0;
|
||||
while (divisor > 0) {
|
||||
lcd()->write('0' + (int)((value / divisor) % 10));
|
||||
divisor /= 10;
|
||||
++digits;
|
||||
}
|
||||
return digits;
|
||||
}
|
40
libraries/FreetronicsLCD/TimeField.h
Normal file
40
libraries/FreetronicsLCD/TimeField.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef TimeField_h
|
||||
#define TimeField_h
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
#define TIMEFIELD_READ_ONLY true
|
||||
#define TIMEFIELD_READ_WRITE false
|
||||
|
||||
class TimeField : public Field {
|
||||
public:
|
||||
explicit TimeField(const String &label);
|
||||
TimeField(Form &form, const String &label);
|
||||
TimeField(Form &form, const String &label, int maxHours, bool readOnly);
|
||||
|
||||
int dispatch(int event);
|
||||
|
||||
void enterField(bool reverse);
|
||||
void exitField();
|
||||
|
||||
unsigned long value() const { return _value; }
|
||||
void setValue(unsigned long value);
|
||||
|
||||
int maxHours() const { return _maxHours; }
|
||||
void setMaxHours(int maxHours) { _maxHours = maxHours; }
|
||||
|
||||
bool isReadOnly() const { return _readOnly; }
|
||||
void setReadOnly(bool value);
|
||||
|
||||
private:
|
||||
unsigned long _value;
|
||||
int _maxHours;
|
||||
int _printLen;
|
||||
bool _readOnly;
|
||||
uint8_t editField;
|
||||
|
||||
void printTime();
|
||||
int printField(unsigned long value);
|
||||
};
|
||||
|
||||
#endif
|
60
libraries/FreetronicsLCD/examples/Form/Form.pde
Normal file
60
libraries/FreetronicsLCD/examples/Form/Form.pde
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
This example demonstrates how to use the Form and Field classes from the
|
||||
FreetronicsLCD library to provide a simple UI on the 16x2 LCD display.
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <FreetronicsLCD.h>
|
||||
#include <Form.h>
|
||||
#include <TextField.h>
|
||||
#include <TimeField.h>
|
||||
#include <IntField.h>
|
||||
#include <BoolField.h>
|
||||
|
||||
// Initialize the LCD
|
||||
FreetronicsLCD lcd;
|
||||
|
||||
// Note: if you are using the USBDroid and have reassigned pin D9 on the LCD shield to some
|
||||
// other pin (e.g. A1), then you will need to initialize the shield with something like:
|
||||
// FreetronicsLCD lcd(A1);
|
||||
// See also: http://www.freetronics.com/pages/combining-the-lcd-keypad-shield-and-the-usbdroid
|
||||
|
||||
// Create the main form and its fields.
|
||||
Form mainForm(lcd);
|
||||
TextField welcomeField(mainForm, "Form example", "v1.0");
|
||||
TimeField timeField(mainForm, "Time since reset", 24, TIMEFIELD_READ_ONLY);
|
||||
IntField volumeField(mainForm, "Volume", 0, 100, 5, 85, "%");
|
||||
BoolField ledField(mainForm, "Status LED", "On", "Off", true);
|
||||
TimeField durationField(mainForm, "Timer duration", 24, TIMEFIELD_READ_WRITE);
|
||||
|
||||
#define STATUS_LED 13
|
||||
|
||||
void setup() {
|
||||
// Status LED initially on.
|
||||
pinMode(STATUS_LED, OUTPUT);
|
||||
digitalWrite(STATUS_LED, HIGH);
|
||||
|
||||
// Enable the screen saver, which will automatically blank the screen after 10 seconds.
|
||||
// The screen will wake up again when a button is pressed or lcd.display() is called.
|
||||
lcd.enableScreenSaver();
|
||||
|
||||
// Show the main form for the first time.
|
||||
mainForm.show();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Update the number of seconds since reset:
|
||||
timeField.setValue(millis() / 1000);
|
||||
|
||||
// Dispatch button events to the main form.
|
||||
int button = lcd.getButton();
|
||||
if (mainForm.dispatch(button) == FORM_CHANGED) {
|
||||
if (mainForm.isCurrent(ledField)) {
|
||||
if (ledField.value())
|
||||
digitalWrite(STATUS_LED, HIGH);
|
||||
else
|
||||
digitalWrite(STATUS_LED, LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,21 @@
|
||||
FreetronicsLCD KEYWORD1
|
||||
Form KEYWORD1
|
||||
Field KEYWORD1
|
||||
BoolField KEYWORD1
|
||||
IntField KEYWORD1
|
||||
TextField KEYWORD1
|
||||
TimeField KEYWORD1
|
||||
|
||||
getButton KEYWORD2
|
||||
enableScreenSaver KEYWORD2
|
||||
disableScreenSaver KEYWORD2
|
||||
isScreenSaved KEYWORD2
|
||||
|
||||
show KEYWORD2
|
||||
hide KEYWORD2
|
||||
dispatch KEYWORD2
|
||||
isCurrent KEYWORD2
|
||||
|
||||
setLabel KEYWORD2
|
||||
setValue KEYWORD2
|
||||
value KEYWORD2
|
||||
|
Loading…
x
Reference in New Issue
Block a user