Skip to content

Commit

Permalink
Merge pull request #1 from JF002/develop
Browse files Browse the repository at this point in the history
Version 0.2.0
  • Loading branch information
JF002 authored Apr 1, 2018
2 parents 1a2ef10 + 25958c3 commit 6e844ce
Show file tree
Hide file tree
Showing 21 changed files with 1,005 additions and 76 deletions.
34 changes: 26 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
# cfGUI
A simple GUI library for M5Stack (ESP32)

This library is intended to run on M5Stack development board (http://www.m5stack.com/). However, it should be easy to port it to any other board.
This library is intended to run on M5Stack development board (http://www.m5stack.com/), base on ESP32.

However, it should be easy to port it to any other board with an LCD screen and 3 physical buttons.

It's composed of a simple hierarchy of graphical widget that can be drawn on screen.
The following widgets have been created so far:
- Screen
- Screen and AppScreen (screen with a top bar and a bottom bar)
- Bar
- StatusBar (with uptime, current time and wifi signal)
- Button
- Mosaic of widge

![Example picture of cfGUI running on a M5Stack board](https://mastodon.codingfield.com/media/oXYl3M6SVqcpn2iefrs)
- StatusBar (Bar with uptime, clock and Wifi signal)
- ButtonInfoBar (display the function of the physical button)
- Button, UpDownButton
- Mosaic of widgets

![Example picture of cfGUI running on a M5Stack board](https://mastodon.codingfield.com/system/media_attachments/files/000/207/740/original/dbacf24f45561e5c.jpg)

# How To (Platform.io)
To use this library with your platform.io project, simply clone or download the library into the directory 'lib' of your project.
Then, you just need to include the headers (e.g. #include <Screen.h>) and write some code.

Look at examples if you need some inspiration ;-)

# Todo
- Remove hard-coded values to make the lib more flexible
- <s>Remove hard-coded values to make the lib more flexible</s>
- Add new widgets
- Better 'focus' management

# Changelog
## 0.2.0
- Change default font (looks better)
- New widgets (AppScreen, StatusBar, ButtonInfoBar, UpDownButton)
- Improved mosaic (the size and position of the widget is not hard-coded anymore)
- Global improvements

## 0.1.0
- First version of the library, with basic functionalities

153 changes: 116 additions & 37 deletions examples/simpleExample/main.cpp
Original file line number Diff line number Diff line change
@@ -1,45 +1,58 @@
#include <M5Stack.h>

#include <NTPClient.h>
#include <Screen.h>
#include <Bar.h>
#include <ButtonInfoBar.h>
#include <StatusBar.h>
#include <Button.h>
#include <WidgetMosaic.h>
#include <string>
#include <time.h>
#include <sys/time.h>
#include <AppScreen.h>
#include <UpDownButton.h>

using namespace Codingfield::UI;
Screen screen(Size(320, 240), BLACK);
AppScreen* screen;
StatusBar* topBar;
Bar* bottomBar;
Codingfield::UI::Button* button0; // M5STack should really use namespaces to avoid name clashes
ButtonInfoBar* bottomBar;
Codingfield::UI::Button* button0;
Codingfield::UI::Button* button1;
Codingfield::UI::Button* button2;
Codingfield::UI::UpDownButton* button2;
Codingfield::UI::Button* button3;
Codingfield::UI::Button* button4;
Codingfield::UI::Button* button5;
WidgetMosaic* mosaic;
Widget* focus;

int32_t editButtonValue = 0;
int32_t editOldButtonValue = 0;

void setup() {
M5.begin();

topBar = new StatusBar(&screen, Point(0,0), 25);
bottomBar = new Bar(&screen, Point(0, screen.GetSize().height-25), 25);
// Instanciate and configure all widgets
topBar = new StatusBar();
bottomBar = new ButtonInfoBar();
mosaic = new WidgetMosaic(3, 2);
screen = new AppScreen(Size(320, 240), BLACK, topBar, bottomBar, mosaic);

mosaic = new WidgetMosaic(&screen, Point(5,30), Size(320, 190));
focus = mosaic;
// Give the focus to the main screen
focus = screen;

button0 = new Codingfield::UI::Button(mosaic);
button0->SetBackgroundColor(BLUE);
button0->SetTextColor(WHITE);
button0->SetText("16C");
button0->SetTitle("Fridge");
button1 = new Codingfield::UI::Button(mosaic);
button1->SetBackgroundColor(ORANGE);
button1->SetTextColor(BLACK);
button1->SetText("50%");
button2 = new Codingfield::UI::Button(mosaic);
button2 = new Codingfield::UI::UpDownButton(mosaic); // Up/Down button
button2->SetBackgroundColor(YELLOW);
button2->SetTextColor(BLACK);
button2->SetText("3h15");
button2->SetText("0");
button3 = new Codingfield::UI::Button(mosaic);
button3->SetBackgroundColor(PURPLE);
button3->SetTextColor(WHITE);
Expand All @@ -56,24 +69,80 @@ void setup() {
topBar->SetUptime(0);
topBar->SetWifiStatus(StatusBar::WifiStatuses::No_signal);

screen.Draw();
bottomBar->SetButtonAText("<");
bottomBar->SetButtonBText("SELECT");
bottomBar->SetButtonCText(">");

// Callback called by the mosaic when it changes mode (mosaic/zoom on 1 widget)
// We use it to update the bottom bar.
mosaic->SetZoomOnSelectedCallback([bottomBar](Widget* widget, bool edit) {
if(edit) {
if(widget->IsEditable()){
bottomBar->SetButtonAText("-");
bottomBar->SetButtonBText("APPLY");
bottomBar->SetButtonCText("+");
} else {
bottomBar->SetButtonAText("");
bottomBar->SetButtonBText("BACK");
bottomBar->SetButtonCText("");
}
} else {
bottomBar->SetButtonAText("<");
bottomBar->SetButtonBText("SELECT");
bottomBar->SetButtonCText(">");
}
});

// Configure callback to be called when the user wants to increment the value
// of button2
button2->SetUpCallback([&editButtonValue](UpDownButton* w) {
editButtonValue++;
w->SetText(String(editButtonValue).c_str());
return true;
});

// Configure callback to be called when the user wants to decrement the value
// of button2
button2->SetDownCallback([&editButtonValue](UpDownButton* w) {
editButtonValue--;
w->SetText(String(editButtonValue).c_str());
return true;
});

// Configure callback to be called when the user wants to apply the value
// of button2
button2->SetApplyCallback([&editButtonValue, &editOldButtonValue](UpDownButton* w) {
editOldButtonValue = editButtonValue;
return false;
});

// Configure callback to be called when the user wants to cancel modification
// of the value of button2
button2->SetCancelCallback([&editButtonValue](UpDownButton* w) {
editButtonValue = editOldButtonValue;
w->SetText(String(editButtonValue).c_str());
return true;
});

// Draw the screen and all its children
screen->Draw();
}

uint32_t loopCount = 0;
uint32_t temperature = 10;
uint32_t percent = 0;
std::string state = "BUSY";
int32_t wifiStatusIndex;
int rssi = -100;
int seconds = 0;
std::vector<StatusBar::WifiStatuses> wifiStatus {StatusBar::WifiStatuses::No_signal,
StatusBar::WifiStatuses::Weak,
StatusBar::WifiStatuses::Medium,
StatusBar::WifiStatuses::Full};
int32_t uptimeHours=0;
bool longPush = false;
void loop() {
M5.update();

// Update values displayd on the screen (status bar, buttons,...)
if((loopCount % 50) == 0) {
if(temperature < 100)
temperature++;
Expand All @@ -94,43 +163,53 @@ void loop() {
topBar->SetUptime(uptimeHours);

char strftime_buf[64];
if(seconds < 60)
seconds++;
else
seconds = 0;
snprintf(strftime_buf, 64, "%02d:%02d:%02d", 1, 2, seconds);
snprintf(strftime_buf, 64, "%02d:%02d:%02d", 12, 14, 59);
topBar->SetDateTime(strftime_buf);

if(rssi < 0)
rssi++;
else
rssi = -100;
if(rssi >= -55)
topBar->SetWifiStatus(StatusBar::WifiStatuses::Full);
else if(rssi >= -75)
topBar->SetWifiStatus(StatusBar::WifiStatuses::Medium);
else if(rssi >= -85)
topBar->SetWifiStatus(StatusBar::WifiStatuses::Weak);
else
topBar->SetWifiStatus(StatusBar::WifiStatuses::No_signal);
}

if((loopCount % 100) == 0) {
if(state == "BUSY") state = "IDLE";
else state = "BUSY";
button5->SetText(state);

auto rssi =WiFi.RSSI();
if(rssi >= -55) {
topBar->SetWifiStatus(StatusBar::WifiStatuses::Full);
} else if(rssi >= -75) {
topBar->SetWifiStatus(StatusBar::WifiStatuses::Medium);
} else if(rssi >= -85) {
topBar->SetWifiStatus(StatusBar::WifiStatuses::Weak);
} else {
topBar->SetWifiStatus(StatusBar::WifiStatuses::No_signal);
}
}

if(M5.BtnA.wasPressed())
// Notify the widgets that physical buttons are pressed
if(M5.BtnA.wasPressed()) {
focus->OnButtonAPressed();
}

if(M5.BtnB.wasPressed())
focus->OnButtonBPressed();
if(M5.BtnB.pressedFor(1000)) {
if(!longPush) {
focus->OnButtonBLongPush();
longPush = true;
}
}
else if(M5.BtnB.wasReleased()) {
if(!longPush) {
focus->OnButtonBPressed();
}
else {
longPush = false;
}
}

if(M5.BtnC.wasPressed())
if(M5.BtnC.wasPressed()) {
focus->OnButtonCPressed();
}

screen.Draw();
// Redraw the screen
screen->Draw();

loopCount++;
delay(10);
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=cfGUI
version=0.1
version=0.2.0
author=Jean-François Milants <[email protected]>
maintainer=Jean-François Milants <[email protected]>
sentence=cfGUI
Expand Down
59 changes: 59 additions & 0 deletions src/AppScreen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "AppScreen.h"
#include <Bar.h>

using namespace Codingfield::UI;

AppScreen::AppScreen(Size size, Color color) : Screen(size, color) {

}

AppScreen::AppScreen(Size size, Color color, Bar* topBar, Bar* bottomBar, Widget* centreWidget) : Screen(size, color), topBar{topBar}, bottomBar{bottomBar}, centreWidget{centreWidget} {
if(topBar != nullptr) {
topBar->SetParent(this);
topBar->SetPosition(Point(0,0));
topBar->SetSize(Size(this->GetSize().width, barHeight));
AddChild(topBar);
}

if(bottomBar != nullptr) {
bottomBar->SetParent(this);
bottomBar->SetPosition(Point(0, this->GetSize().height-barHeight));
bottomBar->SetSize(Size(this->GetSize().width, barHeight));
AddChild(bottomBar);
}

if(centreWidget != nullptr) {
Point centerPosition;
centerPosition.y = position.y + ((topBar != nullptr) ? topBar->GetSize().height : 0) + padding;
centerPosition.x = position.x + padding;

Size centerSize;
centerSize.height = size.height - (((bottomBar != nullptr) ? bottomBar->GetSize().height : 0) + ((topBar != nullptr) ? topBar->GetSize().height : 0) + padding);
centerSize.width = size.width;

centreWidget->SetParent(this);
centreWidget->SetPosition(centerPosition);
centreWidget->SetSize(centerSize);
AddChild(centreWidget);
}
}

void AppScreen::OnButtonAPressed() {
if(centreWidget != nullptr)
centreWidget->OnButtonAPressed();
}

void AppScreen::OnButtonBPressed() {
if(centreWidget != nullptr)
centreWidget->OnButtonBPressed();
}

void AppScreen::OnButtonBLongPush() {
if(centreWidget != nullptr)
centreWidget->OnButtonBLongPush();
}

void AppScreen::OnButtonCPressed() {
if(centreWidget != nullptr)
centreWidget->OnButtonCPressed();
}
26 changes: 26 additions & 0 deletions src/AppScreen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <Screen.h>

namespace Codingfield {
namespace UI {
class Bar;
class AppScreen : public Screen {
public:
AppScreen(Size size, Color color);
AppScreen(Size size, Color color, Bar* topBar, Bar* bottomBar, Widget* centreWidget);

virtual void OnButtonAPressed() override;
virtual void OnButtonBPressed() override;
virtual void OnButtonBLongPush() override;
virtual void OnButtonCPressed() override;

private:
Bar* topBar = nullptr;
Bar* bottomBar = nullptr;
Widget* centreWidget = nullptr;
int32_t padding = 5;
int32_t barHeight = 25;
};
}
}
1 change: 1 addition & 0 deletions src/Bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using namespace Codingfield::UI;

void Bar::Draw() {
if(IsHidden()) return;
if(isUpdated)
M5.Lcd.fillRect(position.x, position.y, size.width, size.height, WHITE);

Expand Down
1 change: 1 addition & 0 deletions src/Bar.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Codingfield {
namespace UI {
class Bar : public Widget {
public:
Bar() : Widget(nullptr, Point(), Size()) {}
Bar(Widget* parent, Point position, int32_t height) : Widget(parent, position, Size(parent->GetSize().width, height)) {}
void Draw() override;
private:
Expand Down
Loading

0 comments on commit 6e844ce

Please sign in to comment.