[home] Added support for a wallpaper in a special format (.obm)

This commit is contained in:
Laury
2021-07-06 14:54:55 +02:00
parent 6f797833b2
commit 649f48919e
15 changed files with 292 additions and 30 deletions

View File

@@ -22,6 +22,7 @@ endif
escher_src += $(addprefix escher/src/,\
alternate_empty_view_controller.cpp \
app.cpp \
background_view.cpp \
bank_view_controller.cpp \
bordered.cpp \
buffer_text_view.cpp \
@@ -46,6 +47,7 @@ escher_src += $(addprefix escher/src/,\
expression_view.cpp \
highlight_cell.cpp \
gauge_view.cpp \
icon_view.cpp \
image_view.cpp \
input_event_handler.cpp \
invocation.cpp \

View File

@@ -3,6 +3,7 @@
#include <escher/alternate_empty_view_controller.h>
#include <escher/alternate_empty_view_delegate.h>
#include <escher/background_view.h>
#include <escher/bank_view_controller.h>
#include <escher/buffer_text_view.h>
#include <escher/button.h>
@@ -26,6 +27,7 @@
#include <escher/expression_view.h>
#include <escher/gauge_view.h>
#include <escher/highlight_cell.h>
#include <escher/icon_view.h>
#include <escher/image.h>
#include <escher/image_view.h>
#include <escher/input_event_handler.h>

View File

@@ -0,0 +1,20 @@
#ifndef ESCHER_BACKGROUND_VIEW_H
#define ESCHER_BACKGROUND_VIEW_H
#include <escher/view.h>
#include <archive.h>
class BackgroundView : public View {
public:
BackgroundView();
void drawRect(KDContext * ctx, KDRect rect) const override;
void setBackgroundImage(const uint8_t * data);
void setDefaultColor(KDColor defaultColor);
void updateDataValidity();
private:
const uint8_t * m_data;
bool m_isDataValid;
KDColor m_defaultColor;
};
#endif

View File

@@ -0,0 +1,20 @@
#ifndef ESCHER_ICON_VIEW_H
#define ESCHER_ICON_VIEW_H
#include <escher/view.h>
#include <escher/image.h>
class IconView : public View {
//Unlike the ImageView class, IconView displays an image with rounded corners
public:
IconView();
void setImage(const Image * image);
void setImage(const uint8_t *data, size_t dataLength);
void drawRect(KDContext * ctx, KDRect rect) const override;
private:
const Image * m_image;
const uint8_t * m_data;
size_t m_dataLength;
};
#endif

View File

@@ -96,25 +96,6 @@ public:
void scrollToContentPoint(KDPoint p, bool allowOverscroll = false);
void scrollToContentRect(KDRect rect, bool allowOverscroll = false); // Minimal scrolling to make this rect visible
protected:
KDCoordinate maxContentWidthDisplayableWithoutScrolling() const {
return m_frame.width() - m_leftMargin - m_rightMargin;
}
KDCoordinate maxContentHeightDisplayableWithoutScrolling() const {
return m_frame.height() - m_topMargin - m_bottomMargin;
}
KDRect visibleContentRect();
void layoutSubviews(bool force = false) override;
virtual KDSize contentSize() const { return m_contentView->minimalSizeForOptimalDisplay(); }
#if ESCHER_VIEW_LOGGING
const char * className() const override;
void logAttributes(std::ostream &os) const override;
#endif
View * m_contentView;
private:
ScrollViewDataSource * m_dataSource;
int numberOfSubviews() const override { return 1 + const_cast<ScrollView *>(this)->decorator()->numberOfIndicators(); }
View * subviewAtIndex(int index) override { return (index == 0) ? &m_innerView : decorator()->indicatorAtIndex(index); }
class InnerView : public View {
public:
InnerView(ScrollView * scrollView) : View(), m_scrollView(scrollView) {}
@@ -127,13 +108,33 @@ private:
}
const ScrollView * m_scrollView;
};
KDCoordinate maxContentWidthDisplayableWithoutScrolling() const {
return m_frame.width() - m_leftMargin - m_rightMargin;
}
KDCoordinate maxContentHeightDisplayableWithoutScrolling() const {
return m_frame.height() - m_topMargin - m_bottomMargin;
}
KDRect visibleContentRect();
void layoutSubviews(bool force = false) override;
virtual KDSize contentSize() const { return m_contentView->minimalSizeForOptimalDisplay(); }
virtual InnerView * getInnerView() { return &m_innerView; }
#if ESCHER_VIEW_LOGGING
const char * className() const override;
void logAttributes(std::ostream &os) const override;
#endif
View * m_contentView;
InnerView m_innerView;
private:
ScrollViewDataSource * m_dataSource;
int numberOfSubviews() const override { return 1 + const_cast<ScrollView *>(this)->decorator()->numberOfIndicators(); }
View * subviewAtIndex(int index) override { return (index == 0) ? &m_innerView : decorator()->indicatorAtIndex(index); }
KDCoordinate m_topMargin;
KDCoordinate m_rightMargin;
KDCoordinate m_bottomMargin;
KDCoordinate m_leftMargin;
InnerView m_innerView;
Decorator::Type m_decoratorType;
union Decorators {
public:

View File

@@ -0,0 +1,65 @@
#include <escher/background_view.h>
#include <ion.h>
#include <kandinsky/ion_context.h>
#include <escher/palette.h>//AND THIS
#include "apps/home/controller.h"
#ifdef HOME_DISPLAY_EXTERNALS
#include "apps/external/external_icon.h"
#include "apps/external/archive.h"
#include <string.h>
#endif
//To store the Omega backgrounds, we use a specific file in the "OmegaBitMap" format.
//Here is its header
struct OBMHeader
{
uint32_t signature; //Normally it is 32145
int32_t width;
int32_t height;
const KDColor image_data;
};
BackgroundView::BackgroundView():
m_data(nullptr),
m_isDataValid(false),
m_defaultColor(Palette::BackgroundHard)
{
}
void BackgroundView::setBackgroundImage(const uint8_t * data) {
m_data = data;
updateDataValidity();
markRectAsDirty(bounds());
}
void BackgroundView::setDefaultColor(KDColor defaultColor) {
m_defaultColor = defaultColor;
}
void BackgroundView::drawRect(KDContext * ctx, KDRect rect) const {
if(!m_isDataValid) {
ctx->fillRect(rect, m_defaultColor);
return;
}
OBMHeader* h = (OBMHeader*)m_data;
int yrectToImage = ctx->origin().y() - m_frame.y();
int xrectToImage = ctx->origin().x() - m_frame.x();
for (int line = rect.y(); line <= rect.bottom(); line++) {
int offset = ((line + yrectToImage) * h->width) + (rect.x() + xrectToImage);
ctx->fillRectWithPixels(KDRect(rect.x(), line, rect.width(), 1), &(h->image_data) + offset, nullptr);
}
}
void BackgroundView::updateDataValidity() {
if(m_data == nullptr || KDIonContext::sharedContext()->gammaEnabled) {
m_isDataValid = false;
return;
}
OBMHeader* h = (OBMHeader*)m_data;
m_isDataValid = h->signature==466512775 && h->height==m_frame.height() && h->width==m_frame.width();
}

79
escher/src/icon_view.cpp Normal file
View File

@@ -0,0 +1,79 @@
#include <escher/icon_view.h>
extern "C" {
#include <assert.h>
}
#include <ion.h>
#include <kandinsky.h>
IconView::IconView() :
View(),
m_image(nullptr)
{
}
constexpr static int iconBufferSize = 3080;
// Icon file is 55 x 56 = 3080
void IconView::drawRect(KDContext * ctx, KDRect rect) const {
const uint8_t* data;
size_t size;
if (m_image != nullptr) {
assert(bounds().width() == m_image->width());
assert(bounds().height() == m_image->height());
assert(bounds().width() == 55);
assert(bounds().height() == 56);
data = m_image->compressedPixelData();
size = m_image->compressedPixelDataSize();
} else if (m_data != nullptr) {
data = m_data;
size = m_dataLength;
} else {
return;
}
KDColor pixelBuffer[iconBufferSize];
assert(Ion::stackSafe()); // That's a VERY big buffer we're allocating on the stack
Ion::decompress(
data,
reinterpret_cast<uint8_t *>(pixelBuffer),
size,
iconBufferSize * sizeof(KDColor)
);
//We push the first 6 lines of the image so that they are truncated on the sides
ctx->fillRectWithPixels(KDRect(6, 0, m_frame.width()-12, 1),pixelBuffer+6, nullptr);
ctx->fillRectWithPixels(KDRect(4, 1, m_frame.width()-8, 1),pixelBuffer+6+55, nullptr);
ctx->fillRectWithPixels(KDRect(3, 2, m_frame.width()-6, 1),pixelBuffer+3+(2*55), nullptr);
ctx->fillRectWithPixels(KDRect(2, 3, m_frame.width()-4, 1),pixelBuffer+2+(3*55), nullptr);
ctx->fillRectWithPixels(KDRect(1, 4, m_frame.width()-2, 1),pixelBuffer+1+(4*55), nullptr);
ctx->fillRectWithPixels(KDRect(1, 5, m_frame.width()-2, 1),pixelBuffer+1+(5*55), nullptr);
//Then we push the rectangular part of the image
ctx->fillRectWithPixels(KDRect(0, 6, m_frame.width(), 44),pixelBuffer+(6*55), nullptr);
//Finaly we push the last 5 lines of the image so that they are truncated on the sides
ctx->fillRectWithPixels(KDRect(1, 50, m_frame.width()-2, 1),pixelBuffer+1+(50*55), nullptr);
ctx->fillRectWithPixels(KDRect(1, 51, m_frame.width()-2, 1),pixelBuffer+1+(51*55), nullptr);
ctx->fillRectWithPixels(KDRect(2, 52, m_frame.width()-4, 1),pixelBuffer+2+(52*55), nullptr);
ctx->fillRectWithPixels(KDRect(3, 53, m_frame.width()-6, 1),pixelBuffer+3+(53*55), nullptr);
ctx->fillRectWithPixels(KDRect(4, 54, m_frame.width()-8, 1),pixelBuffer+4+(54*55), nullptr);
ctx->fillRectWithPixels(KDRect(6, 55, m_frame.width()-12, 1),pixelBuffer+6+(55*55), nullptr);
}
void IconView::setImage(const uint8_t *data, size_t dataLength) {
if (data != m_data && dataLength != m_dataLength) {
m_data = data;
m_dataLength = dataLength;
markRectAsDirty(bounds());
}
}
void IconView::setImage(const Image * image) {
if (image != m_image) {
m_image = image;
markRectAsDirty(bounds());
}
}

View File

@@ -9,12 +9,12 @@ extern "C" {
ScrollView::ScrollView(View * contentView, ScrollViewDataSource * dataSource) :
View(),
m_contentView(contentView),
m_innerView(this),
m_dataSource(dataSource),
m_topMargin(0),
m_rightMargin(0),
m_bottomMargin(0),
m_leftMargin(0),
m_innerView(this),
m_decorators(),
m_backgroundColor(Palette::BackgroundApps)
{
@@ -24,12 +24,12 @@ ScrollView::ScrollView(View * contentView, ScrollViewDataSource * dataSource) :
ScrollView::ScrollView(ScrollView&& other) :
m_contentView(other.m_contentView),
m_innerView(this),
m_dataSource(other.m_dataSource),
m_topMargin(other.m_topMargin),
m_rightMargin(other.m_rightMargin),
m_bottomMargin(other.m_bottomMargin),
m_leftMargin(other.m_leftMargin),
m_innerView(this),
m_backgroundColor(other.m_backgroundColor)
{
setDecoratorType(other.m_decoratorType);
@@ -144,7 +144,7 @@ void ScrollView::layoutSubviews(bool force) {
if (!r2.isEmpty()) {
markRectAsDirty(r2);
}
m_innerView.setFrame(innerFrame, force);
getInnerView()->setFrame(innerFrame, force);
KDPoint absoluteOffset = contentOffset().opposite().translatedBy(KDPoint(m_leftMargin - innerFrame.x(), m_topMargin - innerFrame.y()));
KDRect contentFrame = KDRect(absoluteOffset, contentSize());
m_contentView->setFrame(contentFrame, force);