mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[app/external] External apps on home menu.
This commit is contained in:
8
Makefile
8
Makefile
@@ -22,6 +22,14 @@ ifdef FORCE_EXTERNAL
|
||||
apps_list = ${EPSILON_APPS}
|
||||
endif
|
||||
|
||||
ifdef HOME_DISPLAY_EXTERNALS
|
||||
ifneq ($(filter external,$(apps_list)),)
|
||||
SFLAGS += -DHOME_DISPLAY_EXTERNALS
|
||||
else
|
||||
$(warning HOME_DISPLAY_EXTERNALS is set but external isn't included, ignoring flag.)
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: info
|
||||
info:
|
||||
@echo "EPSILON_VERSION = $(EPSILON_VERSION)"
|
||||
|
||||
14
apps/external/Makefile
vendored
14
apps/external/Makefile
vendored
@@ -1,3 +1,12 @@
|
||||
ifdef HOME_DISPLAY_EXTERNALS
|
||||
|
||||
app_external_src = $(addprefix apps/external/,\
|
||||
extapp_api.cpp \
|
||||
archive.cpp \
|
||||
)
|
||||
|
||||
else
|
||||
|
||||
apps += External::App
|
||||
app_headers += apps/external/app.h
|
||||
|
||||
@@ -9,6 +18,10 @@ app_external_src = $(addprefix apps/external/,\
|
||||
pointer_text_table_cell.cpp \
|
||||
)
|
||||
|
||||
$(eval $(call depends_on_image,apps/external/app.cpp,apps/external/external_icon.png))
|
||||
|
||||
endif
|
||||
|
||||
SFLAGS += -Iapps/external/
|
||||
|
||||
EXTAPP_PATH ?= apps/external/app/
|
||||
@@ -34,4 +47,3 @@ i18n_files += $(addprefix apps/external/,\
|
||||
base.universal.i18n\
|
||||
)
|
||||
|
||||
$(eval $(call depends_on_image,apps/external/app.cpp,apps/external/external_icon.png))
|
||||
|
||||
43
apps/external/archive.cpp
vendored
43
apps/external/archive.cpp
vendored
@@ -115,9 +115,44 @@ size_t numberOfFiles() {
|
||||
return count;
|
||||
}
|
||||
|
||||
bool executableAtIndex(size_t index, File &entry) {
|
||||
File dummy;
|
||||
size_t count;
|
||||
size_t final_count = 0;
|
||||
|
||||
for (count = 0; fileAtIndex(count, dummy); count++) {
|
||||
if (dummy.isExecutable) {
|
||||
if (final_count == index) {
|
||||
entry = dummy;
|
||||
return true;
|
||||
}
|
||||
final_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t numberOfExecutables() {
|
||||
File dummy;
|
||||
size_t count;
|
||||
size_t final_count = 0;
|
||||
|
||||
for (count = 0; fileAtIndex(count, dummy); count++)
|
||||
if (dummy.isExecutable)
|
||||
final_count++;
|
||||
|
||||
return final_count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
bool fileAtIndex(size_t index, File &entry) {
|
||||
if (index != 0)
|
||||
return false;
|
||||
|
||||
entry.name = "Built-in";
|
||||
entry.data = NULL;
|
||||
entry.dataLength = 0;
|
||||
@@ -125,6 +160,14 @@ bool fileAtIndex(size_t index, File &entry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool executableAtIndex(size_t index, File &entry) {
|
||||
return fileAtIndex(index, entry);
|
||||
}
|
||||
|
||||
size_t numberOfExecutables() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" void extapp_main(void);
|
||||
|
||||
uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) {
|
||||
|
||||
2
apps/external/archive.h
vendored
2
apps/external/archive.h
vendored
@@ -19,6 +19,8 @@ struct File {
|
||||
bool fileAtIndex(size_t index, File &entry);
|
||||
int indexFromName(const char *name);
|
||||
size_t numberOfFiles();
|
||||
size_t numberOfExecutables();
|
||||
bool executableAtIndex(size_t index, File &entry);
|
||||
uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize);
|
||||
|
||||
}
|
||||
|
||||
@@ -24,9 +24,18 @@ App::Descriptor * App::Snapshot::descriptor() {
|
||||
return &descriptor;
|
||||
}
|
||||
|
||||
void App::didBecomeActive(Window * window) {
|
||||
::App::didBecomeActive(window);
|
||||
m_window = window;
|
||||
}
|
||||
|
||||
void App::redraw() {
|
||||
m_window->redraw(true);
|
||||
}
|
||||
|
||||
App::App(Snapshot * snapshot) :
|
||||
::App(snapshot, &m_controller, I18n::Message::Warning),
|
||||
m_controller(&m_modalViewController, snapshot)
|
||||
m_controller(&m_modalViewController, snapshot, this)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ public:
|
||||
App * unpack(Container * container) override;
|
||||
Descriptor * descriptor() override;
|
||||
};
|
||||
void redraw();
|
||||
virtual void didBecomeActive(Window * window);
|
||||
static App * app() {
|
||||
return static_cast<App *>(Container::activeApp());
|
||||
}
|
||||
@@ -25,9 +27,18 @@ public:
|
||||
return static_cast<Snapshot *>(::App::snapshot());
|
||||
}
|
||||
TELEMETRY_ID("Home");
|
||||
#if HOME_DISPLAY_EXTERNALS
|
||||
int heapSize() { return k_externalHeapSize; }
|
||||
char * heap() { return m_externalHeap; }
|
||||
#endif
|
||||
private:
|
||||
App(Snapshot * snapshot);
|
||||
Controller m_controller;
|
||||
#if HOME_DISPLAY_EXTERNALS
|
||||
static constexpr int k_externalHeapSize = 80000;
|
||||
char m_externalHeap[k_externalHeapSize];
|
||||
#endif
|
||||
Window * m_window;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,12 @@ void AppCell::layoutSubviews(bool force) {
|
||||
m_nameView.setFrame(KDRect((bounds().width()-nameSize.width())/2-k_nameWidthMargin, bounds().height()-nameSize.height() - 2*k_nameHeightMargin, nameSize.width()+2*k_nameWidthMargin, nameSize.height()+2*k_nameHeightMargin), force);
|
||||
}
|
||||
|
||||
void AppCell::setExtAppDescriptor(const char* name) {
|
||||
// m_iconView.setImage(descriptor->icon());
|
||||
m_nameView.setText(name);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void AppCell::setAppDescriptor(::App::Descriptor * descriptor) {
|
||||
m_iconView.setImage(descriptor->icon());
|
||||
m_nameView.setMessage(descriptor->name());
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
void setVisible(bool visible);
|
||||
void reloadCell() override;
|
||||
void setAppDescriptor(::App::Descriptor * appDescriptor);
|
||||
void setExtAppDescriptor(const char* name);
|
||||
private:
|
||||
static constexpr KDCoordinate k_iconMargin = 22;
|
||||
static constexpr KDCoordinate k_iconWidth = 55;
|
||||
|
||||
@@ -6,6 +6,10 @@ extern "C" {
|
||||
#include <assert.h>
|
||||
}
|
||||
|
||||
#ifdef HOME_DISPLAY_EXTERNALS
|
||||
#include "../external/archive.h"
|
||||
#endif
|
||||
|
||||
namespace Home {
|
||||
|
||||
Controller::ContentView::ContentView(Controller * controller, SelectableTableViewDataSource * selectionDataSource) :
|
||||
@@ -49,16 +53,45 @@ void Controller::ContentView::layoutSubviews(bool force) {
|
||||
m_selectableTableView.setFrame(bounds(), force);
|
||||
}
|
||||
|
||||
Controller::Controller(Responder * parentResponder, SelectableTableViewDataSource * selectionDataSource) :
|
||||
Controller::Controller(Responder * parentResponder, SelectableTableViewDataSource * selectionDataSource, ::App * app) :
|
||||
ViewController(parentResponder),
|
||||
m_view(this, selectionDataSource)
|
||||
{
|
||||
m_app = app;
|
||||
}
|
||||
|
||||
bool Controller::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
AppsContainer * container = AppsContainer::sharedAppsContainer();
|
||||
::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1);
|
||||
|
||||
int index = selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1;
|
||||
|
||||
#ifdef HOME_DISPLAY_EXTERNALS
|
||||
if (index >= container->numberOfApps()) {
|
||||
External::Archive::File executable;
|
||||
if (External::Archive::executableAtIndex(index - container->numberOfApps(), executable)) {
|
||||
uint32_t res = External::Archive::executeFile(executable.name, ((App *)m_app)->heap(), ((App *)m_app)->heapSize());
|
||||
((App*)m_app)->redraw();
|
||||
switch(res) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
Container::activeApp()->displayWarning(I18n::Message::ExternalAppApiMismatch);
|
||||
break;
|
||||
case 2:
|
||||
Container::activeApp()->displayWarning(I18n::Message::StorageMemoryFull1);
|
||||
break;
|
||||
default:
|
||||
Container::activeApp()->displayWarning(I18n::Message::ExternalAppExecError);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
#endif
|
||||
|
||||
::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(index);
|
||||
if (((GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch || GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::NoSymNoText) && selectedSnapshot->descriptor()->examinationLevel() < 2) ||
|
||||
((GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Standard || GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::NoSym) && selectedSnapshot->descriptor()->examinationLevel() < 1)) {
|
||||
App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2);
|
||||
@@ -67,6 +100,9 @@ bool Controller::handleEvent(Ion::Events::Event event) {
|
||||
assert(switched);
|
||||
(void) switched; // Silence compilation warning about unused variable.
|
||||
}
|
||||
#ifdef HOME_DISPLAY_EXTERNALS
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -134,7 +170,19 @@ void Controller::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
|
||||
AppsContainer * container = AppsContainer::sharedAppsContainer();
|
||||
int appIndex = (j*k_numberOfColumns+i)+1;
|
||||
if (appIndex >= container->numberOfApps()) {
|
||||
#ifdef HOME_DISPLAY_EXTERNALS
|
||||
External::Archive::File app_file;
|
||||
|
||||
|
||||
if (External::Archive::executableAtIndex(appIndex - container->numberOfApps(), app_file)) {
|
||||
appCell->setExtAppDescriptor(app_file.name);
|
||||
appCell->setVisible(true);
|
||||
} else {
|
||||
appCell->setVisible(false);
|
||||
}
|
||||
#else
|
||||
appCell->setVisible(false);
|
||||
#endif
|
||||
} else {
|
||||
appCell->setVisible(true);
|
||||
::App::Descriptor * descriptor = container->appSnapshotAtIndex(appIndex)->descriptor();
|
||||
@@ -145,7 +193,11 @@ void Controller::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
|
||||
int Controller::numberOfIcons() const {
|
||||
AppsContainer * container = AppsContainer::sharedAppsContainer();
|
||||
assert(container->numberOfApps() > 0);
|
||||
#ifdef HOME_DISPLAY_EXTERNALS
|
||||
return container->numberOfApps() - 1 + External::Archive::numberOfExecutables();
|
||||
#else
|
||||
return container->numberOfApps() - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
|
||||
@@ -162,7 +214,7 @@ void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previo
|
||||
* background complete redrawing but the code is a bit
|
||||
* clumsy. */
|
||||
if (t->selectedRow() == numberOfRows()-1) {
|
||||
m_view.reloadBottomRow(this, container->numberOfApps()-1, k_numberOfColumns);
|
||||
m_view.reloadBottomRow(this, this->numberOfIcons(), k_numberOfColumns);
|
||||
}
|
||||
/* To prevent the selectable table view to select cells that are unvisible,
|
||||
* we reselect the previous selected cell as soon as the selected cell is
|
||||
@@ -170,7 +222,7 @@ void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previo
|
||||
* stay on a unvisible cell and to initialize the first cell on a visible one
|
||||
* (so the previous one is always visible). */
|
||||
int appIndex = (t->selectedColumn()+t->selectedRow()*k_numberOfColumns)+1;
|
||||
if (appIndex >= container->numberOfApps()) {
|
||||
if (appIndex >= this->numberOfIcons() + 1) {
|
||||
t->selectCellAtLocation(previousSelectedCellX, previousSelectedCellY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Home {
|
||||
|
||||
class Controller : public ViewController, public SimpleTableViewDataSource, public SelectableTableViewDelegate {
|
||||
public:
|
||||
Controller(Responder * parentResponder, SelectableTableViewDataSource * selectionDataSource);
|
||||
Controller(Responder * parentResponder, SelectableTableViewDataSource * selectionDataSource, App * app);
|
||||
|
||||
View * view() override;
|
||||
|
||||
@@ -49,6 +49,7 @@ private:
|
||||
static constexpr int k_cellWidth = 104;
|
||||
ContentView m_view;
|
||||
AppCell m_cells[k_maxNumberOfCells];
|
||||
App * m_app;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
private:
|
||||
I18n::Message m_message;
|
||||
const char* m_text = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,11 +9,13 @@ MessageTextView::MessageTextView(const KDFont * font, I18n::Message message, flo
|
||||
}
|
||||
|
||||
const char * MessageTextView::text() const {
|
||||
if (m_text)
|
||||
return m_text;
|
||||
return I18n::translate(m_message);
|
||||
}
|
||||
|
||||
void MessageTextView::setText(const char * text) {
|
||||
assert(false);
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
void MessageTextView::setMessage(I18n::Message message) {
|
||||
|
||||
Reference in New Issue
Block a user