mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[home] Added support for a wallpaper in a special format (.obm)
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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>
|
||||
|
||||
20
escher/include/escher/background_view.h
Normal file
20
escher/include/escher/background_view.h
Normal 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
|
||||
20
escher/include/escher/icon_view.h
Normal file
20
escher/include/escher/icon_view.h
Normal 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
|
||||
@@ -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:
|
||||
|
||||
65
escher/src/background_view.cpp
Normal file
65
escher/src/background_view.cpp
Normal 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
79
escher/src/icon_view.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user