From 2f97dab6d1fd20b50e9f8d4dff06d022ac44e4fb Mon Sep 17 00:00:00 2001 From: Hugo Saint-Vignes Date: Thu, 8 Oct 2020 16:54:32 +0200 Subject: [PATCH] [apps/shared] Add toggle buttons in Graph view Change-Id: I7548d11fb114b2605ce34d3bda0776277b79ff9d --- apps/regression/graph_view.cpp | 2 +- apps/shared/curve_view.cpp | 8 +-- apps/shared/curve_view.h | 4 +- apps/shared/dots.cpp | 4 +- apps/shared/dots.h | 6 +-- .../interactive_curve_view_controller.cpp | 9 ++-- .../interactive_curve_view_controller.h | 6 ++- apps/shared/interactive_curve_view_range.cpp | 31 ++++++++++-- apps/shared/interactive_curve_view_range.h | 14 ++++-- .../interactive_curve_view_range_delegate.h | 1 + escher/Makefile | 3 ++ escher/include/escher/button.h | 2 +- escher/include/escher/button_state.h | 24 +++++++++ escher/include/escher/switch_view.h | 15 +++--- escher/include/escher/toggleable_dot_view.h | 16 ++++++ escher/include/escher/toggleable_view.h | 15 ++++++ escher/src/button_state.cpp | 35 +++++++++++++ escher/src/switch_view.cpp | 50 ++++++++----------- escher/src/toggleable_dot_view.cpp | 41 +++++++++++++++ escher/src/toggleable_view.cpp | 6 +++ 20 files changed, 226 insertions(+), 66 deletions(-) create mode 100644 escher/include/escher/button_state.h create mode 100644 escher/include/escher/toggleable_dot_view.h create mode 100644 escher/include/escher/toggleable_view.h create mode 100644 escher/src/button_state.cpp create mode 100644 escher/src/toggleable_dot_view.cpp create mode 100644 escher/src/toggleable_view.cpp diff --git a/apps/regression/graph_view.cpp b/apps/regression/graph_view.cpp index 37ee68097..bcd1bb8c9 100644 --- a/apps/regression/graph_view.cpp +++ b/apps/regression/graph_view.cpp @@ -34,7 +34,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { for (int index = 0; index < m_store->numberOfPairsOfSeries(series); index++) { drawDot(ctx, rect, m_store->get(series, 0, index), m_store->get(series, 1, index), color); } - drawDot(ctx, rect, m_store->meanOfColumn(series, 0), m_store->meanOfColumn(series, 1), color, Size::Medium); + drawDot(ctx, rect, m_store->meanOfColumn(series, 0), m_store->meanOfColumn(series, 1), color, Size::Small); drawDot(ctx, rect, m_store->meanOfColumn(series, 0), m_store->meanOfColumn(series, 1), KDColorWhite); } } diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 676c179fb..851883d86 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -458,14 +458,14 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor KDCoordinate diameter = 0; const uint8_t * mask = nullptr; switch (size) { + case Size::Tiny: + diameter = Dots::TinyDotDiameter; + mask = (const uint8_t *)Dots::TinyDotMask; + break; case Size::Small: diameter = Dots::SmallDotDiameter; mask = (const uint8_t *)Dots::SmallDotMask; break; - case Size::Medium: - diameter = Dots::MediumDotDiameter; - mask = (const uint8_t *)Dots::MediumDotMask; - break; default: assert(size == Size::Large); diameter = Dots::LargeDotDiameter; diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index cc882b8f7..faf17ea57 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -75,11 +75,11 @@ protected: KDColor color, bool thick = true ) const; enum class Size : uint8_t { + Tiny, Small, - Medium, Large }; - void drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size = Size::Small) const; + void drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size = Size::Tiny) const; /* 'drawArrow' draws the edge of an arrow pointing to (x,y) with the * orientation (dx,dy). * The parameters defining the shape of the arrow are the length of diff --git a/apps/shared/dots.cpp b/apps/shared/dots.cpp index 0f178b44e..1dc852660 100644 --- a/apps/shared/dots.cpp +++ b/apps/shared/dots.cpp @@ -2,7 +2,7 @@ namespace Shared { -const uint8_t Dots::SmallDotMask[Dots::SmallDotDiameter][Dots::SmallDotDiameter] = { +const uint8_t Dots::TinyDotMask[Dots::TinyDotDiameter][Dots::TinyDotDiameter] = { {0xE1, 0x45, 0x0C, 0x45, 0xE1}, {0x45, 0x00, 0x00, 0x00, 0x45}, {0x00, 0x00, 0x00, 0x00, 0x00}, @@ -10,7 +10,7 @@ const uint8_t Dots::SmallDotMask[Dots::SmallDotDiameter][Dots::SmallDotDiameter] {0xE1, 0x45, 0x0C, 0x45, 0xE1}, }; -const uint8_t Dots::MediumDotMask[Dots::MediumDotDiameter][Dots::MediumDotDiameter] = { +const uint8_t Dots::SmallDotMask[Dots::SmallDotDiameter][Dots::SmallDotDiameter] = { {0xE1, 0x45, 0x0C, 0x00, 0x0C, 0x45, 0xE1}, {0x45, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x45}, {0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C}, diff --git a/apps/shared/dots.h b/apps/shared/dots.h index 07d65ff44..c42be15dc 100644 --- a/apps/shared/dots.h +++ b/apps/shared/dots.h @@ -7,10 +7,10 @@ namespace Shared { class Dots { public: - static constexpr KDCoordinate SmallDotDiameter = 5; + static constexpr KDCoordinate TinyDotDiameter = 5; + static const uint8_t TinyDotMask[TinyDotDiameter][TinyDotDiameter]; + static constexpr KDCoordinate SmallDotDiameter = 7; static const uint8_t SmallDotMask[SmallDotDiameter][SmallDotDiameter]; - static constexpr KDCoordinate MediumDotDiameter = 7; - static const uint8_t MediumDotMask[MediumDotDiameter][MediumDotDiameter]; static constexpr KDCoordinate LargeDotDiameter = 10; static const uint8_t LargeDotMask[LargeDotDiameter][LargeDotDiameter]; }; diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index e77693b4c..391435d01 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -69,6 +69,11 @@ float InteractiveCurveViewController::addMargin(float y, float range, bool isVer return y + ratio * range; } +void InteractiveCurveViewController::updateZoomButtons() { + m_autoButton.setState(m_interactiveRange->zoomAuto()); + m_normalizeButton.setState(m_interactiveRange->zoomNormalize()); +} + const char * InteractiveCurveViewController::title() { return I18n::translate(I18n::Message::GraphTab); } @@ -304,9 +309,7 @@ bool InteractiveCurveViewController::autoButtonAction() { } bool InteractiveCurveViewController::normalizeButtonAction() { - if (m_interactiveRange->zoomNormalize()) { - m_interactiveRange->setZoomNormalize(false); - } else { + if (!m_interactiveRange->zoomNormalize()) { m_interactiveRange->setZoomAuto(false); m_interactiveRange->normalize(); setCurveViewAsMainView(); diff --git a/apps/shared/interactive_curve_view_controller.h b/apps/shared/interactive_curve_view_controller.h index 455fb9284..91f8fa5e1 100644 --- a/apps/shared/interactive_curve_view_controller.h +++ b/apps/shared/interactive_curve_view_controller.h @@ -7,6 +7,7 @@ #include "range_parameter_controller.h" #include "function_zoom_and_pan_curve_view_controller.h" #include +#include namespace Shared { @@ -66,6 +67,7 @@ private: // InteractiveCurveViewRangeDelegate float addMargin(float x, float range, bool isVertical, bool isMin) override; + void updateZoomButtons() override; void setCurveViewAsMainView(); @@ -79,8 +81,8 @@ private: RangeParameterController m_rangeParameterController; FunctionZoomAndPanCurveViewController m_zoomParameterController; InteractiveCurveViewRange * m_interactiveRange; - Button m_autoButton; - Button m_normalizeButton; + ButtonState m_autoButton; + ButtonState m_normalizeButton; Button m_navigationButton; Button m_rangeButton; }; diff --git a/apps/shared/interactive_curve_view_range.cpp b/apps/shared/interactive_curve_view_range.cpp index 7a3d70d97..20793e956 100644 --- a/apps/shared/interactive_curve_view_range.cpp +++ b/apps/shared/interactive_curve_view_range.cpp @@ -11,6 +11,13 @@ using namespace Poincare; namespace Shared { +void InteractiveCurveViewRange::setDelegate(InteractiveCurveViewRangeDelegate * delegate) { + m_delegate = delegate; + if (delegate) { + m_delegate->updateZoomButtons(); + } +} + uint32_t InteractiveCurveViewRange::rangeChecksum() { float data[] = {xMin(), xMax(), yMin(), yMax()}; size_t dataLengthInBytes = sizeof(data); @@ -18,6 +25,20 @@ uint32_t InteractiveCurveViewRange::rangeChecksum() { return Ion::crc32Word((uint32_t *)data, dataLengthInBytes/sizeof(uint32_t)); } +void InteractiveCurveViewRange::setZoomAuto(bool v) { + m_zoomAuto = v; + if (m_delegate) { + m_delegate->updateZoomButtons(); + } +} + +void InteractiveCurveViewRange::setZoomNormalize(bool v) { + m_zoomNormalize = v; + if (m_delegate) { + m_delegate->updateZoomButtons(); + } +} + void InteractiveCurveViewRange::setXMin(float xMin) { MemoizedCurveViewRange::protectedSetXMin(xMin, k_lowerMaxFloat, k_upperMaxFloat); } @@ -55,7 +76,7 @@ void InteractiveCurveViewRange::zoom(float ratio, float x, float y) { float xMa = xMax(); float yMi = yMin(); float yMa = yMax(); - m_zoomAuto = false; + setZoomAuto(false); if (ratio*std::fabs(xMa-xMi) < Range1D::k_minFloat || ratio*std::fabs(yMa-yMi) < Range1D::k_minFloat) { return; } @@ -163,7 +184,7 @@ void InteractiveCurveViewRange::panToMakePointVisible(float x, float y, float to const float xRange = xMax() - xMin(); const float leftMargin = leftMarginRatio * xRange; if (x < xMin() + leftMargin) { - m_zoomAuto = false; + setZoomAuto(false); /* The panning increment is a whole number of pixels so that the caching * for cartesian functions is not invalidated. */ const float newXMin = std::floor((x - leftMargin - xMin()) / pixelWidth) * pixelWidth + xMin(); @@ -172,7 +193,7 @@ void InteractiveCurveViewRange::panToMakePointVisible(float x, float y, float to } const float rightMargin = rightMarginRatio * xRange; if (x > xMax() - rightMargin) { - m_zoomAuto = false; + setZoomAuto(false); const float newXMax = std::ceil((x + rightMargin - xMax()) / pixelWidth) * pixelWidth + xMax(); m_xRange.setMax(newXMax, k_lowerMaxFloat, k_upperMaxFloat); MemoizedCurveViewRange::protectedSetXMin(xMax() - xRange, k_lowerMaxFloat, k_upperMaxFloat); @@ -182,14 +203,14 @@ void InteractiveCurveViewRange::panToMakePointVisible(float x, float y, float to const float yRange = yMax() - yMin(); const float bottomMargin = bottomMarginRatio * yRange; if (y < yMin() + bottomMargin) { - m_zoomAuto = false; + setZoomAuto(false); const float newYMin = y - bottomMargin; m_yRange.setMax(newYMin + yRange, k_lowerMaxFloat, k_upperMaxFloat); MemoizedCurveViewRange::protectedSetYMin(newYMin, k_lowerMaxFloat, k_upperMaxFloat); } const float topMargin = topMarginRatio * yRange; if (y > yMax() - topMargin) { - m_zoomAuto = false; + setZoomAuto(false); m_yRange.setMax(y + topMargin, k_lowerMaxFloat, k_upperMaxFloat); MemoizedCurveViewRange::protectedSetYMin(yMax() - yRange, k_lowerMaxFloat, k_upperMaxFloat); } diff --git a/apps/shared/interactive_curve_view_range.h b/apps/shared/interactive_curve_view_range.h index 0014d3dc1..9608f1bee 100644 --- a/apps/shared/interactive_curve_view_range.h +++ b/apps/shared/interactive_curve_view_range.h @@ -13,21 +13,25 @@ class InteractiveCurveViewRange : public MemoizedCurveViewRange { public: InteractiveCurveViewRange(InteractiveCurveViewRangeDelegate * delegate = nullptr) : MemoizedCurveViewRange(), - m_delegate(delegate), + m_delegate(nullptr), m_zoomAuto(true), m_zoomNormalize(false) - {} + { + if (delegate) { + setDelegate(delegate); + } + } static constexpr float NormalYXRatio() { return NormalizedYHalfRange(1.f) / NormalizedXHalfRange(1.f); } bool isOrthonormal(float tolerance = 2 * FLT_EPSILON) const; - void setDelegate(InteractiveCurveViewRangeDelegate * delegate) { m_delegate = delegate; } + void setDelegate(InteractiveCurveViewRangeDelegate * delegate); uint32_t rangeChecksum() override; bool zoomAuto() const { return m_zoomAuto; } - void setZoomAuto(bool v) { m_zoomAuto = v; } + void setZoomAuto(bool v); bool zoomNormalize() const { return m_zoomNormalize; } - void setZoomNormalize(bool v) { m_zoomNormalize = v; } + void setZoomNormalize(bool v); // MemoizedCurveViewRange float xGridUnit() const override { return m_zoomNormalize ? yGridUnit() : MemoizedCurveViewRange::xGridUnit(); } diff --git a/apps/shared/interactive_curve_view_range_delegate.h b/apps/shared/interactive_curve_view_range_delegate.h index 0fcbea735..6dfb2c9a0 100644 --- a/apps/shared/interactive_curve_view_range_delegate.h +++ b/apps/shared/interactive_curve_view_range_delegate.h @@ -14,6 +14,7 @@ public: virtual bool defaultRangeIsNormalized() const { return false; } virtual void interestingRanges(InteractiveCurveViewRange * range) const { assert(false); } virtual float addMargin(float x, float range, bool isVertical, bool isMin) = 0; + virtual void updateZoomButtons() = 0; }; } diff --git a/escher/Makefile b/escher/Makefile index 421fbed1e..bc76d8937 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -7,6 +7,7 @@ escher_src += $(addprefix escher/src/,\ bordered.cpp \ buffer_text_view.cpp \ button.cpp \ + button_state.cpp \ button_row_controller.cpp \ chevron_view.cpp \ clipboard.cpp \ @@ -81,6 +82,8 @@ escher_src += $(addprefix escher/src/,\ text_view.cpp \ tiled_view.cpp \ timer.cpp \ + toggleable_dot_view.cpp \ + toggleable_view.cpp \ toolbox.cpp \ transparent_view.cpp \ view.cpp \ diff --git a/escher/include/escher/button.h b/escher/include/escher/button.h index f773c5bfc..aa6abbe8f 100644 --- a/escher/include/escher/button.h +++ b/escher/include/escher/button.h @@ -21,13 +21,13 @@ public: KDSize minimalSizeForOptimalDisplay() const override; protected: MessageTextView m_messageTextView; + void layoutSubviews(bool force = false) override; private: constexpr static KDCoordinate k_verticalMargin = 5; constexpr static KDCoordinate k_horizontalMarginSmall = 10; constexpr static KDCoordinate k_horizontalMarginLarge = 20; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; - void layoutSubviews(bool force = false) override; Invocation m_invocation; const KDFont * m_font; }; diff --git a/escher/include/escher/button_state.h b/escher/include/escher/button_state.h new file mode 100644 index 000000000..34bb5b55f --- /dev/null +++ b/escher/include/escher/button_state.h @@ -0,0 +1,24 @@ +#ifndef ESCHER_BUTTON_STATE_H +#define ESCHER_BUTTON_STATE_H + +#include +#include + +class ButtonState : public Button { +public: + using Button::Button; + void setState(bool state) { m_stateView.setState(state); } + KDSize minimalSizeForOptimalDisplay() const override; + void drawRect(KDContext * ctx, KDRect rect) const override; +private: + // Dot right margin. + constexpr static KDCoordinate k_stateMargin = 9; + // Dot vertical position offset. + constexpr static KDCoordinate k_verticalOffset = 5; + int numberOfSubviews() const override { return 2; } + View * subviewAtIndex(int index) override; + void layoutSubviews(bool force = false) override; + ToggleableDotView m_stateView; +}; + +#endif diff --git a/escher/include/escher/switch_view.h b/escher/include/escher/switch_view.h index 482697cc5..23fa375f4 100644 --- a/escher/include/escher/switch_view.h +++ b/escher/include/escher/switch_view.h @@ -1,22 +1,21 @@ #ifndef ESCHER_SWITCH_VIEW_H #define ESCHER_SWITCH_VIEW_H -#include +#include +#include -class SwitchView : public TransparentView { + +class SwitchView final : public ToggleableView { public: - SwitchView(); - bool state(); - void setState(bool state); - void drawRect(KDContext * ctx, KDRect rect) const override; - KDSize minimalSizeForOptimalDisplay() const override; + using ToggleableView::ToggleableView; /* k_switchHeight and k_switchWidth are the dimensions of the switch * (including the outline of the switch). */ constexpr static KDCoordinate k_onOffSize = 12; constexpr static KDCoordinate k_switchHeight = 12; constexpr static KDCoordinate k_switchWidth = 22; + KDSize minimalSizeForOptimalDisplay() const override { return KDSize(k_switchWidth, k_switchHeight); } private: - bool m_state; + void drawRect(KDContext * ctx, KDRect rect) const override; }; #endif diff --git a/escher/include/escher/toggleable_dot_view.h b/escher/include/escher/toggleable_dot_view.h new file mode 100644 index 000000000..c6ec4d5c0 --- /dev/null +++ b/escher/include/escher/toggleable_dot_view.h @@ -0,0 +1,16 @@ +#ifndef ESCHER_TOGGLEABLE_DOT_VIEW_H +#define ESCHER_TOGGLEABLE_DOT_VIEW_H + +#include + +class ToggleableDotView final : public ToggleableView { +public: + using ToggleableView::ToggleableView; + /* k_dotSize is the dimensions of the toggle dot */ + constexpr static KDCoordinate k_dotSize = 8; + KDSize minimalSizeForOptimalDisplay() const override { return KDSize(k_dotSize, k_dotSize); } +private: + void drawRect(KDContext * ctx, KDRect rect) const override; +}; + +#endif \ No newline at end of file diff --git a/escher/include/escher/toggleable_view.h b/escher/include/escher/toggleable_view.h new file mode 100644 index 000000000..34a7ef996 --- /dev/null +++ b/escher/include/escher/toggleable_view.h @@ -0,0 +1,15 @@ +#ifndef ESCHER_TOGGLEABLE_VIEW_H +#define ESCHER_TOGGLEABLE_VIEW_H + +#include + +class ToggleableView : public TransparentView { +public: + ToggleableView() : m_state(true) {} + bool state() { return m_state; } + void setState(bool state); +protected: + bool m_state; +}; + +#endif \ No newline at end of file diff --git a/escher/src/button_state.cpp b/escher/src/button_state.cpp new file mode 100644 index 000000000..e5c276ff4 --- /dev/null +++ b/escher/src/button_state.cpp @@ -0,0 +1,35 @@ +#include +#include +#include + +View * ButtonState::subviewAtIndex(int index) { + assert(index >= 0 && index < 2); + if (index == 0) { + return &m_messageTextView; + } + return &m_stateView; +} + +void ButtonState::layoutSubviews(bool force) { + KDSize textSize = Button::minimalSizeForOptimalDisplay(); + KDRect textRect = KDRect(0, 0, textSize.width(), bounds().height()); + // State view will be vertically centered and aligned on the left + KDSize stateSize = m_stateView.minimalSizeForOptimalDisplay(); + KDRect stateRect = KDRect(textSize.width(), k_verticalOffset, stateSize.width(), stateSize.height()); + + m_messageTextView.setFrame(textRect, force); + m_stateView.setFrame(stateRect, force); +} + +void ButtonState::drawRect(KDContext * ctx, KDRect rect) const { + KDColor backColor = isHighlighted() ? highlightedBackgroundColor() : KDColorWhite; + ctx->fillRect(bounds(), backColor); +} + +KDSize ButtonState::minimalSizeForOptimalDisplay() const { + KDSize textSize = Button::minimalSizeForOptimalDisplay(); + KDSize stateSize = m_stateView.minimalSizeForOptimalDisplay(); + return KDSize( + textSize.width() + stateSize.width() + k_stateMargin, + std::max(textSize.height(), stateSize.height())); +} diff --git a/escher/src/switch_view.cpp b/escher/src/switch_view.cpp index e336d30cf..b59be0c6a 100644 --- a/escher/src/switch_view.cpp +++ b/escher/src/switch_view.cpp @@ -1,5 +1,4 @@ #include -#include const uint8_t switchMask[SwitchView::k_switchHeight][SwitchView::k_switchWidth] = { {0xFF, 0xFF, 0xE1, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xE1, 0xFF, 0xFF}, @@ -32,37 +31,28 @@ const uint8_t onOffMask[SwitchView::k_onOffSize][SwitchView::k_onOffSize] = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, }; -SwitchView::SwitchView() : -m_state(true) -{ -} - -bool SwitchView::state() { - return m_state; -} - -void SwitchView::setState(bool state) { - m_state = state; - markRectAsDirty(bounds()); -} - void SwitchView::drawRect(KDContext * ctx, KDRect rect) const { - /* Draw the switch aligned on the right of the view and vertically centered. + /* Draw the view aligned on the right of the view and vertically centered * The heightCenter is the coordinate of the vertical middle of the view. That - * way, (heightCenter-switchHalfHeight) indicates the top the switch. */ + * way, (heightCenter-halfHeight) indicates the top of the StateView. */ KDCoordinate width = bounds().width(); - KDCoordinate heightCenter = bounds().height()/2; - KDCoordinate switchHalfHeight = k_switchHeight/2; - KDColor switchWorkingBuffer[SwitchView::k_switchWidth*SwitchView::k_switchHeight]; + KDCoordinate heightCenter = bounds().height() / 2; + KDCoordinate halfHeight = k_switchHeight / 2; + KDColor workingBuffer[k_switchWidth * k_switchHeight]; + + KDRect frame(width - k_switchWidth, heightCenter - halfHeight, k_switchWidth, k_switchHeight); + ctx->blendRectWithMask( + frame, + m_state ? Palette::YellowDark : Palette::GrayDark, + reinterpret_cast(switchMask), + workingBuffer); + - KDColor mainColor = m_state ? Palette::YellowDark : Palette::GrayDark; - KDRect frame(width - k_switchWidth, heightCenter -switchHalfHeight, k_switchWidth, k_switchHeight); - ctx->blendRectWithMask(frame, mainColor, (const uint8_t *)switchMask, switchWorkingBuffer); KDCoordinate onOffX = width - (m_state ? k_onOffSize : k_switchWidth); - KDRect onOffFrame(onOffX, heightCenter -switchHalfHeight, k_onOffSize, k_onOffSize); - ctx->blendRectWithMask(onOffFrame, KDColorWhite, (const uint8_t *)onOffMask, switchWorkingBuffer); -} - -KDSize SwitchView::minimalSizeForOptimalDisplay() const { - return KDSize(k_switchWidth, k_switchHeight); -} + KDRect onOffFrame(onOffX, heightCenter - halfHeight, k_onOffSize, k_onOffSize); + ctx->blendRectWithMask( + onOffFrame, + KDColorWhite, + reinterpret_cast(onOffMask), + workingBuffer); +} \ No newline at end of file diff --git a/escher/src/toggleable_dot_view.cpp b/escher/src/toggleable_dot_view.cpp new file mode 100644 index 000000000..3195ae1f4 --- /dev/null +++ b/escher/src/toggleable_dot_view.cpp @@ -0,0 +1,41 @@ +#include +#include + +const uint8_t MediumDotMask[ToggleableDotView::k_dotSize][ToggleableDotView::k_dotSize] = { + {0xFF, 0xDB, 0x53, 0x0F, 0x0F, 0x53, 0xDB, 0xFF}, + {0xD8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0xD8}, + {0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53}, + {0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C}, + {0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C}, + {0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53}, + {0xD7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0xD7}, + {0xFF, 0xD8, 0x53, 0x0C, 0x0C, 0x53, 0xD8, 0xFF}, +}; + +const uint8_t MediumShallowDotMask[ToggleableDotView::k_dotSize][ToggleableDotView::k_dotSize] = { + {0xFF, 0xDB, 0x53, 0x0F, 0x0F, 0x53, 0xDB, 0xFF}, + {0xD8, 0x17, 0x90, 0xEC, 0xEC, 0x90, 0x17, 0xD8}, + {0x53, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0x88, 0x53}, + {0x0F, 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0x0C}, + {0x0F, 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0x0C}, + {0x53, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0x88, 0x53}, + {0xD7, 0x17, 0x90, 0xEF, 0xEF, 0x90, 0x17, 0xD7}, + {0xFF, 0xD8, 0x53, 0x0C, 0x0C, 0x53, 0xD8, 0xFF}, +}; + +void ToggleableDotView::drawRect(KDContext * ctx, KDRect rect) const { + /* Draw the view aligned on the right of the view and vertically centered + * The heightCenter is the coordinate of the vertical middle of the view. That + * way, (heightCenter-halfHeight) indicates the top of the StateView. */ + KDCoordinate width = bounds().width(); + KDCoordinate heightCenter = bounds().height() / 2; + KDCoordinate halfHeight = k_dotSize / 2; + KDColor workingBuffer[k_dotSize * k_dotSize]; + + KDRect frame(width - k_dotSize, heightCenter - halfHeight, k_dotSize, k_dotSize); + ctx->blendRectWithMask( + frame, + m_state ? Palette::YellowDark : Palette::GrayDark, + m_state ? reinterpret_cast(MediumDotMask) : reinterpret_cast(MediumShallowDotMask), + workingBuffer); +} \ No newline at end of file diff --git a/escher/src/toggleable_view.cpp b/escher/src/toggleable_view.cpp new file mode 100644 index 000000000..2e2660277 --- /dev/null +++ b/escher/src/toggleable_view.cpp @@ -0,0 +1,6 @@ +#include + +void ToggleableView::setState(bool state) { + m_state = state; + markRectAsDirty(bounds()); +} \ No newline at end of file