Moved all the bobbycar gui code into this library
This commit is contained in:
@ -1,17 +1,59 @@
|
||||
set(headers
|
||||
src/accessorinterface.h
|
||||
src/actioninterface.h
|
||||
src/changevaluedisplay.h
|
||||
src/changevaluedisplay_bool.h
|
||||
src/changevaluedisplay_daylightsavingmode.h
|
||||
src/changevaluedisplay_sntp_sync_mode_t.h
|
||||
src/checkboxicon.h
|
||||
src/colorinterface.h
|
||||
src/display.h
|
||||
src/fontinterface.h
|
||||
src/icon.h
|
||||
src/iconinterface.h
|
||||
src/menudisplay.h
|
||||
src/menuitem.h
|
||||
src/tftinstance.h
|
||||
src/textinterface.h
|
||||
src/actions/backproxyaction.h
|
||||
src/actions/dummyaction.h
|
||||
src/actions/setvalueaction.h
|
||||
src/actions/switchscreenaction.h
|
||||
src/icons/back.h
|
||||
src/icons/checked.h
|
||||
src/icons/unchecked.h
|
||||
src/widgets/graph.h
|
||||
src/widgets/label.h
|
||||
src/widgets/progressbar.h
|
||||
src/widgets/reverseprogressbar.h
|
||||
src/widgets/verticalmeter.h
|
||||
src/widgets/vumeter.h
|
||||
)
|
||||
|
||||
set(sources
|
||||
src/changevaluedisplay.cpp
|
||||
src/changevaluedisplay_bool.cpp
|
||||
src/changevaluedisplay_daylightsavingmode.cpp
|
||||
src/changevaluedisplay_sntp_sync_mode_t.cpp
|
||||
src/menudisplay.cpp
|
||||
src/tftinstance.cpp
|
||||
src/icons/back.cpp
|
||||
src/icons/checked.cpp
|
||||
src/icons/unchecked.cpp
|
||||
src/widgets/label.cpp
|
||||
src/widgets/progressbar.cpp
|
||||
src/widgets/reverseprogressbar.cpp
|
||||
src/widgets/verticalmeter.cpp
|
||||
src/widgets/vumeter.cpp
|
||||
)
|
||||
|
||||
set(dependencies
|
||||
cpputils
|
||||
cxx-ring-buffer
|
||||
espchrono
|
||||
espcpputils
|
||||
expected
|
||||
fmt
|
||||
|
||||
TFT_eSPI
|
||||
)
|
||||
|
||||
|
BIN
icons/back.png
Normal file
BIN
icons/back.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
BIN
icons/checked.png
Normal file
BIN
icons/checked.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
BIN
icons/unchecked.png
Normal file
BIN
icons/unchecked.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
21
src/accessorinterface.h
Normal file
21
src/accessorinterface.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace espgui {
|
||||
template<typename T>
|
||||
struct AccessorInterface
|
||||
{
|
||||
virtual T getValue() const = 0;
|
||||
virtual void setValue(T value) = 0;
|
||||
};
|
||||
|
||||
//! A special type of AccessorInterface that allows for simple variable read/write operations
|
||||
//! Can be used to read and write global settings for example.
|
||||
template<typename T>
|
||||
struct RefAccessor : public virtual AccessorInterface<T>
|
||||
{
|
||||
virtual T& getRef() const = 0;
|
||||
|
||||
T getValue() const override { return getRef(); };
|
||||
void setValue(T value) override { getRef() = value; };
|
||||
};
|
||||
} // namespace espgui
|
9
src/actioninterface.h
Normal file
9
src/actioninterface.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace espgui {
|
||||
class ActionInterface
|
||||
{
|
||||
public:
|
||||
virtual void triggered() = 0;
|
||||
};
|
||||
} // namespace espgui
|
23
src/actions/backproxyaction.h
Normal file
23
src/actions/backproxyaction.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "actioninterface.h"
|
||||
|
||||
namespace espgui {
|
||||
class BackProxyAction : public virtual ActionInterface
|
||||
{
|
||||
public:
|
||||
BackProxyAction(BackInterface &backInterface) :
|
||||
m_backInterface{backInterface}
|
||||
{
|
||||
}
|
||||
|
||||
void triggered() override
|
||||
{
|
||||
m_backInterface.back();
|
||||
}
|
||||
|
||||
private:
|
||||
BackInterface &m_backInterface;
|
||||
};
|
||||
} // namespace espgui
|
12
src/actions/dummyaction.h
Normal file
12
src/actions/dummyaction.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "actioninterface.h"
|
||||
|
||||
namespace espgui {
|
||||
class DummyAction : public virtual ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override {}
|
||||
};
|
||||
} // namespace espgui
|
31
src/actions/setvalueaction.h
Normal file
31
src/actions/setvalueaction.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "actioninterface.h"
|
||||
#include "accessorinterface.h"
|
||||
|
||||
namespace espgui {
|
||||
template<typename T>
|
||||
class SetValueAction : public virtual ActionInterface
|
||||
{
|
||||
public:
|
||||
SetValueAction(T value, AccessorInterface<T> &accessorInterface, BackInterface &backInterface) :
|
||||
m_value{value},
|
||||
m_accessorInterface{accessorInterface},
|
||||
m_backInterface{backInterface}
|
||||
{
|
||||
}
|
||||
|
||||
void triggered() override
|
||||
{
|
||||
m_accessorInterface.setValue(m_value);
|
||||
}
|
||||
|
||||
T value() const { return m_value; }
|
||||
|
||||
private:
|
||||
const T m_value;
|
||||
AccessorInterface<T> &m_accessorInterface;
|
||||
BackInterface &m_backInterface;
|
||||
};
|
||||
} // namespace espgui
|
13
src/actions/switchscreenaction.h
Normal file
13
src/actions/switchscreenaction.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "actioninterface.h"
|
||||
|
||||
namespace espgui {
|
||||
template<typename Tscreen, typename ...Targs>
|
||||
class SwitchScreenAction : public virtual ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override { switchScreen<Tscreen>(std::make_unique<Targs>()...); }
|
||||
};
|
||||
} // namespace espgui
|
34
src/changevaluedisplay.cpp
Normal file
34
src/changevaluedisplay.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "changevaluedisplay.h"
|
||||
|
||||
namespace espgui {
|
||||
void ChangeValueDisplayInterface::initScreen()
|
||||
{
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
|
||||
m_titleLabel.start();
|
||||
|
||||
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
|
||||
|
||||
tft.drawRect(25, 75, 190, 65, TFT_WHITE);
|
||||
m_valueLabel.start();
|
||||
|
||||
tft.setTextFont(4);
|
||||
tft.setTextColor(TFT_WHITE);
|
||||
tft.drawString("Change value and", 10, 160);
|
||||
tft.drawString("press button to", 10, 185);
|
||||
tft.drawString("confirm and go", 10, 210);
|
||||
tft.drawString("back.", 10, 235);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChangeValueDisplay<float>::redraw()
|
||||
{
|
||||
tft.setTextFont(4);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
m_titleLabel.redraw(text());
|
||||
|
||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
tft.setTextFont(7);
|
||||
m_valueLabel.redraw(fmt::format("{:.02f}", m_value));
|
||||
}
|
||||
} // namespace espgui
|
129
src/changevaluedisplay.h
Normal file
129
src/changevaluedisplay.h
Normal file
@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <fmt/core.h>
|
||||
|
||||
// local includes
|
||||
#include "display.h"
|
||||
#include "textinterface.h"
|
||||
#include "actioninterface.h"
|
||||
#include "accessorinterface.h"
|
||||
#include "widgets/label.h"
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
class ChangeValueDisplayInterface :
|
||||
public Display,
|
||||
public virtual TextInterface,
|
||||
public virtual ActionInterface
|
||||
{
|
||||
public:
|
||||
void initScreen() override;
|
||||
|
||||
TextInterface *asTextInterface() override { return this; }
|
||||
const TextInterface *asTextInterface() const override { return this; }
|
||||
|
||||
ChangeValueDisplayInterface *asChangeValueDisplayInterface() override { return this; }
|
||||
const ChangeValueDisplayInterface *asChangeValueDisplayInterface() const override { return this; }
|
||||
|
||||
virtual int shownValue() const = 0;
|
||||
virtual void setShownValue(int value) = 0;
|
||||
|
||||
protected:
|
||||
Label m_titleLabel{5, 5}; // 230, 25
|
||||
Label m_valueLabel{26, 81}; // 188, 53
|
||||
};
|
||||
|
||||
template<typename Tvalue>
|
||||
class ChangeValueDisplaySettingsInterface
|
||||
{
|
||||
public:
|
||||
virtual Tvalue step() const { return 1; };
|
||||
};
|
||||
|
||||
template<typename Tvalue, typename Tratio>
|
||||
class RatioNumberStep : public virtual ChangeValueDisplaySettingsInterface<Tvalue>
|
||||
{
|
||||
public:
|
||||
Tvalue step() const override { return Tvalue(Tratio::num) / Tratio::den; }
|
||||
};
|
||||
|
||||
template<typename Tvalue>
|
||||
class ChangeValueDisplay :
|
||||
public ChangeValueDisplayInterface,
|
||||
public virtual AccessorInterface<Tvalue>,
|
||||
public virtual ChangeValueDisplaySettingsInterface<Tvalue>
|
||||
{
|
||||
using Base = ChangeValueDisplayInterface;
|
||||
|
||||
public:
|
||||
void start() override;
|
||||
void update() override;
|
||||
void redraw() override;
|
||||
|
||||
void rotate(int offset) override;
|
||||
void confirm() override;
|
||||
|
||||
int shownValue() const { return m_value; }
|
||||
void setShownValue(int value) { m_value = value; }
|
||||
|
||||
private:
|
||||
Tvalue m_value{};
|
||||
|
||||
int m_rotateOffset;
|
||||
bool m_pressed{};
|
||||
};
|
||||
|
||||
template<typename Tvalue>
|
||||
void ChangeValueDisplay<Tvalue>::start()
|
||||
{
|
||||
m_value = static_cast<AccessorInterface<Tvalue>*>(this)->getValue();
|
||||
|
||||
m_rotateOffset = 0;
|
||||
m_pressed = false;
|
||||
}
|
||||
|
||||
template<typename Tvalue>
|
||||
void ChangeValueDisplay<Tvalue>::update()
|
||||
{
|
||||
if (!m_pressed)
|
||||
{
|
||||
const auto rotateOffset = m_rotateOffset;
|
||||
m_rotateOffset = 0;
|
||||
|
||||
m_value -= rotateOffset * static_cast<ChangeValueDisplaySettingsInterface<Tvalue>*>(this)->step();
|
||||
}
|
||||
else
|
||||
{
|
||||
static_cast<AccessorInterface<Tvalue>*>(this)->setValue(m_value);
|
||||
triggered();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Tvalue>
|
||||
void ChangeValueDisplay<Tvalue>::redraw()
|
||||
{
|
||||
tft.setTextFont(4);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
m_titleLabel.redraw(text());
|
||||
|
||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
tft.setTextFont(7);
|
||||
m_valueLabel.redraw(std::to_string(m_value));
|
||||
}
|
||||
|
||||
template<>
|
||||
void ChangeValueDisplay<float>::redraw();
|
||||
|
||||
template<typename Tvalue>
|
||||
void ChangeValueDisplay<Tvalue>::rotate(int offset)
|
||||
{
|
||||
m_rotateOffset += offset;
|
||||
}
|
||||
|
||||
template<typename Tvalue>
|
||||
void ChangeValueDisplay<Tvalue>::confirm()
|
||||
{
|
||||
m_pressed = true;
|
||||
}
|
||||
} // namespace espgui
|
32
src/changevaluedisplay_bool.cpp
Normal file
32
src/changevaluedisplay_bool.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "changevaluedisplay_bool.h"
|
||||
|
||||
// local includes
|
||||
#include "actions/setvalueaction.h"
|
||||
#include "actions/backproxyaction.h"
|
||||
#include "icons/back.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace {
|
||||
constexpr char TEXT_TRUE[] = "true";
|
||||
constexpr char TEXT_FALSE[] = "false";
|
||||
constexpr char TEXT_BACK[] = "Back";
|
||||
} // namespace
|
||||
|
||||
ChangeValueDisplay<bool>::ChangeValueDisplay()
|
||||
{
|
||||
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<bool>, StaticText<TEXT_TRUE>>>(true, *this, *this);
|
||||
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<bool>, StaticText<TEXT_FALSE>>>(false, *this, *this);
|
||||
constructMenuItem<makeComponentArgs<MenuItem, BackProxyAction, StaticText<TEXT_BACK>, StaticMenuItemIcon<&icons::back>>>(*this);
|
||||
}
|
||||
|
||||
void ChangeValueDisplay<bool>::start()
|
||||
{
|
||||
Base::start();
|
||||
|
||||
switch (getValue())
|
||||
{
|
||||
case true: setSelectedIndex(0); break;
|
||||
case false: setSelectedIndex(1); break;
|
||||
}
|
||||
}
|
||||
} // namespace espgui
|
22
src/changevaluedisplay_bool.h
Normal file
22
src/changevaluedisplay_bool.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "changevaluedisplay.h"
|
||||
#include "menudisplay.h"
|
||||
#include "actioninterface.h"
|
||||
|
||||
namespace espgui {
|
||||
template<>
|
||||
class ChangeValueDisplay<bool> :
|
||||
public MenuDisplay,
|
||||
public virtual AccessorInterface<bool>,
|
||||
public virtual ActionInterface
|
||||
{
|
||||
using Base = MenuDisplay;
|
||||
|
||||
public:
|
||||
ChangeValueDisplay();
|
||||
|
||||
void start() override;
|
||||
};
|
||||
} // namespace espgui
|
43
src/changevaluedisplay_daylightsavingmode.cpp
Normal file
43
src/changevaluedisplay_daylightsavingmode.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "changevaluedisplay_daylightsavingmode.h"
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// local includes
|
||||
#include "actions/setvalueaction.h"
|
||||
#include "actions/backproxyaction.h"
|
||||
#include "icons/back.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace {
|
||||
constexpr const char * const TAG = "ESPGUI";
|
||||
|
||||
constexpr char TEXT_NONE[] = "None";
|
||||
constexpr char TEXT_EUROPEANSUMMERTIME[] = "EuropeanSummerTime";
|
||||
constexpr char TEXT_USDAYLIGHTTIME[] = "UsDaylightTime";
|
||||
constexpr char TEXT_BACK[] = "Back";
|
||||
} // namespace
|
||||
|
||||
ChangeValueDisplay<espchrono::DayLightSavingMode>::ChangeValueDisplay()
|
||||
{
|
||||
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<espchrono::DayLightSavingMode>, StaticText<TEXT_NONE>>>(espchrono::DayLightSavingMode::None, *this, *this);
|
||||
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<espchrono::DayLightSavingMode>, StaticText<TEXT_EUROPEANSUMMERTIME>>>(espchrono::DayLightSavingMode::EuropeanSummerTime, *this, *this);
|
||||
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<espchrono::DayLightSavingMode>, StaticText<TEXT_USDAYLIGHTTIME>>>(espchrono::DayLightSavingMode::UsDaylightTime, *this, *this);
|
||||
constructMenuItem<makeComponentArgs<MenuItem, BackProxyAction, StaticText<TEXT_BACK>, StaticMenuItemIcon<&icons::back>>>(*this);
|
||||
}
|
||||
|
||||
void ChangeValueDisplay<espchrono::DayLightSavingMode>::start()
|
||||
{
|
||||
Base::start();
|
||||
|
||||
switch (const auto value = getValue())
|
||||
{
|
||||
case espchrono::DayLightSavingMode::None: setSelectedIndex(0); break;
|
||||
case espchrono::DayLightSavingMode::EuropeanSummerTime: setSelectedIndex(1); break;
|
||||
case espchrono::DayLightSavingMode::UsDaylightTime: setSelectedIndex(2); break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unknown DayLightSavingMode: %i", int(value));
|
||||
setSelectedIndex(3);
|
||||
}
|
||||
}
|
||||
}
|
25
src/changevaluedisplay_daylightsavingmode.h
Normal file
25
src/changevaluedisplay_daylightsavingmode.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <espchrono.h>
|
||||
|
||||
// local includes
|
||||
#include "changevaluedisplay.h"
|
||||
#include "menudisplay.h"
|
||||
#include "actioninterface.h"
|
||||
|
||||
namespace espgui {
|
||||
template<>
|
||||
class ChangeValueDisplay<espchrono::DayLightSavingMode> :
|
||||
public MenuDisplay,
|
||||
public virtual AccessorInterface<espchrono::DayLightSavingMode>,
|
||||
public virtual ActionInterface
|
||||
{
|
||||
using Base = MenuDisplay;
|
||||
|
||||
public:
|
||||
ChangeValueDisplay();
|
||||
|
||||
void start() override;
|
||||
};
|
||||
} // namespace espgui
|
40
src/changevaluedisplay_sntp_sync_mode_t.cpp
Normal file
40
src/changevaluedisplay_sntp_sync_mode_t.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "changevaluedisplay_sntp_sync_mode_t.h"
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// local includes
|
||||
#include "actions/setvalueaction.h"
|
||||
#include "actions/backproxyaction.h"
|
||||
#include "icons/back.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace {
|
||||
constexpr const char * const TAG = "ESPGUI";
|
||||
|
||||
constexpr char TEXT_IMMED[] = "IMMED";
|
||||
constexpr char TEXT_SMOOTH[] = "SMOOTH";
|
||||
constexpr char TEXT_BACK[] = "Back";
|
||||
} // namespace
|
||||
|
||||
ChangeValueDisplay<sntp_sync_mode_t>::ChangeValueDisplay()
|
||||
{
|
||||
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<sntp_sync_mode_t>, StaticText<TEXT_IMMED>>>(SNTP_SYNC_MODE_IMMED, *this, *this);
|
||||
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<sntp_sync_mode_t>, StaticText<TEXT_SMOOTH>>>(SNTP_SYNC_MODE_SMOOTH, *this, *this);
|
||||
constructMenuItem<makeComponentArgs<MenuItem, BackProxyAction, StaticText<TEXT_BACK>, StaticMenuItemIcon<&icons::back>>>(*this);
|
||||
}
|
||||
|
||||
void ChangeValueDisplay<sntp_sync_mode_t>::start()
|
||||
{
|
||||
Base::start();
|
||||
|
||||
switch (const auto value = getValue())
|
||||
{
|
||||
case SNTP_SYNC_MODE_IMMED: setSelectedIndex(0); break;
|
||||
case SNTP_SYNC_MODE_SMOOTH: setSelectedIndex(1); break;
|
||||
default:
|
||||
ESP_LOGW("BOBBY", "Unknown sntp_sync_mode_t: %i", int(value));
|
||||
setSelectedIndex(2);
|
||||
}
|
||||
}
|
||||
}
|
24
src/changevaluedisplay_sntp_sync_mode_t.h
Normal file
24
src/changevaluedisplay_sntp_sync_mode_t.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_sntp.h>
|
||||
|
||||
// local includes
|
||||
#include "changevaluedisplay.h"
|
||||
#include "menudisplay.h"
|
||||
|
||||
namespace espgui {
|
||||
template<>
|
||||
class ChangeValueDisplay<sntp_sync_mode_t> :
|
||||
public MenuDisplay,
|
||||
public virtual AccessorInterface<sntp_sync_mode_t>,
|
||||
public virtual ActionInterface
|
||||
{
|
||||
using Base = MenuDisplay;
|
||||
|
||||
public:
|
||||
ChangeValueDisplay();
|
||||
|
||||
void start() override;
|
||||
};
|
||||
} // namespace espgui
|
18
src/checkboxicon.h
Normal file
18
src/checkboxicon.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "menuitem.h"
|
||||
#include "accessorinterface.h"
|
||||
#include "icons/checked.h"
|
||||
#include "icons/unchecked.h"
|
||||
|
||||
namespace espgui {
|
||||
class CheckboxIcon : public virtual MenuItemIconInterface, public virtual AccessorInterface<bool>
|
||||
{
|
||||
public:
|
||||
const MenuItemIcon *icon() const override
|
||||
{
|
||||
return getValue() ? &icons::checked : &icons::unchecked;
|
||||
}
|
||||
};
|
||||
} // namespace espgui
|
33
src/colorinterface.h
Normal file
33
src/colorinterface.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
namespace espgui {
|
||||
class ColorInterface {
|
||||
public:
|
||||
virtual int color() const { return TFT_WHITE; };
|
||||
};
|
||||
|
||||
template<int TColor>
|
||||
class StaticColor : public virtual ColorInterface
|
||||
{
|
||||
public:
|
||||
static constexpr int STATIC_COLOR = TColor;
|
||||
|
||||
int color() const override { return TColor; }
|
||||
};
|
||||
|
||||
using DefaultColor = StaticColor<TFT_WHITE>;
|
||||
using DisabledColor = StaticColor<TFT_DARKGREY>;
|
||||
|
||||
class ChangeableColor : public virtual ColorInterface
|
||||
{
|
||||
public:
|
||||
int color() const override { return m_color; }
|
||||
void setColor(const int &color) { m_color = color; }
|
||||
|
||||
private:
|
||||
int m_color;
|
||||
};
|
||||
} // namespace espgui
|
88
src/display.h
Normal file
88
src/display.h
Normal file
@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <string>
|
||||
|
||||
// forward declares
|
||||
namespace espgui {
|
||||
class TextInterface;
|
||||
class MenuDisplay;
|
||||
class ChangeValueDisplayInterface;
|
||||
}
|
||||
|
||||
namespace espgui {
|
||||
template<typename ...T>
|
||||
class makeComponent : public T...
|
||||
{};
|
||||
|
||||
template <typename T1, typename T2, typename ...T3>
|
||||
class makeComponentArgs : public T1, public T2, public T3...
|
||||
{
|
||||
public:
|
||||
template<typename ...T>
|
||||
makeComponentArgs(T&& ...args) :
|
||||
T2{std::forward<T>(args)...}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ConfirmInterface
|
||||
{
|
||||
public:
|
||||
virtual void confirm() = 0;
|
||||
};
|
||||
|
||||
class BackInterface
|
||||
{
|
||||
public:
|
||||
virtual void back() = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ConfirmActionInterface : public virtual ConfirmInterface
|
||||
{
|
||||
public:
|
||||
void confirm() override { T{}.triggered(); }
|
||||
};
|
||||
|
||||
class DummyConfirm : public virtual ConfirmInterface
|
||||
{
|
||||
public:
|
||||
void confirm() override {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class BackActionInterface : public virtual BackInterface
|
||||
{
|
||||
public:
|
||||
void back() override { T{}.triggered(); }
|
||||
};
|
||||
|
||||
class DummyBack : public virtual BackInterface
|
||||
{
|
||||
public:
|
||||
void back() override {}
|
||||
};
|
||||
|
||||
class Display : public virtual ConfirmInterface, public virtual BackInterface {
|
||||
public:
|
||||
virtual ~Display() = default;
|
||||
|
||||
virtual void start() {};
|
||||
virtual void initScreen() {};
|
||||
virtual void update() {};
|
||||
virtual void redraw() {};
|
||||
virtual void stop() {}
|
||||
|
||||
virtual void rotate(int offset) {}
|
||||
|
||||
virtual TextInterface *asTextInterface() { return nullptr; }
|
||||
virtual const TextInterface *asTextInterface() const { return nullptr; }
|
||||
|
||||
virtual MenuDisplay *asMenuDisplay() { return nullptr; }
|
||||
virtual const MenuDisplay *asMenuDisplay() const { return nullptr; }
|
||||
|
||||
virtual ChangeValueDisplayInterface *asChangeValueDisplayInterface() { return nullptr; }
|
||||
virtual const ChangeValueDisplayInterface *asChangeValueDisplayInterface() const { return nullptr; }
|
||||
};
|
||||
} // namespace espgui
|
29
src/fontinterface.h
Normal file
29
src/fontinterface.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
namespace espgui {
|
||||
class FontInterface {
|
||||
public:
|
||||
virtual int font() const { return 4; };
|
||||
};
|
||||
|
||||
template<int TFont>
|
||||
class StaticFont : public virtual FontInterface
|
||||
{
|
||||
public:
|
||||
static constexpr int STATIC_FONT = TFont;
|
||||
|
||||
int font() const override { return TFont; }
|
||||
};
|
||||
|
||||
using DefaultFont = StaticFont<4>;
|
||||
|
||||
class ChangeableFont : public virtual FontInterface
|
||||
{
|
||||
public:
|
||||
int font() const override { return m_font; }
|
||||
void setfont(const int &font) { m_font = font; }
|
||||
|
||||
private:
|
||||
int m_font;
|
||||
};
|
||||
} // namespace espgui
|
@ -3,6 +3,7 @@
|
||||
// system includes
|
||||
#include <cstdint>
|
||||
|
||||
namespace espgui {
|
||||
template<uint16_t width, uint16_t height>
|
||||
struct Icon
|
||||
{
|
||||
@ -11,3 +12,4 @@ struct Icon
|
||||
|
||||
const unsigned short buffer[width*height];
|
||||
};
|
||||
} // namespace espgui
|
||||
|
20
src/iconinterface.h
Normal file
20
src/iconinterface.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "icon.h"
|
||||
|
||||
namespace espgui {
|
||||
template<uint16_t width, uint16_t height>
|
||||
class IconInterface
|
||||
{
|
||||
public:
|
||||
virtual const Icon<width, height> *icon() const { return nullptr; }
|
||||
};
|
||||
|
||||
template<uint16_t width, uint16_t height, const Icon<width, height> *T>
|
||||
class StaticIcon : public virtual IconInterface<width, height>
|
||||
{
|
||||
public:
|
||||
virtual const Icon<width, height> *icon() const { return T; }
|
||||
};
|
||||
} // namespace espgui
|
44
src/icons/back.cpp
Normal file
44
src/icons/back.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "back.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace icons {
|
||||
const Icon<24, 24> back{{
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016C, 0x014B, 0x010B, 0x01AC, 0x018C, 0x018C, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0010 (16) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014B, 0x0009, 0x0000, // 0x0020 (32) pixels
|
||||
0x2AD0, 0x3331, 0x00CB, 0x09CD, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0030 (48) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x012B, 0x0007, 0x0000, 0x1A6F, 0x5CD7, 0x5C96, 0x0003, 0x09ED, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0040 (64) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010B, 0x0006, 0xFFFF, 0x022F, 0x6518, // 0x0050 (80) pixels
|
||||
0x75FB, 0x5C96, 0x0000, 0x1AB0, 0x2312, 0x22F1, 0x1AB0, 0x1A6F, 0x0A0E, 0x016C, 0x0048, 0x00EA, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0060 (96) pixels
|
||||
0x0000, 0x0000, 0x010A, 0x0029, 0x0000, 0x022F, 0x6538, 0x761B, 0x761B, 0x5CD7, 0x024F, 0x22D0, 0x22D0, 0x1AB0, 0x1A6F, 0x124F, // 0x0070 (112) pixels
|
||||
0x01CD, 0x002A, 0x0000, 0x018C, 0x0007, 0x014B, 0x0000, 0x0000, 0x0002, 0x0003, 0x0A2E, 0x0000, 0x1A90, 0x6518, 0x7E3C, 0x761C, // 0x0080 (128) pixels
|
||||
0x761C, 0x6E1C, 0x65BB, 0x5D9A, 0x5D7A, 0x5539, 0x54F8, 0x4CB7, 0x4C76, 0x3BD4, 0x2B11, 0x1A6F, 0x016C, 0x43F5, 0x012B, 0x00A6, // 0x0090 (144) pixels
|
||||
0x0006, 0x024F, 0x0000, 0x22F1, 0x6518, 0x7E3C, 0x7E5C, 0x765C, 0x765C, 0x6E3C, 0x661C, 0x65FC, 0x5DBB, 0x559A, 0x4D5A, 0x44F9, // 0x00A0 (160) pixels
|
||||
0x44D8, 0x3C97, 0x4456, 0x3BD4, 0x2AF1, 0x09CD, 0x5D7C, 0x00AA, 0x022F, 0x0000, 0x2AF1, 0x6518, 0x863C, 0x7E3C, 0x6E3C, 0x663C, // 0x00B0 (176) pixels
|
||||
0x663D, 0x5E3D, 0x5E1C, 0x5DFC, 0x55DB, 0x559B, 0x4D5A, 0x4519, 0x3CB8, 0x3477, 0x3436, 0x33F5, 0x3BD4, 0x2AF1, 0x018C, 0x0000, // 0x00C0 (192) pixels
|
||||
0x014B, 0x22B0, 0x54B7, 0x5D9A, 0x4D7A, 0x3D7B, 0x357B, 0x2D9C, 0x2DDC, 0x2DDC, 0x2DBC, 0x2D7B, 0x355A, 0x3D5A, 0x453A, 0x4519, // 0x00D0 (208) pixels
|
||||
0x3CD8, 0x3477, 0x3436, 0x2BD5, 0x2BB5, 0x3394, 0x1A6F, 0x014C, 0x016B, 0x1A90, 0x3436, 0x24D9, 0x14D9, 0x1D1A, 0x1D5B, 0x1D9C, // 0x00E0 (224) pixels
|
||||
0x25DD, 0x25DD, 0x1D9C, 0x1D5B, 0x1D1A, 0x1CD9, 0x1CB8, 0x2CB8, 0x3CB8, 0x3477, 0x2C36, 0x2BD5, 0x2394, 0x33D5, 0x22F1, 0x11CC, // 0x00F0 (240) pixels
|
||||
0x022F, 0x0004, 0x1AD0, 0x2C57, 0x24F9, 0x1D1A, 0x1D5B, 0x1D7C, 0x1DBC, 0x25BC, 0x1D9C, 0x1D5B, 0x1D1A, 0x1CD9, 0x1C98, 0x1457, // 0x0100 (256) pixels
|
||||
0x1C37, 0x2C36, 0x2C16, 0x23D5, 0x2394, 0x23B5, 0x2B32, 0x11CD, 0x0000, 0x0A0E, 0x0000, 0x22F1, 0x2C77, 0x251A, 0x1D3A, 0x1D5B, // 0x0110 (272) pixels
|
||||
0x1D7B, 0x1D7B, 0x1D5B, 0x1D3A, 0x1CFA, 0x1CB9, 0x1C78, 0x1457, 0x1416, 0x13D5, 0x23D5, 0x23B5, 0x1B94, 0x1B94, 0x2B52, 0x11ED, // 0x0120 (288) pixels
|
||||
0x0023, 0x0000, 0x0A4F, 0x0000, 0x22F1, 0x3497, 0x251A, 0x1D1A, 0x1D3A, 0x2D5B, 0x2D3A, 0x2D1A, 0x24F9, 0x24D9, 0x1478, 0x1437, // 0x0130 (304) pixels
|
||||
0x13F6, 0x13B5, 0x1394, 0x1B74, 0x1B74, 0x1B94, 0x2B52, 0x11ED, 0x0000, 0x0087, 0x0000, 0x124F, 0x0000, 0x1AB0, 0x3497, 0x1D1A, // 0x0140 (320) pixels
|
||||
0x1CFA, 0x3497, 0x1B32, 0x2373, 0x2393, 0x2BD4, 0x3415, 0x2C57, 0x13F6, 0x1395, 0x1374, 0x1353, 0x1354, 0x2394, 0x2B32, 0x11ED, // 0x0150 (336) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x00EA, 0x00EA, 0x0000, 0x126F, 0x3497, 0x24D9, 0x3435, 0x0000, 0x1270, 0x0000, 0x0029, 0x01AC, 0x22F1, // 0x0160 (352) pixels
|
||||
0x33F5, 0x1395, 0x1354, 0x1333, 0x0B33, 0x2394, 0x22F1, 0x22B0, 0x0000, 0x0000, 0x0000, 0x0000, 0x010B, 0x0008, 0x0000, 0x1A6F, // 0x0170 (368) pixels
|
||||
0x3477, 0x3435, 0x0006, 0x09ED, 0x0027, 0x00EA, 0x01AC, 0x0000, 0x22B0, 0x2BB4, 0x0B33, 0x1333, 0x0B34, 0x2B73, 0x22B0, 0x09AD, // 0x0180 (384) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012B, 0x0009, 0x0000, 0x1A90, 0x3352, 0x004A, 0x09CD, 0x0000, 0x0000, 0x010A, 0x012B, // 0x0190 (400) pixels
|
||||
0x09CD, 0x2B53, 0x1354, 0x0B33, 0x1B54, 0x2B32, 0x228F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014B, 0x010B, // 0x01A0 (416) pixels
|
||||
0x0007, 0x018D, 0x01AC, 0x01AC, 0x0000, 0x0000, 0x0000, 0x014B, 0x09CD, 0x2B32, 0x1374, 0x0B33, 0x2353, 0x2AF1, 0x08EA, 0x1A0D, // 0x01B0 (432) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01AD, 0x09ED, 0x00CA, 0x018C, 0x018C, 0x0000, 0x0000, 0x0000, 0x018C, // 0x01C0 (448) pixels
|
||||
0x09ED, 0x2B53, 0x1354, 0x1B53, 0x2B32, 0x224E, 0x2B11, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01D0 (464) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A8, 0x09ED, 0x122E, 0x2B73, 0x1B54, 0x2B53, 0x32D0, 0x43D4, 0x0004, 0x0000, // 0x01E0 (480) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0049, 0x451B, // 0x01F0 (496) pixels
|
||||
0x1AB0, 0x2BB4, 0x2B53, 0x32F0, 0x5D3A, 0x0008, 0x00C9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0200 (512) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018C, 0x010B, 0x3332, 0x3393, 0x2AD0, 0x873F, 0x012B, 0x11ED, 0x0000, 0x0000, // 0x0210 (528) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0109, 0x01AD, 0x018C, // 0x0220 (544) pixels
|
||||
0x22B0, 0x32F0, 0x761E, 0x016C, 0x1A2E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0230 (560) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014B, 0x018C, 0x018C, 0x09CD, 0x4C77, 0x012B, 0x1A0E, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0240 (576) pixels
|
||||
}};
|
||||
} // namespace icons
|
||||
} // namespace espgui
|
10
src/icons/back.h
Normal file
10
src/icons/back.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "icon.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace icons {
|
||||
extern const Icon<24, 24> back;
|
||||
} // namespace icons
|
||||
} // namespace espgui
|
44
src/icons/checked.cpp
Normal file
44
src/icons/checked.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "checked.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace icons {
|
||||
const Icon<24, 24> checked{{
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0010 (16) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0020 (32) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0030 (48) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0040 (64) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2945, 0x6B4D, 0x5AEB, 0x5AEB, // 0x0050 (80) pixels
|
||||
0x5AEB, 0x5AEB, 0x5AEB, 0x5AEB, 0x5AEB, 0x5AEB, 0x5AEB, 0x8BF1, 0x0240, 0x01E0, 0x02C0, 0x0280, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0060 (96) pixels
|
||||
0x0000, 0x0000, 0xA514, 0xA534, 0xA534, 0xBDD7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDF7, 0x8C91, // 0x0070 (112) pixels
|
||||
0x3807, 0x0000, 0x0000, 0x0260, 0x0260, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xC618, 0xBDD7, 0xCE59, 0xAD75, 0xB596, 0xB596, // 0x0080 (128) pixels
|
||||
0xB596, 0xB596, 0xAD75, 0xAD75, 0xAD75, 0xB596, 0xAD75, 0x9CD3, 0x0300, 0x8E31, 0x00E0, 0x0240, 0x0260, 0x0000, 0x0000, 0x0000, // 0x0090 (144) pixels
|
||||
0x0000, 0x8431, 0xA534, 0xA514, 0xA534, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD55, 0xAD75, 0xAD75, 0xA554, 0x5BEB, // 0x00A0 (160) pixels
|
||||
0x4508, 0xBF77, 0x1C43, 0x0240, 0x01C0, 0x02C0, 0x0000, 0x0000, 0x0000, 0x8C51, 0xFFFF, 0x9492, 0xCE59, 0xF7BE, 0xFFBF, 0xF79E, // 0x00B0 (176) pixels
|
||||
0xF79E, 0xF79E, 0xEF7D, 0xEF7D, 0xF7BE, 0xEF9D, 0x8D51, 0x34E6, 0xA6F4, 0xA734, 0xA6F4, 0x54EA, 0x02E0, 0x0240, 0x0000, 0x0000, // 0x00C0 (192) pixels
|
||||
0x0000, 0x7BCF, 0x0000, 0x8C72, 0x7C8F, 0x6CCD, 0xC698, 0xF79E, 0xEF7D, 0xEF7D, 0xEF5D, 0xF79E, 0xF79E, 0x8510, 0x34C6, 0x9EB3, // 0x00D0 (208) pixels
|
||||
0x9692, 0x9672, 0x9692, 0x44C8, 0x02E0, 0x0220, 0x0000, 0x0000, 0x0160, 0x632C, 0x02A0, 0x3B27, 0x3426, 0x8E30, 0x23C4, 0xCEB9, // 0x00E0 (224) pixels
|
||||
0xF77E, 0xEF7D, 0xF79E, 0xF79E, 0x8D51, 0x2463, 0x8E51, 0x8630, 0x8610, 0x8610, 0x44A8, 0x02A0, 0x0160, 0x0000, 0x0000, 0x0000, // 0x00F0 (240) pixels
|
||||
0x0240, 0x02A0, 0x0260, 0x1BA3, 0x75AD, 0x860F, 0x656B, 0x4C29, 0xCED9, 0xF7BE, 0xEF7D, 0x8D31, 0x2C24, 0x7E0E, 0x7DEE, 0x7DCE, // 0x0100 (256) pixels
|
||||
0x7DCE, 0x4CA9, 0x02A0, 0x1843, 0x0220, 0x0280, 0x0000, 0x0000, 0x0240, 0x0000, 0x0321, 0x6D6B, 0x75AC, 0x75AC, 0x75EC, 0x654A, // 0x0110 (272) pixels
|
||||
0x33A6, 0xCED9, 0x9D73, 0x3C26, 0x7E0D, 0x75CC, 0x75AC, 0x6D8C, 0x5CEA, 0x2AE5, 0x634D, 0x2288, 0x7BCE, 0x0000, 0x0000, 0x0000, // 0x0120 (288) pixels
|
||||
0x0260, 0x0220, 0x0200, 0x1361, 0x6549, 0x658A, 0x6DCA, 0x760B, 0x5CE8, 0x02E0, 0x33C4, 0x760B, 0x6DCA, 0x6DCA, 0x6DAA, 0x7D6D, // 0x0130 (304) pixels
|
||||
0x646C, 0x6B6D, 0x6B6E, 0x8C4E, 0x52AD, 0x0000, 0x0000, 0x0000, 0x0200, 0x5B0B, 0x0220, 0x2A85, 0x2B83, 0x6568, 0x5DC8, 0x65E8, // 0x0140 (320) pixels
|
||||
0x7649, 0x6D49, 0x75EA, 0x6E09, 0x65C8, 0x65A9, 0x6CEB, 0x3BA8, 0xE75C, 0x7BD0, 0x634D, 0x73B1, 0x5ACA, 0x0000, 0x0000, 0x0000, // 0x0150 (336) pixels
|
||||
0x0000, 0x5AAD, 0x000A, 0x630D, 0x5BCB, 0x2344, 0x65A6, 0x4D84, 0x55C4, 0x4DC4, 0x4DA3, 0x4D83, 0x4563, 0x4463, 0x1B83, 0xE73C, // 0x0160 (352) pixels
|
||||
0xFFDF, 0x7BF0, 0x6B4D, 0x7BEE, 0x52AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x630E, 0x0010, 0x5AEC, 0xCE79, 0x9DB3, 0x1300, 0x5DC3, // 0x0170 (368) pixels
|
||||
0x4E01, 0x4E22, 0x4E21, 0x4E02, 0x5D24, 0x4388, 0xE73C, 0xF79E, 0xFFDF, 0x8410, 0x6B6E, 0x840D, 0x630E, 0x0000, 0x0000, 0x0000, // 0x0180 (384) pixels
|
||||
0x0000, 0x73AE, 0x8C6A, 0x630D, 0xC638, 0xFFFF, 0xADF5, 0x0B60, 0x6664, 0x56A1, 0x66C3, 0x5503, 0x3B48, 0xDF3B, 0xF7BE, 0xF79E, // 0x0190 (400) pixels
|
||||
0xFFDF, 0x8431, 0x73AF, 0x6B4F, 0x73AE, 0x0000, 0x0000, 0x0000, 0x0000, 0x738D, 0x5280, 0x6B4D, 0xC638, 0xFFFF, 0xFFFF, 0xA5D4, // 0x01A0 (416) pixels
|
||||
0x1280, 0x7F45, 0x5D83, 0x0300, 0xEF9D, 0xFFFF, 0xFFDF, 0xF7BE, 0xFFFF, 0x8C51, 0x7BCF, 0x7BF2, 0x738D, 0x0000, 0x0000, 0x0000, // 0x01B0 (432) pixels
|
||||
0x0000, 0x738D, 0x0000, 0x6B6E, 0xC638, 0xFFFF, 0xFFFF, 0xFFFF, 0x9572, 0x32A5, 0x53C9, 0xEF9D, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDF, // 0x01C0 (448) pixels
|
||||
0xFFFF, 0x8C72, 0x7BF0, 0x8C53, 0x738D, 0x0000, 0x0000, 0x0000, 0x0000, 0x7BD0, 0xA510, 0x7BCF, 0xA535, 0xCE59, 0xCE59, 0xCE59, // 0x01D0 (464) pixels
|
||||
0xCE79, 0x84B0, 0xADB5, 0xCE59, 0xCE59, 0xCE59, 0xCE59, 0xCE59, 0xC638, 0x8C51, 0x8410, 0x8430, 0x7BD0, 0x0000, 0x0000, 0x0000, // 0x01E0 (480) pixels
|
||||
0x0000, 0x8C71, 0x8431, 0x8431, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x8410, 0x83F0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, // 0x01F0 (496) pixels
|
||||
0x7BF0, 0x8410, 0x8C51, 0x8431, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9CD3, 0x9492, 0xB593, 0x9493, 0x9491, 0x94B1, // 0x0200 (512) pixels
|
||||
0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x9491, 0x9CF3, 0x4200, 0x8430, 0x9492, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0210 (528) pixels
|
||||
0x0000, 0x0020, 0x0000, 0x630D, 0x8C71, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, // 0x0220 (544) pixels
|
||||
0x8C71, 0x8410, 0x8C51, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0230 (560) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0240 (576) pixels
|
||||
}};
|
||||
} // namespace icons
|
||||
} // namespace espgui
|
10
src/icons/checked.h
Normal file
10
src/icons/checked.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "icon.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace icons {
|
||||
extern const Icon<24, 24> checked;
|
||||
} // namespace icons
|
||||
} // namespace espgui
|
44
src/icons/unchecked.cpp
Normal file
44
src/icons/unchecked.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "unchecked.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace icons {
|
||||
const Icon<24, 24> unchecked{{
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0010 (16) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0020 (32) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0030 (48) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0040 (64) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2945, 0x6B4D, 0x5AEB, 0x5AEB, // 0x0050 (80) pixels
|
||||
0x5AEB, 0x5AEB, 0x5AEB, 0x5AEB, 0x2124, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0060 (96) pixels
|
||||
0x0000, 0x0000, 0xA514, 0xA534, 0xA534, 0xBDD7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDF7, 0xBDD7, 0xB5B6, 0xB5B6, 0x31A6, 0x31A6, 0x39E7, // 0x0070 (112) pixels
|
||||
0x0180, 0x0000, 0x11E3, 0x4269, 0x4229, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xC618, 0xBDD7, 0xCE59, 0xAD75, 0xB596, 0xB596, // 0x0080 (128) pixels
|
||||
0xB596, 0xB596, 0xAD75, 0xAD55, 0xA514, 0xA514, 0xA514, 0xA514, 0xA514, 0x8C71, 0x8C51, 0x5B0C, 0x4AC9, 0x0000, 0x0000, 0x0000, // 0x0090 (144) pixels
|
||||
0x0000, 0x8431, 0xA534, 0xA514, 0xA534, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, 0xAD75, // 0x00A0 (160) pixels
|
||||
0xB596, 0x8C71, 0x8431, 0x5BCC, 0x2A85, 0x52AC, 0x0000, 0x0000, 0x0000, 0x8C51, 0xFFFF, 0x9492, 0xC638, 0xF7BE, 0xFFDF, 0xFFDF, // 0x00B0 (176) pixels
|
||||
0xF7BE, 0xF7BE, 0xFFDF, 0xF7BE, 0xF7DE, 0xF7BE, 0xFFDF, 0xFFDF, 0xFFFF, 0x8C51, 0x6B6E, 0x538A, 0x2A85, 0x528C, 0x0000, 0x0000, // 0x00C0 (192) pixels
|
||||
0x5ACB, 0x52AA, 0xFFFF, 0x8451, 0xC638, 0xF7BE, 0xF7BE, 0xF7BE, 0xF79E, 0xF79E, 0xF79E, 0xF7BE, 0xF7BE, 0xF79E, 0xF7BE, 0xF7BE, // 0x00D0 (208) pixels
|
||||
0xFFDF, 0x8C51, 0x6B6E, 0x53AA, 0x2284, 0x52AC, 0x0000, 0x0000, 0xEF7D, 0xFFFF, 0xEF5D, 0x632D, 0xBDF7, 0xF7BE, 0xF7BE, 0xF79E, // 0x00E0 (224) pixels
|
||||
0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF79E, 0xF7BE, 0xF7BE, 0xFFDF, 0x8431, 0x6B6E, 0x4B0A, 0x52CB, 0x528C, 0x0000, 0x0000, // 0x00F0 (240) pixels
|
||||
0xF7BE, 0xE73C, 0x8CD1, 0x738E, 0xBDF7, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, // 0x0100 (256) pixels
|
||||
0xFFDF, 0x8431, 0x6B6E, 0x5B0C, 0x5ACC, 0x39C8, 0x0000, 0x0000, 0xF7BE, 0xF79E, 0xB616, 0x73CF, 0xC638, 0xFFDF, 0xF79E, 0xF7BE, // 0x0110 (272) pixels
|
||||
0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF79E, 0xF7BE, 0xFFDF, 0xF7BE, 0xFFDF, 0x8431, 0x6B6E, 0x630D, 0x5AED, 0x0000, 0x0000, 0x0000, // 0x0120 (288) pixels
|
||||
0xF79E, 0xFFFF, 0x8CD1, 0x52CB, 0xC618, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF79E, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, // 0x0130 (304) pixels
|
||||
0xFFDF, 0x8431, 0x6B6E, 0x5AEC, 0x52AC, 0x0000, 0x0000, 0x0000, 0x10A2, 0xBDF7, 0x634B, 0x4A4A, 0xC618, 0xF7DE, 0xF7BE, 0xF7BE, // 0x0140 (320) pixels
|
||||
0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xFFFF, 0x8C51, 0x6B6E, 0x7BCF, 0x5AED, 0x0000, 0x0000, 0x0000, // 0x0150 (336) pixels
|
||||
0x0000, 0x0000, 0x528C, 0x4A6A, 0xC618, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7DF, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF79E, 0xF7BE, // 0x0160 (352) pixels
|
||||
0xFFDF, 0x8431, 0x6B6E, 0x7BCF, 0x5AED, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5ACD, 0x4A4A, 0xBDF8, 0xF7BE, 0xF7BE, 0xF7BE, // 0x0170 (368) pixels
|
||||
0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xFFFF, 0x8C51, 0x738E, 0x73AE, 0x632E, 0x0000, 0x0000, 0x0000, // 0x0180 (384) pixels
|
||||
0x0000, 0x0000, 0x6B6D, 0x4209, 0xC618, 0xFFDF, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xF7BE, 0xFFDF, 0xF7BE, // 0x0190 (400) pixels
|
||||
0xFFDF, 0x8C51, 0x73AF, 0x738F, 0x73AE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6B4C, 0x4A6A, 0xC638, 0xFFFF, 0xFFFF, 0xF7BE, // 0x01A0 (416) pixels
|
||||
0xFFDF, 0xFFDF, 0xF7BE, 0xFFDF, 0xF7BE, 0xF7BE, 0xFFDF, 0xF7BE, 0xFFFF, 0x8C51, 0x7BCF, 0x7BF1, 0x738D, 0x0000, 0x0000, 0x0000, // 0x01B0 (432) pixels
|
||||
0x0000, 0x0000, 0x6B4C, 0x5ACB, 0xC638, 0xFFFF, 0xFFFF, 0xFFDF, 0xF7BE, 0xFFDF, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDF, // 0x01C0 (448) pixels
|
||||
0xFFFF, 0x8C72, 0x7BF0, 0x8C53, 0x738D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9492, 0x738E, 0xA534, 0xCE59, 0xCE59, 0xCE59, // 0x01D0 (464) pixels
|
||||
0xCE59, 0xC638, 0xC618, 0xCE59, 0xCE59, 0xCE59, 0xCE59, 0xCE59, 0xC638, 0x8C51, 0x8410, 0x8430, 0x7BD0, 0x0000, 0x0000, 0x0000, // 0x01E0 (480) pixels
|
||||
0x0000, 0x0000, 0x8C51, 0x8431, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, 0x7BF0, // 0x01F0 (496) pixels
|
||||
0x7BF0, 0x8410, 0x8C51, 0x8431, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9CD3, 0x9492, 0xB593, 0x9493, 0x9491, 0x94B1, // 0x0200 (512) pixels
|
||||
0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x94B1, 0x9491, 0x9CF3, 0x4200, 0x8430, 0x9492, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0210 (528) pixels
|
||||
0x0000, 0x0020, 0x0000, 0x630D, 0x8C71, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, 0x8C51, // 0x0220 (544) pixels
|
||||
0x8C71, 0x8410, 0x8C51, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0230 (560) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0240 (576) pixels
|
||||
}};
|
||||
} // namespace icons
|
||||
} // namespace espgui
|
10
src/icons/unchecked.h
Normal file
10
src/icons/unchecked.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "icon.h"
|
||||
|
||||
namespace espgui {
|
||||
namespace icons {
|
||||
extern const Icon<24, 24> unchecked;
|
||||
} // namespace icons
|
||||
} // namespace espgui
|
180
src/menudisplay.cpp
Normal file
180
src/menudisplay.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
#include "menudisplay.h"
|
||||
|
||||
// local includes
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
void MenuDisplay::start()
|
||||
{
|
||||
m_selectedIndex = 0;
|
||||
m_scrollOffset = 0;
|
||||
|
||||
m_rotateOffset = 0;
|
||||
m_pressed = false;
|
||||
}
|
||||
|
||||
void MenuDisplay::initScreen()
|
||||
{
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
|
||||
m_titleLabel.start();
|
||||
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
|
||||
|
||||
for (auto &label : m_labels)
|
||||
label.start();
|
||||
|
||||
runForEveryMenuItem([](MenuItem &item){
|
||||
item.start();
|
||||
});
|
||||
|
||||
m_icons.fill(nullptr);
|
||||
|
||||
m_highlightedIndex = -1;
|
||||
}
|
||||
|
||||
void MenuDisplay::update()
|
||||
{
|
||||
if (!m_pressed)
|
||||
{
|
||||
const auto offset = m_rotateOffset;
|
||||
m_rotateOffset = 0;
|
||||
|
||||
const auto itemCount = menuItemCount();
|
||||
|
||||
if (itemCount)
|
||||
{
|
||||
if (m_selectedIndex == -1)
|
||||
m_selectedIndex = 0;
|
||||
|
||||
m_selectedIndex = m_selectedIndex + offset;
|
||||
|
||||
if (m_selectedIndex < 0)
|
||||
m_selectedIndex += itemCount;
|
||||
if (m_selectedIndex >= itemCount)
|
||||
m_selectedIndex -= itemCount;
|
||||
|
||||
if (m_selectedIndex < m_scrollOffset)
|
||||
m_scrollOffset = m_selectedIndex;
|
||||
if (m_selectedIndex >= m_scrollOffset + m_labels.size())
|
||||
m_scrollOffset = m_selectedIndex - m_labels.size() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selectedIndex = -1;
|
||||
m_scrollOffset = 0;
|
||||
}
|
||||
|
||||
runForEveryMenuItem([&](MenuItem &item){
|
||||
item.update();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pressed = false;
|
||||
if (m_selectedIndex >= 0)
|
||||
getMenuItem(m_selectedIndex).triggered();
|
||||
}
|
||||
}
|
||||
|
||||
void MenuDisplay::redraw()
|
||||
{
|
||||
tft.setTextFont(4);
|
||||
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
|
||||
m_titleLabel.redraw(text());
|
||||
|
||||
int i{0};
|
||||
|
||||
auto labelsIter = std::begin(m_labels);
|
||||
|
||||
auto iconsIter = std::begin(m_icons);
|
||||
|
||||
int newHighlightedIndex{-1};
|
||||
|
||||
const auto drawItemRect = [](const auto &label, const auto color){
|
||||
tft.drawRect(5,
|
||||
label.y()-1,
|
||||
240 - 10,
|
||||
lineHeight+2,
|
||||
color);
|
||||
};
|
||||
|
||||
runForEveryMenuItem([&](MenuItem &item){
|
||||
const auto index = i++;
|
||||
|
||||
if (index < m_scrollOffset)
|
||||
return;
|
||||
|
||||
if (labelsIter == std::end(m_labels))
|
||||
return;
|
||||
|
||||
const auto relativeIndex = index - m_scrollOffset;
|
||||
const auto selected = index == m_selectedIndex;
|
||||
|
||||
if (selected)
|
||||
newHighlightedIndex = relativeIndex;
|
||||
else if (relativeIndex == m_highlightedIndex)
|
||||
drawItemRect(*labelsIter, TFT_BLACK);
|
||||
|
||||
tft.setTextFont(item.font());
|
||||
tft.setTextColor(item.color(), TFT_BLACK);
|
||||
labelsIter->redraw(item.text());
|
||||
|
||||
if (item.icon() != *iconsIter)
|
||||
{
|
||||
tft.fillRect(5, labelsIter->y()+1, 24, 24, TFT_BLACK);
|
||||
|
||||
auto icon = item.icon();
|
||||
if (icon)
|
||||
{
|
||||
tft.setSwapBytes(true);
|
||||
tft.pushImage(6, labelsIter->y()+1, icon->WIDTH, icon->HEIGHT, icon->buffer);
|
||||
tft.setSwapBytes(false);
|
||||
}
|
||||
*iconsIter = icon;
|
||||
}
|
||||
|
||||
if (selected && (relativeIndex != m_highlightedIndex))
|
||||
{
|
||||
drawItemRect(*labelsIter, TFT_WHITE);
|
||||
}
|
||||
|
||||
labelsIter++;
|
||||
iconsIter++;
|
||||
});
|
||||
|
||||
for (; labelsIter != std::end(m_labels); labelsIter++, iconsIter++)
|
||||
{
|
||||
const auto relativeIndex = std::distance(std::begin(m_labels), labelsIter);
|
||||
|
||||
if (relativeIndex == m_highlightedIndex)
|
||||
drawItemRect(*labelsIter, TFT_BLACK);
|
||||
|
||||
labelsIter->clear();
|
||||
|
||||
if (*iconsIter)
|
||||
{
|
||||
tft.fillRect(5, labelsIter->y()+1, 24, 24, TFT_BLACK);
|
||||
*iconsIter = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
m_highlightedIndex = newHighlightedIndex;
|
||||
}
|
||||
|
||||
void MenuDisplay::stop()
|
||||
{
|
||||
runForEveryMenuItem([](MenuItem &item){
|
||||
item.stop();
|
||||
});
|
||||
}
|
||||
|
||||
void MenuDisplay::rotate(int offset)
|
||||
{
|
||||
m_rotateOffset += offset;
|
||||
}
|
||||
|
||||
void MenuDisplay::confirm()
|
||||
{
|
||||
m_pressed = true;
|
||||
}
|
||||
} // namespace espgui
|
127
src/menudisplay.h
Normal file
127
src/menudisplay.h
Normal file
@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
// local includes
|
||||
#include "display.h"
|
||||
#include "textinterface.h"
|
||||
#include "widgets/label.h"
|
||||
#include "menuitem.h"
|
||||
|
||||
namespace espgui {
|
||||
class MenuDisplay : public Display, public virtual TextInterface
|
||||
{
|
||||
public:
|
||||
void start() override;
|
||||
void initScreen() override;
|
||||
void update() override;
|
||||
void redraw() override;
|
||||
void stop() override;
|
||||
|
||||
void rotate(int offset) override;
|
||||
void confirm() override;
|
||||
|
||||
TextInterface *asTextInterface() override { return this; }
|
||||
const TextInterface *asTextInterface() const override { return this; }
|
||||
|
||||
MenuDisplay *asMenuDisplay() override { return this; }
|
||||
const MenuDisplay *asMenuDisplay() const override { return this; }
|
||||
|
||||
int selectedIndex() const { return m_selectedIndex; }
|
||||
|
||||
|
||||
std::size_t menuItemCount() const { return m_menuItems.size(); }
|
||||
|
||||
MenuItem& getMenuItem(std::size_t index)
|
||||
{
|
||||
assert(index < m_menuItems.size());
|
||||
return *m_menuItems[index].get();
|
||||
}
|
||||
|
||||
const MenuItem& getMenuItem(std::size_t index) const
|
||||
{
|
||||
assert(index < m_menuItems.size());
|
||||
return *m_menuItems[index].get();
|
||||
}
|
||||
|
||||
void runForEveryMenuItem(std::function<void(MenuItem&)> &&callback)
|
||||
{
|
||||
for (const auto &ptr : m_menuItems)
|
||||
callback(*ptr);
|
||||
}
|
||||
|
||||
void runForEveryMenuItem(std::function<void(const MenuItem&)> &&callback) const
|
||||
{
|
||||
for (const auto &ptr : m_menuItems)
|
||||
callback(*ptr);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T &constructMenuItem(Args&&... args)
|
||||
{
|
||||
auto ptr = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
T &ref = *ptr;
|
||||
emplaceMenuItem(std::move(ptr));
|
||||
return ref;
|
||||
}
|
||||
|
||||
void emplaceMenuItem(std::unique_ptr<MenuItem> &&ptr)
|
||||
{
|
||||
m_menuItems.emplace_back(std::move(ptr));
|
||||
}
|
||||
|
||||
void clearMenuItems()
|
||||
{
|
||||
m_menuItems.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<MenuItem> takeLastMenuItem()
|
||||
{
|
||||
assert(!m_menuItems.empty());
|
||||
std::unique_ptr<MenuItem> ptr = std::move(m_menuItems.back());
|
||||
m_menuItems.pop_back();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void setSelectedIndex(int selectedIndex) { m_selectedIndex = selectedIndex; }
|
||||
|
||||
private:
|
||||
Label m_titleLabel{5, 5}; // 230, 25
|
||||
|
||||
static constexpr auto iconWidth = 25;
|
||||
static constexpr auto horizontalSpacing = 10;
|
||||
static constexpr auto topMargin = 40;
|
||||
static constexpr auto lineHeight = 25;
|
||||
static constexpr auto verticalSpacing = 3;
|
||||
|
||||
std::array<Label, 10> m_labels {{
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(0*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(1*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(2*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(3*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(4*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(5*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(6*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(7*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(8*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
Label{horizontalSpacing + iconWidth, topMargin+(9*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
|
||||
}};
|
||||
|
||||
std::array<const Icon<24, 24> *, 10> m_icons;
|
||||
|
||||
int m_selectedIndex;
|
||||
int m_scrollOffset;
|
||||
int m_highlightedIndex;
|
||||
|
||||
int m_rotateOffset;
|
||||
bool m_pressed;
|
||||
|
||||
std::vector<std::unique_ptr<MenuItem>> m_menuItems;
|
||||
};
|
||||
} // namespace espgui
|
30
src/menuitem.h
Normal file
30
src/menuitem.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "textinterface.h"
|
||||
#include "fontinterface.h"
|
||||
#include "colorinterface.h"
|
||||
#include "iconinterface.h"
|
||||
#include "actioninterface.h"
|
||||
|
||||
namespace espgui {
|
||||
using MenuItemIconInterface = IconInterface<24, 24>;
|
||||
|
||||
using MenuItemIcon = Icon<24, 24>;
|
||||
|
||||
template<const MenuItemIcon *T>
|
||||
using StaticMenuItemIcon = StaticIcon<24, 24, T>;
|
||||
|
||||
class MenuItem :
|
||||
public virtual ActionInterface,
|
||||
public virtual TextInterface,
|
||||
public virtual FontInterface,
|
||||
public virtual ColorInterface,
|
||||
public virtual MenuItemIconInterface
|
||||
{
|
||||
public:
|
||||
virtual void start() {}
|
||||
virtual void update() {}
|
||||
virtual void stop() {}
|
||||
};
|
||||
} // namespace espgui
|
77
src/textinterface.h
Normal file
77
src/textinterface.h
Normal file
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <string>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <fmt/core.h>
|
||||
|
||||
namespace espgui {
|
||||
class TextInterface {
|
||||
public:
|
||||
virtual std::string text() const = 0;
|
||||
};
|
||||
|
||||
class EmptyText : public virtual TextInterface
|
||||
{
|
||||
public:
|
||||
std::string text() const override { return {}; }
|
||||
};
|
||||
|
||||
template<const char *Ttext>
|
||||
class StaticText : public virtual TextInterface
|
||||
{
|
||||
public:
|
||||
static constexpr const char *STATIC_TEXT = Ttext;
|
||||
|
||||
std::string text() const override { return Ttext; }
|
||||
};
|
||||
|
||||
class ChangeableText : public virtual TextInterface
|
||||
{
|
||||
public:
|
||||
std::string text() const override { return m_title; }
|
||||
void setTitle(std::string &&title) { m_title = std::move(title); }
|
||||
void setTitle(const std::string &title) { m_title = title; }
|
||||
|
||||
private:
|
||||
std::string m_title;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class CachedText : public virtual T
|
||||
{
|
||||
public:
|
||||
std::string text() const override
|
||||
{
|
||||
if (!m_loaded)
|
||||
{
|
||||
m_text = T::text();
|
||||
m_loaded = true;
|
||||
}
|
||||
|
||||
return m_text;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable bool m_loaded{};
|
||||
mutable std::string m_text;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class StaticallyCachedText : public virtual T
|
||||
{
|
||||
public:
|
||||
std::string text() const override
|
||||
{
|
||||
static const auto text = T::text();
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
template<const char *Tprefix, typename Taccessor>
|
||||
struct TextWithValueHelper : public virtual TextInterface
|
||||
{
|
||||
std::string text() const override { return fmt::format("{} {}", Tprefix, Taccessor{}.getValue()); }
|
||||
};
|
||||
} // namespace espgui
|
5
src/tftinstance.cpp
Normal file
5
src/tftinstance.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
TFT_eSPI tft;
|
||||
}
|
8
src/tftinstance.h
Normal file
8
src/tftinstance.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
namespace espgui {
|
||||
extern TFT_eSPI tft;
|
||||
}
|
148
src/widgets/graph.h
Normal file
148
src/widgets/graph.h
Normal file
@ -0,0 +1,148 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <functional>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <ring-buffer.h>
|
||||
#include <cpputils.h>
|
||||
|
||||
// local includes
|
||||
#include "label.h"
|
||||
|
||||
namespace espgui {
|
||||
template<size_t LENGTH, size_t COUNT>
|
||||
class Graph
|
||||
{
|
||||
static constexpr int labelOffset = -5;
|
||||
static constexpr int leftMargin = 40;
|
||||
|
||||
public:
|
||||
using Container = std::array<std::reference_wrapper<const ring_buffer<float, LENGTH>>, COUNT>;
|
||||
static constexpr int WIDTH = LENGTH+40;
|
||||
|
||||
Graph(int x, int y, int height);
|
||||
|
||||
void start(const Container &buffers);
|
||||
void redraw(const Container &buffers);
|
||||
|
||||
private:
|
||||
void render(const Container &buffers, bool delta);
|
||||
|
||||
const int m_x, m_y, m_height;
|
||||
|
||||
std::array<Label, 5> m_labels;
|
||||
|
||||
std::array<std::array<int, COUNT>, LENGTH> m_lastPixels;
|
||||
|
||||
float m_min;
|
||||
float m_max;
|
||||
};
|
||||
|
||||
template<size_t LENGTH, size_t COUNT>
|
||||
Graph<LENGTH, COUNT>::Graph(int x, int y, int height) :
|
||||
m_x{x}, m_y{y}, m_height{height},
|
||||
m_labels{
|
||||
Label{m_x, int(m_y+(m_height/4.f*0)+labelOffset)},
|
||||
Label{m_x, int(m_y+(m_height/4.f*1)+labelOffset)},
|
||||
Label{m_x, int(m_y+(m_height/4.f*2)+labelOffset)},
|
||||
Label{m_x, int(m_y+(m_height/4.f*3)+labelOffset)},
|
||||
Label{m_x, int(m_y+(m_height/4.f*4)+labelOffset)},
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
template<size_t LENGTH, size_t COUNT>
|
||||
void Graph<LENGTH, COUNT>::start(const Container &buffers)
|
||||
{
|
||||
m_min = 0.f;
|
||||
m_max = 10.f;
|
||||
|
||||
tft.drawFastVLine(m_x+leftMargin-1, m_y, m_height, TFT_WHITE);
|
||||
|
||||
for (auto iter = std::begin(m_labels); iter != std::end(m_labels); iter++)
|
||||
{
|
||||
tft.drawFastHLine(m_x+leftMargin-5, float(m_y)+(float(m_height)/(m_labels.size()-1)*std::distance(std::begin(m_labels), iter)), 4, TFT_WHITE);
|
||||
iter->start();
|
||||
}
|
||||
|
||||
render(buffers, false);
|
||||
}
|
||||
|
||||
template<size_t LENGTH, size_t COUNT>
|
||||
void Graph<LENGTH, COUNT>::redraw(const Container &buffers)
|
||||
{
|
||||
render(buffers, true);
|
||||
}
|
||||
|
||||
template<size_t LENGTH, size_t COUNT>
|
||||
void Graph<LENGTH, COUNT>::render(const Container &buffers, bool delta)
|
||||
{
|
||||
float min{std::numeric_limits<float>::quiet_NaN()}, max{std::numeric_limits<float>::quiet_NaN()};
|
||||
bool first{true};
|
||||
for (const ring_buffer<float, LENGTH> &buffer : buffers)
|
||||
{
|
||||
auto minmax = std::minmax_element(std::cbegin(buffer), std::cend(buffer));
|
||||
|
||||
if (first || *minmax.first < min)
|
||||
min = *minmax.first;
|
||||
if (first || *minmax.second > max)
|
||||
max = *minmax.second;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (min < m_min)
|
||||
m_min = min*0.9f;
|
||||
else if (min > m_min*1.1f)
|
||||
m_min = min*1.1f;
|
||||
|
||||
if (max > m_max)
|
||||
m_max = max*1.1f;
|
||||
else if (max < m_max*0.9f)
|
||||
m_max = max*1.1f;
|
||||
|
||||
if (m_max-m_min < 2.f)
|
||||
{
|
||||
m_min-=1.f;
|
||||
m_max+=1.f;
|
||||
}
|
||||
|
||||
if (m_min > 0 && m_max > 0)
|
||||
m_min = 0;
|
||||
if (m_min < 0 && m_max < 0)
|
||||
m_max = 0;
|
||||
|
||||
tft.setTextFont(2);
|
||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
for (auto iter = std::begin(m_labels); iter != std::end(m_labels); iter++)
|
||||
iter->redraw(std::to_string(int(m_max+((m_min-m_max)/(m_labels.size()-1)*std::distance(std::begin(m_labels), iter)))));
|
||||
|
||||
int x{leftMargin};
|
||||
for (auto pixelsIter = std::begin(m_lastPixels); pixelsIter!=std::end(m_lastPixels); pixelsIter++)
|
||||
{
|
||||
const auto index0 = std::distance(std::begin(m_lastPixels), pixelsIter);
|
||||
auto &pixels = *pixelsIter;
|
||||
|
||||
for (auto iter = std::begin(pixels); iter != std::end(pixels); iter++)
|
||||
{
|
||||
const auto index1 = std::distance(std::begin(pixels), iter);
|
||||
|
||||
const std::reference_wrapper<const ring_buffer<float, LENGTH>> &ref = *(std::begin(buffers)+index1);
|
||||
const ring_buffer<float, LENGTH> &buffer = ref.get();
|
||||
|
||||
const float &val = *(std::begin(buffer)+index0);
|
||||
|
||||
int y = cpputils::mapValueClamped<float>(val, m_min, m_max, m_y+m_height-1, m_y+1);
|
||||
if (!delta || *iter != y)
|
||||
{
|
||||
if (delta)
|
||||
tft.drawFastVLine(x, *iter-1, 3, TFT_BLACK);
|
||||
tft.drawFastVLine(x, y-1, 3, TFT_WHITE);
|
||||
*iter = y;
|
||||
}
|
||||
}
|
||||
|
||||
x++;
|
||||
}
|
||||
}
|
||||
} // namespace espgui
|
59
src/widgets/label.cpp
Normal file
59
src/widgets/label.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "label.h"
|
||||
|
||||
// local includes
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
Label::Label(int x, int y) :
|
||||
m_x{x},
|
||||
m_y{y}
|
||||
{
|
||||
}
|
||||
|
||||
void Label::start()
|
||||
{
|
||||
m_lastStr.clear();
|
||||
m_lastFont = -1;
|
||||
m_lastColor = -1;
|
||||
|
||||
m_lastWidth = 0;
|
||||
m_lastHeight = 0;
|
||||
}
|
||||
|
||||
void Label::redraw(std::string_view str, bool forceRedraw)
|
||||
{
|
||||
if (m_lastStr == str &&
|
||||
m_lastFont == tft.textfont &&
|
||||
m_lastColor == tft.textcolor &&
|
||||
!forceRedraw)
|
||||
return;
|
||||
|
||||
const auto renderedWidth = tft.drawString(str.data(), m_x, m_y);
|
||||
const auto renderedHeight = tft.fontHeight();
|
||||
|
||||
if (renderedWidth < m_lastWidth)
|
||||
tft.fillRect(m_x + renderedWidth, m_y,
|
||||
m_lastWidth - renderedWidth, m_lastHeight,
|
||||
tft.textbgcolor);
|
||||
|
||||
if (renderedHeight < m_lastHeight)
|
||||
tft.fillRect(m_x, m_y + renderedHeight,
|
||||
renderedWidth, m_lastHeight - renderedHeight,
|
||||
tft.textbgcolor);
|
||||
|
||||
m_lastStr = str;
|
||||
m_lastFont = tft.textfont;
|
||||
m_lastColor = tft.textcolor;
|
||||
|
||||
m_lastWidth = renderedWidth;
|
||||
m_lastHeight = renderedHeight;
|
||||
}
|
||||
|
||||
void Label::clear()
|
||||
{
|
||||
if (m_lastWidth || m_lastHeight)
|
||||
tft.fillRect(m_x, m_y, m_lastWidth, m_lastHeight, tft.textbgcolor);
|
||||
|
||||
start();
|
||||
}
|
||||
}
|
30
src/widgets/label.h
Normal file
30
src/widgets/label.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <string>
|
||||
|
||||
namespace espgui {
|
||||
class Label
|
||||
{
|
||||
public:
|
||||
Label(int x, int y);
|
||||
|
||||
int x() const { return m_x; };
|
||||
int y() const { return m_y; };
|
||||
|
||||
void start();
|
||||
void redraw(std::string_view str, bool forceRedraw = false);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
const int m_x;
|
||||
const int m_y;
|
||||
|
||||
std::string m_lastStr;
|
||||
int m_lastFont;
|
||||
int m_lastColor;
|
||||
|
||||
int m_lastWidth;
|
||||
int m_lastHeight;
|
||||
};
|
||||
} // namespace espgui
|
32
src/widgets/progressbar.cpp
Normal file
32
src/widgets/progressbar.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "progressbar.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <cpputils.h>
|
||||
|
||||
// local includes
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
ProgressBar::ProgressBar(int x, int y, int width, int height, int min, int max, uint32_t color) :
|
||||
m_x{x}, m_y{y}, m_width{width}, m_height{height}, m_min{min}, m_max{max}, m_color{color}
|
||||
{
|
||||
}
|
||||
|
||||
void ProgressBar::start()
|
||||
{
|
||||
m_lastValue = m_x+1;
|
||||
tft.drawRect(m_x, m_y, m_width, m_height, TFT_WHITE);
|
||||
}
|
||||
|
||||
void ProgressBar::redraw(int value)
|
||||
{
|
||||
value = cpputils::mapValueClamped(value, m_min, m_max, m_x+1, m_x+m_width-1);
|
||||
|
||||
if (value < m_lastValue)
|
||||
tft.fillRect(value, m_y+1, m_lastValue-value, m_height-2, TFT_BLACK);
|
||||
else if (value > m_lastValue)
|
||||
tft.fillRect(m_lastValue, m_y+1, value-m_lastValue, m_height-2, m_color);
|
||||
|
||||
m_lastValue = value;
|
||||
}
|
||||
} // namespace espgui
|
29
src/widgets/progressbar.h
Normal file
29
src/widgets/progressbar.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <cstdint>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
namespace espgui {
|
||||
class ProgressBar
|
||||
{
|
||||
public:
|
||||
ProgressBar(int x, int y, int width, int height, int min, int max, uint32_t color=TFT_YELLOW);
|
||||
|
||||
void start();
|
||||
void redraw(int value);
|
||||
|
||||
private:
|
||||
const int m_x;
|
||||
const int m_y;
|
||||
const int m_width;
|
||||
const int m_height;
|
||||
const int m_min;
|
||||
const int m_max;
|
||||
const uint32_t m_color;
|
||||
|
||||
int m_lastValue{};
|
||||
};
|
||||
} // namespace espgui
|
32
src/widgets/reverseprogressbar.cpp
Normal file
32
src/widgets/reverseprogressbar.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "reverseprogressbar.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <cpputils.h>
|
||||
|
||||
// local includes
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
ReverseProgressBar::ReverseProgressBar(int x, int y, int width, int height, int min, int max, uint32_t color) :
|
||||
m_x{x}, m_y{y}, m_width{width}, m_height{height}, m_min{min}, m_max{max}, m_color{color}
|
||||
{
|
||||
}
|
||||
|
||||
void ReverseProgressBar::start()
|
||||
{
|
||||
m_lastValue = m_x+m_width-1;
|
||||
tft.drawRect(m_x, m_y, m_width, m_height, TFT_WHITE);
|
||||
}
|
||||
|
||||
void ReverseProgressBar::redraw(int value)
|
||||
{
|
||||
value = cpputils::mapValueClamped(value, m_min, m_max, m_x+m_width-1, m_x+1);
|
||||
|
||||
if (value < m_lastValue)
|
||||
tft.fillRect(value, m_y+1, m_lastValue-value, m_height-2, m_color);
|
||||
else if (value > m_lastValue)
|
||||
tft.fillRect(m_lastValue, m_y+1, value-m_lastValue, m_height-2, TFT_BLACK);
|
||||
|
||||
m_lastValue = value;
|
||||
}
|
||||
} // namespace espgui
|
29
src/widgets/reverseprogressbar.h
Normal file
29
src/widgets/reverseprogressbar.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <cstdint>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
namespace espgui {
|
||||
class ReverseProgressBar
|
||||
{
|
||||
public:
|
||||
ReverseProgressBar(int x, int y, int width, int height, int min, int max, uint32_t color=TFT_YELLOW);
|
||||
|
||||
void start();
|
||||
void redraw(int value);
|
||||
|
||||
private:
|
||||
const int m_x;
|
||||
const int m_y;
|
||||
const int m_width;
|
||||
const int m_height;
|
||||
const int m_min;
|
||||
const int m_max;
|
||||
const uint32_t m_color;
|
||||
|
||||
int m_lastValue{};
|
||||
};
|
||||
} // namespace espgui
|
62
src/widgets/verticalmeter.cpp
Normal file
62
src/widgets/verticalmeter.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include "verticalmeter.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <cpputils.h>
|
||||
|
||||
// local includes
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
VerticalMeter::VerticalMeter(const char *text, const char *format, int x, int y) :
|
||||
m_text{text}, m_format{format}, m_x{x}, m_y{y}
|
||||
{
|
||||
}
|
||||
|
||||
void VerticalMeter::start()
|
||||
{
|
||||
int w = 36;
|
||||
tft.drawRect(m_x, m_y, w, 155, TFT_GREY);
|
||||
tft.fillRect(m_x + 2, m_y + 19, w - 3, 155 - 38, TFT_WHITE);
|
||||
tft.setTextColor(TFT_CYAN, TFT_BLACK);
|
||||
tft.drawCentreString(m_text, m_x + w / 2, m_y + 2, 2);
|
||||
|
||||
for (int i = 0; i < 110; i += 10)
|
||||
tft.drawFastHLine(m_x + 20, m_y + 27 + i, 6, TFT_BLACK);
|
||||
|
||||
for (int i = 0; i < 110; i += 50)
|
||||
tft.drawFastHLine(m_x + 20, m_y + 27 + i, 9, TFT_BLACK);
|
||||
|
||||
tft.fillTriangle(m_x + 3, m_y + 127, m_x + 3 + 16, m_y + 127, m_x + 3, m_y + 127 - 5, TFT_RED);
|
||||
tft.fillTriangle(m_x + 3, m_y + 127, m_x + 3 + 16, m_y + 127, m_x + 3, m_y + 127 + 5, TFT_RED);
|
||||
|
||||
tft.drawCentreString("---", m_x + w / 2, m_y + 155 - 18, 2);
|
||||
}
|
||||
|
||||
void VerticalMeter::redraw(float value, float min, float max)
|
||||
{
|
||||
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||
|
||||
char buf[16];
|
||||
snprintf(&buf[0], 16, m_format, value);
|
||||
tft.drawRightString(buf, m_x + 36 - 5, 187 - 27 + 155 - 18, 2);
|
||||
|
||||
const int dx = 3 + m_x;
|
||||
value = cpputils::mapValueClamped<float>(value, min, max, 0.f, 100.f);
|
||||
|
||||
while (m_oldValue > value)
|
||||
{
|
||||
const int dy = 187 + 100 - m_oldValue;
|
||||
tft.drawLine(dx, dy - 5, dx + 16, dy, TFT_WHITE);
|
||||
m_oldValue--;
|
||||
tft.drawLine(dx, dy + 6, dx + 16, dy + 1, TFT_RED);
|
||||
}
|
||||
|
||||
while (m_oldValue < value)
|
||||
{
|
||||
const int dy = 187 + 100 - m_oldValue;
|
||||
tft.drawLine(dx, dy + 5, dx + 16, dy, TFT_WHITE);
|
||||
m_oldValue++;
|
||||
tft.drawLine(dx, dy - 6, dx + 16, dy - 1, TFT_RED);
|
||||
}
|
||||
}
|
||||
}
|
23
src/widgets/verticalmeter.h
Normal file
23
src/widgets/verticalmeter.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <cstdint>
|
||||
|
||||
namespace espgui {
|
||||
class VerticalMeter
|
||||
{
|
||||
public:
|
||||
VerticalMeter(const char *text, const char *format, int x, int y);
|
||||
|
||||
void start();
|
||||
void redraw(float value, float min, float max);
|
||||
|
||||
private:
|
||||
const char * const m_text;
|
||||
const char * const m_format;
|
||||
const int m_x;
|
||||
const int m_y;
|
||||
|
||||
float m_oldValue{};
|
||||
};
|
||||
} // namespace espgui
|
135
src/widgets/vumeter.cpp
Normal file
135
src/widgets/vumeter.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include "vumeter.h"
|
||||
|
||||
// local includes
|
||||
#include "tftinstance.h"
|
||||
|
||||
namespace espgui {
|
||||
void VuMeter::start()
|
||||
{
|
||||
ltx = 0;
|
||||
osx = 120;
|
||||
osy = 120;
|
||||
|
||||
// Meter outline
|
||||
tft.fillRect(0, 0, 239, 126, TFT_GREY);
|
||||
tft.fillRect(5, 3, 230, 119, TFT_WHITE);
|
||||
|
||||
tft.setTextColor(TFT_BLACK); // Text colour
|
||||
|
||||
// Draw ticks every 5 degrees from -50 to +50 degrees (100 deg. FSD swing)
|
||||
for (int i = -50; i < 51; i += 5) {
|
||||
// Long scale tick length
|
||||
int tl = 15;
|
||||
|
||||
// Coodinates of tick to draw
|
||||
float sx = cos((i - 90) * 0.0174532925);
|
||||
float sy = sin((i - 90) * 0.0174532925);
|
||||
uint16_t x0 = sx * (100 + tl) + 120;
|
||||
uint16_t y0 = sy * (100 + tl) + 140;
|
||||
uint16_t x1 = sx * 100 + 120;
|
||||
uint16_t y1 = sy * 100 + 140;
|
||||
|
||||
// Coordinates of next tick for zone fill
|
||||
float sx2 = cos((i + 5 - 90) * 0.0174532925);
|
||||
float sy2 = sin((i + 5 - 90) * 0.0174532925);
|
||||
int x2 = sx2 * (100 + tl) + 120;
|
||||
int y2 = sy2 * (100 + tl) + 140;
|
||||
int x3 = sx2 * 100 + 120;
|
||||
int y3 = sy2 * 100 + 140;
|
||||
|
||||
// Yellow zone limits
|
||||
//if (i >= -50 && i < 0) {
|
||||
// tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_YELLOW);
|
||||
// tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_YELLOW);
|
||||
//}
|
||||
|
||||
// Green zone limits
|
||||
if (i >= 0 && i < 25) {
|
||||
tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_GREEN);
|
||||
tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_GREEN);
|
||||
}
|
||||
|
||||
// Orange zone limits
|
||||
if (i >= 25 && i < 50) {
|
||||
tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_ORANGE);
|
||||
tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_ORANGE);
|
||||
}
|
||||
|
||||
// Short scale tick length
|
||||
if (i % 25 != 0) tl = 8;
|
||||
|
||||
// Recalculate coords incase tick lenght changed
|
||||
x0 = sx * (100 + tl) + 120;
|
||||
y0 = sy * (100 + tl) + 140;
|
||||
x1 = sx * 100 + 120;
|
||||
y1 = sy * 100 + 140;
|
||||
|
||||
// Draw tick
|
||||
tft.drawLine(x0, y0, x1, y1, TFT_BLACK);
|
||||
|
||||
// Check if labels should be drawn, with position tweaks
|
||||
if (i % 25 == 0) {
|
||||
// Calculate label positions
|
||||
x0 = sx * (100 + tl + 10) + 120;
|
||||
y0 = sy * (100 + tl + 10) + 140;
|
||||
switch (i / 25) {
|
||||
case -2: tft.drawCentreString("0", x0, y0 - 12, 2); break;
|
||||
case -1: tft.drawCentreString("7.5", x0, y0 - 9, 2); break;
|
||||
case 0: tft.drawCentreString("15", x0, y0 - 6, 2); break;
|
||||
case 1: tft.drawCentreString("22.5", x0, y0 - 9, 2); break;
|
||||
case 2: tft.drawCentreString("30", x0, y0 - 12, 2); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now draw the arc of the scale
|
||||
sx = cos((i + 5 - 90) * 0.0174532925);
|
||||
sy = sin((i + 5 - 90) * 0.0174532925);
|
||||
x0 = sx * 100 + 120;
|
||||
y0 = sy * 100 + 140;
|
||||
// Draw scale arc, don't draw the last part
|
||||
if (i < 50) tft.drawLine(x0, y0, x1, y1, TFT_BLACK);
|
||||
}
|
||||
|
||||
tft.drawString("KM/h", 5 + 230 - 40, 119 - 20, 2); // Units at bottom right
|
||||
tft.drawCentreString("KM/h", 120, 70, 4); // Comment out to avoid font 4
|
||||
tft.drawRect(5, 3, 230, 119, TFT_BLACK); // Draw bezel line
|
||||
}
|
||||
|
||||
void VuMeter::redraw(float value)
|
||||
{
|
||||
tft.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
char buf[8]; dtostrf(value, 4, 0, buf);
|
||||
tft.drawRightString(buf, 50, 119 - 25, 4);
|
||||
|
||||
if (value < -3) value = -3; // Limit value to emulate needle end stops
|
||||
if (value > 33) value = 33;
|
||||
|
||||
float sdeg = map(value, -3, 33, -150, -30); // Map value to angle
|
||||
// Calcualte tip of needle coords
|
||||
float sx = cos(sdeg * 0.0174532925);
|
||||
float sy = sin(sdeg * 0.0174532925);
|
||||
|
||||
// Calculate x delta of needle start (does not start at pivot point)
|
||||
float tx = tan((sdeg + 90) * 0.0174532925);
|
||||
|
||||
// Erase old needle image
|
||||
tft.drawLine(120 + 20 * ltx - 1, 140 - 20, osx - 1, osy, TFT_WHITE);
|
||||
tft.drawLine(120 + 20 * ltx, 140 - 20, osx, osy, TFT_WHITE);
|
||||
tft.drawLine(120 + 20 * ltx + 1, 140 - 20, osx + 1, osy, TFT_WHITE);
|
||||
|
||||
// Re-plot text under needle
|
||||
tft.setTextColor(TFT_BLACK);
|
||||
tft.drawCentreString("KM/h", 120, 70, 4); // // Comment out to avoid font 4
|
||||
|
||||
// Store new needle end coords for next erase
|
||||
ltx = tx;
|
||||
osx = sx * 98 + 120;
|
||||
osy = sy * 98 + 140;
|
||||
|
||||
// Draw the needle in the new postion, magenta makes needle a bit bolder
|
||||
// draws 3 lines to thicken needle
|
||||
tft.drawLine(120 + 20 * ltx - 1, 140 - 20, osx - 1, osy, TFT_RED);
|
||||
tft.drawLine(120 + 20 * ltx, 140 - 20, osx, osy, TFT_MAGENTA);
|
||||
tft.drawLine(120 + 20 * ltx + 1, 140 - 20, osx + 1, osy, TFT_RED);
|
||||
}
|
||||
} // namespace espgui
|
17
src/widgets/vumeter.h
Normal file
17
src/widgets/vumeter.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <cstdint>
|
||||
|
||||
namespace espgui {
|
||||
class VuMeter
|
||||
{
|
||||
public:
|
||||
void start();
|
||||
void redraw(float value);
|
||||
|
||||
private:
|
||||
float ltx; // Saved x coord of bottom of needle
|
||||
uint16_t osx, osy; // Saved x & y coords
|
||||
};
|
||||
} // namespace espgui
|
Reference in New Issue
Block a user