├── .gitignore ├── Gui.cpp ├── GuiButton.cpp ├── GuiCheckBox.cpp ├── GuiConfig.h.template ├── GuiElementList.cpp ├── GuiGrid.cpp ├── GuiLabel.cpp ├── GuiLibrary.cpp ├── GuiLibrary.h ├── GuiListBox.cpp ├── GuiMultiLineTextBox.cpp ├── GuiPanel.cpp ├── GuiRadioList.cpp ├── GuiUtils.cpp ├── LICENSE ├── LinkedList.cpp ├── LinkedList.h ├── MetroCharmsTileColors.png ├── README.md ├── examples ├── GuiCheckRadio │ └── GuiCheckRadio.ino ├── GuiListBox │ └── GuiListBox.ino ├── GuiListElement │ └── GuiListElement.ino ├── GuiMetro │ └── GuiMetro.ino ├── GuiMetroGrid │ └── GuiMetroGrid.ino ├── GuiMetroGridImages │ └── GuiMetroGridImages.ino ├── GuiTextBox │ └── GuiTextBox.ino └── KBMenuMockup │ └── KBMenuMockup.ino ├── images ├── checkradioexample.jpg ├── listexample.jpg ├── metroexample.jpg └── metroexample2.jpg ├── library.json └── readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | GuiConfig.h 2 | -------------------------------------------------------------------------------- /Gui.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | #if ARDUINO < 100 15 | #include 16 | #else 17 | #include 18 | #endif 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include "GuiLibrary.h" 26 | 27 | Adafruit_GFX* _tft; 28 | 29 | #if USING_SD 30 | SdFat* _sd; 31 | uint8_t _TFT_CS = 10; 32 | #endif 33 | 34 | Gui::Gui(void) { 35 | 36 | } 37 | 38 | void Gui::draw(void) { 39 | drawBase(); 40 | GuiElement::draw(); 41 | } 42 | 43 | void Gui::setRotation(int16_t degrees) { // multiples of 90 44 | if (degrees == 0) 45 | _tft->setRotation(0); 46 | else 47 | _tft->setRotation(degrees/90); 48 | 49 | rotation = degrees; 50 | } 51 | 52 | void Gui::sendEventToWidget(int16_t x, int16_t y, int8_t eventid) { 53 | // do collision detection 54 | GuiNode *tmphead = children.head(); 55 | 56 | if (tmphead != NULL) { 57 | // get the last element 58 | while (tmphead != NULL) { 59 | GuiElement* element = (GuiElement*)tmphead->element(); 60 | GuiElement *found = element->pointInWidget(x, y); 61 | 62 | if (found != NULL) { 63 | found->callbackProcess(found, eventid); 64 | return; 65 | } 66 | 67 | if (tmphead->next() == NULL) 68 | break; 69 | 70 | tmphead = tmphead->next(); 71 | } 72 | } 73 | } 74 | 75 | // main app processing loop 76 | void Gui::update(void) { 77 | static bool isPressing = false; 78 | static int16_t pressing_x, pressing_y; 79 | static uint16_t stamp = millis(); 80 | 81 | // Retrieve a point 82 | TSPoint p = ts->getPoint(); 83 | 84 | // we have some minimum pressure we consider 'valid' 85 | // pressure of 0 means no pressing! 86 | if (p.z < MINPRESSURE || p.z > MAXPRESSURE) { 87 | uint16_t stampnow = millis() - stamp; 88 | 89 | // this serves as a debouncer/filter for those seemingly super crapola resistive panels 90 | // we are going to release this key after 5k millis regardless 91 | if ((stampnow > DEBOUNCE_DELAY && stampnow < 5000) && isPressing) { 92 | sendEventToWidget(pressing_x, pressing_y, GUI_EVENT_RELEASE); 93 | isPressing = false; 94 | stamp = millis(); 95 | } 96 | return; 97 | } 98 | 99 | stamp = millis(); 100 | 101 | // if the finger is still on the screen we don't need to do any work until it is released 102 | if (isPressing) 103 | return; 104 | 105 | // given a rotation for this tft, set th input device to map correctly to the display's orientation 106 | if (rotation == 0) { 107 | p.x = map(p.x, TS_MINX, TS_MAXX, 0, _tft->width()); 108 | p.y = map(p.y, TS_MINY, TS_MAXY, 0, _tft->height()); 109 | } 110 | else if (rotation == 90) { 111 | 112 | p.x = map(p.y, TS_MINY, TS_MAXY, 0, _tft->width()); 113 | p.y = map(p.x, TS_MINX, TS_MAXX, _tft->height(), 0); 114 | } 115 | else if (rotation == 180) { 116 | 117 | p.x = map(p.x, TS_MINX, TS_MAXX, _tft->width(), 0); 118 | p.y = map(p.y, TS_MINY, TS_MAXY, _tft->height(), 0); 119 | } 120 | else if (rotation == 270) { 121 | int16_t oldx = p.x; 122 | p.x = map(p.y, TS_MINY, TS_MAXY, _tft->width(), 0); 123 | p.y = map(oldx, TS_MINX, TS_MAXX, 0, _tft->height()); 124 | } 125 | 126 | Serial.print("x: "); Serial.print(p.x); Serial.print(" y: "); Serial.println(p.y); 127 | 128 | pressing_x = p.x; 129 | pressing_y = p.y; 130 | 131 | sendEventToWidget(p.x, p.y, GUI_EVENT_PRESS); 132 | 133 | isPressing = true; 134 | } 135 | -------------------------------------------------------------------------------- /GuiButton.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | //an external global reference to the tft. 18 | extern Adafruit_GFX* _tft; 19 | 20 | // process the callback. This invokes the callback by calling the handle, 21 | // and using the processEventPointer to send back the scope 22 | uint8_t GuiButton::callbackProcess(processEvent_t processEventHandle, void* processEventPointer, GuiElement *element, uint8_t event) { 23 | if (!visible() || !enabled()) 24 | return 0; 25 | 26 | uint8_t ret = 0; 27 | 28 | if (processEventHandle != NULL) 29 | processEventHandle(processEventPointer, element, event); 30 | 31 | GuiElement* backupParent = parent; 32 | 33 | // the callback wants to go somewhere else, or otherwise doesn't want a redraw. 34 | // we are going to cheat here and tell this widget it has no parent, set the flags, and then restore the parent 35 | // TODO maybe bring back those nodraw options to the setters 36 | if (ret > 0) 37 | { 38 | // force element to be un-pressed without a redraw 39 | parent = NULL; 40 | } 41 | 42 | // do some drawing state stuff 43 | if (event == GUI_EVENT_PRESS) { 44 | pressed(true); 45 | } 46 | else if (event == GUI_EVENT_RELEASE) { 47 | pressed(false); 48 | } 49 | 50 | parent = backupParent; 51 | 52 | // this return is for the c++ version of the callbacks, for a c callback the EventPointer will be null 53 | return ret; 54 | 55 | /* 56 | * Here is the caller side implementation. it needs a static class wrapper adding to the caller 57 | * which when called uses casting to cast back to the stored source class 58 | * 59 | * static uint8_t processEvent(void *p, GuiElement *element, uint8_t event) { 60 | * return ((CallBackSourceClass *)p)->callbackFunction(element, event); 61 | * } 62 | * 63 | * where the callback function is defined as 64 | * uint8_t callbackFunction(GuiElement *element, uint8_t event); 65 | * 66 | * don't forget to connect the callback 67 | * 68 | * button.connectCallback(processEvent, this); <-- note we pass the static function 69 | * 70 | */ 71 | } 72 | 73 | 74 | void GuiButton::draw(void) { 75 | if (!visible()) return; 76 | 77 | int16_t newx = absoluteX(); 78 | int16_t newy = absoluteY(); 79 | 80 | // erase or fill the bg 81 | if (pressed()) { 82 | _tft->fillRect(newx, newy, width, height, COLOR_WHITE); 83 | } 84 | else { 85 | // when we press we take care of the background fill below 86 | GuiElement::drawBase(); 87 | } 88 | 89 | #if USING_SD 90 | // all we are responsible for is drawing the image. the text is drawn by the base Label class 91 | if (imageFileName != NULL && !pressed()) { 92 | newy += (height/2) - imageSize/2; 93 | 94 | if (imageAlignH == TEXT_H_ALIGN_CENTRE) { 95 | newx += (width/2) - imageSize/2; 96 | } 97 | else if (imageAlignH == TEXT_H_ALIGN_RIGHT) { 98 | newx += width - imageSize/2 + margin; 99 | } 100 | 101 | GuiUtils::bmpDraw(imageFileName, newx + padding, newy + padding); 102 | } 103 | #endif 104 | 105 | // draw all of the children now 106 | GuiLabel::draw(false); 107 | 108 | } 109 | -------------------------------------------------------------------------------- /GuiCheckBox.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | //an external global reference to the tft. 18 | extern Adafruit_GFX* _tft; 19 | 20 | // process the callback. This invokes the callback by calling the handle, 21 | // and using the processEventPointer to send back the scope 22 | uint8_t GuiCheckBox::callbackProcess(processEvent_t processEventHandle, void* processEventPointer, GuiElement *element, uint8_t event) { 23 | if (!visible() || !enabled()) 24 | return 0; 25 | 26 | //GuiElement* backupParent = parent; 27 | 28 | // the callback wants to go somewhere else, or otherwise doesn't want a redraw. 29 | // we are going to cheat here and tell this widget it has no parent, set the flags, and then restore the parent 30 | // TODO maybe bring back those nodraw options to the setters 31 | // if (ret > 0) 32 | // parent = NULL; 33 | 34 | // when the finger comes away from the checkbox, we toggle state 35 | if (event == GUI_EVENT_RELEASE) { 36 | pressed(!(pressed())); 37 | } 38 | 39 | // this return is for the c++ version of the callbacks, for a c callback the EventPointer will be null 40 | if (processEventHandle != NULL) 41 | processEventHandle(processEventPointer, element, event); 42 | 43 | // parent = backupParent; 44 | 45 | return 0; 46 | 47 | /* 48 | * Here is the caller side implementation. it needs a static class wrapper adding to the caller 49 | * which when called uses casting to cast back to the stored source class 50 | * 51 | * static uint8_t processEvent(void *p, GuiElement *element, uint8_t event) { 52 | * return ((CallBackSourceClass *)p)->callbackFunction(element, event); 53 | * } 54 | * 55 | * where the callback function is defined as 56 | * uint8_t callbackFunction(GuiElement *element, uint8_t event); 57 | * 58 | * don't forget to connect the callback 59 | * 60 | * button.connectCallback(processEvent, this); <-- note we pass the static function 61 | * 62 | */ 63 | } 64 | 65 | 66 | void GuiCheckBox::draw(void) { 67 | if (!visible()) return; 68 | 69 | int16_t newx = absoluteX() + padding; 70 | int16_t midy = GuiUtils::getElementCentreY(this); 71 | int16_t midFontHeight = (fontSize() * 7)/2; 72 | int8_t boxSize = fontSize() * 7; 73 | 74 | GuiElement::drawBase(); 75 | 76 | _tft->drawRect(newx, midy - midFontHeight, boxSize, boxSize, COLOR_WHITE); 77 | 78 | // erase or fill the bg 79 | if (pressed()) { 80 | // tick it 81 | _tft->drawLine(newx, midy - midFontHeight, newx + boxSize - 1, midy + (boxSize /2) - 1, COLOR_WHITE); 82 | _tft->drawLine(newx + boxSize - 1, midy - midFontHeight, newx, midy + (boxSize /2) - 1, COLOR_WHITE); 83 | } 84 | extraXOffset = 5 + fontSize() * 7; 85 | 86 | // draw all of the children now 87 | GuiLabel::draw(false); 88 | 89 | } 90 | -------------------------------------------------------------------------------- /GuiConfig.h.template: -------------------------------------------------------------------------------- 1 | /* 2 | * GuiConfig.h 3 | * 4 | * Created on: 19. 5. 2016 5 | * Author: jindra 6 | */ 7 | 8 | #ifndef GUICONFIG_H_ 9 | #define GUICONFIG_H_ 10 | 11 | 12 | // This is calibration data for the raw touch data to the screen coordinates 13 | #define TS_MINX 340 14 | #define TS_MAXX 583 15 | #define TS_MINY 283 16 | #define TS_MAXY 966 17 | 18 | 19 | 20 | #endif /* GUICONFIG_H_ */ 21 | -------------------------------------------------------------------------------- /GuiElementList.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | void GuiElementList::addChild(GuiElement *child) { 18 | // remap the x and y of the child 19 | child->y += totalHeight + child->margin + padding; 20 | totalHeight = absoluteY() + child->y + child->height + child->margin + padding; 21 | height = totalHeight; 22 | 23 | GuiElement::addChild(child); 24 | }; 25 | 26 | GuiElement* GuiElementList::pointInWidget(int16_t x, int16_t y) { 27 | GuiElement* element = GuiUtils::pointInWidget(this, x, y); 28 | if (element != NULL) { 29 | selectedElement = element; 30 | return this; 31 | } 32 | return NULL; 33 | } 34 | 35 | void GuiElementList::selectElement(GuiElement* element, bool skipredraw) { 36 | GuiElement* backupParent = parent; 37 | 38 | // deselect all elements apart from the last selected element 39 | GuiNode *tmphead = children.head(); 40 | 41 | while (tmphead != NULL) { 42 | GuiElement* element = (GuiElement*)tmphead->element(); 43 | 44 | // the callback wants to go somewhere else, or otherwise doesn't want a redraw. 45 | // we are going to cheat here and tell this widget it has no parent, set the flags, and then restore the parent 46 | // TODO maybe bring back those nodraw options to the setters 47 | if (skipredraw) 48 | parent = NULL; 49 | 50 | if (element != selectedElement) 51 | element->pressed(false); 52 | else { 53 | element->pressed(true); 54 | } 55 | 56 | parent = backupParent; 57 | 58 | if (tmphead->next() == NULL) 59 | break; 60 | 61 | tmphead = tmphead->next(); 62 | } 63 | } 64 | 65 | 66 | // process the callback. This invokes the callback by calling the handle, 67 | // and using the processEventPointer to send back the scope 68 | uint8_t GuiElementList::callbackProcess(processEvent_t processEventHandle, void* processEventPointer, GuiElement *element, uint8_t event) { 69 | if (!visible() || !enabled()) 70 | return 0; 71 | 72 | if (event == GUI_EVENT_PRESS && selectedElement) { 73 | selectElement(selectedElement, true); 74 | // chain the callback 75 | selectedElement->callbackProcess(processEventHandle, processEventPointer, selectedElement, event); 76 | } 77 | 78 | if (processEventHandle != NULL) 79 | processEventHandle(NULL, selectedElement, event); 80 | 81 | // draw(); 82 | 83 | // this return is for the c++ version of the callbacks 84 | return 0; 85 | 86 | /* 87 | * Here is the caller side implementation. it needs a static class wrapper adding to the caller 88 | * which when called uses casting to cast back to the stored source class 89 | * 90 | * static uint8_t processEvent(void *p, GuiElement *element, uint8_t event) { 91 | * return ((CallBackSourceClass *)p)->callbackFunction(element, event); 92 | * } 93 | * 94 | * where the callback function is defined as 95 | * uint8_t callbackFunction(GuiElement *element, uint8_t event); 96 | * 97 | * don't forget to connect the callback 98 | * 99 | * button.connectCallback(processEvent, this); <-- note we pass the static function 100 | * 101 | */ 102 | } 103 | -------------------------------------------------------------------------------- /GuiGrid.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | GuiGrid::GuiGrid(int16_t x, int16_t y, int16_t width, int16_t height, uint8_t columns, uint8_t rows) 18 | : GuiElement(x, y, width, height) { 19 | columnCount = columns; 20 | rowCount = rows; 21 | }; 22 | 23 | void GuiGrid::addElement(GuiElement *element, uint8_t col, uint8_t row, uint8_t colspan, uint8_t rowspan) { 24 | uint16_t columnWidth = width / columnCount; 25 | uint16_t columnHeight = height / rowCount; 26 | // remap the x and y of the child 27 | element->x = (col * columnWidth); 28 | element->y = (row * columnHeight); 29 | GuiElement::addChild(element); 30 | element->width = (columnWidth * colspan) - (2 * element->margin); 31 | element->height = (columnHeight * rowspan) - (2 * element->margin);; 32 | 33 | } 34 | 35 | void GuiGrid::draw(void) { 36 | if (!visible()) return; 37 | 38 | // draw the borders background, all that stuff 39 | GuiElement::drawBase(); 40 | 41 | // draw all of the children now 42 | GuiElement::draw(); 43 | } 44 | 45 | 46 | ////////////////////////// 47 | -------------------------------------------------------------------------------- /GuiLabel.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | void GuiLabel::draw() { 18 | draw(true); 19 | } 20 | 21 | void GuiLabel::draw(bool andBase) { 22 | if (!visible()) return; 23 | 24 | if (andBase) 25 | GuiElement::drawBase(); 26 | 27 | // draw the text 28 | int16_t newx = absoluteX() + padding; 29 | int16_t newy = absoluteY() + padding; 30 | 31 | // only do this if there is some text to draw 32 | if (labelText != NULL) { 33 | // vertically align 34 | newy = GuiUtils::getElementCentreY(this) - ((labelFontSize * 7)/2); 35 | 36 | if (textAlignH == TEXT_H_ALIGN_CENTRE) { 37 | uint16_t centrex = GuiUtils::getElementCentreX(this); 38 | newx = extraXOffset + centrex - ((strlen(labelText) * (labelFontSize *6)) / 2); 39 | } 40 | else if (textAlignH == TEXT_H_ALIGN_RIGHT) { 41 | newx = extraXOffset + (newx + width) - (strlen(labelText) * (labelFontSize *6)) - padding; 42 | } 43 | else { 44 | newx += extraXOffset; 45 | } 46 | 47 | GuiUtils::drawText(this, labelText, foregroundColour, newx, newy, labelFontSize); 48 | } 49 | // draw all children 50 | GuiElement::draw(); 51 | } 52 | 53 | ////////////////////////// 54 | -------------------------------------------------------------------------------- /GuiLibrary.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #if ARDUINO < 100 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include "GuiLibrary.h" 27 | 28 | //an external global reference to the tft. 29 | extern Adafruit_GFX* _tft; 30 | 31 | GuiElement::GuiElement(void) { 32 | } 33 | 34 | GuiElement::GuiElement(int16_t posX, int16_t posY, int16_t w, int16_t h) 35 | { 36 | x = posX; 37 | y = posY; 38 | width = w; 39 | height = h; 40 | } 41 | 42 | // set enabled or not the for element. 43 | void GuiElement::enabled(bool isenabled) { 44 | if (((settingsFlags >> ENABLED) & 1) == isenabled) return; 45 | 46 | if (isenabled) 47 | settingsFlags |= 1 << ENABLED; 48 | else 49 | settingsFlags &= ~(1 << ENABLED); 50 | 51 | // we don't draw unparented widgets. They are usually just being built 52 | if (parent != NULL) 53 | draw(); 54 | } 55 | 56 | void GuiElement::transparent(bool istransparent) { 57 | if (((settingsFlags >> TRANSPARENT) & 1) == istransparent) return; 58 | 59 | if (istransparent) 60 | settingsFlags |= 1 << TRANSPARENT; 61 | else 62 | settingsFlags &= ~(1 << TRANSPARENT); 63 | 64 | // we don't draw unparented widgets. They are usually just being built 65 | if (parent != NULL) 66 | draw(); 67 | } 68 | 69 | bool GuiElement::visible(void) { 70 | // if the parent isn't visible, we shouldn't be 71 | if ((settingsFlags >> VISIBLE) & 1) 72 | { 73 | if (parent != NULL && !parent->visible()) 74 | return false; 75 | return true; 76 | } 77 | return false; 78 | } 79 | 80 | // hide the element and stop any further processing 81 | void GuiElement::visible(bool isvisible) { 82 | if (((settingsFlags >> VISIBLE) & 1) == isvisible) return; 83 | 84 | if (isvisible) 85 | settingsFlags |= 1 << VISIBLE; 86 | else 87 | settingsFlags &= ~(1 << VISIBLE); 88 | 89 | // we have to clear the area the element was in now 90 | _tft->fillRect(absoluteX(), absoluteY(), width, height, backgroundColourFromParent()); 91 | 92 | // we don't draw unparented widgets. They are usually just being built 93 | if (parent != NULL) 94 | draw(); 95 | } 96 | 97 | void GuiElement::pressed(bool ispressed) { 98 | if (((settingsFlags >> PRESSED) & 1) == ispressed) return; 99 | 100 | if (ispressed) 101 | settingsFlags |= 1 << PRESSED; 102 | else 103 | settingsFlags &= ~(1 << PRESSED); 104 | 105 | // we don't draw unparented widgets. They are usually just being built 106 | if (parent != NULL) 107 | draw(); 108 | } 109 | 110 | // calculate the actual position of this element 111 | int16_t GuiElement::absoluteX() { 112 | return ((parent == NULL) ? (x + margin) : parent->absoluteX() + (x + margin)); 113 | } 114 | 115 | int16_t GuiElement::absoluteY() { 116 | return ((parent == NULL) ? (y + margin) : parent->absoluteY() + (y + margin)); 117 | } 118 | 119 | // draw the base of the widget. teh background, 120 | void GuiElement::drawBase(void) { 121 | if (((settingsFlags >> VISIBLE) & 1) == false) return; 122 | 123 | // if the parent isn't visible, we shouldn't be 124 | if (parent != NULL && !parent->enabled()) return; 125 | 126 | bool isEnabled = (settingsFlags >> ENABLED) & 1; 127 | 128 | if (!transparent() || !isEnabled) { 129 | _tft->fillRect(absoluteX(), absoluteY(), width, height, (isEnabled ? backgroundColour : COLOR_LIGHTGREY)); 130 | } 131 | else if (transparent()) { 132 | // it won't get drawn if there is no background on it, so we swipe it from the parent 133 | uint16_t colour = backgroundColourFromParent(); 134 | _tft->fillRect(absoluteX(), absoluteY(), width, height, colour); 135 | } 136 | 137 | // draw the guide lines 138 | // uint16_t y = GuiUtils::getElementCentreY(this); 139 | // _tft->drawLine(absoluteX(), y, absoluteX() + width - margin, y, ILI9341_RED); 140 | 141 | // draw the outline border 142 | if (borderWidth > 0) { 143 | int16_t colour = borderColour; 144 | 145 | if (!enabled()) { 146 | colour = COLOR_DARKGREY; 147 | } 148 | _tft->drawRect(absoluteX(), absoluteY(), width, height, colour); 149 | } 150 | } 151 | 152 | void GuiElement::draw(void) { 153 | if (!visible()) return; 154 | 155 | GuiNode *tmphead = children.head(); 156 | 157 | while (tmphead != NULL) { 158 | GuiElement* element = (GuiElement*)tmphead->element(); 159 | element->draw(); 160 | 161 | if (tmphead->next() == NULL) 162 | break; 163 | 164 | tmphead = tmphead->next(); 165 | } 166 | } 167 | 168 | uint16_t GuiElement::backgroundColourFromParent(void) { 169 | GuiElement* el = parent; 170 | while (el != NULL) { 171 | if (parent->backgroundColour >= 0) 172 | break; 173 | el = el->parent; 174 | } 175 | if (el == NULL || backgroundColour < 0) 176 | return DEFAULT_COLOUR_BG; 177 | else 178 | return el->backgroundColour; 179 | } 180 | 181 | void GuiElement::addChild(GuiElement *child) { 182 | child->parent = this; 183 | children.addElement((char*)child); 184 | } 185 | 186 | GuiElement* GuiElement::pointInWidget(int16_t x, int16_t y) { 187 | // if the parent isn't visible, we shouldn't be 188 | if ((parent != NULL && !parent->visible()) || !visible()) return NULL; 189 | 190 | if ((x > absoluteX() && x < absoluteX() + width) && 191 | (y > absoluteY() && y < absoluteY() + height)) { 192 | // we know the point is in this element somewhere, 193 | // check all childrent to see if this event is for a child 194 | GuiElement* found = GuiUtils::pointInWidget(this, x, y); 195 | if (!found) { 196 | return this; 197 | } 198 | return found; 199 | } 200 | return NULL; 201 | } 202 | 203 | -------------------------------------------------------------------------------- /GuiLibrary.h: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #ifndef _GUILIBRARY_H_ 16 | #define _GUILIBRARY_H_ 17 | #include 18 | #include "LinkedList.h" 19 | #include // Core graphics library 20 | #include 21 | #include "TouchScreen.h" 22 | 23 | // sometimes we want to disable this 24 | //#define USING_SD 1 25 | 26 | #if USING_SD 27 | #include 28 | #endif 29 | 30 | // This is calibration data for the raw touch data to the screen coordinates 31 | #ifndef TS_MINX 32 | #define TS_MINX 150 33 | #endif 34 | #ifndef TS_MINY 35 | #define TS_MINY 120 36 | #endif 37 | #ifndef TS_MAXX 38 | #define TS_MAXX 920 39 | #endif 40 | #ifndef TS_MAXY 41 | #define TS_MAXY 940 42 | #endif 43 | 44 | #define MINPRESSURE 15 45 | #define MAXPRESSURE 1000 46 | 47 | // debounce delay for button presses on crappy touchsreens 48 | #define DEBOUNCE_DELAY 50 49 | 50 | // Event types for button presse etc 51 | #define GUI_EVENT_PRESS 0 52 | #define GUI_EVENT_RELEASE 1 53 | #define GUI_EVENT_DRAG 2 54 | 55 | 56 | // settings flags to save memory 57 | #define ENABLED 0 58 | #define VISIBLE 1 59 | #define TRANSPARENT 2 60 | #define PRESSED 3 61 | 62 | #define COLOR_BLACK 0x0000 /* 0, 0, 0 */ 63 | #define COLOR_NAVY 0x000F /* 0, 0, 128 */ 64 | #define COLOR_DARKGREEN 0x03E0 /* 0, 128, 0 */ 65 | #define COLOR_DARKCYAN 0x03EF /* 0, 128, 128 */ 66 | #define COLOR_MAROON 0x7800 /* 128, 0, 0 */ 67 | #define COLOR_PURPLE 0x780F /* 128, 0, 128 */ 68 | #define COLOR_OLIVE 0x7BE0 /* 128, 128, 0 */ 69 | #define COLOR_LIGHTGREY 0xC618 /* 192, 192, 192 */ 70 | #define COLOR_DARKGREY 0x7BEF /* 128, 128, 128 */ 71 | #define COLOR_BLUE 0x001F /* 0, 0, 255 */ 72 | #define COLOR_GREEN 0x07E0 /* 0, 255, 0 */ 73 | #define COLOR_CYAN 0x07FF /* 0, 255, 255 */ 74 | #define COLOR_RED 0xF800 /* 255, 0, 0 */ 75 | #define COLOR_MAGENTA 0xF81F /* 255, 0, 255 */ 76 | #define COLOR_YELLOW 0xFFE0 /* 255, 255, 0 */ 77 | #define COLOR_WHITE 0xFFFF /* 255, 255, 255 */ 78 | #define COLOR_ORANGE 0xFD20 /* 255, 165, 0 */ 79 | #define COLOR_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ 80 | #define COLOR_PINK 0xF81F 81 | 82 | // default colours 83 | #define DEFAULT_COLOUR_BG COLOR_DARKGREY 84 | #define DEFAULT_COLOUR_FG COLOR_BLACK 85 | #define DEFAULT_COLOUR_BORDER COLOR_WHITE 86 | 87 | 88 | class GuiElement { 89 | public: 90 | typedef uint8_t (*processEvent_t)(void *p, GuiElement* element, uint8_t event); // anonymous type to function pointer 91 | GuiElement(void); 92 | GuiElement(int16_t x, int16_t y, int16_t width, int16_t height); 93 | 94 | int16_t x, y, width, height; // size and position related 95 | int8_t margin = 1; 96 | int8_t padding = 3; 97 | uint8_t borderWidth = 0; 98 | uint16_t borderColour = DEFAULT_COLOUR_BORDER; 99 | uint16_t backgroundColour = DEFAULT_COLOUR_BG; 100 | uint16_t foregroundColour = DEFAULT_COLOUR_FG; 101 | 102 | bool enabled() { return (settingsFlags >> ENABLED) & 1; } 103 | void enabled(bool isenabled); 104 | bool visible(); 105 | void visible(bool isvisible); 106 | bool pressed() { return (settingsFlags >> PRESSED) & 1; } 107 | void pressed(bool ispressed); 108 | bool transparent() { return (settingsFlags >> TRANSPARENT) & 1; } 109 | void transparent(bool istransparent); 110 | 111 | GuiList children; 112 | virtual void addChild(GuiElement *child); // Add a child node to this node 113 | 114 | // get the absolute position of the control 115 | int16_t absoluteX(); 116 | int16_t absoluteY(); 117 | 118 | // do point bound checking 119 | virtual GuiElement* pointInWidget(int16_t x, int16_t y); // does this point exist in this widget? 120 | 121 | // button and callback 122 | void connectCallback(processEvent_t callback, void *p) { processEventHandle = callback; processEventPointer = p; } // c++ classes (for class to class callbacks) 123 | void connectCallback(processEvent_t callback) { processEventHandle = callback; processEventPointer = NULL; } // c classes (use in a sketch for example 124 | 125 | // allow events from the input device (key/mouse etc) to be triggered in this event handler 126 | void triggerEvent(uint8_t event) { callbackProcess(this, event); }; 127 | 128 | virtual void draw(void); // needs calling after a change. most state changes will deal with this for you 129 | void drawBase(void); // draw the outline 130 | 131 | virtual uint8_t callbackProcess(GuiElement *element, uint8_t event) { callbackProcess(processEventHandle, processEventPointer, element, event); return 0; }; 132 | virtual uint8_t callbackProcess(processEvent_t processEventHandle, void* processEventPointer, GuiElement *element, uint8_t event) { return 0; }; 133 | 134 | GuiElement* parent = NULL; // the element this is attached to 135 | uint16_t backgroundColourFromParent(void); // used to get the background colour the widget is sat on 136 | 137 | int16_t value() { return dataValue; } // elements can hold an arbitary data tag 138 | void value(int16_t newvalue) { dataValue = newvalue; } 139 | 140 | private: 141 | 142 | int16_t dataValue = 0; // an arbitary value reference 143 | // button press callback related 144 | processEvent_t processEventHandle = NULL; 145 | void* processEventPointer = NULL; 146 | 147 | uint8_t settingsFlags = (1 << VISIBLE) | (1 << ENABLED) | (1 << TRANSPARENT); 148 | }; 149 | 150 | /////////////////// 151 | 152 | #define TEXT_H_ALIGN_LEFT 0 153 | #define TEXT_H_ALIGN_CENTRE 1 154 | #define TEXT_H_ALIGN_RIGHT 2 155 | 156 | class GuiLabel : public GuiElement { 157 | public: 158 | GuiLabel(void) : GuiElement(0, 0, 0, 0) { labelText = ""; }; 159 | GuiLabel(int16_t x, int16_t y, int16_t width, int16_t height, char const* text): GuiElement(x, y, width, height) { labelText = text; }; 160 | 161 | uint8_t textAlignH = TEXT_H_ALIGN_LEFT; 162 | char const* text() { return labelText; } 163 | void text(char const* text) { labelText = text; draw(); } 164 | 165 | void fontSize(uint8_t size) { labelFontSize = size; } 166 | uint8_t fontSize() { return labelFontSize; } 167 | void draw(); 168 | void draw(bool andBase); 169 | uint8_t extraXOffset = 0; 170 | private: 171 | char const* labelText = NULL; 172 | uint8_t labelFontSize = 2; 173 | }; 174 | 175 | ////////////////// 176 | 177 | class GuiElementList : public GuiElement { 178 | public: 179 | GuiElementList(void) : GuiElement(0, 0, 0, 0) {}; 180 | GuiElementList(int16_t x, int16_t y, int16_t width, int16_t height) : GuiElement(x, y, width, height) {}; 181 | 182 | void addChild(GuiElement* child); 183 | GuiElement* pointInWidget(int16_t x, int16_t y); 184 | 185 | uint8_t callbackProcess(processEvent_t processEventHandle, void* processEventPointer, GuiElement *element, uint8_t event); 186 | GuiElement* selectedElement = NULL; 187 | 188 | void selectElement(GuiElement* element, bool skipredraw); 189 | private: 190 | uint16_t totalHeight = 0; 191 | }; 192 | 193 | 194 | ////////////////// 195 | 196 | class GuiButton : public GuiLabel { 197 | public: 198 | GuiButton(void) : GuiLabel(0, 0, 0, 0, "") { borderWidth = 1; textAlignH = TEXT_H_ALIGN_CENTRE; transparent(false); }; 199 | GuiButton(int16_t x, int16_t y, int16_t width, int16_t height, char const* text) : GuiLabel(x, y, width, height, text) { borderWidth = 1; textAlignH = TEXT_H_ALIGN_CENTRE; transparent(false); }; 200 | 201 | void draw(void); 202 | 203 | void image(char const* imageFileNameBmp) { imageFileName = imageFileNameBmp; } 204 | char const* image(void) { return imageFileName; } 205 | uint8_t imageAlignH = TEXT_H_ALIGN_LEFT; 206 | uint16_t imageSize = 32; 207 | 208 | uint8_t callbackProcess(processEvent_t processEventHandle, void* processEventPointer, GuiElement *element, uint8_t event); 209 | private: 210 | char const* imageFileName = NULL; 211 | }; 212 | 213 | ////////////// 214 | 215 | class GuiCheckBox : public GuiLabel { 216 | public: 217 | GuiCheckBox(void) : GuiLabel(0, 0, 0, 0, "") { borderWidth = 0; textAlignH = TEXT_H_ALIGN_LEFT; transparent(true); }; 218 | GuiCheckBox(int16_t x, int16_t y, int16_t width, int16_t height, char const* text) : GuiLabel(x, y, width, height, text) { borderWidth = 0; textAlignH = TEXT_H_ALIGN_LEFT; transparent(true); }; 219 | 220 | void draw(void); 221 | 222 | uint8_t callbackProcess(processEvent_t processEventHandle, void* processEventPointer, GuiElement *element, uint8_t event); 223 | private: 224 | 225 | }; 226 | 227 | 228 | ////////////////// 229 | 230 | extern Adafruit_GFX* _tft; 231 | extern uint8_t _TFT_CS; 232 | 233 | #if USING_SD 234 | extern SdFat* _sd; 235 | #endif 236 | 237 | class Gui : public GuiElement { 238 | public: 239 | Gui(void); 240 | Gui(Adafruit_GFX* thetft, TouchScreen* thets, int16_t x, int16_t y, int16_t width, int16_t height) 241 | : GuiElement(x, y, width, height) { _tft = thetft; ts = thets; borderWidth = 0; margin = 0; backgroundColour = DEFAULT_COLOUR_BG; transparent(false); }; // usually the size of you tft. i.e. (0,0,320,240) 242 | void setRotation(int16_t degrees); 243 | 244 | void update(void); 245 | 246 | void draw(void); 247 | TouchScreen* ts; 248 | 249 | private: 250 | void sendEventToWidget(int16_t x, int16_t y, int8_t eventid); 251 | int16_t rotation = 0; 252 | }; 253 | 254 | //////////////////// 255 | 256 | class GuiListBox : public GuiElementList { 257 | public: 258 | GuiListBox(void); 259 | GuiListBox(int16_t x, int16_t y, int16_t width, int16_t height) : GuiElementList(x, y, width, height) {}; 260 | 261 | void addListElement(char const* text, uint16_t value); 262 | 263 | private: 264 | uint16_t totalHeight = 0; 265 | }; 266 | 267 | //////////////////// 268 | class GuiRadioList : public GuiElementList { 269 | public: 270 | GuiRadioList(void); 271 | GuiRadioList(int16_t x, int16_t y, int16_t width, int16_t height) : GuiElementList(x, y, width, height) {}; 272 | void addListElement(char const* text, uint16_t value); 273 | 274 | private: 275 | uint16_t totalHeight = 0; 276 | }; 277 | 278 | //////////////////// 279 | class GuiPanel : public GuiElement { 280 | public: 281 | GuiPanel(void); 282 | GuiPanel(int16_t x, int16_t y, int16_t width, int16_t height) : GuiElement(x, y, width, height) {}; 283 | void draw(void); 284 | }; 285 | 286 | //////////////////// 287 | 288 | class GuiMultiLineTextBox : public GuiElementList { 289 | public: 290 | GuiMultiLineTextBox(void); 291 | GuiMultiLineTextBox(int16_t x, int16_t y, int16_t width, int16_t height) : GuiElementList(x, y, width, height) { backgroundColour = COLOR_WHITE; transparent(false); }; 292 | 293 | void addChild(GuiElement *child); 294 | void addLine(char const* text); 295 | void clear(); 296 | 297 | private: 298 | uint16_t totalHeight = 0; 299 | }; 300 | 301 | //////////////////// 302 | class GuiGrid : public GuiElement { 303 | public: 304 | GuiGrid(void); 305 | GuiGrid(int16_t x, int16_t y, int16_t width, int16_t height, uint8_t columns, uint8_t rows); 306 | void draw(void); 307 | void addElement(GuiElement *element, uint8_t col, uint8_t row, uint8_t rowspan, uint8_t colspan); 308 | private: 309 | uint8_t columnCount = 0; 310 | uint8_t rowCount = 0; 311 | }; 312 | 313 | //////////////////// 314 | class GuiUtils { 315 | public: 316 | static GuiElement* pointInWidget(GuiElement* element, int16_t x, int16_t y); 317 | static void drawText(GuiElement* element, char const* text, uint16_t colour, int16_t x, int16_t y, uint8_t fontSize); 318 | 319 | static uint16_t getColour(uint8_t red, uint8_t green, uint8_t blue); 320 | 321 | // find centre lines in an eleemnt 322 | static uint16_t getElementCentreX(GuiElement* element); 323 | static uint16_t getElementCentreY(GuiElement* element); 324 | 325 | #if USING_SD 326 | // SD Card and bitmap 327 | static void bmpDraw(char const* filename, uint16_t x, uint16_t y); 328 | static uint16_t read16(SdFile &f); 329 | static uint32_t read32(SdFile &f); 330 | #endif 331 | }; 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | #endif 342 | 343 | -------------------------------------------------------------------------------- /GuiListBox.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | void GuiListBox::addListElement(char const* text, uint16_t value) { 18 | GuiLabel *label = new GuiLabel(0, 0, width - padding, 30, text); 19 | label->value(value); 20 | 21 | addChild(label); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /GuiMultiLineTextBox.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | void GuiMultiLineTextBox::addChild(GuiElement *child) { 18 | // remap the x and y of the child 19 | child->y = totalHeight + child->margin; 20 | totalHeight = child->y + child->height + child->margin; 21 | height = totalHeight; 22 | GuiElement::addChild(child); 23 | }; 24 | 25 | void GuiMultiLineTextBox::addLine(char const* text) { 26 | GuiLabel *label = new GuiLabel(0, 0, width - padding, 10, text); 27 | label->fontSize(1); 28 | addChild(label); 29 | draw(); 30 | } 31 | 32 | void GuiMultiLineTextBox::clear(void) { 33 | // delete all child nodes 34 | //TODO 35 | } 36 | -------------------------------------------------------------------------------- /GuiPanel.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | void GuiPanel::draw(void) { 18 | if (!visible()) return; 19 | 20 | // draw the borders background, all that stuff 21 | GuiElement::drawBase(); 22 | 23 | // draw all of the children now 24 | GuiElement::draw(); 25 | } 26 | 27 | 28 | ////////////////////////// 29 | -------------------------------------------------------------------------------- /GuiRadioList.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | //an external global reference to the tft. 18 | extern Adafruit_GFX* _tft; 19 | 20 | class GuiRadioButton : public GuiCheckBox { 21 | public: 22 | GuiRadioButton(int16_t x, int16_t y, int16_t width, int16_t height, char const* text) : GuiCheckBox(x, y, width, height, text) {}; 23 | void draw(void) { 24 | if (!visible()) return; 25 | Serial.println(absoluteX()); 26 | int16_t newx = absoluteX() + padding; 27 | int16_t midy = GuiUtils::getElementCentreY(this); 28 | int8_t boxSize = fontSize() * 7; 29 | 30 | // we are going to recalc the width here too. not ideal but the width isn't know when an element is added 31 | if (parent == NULL) { 32 | width = 30; 33 | } 34 | else { 35 | width = parent->width - (2*margin) - (2*parent->padding); 36 | } 37 | 38 | GuiElement::drawBase(); 39 | 40 | _tft->drawCircle(newx + (boxSize / 2), midy, boxSize/2, COLOR_WHITE); 41 | if (pressed()) 42 | Serial.println("pressed"); 43 | 44 | // erase or fill the bg 45 | if (pressed()) { 46 | // tick it 47 | _tft->fillCircle(newx + (boxSize / 2), midy, (boxSize/2) - 3, COLOR_WHITE); 48 | } 49 | extraXOffset = 3 + fontSize() * 7; 50 | 51 | // draw all of the children now 52 | GuiLabel::draw(false); 53 | } 54 | }; 55 | 56 | void GuiRadioList::addListElement(char const* text, uint16_t value) { 57 | Serial.print("w ");Serial.println(width); 58 | GuiRadioButton *label = new GuiRadioButton(0, 0, 30, 30, text); 59 | label->value(value); 60 | if (children.count == 0) { 61 | label->pressed(true); 62 | } 63 | addChild(label); 64 | } 65 | -------------------------------------------------------------------------------- /GuiUtils.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "GuiLibrary.h" 16 | 17 | #if USING_SD 18 | #include 19 | #endif 20 | 21 | GuiElement* GuiUtils::pointInWidget(GuiElement* element, int16_t x, int16_t y) { 22 | // do collision detection 23 | GuiNode *tmphead = element->children.head(); 24 | 25 | if (tmphead != NULL) { 26 | while (tmphead != NULL) { 27 | GuiElement* element = (GuiElement*)tmphead->element(); 28 | GuiElement *found = element->pointInWidget(x, y); 29 | // see if the point element returned is valid 30 | // if it is then we know the element returned the top level, but nt a child descendant 31 | if (found != NULL) { 32 | return found; 33 | } 34 | 35 | if (tmphead->next() == NULL) 36 | break; 37 | 38 | tmphead = tmphead->next(); 39 | } 40 | } 41 | 42 | return NULL; 43 | } 44 | 45 | void GuiUtils::drawText(GuiElement* element, char const* text, uint16_t colour, int16_t x, int16_t y, uint8_t fontSize) { 46 | if (element->enabled()) 47 | _tft->setTextColor(colour); 48 | else 49 | _tft->setTextColor(COLOR_DARKGREY); 50 | 51 | _tft->setCursor(x, y); 52 | _tft->setTextSize(fontSize); 53 | _tft->println(text); 54 | } 55 | 56 | // convert from RGB to RGR565 that the GFX lib uses 57 | uint16_t GuiUtils::getColour(uint8_t red, uint8_t green, uint8_t blue) { 58 | return ((red / 8) << 11) | ((green / 4) << 5) | (blue / 8); 59 | } 60 | 61 | uint16_t GuiUtils::getElementCentreX(GuiElement* element) { 62 | return element->absoluteX() - element->margin + (element->width / 2); 63 | } 64 | 65 | uint16_t GuiUtils::getElementCentreY(GuiElement* element) { 66 | return element->absoluteY() - element->margin + (element->height / 2); 67 | } 68 | 69 | 70 | #if USING_SD 71 | // This function opens a Windows Bitmap (BMP) file and 72 | // displays it at the given coordinates. It's sped up 73 | // by reading many pixels worth of data at a time 74 | // (rather than pixel by pixel). Increasing the buffer 75 | // size takes more of the Arduino's precious RAM but 76 | // makes loading a little faster. 20 pixels seems a 77 | // good balance. 78 | 79 | #define BUFFPIXEL 20 80 | 81 | void GuiUtils::bmpDraw(char const* filename, uint16_t x, uint16_t y) { 82 | SdFile bmpFile; 83 | int bmpWidth, bmpHeight; // W+H in pixels 84 | uint8_t bmpDepth; // Bit depth (currently must be 24) 85 | uint32_t bmpImageoffset; // Start of image data in file 86 | uint32_t rowSize; // Not always = bmpWidth; may have padding 87 | uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) 88 | uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer 89 | boolean goodBmp = false; // Set to true on valid header parse 90 | boolean flip = true; // BMP is stored bottom-to-top 91 | int w, h, row, col; 92 | uint8_t r, g, b; 93 | uint32_t pos = 0, startTime = millis(); 94 | 95 | if((x >= _tft->width()) || (y >= _tft->height())) return; 96 | 97 | // Open requested file on SD card 98 | if (!bmpFile.open(filename, O_READ)) { 99 | Serial.print(F("File not found")); 100 | return; 101 | } 102 | 103 | // Parse BMP header 104 | if(read16(bmpFile) == 0x4D42) { // BMP signature 105 | Serial.print(F("File size: ")); Serial.println(read32(bmpFile)); 106 | (void)read32(bmpFile); // Read & ignore creator bytes 107 | bmpImageoffset = read32(bmpFile); // Start of image data 108 | // Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC); 109 | // Read DIB header 110 | Serial.print(F("Header size: ")); Serial.println(read32(bmpFile)); 111 | bmpWidth = read32(bmpFile); 112 | bmpHeight = read32(bmpFile); 113 | if(read16(bmpFile) == 1) { // # planes -- must be '1' 114 | bmpDepth = read16(bmpFile); // bits per pixel 115 | // Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth); 116 | if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed 117 | 118 | goodBmp = true; // Supported BMP format -- proceed! 119 | // Serial.print(F("Image size: ")); 120 | // Serial.print(bmpWidth); 121 | // Serial.print('x'); 122 | // Serial.println(bmpHeight); 123 | 124 | // BMP rows are padded (if needed) to 4-byte boundary 125 | rowSize = (bmpWidth * 3 + 3) & ~3; 126 | 127 | // If bmpHeight is negative, image is in top-down order. 128 | // This is not canon but has been observed in the wild. 129 | if(bmpHeight < 0) { 130 | bmpHeight = -bmpHeight; 131 | flip = false; 132 | } 133 | 134 | // Crop area to be loaded 135 | w = bmpWidth; 136 | h = bmpHeight; 137 | if((x+w-1) >= _tft->width()) w = _tft->width() - x; 138 | if((y+h-1) >= _tft->height()) h = _tft->height() - y; 139 | 140 | // Set TFT address window to clipped image bounds 141 | _tft->setAddrWindow(x, y, x+w-1, y+h-1); 142 | 143 | for (row=0; row= sizeof(sdbuffer)) { // Indeed 163 | bmpFile.read(sdbuffer, sizeof(sdbuffer)); 164 | buffidx = 0; // Set index to beginning 165 | } 166 | 167 | // Convert pixel from BMP to TFT format, push to display 168 | b = sdbuffer[buffidx++]; 169 | g = sdbuffer[buffidx++]; 170 | r = sdbuffer[buffidx++]; 171 | _tft->pushColor(_tft->color565(r,g,b)); 172 | } // end pixel 173 | } // end scanline 174 | Serial.print(F("Loaded in ")); 175 | Serial.print(millis() - startTime); 176 | Serial.println(" ms"); 177 | } // end goodBmp 178 | } 179 | } 180 | 181 | bmpFile.close(); 182 | if(!goodBmp) Serial.println(F("BMP format not recognized.")); 183 | } 184 | 185 | // These read 16- and 32-bit types from the SD card file. 186 | // BMP data is stored little-endian, Arduino is little-endian too. 187 | // May need to reverse subscript order if porting elsewhere. 188 | 189 | uint16_t GuiUtils::read16(SdFile &f) { 190 | uint16_t result; 191 | ((uint8_t *)&result)[0] = f.read(); // LSB 192 | ((uint8_t *)&result)[1] = f.read(); // MSB 193 | return result; 194 | } 195 | 196 | uint32_t GuiUtils::read32(SdFile &f) { 197 | uint32_t result; 198 | ((uint8_t *)&result)[0] = f.read(); // LSB 199 | ((uint8_t *)&result)[1] = f.read(); 200 | ((uint8_t *)&result)[2] = f.read(); 201 | ((uint8_t *)&result)[3] = f.read(); // MSB 202 | return result; 203 | } 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Barry Carter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /LinkedList.cpp: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #include "LinkedList.h" 16 | 17 | void GuiList::addElement(char *element) { 18 | GuiNode *newNode = new GuiNode(); 19 | newNode->setElement(element); 20 | newNode->setNext(NULL); 21 | 22 | GuiNode *tmphead = head_element; 23 | 24 | // if head is not empty, find the last and append 25 | if (tmphead != NULL) { 26 | // get the last element 27 | while (tmphead->next() != NULL) { 28 | tmphead = tmphead->next(); 29 | } 30 | 31 | tmphead->setNext(newNode); // we got the last element. now point the last element at our new element 32 | } 33 | else { 34 | // the new node is now the head of the list 35 | head_element = newNode; 36 | } 37 | 38 | count++; 39 | } 40 | 41 | char* GuiList::getNthElement(uint8_t index) { 42 | GuiNode *tmphead = head_element; 43 | uint8_t count = 0; 44 | 45 | if (tmphead != NULL) { 46 | while (tmphead != NULL) { 47 | if (count == index) 48 | return tmphead->element(); 49 | 50 | if (tmphead->next() == NULL) 51 | break; 52 | 53 | tmphead = tmphead->next(); 54 | count++; 55 | } 56 | } 57 | 58 | return NULL; 59 | } -------------------------------------------------------------------------------- /LinkedList.h: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | */ 14 | 15 | #ifndef _LINKEDLIST_H_ 16 | #define _LINKEDLIST_H_ 17 | 18 | #if ARDUINO < 100 19 | #include 20 | #else 21 | #include 22 | #endif 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | // Node class 31 | class GuiNode { 32 | char *data_element; 33 | GuiNode *next_element; 34 | 35 | public: 36 | GuiNode() {}; 37 | void setElement(char *element) { data_element = element; }; 38 | void setNext(GuiNode* aNext) { next_element = aNext; }; 39 | char *element() { return data_element; }; 40 | GuiNode *next() { return next_element; }; 41 | }; 42 | 43 | ////////////////// 44 | class GuiList { 45 | GuiNode *head_element; 46 | public: 47 | GuiList() { head_element = NULL; } 48 | GuiNode *head() { return head_element; }; 49 | void addElement(char *element); 50 | char* getNthElement(uint8_t index); 51 | int8_t count = 0; 52 | }; 53 | 54 | 55 | #endif -------------------------------------------------------------------------------- /MetroCharmsTileColors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ginge/GuiLibrary/f9b90686ba910c6fa63f3b7826a0b75264948586/MetroCharmsTileColors.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | 14 | What 15 | ---- 16 | 17 | This is a library that allows you to draw simple widgets onto the screen in the 18 | simplest possible way. 19 | There are simple yet powerful grid and list layout options to let you get 20 | working straight away. Multiple screens of information are available by 21 | placing widgets on panels, and making the page you want to see visible, and the 22 | rest invisible. 23 | Callback functions can be used to trigger page changes, code execution or 24 | anything you want to do in your sketch. 25 | 26 | 27 | Requires: 28 | * Adafruit TFT and Adafruid GFX library 29 | * Touch input library 30 | * SdFat (for optional image support) 31 | 32 | 33 | Supported widgets 34 | * Label 35 | * Panel 36 | * Button 37 | * Radio Group 38 | * Checkbox 39 | * ListBox 40 | * Multi Line Text Box 41 | * Image Box 42 | 43 | 44 | Supported layout widgets 45 | * Grid view (with rowspan and colspan) 46 | * List views that auto place the elements 47 | * Just place the widget where you want using x and y 48 | 49 | 50 | supported features 51 | * Widget margins and padding 52 | * Text size and alignment (only one shitty font) 53 | * Element borders 54 | * Element background colours and font colours 55 | * Icons for buttons 56 | * Press/unpress states (where supported) 57 | * Callback functions for element actions (press, release etc) 58 | * Colours (background, border etc) are specified in normal good ol' RGB 59 | * Easily create your own widget elements 60 | 61 | 62 | Bad things 63 | * While every effort has been made to keep this lightweight, it just isn't. 64 | The library may not fit on an Arduino, tests required. 65 | * Sometimes the elements on the scren overdraw. There is 0 dame detection 66 | and redraws in the library are crafted to keep redrawing while elements low 67 | * The drawing engine is pretty dumb. If the text is bigger than your element, 68 | it will overflow. You will have to work that one out yourself for now. 69 | * There is no other input except for touchscreen. You can't move around your 70 | widgets with a joystick, say. 71 | * It isn't going to win any screen redraw speed awards 72 | * No scrollbars I guess thats up to you for a little while. 73 | 74 | 75 | TODO: 76 | * The header is a bit monolithic. It screams for a refactor 77 | * Those linked lists could probably be thinned down 78 | * you can't delete an element. Sorry! 79 | * Scrollbars 80 | * more fonts? 81 | * Now we have primitives, some shiny widgets. 82 | * Progress bar 83 | * Dials 84 | * Etc 85 | 86 | 87 | Example: 88 | There are lots of examples int he examples folder. 89 | 90 | Here is the minimum you need to get going 91 | 92 | #include "GuiLibrary.h" 93 | ... 94 | // Set our main window. 95 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 96 | 97 | void setup() { 98 | GuiLabel *label = new GuiLabel(0, 0, 50, 30, "Hello World!"); 99 | gui.addChild(label); 100 | gui.draw(); // set first draw going 101 | } 102 | 103 | 104 | 105 | Custom Widget: 106 | You can create your own widgets really easily by taking on the attributes of another element and overriding it. This is called subclassing. 107 | 108 | Example, lets create a new label that draws a line through the centre. 109 | 110 | // create a new label of type GuiLabel and override the draw 111 | class GuiLabelLine : public GuiLabel { 112 | public: 113 | GuiLabelLine(int16_t x, int16_t y, int16_t width, int16_t height, char const* text) : GuiLabel(x, y, width, height, text) { }; 114 | 115 | // This is the only function we need! 116 | void draw(void); 117 | }; 118 | 119 | void GuiLabelLine::draw() { 120 | if (!visible()) return; 121 | 122 | // we want to draw the outlines and whatnot 123 | GuiElement::drawBase(); 124 | 125 | GuiUtils::drawLine(absoluteX(), GuiUtils::getElementCentreY(), absoluteX() + width, GuiUtils::getElementCentreY(), GuiUtils::getColour(255, 0, 0)); 126 | 127 | // draw the normal label 128 | GuiLabel::draw(false); 129 | } 130 | 131 | ////////////////////////// 132 | 133 | 134 | -------------------------------------------------------------------------------- /examples/GuiCheckRadio/GuiCheckRadio.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | A few labels with different text alignment along with a group of radio 3 | buttons and also checkbox 4 | 5 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 6 | correctly. 7 | 8 | Uses Adafruit TFT library for the example: 9 | Written by Limor Fried/Ladyada for Adafruit Industries. 10 | MIT license, all text above must be included in any redistribution 11 | ****************************************************/ 12 | 13 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 14 | 15 | #include // Core graphics library 16 | #include 17 | #include 18 | #include "TouchScreen.h" 19 | #include "GuiLibrary.h" 20 | #include "SdFat.h" 21 | 22 | // These are the four touchscreen analog pins 23 | #define YP A0 // must be an analog pin, use "An" notation! 24 | #define XM A1 // must be an analog pin, use "An" notation! 25 | #define YM 6 // can be a digital pin 26 | #define XP 5 // can be a digital pin 27 | 28 | 29 | // This is calibration data for the raw touch data to the screen coordinates 30 | #define TS_MINX 150 31 | #define TS_MINY 120 32 | #define TS_MAXX 920 33 | #define TS_MAXY 940 34 | 35 | 36 | // The display uses hardware SPI, plus #9 & #10 37 | #define TFT_CS 4 38 | #define TFT_DC 5 39 | 40 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 41 | 42 | // For better pressure precision, we need to know the resistance 43 | // between X+ and X- Use any multimeter to read it 44 | // For the one we're using, its 300 ohms across the X plate 45 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 46 | 47 | // Setup the gui model 48 | // needs reference to the tft and the touchscreen 49 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 50 | 51 | // we need these so we can show and hide them 52 | GuiGrid* panelSettings; 53 | 54 | // This will be called when the button is pressed or released 55 | uint8_t callbackFunction_radio(void *a, GuiElement *element, uint8_t event) { 56 | if (event == GUI_EVENT_RELEASE) { 57 | Serial.print("Radio "); Serial.print(element->value()); Serial.println("Selected"); 58 | } 59 | return 0; 60 | } 61 | 62 | // This will be called when the button is pressed or released 63 | uint8_t callbackFunction_checkbox(void *a, GuiElement *element, uint8_t event) { 64 | if (event == GUI_EVENT_RELEASE) { 65 | if (element->pressed()) 66 | Serial.println("Checkbox checked"); 67 | else 68 | Serial.println("Checkbox un-checked"); 69 | } 70 | return 0; 71 | } 72 | 73 | void buildPanelSettings() { 74 | // build a new panel and make it the same size as the screen 75 | // this panel will be hidden 76 | // Create a new grid, smaller than the last one. 2x2 77 | panelSettings = new GuiGrid(0, 0, 320, 240, 4, 4); 78 | panelSettings->padding = 0; 79 | panelSettings->margin = 0; 80 | 81 | // Some labs with different alignment 82 | GuiLabel *label = new GuiLabel(0, 0, 0, 0, "Label Default"); 83 | GuiLabel *label1 = new GuiLabel(0, 0, 0, 0, "Centered"); 84 | label1->textAlignH = TEXT_H_ALIGN_CENTRE; 85 | GuiLabel *label2 = new GuiLabel(0, 0, 0, 0, "Label Right"); 86 | label2->textAlignH = TEXT_H_ALIGN_RIGHT; 87 | 88 | // our checkbox 89 | GuiCheckBox* checkBox = new GuiCheckBox(0,0,0,0, "Check Me!"); 90 | checkBox->connectCallback(callbackFunction_checkbox); 91 | 92 | // Create a radio list and add 2 element 93 | GuiRadioList* radioList = new GuiRadioList(0,0,0,0); // the grid will sort the sizes out 94 | radioList->addListElement("Check 1", 1); 95 | radioList->addListElement("Check 2", 2); 96 | radioList->connectCallback(callbackFunction_radio); 97 | 98 | // add to grid 99 | panelSettings->addElement(label, 0, 0, 2, 1); 100 | panelSettings->addElement(label1, 0, 1, 2, 1); 101 | panelSettings->addElement(label2, 0, 2, 2, 1); 102 | panelSettings->addElement(radioList, 2, 0, 2, 4); 103 | 104 | panelSettings->addElement(checkBox, 2, 3, 2, 1); 105 | 106 | // finally add the widget to the page 107 | gui.addChild(panelSettings); 108 | } 109 | 110 | void setup(void) { 111 | // while (!Serial); // used for leonardo debugging 112 | 113 | Serial.begin(115200); 114 | delay(1000); 115 | Serial.println(F("Gui Widgets test!")); 116 | 117 | // TFT is a go 118 | tft.begin(); 119 | 120 | // in multiples of 90 only (duh) 121 | gui.setRotation(270); 122 | 123 | buildPanelSettings(); 124 | 125 | gui.draw(); 126 | 127 | return; 128 | } 129 | 130 | 131 | void loop() 132 | { 133 | // this has to be called to keep the system up to date and catch touch input 134 | gui.update(); 135 | 136 | return; 137 | } 138 | 139 | -------------------------------------------------------------------------------- /examples/GuiListBox/GuiListBox.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Example showing a list box and a selected item panel 3 | 4 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 5 | correctly. 6 | 7 | Uses Adafruit TFT library for the example: 8 | Written by Limor Fried/Ladyada for Adafruit Industries. 9 | MIT license, all text above must be included in any redistribution 10 | ****************************************************/ 11 | 12 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 13 | 14 | #include // Core graphics library 15 | #include 16 | #include 17 | #include "TouchScreen.h" 18 | #include "GuiLibrary.h" 19 | #include "SdFat.h" 20 | 21 | // These are the four touchscreen analog pins 22 | #define YP A0 // must be an analog pin, use "An" notation! 23 | #define XM A1 // must be an analog pin, use "An" notation! 24 | #define YM 6 // can be a digital pin 25 | #define XP 5 // can be a digital pin 26 | 27 | // This is calibration data for the raw touch data to the screen coordinates 28 | #define TS_MINX 150 29 | #define TS_MINY 120 30 | #define TS_MAXX 920 31 | #define TS_MAXY 940 32 | 33 | 34 | // The display uses hardware SPI, plus #9 & #10 35 | #define TFT_CS 4 36 | #define TFT_DC 5 37 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 38 | 39 | // For better pressure precision, we need to know the resistance 40 | // between X+ and X- Use any multimeter to read it 41 | // For the one we're using, its 300 ohms across the X plate 42 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 43 | 44 | // Setup the gui model 45 | // needs reference to the tft and the touchscreen 46 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 47 | 48 | class DataBlock { 49 | public: 50 | DataBlock(uint8_t theid, char const* fname, char const *lname, uint8_t theage) { id = theid; lastName = lname; firstName = fname; age = theage; }; 51 | uint8_t id = 0; 52 | char const* firstName; 53 | char const* lastName; 54 | uint8_t age; 55 | }; 56 | 57 | DataBlock* dataBlocks[3]; 58 | 59 | GuiLabel* labelNameValue = new GuiLabel(10, 35, 170, 40, "Select"); 60 | GuiLabel* labelAgeValue = new GuiLabel(10, 120, 80, 40, "Select"); 61 | 62 | 63 | // This will be called when the button is pressed or released 64 | uint8_t callbackFunction(void *a, GuiElement *element, uint8_t event) { 65 | Serial.print("Button was "); 66 | if (event == GUI_EVENT_PRESS) { 67 | Serial.println("Pressed"); 68 | } 69 | else if (event == GUI_EVENT_RELEASE) { 70 | Serial.println("Released"); 71 | 72 | Serial.print("The value of the selected element is "); 73 | Serial.println(element->value()); 74 | 75 | DataBlock* block = dataBlocks[element->value() - 1]; 76 | char name[strlen(block->firstName) + strlen(block->lastName) + 2]; 77 | 78 | strcpy(name, block->firstName); 79 | strcat(name, " "); 80 | strcat(name, block->lastName); 81 | labelNameValue->text(name); 82 | 83 | String s = String(block->age); 84 | char arr[4]; 85 | s.toCharArray(arr, 4); 86 | labelAgeValue->text(arr); 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | 93 | void setup(void) { 94 | // while (!Serial); // used for leonardo debugging 95 | 96 | // initialise the fake data for this demo 97 | dataBlocks[0] = new DataBlock(1, "Robert", "Smith", 27); 98 | dataBlocks[1] = new DataBlock(2, "Steve", "Jones", 42); 99 | dataBlocks[2] = new DataBlock(3, "John", "Wheeler", 35); 100 | 101 | 102 | Serial.begin(115200); 103 | delay(1000); 104 | Serial.println(F("Gui Widgets test!")); 105 | 106 | tft.begin(); 107 | // in multiples of 90 only (duh) 108 | gui.setRotation(270); 109 | 110 | // build some widgets 111 | GuiListBox *listbox = new GuiListBox(10, 0, 100, 230); 112 | 113 | for (uint8_t i = 0; i < 3; i++) { 114 | listbox->addListElement(dataBlocks[i]->firstName, dataBlocks[i]->id); 115 | } 116 | 117 | // hook up the callback function defined above to the button so we can track clicks 118 | listbox->connectCallback(callbackFunction); 119 | 120 | 121 | // now lets setup the right hand panel 122 | // we want a few labels to display this stuff. 123 | // first we want a panel 124 | GuiPanel *panel = new GuiPanel(120, 0, 190, 230); 125 | panel->borderWidth = 2; 126 | GuiLabel* labelName = new GuiLabel(10, 0, 65, 40, "Name:"); 127 | GuiLabel* labelAge = new GuiLabel(10, 80, 65, 40, "Age:"); 128 | 129 | panel->addChild(labelName); 130 | panel->addChild(labelNameValue); 131 | panel->addChild(labelAge); 132 | panel->addChild(labelAgeValue); 133 | 134 | // finally add the widgt to the page 135 | gui.addChild(listbox); 136 | gui.addChild(panel); 137 | 138 | gui.draw(); 139 | 140 | return; 141 | } 142 | 143 | 144 | void loop() 145 | { 146 | // this has to be called to keep the system up to date 147 | gui.update(); 148 | 149 | return; 150 | } 151 | 152 | -------------------------------------------------------------------------------- /examples/GuiListElement/GuiListElement.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Example showing a list of elements, some enabled, some disabled some touch enabled 3 | 4 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 5 | correctly. 6 | 7 | Uses Adafruit TFT library for the example: 8 | Written by Limor Fried/Ladyada for Adafruit Industries. 9 | MIT license, all text above must be included in any redistribution 10 | ****************************************************/ 11 | 12 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 13 | 14 | #include // Core graphics library 15 | #include 16 | #include 17 | #include "TouchScreen.h" 18 | #include "GuiLibrary.h" 19 | 20 | // These are the four touchscreen analog pins 21 | #define YP A0 // must be an analog pin, use "An" notation! 22 | #define XM A1 // must be an analog pin, use "An" notation! 23 | #define YM 6 // can be a digital pin 24 | #define XP 5 // can be a digital pin 25 | 26 | // This is calibration data for the raw touch data to the screen coordinates 27 | #define TS_MINX 150 28 | #define TS_MINY 120 29 | #define TS_MAXX 920 30 | #define TS_MAXY 940 31 | 32 | 33 | // The display uses hardware SPI, plus #9 & #10 34 | #define TFT_CS 4 35 | #define TFT_DC 5 36 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 37 | 38 | // For better pressure precision, we need to know the resistance 39 | // between X+ and X- Use any multimeter to read it 40 | // For the one we're using, its 300 ohms across the X plate 41 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 42 | 43 | // Setup the gui model 44 | // needs reference to the tft and the touchscreen 45 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 46 | 47 | // This will be called when the button is pressed or released 48 | uint8_t callbackFunction(void *a, GuiElement *element, uint8_t event) { 49 | Serial.print("Button was "); 50 | if (event == GUI_EVENT_PRESS) { 51 | Serial.println("Pressed"); 52 | ((GuiButton*)element)->text("Pressed"); 53 | } 54 | else if (event == GUI_EVENT_RELEASE) { 55 | Serial.println("Released"); 56 | // the element was actually a button, so we can cast to that type and access the text setter 57 | ((GuiButton*)element)->text("Released"); 58 | 59 | // we are going to make the second label element non-invis manually. we could have kept a reference to the element 60 | // and used it again here to access it directly, but this should illustrate how to walk te elements 61 | // WARNING: ADVANCED 62 | // short version. getnthElement looks at the children and returns index n 63 | // it returns a pointer to char, so you have to convert it back to the relevant widget type 64 | // GuiElement* elementlist = (GuiElement*)(gui.children.getNthElement(0)); 65 | // GuiElement* element = (GuiElement*)(elementlist->children.getNthElement(1)); 66 | // 67 | // broken down 68 | // 69 | // From the top level window, gui, get the first child. 70 | // we set the first child up before to be a list box which has more elements in it 71 | // here is how the element tree looks with the setup below 72 | // gui--- 73 | // |--->GuiListElement (child 0 of gui) 74 | // |---> Label (disabled) (child 0 of GuiListElement) 75 | // |---> Label (invisible) (child 1 of GuiListElement) 76 | // |---> Label (label normal) (child 2 of GuiListElement) 77 | // |---> Button (handled in this function here) (child 3 of GuiListElement) 78 | // 79 | // cool, so now we know how it looks, lets get them elements! 80 | // first get the element list. The function getNthElement returns a pointer. 81 | // If you don't know what a pointer is, don't worry. Thats cool. Just follow the steps below. Monkey see, Monkey do, you'll be just fine. 82 | // Anyone reading this who knows c in depth will shoot me for this, but here goes... 83 | // The pointer is the address where your data is at. If, say, your data is in a warehouse, the pointer is the zip code to the warehouse. 84 | // 85 | // Get the list element. 86 | char* elementlist = gui.children.getNthElement(0); 87 | // great, we got the list element. Now lets get the second element in the list... Remember that invisible label we set up earlier 88 | // hello invisible label, we're coming for you! 89 | // NOTE: see how this time we use the "zip" code to the data element list above. When we do -> in code, it means go and get that data from that warehouse. 90 | char* element = ((GuiElement*)elementlist)->children.getNthElement(1); 91 | // element is now the zip code to the data in the invisible label. nice! But wait, I can't use that char*? 92 | // this is where we use the power of casting. At this point, the computer has no idea what data is in those warehouses, it just knows where that data is. 93 | // So... How do we fix that? 94 | // We tell the computer (specifically the compiler) what the data is! 95 | // we create a GuiLabel* in a variable elementConvertedToALabel and set that to the zip code we got from element 96 | // but see that (GuiLabel *) ? Well that is how we tell the computer that the data in the zip code of element is actually a label. booyah. 97 | // (GuiLabel*)element; 98 | // (Convert the element "TheAwesomeEelement" to the type in these brackets)TheAwesomeEelement; 99 | GuiLabel* elementConvertedToALabel = (GuiLabel*)element; 100 | // now we can make it appear! 101 | elementConvertedToALabel->visible(true); 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | 108 | void setup(void) { 109 | // while (!Serial); // used for leonardo debugging 110 | 111 | Serial.begin(115200); 112 | delay(1000); 113 | Serial.println(F("Gui Widgets test!")); 114 | 115 | tft.begin(); 116 | // in multiples of 90 only (duh) 117 | gui.setRotation(270); 118 | 119 | // build some widgets 120 | // first we want 3 labels 121 | GuiLabel *label = new GuiLabel(10, 0, 110, 40, "Disabled"); 122 | label->borderWidth = 2; 123 | // make sure it is disabled 124 | label->enabled(false); 125 | 126 | GuiLabel *label1 = new GuiLabel(10, 0, 110, 40, "Invis"); 127 | label1->borderWidth = 2; 128 | // this one is invisible. 129 | label1->visible(false); 130 | 131 | GuiLabel *label2 = new GuiLabel(10, 0, 110, 40, "Label"); 132 | label2->borderWidth = 2; 133 | 134 | GuiButton *button = new GuiButton(10, 0, 110, 40, "Button!"); 135 | 136 | GuiButton *button1 = new GuiButton(10, 0, 60, 20, "Small!"); 137 | button1->fontSize(1); 138 | 139 | // hook up the callback function defined above to the button so we can track clicks 140 | button->connectCallback(callbackFunction); 141 | 142 | // create a element list box and add the elements 143 | GuiElementList *l = new GuiElementList(10, 0, 200, 200); 144 | l->addChild(label); 145 | l->addChild(label1); 146 | l->addChild(label2); 147 | l->addChild(button); 148 | l->addChild(button1); 149 | 150 | // finally add the widgt to the page 151 | gui.addChild(l); 152 | 153 | gui.draw(); 154 | 155 | return; 156 | } 157 | 158 | 159 | void loop() 160 | { 161 | // this has to be called to keep the system up to date 162 | gui.update(); 163 | 164 | return; 165 | } 166 | 167 | -------------------------------------------------------------------------------- /examples/GuiMetro/GuiMetro.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Example showing a list of elements, some enabled, some disabled some touch enabled 3 | 4 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 5 | correctly. 6 | 7 | Uses Adafruit TFT library for the example: 8 | Written by Limor Fried/Ladyada for Adafruit Industries. 9 | MIT license, all text above must be included in any redistribution 10 | ****************************************************/ 11 | 12 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 13 | 14 | #include // Core graphics library 15 | #include 16 | #include 17 | #include "TouchScreen.h" 18 | #include "GuiLibrary.h" 19 | 20 | // These are the four touchscreen analog pins 21 | #define YP A0 // must be an analog pin, use "An" notation! 22 | #define XM A1 // must be an analog pin, use "An" notation! 23 | #define YM 6 // can be a digital pin 24 | #define XP 5 // can be a digital pin 25 | 26 | 27 | // This is calibration data for the raw touch data to the screen coordinates 28 | #define TS_MINX 150 29 | #define TS_MINY 120 30 | #define TS_MAXX 920 31 | #define TS_MAXY 940 32 | 33 | 34 | // The display uses hardware SPI, plus #9 & #10 35 | #define TFT_CS 4 36 | #define TFT_DC 5 37 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 38 | 39 | // For better pressure precision, we need to know the resistance 40 | // between X+ and X- Use any multimeter to read it 41 | // For the one we're using, its 300 ohms across the X plate 42 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 43 | 44 | // Setup the gui model 45 | // needs reference to the tft and the touchscreen 46 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 47 | 48 | // some global references to the menu panels 49 | GuiPanel* panelMenu; 50 | GuiPanel* panelSettings; 51 | 52 | #define TILE_HEIGHT 116 53 | #define TILE_WIDTH 156 54 | #define TILE_COLUMN1 160 55 | 56 | // This will be called when the button is pressed or released 57 | uint8_t callbackFunction_home(void *a, GuiElement *element, uint8_t event) { 58 | if (event == GUI_EVENT_RELEASE) { 59 | Serial.println("Pressed Back"); 60 | panelSettings->visible(false); 61 | panelMenu->visible(true); 62 | } 63 | return 0; 64 | } 65 | 66 | // This will be called when the button is pressed or released 67 | uint8_t callbackFunction_settings(void *a, GuiElement *element, uint8_t event) { 68 | if (event == GUI_EVENT_RELEASE) { 69 | Serial.println("Pressed Settings"); 70 | panelMenu->visible(false); 71 | panelSettings->visible(true); 72 | } 73 | return 0; 74 | } 75 | 76 | uint8_t callbackFunction_menu1(void *a, GuiElement *element, uint8_t event) { 77 | if (event == GUI_EVENT_RELEASE) { 78 | Serial.println("Pressed menu 1"); 79 | } 80 | return 0; 81 | } 82 | 83 | void buildPanelMenu() { 84 | // build a 4 tile of elements 85 | panelMenu = new GuiPanel(0, 0, 320, 240); 86 | panelMenu->padding = 0; 87 | panelMenu->margin = 0; 88 | 89 | GuiButton *button = new GuiButton(0, 0, TILE_WIDTH, TILE_HEIGHT, "Settings"); 90 | button->backgroundColour = GuiUtils::getColour(119, 185, 0); // purple 91 | // hook up the callback function defined above to the button so we can track clicks 92 | button->connectCallback(callbackFunction_settings); 93 | button->borderWidth = 0; 94 | 95 | GuiButton *button1 = new GuiButton(TILE_COLUMN1, 0, TILE_WIDTH, TILE_HEIGHT, "Menu 1"); 96 | button1->backgroundColour = GuiUtils::getColour(99, 47, 0); // brown 97 | button1->connectCallback(callbackFunction_menu1); 98 | button1->borderWidth = 0; 99 | 100 | 101 | GuiButton *button2 = new GuiButton(0, TILE_HEIGHT + 4, TILE_WIDTH, TILE_HEIGHT, "Menu 2"); 102 | button2->backgroundColour = GuiUtils::getColour(70,23,180); // blue 103 | // button2->connectCallback(callbackFunction); 104 | button2->borderWidth = 0; 105 | 106 | 107 | GuiButton *button3 = new GuiButton(TILE_COLUMN1, TILE_HEIGHT + 4, (TILE_WIDTH / 2) - 2, (TILE_HEIGHT / 2) - 2, "Exit"); 108 | button3->backgroundColour = GuiUtils::getColour(0, 193, 63); // green 109 | // button3->connectCallback(callbackFunction); 110 | button3->borderWidth = 0; 111 | 112 | GuiButton *button4 = new GuiButton(TILE_COLUMN1 + (TILE_WIDTH / 2) + 2, TILE_HEIGHT + 4, (TILE_WIDTH / 2) - 2, (TILE_HEIGHT / 2) - 2, "Exit"); 113 | button4->backgroundColour = GuiUtils::getColour(0, 193, 63); // green 114 | // button3->connectCallback(callbackFunction); 115 | button4->borderWidth = 0; 116 | 117 | 118 | GuiButton *button5 = new GuiButton(TILE_COLUMN1, TILE_HEIGHT + (TILE_HEIGHT / 2) + 6, (TILE_WIDTH / 2) - 2, (TILE_HEIGHT / 2) - 2, "Exit"); 119 | button5->backgroundColour = GuiUtils::getColour(0, 193, 63); // green 120 | // button3->connectCallback(callbackFunction); 121 | button5->borderWidth = 0; 122 | 123 | GuiButton *button6 = new GuiButton(TILE_COLUMN1 + (TILE_WIDTH / 2) + 2, TILE_HEIGHT + (TILE_HEIGHT / 2) + 6, (TILE_WIDTH / 2) - 2, (TILE_HEIGHT / 2) - 2, "Exit"); 124 | button6->backgroundColour = GuiUtils::getColour(0, 193, 63); // green 125 | // button3->connectCallback(callbackFunction); 126 | button6->borderWidth = 0; 127 | 128 | 129 | panelMenu->addChild(button); 130 | panelMenu->addChild(button1); 131 | panelMenu->addChild(button2); 132 | panelMenu->addChild(button3); 133 | panelMenu->addChild(button4); 134 | panelMenu->addChild(button5); 135 | panelMenu->addChild(button6); 136 | 137 | // finally add the widgt to the page 138 | gui.addChild(panelMenu); 139 | } 140 | 141 | void buildPanelSettings() { 142 | // build a new panel and make it the same size as the screen 143 | // this panel will be hidden 144 | panelSettings = new GuiPanel(0, 0, 320, 240); 145 | panelSettings->padding = 0; 146 | panelSettings->margin = 0; 147 | 148 | GuiLabel *label = new GuiLabel(0, 0, TILE_WIDTH, TILE_HEIGHT, "System Status: Mauve"); 149 | 150 | GuiButton *button1 = new GuiButton(0, TILE_HEIGHT + 4, TILE_WIDTH, TILE_HEIGHT, "<- Home"); 151 | button1->backgroundColour = GuiUtils::getColour(70,23,180); // blue 152 | button1->connectCallback(callbackFunction_home); 153 | button1->borderWidth = 0; 154 | 155 | panelSettings->addChild(label); 156 | panelSettings->addChild(button1); 157 | 158 | panelSettings->visible(false); 159 | 160 | // finally add the widget to the page 161 | gui.addChild(panelSettings); 162 | } 163 | 164 | void setup(void) { 165 | // while (!Serial); // used for leonardo debugging 166 | 167 | Serial.begin(115200); 168 | delay(1000); 169 | Serial.println(F("Gui Widgets test!")); 170 | 171 | tft.begin(); 172 | // in multiples of 90 only (duh) 173 | gui.setRotation(270); 174 | 175 | buildPanelMenu(); 176 | buildPanelSettings(); 177 | 178 | gui.draw(); 179 | 180 | return; 181 | } 182 | 183 | 184 | void loop() 185 | { 186 | // this has to be called to keep the system up to date 187 | gui.update(); 188 | 189 | return; 190 | } 191 | 192 | -------------------------------------------------------------------------------- /examples/GuiMetroGrid/GuiMetroGrid.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Example showing a list of elements, some enabled, some disabled some touch enabled 3 | 4 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 5 | correctly. 6 | 7 | Uses Adafruit TFT library for the example: 8 | Written by Limor Fried/Ladyada for Adafruit Industries. 9 | MIT license, all text above must be included in any redistribution 10 | ****************************************************/ 11 | 12 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 13 | 14 | #include // Core graphics library 15 | #include 16 | #include 17 | #include "TouchScreen.h" 18 | #include "GuiLibrary.h" 19 | 20 | // These are the four touchscreen analog pins 21 | #define YP A0 // must be an analog pin, use "An" notation! 22 | #define XM A1 // must be an analog pin, use "An" notation! 23 | #define YM 6 // can be a digital pin 24 | #define XP 5 // can be a digital pin 25 | 26 | 27 | // This is calibration data for the raw touch data to the screen coordinates 28 | #define TS_MINX 150 29 | #define TS_MINY 120 30 | #define TS_MAXX 920 31 | #define TS_MAXY 940 32 | 33 | 34 | // The display uses hardware SPI, plus #9 & #10 35 | #define TFT_CS 4 36 | #define TFT_DC 5 37 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 38 | 39 | // For better pressure precision, we need to know the resistance 40 | // between X+ and X- Use any multimeter to read it 41 | // For the one we're using, its 300 ohms across the X plate 42 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 43 | 44 | // Setup the gui model 45 | // needs reference to the tft and the touchscreen 46 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 47 | 48 | // some global references to the menu panels 49 | GuiGrid* panelMenu; 50 | GuiGrid* panelSettings; 51 | 52 | // This will be called when the button is pressed or released 53 | uint8_t callbackFunction_home(void *a, GuiElement *element, uint8_t event) { 54 | if (event == GUI_EVENT_RELEASE) { 55 | Serial.println("Pressed Back"); 56 | panelSettings->visible(false); 57 | panelMenu->visible(true); 58 | } 59 | return 1; // tell the gui engine we are going to be moving away and not to redraw 60 | } 61 | 62 | // This will be called when the button is pressed or released 63 | uint8_t callbackFunction_settings(void *a, GuiElement *element, uint8_t event) { 64 | if (event == GUI_EVENT_RELEASE) { 65 | Serial.println("Pressed Settings"); 66 | Serial.print("x "); Serial.print(element->absoluteX()); 67 | Serial.print(" y "); Serial.print(element->absoluteY()); 68 | Serial.print(" p "); Serial.print(element->padding); 69 | Serial.print(" w "); Serial.print(element->width); 70 | Serial.print(" h "); Serial.println(element->height); 71 | panelMenu->visible(false); 72 | panelSettings->visible(true); 73 | } 74 | return 1; // tell the gui engine we are going to be moving away and not to redraw 75 | } 76 | 77 | uint8_t callbackFunction_menu1(void *a, GuiElement *element, uint8_t event) { 78 | if (event == GUI_EVENT_RELEASE) { 79 | Serial.println("Pressed menu 1"); 80 | } 81 | return 0; 82 | } 83 | 84 | void buildPanelMenu() { 85 | // build a 4x4 grid of elements 86 | panelMenu = new GuiGrid(0, 0, 320, 240, 4, 4); 87 | panelMenu->padding = 0; 88 | panelMenu->margin = 0; 89 | 90 | GuiButton *button = new GuiButton(0, 0, 0, 0, "Settings"); 91 | button->backgroundColour = GuiUtils::getColour(119, 185, 0); // purple 92 | // hook up the callback function defined above to the button so we can track clicks 93 | button->connectCallback(callbackFunction_settings); 94 | button->borderWidth = 0; 95 | 96 | GuiButton *button1 = new GuiButton(0, 0, 0, 0, "Menu 1"); 97 | button1->backgroundColour = GuiUtils::getColour(99, 47, 0); // brown 98 | button1->connectCallback(callbackFunction_menu1); 99 | button1->borderWidth = 0; 100 | 101 | 102 | GuiButton *button2 = new GuiButton(0, 0, 0, 0, "Menu 2"); 103 | button2->backgroundColour = GuiUtils::getColour(70,23,180); // blue 104 | // button2->connectCallback(callbackFunction); 105 | button2->borderWidth = 0; 106 | 107 | 108 | GuiButton *button3 = new GuiButton(0, 0, 0, 0, "Small"); 109 | button3->backgroundColour = GuiUtils::getColour(255, 152, 29); 110 | // button3->connectCallback(callbackFunction); 111 | button3->borderWidth = 0; 112 | 113 | GuiButton *button4 = new GuiButton(0, 0, 0, 0, "Tiles"); 114 | button4->backgroundColour = GuiUtils::getColour(255, 118, 188); 115 | // button3->connectCallback(callbackFunction); 116 | button4->borderWidth = 0; 117 | 118 | 119 | GuiButton *button5 = new GuiButton(0, 0, 0, 0, "Rock"); 120 | button5->backgroundColour = GuiUtils::getColour(193, 0, 79); 121 | // button3->connectCallback(callbackFunction); 122 | button5->borderWidth = 0; 123 | 124 | GuiButton *button6 = new GuiButton(0, 0, 0, 0, "Exit"); 125 | button6->backgroundColour = GuiUtils::getColour(86, 197, 255); 126 | // button3->connectCallback(callbackFunction); 127 | button6->borderWidth = 0; 128 | 129 | // add the elements into the grid. Each element it set to the grid by row and column 130 | // element, col, row, column span, row span 131 | panelMenu->addElement(button, 0, 0, 2, 2); 132 | panelMenu->addElement(button1, 2, 0, 2, 2); 133 | panelMenu->addElement(button2, 0, 2, 2, 2); 134 | panelMenu->addElement(button3, 2, 2, 1, 1); 135 | panelMenu->addElement(button4, 3, 2, 1, 1); 136 | panelMenu->addElement(button5, 2, 3, 1, 1); 137 | panelMenu->addElement(button6, 3, 3, 1, 1); 138 | 139 | // finally add the widgt to the page 140 | gui.addChild(panelMenu); 141 | } 142 | 143 | void buildPanelSettings() { 144 | // build a new panel and make it the same size as the screen 145 | // this panel will be hidden 146 | panelSettings = new GuiGrid(0, 0, 320, 240, 2, 2); 147 | panelSettings->padding = 0; 148 | panelSettings->margin = 0; 149 | 150 | GuiLabel *label = new GuiLabel(0, 0, 0, 0, "System Status: Mauve"); 151 | 152 | GuiButton *button1 = new GuiButton(0, 0, 0, 0, "<- Home"); 153 | button1->backgroundColour = GuiUtils::getColour(70,23,180); // blue 154 | button1->connectCallback(callbackFunction_home); 155 | button1->borderWidth = 0; 156 | 157 | panelSettings->addElement(label, 0, 0, 2, 1); 158 | panelSettings->addElement(button1, 0, 1, 1, 1); 159 | 160 | panelSettings->visible(false); 161 | 162 | // finally add the widget to the page 163 | gui.addChild(panelSettings); 164 | } 165 | 166 | void setup(void) { 167 | // while (!Serial); // used for leonardo debugging 168 | 169 | Serial.begin(115200); 170 | delay(1000); 171 | Serial.println(F("Gui Widgets test!")); 172 | 173 | tft.begin(); 174 | // in multiples of 90 only (duh) 175 | gui.setRotation(270); 176 | 177 | buildPanelMenu(); 178 | buildPanelSettings(); 179 | 180 | gui.draw(); 181 | 182 | return; 183 | } 184 | 185 | 186 | void loop() 187 | { 188 | // this has to be called to keep the system up to date 189 | gui.update(); 190 | 191 | return; 192 | } 193 | 194 | -------------------------------------------------------------------------------- /examples/GuiMetroGridImages/GuiMetroGridImages.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Example showing a the power of grids and icons to make nice looking modernui tiles 3 | Click on settings for screen 2. 4 | Serial will also print some stuff for your pleasure 5 | Requires SdFat library 6 | 7 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 8 | correctly. 9 | 10 | Uses Adafruit TFT library for the example: 11 | Written by Limor Fried/Ladyada for Adafruit Industries. 12 | MIT license, all text above must be included in any redistribution 13 | ****************************************************/ 14 | 15 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 16 | // Make sure the SD code is enabled for loading images 17 | #define USING_SD 1 18 | 19 | #include // Core graphics library 20 | #include 21 | #include 22 | #include "TouchScreen.h" 23 | #include "GuiLibrary.h" 24 | #if USING_SD 25 | #include 26 | #endif 27 | // These are the four touchscreen analog pins 28 | #define YP A0 // must be an analog pin, use "An" notation! 29 | #define XM A1 // must be an analog pin, use "An" notation! 30 | #define YM 6 // can be a digital pin 31 | #define XP 5 // can be a digital pin 32 | 33 | 34 | // This is calibration data for the raw touch data to the screen coordinates 35 | #define TS_MINX 150 36 | #define TS_MINY 120 37 | #define TS_MAXX 920 38 | #define TS_MAXY 940 39 | 40 | 41 | // The display uses hardware SPI, plus #9 & #10 42 | #define TFT_CS 4 43 | #define TFT_DC 5 44 | #define SD_CS 8 45 | 46 | #if USING_SD 47 | SdFat sd; 48 | #endif 49 | 50 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 51 | 52 | // For better pressure precision, we need to know the resistance 53 | // between X+ and X- Use any multimeter to read it 54 | // For the one we're using, its 300 ohms across the X plate 55 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 56 | 57 | // Setup the gui model 58 | // needs reference to the tft and the touchscreen 59 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 60 | 61 | // some global references to the menu panels 62 | // we need these so we can show and hide them 63 | GuiGrid* panelMenu; 64 | GuiGrid* panelSettings; 65 | 66 | // This will be called when the button is pressed or released 67 | uint8_t callbackFunction_home(void *a, GuiElement *element, uint8_t event) { 68 | if (event == GUI_EVENT_RELEASE) { 69 | Serial.println("Pressed Back"); 70 | panelSettings->visible(false); 71 | panelMenu->visible(true); 72 | } 73 | return 1; // tell the gui engine we are going to be moving away and not to redraw 74 | } 75 | 76 | // This will be called when the button is pressed or released 77 | uint8_t callbackFunction_settings(void *a, GuiElement *element, uint8_t event) { 78 | if (event == GUI_EVENT_RELEASE) { 79 | Serial.println("Pressed Settings"); 80 | panelMenu->visible(false); 81 | panelSettings->visible(true); 82 | } 83 | return 1; // no redraw thank you 84 | } 85 | 86 | uint8_t callbackFunction_menu1(void *a, GuiElement *element, uint8_t event) { 87 | if (event == GUI_EVENT_RELEASE) { 88 | Serial.println("Pressed menu 1"); 89 | } 90 | return 0; 91 | } 92 | 93 | void buildPanelMenu() { 94 | // build a 4x4 grid of elements 95 | panelMenu = new GuiGrid(0, 0, 320, 240, 4, 4); 96 | panelMenu->padding = 0; 97 | panelMenu->margin = 0; 98 | 99 | // A button with an icon for getting to the second screen 100 | GuiButton *button = new GuiButton(0, 0, 0, 0, " Settings"); 101 | button->backgroundColour = GuiUtils::getColour(0, 172, 220); // purple 102 | // hook up the callback function defined above to the button so we can track clicks 103 | button->connectCallback(callbackFunction_settings); 104 | button->borderWidth = 0; 105 | button->image("sc32/configure_alt_3_mirror.bmp"); 106 | 107 | // A Button with a callback to print some text 108 | GuiButton *button1 = new GuiButton(0, 0, 0, 0, "Tiles Made"); 109 | button1->backgroundColour = GuiUtils::getColour(99, 47, 0); 110 | button1->connectCallback(callbackFunction_menu1); 111 | button1->borderWidth = 0; 112 | 113 | // A Button with no callback 114 | GuiButton *button2 = new GuiButton(0, 0, 0, 0, " In Grids"); 115 | button2->backgroundColour = GuiUtils::getColour(232,100,27); 116 | button2->borderWidth = 0; 117 | button2->image("sc32/connect_to_mirror.bmp"); 118 | 119 | // Another button 120 | GuiButton *button3 = new GuiButton(0, 0, 0, 0, "Small"); 121 | button3->backgroundColour = GuiUtils::getColour(255, 152, 29); 122 | button3->borderWidth = 0; 123 | 124 | // A bunch of buttons for the small grid 125 | GuiButton *button4 = new GuiButton(0, 0, 0, 0, ""); 126 | button4->backgroundColour = GuiUtils::getColour(0, 159, 60); 127 | button4->image("sc32/system_restore_mirror.bmp"); 128 | button4->imageAlignH = TEXT_H_ALIGN_CENTRE; 129 | button4->borderWidth = 0; 130 | 131 | GuiButton *button5 = new GuiButton(0, 0, 0, 0, ""); 132 | button5->backgroundColour = GuiUtils::getColour(20, 109, 201); 133 | button5->image("sc32/signal_mirror.bmp"); 134 | button5->imageAlignH = TEXT_H_ALIGN_CENTRE; 135 | button5->borderWidth = 0; 136 | 137 | GuiButton *button6 = new GuiButton(0, 0, 0, 0, ""); 138 | button6->backgroundColour = GuiUtils::getColour(223, 0, 35); 139 | button6->image("sc32/mail_alt_mirror.bmp"); 140 | button6->imageAlignH = TEXT_H_ALIGN_CENTRE; 141 | button6->borderWidth = 0; 142 | 143 | // add the elements into the grid. Each element it set to the grid by row and column 144 | // element, col, row, column span, row span 145 | panelMenu->addElement(button, 0, 0, 2, 2); 146 | panelMenu->addElement(button1, 2, 0, 2, 2); 147 | panelMenu->addElement(button2, 0, 2, 2, 2); 148 | panelMenu->addElement(button3, 2, 2, 1, 1); 149 | panelMenu->addElement(button4, 3, 2, 1, 1); 150 | panelMenu->addElement(button5, 2, 3, 1, 1); 151 | panelMenu->addElement(button6, 3, 3, 1, 1); 152 | 153 | // finally add the widgt to the page 154 | gui.addChild(panelMenu); 155 | } 156 | 157 | void buildPanelSettings() { 158 | // build a new panel and make it the same size as the screen 159 | // this panel will be hidden 160 | // Create a new grid, smaller than the last one. 2x2 161 | panelSettings = new GuiGrid(0, 0, 320, 240, 2, 2); 162 | panelSettings->padding = 0; 163 | panelSettings->margin = 0; 164 | 165 | // put a couple of controls on the demo page 166 | GuiLabel *label = new GuiLabel(0, 0, 0, 0, "System Status: Mauve"); 167 | 168 | // A big icon on the button 169 | GuiButton *button1 = new GuiButton(0, 0, 0, 0, ""); 170 | button1->backgroundColour = GuiUtils::getColour(163,98,10); // blue 171 | button1->connectCallback(callbackFunction_home); 172 | button1->image("sc64/40405_mirror.bmp"); 173 | button1->imageAlignH = TEXT_H_ALIGN_CENTRE; 174 | button1->imageSize = 64; 175 | button1->borderWidth = 0; 176 | 177 | // add to grid 178 | panelSettings->addElement(label, 0, 0, 2, 1); 179 | panelSettings->addElement(button1, 0, 1, 1, 1); 180 | 181 | // make it invisible before it is added to the gui 182 | panelSettings->visible(false); 183 | 184 | // finally add the widget to the page 185 | gui.addChild(panelSettings); 186 | } 187 | 188 | void setup(void) { 189 | // while (!Serial); // used for leonardo debugging 190 | 191 | Serial.begin(115200); 192 | delay(1000); 193 | Serial.println(F("Gui Widgets test!")); 194 | 195 | #if USING_SD 196 | // SD is a go 197 | if (!sd.begin(SD_CS, SPI_HALF_SPEED)) { 198 | Serial.println("Begin failed"); 199 | return; 200 | } 201 | #endif 202 | 203 | // TFT is a go 204 | tft.begin(); 205 | 206 | // in multiples of 90 only (duh) 207 | gui.setRotation(270); 208 | 209 | // create our GUI elements 210 | buildPanelMenu(); 211 | buildPanelSettings(); 212 | 213 | gui.draw(); 214 | 215 | return; 216 | } 217 | 218 | 219 | void loop() 220 | { 221 | // this has to be called to keep the system up to date and catch touch input 222 | gui.update(); 223 | 224 | return; 225 | } 226 | 227 | -------------------------------------------------------------------------------- /examples/GuiTextBox/GuiTextBox.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Example showing a list of elements, some enabled, some disabled some touch enabled 3 | 4 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 5 | correctly. 6 | 7 | Uses Adafruit TFT library for the example: 8 | Written by Limor Fried/Ladyada for Adafruit Industries. 9 | MIT license, all text above must be included in any redistribution 10 | ****************************************************/ 11 | 12 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 13 | 14 | #include // Core graphics library 15 | #include 16 | #include 17 | #include "TouchScreen.h" 18 | #include "GuiLibrary.h" 19 | 20 | // These are the four touchscreen analog pins 21 | #define YP A0 // must be an analog pin, use "An" notation! 22 | #define XM A1 // must be an analog pin, use "An" notation! 23 | #define YM 6 // can be a digital pin 24 | #define XP 5 // can be a digital pin 25 | 26 | // This is calibration data for the raw touch data to the screen coordinates 27 | #define TS_MINX 150 28 | #define TS_MINY 120 29 | #define TS_MAXX 920 30 | #define TS_MAXY 940 31 | 32 | 33 | // The display uses hardware SPI, plus #9 & #10 34 | #define TFT_CS 4 35 | #define TFT_DC 5 36 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 37 | 38 | // For better pressure precision, we need to know the resistance 39 | // between X+ and X- Use any multimeter to read it 40 | // For the one we're using, its 300 ohms across the X plate 41 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 42 | 43 | // Setup the gui model 44 | // needs reference to the tft and the touchscreen 45 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 46 | 47 | GuiMultiLineTextBox* textbox = new GuiMultiLineTextBox(150, 0, 100, 200); 48 | 49 | // This will be called when the button is pressed or released 50 | uint8_t callbackFunction(void *a, GuiElement *element, uint8_t event) { 51 | Serial.print("Button was "); 52 | if (event == GUI_EVENT_PRESS) { 53 | Serial.println("Pressed"); 54 | ((GuiButton*)element)->text("Pressed"); 55 | textbox->addLine("Pressed Button"); 56 | } 57 | else if (event == GUI_EVENT_RELEASE) { 58 | Serial.println("Released"); 59 | // the element was actually a button, so we can cast to that type and access the text setter 60 | ((GuiButton*)element)->text("Released"); 61 | textbox->addLine("Released Button"); 62 | } 63 | 64 | return 0; 65 | } 66 | 67 | 68 | void setup(void) { 69 | // while (!Serial); // used for leonardo debugging 70 | 71 | Serial.begin(115200); 72 | delay(1000); 73 | Serial.println(F("Gui Widgets test!")); 74 | 75 | tft.begin(); 76 | // in multiples of 90 only (duh) 77 | gui.setRotation(270); 78 | 79 | // build some widgets 80 | GuiButton *button = new GuiButton(10, 0, 110, 40, "Button!"); 81 | 82 | // hook up the callback function defined above to the button so we can track clicks 83 | button->connectCallback(callbackFunction); 84 | 85 | // finally add the widgt to the page 86 | gui.addChild(button); 87 | 88 | // now the log output box 89 | 90 | gui.addChild(textbox); 91 | 92 | gui.draw(); 93 | 94 | return; 95 | } 96 | 97 | 98 | void loop() 99 | { 100 | // this has to be called to keep the system up to date 101 | gui.update(); 102 | 103 | return; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /examples/KBMenuMockup/KBMenuMockup.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Example showing a the power of grids and icons to make nice looking modernui tiles 3 | Click on settings for screen 2. 4 | Serial will also print some stuff for your pleasure 5 | Requires SdFat library 6 | 7 | NOTE: screeen rotation is set to 270 degrees. Don't worry, the touchscreen will map 8 | correctly. 9 | 10 | Uses Adafruit TFT library for the example: 11 | Written by Limor Fried/Ladyada for Adafruit Industries. 12 | MIT license, all text above must be included in any redistribution 13 | ****************************************************/ 14 | 15 | /** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ 16 | // Make sure the SD code is enabled for loading images 17 | #define USING_SD 1 18 | 19 | #include // Core graphics library 20 | #include 21 | #include 22 | #include "TouchScreen.h" 23 | #include "GuiLibrary.h" 24 | #include 25 | 26 | // These are the four touchscreen analog pins 27 | #define YP A0 // must be an analog pin, use "An" notation! 28 | #define XM A1 // must be an analog pin, use "An" notation! 29 | #define YM 6 // can be a digital pin 30 | #define XP 5 // can be a digital pin 31 | 32 | 33 | // This is calibration data for the raw touch data to the screen coordinates 34 | #define TS_MINX 150 35 | #define TS_MINY 120 36 | #define TS_MAXX 920 37 | #define TS_MAXY 940 38 | 39 | 40 | // The display uses hardware SPI, plus #9 & #10 41 | #define TFT_CS 4 42 | #define TFT_DC 5 43 | #define SD_CS 8 44 | 45 | SdFat sd; 46 | 47 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); 48 | 49 | // For better pressure precision, we need to know the resistance 50 | // between X+ and X- Use any multimeter to read it 51 | // For the one we're using, its 300 ohms across the X plate 52 | TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 53 | 54 | // Setup the gui model 55 | // needs reference to the tft and the touchscreen 56 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 57 | 58 | // some global references to the menu panels 59 | // we need these so we can show and hide them 60 | GuiGrid* panelMenu; 61 | GuiGrid* panelSettings; 62 | 63 | // list of buttons 64 | GuiButton deviceButtons[5]; 65 | 66 | // pointer to the selected output device 67 | GuiElement* selectedElement = NULL; 68 | 69 | // This will be called when the button is pressed or released 70 | uint8_t callbackFunction_home(void *a, GuiElement *element, uint8_t event) { 71 | if (event == GUI_EVENT_RELEASE) { 72 | Serial.println("Pressed Back"); 73 | panelSettings->visible(false); 74 | panelMenu->visible(true); 75 | } 76 | return 1; // tell the gui engine we are going to be moving away and not to redraw 77 | } 78 | 79 | // This will be called when the button is pressed or released 80 | uint8_t callbackFunction_device(void *a, GuiElement *element, uint8_t event) { 81 | if (event == GUI_EVENT_RELEASE) { 82 | Serial.println("Pressed Device"); 83 | //deselect the old selection 84 | if (selectedElement != NULL) { 85 | selectedElement->backgroundColour = GuiUtils::getColour(20, 109, 201); 86 | selectedElement->draw(); 87 | } 88 | 89 | // select the new selection 90 | element->backgroundColour = GuiUtils::getColour(0, 159, 60); 91 | selectedElement = element; 92 | } 93 | return 0; 94 | } 95 | 96 | uint8_t callbackFunction_next(void *a, GuiElement *element, uint8_t event) { 97 | if (event == GUI_EVENT_RELEASE) { 98 | Serial.println("Pressed Next"); 99 | } 100 | return 1; 101 | } 102 | 103 | void buildPanelMenu() { 104 | // build a 6x3 grid of elements 105 | panelMenu = new GuiGrid(0, 0, 320, 240, 6, 3); 106 | panelMenu->padding = 0; 107 | panelMenu->margin = 0; 108 | 109 | // 6 buttons, 5 kb shortcuts, one for "next" 110 | // GuiButton *button0 = new GuiButton(0, 0, 0, 0, "1"); 111 | // GuiButton *button1 = new GuiButton(0, 0, 0, 0, "2"); 112 | // GuiButton *button2 = new GuiButton(0, 0, 0, 0, "3"); 113 | // GuiButton *button3 = new GuiButton(0, 0, 0, 0, "4"); 114 | // GuiButton *button4 = new GuiButton(0, 0, 0, 0, "5"); 115 | GuiButton *next = new GuiButton(0, 0, 0, 0, "More..."); 116 | 117 | int row = 0; 118 | int col = 0; 119 | 120 | for (int i = 0; i < 5; i++) { 121 | deviceButtons[i].borderWidth = 0; 122 | deviceButtons[i].image("sc32/configure_alt_3_mirror.bmp"); 123 | deviceButtons[i].backgroundColour = GuiUtils::getColour(20, 109, 201); 124 | deviceButtons[i].connectCallback(callbackFunction_device); 125 | 126 | // add to the grid 127 | if (i > 2) 128 | row = 1; 129 | col = 2*(i%3); 130 | panelMenu->addElement(&deviceButtons[i], col, row, 2, 1); 131 | } 132 | 133 | next->borderWidth = 0; 134 | next->image("sc32/configure_alt_3_mirror.bmp"); 135 | next->backgroundColour = GuiUtils::getColour(223, 0, 35); 136 | next->connectCallback(callbackFunction_next); 137 | 138 | // // A bunch of buttons for the small grid 139 | // GuiButton *button4 = new GuiButton(0, 0, 0, 0, ""); 140 | // button4->backgroundColour = GuiUtils::getColour(0, 159, 60); 141 | // button4->image("sc32/system_restore_mirror.bmp"); 142 | // button4->imageAlignH = TEXT_H_ALIGN_CENTRE; 143 | // button4->borderWidth = 0; 144 | // 145 | // GuiButton *button5 = new GuiButton(0, 0, 0, 0, ""); 146 | // button5->backgroundColour = GuiUtils::getColour(20, 109, 201); 147 | // button5->image("sc32/signal_mirror.bmp"); 148 | // button5->imageAlignH = TEXT_H_ALIGN_CENTRE; 149 | // button5->borderWidth = 0; 150 | // 151 | // GuiButton *button6 = new GuiButton(0, 0, 0, 0, ""); 152 | // button6->backgroundColour = GuiUtils::getColour(223, 0, 35); 153 | // button6->image("sc32/mail_alt_mirror.bmp"); 154 | // button6->imageAlignH = TEXT_H_ALIGN_CENTRE; 155 | // button6->borderWidth = 0; 156 | 157 | // add the elements into the grid. Each element it set to the grid by row and column 158 | // element, col, row, column span, row span 159 | panelMenu->addElement(next, 4, 1, 2, 1); 160 | 161 | // finally add the widgt to the page 162 | gui.addChild(panelMenu); 163 | } 164 | 165 | void buildPanelSettings() { 166 | // build a new panel and make it the same size as the screen 167 | // this panel will be hidden 168 | // Create a new grid, smaller than the last one. 2x2 169 | panelSettings = new GuiGrid(0, 0, 320, 240, 2, 2); 170 | panelSettings->padding = 0; 171 | panelSettings->margin = 0; 172 | 173 | // put a couple of controls on the demo page 174 | GuiLabel *label = new GuiLabel(0, 0, 0, 0, "System Status: Mauve"); 175 | 176 | // A big icon on the button 177 | GuiButton *button1 = new GuiButton(0, 0, 0, 0, ""); 178 | button1->backgroundColour = GuiUtils::getColour(163,98,10); // blue 179 | button1->connectCallback(callbackFunction_home); 180 | button1->image("sc64/40405_mirror.bmp"); 181 | button1->imageAlignH = TEXT_H_ALIGN_CENTRE; 182 | button1->imageSize = 64; 183 | button1->borderWidth = 0; 184 | 185 | // add to grid 186 | panelSettings->addElement(label, 0, 0, 2, 1); 187 | panelSettings->addElement(button1, 0, 1, 1, 1); 188 | 189 | // make it invisible before it is added to the gui 190 | panelSettings->visible(false); 191 | 192 | // finally add the widget to the page 193 | gui.addChild(panelSettings); 194 | } 195 | 196 | void setup(void) { 197 | // while (!Serial); // used for leonardo debugging 198 | 199 | Serial.begin(115200); 200 | delay(1000); 201 | Serial.println(F("Gui Widgets test!")); 202 | 203 | // SD is a go 204 | if (!sd.begin(SD_CS, SPI_HALF_SPEED)) { 205 | Serial.println("Begin failed"); 206 | return; 207 | } 208 | 209 | // TFT is a go 210 | tft.begin(); 211 | 212 | // in multiples of 90 only (duh) 213 | gui.setRotation(270); 214 | 215 | // create our GUI elements 216 | buildPanelMenu(); 217 | buildPanelSettings(); 218 | 219 | gui.draw(); 220 | 221 | return; 222 | } 223 | 224 | 225 | void loop() 226 | { 227 | // this has to be called to keep the system up to date and catch touch input 228 | gui.update(); 229 | 230 | return; 231 | } 232 | 233 | -------------------------------------------------------------------------------- /images/checkradioexample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ginge/GuiLibrary/f9b90686ba910c6fa63f3b7826a0b75264948586/images/checkradioexample.jpg -------------------------------------------------------------------------------- /images/listexample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ginge/GuiLibrary/f9b90686ba910c6fa63f3b7826a0b75264948586/images/listexample.jpg -------------------------------------------------------------------------------- /images/metroexample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ginge/GuiLibrary/f9b90686ba910c6fa63f3b7826a0b75264948586/images/metroexample.jpg -------------------------------------------------------------------------------- /images/metroexample2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ginge/GuiLibrary/f9b90686ba910c6fa63f3b7826a0b75264948586/images/metroexample2.jpg -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GuiLibrary", 3 | "keywords": "txt, gfx, gui, controls", 4 | "description": "GUI Toolkit to allow drawing of buttons and other controls to the tft easily", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/ginge/GuiToolkit.git" 9 | }, 10 | "include": [ 11 | "*.h", 12 | "*.c", 13 | "*.cpp", 14 | ], 15 | "frameworks": "arduino", 16 | "platforms": [ 17 | "atmelavr", 18 | "atmelsam", 19 | "teensy" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | ==================================================================================== 2 | Copyright (c) 2015 Barry Carter 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | A simple GUI Widget library for TFT screens. 12 | ==================================================================================== 13 | 14 | What 15 | ---- 16 | 17 | This is a library that allows you to draw simple widgets onto the screen in the 18 | simplest possible way. 19 | There are simple yet powerful grid and list layout options to let you get 20 | working straight away. Multiple screens of information are available by 21 | placing widgets on panels, and making the page you want to see visible, and the 22 | rest invisible. 23 | Callback functions can be used to trigger page changes, code execution or 24 | anything you want to do in your sketch. 25 | 26 | 27 | Requires: 28 | * Adafruit TFT and Adafruit GFX library 29 | * Touch input library 30 | * SdFat (for optional image support) 31 | 32 | 33 | Supported widgets 34 | * Label 35 | * Panel 36 | * Button 37 | * Radio Group 38 | * Checkbox 39 | * ListBox 40 | * Multi Line Text Box 41 | * Image Box 42 | 43 | 44 | Supported layout widgets 45 | * Grid view (with rowspan and colspan) 46 | * List views that auto place the elements 47 | * Just place the widget where you want using x and y 48 | 49 | 50 | supported features 51 | * Widget margins and padding 52 | * Text size and alignment (only one shitty font) 53 | * Element borders 54 | * Element background colours and font colours 55 | * Icons for buttons 56 | * Press/unpress states (where supported) 57 | * Callback functions for element actions (press, release etc) 58 | * Colours (background, border etc) are specified in normal good ol' RGB 59 | * Easily create your own widget elements 60 | 61 | 62 | Bad things 63 | * While every effort has been made to keep this lightweight, it just isn't. 64 | The library may not fit on an Arduino, tests required. 65 | * Sometimes the elements on the scren overdraw. There is 0 dame detection 66 | and redraws in the library are crafted to keep redrawing while elements low 67 | * The drawing engine is pretty dumb. If the text is bigger than your element, 68 | it will overflow. You will have to work that one out yourself for now. 69 | * There is no other input except for touchscreen. You can't move around your 70 | widgets with a joystick, say. 71 | * It isn't going to win any screen redraw speed awards 72 | * No scrollbars I guess thats up to you for a little while. 73 | 74 | 75 | TODO: 76 | * The header is a bit monolithic. It screams for a refactor 77 | * Those linked lists could probably be thinned down 78 | * you can't delete an element. Sorry! 79 | * Scrollbars 80 | * more fonts? 81 | * Now we have primitives, some shiny widgets. 82 | * Progress bar 83 | * Dials 84 | * Etc 85 | 86 | 87 | Example: 88 | There are lots of examples int he examples folder. 89 | 90 | Here is the minimum you need to get going 91 | 92 | #include "GuiLibrary.h" 93 | ... 94 | // Set our main window. 95 | Gui gui(&tft, &ts, 0, 0, tft.height(), tft.width()); 96 | 97 | void setup() { 98 | GuiLabel *label = new GuiLabel(0, 0, 50, 30, "Hello World!"); 99 | gui.addChild(label); 100 | gui.draw(); // set first draw going 101 | } 102 | 103 | 104 | 105 | Custom Widget: 106 | You can create your own widgets really easily by taking on the attributes of another element and overriding it. This is called subclassing. 107 | 108 | Example, lets create a new label that draws a line through the centre. 109 | 110 | // create a new label of type GuiLabel and override the draw 111 | class GuiLabelLine : public GuiLabel { 112 | public: 113 | GuiLabelLine(int16_t x, int16_t y, int16_t width, int16_t height, char const* text) : GuiLabel(x, y, width, height, text) { }; 114 | 115 | // This is the only function we need! 116 | void draw(void); 117 | }; 118 | 119 | void GuiLabelLine::draw() { 120 | if (!visible()) return; 121 | 122 | // we want to draw the outlines and whatnot 123 | GuiElement::drawBase(); 124 | 125 | GuiUtils::drawLine(absoluteX(), GuiUtils::getElementCentreY(), absoluteX() + width, GuiUtils::getElementCentreY(), GuiUtils::getColour(255, 0, 0)); 126 | 127 | // draw the normal label 128 | GuiLabel::draw(false); 129 | } 130 | 131 | ////////////////////////// 132 | 133 | 134 | --------------------------------------------------------------------------------