diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 45cb09d42..7b53519b9 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -14,11 +14,13 @@ jobs: build-device-n0100: runs-on: ubuntu-latest steps: - - run: sudo apt-get install binutils-arm-none-eabi build-essential gcc-arm-none-eabi imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - uses: numworks/setup-arm-toolchain@v1 - uses: actions/checkout@v1 - run: make -j2 MODEL=n0100 epsilon.dfu - run: make -j2 MODEL=n0100 epsilon.onboarding.dfu - run: make -j2 MODEL=n0100 epsilon.onboarding.update.dfu + - run: make -j2 MODEL=n0100 epsilon.onboarding.beta.dfu - run: make -j2 MODEL=n0100 flasher.light.dfu - run: make -j2 MODEL=n0100 flasher.verbose.dfu - uses: actions/upload-artifact@master @@ -29,11 +31,13 @@ jobs: build-device-n0110: runs-on: ubuntu-latest steps: - - run: sudo apt-get install binutils-arm-none-eabi build-essential gcc-arm-none-eabi imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config + - uses: numworks/setup-arm-toolchain@v1 - uses: actions/checkout@v1 - run: make -j2 epsilon.dfu - run: make -j2 epsilon.onboarding.dfu - run: make -j2 epsilon.onboarding.update.dfu + - run: make -j2 epsilon.onboarding.beta.dfu - run: make -j2 flasher.light.dfu - run: make -j2 flasher.verbose.dfu - run: make -j2 bench.ram.dfu diff --git a/.gitignore b/.gitignore index 6d58dfa02..5019cb014 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build/device/**/*.pyc epsilon.elf .vscode +.DS_Store \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 134e135f6..1e294d433 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "apps/atom"] path = apps/atom url = https://github.com/Omega-Numworks/Omega-Atom.git +[submodule "themes"] + path = themes + url = https://github.com/Omega-Numworks/Omega-Themes.git diff --git a/Makefile b/Makefile index 8f8af5d51..c420bd2d2 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,8 @@ info: @echo "EPSILON_VERSION = $(EPSILON_VERSION)" @echo "EPSILON_APPS = $(EPSILON_APPS)" @echo "EPSILON_I18N = $(EPSILON_I18N)" + @echo "OMEGA_THEME = $(OMEGA_THEME)" + @echo "BUILD_DIR = $(BUILD_DIR)" @echo "PLATFORM" = $(PLATFORM) @echo "DEBUG" = $(DEBUG) @echo "EPSILON_GETOPT" = $(EPSILON_GETOPT) @@ -66,6 +68,17 @@ help: @echo " make PLATFORM=simulator TARGET=web" @echo " make PLATFORM=simulator TARGET=windows" +.PHONY: doc +doc: + @echo "DOXYGEN" + @mkdir -p output/doc/ + $(Q) doxygen build/doc/Doxyfile + +.PHONY: print-% +print-%: + @echo $* = $($*) + @echo $*\'s origin is $(origin $*) + # Since we're building out-of-tree, we need to make sure the output directories # are created, otherwise the receipes will fail (e.g. gcc will fail to create # "output/foo/bar.o" because the directory "output/foo" doesn't exist). @@ -103,6 +116,11 @@ include build/scenario/Makefile include quiz/Makefile # Quiz needs to be included at the end all_src = $(apps_all_src) $(escher_src) $(ion_all_src) $(kandinsky_src) $(liba_src) $(libaxx_src) $(poincare_src) $(python_src) $(epsilon_src) $(runner_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(ion_target_device_bench_src) $(tests_src) + +# Make palette.h a dep for every source-file. +# This ensures that the theming engine works correctly. +$(call object_for,$(all_app_src)): $(BUILD_DIR)/escher/palette.h + all_objs = $(call object_for,$(all_src)) .SECONDARY: $(all_objs) @@ -127,6 +145,11 @@ clean: @echo "CLEAN" $(Q) rm -rf $(BUILD_DIR) +.PHONY: cleanall +cleanall: + @echo "CLEANALL" + $(Q) rm -rf output + .PHONY: cowsay_% cowsay_%: @echo " -------" @@ -141,3 +164,23 @@ cowsay_%: .PHONY: clena clena: cowsay_CLENA clean +.PHONY: compile +compile: output/$(BUILD_TYPE)/simulator/$(HOST)/epsilon.$(EXE) + +.PHONY: cleanandcompile +cleanandcompile: + ${MAKE} cleanall + ${MAKE} compile + +.PHONY: start +start: + @echo "INFO Starting output/$(BUILD_TYPE)/simulator/$(HOST)/epsilon.$(EXE)" + @$(Q) output/$(BUILD_TYPE)/simulator/$(HOST)/epsilon.$(EXE) + +.PHONY: clean_run +clean_run: cleanandcompile + ${MAKE} start + +.PHONY: run +run: compile + ${MAKE} start diff --git a/apps/Makefile b/apps/Makefile index 8696bef5e..631f436ae 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -79,18 +79,31 @@ $(eval $(call rule_for, \ $$(PYTHON) apps/i18n.py --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --files $$^ \ )) + + $(BUILD_DIR)/apps/i18n.h: $(BUILD_DIR)/apps/i18n.cpp # Handle PNG files $(eval $(call depends_on_image,apps/title_bar_view.cpp,apps/exam_icon.png)) -all_app_src = $(app_src) $(epsilon_src) $(apps_launch_on_boarding_src) $(apps_launch_default_src) $(apps_prompt_none_src) $(apps_container_prompt_update) $(apps_prompt_beta_src) $(tests_src) +all_app_src = $(app_src) $(epsilon_src) $(apps_launch_on_boarding_src) $(apps_launch_default_src) $(apps_prompt_none_src) $(apps_prompt_update_src) $(apps_prompt_beta_src) $(tests_src) $(call object_for,$(all_app_src)): $(BUILD_DIR)/apps/i18n.h $(call object_for,$(all_app_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.generated.h apps_tests_src = $(app_calculation_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_solver_test_src) +apps_tests_src += $(addprefix apps/,\ + global_preferences.cpp \ +) + + +$(foreach img,$(image_list), $(eval $(call rule_for, \ + ICON, \ + $(img), \ + $(addprefix themes/themes/, $(addsuffix .json, $(OMEGA_THEME))), \ + $$(PYTHON) themes/themes_manager.py -i $(OMEGA_THEME) $$@ $(BUILD_DIR)/ \ +))) # Configure variants apps_all_src = $(app_src) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 776153935..f08efd05b 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -4,11 +4,14 @@ #include #include #include +#include +#include extern "C" { #include } +using namespace Poincare; using namespace Shared; AppsContainer * AppsContainer::sharedAppsContainer() { @@ -198,8 +201,8 @@ bool AppsContainer::processEvent(Ion::Events::Event event) { // Warning: if the window is dirtied, you need to call window()->redraw() if (event == Ion::Events::USBPlug) { if (Ion::USB::isPlugged()) { - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) { - displayExamModePopUp(false); + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + displayExamModePopUp(GlobalPreferences::ExamMode::Off); window()->redraw(); } else { Ion::USB::enable(); @@ -218,6 +221,11 @@ bool AppsContainer::processEvent(Ion::Events::Event event) { suspend(true); return true; } + if (event == Ion::Events::BrightnessPlus || event == Ion::Events::BrightnessMinus) { + int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates; + int direction = (event == Ion::Events::BrightnessPlus) ? Ion::Backlight::NumberOfStepsPerShortcut*delta : -delta*Ion::Backlight::NumberOfStepsPerShortcut; + GlobalPreferences::sharedGlobalPreferences()->setBrightnessLevel(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()+direction); + } return false; } @@ -237,7 +245,15 @@ bool AppsContainer::switchTo(App::Snapshot * snapshot) { } void AppsContainer::run() { - window()->setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); + KDRect screenRect = KDRect(0, 0, Ion::Display::Width, Ion::Display::Height); + window()->setFrame(screenRect); + /* We push a white screen here, because fetching the exam mode takes some time + * and it is visible when reflashing a N0100 (there is some noise on the + * screen before the logo appears). */ + Ion::Display::pushRectUniform(screenRect, KDColorWhite); + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + activateExamMode(GlobalPreferences::sharedGlobalPreferences()->examMode()); + } refreshPreferences(); /* ExceptionCheckpoint stores the value of the stack pointer when setjump is @@ -297,8 +313,8 @@ void AppsContainer::reloadTitleBarView() { m_window.reloadTitleBarView(); } -void AppsContainer::displayExamModePopUp(bool activate) { - m_examPopUpController.setActivatingExamMode(activate); +void AppsContainer::displayExamModePopUp(GlobalPreferences::ExamMode mode) { + m_examPopUpController.setTargetExamMode(mode); s_activeApp->displayModalViewController(&m_examPopUpController, 0.f, 0.f, Metric::ExamPopUpTopMargin, Metric::PopUpRightMargin, Metric::ExamPopUpBottomMargin, Metric::PopUpLeftMargin); } @@ -313,7 +329,7 @@ void AppsContainer::shutdownDueToLowBattery() { } while (Ion::Battery::level() == Ion::Battery::Charge::EMPTY) { Ion::Backlight::setBrightness(0); - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Deactivate) { + if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { /* Unless the LED is lit up for the exam mode, switch off the LED. IF the * low battery event happened during the Power-On Self-Test, a LED might * have stayed lit up. */ @@ -346,6 +362,35 @@ void AppsContainer::redrawWindow(bool force) { m_window.redraw(force); } +void AppsContainer::activateExamMode(GlobalPreferences::ExamMode examMode) { + assert(examMode == GlobalPreferences::ExamMode::Standard || examMode == GlobalPreferences::ExamMode::Dutch || examMode == GlobalPreferences::ExamMode::NoSym); + reset(); + Preferences * preferences = Preferences::sharedPreferences(); + switch ((int)preferences->colorOfLED()) { + case 0: + Ion::LED::setColor(KDColorWhite); + break; + case 1: + Ion::LED::setColor(KDColorGreen); + break; + case 2: + Ion::LED::setColor(KDColorBlue); + break; + case 3: + Ion::LED::setColor(KDColorYellow); + break; + } + /* The Dutch exam mode LED is supposed to be orange but we can only make + * blink "pure" colors: with RGB leds on or off (as the PWM is used for + * blinking). The closest "pure" color is Yellow. Moreover, Orange LED is + * already used when the battery is charging. Using yellow, we can assert + * that the yellow LED only means that Dutch exam mode is on and avoid + * confusing states when the battery is charging and states when the Dutch + * exam mode is on. */ + // Ion::LED::setColor(examMode == GlobalPreferences::ExamMode::Dutch ? KDColorYellow : KDColorRed); + Ion::LED::setBlinking(1000, 0.1f); +} + void AppsContainer::examDeactivatingPopUpIsDismissed() { if (Ion::USB::isPlugged()) { Ion::USB::enable(); diff --git a/apps/apps_container.h b/apps/apps_container.h index 87c0adea6..814e642a1 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -13,6 +13,7 @@ #include "exam_pop_up_controller_delegate.h" #include "battery_timer.h" #include "suspend_timer.h" +#include "global_preferences.h" #include "backlight_dimming_timer.h" #include "shared/global_context.h" #include "on_boarding/pop_up_controller.h" @@ -41,11 +42,12 @@ public: bool updateBatteryState(); void refreshPreferences(); void reloadTitleBarView(); - void displayExamModePopUp(bool activate); + void displayExamModePopUp(GlobalPreferences::ExamMode mode); void shutdownDueToLowBattery(); void setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus); OnBoarding::PopUpController * promptController(); void redrawWindow(bool force = false); + void activateExamMode(GlobalPreferences::ExamMode examMode); // Exam pop-up controller delegate void examDeactivatingPopUpIsDismissed() override; // Ion::StorageDelegate diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 25b71a71d..711408b3e 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -1,5 +1,6 @@ #include "calculation.h" #include "../shared/poincare_helpers.h" +#include "../global_preferences.h" #include #include #include @@ -123,7 +124,9 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { } if (shouldOnlyDisplayExactOutput()) { m_displayOutput = DisplayOutput::ExactOnly; - } else if (input().recursivelyMatches( + // Force all results to be ApproximateOnly in Dutch exam mode + } else if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch || + input().recursivelyMatches( [](const Expression e, Context * c) { constexpr int approximateOnlyTypesCount = 9; /* If the input contains the following types, we only display the diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index f466c4e01..10505479a 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -1,5 +1,6 @@ #include "calculation_store.h" #include "../shared/poincare_helpers.h" +#include "../global_preferences.h" #include #include #include @@ -91,7 +92,7 @@ ExpiringPointer CalculationStore::push(const char * text, Context * // Compute and serialize the outputs { Expression outputs[] = {Expression(), Expression()}; - PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, true); // Symbolic computation + PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->isInExamModeSymbolic()); // Symbolic computation for (int i = 0; i < 2; i++) { if (!serializeExpression(outputs[i], nextSerializationLocation, &newCalculationsLocation)) { /* If the exat/approximate output does not fit in the store (event if the diff --git a/apps/exam_pop_up_controller.cpp b/apps/exam_pop_up_controller.cpp index 8d4f25c65..27451be80 100644 --- a/apps/exam_pop_up_controller.cpp +++ b/apps/exam_pop_up_controller.cpp @@ -10,16 +10,14 @@ using namespace Poincare; ExamPopUpController::ExamPopUpController(ExamPopUpControllerDelegate * delegate) : ViewController(nullptr), m_contentView(this), - m_isActivatingExamMode(false), + m_targetExamMode(GlobalPreferences::ExamMode::Unknown), m_delegate(delegate) { } -void ExamPopUpController::setActivatingExamMode(bool activatingExamMode) { - if (m_isActivatingExamMode != activatingExamMode) { - m_isActivatingExamMode = activatingExamMode; - m_contentView.setMessages(activatingExamMode); - } +void ExamPopUpController::setTargetExamMode(GlobalPreferences::ExamMode mode) { + m_targetExamMode = mode; + m_contentView.setMessagesForExamMode(mode); } View * ExamPopUpController::view() { @@ -27,7 +25,7 @@ View * ExamPopUpController::view() { } void ExamPopUpController::viewDidDisappear() { - if (m_isActivatingExamMode == false) { + if (m_targetExamMode == GlobalPreferences::ExamMode::Off) { m_delegate->examDeactivatingPopUpIsDismissed(); } } @@ -55,30 +53,15 @@ ExamPopUpController::ContentView::ContentView(Responder * parentResponder) : }, parentResponder), KDFont::SmallFont), m_okButton(parentResponder, I18n::Message::Ok, Invocation([](void * context, void * sender) { ExamPopUpController * controller = (ExamPopUpController *)context; - GlobalPreferences::ExamMode nextExamMode = controller->isActivatingExamMode() ? GlobalPreferences::ExamMode::Activate : GlobalPreferences::ExamMode::Deactivate; - GlobalPreferences::sharedGlobalPreferences()->setExamMode(nextExamMode); - Preferences * preferences = Preferences::sharedPreferences(); + GlobalPreferences::ExamMode mode = controller->targetExamMode(); + assert(mode != GlobalPreferences::ExamMode::Unknown); + GlobalPreferences::sharedGlobalPreferences()->setExamMode(mode); AppsContainer * container = AppsContainer::sharedAppsContainer(); - if (controller->isActivatingExamMode()) { - container->reset(); - switch ((int)preferences->colorOfLED()) { - case 0: - Ion::LED::setColor(KDColorWhite); - break; - case 1: - Ion::LED::setColor(KDColorGreen); - break; - case 2: - Ion::LED::setColor(KDColorBlue); - break; - case 3: - Ion::LED::setColor(KDColorYellow); - break; - } - Ion::LED::setBlinking(1000, 0.1f); - } else { + if (mode == GlobalPreferences::ExamMode::Off) { Ion::LED::setColor(KDColorBlack); Ion::LED::updateColorWithPlugAndCharge(); + } else { + container->activateExamMode(mode); } container->refreshPreferences(); Container::activeApp()->dismissModalViewController(); @@ -108,15 +91,20 @@ int ExamPopUpController::ContentView::selectedButton() { return 1; } -void ExamPopUpController::ContentView::setMessages(bool activingExamMode) { - if (activingExamMode) { +void ExamPopUpController::ContentView::setMessagesForExamMode(GlobalPreferences::ExamMode mode) { + if (mode == GlobalPreferences::ExamMode::Off) { + m_messageTextView1.setMessage(I18n::Message::ExitExamMode1); + m_messageTextView2.setMessage(I18n::Message::ExitExamMode2); + m_messageTextView3.setMessage(I18n::Message::Default); + } else if (mode == GlobalPreferences::ExamMode::Standard || mode == GlobalPreferences::ExamMode::NoSym) { m_messageTextView1.setMessage(I18n::Message::ActiveExamModeMessage1); m_messageTextView2.setMessage(I18n::Message::ActiveExamModeMessage2); m_messageTextView3.setMessage(I18n::Message::ActiveExamModeMessage3); } else { - m_messageTextView1.setMessage(I18n::Message::ExitExamMode1); - m_messageTextView2.setMessage(I18n::Message::ExitExamMode2); - m_messageTextView3.setMessage(I18n::Message::Default); + assert(mode == GlobalPreferences::ExamMode::Dutch); + m_messageTextView1.setMessage(I18n::Message::ActiveDutchExamModeMessage1); + m_messageTextView2.setMessage(I18n::Message::ActiveDutchExamModeMessage2); + m_messageTextView3.setMessage(I18n::Message::ActiveDutchExamModeMessage3); } } diff --git a/apps/exam_pop_up_controller.h b/apps/exam_pop_up_controller.h index 3bff108f7..79ca4d6c9 100644 --- a/apps/exam_pop_up_controller.h +++ b/apps/exam_pop_up_controller.h @@ -3,6 +3,7 @@ #include #include "exam_pop_up_controller_delegate.h" +#include "global_preferences.h" class HighContrastButton : public Button { public: @@ -13,8 +14,8 @@ public: class ExamPopUpController : public ViewController { public: ExamPopUpController(ExamPopUpControllerDelegate * delegate); - void setActivatingExamMode(bool activingExamMode); - bool isActivatingExamMode() const { return m_isActivatingExamMode; } + void setTargetExamMode(GlobalPreferences::ExamMode mode); + GlobalPreferences::ExamMode targetExamMode() const { return m_targetExamMode; } // View Controller View * view() override; void viewDidDisappear() override; @@ -28,7 +29,7 @@ private: void drawRect(KDContext * ctx, KDRect rect) const override; void setSelectedButton(int selectedButton); int selectedButton(); - void setMessages(bool activingExamMode); + void setMessagesForExamMode(GlobalPreferences::ExamMode mode); private: constexpr static KDCoordinate k_buttonMargin = 10; constexpr static KDCoordinate k_buttonHeight = 20; @@ -45,7 +46,7 @@ private: MessageTextView m_messageTextView3; }; ContentView m_contentView; - bool m_isActivatingExamMode; + GlobalPreferences::ExamMode m_targetExamMode; ExamPopUpControllerDelegate * m_delegate; }; diff --git a/apps/external/Makefile b/apps/external/Makefile new file mode 100644 index 000000000..f2680b165 --- /dev/null +++ b/apps/external/Makefile @@ -0,0 +1,31 @@ +apps += External::App +app_headers += apps/external/app.h + +app_external_src = $(addprefix apps/external/,\ + app.cpp \ + extapp_api.cpp \ + archive.cpp \ + main_controller.cpp \ + pointer_text_table_cell.cpp \ +) + +SFLAGS += -Iapps/external/ + +EXTAPP_PATH ?= apps/external/app/ +ifeq ($(PLATFORM),device) + SFLAGS += -DDEVICE +else + include $(EXTAPP_PATH)/sources.mak +endif + +app_src += $(app_external_src) + +i18n_files += $(addprefix apps/external/,\ + base.de.i18n\ + base.en.i18n\ + base.es.i18n\ + base.fr.i18n\ + base.pt.i18n\ +) + +$(eval $(call depends_on_image,apps/external/app.cpp,apps/external/external_icon.png)) diff --git a/apps/external/app.cpp b/apps/external/app.cpp new file mode 100644 index 000000000..ac0f6141c --- /dev/null +++ b/apps/external/app.cpp @@ -0,0 +1,44 @@ +#include "app.h" +#include "external_icon.h" +#include + +namespace External { + +I18n::Message App::Descriptor::name() { + return I18n::Message::ExternalApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::ExternalAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::ExternalIcon; +} + +App * App::Snapshot::unpack(Container * container) { + return new (container->currentAppBuffer()) App(this); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor 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_stackViewController), + m_mainController(&m_stackViewController, this), + m_stackViewController(&m_modalViewController, &m_mainController) +{ +} + +} diff --git a/apps/external/app.h b/apps/external/app.h new file mode 100644 index 000000000..e1dd47043 --- /dev/null +++ b/apps/external/app.h @@ -0,0 +1,37 @@ +#ifndef EXTERNAL_APP_H +#define EXTERNAL_APP_H + +#include +#include "main_controller.h" + +namespace External { + +class App : public ::App { +public: + class Descriptor : public ::App::Descriptor { + public: + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + Descriptor * descriptor() override; + }; + void redraw(); + virtual void didBecomeActive(Window * window); + int heapSize() { return k_externalHeapSize; } + char * heap() { return m_externalHeap; } +private: + App(Snapshot * snapshot); + MainController m_mainController; + StackViewController m_stackViewController; + Window * m_window; + static constexpr int k_externalHeapSize = 131072; + char m_externalHeap[k_externalHeapSize]; +}; + +} + +#endif diff --git a/apps/external/app/sample.c b/apps/external/app/sample.c new file mode 100644 index 000000000..dbc13fd95 --- /dev/null +++ b/apps/external/app/sample.c @@ -0,0 +1,6 @@ +#include + +void extapp_main() { + extapp_pushRectUniform(10, 10, LCD_WIDTH-20, LCD_HEIGHT-20, 0); + extapp_msleep(1000); +} diff --git a/apps/external/app/sources.mak b/apps/external/app/sources.mak new file mode 100644 index 000000000..3f285e23a --- /dev/null +++ b/apps/external/app/sources.mak @@ -0,0 +1,3 @@ +app_external_src += $(addprefix apps/external/app/,\ + sample.c \ +) \ No newline at end of file diff --git a/apps/external/archive.cpp b/apps/external/archive.cpp new file mode 100644 index 000000000..3472aabe5 --- /dev/null +++ b/apps/external/archive.cpp @@ -0,0 +1,146 @@ +#include "archive.h" +#include "extapp_api.h" +#include "../global_preferences.h" + +#include +#include + +namespace External { +namespace Archive { + +#ifdef DEVICE + +struct TarHeader +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[8]; /* 257 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char padding[167]; /* 345 */ +} __attribute__((packed)); + +static_assert(sizeof(TarHeader) == 512); + +bool isSane(const TarHeader* tar) { + return !memcmp(tar->magic, "ustar ", 8) && tar->name[0] != '\x00' && tar->name[0] != '\xFF'; +} + +bool isExamModeAndFileNotExecutable(const TarHeader* tar) { + return GlobalPreferences::sharedGlobalPreferences()->isInExamMode() && (tar->mode[4] & 0x01) == 0; +} + +bool fileAtIndex(size_t index, File &entry) { + const TarHeader* tar = reinterpret_cast(0x90200000); + unsigned size = 0; + + // Sanity check. + if (!isSane(tar) || isExamModeAndFileNotExecutable(tar)) { + return false; + } + + /** + * TAR files are comprised of a set of records aligned to 512 bytes boundary + * followed by data. + */ + while (index-- > 0) { + size = 0; + for (int i = 0; i < 11; i++) + size = size * 8 + (tar->size[i] - '0'); + + // Move to the next TAR header. + unsigned stride = (sizeof(TarHeader) + size + 511); + stride = (stride >> 9) << 9; + tar = reinterpret_cast(reinterpret_cast(tar) + stride); + + // Sanity check. + if (!isSane(tar) || isExamModeAndFileNotExecutable(tar)) { + return false; + } + } + + // File entry found, copy data out. + entry.name = tar->name; + entry.data = reinterpret_cast(tar) + sizeof(TarHeader); + entry.dataLength = size; + entry.isExecutable = (tar->mode[4] & 0x01) == 1; + + return true; +} + +extern "C" void (* const apiPointers[])(void); +typedef uint32_t (*entrypoint)(const uint32_t, const void *, void *, const uint32_t); + +uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) { + File entry; + if(fileAtIndex(indexFromName(name), entry)) { + if(!entry.isExecutable) { + return 0; + } + uint32_t ep = *reinterpret_cast(entry.data); + if(ep >= 0x90200000 && ep < 0x90800000) { + return ((entrypoint)ep)(API_VERSION, apiPointers, heap, heapSize); + } + } + return -1; +} + +int indexFromName(const char *name) { + File entry; + + for (int i = 0; fileAtIndex(i, entry); i++) { + if (strcmp(name, entry.name) == 0) { + return i; + } + } + + return -1; +} + +size_t numberOfFiles() { + File dummy; + size_t count; + + for (count = 0; fileAtIndex(count, dummy); count++); + + return count; +} + +#else + +bool fileAtIndex(size_t index, File &entry) { + entry.name = "App"; + entry.data = NULL; + entry.dataLength = 0; + entry.isExecutable = true; + return true; +} + +extern "C" void extapp_main(void); + +uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) { + extapp_main(); + return 0; +} + +int indexFromName(const char *name) { + return 0; +} + +size_t numberOfFiles() { + return 1; +} + +#endif + +} +} diff --git a/apps/external/archive.h b/apps/external/archive.h new file mode 100644 index 000000000..80b71d0e1 --- /dev/null +++ b/apps/external/archive.h @@ -0,0 +1,27 @@ +#ifndef EXTERNAL_ARCHIVE_H +#define EXTERNAL_ARCHIVE_H + +#include +#include + +namespace External { +namespace Archive { + +constexpr int MaxNameLength = 40; + +struct File { + const char *name; + const uint8_t *data; + size_t dataLength; + bool isExecutable; +}; + +bool fileAtIndex(size_t index, File &entry); +int indexFromName(const char *name); +size_t numberOfFiles(); +uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize); + +} +} + +#endif diff --git a/apps/external/base.de.i18n b/apps/external/base.de.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.de.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.en.i18n b/apps/external/base.en.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.en.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.es.i18n b/apps/external/base.es.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.es.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.fr.i18n b/apps/external/base.fr.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.fr.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/base.pt.i18n b/apps/external/base.pt.i18n new file mode 100644 index 000000000..6072a563a --- /dev/null +++ b/apps/external/base.pt.i18n @@ -0,0 +1,4 @@ +ExternalApp = "External" +ExternalAppCapital = "EXTERNAL" +ExternalAppApiMismatch = "API mismatch" +ExternalAppExecError = "Cannot execute file" diff --git a/apps/external/extapp_api.cpp b/apps/external/extapp_api.cpp new file mode 100644 index 000000000..248fc6ee2 --- /dev/null +++ b/apps/external/extapp_api.cpp @@ -0,0 +1,309 @@ +#include +#include +#include +#include +#include +#include +#include "archive.h" +#include "extapp_api.h" +#include "../apps_container.h" +#include "../global_preferences.h" + +#include + +extern "C" { + #include +} + +uint64_t extapp_millis() { + return Ion::Timing::millis(); +} + +void extapp_msleep(uint32_t ms) { + Ion::Timing::msleep(ms); +} + +uint64_t extapp_scanKeyboard() { + return Ion::Keyboard::scan(); +} + +void extapp_pushRect(int16_t x, int16_t y, uint16_t w, uint16_t h, const uint16_t * pixels) { + KDRect rect(x, y, w, h); + + Ion::Display::pushRect(rect, reinterpret_cast(pixels)); +} + +void extapp_pushRectUniform(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t color) { + KDRect rect(x, y, w, h); + + Ion::Display::pushRectUniform(rect, KDColor::RGB16(color)); +} + +void extapp_pullRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t * pixels) { + KDRect rect(x, y, w, h); + + Ion::Display::pullRect(rect, (KDColor *) pixels); +} + +int16_t extapp_drawTextLarge(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake) { + KDPoint point(x, y); + + auto ctx = KDIonContext::sharedContext(); + ctx->setClippingRect(KDRect(0, 0, 320, fake ? 0 : 240)); + ctx->setOrigin(KDPoint(0, 0)); + point = ctx->drawString(text, point, KDFont::LargeFont, KDColor::RGB16(fg), KDColor::RGB16(bg)); + + return point.x(); +} + +int16_t extapp_drawTextSmall(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake) { + KDPoint point(x, y); + + auto ctx = KDIonContext::sharedContext(); + ctx->setClippingRect(KDRect(0, 0, 320, fake ? 0 : 240)); + ctx->setOrigin(KDPoint(0, 0)); + point = ctx->drawString(text, point, KDFont::SmallFont, KDColor::RGB16(fg), KDColor::RGB16(bg)); + + return point.x(); +} + +bool extapp_waitForVBlank() { + return Ion::Display::waitForVBlank(); +} + +void extapp_clipboardStore(const char *text) { + Clipboard::sharedClipboard()->store(text); +} + +const char * extapp_clipboardText() { + return Clipboard::sharedClipboard()->storedText(); +} + +int extapp_fileListWithExtension(const char ** filenames, int maxrecords, const char * extension, int storage) { + if(storage == EXTAPP_RAM_FILE_SYSTEM) { + int n = Ion::Storage::sharedStorage()->numberOfRecordsWithExtension(extension); + if (n > maxrecords) { + n = maxrecords; + } + for(int i = 0; i < n; i++) { + filenames[i] = Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(extension, i).fullName(); + } + return n; + } else if(storage == EXTAPP_FLASH_FILE_SYSTEM) { + // TODO: filter by extension + int n = External::Archive::numberOfFiles(); + if (n > maxrecords) { + n = maxrecords; + } + for(int i = 0; i < n; i++) { + External::Archive::File entry; + External::Archive::fileAtIndex(i, entry); + filenames[i] = entry.name; + } + return n; + } else { + return 0; + } +} + +bool extapp_fileExists(const char * filename, int storage) { + if(storage == EXTAPP_RAM_FILE_SYSTEM) { + return !Ion::Storage::sharedStorage()->recordNamed(filename).isNull(); + } else if(storage == EXTAPP_FLASH_FILE_SYSTEM) { + return External::Archive::indexFromName(filename) >= 0; + } else { + return false; + } +} + +bool extapp_fileErase(const char * filename, int storage) { + if(storage == EXTAPP_RAM_FILE_SYSTEM) { + Ion::Storage::Record record = Ion::Storage::sharedStorage()->recordNamed(filename); + if(record.isNull()) { + return false; + } else { + record.destroy(); + return true; + } + } else { + return false; + } +} + +const char * extapp_fileRead(const char * filename, size_t *len, int storage) { + if(storage == EXTAPP_RAM_FILE_SYSTEM) { + const Ion::Storage::Record record = Ion::Storage::sharedStorage()->recordNamed(filename); + if (record.isNull()) { + return NULL; + } else { + if(len) { + *len = record.value().size; + } + return (const char *) record.value().buffer; + } + } else if(storage == EXTAPP_FLASH_FILE_SYSTEM) { + int index = External::Archive::indexFromName(filename); + if (index >= 0) { + External::Archive::File entry; + External::Archive::fileAtIndex(index, entry); + if(len) { + *len = entry.dataLength; + } + return (const char *)entry.data; + } else { + return NULL; + } + } else { + return NULL; + } +} + +bool extapp_fileWrite(const char * filename, const char * content, size_t len, int storage) { + if(storage == EXTAPP_RAM_FILE_SYSTEM) { + Ion::Storage::Record::ErrorStatus status = Ion::Storage::sharedStorage()->createRecordWithFullName(filename, content, len); + if (status == Ion::Storage::Record::ErrorStatus::NameTaken) { + Ion::Storage::Record::Data data; + data.buffer = content; + data.size = len; + return Ion::Storage::sharedStorage()->recordNamed(filename).setValue(data) == Ion::Storage::Record::ErrorStatus::None; + } else if (status == Ion::Storage::Record::ErrorStatus::None) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +static void reloadTitleBar() { + AppsContainer::sharedAppsContainer()->setShiftAlphaStatus(Ion::Events::shiftAlphaStatus()); + AppsContainer::sharedAppsContainer()->refreshPreferences(); + AppsContainer::sharedAppsContainer()->updateBatteryState(); + AppsContainer::sharedAppsContainer()->reloadTitleBarView(); + AppsContainer::sharedAppsContainer()->redrawWindow(); +} + +void extapp_lockAlpha() { + Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::AlphaLock); + reloadTitleBar(); +} + +void extapp_resetKeyboard() { + Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default); + reloadTitleBar(); +} + +const int16_t translated_keys[] = +{ + // non shifted + KEY_CTRL_LEFT,KEY_CTRL_UP,KEY_CTRL_DOWN,KEY_CTRL_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,KEY_CTRL_XTT,KEY_CTRL_VARS,KEY_CTRL_CATALOG,KEY_CTRL_DEL, + KEY_CHAR_EXPN,KEY_CHAR_LN,KEY_CHAR_LOG,KEY_CHAR_IMGNRY,',',KEY_CHAR_POW, + KEY_CHAR_SIN,KEY_CHAR_COS,KEY_CHAR_TAN,KEY_CHAR_PI,KEY_CHAR_ROOT,KEY_CHAR_SQUARE, + '7','8','9','(',')',-1, + '4','5','6','*','/',-1, + '1','2','3','+','-',-1, + '0','.',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1, + // shifted + KEY_SHIFT_LEFT,KEY_CTRL_PAGEUP,KEY_CTRL_PAGEDOWN,KEY_SHIFT_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,KEY_CTRL_CUT,KEY_CTRL_CLIP,KEY_CTRL_PASTE,KEY_CTRL_AC, + KEY_CHAR_LBRCKT,KEY_CHAR_RBRCKT,KEY_CHAR_LBRACE,KEY_CHAR_RBRACE,'_',KEY_CHAR_STORE, + KEY_CHAR_ASIN,KEY_CHAR_ACOS,KEY_CHAR_ATAN,'=','<','>', + KEY_CTRL_F7,KEY_CTRL_F8,KEY_CTRL_F9,KEY_CTRL_F13,KEY_CTRL_F14,-1, + KEY_CTRL_F4,KEY_CTRL_F5,KEY_CTRL_F6,KEY_CHAR_FACTOR,'%',-1, + KEY_CTRL_F1,KEY_CTRL_F2,KEY_CTRL_F3,KEY_CHAR_NORMAL,'\\',-1, + KEY_CTRL_F10,KEY_CTRL_F11,KEY_CTRL_F12,KEY_SHIFT_ANS,KEY_CTRL_EXE,-1, + // alpha + KEY_CTRL_LEFT,KEY_CTRL_UP,KEY_CTRL_DOWN,KEY_CTRL_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,':',';','"',KEY_CTRL_DEL, + 'a','b','c','d','e','f', + 'g','h','i','j','k','l', + 'm','n','o','p','q',-1, + 'r','s','t','u','v',-1, + 'w','x','y','z',' ',-1, + '?','!',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1, + // alpha shifted + KEY_SHIFT_LEFT,KEY_CTRL_PAGEUP,KEY_CTRL_PAGEDOWN,KEY_SHIFT_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT, + KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11, + KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,':',';','\'','%', + 'A','B','C','D','E','F', + 'G','H','I','J','K','L', + 'M','N','O','P','Q',-1, + 'R','S','T','U','V',-1, + 'W','X','Y','Z',' ',-1, + '?','!',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1, +}; + +#ifdef SIMULATOR +#define TICKS_PER_MINUTE 60000 +#else +#define TICKS_PER_MINUTE 11862 +#endif + +int extapp_getKey(bool allowSuspend, bool *alphaWasActive) { + int key = -1; + size_t t1 = Ion::Timing::millis(); + for (;;) { + int timeout = 10000; + if(alphaWasActive) { + *alphaWasActive = Ion::Events::isAlphaActive(); + } + Ion::Events::Event event = Ion::Events::getEvent(&timeout); + reloadTitleBar(); + if (event == Ion::Events::None) { + size_t t2 = Ion::Timing::millis(); + if (t2 - t1 > 2 * TICKS_PER_MINUTE) { + event = Ion::Events::OnOff; + } + } else { + t1 = Ion::Timing::millis(); + } + if (event.isKeyboardEvent()) { + Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()); + } + if (event == Ion::Events::Shift || event == Ion::Events::Alpha) { + continue; + } + if (event.isKeyboardEvent()) { + key = event.id(); + if (key == 17 || key == 4 || key == 5 || key == 52) { + extapp_resetKeyboard(); + } + if (allowSuspend && (key == 7 || key == 8)) { // power + Ion::Power::suspend(true); + extapp_pushRectUniform(0, 0, 320, 240, 65535); + Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()); + reloadTitleBar(); + } + break; + } + } + return translated_keys[key]; +} + +extern "C" void (* const apiPointers[])(void) = { + (void (*)(void)) extapp_millis, + (void (*)(void)) extapp_msleep, + (void (*)(void)) extapp_scanKeyboard, + (void (*)(void)) extapp_pushRect, + (void (*)(void)) extapp_pushRectUniform, + (void (*)(void)) extapp_pullRect, + (void (*)(void)) extapp_drawTextLarge, + (void (*)(void)) extapp_drawTextSmall, + (void (*)(void)) extapp_waitForVBlank, + (void (*)(void)) extapp_clipboardStore, + (void (*)(void)) extapp_clipboardText, + (void (*)(void)) extapp_fileListWithExtension, + (void (*)(void)) extapp_fileExists, + (void (*)(void)) extapp_fileErase, + (void (*)(void)) extapp_fileRead, + (void (*)(void)) extapp_fileWrite, + (void (*)(void)) extapp_lockAlpha, + (void (*)(void)) extapp_resetKeyboard, + (void (*)(void)) extapp_getKey, + (void (*)(void)) nullptr, +}; diff --git a/apps/external/extapp_api.h b/apps/external/extapp_api.h new file mode 100644 index 000000000..b17b86436 --- /dev/null +++ b/apps/external/extapp_api.h @@ -0,0 +1,256 @@ +#ifndef EXTERNAL_API_H +#define EXTERNAL_API_H + +#include +#include +#include + +#define API_VERSION 2 + +#ifdef __cplusplus +#define EXTERNC extern "C" +#else +#define EXTERNC +#endif + +#define LCD_WIDTH 320 +#define LCD_HEIGHT 240 + +#define EXTAPP_RAM_FILE_SYSTEM 0 +#define EXTAPP_FLASH_FILE_SYSTEM 1 + +#define SCANCODE_Left ((uint64_t)1 << 0) +#define SCANCODE_Up ((uint64_t)1 << 1) +#define SCANCODE_Down ((uint64_t)1 << 2) +#define SCANCODE_Right ((uint64_t)1 << 3) +#define SCANCODE_OK ((uint64_t)1 << 4) +#define SCANCODE_Back ((uint64_t)1 << 5) +#define SCANCODE_Home ((uint64_t)1 << 6) +#define SCANCODE_OnOff (((uint64_t)1 << 7) || ((uint64_t)1 << 8)) +#define SCANCODE_Shift ((uint64_t)1 << 12) +#define SCANCODE_Alpha ((uint64_t)1 << 13) +#define SCANCODE_XNT ((uint64_t)1 << 14) +#define SCANCODE_Var ((uint64_t)1 << 15) +#define SCANCODE_Toolbox ((uint64_t)1 << 16) +#define SCANCODE_Backspace ((uint64_t)1 << 17) +#define SCANCODE_Exp ((uint64_t)1 << 18) +#define SCANCODE_Ln ((uint64_t)1 << 19) +#define SCANCODE_Log ((uint64_t)1 << 20) +#define SCANCODE_Imaginary ((uint64_t)1 << 21) +#define SCANCODE_Comma ((uint64_t)1 << 22) +#define SCANCODE_Power ((uint64_t)1 << 23) +#define SCANCODE_Sine ((uint64_t)1 << 24) +#define SCANCODE_Cosine ((uint64_t)1 << 25) +#define SCANCODE_Tangent ((uint64_t)1 << 26) +#define SCANCODE_Pi ((uint64_t)1 << 27) +#define SCANCODE_Sqrt ((uint64_t)1 << 28) +#define SCANCODE_Square ((uint64_t)1 << 29) +#define SCANCODE_Seven ((uint64_t)1 << 30) +#define SCANCODE_Eight ((uint64_t)1 << 31) +#define SCANCODE_Nine ((uint64_t)1 << 32) +#define SCANCODE_LeftParenthesis ((uint64_t)1 << 33) +#define SCANCODE_RightParenthesis ((uint64_t)1 << 34) +#define SCANCODE_Four ((uint64_t)1 << 36) +#define SCANCODE_Five ((uint64_t)1 << 37) +#define SCANCODE_Six ((uint64_t)1 << 38) +#define SCANCODE_Multiplication ((uint64_t)1 << 39) +#define SCANCODE_Division ((uint64_t)1 << 40) +#define SCANCODE_One ((uint64_t)1 << 42) +#define SCANCODE_Two ((uint64_t)1 << 43) +#define SCANCODE_Three ((uint64_t)1 << 44) +#define SCANCODE_Plus ((uint64_t)1 << 45) +#define SCANCODE_Minus ((uint64_t)1 << 46) +#define SCANCODE_Zero ((uint64_t)1 << 48) +#define SCANCODE_Dot ((uint64_t)1 << 49) +#define SCANCODE_EE ((uint64_t)1 << 50) +#define SCANCODE_Ans ((uint64_t)1 << 51) +#define SCANCODE_EXE ((uint64_t)1 << 52) +#define SCANCODE_None ((uint64_t)1 << 54) + +// Character codes +#define KEY_CHAR_0 0x30 +#define KEY_CHAR_1 0x31 +#define KEY_CHAR_2 0x32 +#define KEY_CHAR_3 0x33 +#define KEY_CHAR_4 0x34 +#define KEY_CHAR_5 0x35 +#define KEY_CHAR_6 0x36 +#define KEY_CHAR_7 0x37 +#define KEY_CHAR_8 0x38 +#define KEY_CHAR_9 0x39 +#define KEY_CHAR_DP 0x2e +#define KEY_CHAR_EXP 0x0f +#define KEY_CHAR_PMINUS 30200 +#define KEY_CHAR_PLUS 43 +#define KEY_CHAR_MINUS 45 +#define KEY_CHAR_MULT 42 +#define KEY_CHAR_DIV 47 +#define KEY_CHAR_FRAC 0xbb +#define KEY_CHAR_LPAR 0x28 +#define KEY_CHAR_RPAR 0x29 +#define KEY_CHAR_COMMA 0x2c +#define KEY_CHAR_STORE 0x0e +#define KEY_CHAR_LOG 0x95 +#define KEY_CHAR_LN 0x85 +#define KEY_CHAR_SIN 0x81 +#define KEY_CHAR_COS 0x82 +#define KEY_CHAR_TAN 0x83 +#define KEY_CHAR_SQUARE 0x8b +#define KEY_CHAR_POW 0xa8 +#define KEY_CHAR_IMGNRY 0x7f50 +#define KEY_CHAR_LIST 0x7f51 +#define KEY_CHAR_MAT 0x7f40 +#define KEY_CHAR_EQUAL 0x3d +#define KEY_CHAR_PI 0xd0 +#define KEY_CHAR_ANS 0xc0 +#define KEY_SHIFT_ANS 0xc1 +#define KEY_CHAR_LBRCKT 0x5b +#define KEY_CHAR_RBRCKT 0x5d +#define KEY_CHAR_LBRACE 0x7b +#define KEY_CHAR_RBRACE 0x7d +#define KEY_CHAR_CR 0x0d +#define KEY_CHAR_CUBEROOT 0x96 +#define KEY_CHAR_RECIP 0x9b +#define KEY_CHAR_ANGLE 0x7f54 +#define KEY_CHAR_EXPN10 0xb5 +#define KEY_CHAR_EXPN 0xa5 +#define KEY_CHAR_ASIN 0x91 +#define KEY_CHAR_ACOS 0x92 +#define KEY_CHAR_ATAN 0x93 +#define KEY_CHAR_ROOT 0x86 +#define KEY_CHAR_POWROOT 0xb8 +#define KEY_CHAR_SPACE 0x20 +#define KEY_CHAR_DQUATE 0x22 +#define KEY_CHAR_VALR 0xcd +#define KEY_CHAR_THETA 0xce +#define KEY_CHAR_FACTOR 0xda +#define KEY_CHAR_NORMAL 0xdb +#define KEY_CHAR_A 0x41 +#define KEY_CHAR_B 0x42 +#define KEY_CHAR_C 0x43 +#define KEY_CHAR_D 0x44 +#define KEY_CHAR_E 0x45 +#define KEY_CHAR_F 0x46 +#define KEY_CHAR_G 0x47 +#define KEY_CHAR_H 0x48 +#define KEY_CHAR_I 0x49 +#define KEY_CHAR_J 0x4a +#define KEY_CHAR_K 0x4b +#define KEY_CHAR_L 0x4c +#define KEY_CHAR_M 0x4d +#define KEY_CHAR_N 0x4e +#define KEY_CHAR_O 0x4f +#define KEY_CHAR_P 0x50 +#define KEY_CHAR_Q 0x51 +#define KEY_CHAR_R 0x52 +#define KEY_CHAR_S 0x53 +#define KEY_CHAR_T 0x54 +#define KEY_CHAR_U 0x55 +#define KEY_CHAR_V 0x56 +#define KEY_CHAR_W 0x57 +#define KEY_CHAR_X 0x58 +#define KEY_CHAR_Y 0x59 +#define KEY_CHAR_Z 0x5a + +// Control codes +#define KEY_CTRL_NOP 30202 +#define KEY_CTRL_EXE 30201 +#define KEY_CTRL_DEL 30025 +#define KEY_CTRL_AC 30070 +#define KEY_CTRL_FD 30046 +#define KEY_CTRL_UNDO 30045 +#define KEY_CTRL_XTT 30001 +#define KEY_CTRL_EXIT 5 +#define KEY_CTRL_OK 4 +#define KEY_CTRL_SHIFT 30006 +#define KEY_CTRL_ALPHA 30007 +#define KEY_CTRL_OPTN 30008 +#define KEY_CTRL_VARS 30030 +#define KEY_CTRL_UP 1 +#define KEY_CTRL_DOWN 2 +#define KEY_CTRL_LEFT 0 +#define KEY_CTRL_RIGHT 3 +#define KEY_CTRL_F1 30009 +#define KEY_CTRL_F2 30010 +#define KEY_CTRL_F3 30011 +#define KEY_CTRL_F4 30012 +#define KEY_CTRL_F5 30013 +#define KEY_CTRL_F6 30014 +#define KEY_CTRL_F7 30015 +#define KEY_CTRL_F8 30016 +#define KEY_CTRL_F9 30017 +#define KEY_CTRL_F10 30018 +#define KEY_CTRL_F11 30019 +#define KEY_CTRL_F12 30020 +#define KEY_CTRL_F13 30021 +#define KEY_CTRL_F14 30022 +#define KEY_CTRL_CATALOG 30100 +#define KEY_CTRL_CAPTURE 30055 +#define KEY_CTRL_CLIP 30050 +#define KEY_CTRL_CUT 30250 +#define KEY_CTRL_PASTE 30036 +#define KEY_CTRL_INS 30033 +#define KEY_CTRL_MIXEDFRAC 30054 +#define KEY_CTRL_FRACCNVRT 30026 +#define KEY_CTRL_QUIT 30029 +#define KEY_CTRL_PRGM 30028 +#define KEY_CTRL_SETUP 30037 +#define KEY_CTRL_PAGEUP 30052 +#define KEY_CTRL_PAGEDOWN 30053 +#define KEY_CTRL_MENU 30003 +#define KEY_SHIFT_OPTN 30059 +#define KEY_CTRL_RESERVE1 30060 +#define KEY_CTRL_RESERVE2 30061 +#define KEY_SHIFT_LEFT 30062 +#define KEY_SHIFT_RIGHT 30063 + +#define KEY_PRGM_ACON 10 +#define KEY_PRGM_DOWN 37 +#define KEY_PRGM_EXIT 47 +#define KEY_PRGM_F1 79 +#define KEY_PRGM_F2 69 +#define KEY_PRGM_F3 59 +#define KEY_PRGM_F4 49 +#define KEY_PRGM_F5 39 +#define KEY_PRGM_F6 29 +#define KEY_PRGM_LEFT 38 +#define KEY_PRGM_NONE 0 +#define KEY_PRGM_RETURN 31 +#define KEY_PRGM_RIGHT 27 +#define KEY_PRGM_UP 28 +#define KEY_PRGM_1 72 +#define KEY_PRGM_2 62 +#define KEY_PRGM_3 52 +#define KEY_PRGM_4 73 +#define KEY_PRGM_5 63 +#define KEY_PRGM_6 53 +#define KEY_PRGM_7 74 +#define KEY_PRGM_8 64 +#define KEY_PRGM_9 54 +#define KEY_PRGM_A 76 +#define KEY_PRGM_F 26 +#define KEY_PRGM_ALPHA 77 +#define KEY_PRGM_SHIFT 78 +#define KEY_PRGM_MENU 48 + +EXTERNC uint64_t extapp_millis(); +EXTERNC void extapp_msleep(uint32_t ms); +EXTERNC uint64_t extapp_scanKeyboard(); +EXTERNC void extapp_pushRect(int16_t x, int16_t y, uint16_t w, uint16_t h, const uint16_t * pixels); +EXTERNC void extapp_pushRectUniform(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t color); +EXTERNC void extapp_pullRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t * pixels); +EXTERNC int16_t extapp_drawTextLarge(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake); +EXTERNC int16_t extapp_drawTextSmall(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake); +EXTERNC bool extapp_waitForVBlank(); +EXTERNC void extapp_clipboardStore(const char *text); +EXTERNC const char * extapp_clipboardText(); +EXTERNC int extapp_fileListWithExtension(const char ** filenames, int maxrecords, const char * extension, int storage); +EXTERNC bool extapp_fileExists(const char * filename, int storage); +EXTERNC bool extapp_fileErase(const char * filename, int storage); +EXTERNC const char * extapp_fileRead(const char * filename, size_t *len, int storage); +EXTERNC bool extapp_fileWrite(const char * filename, const char * content, size_t len, int storage); +EXTERNC void extapp_lockAlpha(); +EXTERNC void extapp_resetKeyboard(); +EXTERNC int extapp_getKey(bool allowSuspend, bool *alphaWasActive); + +#endif diff --git a/apps/external/external_icon.png b/apps/external/external_icon.png new file mode 100644 index 000000000..297dc31c6 Binary files /dev/null and b/apps/external/external_icon.png differ diff --git a/apps/external/main_controller.cpp b/apps/external/main_controller.cpp new file mode 100644 index 000000000..627fbca08 --- /dev/null +++ b/apps/external/main_controller.cpp @@ -0,0 +1,98 @@ +#include "main_controller.h" +#include +#include +#include +#include "archive.h" +#include "app.h" + +using namespace Poincare; + +namespace External { + +using namespace Archive; + +MainController::MainController(Responder * parentResponder, ::App * app) : + ViewController(parentResponder), + m_selectableTableView(this) +{ + m_app = app; +} + +View * MainController::view() { + return &m_selectableTableView; +} + +void MainController::didBecomeFirstResponder() { + if (selectedRow() < 0) { + selectCellAtLocation(0, 0); + } + Container::activeApp()->setFirstResponder(&m_selectableTableView); +} + +bool MainController::handleEvent(Ion::Events::Event event) { + if (numberOfRows() > 0 && (event == Ion::Events::OK || event == Ion::Events::EXE)) { + uint32_t res = executeFile(m_cells[selectedRow()].text(), ((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; + } + return false; +} + +int MainController::numberOfRows() const { + return k_numberOfCells; +}; + +KDCoordinate MainController::rowHeight(int j) { + return Metric::ParameterCellHeight; +} + +KDCoordinate MainController::cumulatedHeightFromIndex(int j) { + return j*rowHeight(0); +} + +int MainController::indexFromCumulatedHeight(KDCoordinate offsetY) { + return offsetY/rowHeight(0); +} + +HighlightCell * MainController::reusableCell(int index, int type) { + assert(index < k_numberOfCells); + return &m_cells[index]; +} + +int MainController::reusableCellCount(int type) { + return k_numberOfCells; +} + +int MainController::typeAtLocation(int i, int j) { + return 0; +} + +void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { + PointerTextTableCell * myTextCell = (PointerTextTableCell *)cell; + struct File f; + if(fileAtIndex(index, f)) { + myTextCell->setText(f.name); + myTextCell->setTextColor(f.isExecutable ? KDColorBlack : Palette::GreyDark); + } +} + +void MainController::viewWillAppear() { + int count = numberOfFiles(); + k_numberOfCells = count <= k_maxNumberOfCells ? count : k_maxNumberOfCells; + m_selectableTableView.reloadData(); +} + +} diff --git a/apps/external/main_controller.h b/apps/external/main_controller.h new file mode 100644 index 000000000..bdb6d275b --- /dev/null +++ b/apps/external/main_controller.h @@ -0,0 +1,34 @@ +#ifndef EXTERNAL_MAIN_CONTROLLER_H +#define EXTERNAL_MAIN_CONTROLLER_H + +#include +#include "pointer_text_table_cell.h" + +namespace External { + +class MainController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource { +public: + MainController(Responder * parentResponder, App * app); + View * view() override; + bool handleEvent(Ion::Events::Event event) override; + void didBecomeFirstResponder() override; + int numberOfRows() const override; + KDCoordinate rowHeight(int j) override; + KDCoordinate cumulatedHeightFromIndex(int j) override; + int indexFromCumulatedHeight(KDCoordinate offsetY) override; + HighlightCell * reusableCell(int index, int type) override; + int reusableCellCount(int type) override; + int typeAtLocation(int i, int j) override; + void willDisplayCellForIndex(HighlightCell * cell, int index) override; + void viewWillAppear() override; +private: + App * m_app; + SelectableTableView m_selectableTableView; + int k_numberOfCells = 1; + constexpr static int k_maxNumberOfCells = 16; + PointerTextTableCell m_cells[k_maxNumberOfCells]; +}; + +} + +#endif diff --git a/apps/external/pointer_text_table_cell.cpp b/apps/external/pointer_text_table_cell.cpp new file mode 100644 index 000000000..00967fafb --- /dev/null +++ b/apps/external/pointer_text_table_cell.cpp @@ -0,0 +1,38 @@ +#include "pointer_text_table_cell.h" +#include +#include +#include + +PointerTextTableCell::PointerTextTableCell(const char * text, const KDFont * font, Layout layout) : + TableCell(layout), + m_pointerTextView(font, text, 0, 0.5, KDColorBlack, KDColorWhite) +{ +} + +View * PointerTextTableCell::labelView() const { + return (View *)&m_pointerTextView; +} + +const char * PointerTextTableCell::text() const { + return m_pointerTextView.text(); +} + +void PointerTextTableCell::setHighlighted(bool highlight) { + HighlightCell::setHighlighted(highlight); + KDColor backgroundColor = highlight? Palette::ListCellBackgroundSelected : Palette::ListCellBackground; + m_pointerTextView.setBackgroundColor(backgroundColor); +} + +void PointerTextTableCell::setText(const char * text) { + m_pointerTextView.setText(text); + layoutSubviews(); +} + +void PointerTextTableCell::setTextColor(KDColor color) { + m_pointerTextView.setTextColor(color); +} + +void PointerTextTableCell::setTextFont(const KDFont * font) { + m_pointerTextView.setFont(font); + layoutSubviews(); +} diff --git a/apps/external/pointer_text_table_cell.h b/apps/external/pointer_text_table_cell.h new file mode 100644 index 000000000..be011b76e --- /dev/null +++ b/apps/external/pointer_text_table_cell.h @@ -0,0 +1,20 @@ +#ifndef ESCHER_POINTER_TEXT_TABLE_CELL_H +#define ESCHER_POINTER_TEXT_TABLE_CELL_H + +#include +#include + +class PointerTextTableCell : public TableCell { +public: + PointerTextTableCell(const char * text = "", const KDFont * font = KDFont::SmallFont, Layout layout = Layout::Horizontal); + View * labelView() const override; + const char * text() const override; + virtual void setHighlighted(bool highlight) override; + void setText(const char * text); + virtual void setTextColor(KDColor color); + void setTextFont(const KDFont * font); +private: + PointerTextView m_pointerTextView; +}; + +#endif diff --git a/apps/global_preferences.cpp b/apps/global_preferences.cpp index f509b7a65..d05127172 100644 --- a/apps/global_preferences.cpp +++ b/apps/global_preferences.cpp @@ -5,6 +5,37 @@ GlobalPreferences * GlobalPreferences::sharedGlobalPreferences() { return &globalPreferences; } +GlobalPreferences::ExamMode GlobalPreferences::examMode() const { + if (m_examMode == ExamMode::Unknown) { + uint8_t mode = Ion::ExamMode::FetchExamMode(); + assert(mode >= 0 && mode < 4); // mode can be cast in ExamMode (Off, Standard, NoSym or Dutch) + m_examMode = (ExamMode)mode; + } + return m_examMode; +} + +GlobalPreferences::ExamMode GlobalPreferences::tempExamMode() const { + return m_tempExamMode; +} + + +void GlobalPreferences::setExamMode(ExamMode mode) { + ExamMode currentMode = examMode(); + if (currentMode == mode) { + return; + } + assert(mode != ExamMode::Unknown); + int8_t deltaMode = (int8_t)mode - (int8_t)currentMode; + deltaMode = deltaMode < 0 ? deltaMode + 4 : deltaMode; + assert(deltaMode > 0); + Ion::ExamMode::IncrementExamMode(deltaMode); + m_examMode = mode; +} + +void GlobalPreferences::setTempExamMode(ExamMode mode) { + m_tempExamMode = mode; +} + void GlobalPreferences::setBrightnessLevel(int brightnessLevel) { if (m_brightnessLevel != brightnessLevel) { brightnessLevel = brightnessLevel < 0 ? 0 : brightnessLevel; diff --git a/apps/global_preferences.h b/apps/global_preferences.h index 201957ab2..adf5e27fd 100644 --- a/apps/global_preferences.h +++ b/apps/global_preferences.h @@ -5,15 +5,22 @@ class GlobalPreferences { public: - enum class ExamMode { - Activate, - Deactivate + enum class ExamMode : int8_t { + Unknown = -1, + Off = 0, + Standard = 1, + NoSym = 2, + Dutch = 3, }; static GlobalPreferences * sharedGlobalPreferences(); I18n::Language language() const { return m_language; } void setLanguage(I18n::Language language) { m_language = language; } - ExamMode examMode() const { return m_examMode; } - void setExamMode(ExamMode examMode) { m_examMode = examMode; } + bool isInExamMode() const { return (int8_t)examMode() > 0; } + bool isInExamModeSymbolic() const { return !((int8_t)examMode() > 1); } + ExamMode examMode() const; + ExamMode tempExamMode() const; + void setExamMode(ExamMode examMode); + void setTempExamMode(ExamMode examMode); bool showPopUp() const { return m_showPopUp; } void setShowPopUp(bool showPopUp) { m_showPopUp = showPopUp; } int brightnessLevel() const { return m_brightnessLevel; } @@ -22,11 +29,15 @@ public: private: GlobalPreferences() : m_language(I18n::Language::EN), - m_examMode(ExamMode::Deactivate), + m_examMode(ExamMode::Unknown), + m_tempExamMode(ExamMode::Standard), m_showPopUp(true), m_brightnessLevel(Ion::Backlight::MaxBrightness) {} I18n::Language m_language; - ExamMode m_examMode; + static_assert((int8_t)GlobalPreferences::ExamMode::Off == 0, "GlobalPreferences::isInExamMode() is not right"); + static_assert((int8_t)GlobalPreferences::ExamMode::Unknown < 0, "GlobalPreferences::isInExamMode() is not right"); + mutable ExamMode m_examMode; + mutable ExamMode m_tempExamMode; bool m_showPopUp; int m_brightnessLevel; }; diff --git a/apps/hardware_test/Makefile b/apps/hardware_test/Makefile index 6921f94ed..339b8887c 100644 --- a/apps/hardware_test/Makefile +++ b/apps/hardware_test/Makefile @@ -6,6 +6,7 @@ app_hardware_test_src = $(addprefix apps/hardware_test/,\ colors_lcd_test_controller.cpp \ dead_pixels_test_controller.cpp \ keyboard_test_controller.cpp \ + keyboard_model.cpp \ keyboard_view.cpp \ lcd_data_test_controller.cpp \ lcd_timing_test_controller.cpp \ diff --git a/apps/hardware_test/keyboard_model.cpp b/apps/hardware_test/keyboard_model.cpp new file mode 100644 index 000000000..0bc9b5084 --- /dev/null +++ b/apps/hardware_test/keyboard_model.cpp @@ -0,0 +1,16 @@ +#include "keyboard_model.h" + +namespace HardwareTest { + +constexpr Ion::Keyboard::Key KeyboardModel::TestedKeys[KeyboardModel::NumberOfTestedKeys]; + +bool KeyboardModel::belongsToTestedKeysSubset(Ion::Keyboard::Key key) const { + for (int i = 0; i < NumberOfTestedKeys; i++) { + if (TestedKeys[i] == key) { + return true; + } + } + return false; +} + +} diff --git a/apps/hardware_test/keyboard_model.h b/apps/hardware_test/keyboard_model.h new file mode 100644 index 000000000..8c0c8e47b --- /dev/null +++ b/apps/hardware_test/keyboard_model.h @@ -0,0 +1,37 @@ +#ifndef HARDWARE_TEST_KEYBOARD_MODEL_H +#define HARDWARE_TEST_KEYBOARD_MODEL_H + +#include + +namespace HardwareTest { + +class KeyboardModel { +public: + KeyboardModel() : m_testedKeyIndex(0) {} + Ion::Keyboard::Key testedKey() const { return TestedKeys[m_testedKeyIndex]; } + int testedKeyIndex() const { return m_testedKeyIndex; } + void setTestedKeyIndex(int i) { + assert(i >= 0 && i < NumberOfTestedKeys); + m_testedKeyIndex = i; + } + bool belongsToTestedKeysSubset(Ion::Keyboard::Key key) const; + + static constexpr int NumberOfTestedKeys = 20; + static constexpr Ion::Keyboard::Key TestedKeys[KeyboardModel::NumberOfTestedKeys] = { + Ion::Keyboard::Key::Left, Ion::Keyboard::Key::Up, Ion::Keyboard::Key::Down, Ion::Keyboard::Key::Right, Ion::Keyboard::Key::OK, Ion::Keyboard::Key::Back, + Ion::Keyboard::Key::Home, Ion::Keyboard::Key::OnOff, + Ion::Keyboard::Key::Shift, Ion::Keyboard::Key::Alpha, Ion::Keyboard::Key::XNT, Ion::Keyboard::Key::Var, Ion::Keyboard::Key::Toolbox, Ion::Keyboard::Key::Backspace, + Ion::Keyboard::Key::Power, + Ion::Keyboard::Key::Square, + Ion::Keyboard::Key::RightParenthesis, + Ion::Keyboard::Key::Division, + Ion::Keyboard::Key::Minus, + Ion::Keyboard::Key::EXE + }; +private: + int m_testedKeyIndex; +}; +} + +#endif + diff --git a/apps/hardware_test/keyboard_test_controller.cpp b/apps/hardware_test/keyboard_test_controller.cpp index 730b2340c..c787ec289 100644 --- a/apps/hardware_test/keyboard_test_controller.cpp +++ b/apps/hardware_test/keyboard_test_controller.cpp @@ -17,10 +17,10 @@ View * KeyboardTestController::view() { bool KeyboardTestController::handleEvent(Ion::Events::Event event) { Ion::Keyboard::State state = Ion::Keyboard::scan(); - Ion::Keyboard::State onlyKeyDown = Ion::Keyboard::State(Ion::Keyboard::ValidKeys[m_keyboardView.testedKeyIndex()]); + Ion::Keyboard::State onlyKeyDown = Ion::Keyboard::State(KeyboardModel::TestedKeys[m_keyboardView.testedKeyIndex()]); if (state == onlyKeyDown) { - m_keyboardView.setTestedKeyIndex(m_keyboardView.testedKeyIndex()+1); - if (m_keyboardView.testedKeyIndex() == Ion::Keyboard::NumberOfValidKeys) { + m_keyboardView.setTestedKeyIndex(m_keyboardView.testedKeyIndex() + 1); + if (m_keyboardView.testedKeyIndex() == KeyboardModel::NumberOfTestedKeys) { // Returning false will go to the next step in the WizardViewController return false; } diff --git a/apps/hardware_test/keyboard_view.cpp b/apps/hardware_test/keyboard_view.cpp index 41c2cb694..1b15f28df 100644 --- a/apps/hardware_test/keyboard_view.cpp +++ b/apps/hardware_test/keyboard_view.cpp @@ -3,17 +3,8 @@ namespace HardwareTest { -KeyboardView::KeyboardView() : - m_testedKeyIndex(0) -{ -} - -int KeyboardView::testedKeyIndex() const { - return m_testedKeyIndex; -} - void KeyboardView::setTestedKeyIndex(int i) { - m_testedKeyIndex = i; + m_keyboardModel.setTestedKeyIndex(i); markRectAsDirty(bounds()); } @@ -26,11 +17,8 @@ void KeyboardView::drawRect(KDContext * ctx, KDRect rect) const { } void KeyboardView::drawKey(int keyIndex, KDContext * ctx, KDRect rect) const { - KDColor color = keyIndex < m_testedKeyIndex ? KDColorGreen: KDColorBlack; - if (keyIndex == m_testedKeyIndex) { - color = KDColorBlue; - } Ion::Keyboard::Key key = Ion::Keyboard::ValidKeys[keyIndex]; + KDColor color = keyColor(key); /* the key is on the cross */ if ((uint8_t)key < 4) { KDCoordinate x = (uint8_t)key == 1 || (uint8_t)key == 2 ? k_margin + k_smallSquareSize : k_margin; @@ -69,4 +57,14 @@ void KeyboardView::drawKey(int keyIndex, KDContext * ctx, KDRect rect) const { } } +KDColor KeyboardView::keyColor(Ion::Keyboard::Key key) const { + if (!m_keyboardModel.belongsToTestedKeysSubset(key)) { + return Palette::GreyBright; + } + if (m_keyboardModel.testedKey() == key) { + return KDColorBlue; + } + return (uint8_t)key < (uint8_t)m_keyboardModel.testedKey() ? KDColorGreen : KDColorBlack; +} + } diff --git a/apps/hardware_test/keyboard_view.h b/apps/hardware_test/keyboard_view.h index 47d36abff..1d02b0b5f 100644 --- a/apps/hardware_test/keyboard_view.h +++ b/apps/hardware_test/keyboard_view.h @@ -2,17 +2,19 @@ #define HARDWARE_TEST_KEYBOARD_VIEW_H #include +#include "keyboard_model.h" namespace HardwareTest { class KeyboardView : public View { public: - KeyboardView(); - int testedKeyIndex() const; + KeyboardView() : m_keyboardModel() {} + int testedKeyIndex() const { return m_keyboardModel.testedKeyIndex(); } void setTestedKeyIndex(int i); void drawRect(KDContext * ctx, KDRect rect) const override; private: void drawKey(int key, KDContext * ctx, KDRect rect) const; + KDColor keyColor(Ion::Keyboard::Key key) const; constexpr static int k_margin = 4; constexpr static int k_smallSquareSize = 8; constexpr static int k_bigSquareSize = 14; @@ -20,7 +22,7 @@ private: constexpr static int k_smallRectWidth = 16; constexpr static int k_bigRectHeight = 14; constexpr static int k_bigRectWidth = 20; - int m_testedKeyIndex; + KeyboardModel m_keyboardModel; }; } diff --git a/apps/home/base.de.i18n b/apps/home/base.de.i18n index dbfdc7c34..352d41520 100644 --- a/apps/home/base.de.i18n +++ b/apps/home/base.de.i18n @@ -1,2 +1,4 @@ Apps = "Anwendungen" AppsCapital = "OMEGA" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.en.i18n b/apps/home/base.en.i18n index f86319c3b..dde4e2129 100644 --- a/apps/home/base.en.i18n +++ b/apps/home/base.en.i18n @@ -1,2 +1,4 @@ Apps = "Applications" AppsCapital = "OMEGA" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.es.i18n b/apps/home/base.es.i18n index cfad4a8e3..9d3258766 100644 --- a/apps/home/base.es.i18n +++ b/apps/home/base.es.i18n @@ -1,2 +1,4 @@ Apps = "Aplicaciones" AppsCapital = "OMEGA" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.fr.i18n b/apps/home/base.fr.i18n index f86319c3b..dde4e2129 100644 --- a/apps/home/base.fr.i18n +++ b/apps/home/base.fr.i18n @@ -1,2 +1,4 @@ Apps = "Applications" AppsCapital = "OMEGA" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/base.pt.i18n b/apps/home/base.pt.i18n index bdd4d1f63..5e84c0ba1 100644 --- a/apps/home/base.pt.i18n +++ b/apps/home/base.pt.i18n @@ -1,2 +1,4 @@ Apps = "Aplicações" AppsCapital = "OMEGA" +ForbidenAppInExamMode1 = "This application is" +ForbidenAppInExamMode2 = "forbidden in exam mode" diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index cd2919556..2cd40bf8f 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -58,9 +58,15 @@ Controller::Controller(Responder * parentResponder, SelectableTableViewDataSourc bool Controller::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { AppsContainer * container = AppsContainer::sharedAppsContainer(); - bool switched = container->switchTo(container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1)); - assert(switched); - (void) switched; // Silence compilation warning about unused variable. + ::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1); + if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch && + (selectedSnapshot->descriptor()->name() == I18n::Message::CodeApp || selectedSnapshot->descriptor()->name() == I18n::Message::ExternalApp)) { + App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2); + } else { + bool switched = container->switchTo(selectedSnapshot); + assert(switched); + (void) switched; // Silence compilation warning about unused variable. + } return true; } diff --git a/apps/on_boarding/logo_controller.cpp b/apps/on_boarding/logo_controller.cpp index 197a29e7b..13df87e4d 100644 --- a/apps/on_boarding/logo_controller.cpp +++ b/apps/on_boarding/logo_controller.cpp @@ -1,5 +1,7 @@ #include "logo_controller.h" #include "power_on_self_test.h" +#include +#include #include namespace OnBoarding { @@ -45,6 +47,11 @@ void LogoController::viewWillAppear() { void LogoController::viewDidDisappear() { if (m_didPerformTests) { Ion::LED::setColor(m_previousLEDColor); + /* TODO: instead of setting again the exam mode, put the previous led color + * AND BLINKING.*/ + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + AppsContainer::sharedAppsContainer()->activateExamMode(GlobalPreferences::sharedGlobalPreferences()->examMode()); + } } ViewController::viewDidDisappear(); } diff --git a/apps/on_boarding/power_on_self_test.cpp b/apps/on_boarding/power_on_self_test.cpp index f83e30347..5bdeb1807 100644 --- a/apps/on_boarding/power_on_self_test.cpp +++ b/apps/on_boarding/power_on_self_test.cpp @@ -6,7 +6,7 @@ namespace OnBoarding { KDColor PowerOnSelfTest::Perform() { KDColor previousLEDColor = Ion::LED::getColor(); - KDColor resultColor = KDColorGreen; + KDColor resultColor = KDColorWhite; // Screen tests bool screenTestsOK = Shared::POSTAndHardwareTests::VBlankOK() && (Shared::POSTAndHardwareTests::TextLCDGlyphFailures() <= k_textErrorsLimit); @@ -20,7 +20,7 @@ KDColor PowerOnSelfTest::Perform() { resultColor = KDColorRed; } } else { - resultColor = KDColorBlue; + resultColor = KDColorPurple; } Ion::LED::setColor(resultColor); return previousLEDColor; diff --git a/apps/settings/Makefile b/apps/settings/Makefile index bb3156a6d..1226acb40 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -15,7 +15,6 @@ app_settings_src = $(addprefix apps/settings/,\ sub_menu/preferences_controller.cpp \ sub_menu/contributors_controller.cpp \ sub_menu/math_options_controller.cpp \ - sub_menu/symbol_controller.cpp \ ) app_src += $(app_settings_src) diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 844dfe30b..cf1e413b8 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -7,8 +7,8 @@ EditionLinear = "Linear " Edition2D = "Natürlich " ComplexFormat = "Komplex" ExamMode = "Testmodus" -ActivateExamMode = "Start Testmodus" -ExamModeActive = "Testmodus: aktiv" +ActivateExamMode = "Starten Testmodus" +ExamModeActive = "Wieder starten Testmodus" About = "Über" Degrees = "Grad " Gradians = "Gone " @@ -24,10 +24,15 @@ Brightness = "Helligkeit" SoftwareVersion = "Epsilon version" CustomSoftwareVersion = "Omega version" Username = "Name" +MicroPythonVersion = "µPythonversion" SerialNumber = "Seriennummer" UpdatePopUp = "Erinnerung: Update" BetaPopUp = "Beta pop-up" LEDColor = "LEDs farbe" +ExamModeMode = "Modus" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "Ohne symbolisch " +ExamModeModeDutch = "Niederländisch " ColorWhite = "Weiss " ColorBlue = "Blau " ColorGreen = "Grün " @@ -41,8 +46,8 @@ AccessibilityGammaRed = "Rotes Gamma" AccessibilityGammaGreen = "Grünes Gamma" AccessibilityGammaBlue = "Blaues Gamma" MathOptions = "Mathe-optionen" -SymbolMultiplication = "Multiplikationszeichen" -SymbolMultiplicationCross = "Kreuz" -SymbolMultiplicationMiddleDot = "Mittelpunkt" -SymbolMultiplicationStar = "Stern" -SymbolMultiplicationAutoSymbol = "automatisch" +SymbolMultiplication = "Multiplikation" +SymbolMultiplicationCross = "Kreuz " +SymbolMultiplicationMiddleDot = "Mittelpunkt " +SymbolMultiplicationStar = "Stern " +SymbolMultiplicationAutoSymbol = "automatisch " \ No newline at end of file diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index ef738ead6..811b3acf2 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -8,7 +8,7 @@ Edition2D = "Natural " ComplexFormat = "Complex format" ExamMode = "Exam mode" ActivateExamMode = "Activate exam mode" -ExamModeActive = "Exam mode: active" +ExamModeActive = "Reactivate exam mode" About = "About" Degrees = "Degrees " Gradians = "Gradians " @@ -24,10 +24,15 @@ Brightness = "Brightness" SoftwareVersion = "Epsilon version" CustomSoftwareVersion = "Omega version" Username = "Name" +MicroPythonVersion = "µPython version" SerialNumber = "Serial number" UpdatePopUp = "Update pop-up" BetaPopUp = "Beta pop-up" LEDColor = "LED color" +ExamModeMode = "Mode" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "No sym " +ExamModeModeDutch = "Dutch " ColorWhite = "White " ColorBlue = "Blue " ColorGreen = "Green " @@ -41,8 +46,8 @@ AccessibilityGammaRed = "Red gamma" AccessibilityGammaGreen = "Green gamma" AccessibilityGammaBlue = "Blue gamma" MathOptions = "Math options" -SymbolMultiplication = "Multiplication sign" -SymbolMultiplicationCross = "Cross" -SymbolMultiplicationMiddleDot = "Middle dot" -SymbolMultiplicationStar = "Star" -SymbolMultiplicationAutoSymbol = "Automatic" +SymbolMultiplication = "Multiply" +SymbolMultiplicationCross = "Cross " +SymbolMultiplicationMiddleDot = "Dot " +SymbolMultiplicationStar = "Star " +SymbolMultiplicationAutoSymbol = "Auto " \ No newline at end of file diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index abfb8edc5..4ecd529aa 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -8,7 +8,7 @@ Edition2D = "Natural " ComplexFormat = "Forma compleja" ExamMode = "Modo examen" ActivateExamMode = "Activar el modo examen" -ExamModeActive = "Modo examen: activo" +ExamModeActive = "Reactivar el modo examen" About = "Acerca" Degrees = "Grados " Gradians = "Gradianes " @@ -24,10 +24,15 @@ Brightness = "Brillo" SoftwareVersion = "Versión de Epsilon" CustomSoftwareVersion = "Versión de Omega" Username = "Apellido" +MicroPythonVersion = "Version de µPython" SerialNumber = "Número serie" UpdatePopUp = "Pop-up de actualización" BetaPopUp = "Beta pop-up" LEDColor = "Color del LED" +ExamModeMode = "Modo" +ExamModeModeStandard = "Estándar " +ExamModeModeNoSym = "Sin simbólico " +ExamModeModeDutch = "Holandés " ColorWhite = "Blanco " ColorBlue = "Azul " ColorGreen = "Verde " @@ -41,8 +46,8 @@ AccessibilityGammaRed = "Gamma roja" AccessibilityGammaGreen = "Gamma verde" AccessibilityGammaBlue = "Gamma azul" MathOptions = "Matemáticas" -SymbolMultiplication = "signo de multiplicación" -SymbolMultiplicationCross = "contrariar" -SymbolMultiplicationMiddleDot = "punto medio" -SymbolMultiplicationStar = "estrella" -SymbolMultiplicationAutoSymbol = "automático" +SymbolMultiplication = "Multiplicación" +SymbolMultiplicationCross = "Contrariar " +SymbolMultiplicationMiddleDot = "Punto " +SymbolMultiplicationStar = "Estrella " +SymbolMultiplicationAutoSymbol = "Auto " \ No newline at end of file diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index 534510529..f2c8b0a39 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -8,7 +8,7 @@ Edition2D = "Naturelle " ComplexFormat = "Forme complexe" ExamMode = "Mode examen" ActivateExamMode = "Activer le mode examen" -ExamModeActive = "Mode examen: actif" +ExamModeActive = "Réactiver le mode examen" About = "À propos" Degrees = "Degrés " Gradians = "Grades " @@ -24,10 +24,15 @@ Brightness = "Luminosité" SoftwareVersion = "Version d'Epsilon" CustomSoftwareVersion = "Version d'Omega" Username = "Nom" +MicroPythonVersion = "Version de µPython" SerialNumber = "Numéro série" UpdatePopUp = "Rappel mise à jour" BetaPopUp = "Rappel version bêta" LEDColor = "Couleur LED" +ExamModeMode = "Mode" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "Sans symbolique " +ExamModeModeDutch = "Néerlandais " ColorWhite = "Blanc " ColorBlue = "Bleu " ColorGreen = "Vert " @@ -41,8 +46,8 @@ AccessibilityGammaRed = "Gamma rouge" AccessibilityGammaGreen = "Gamma vert" AccessibilityGammaBlue = "Gamma bleu" MathOptions = "Math" -SymbolMultiplication = "Signe de multiplication" -SymbolMultiplicationCross = "Croix" -SymbolMultiplicationMiddleDot = "Point" -SymbolMultiplicationStar = "Etoile" -SymbolMultiplicationAutoSymbol = "Automatique" +SymbolMultiplication = "Multiplication" +SymbolMultiplicationCross = "Croix " +SymbolMultiplicationMiddleDot = "Point " +SymbolMultiplicationStar = "Etoile " +SymbolMultiplicationAutoSymbol = "Automatique " \ No newline at end of file diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 52e5c0e11..8194baeff 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -6,9 +6,9 @@ EditionMode = "Formato escrita " EditionLinear = "Em linha " Edition2D = "Natural " ComplexFormat = "Complexos" -ExamMode = "Modo de Exame" -ActivateExamMode = "Inicio modo de exame" -ExamModeActive = "Modo de exame : ativo" +ExamMode = "Modo de exame" +ActivateExamMode = "Ativar o modo de exame" +ExamModeActive = "Reativar o modo de exame" About = "Acerca" Degrees = "Graus " Gradians = "Grados " @@ -24,10 +24,15 @@ Brightness = "Brilho" SoftwareVersion = "Versão do Epsilon" CustomSoftwareVersion = "Versão do Omega" Username = "Nome" +MicroPythonVersion = "Versao do µPython" SerialNumber = "Número serie" UpdatePopUp = "Alertas de atualização" BetaPopUp = "Beta pop-up" LEDColor = "Cor LED" +ExamModeMode = "Modo" +ExamModeModeStandard = "Padrão " +ExamModeModeNoSym = "Sem simbólico " +ExamModeModeDutch = "Holandês " ColorWhite = "Branco " ColorBlue = "Azul " ColorGreen = "Verde " @@ -41,8 +46,8 @@ AccessibilityGammaRed = "Gama vermelha" AccessibilityGammaGreen = "Gama verde" AccessibilityGammaBlue = "Gama azul" MathOptions = "Matemática" -SymbolMultiplication = "Sinal de multiplicação" -SymbolMultiplicationCross = "crómio" -SymbolMultiplicationMiddleDot = "ponto médio" -SymbolMultiplicationStar = "estrela" -SymbolMultiplicationAutoSymbol = "automático" +SymbolMultiplication = "Multiplicação" +SymbolMultiplicationCross = "crómio " +SymbolMultiplicationMiddleDot = "ponto médio " +SymbolMultiplicationStar = "estrela " +SymbolMultiplicationAutoSymbol = "automático " \ No newline at end of file diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 59ac61ca8..12419bc55 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -2,6 +2,7 @@ #include "../global_preferences.h" #include #include +#include using namespace Poincare; @@ -36,6 +37,13 @@ void MainController::didBecomeFirstResponder() { bool MainController::handleEvent(Ion::Events::Event event) { GlobalPreferences * globalPreferences = GlobalPreferences::sharedGlobalPreferences(); + if (event == Ion::Events::BrightnessPlus || event == Ion::Events::BrightnessMinus){ + int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates; + int direction = (event == Ion::Events::BrightnessPlus) ? Ion::Backlight::NumberOfStepsPerShortcut*delta : -delta*Ion::Backlight::NumberOfStepsPerShortcut; + GlobalPreferences::sharedGlobalPreferences()->setBrightnessLevel(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()+direction); + m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), 1); + return true; + } if (model()->children(selectedRow())->numberOfChildren() == 0) { if (model()->children(selectedRow())->label() == promptMessage()) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h index 2a371b0c9..bfa85be37 100644 --- a/apps/settings/main_controller.h +++ b/apps/settings/main_controller.h @@ -8,7 +8,6 @@ #include "sub_menu/exam_mode_controller.h" #include "sub_menu/language_controller.h" #include "sub_menu/math_options_controller.h" -#include "sub_menu/symbol_controller.h" namespace Settings { diff --git a/apps/settings/main_controller_prompt_beta.cpp b/apps/settings/main_controller_prompt_beta.cpp index ec8d244b7..871ee77da 100644 --- a/apps/settings/main_controller_prompt_beta.cpp +++ b/apps/settings/main_controller_prompt_beta.cpp @@ -5,7 +5,8 @@ namespace Settings { //sub-sub-menus constexpr SettingsMessageTree s_ledColorChildren[4] = {SettingsMessageTree(I18n::Message::ColorWhite), SettingsMessageTree(I18n::Message::ColorGreen), SettingsMessageTree(I18n::Message::ColorBlue), SettingsMessageTree(I18n::Message::ColorYellow)}; -constexpr SettingsMessageTree s_contributorsChildren[5] = {SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::DannySimmons), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::MaximeFriess)}; +constexpr SettingsMessageTree s_examModeMode[3] = {SettingsMessageTree(I18n::Message::ExamModeModeStandard), SettingsMessageTree(I18n::Message::ExamModeModeNoSym), SettingsMessageTree(I18n::Message::ExamModeModeDutch)}; +constexpr SettingsMessageTree s_contributorsChildren[7] = {SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::DannySimmons), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::MaximeFriess), SettingsMessageTree(I18n::Message::David),SettingsMessageTree(I18n::Message::DamienNicolet)}; constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18n::Message::Degrees), SettingsMessageTree(I18n::Message::Radian), SettingsMessageTree(I18n::Message::Gradians)}; constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; @@ -14,25 +15,25 @@ constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::M //sub-menus constexpr SettingsMessageTree s_modelMathOptionsChildren[5] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren, 4)}; -constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::ActivateExamMode)}; +constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::ExamModeMode, s_examModeMode, 3), SettingsMessageTree(I18n::Message::ActivateExamMode)}; constexpr SettingsMessageTree s_accessibilityChildren[6] = {SettingsMessageTree(I18n::Message::AccessibilityInvertColors), SettingsMessageTree(I18n::Message::AccessibilityMagnify),SettingsMessageTree(I18n::Message::AccessibilityGamma),SettingsMessageTree(I18n::Message::AccessibilityGammaRed),SettingsMessageTree(I18n::Message::AccessibilityGammaGreen),SettingsMessageTree(I18n::Message::AccessibilityGammaBlue)}; #ifdef USERNAME -constexpr SettingsMessageTree s_modelAboutChildren[6] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; +constexpr SettingsMessageTree s_modelAboutChildren[7] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; #else -constexpr SettingsMessageTree s_modelAboutChildren[5] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; +constexpr SettingsMessageTree s_modelAboutChildren[6] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; #endif constexpr SettingsMessageTree s_modelMenu[] = {SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren, 5), SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), - SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), + SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 4), SettingsMessageTree(I18n::Message::BetaPopUp), SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren, 6), #ifdef USERNAME - SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 6)}; + SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 7)}; #else - SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 5)}; + SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 6)}; #endif constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 7); diff --git a/apps/settings/main_controller_prompt_none.cpp b/apps/settings/main_controller_prompt_none.cpp index bb4925f49..ab5072eaa 100644 --- a/apps/settings/main_controller_prompt_none.cpp +++ b/apps/settings/main_controller_prompt_none.cpp @@ -6,7 +6,8 @@ namespace Settings { // TODO: factorize most parts of the final models with main_controller_prompt_beta and main_controller_prompt_update //sub-sub-menus constexpr SettingsMessageTree s_ledColorChildren[4] = {SettingsMessageTree(I18n::Message::ColorWhite), SettingsMessageTree(I18n::Message::ColorGreen), SettingsMessageTree(I18n::Message::ColorBlue), SettingsMessageTree(I18n::Message::ColorYellow)}; -constexpr SettingsMessageTree s_contributorsChildren[5] = {SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::DannySimmons), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::MaximeFriess)}; +constexpr SettingsMessageTree s_examModeMode[3] = {SettingsMessageTree(I18n::Message::ExamModeModeStandard), SettingsMessageTree(I18n::Message::ExamModeModeNoSym), SettingsMessageTree(I18n::Message::ExamModeModeDutch)}; +constexpr SettingsMessageTree s_contributorsChildren[7] = {SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::DannySimmons), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::MaximeFriess), SettingsMessageTree(I18n::Message::David),SettingsMessageTree(I18n::Message::DamienNicolet)}; constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18n::Message::Degrees), SettingsMessageTree(I18n::Message::Radian), SettingsMessageTree(I18n::Message::Gradians)}; constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; @@ -15,24 +16,24 @@ constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::M //sub-menus constexpr SettingsMessageTree s_modelMathOptionsChildren[5] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren, 4)}; -constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::ActivateExamMode)}; +constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::ExamModeMode, s_examModeMode, 3), SettingsMessageTree(I18n::Message::ActivateExamMode)}; constexpr SettingsMessageTree s_accessibilityChildren[6] = {SettingsMessageTree(I18n::Message::AccessibilityInvertColors), SettingsMessageTree(I18n::Message::AccessibilityMagnify),SettingsMessageTree(I18n::Message::AccessibilityGamma),SettingsMessageTree(I18n::Message::AccessibilityGammaRed),SettingsMessageTree(I18n::Message::AccessibilityGammaGreen),SettingsMessageTree(I18n::Message::AccessibilityGammaBlue)}; #ifdef USERNAME -constexpr SettingsMessageTree s_modelAboutChildren[6] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; +constexpr SettingsMessageTree s_modelAboutChildren[7] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 7)}; #else -constexpr SettingsMessageTree s_modelAboutChildren[5] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; +constexpr SettingsMessageTree s_modelAboutChildren[6] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; #endif constexpr SettingsMessageTree s_modelMenu[] = {SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren, 5), SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), - SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), + SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 3), SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren, 6), #ifdef USERNAME - SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 6)}; + SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 7)}; #else - SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 5)}; + SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 6)}; #endif constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 6); diff --git a/apps/settings/main_controller_prompt_update.cpp b/apps/settings/main_controller_prompt_update.cpp index 16da8fc71..f02e894b9 100644 --- a/apps/settings/main_controller_prompt_update.cpp +++ b/apps/settings/main_controller_prompt_update.cpp @@ -5,7 +5,8 @@ namespace Settings { //sub-sub-menus constexpr SettingsMessageTree s_ledColorChildren[4] = {SettingsMessageTree(I18n::Message::ColorWhite), SettingsMessageTree(I18n::Message::ColorGreen), SettingsMessageTree(I18n::Message::ColorBlue), SettingsMessageTree(I18n::Message::ColorYellow)}; -constexpr SettingsMessageTree s_contributorsChildren[5] = {SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::DannySimmons), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::MaximeFriess)}; +constexpr SettingsMessageTree s_examModeMode[3] = {SettingsMessageTree(I18n::Message::ExamModeModeStandard), SettingsMessageTree(I18n::Message::ExamModeModeNoSym), SettingsMessageTree(I18n::Message::ExamModeModeDutch)}; +constexpr SettingsMessageTree s_contributorsChildren[7] = {SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::DannySimmons), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::MaximeFriess), SettingsMessageTree(I18n::Message::David),SettingsMessageTree(I18n::Message::DamienNicolet)}; constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18n::Message::Degrees), SettingsMessageTree(I18n::Message::Radian), SettingsMessageTree(I18n::Message::Gradians)}; constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; @@ -14,25 +15,25 @@ constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::M //sub-menus constexpr SettingsMessageTree s_modelMathOptionsChildren[5] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren, 4)}; -constexpr SettingsMessageTree s_modelExamChildren[2] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::ActivateExamMode)}; +constexpr SettingsMessageTree s_modelExamChildren[3] = {SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren, 4), SettingsMessageTree(I18n::Message::ExamModeMode, s_examModeMode, 3), SettingsMessageTree(I18n::Message::ActivateExamMode)}; constexpr SettingsMessageTree s_accessibilityChildren[6] = {SettingsMessageTree(I18n::Message::AccessibilityInvertColors), SettingsMessageTree(I18n::Message::AccessibilityMagnify),SettingsMessageTree(I18n::Message::AccessibilityGamma),SettingsMessageTree(I18n::Message::AccessibilityGammaRed),SettingsMessageTree(I18n::Message::AccessibilityGammaGreen),SettingsMessageTree(I18n::Message::AccessibilityGammaBlue)}; #ifdef USERNAME -constexpr SettingsMessageTree s_modelAboutChildren[6] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; +constexpr SettingsMessageTree s_modelAboutChildren[7] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; #else -constexpr SettingsMessageTree s_modelAboutChildren[5] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; +constexpr SettingsMessageTree s_modelAboutChildren[6] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::CustomSoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren, 5)}; #endif constexpr SettingsMessageTree s_modelMenu[] = {SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren, 5), SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), - SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 2), + SettingsMessageTree(I18n::Message::ExamMode, s_modelExamChildren, 4), SettingsMessageTree(I18n::Message::UpdatePopUp), SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren, 6), #ifdef USERNAME - SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 6)}; + SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 7)}; #else - SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 5)}; + SettingsMessageTree(I18n::Message::About, s_modelAboutChildren, 6)}; #endif constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu, 7); diff --git a/apps/settings/sub_menu/about_controller.cpp b/apps/settings/sub_menu/about_controller.cpp index 1cbb9ab42..eeebd539c 100644 --- a/apps/settings/sub_menu/about_controller.cpp +++ b/apps/settings/sub_menu/about_controller.cpp @@ -1,8 +1,12 @@ #include "about_controller.h" +#include "../../../python/src/py/mpconfig.h" #include #include #include +#define MP_STRINGIFY_HELPER(x) #x +#define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) + namespace Settings { AboutController::AboutController(Responder * parentResponder) : @@ -93,12 +97,14 @@ void AboutController::willDisplayCellForIndex(HighlightCell * cell, int index) { } else { MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)cell; + static const char * mpVersion = MICROPY_VERSION_STRING; static const char * messages[] = { #ifdef USERNAME Ion::username(), #endif Ion::softwareVersion(), Ion::customSoftwareVersion(), + mpVersion, Ion::serialNumber(), Ion::fccId() }; diff --git a/apps/settings/sub_menu/about_controller.h b/apps/settings/sub_menu/about_controller.h index 541360d19..9717df3ba 100644 --- a/apps/settings/sub_menu/about_controller.h +++ b/apps/settings/sub_menu/about_controller.h @@ -17,9 +17,9 @@ public: int typeAtLocation(int i, int j) override; private: #ifdef USERNAME - constexpr static int k_totalNumberOfCell = 6; + constexpr static int k_totalNumberOfCell = 7; #else - constexpr static int k_totalNumberOfCell = 5; + constexpr static int k_totalNumberOfCell = 6; #endif ContributorsController m_contributorsController; MessageTableCellWithChevronAndMessage m_contributorsCell; diff --git a/apps/settings/sub_menu/contributors_controller.cpp b/apps/settings/sub_menu/contributors_controller.cpp index 50364cd62..e70db01bd 100644 --- a/apps/settings/sub_menu/contributors_controller.cpp +++ b/apps/settings/sub_menu/contributors_controller.cpp @@ -28,7 +28,19 @@ int ContributorsController::reusableCellCount(int type) { return k_totalNumberOfCell; } +constexpr static I18n::Message s_contributorsUsernames[7] = { + I18n::Message::PQuentinGuidee, + I18n::Message::PDannySimmons, + I18n::Message::PJoachimLeFournis, + I18n::Message::PJeanBaptisteBoric, + I18n::Message::PMaximeFriess, + I18n::Message::PDavid, + I18n::Message::PDamienNicolet +}; + void ContributorsController::willDisplayCellForIndex(HighlightCell * cell, int index) { + MessageTableCellWithBuffer * myTextCell = (MessageTableCellWithBuffer *)cell; + myTextCell->setAccessoryText(I18n::translate(s_contributorsUsernames[index])); GenericSubController::willDisplayCellForIndex(cell, index); } diff --git a/apps/settings/sub_menu/contributors_controller.h b/apps/settings/sub_menu/contributors_controller.h index deac2515e..71674836c 100644 --- a/apps/settings/sub_menu/contributors_controller.h +++ b/apps/settings/sub_menu/contributors_controller.h @@ -14,7 +14,7 @@ public: int reusableCellCount(int type) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; private: - constexpr static int k_totalNumberOfCell = 5; + constexpr static int k_totalNumberOfCell = 7; MessageTableCellWithBuffer m_cells[k_totalNumberOfCell]; }; diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp index 78ba177db..0909bc6f6 100644 --- a/apps/settings/sub_menu/exam_mode_controller.cpp +++ b/apps/settings/sub_menu/exam_mode_controller.cpp @@ -1,6 +1,7 @@ #include "exam_mode_controller.h" #include "../../global_preferences.h" #include "../../apps_container.h" +#include #include #include #include @@ -15,25 +16,28 @@ ExamModeController::ExamModeController(Responder * parentResponder) : GenericSubController(parentResponder), m_preferencesController(this), m_examModeCell(I18n::Message::Default, KDFont::LargeFont), - m_ledCell(KDFont::LargeFont, KDFont::SmallFont) + m_ledCell(KDFont::LargeFont, KDFont::SmallFont), + m_modeCell(KDFont::LargeFont, KDFont::SmallFont) { } -void ExamModeController::didEnterResponderChain(Responder * previousFirstResponder) { - m_selectableTableView.reloadData(); -} - bool ExamModeController::handleEvent(Ion::Events::Event event) { - I18n::Message childLabel = m_messageTreeModel->children(selectedRow())->label(); +I18n::Message childLabel = m_messageTreeModel->children(selectedRow())->label(); if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) { - if (childLabel == I18n::Message::ActivateExamMode || childLabel == I18n::Message::ExamModeActive) { - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) { - return false; - } - AppsContainer::sharedAppsContainer()->displayExamModePopUp(true); + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + // If the exam mode is already on, this re-activate the same exam mode + GlobalPreferences::ExamMode mode = GlobalPreferences::sharedGlobalPreferences()->examMode(); + if (childLabel == I18n::Message::ActivateExamMode || childLabel == I18n::Message::ExamModeActive) + AppsContainer::sharedAppsContainer()->displayExamModePopUp(mode); return true; } - if (childLabel == I18n::Message::LEDColor) { + + if (childLabel == I18n::Message::ActivateExamMode || childLabel == I18n::Message::ExamModeActive) { + GlobalPreferences::ExamMode mode = GlobalPreferences::ExamMode::Standard; + AppsContainer::sharedAppsContainer()->displayExamModePopUp(GlobalPreferences::sharedGlobalPreferences()->tempExamMode()); + return true; + } + if (childLabel == I18n::Message::LEDColor || childLabel == I18n::Message::ExamModeMode) { GenericSubController * subController = &m_preferencesController; subController->setMessageTreeModel(m_messageTreeModel->children(selectedRow())); StackViewController * stack = stackController(); @@ -45,23 +49,22 @@ bool ExamModeController::handleEvent(Ion::Events::Event event) { } HighlightCell * ExamModeController::reusableCell(int index, int type) { - assert(index == 0); - if (type == 0) { - return &m_ledCell; + assert(type == 0); + assert(index >= 0 && index < 3); + + switch(index) { + case 0: + return &m_ledCell; + case 1: + return &m_modeCell; + case 2: + return &m_examModeCell; } - return &m_examModeCell; } int ExamModeController::reusableCellCount(int type) { - switch (type) { - case 0: - return 1; - case 1: - return 1; - default: - assert(false); - return 0; - } + assert(type == 0); + return 3; } void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index) { @@ -69,7 +72,7 @@ void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index GenericSubController::willDisplayCellForIndex(cell, index); I18n::Message thisLabel = m_messageTreeModel->children(index)->label(); - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate && (thisLabel == I18n::Message::ActivateExamMode || thisLabel == I18n::Message::ExamModeActive)) { + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode() && (thisLabel == I18n::Message::ActivateExamMode || thisLabel == I18n::Message::ExamModeActive)) { MessageTableCell * myCell = (MessageTableCell *)cell; myCell->setMessage(I18n::Message::ExamModeActive); } @@ -78,17 +81,10 @@ void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index I18n::Message message = (I18n::Message) m_messageTreeModel->children(index)->children((int)preferences->colorOfLED())->label(); myTextCell->setSubtitle(message); } -} - -int ExamModeController::typeAtLocation(int i, int j) { - switch (j) { - case 0: - return 0; - case 1: - return 1; - default: - assert(false); - return 0; + if (thisLabel == I18n::Message::ExamModeMode) { + MessageTableCellWithChevronAndMessage * myTextCell = (MessageTableCellWithChevronAndMessage *)cell; + I18n::Message message = (I18n::Message) m_messageTreeModel->children(index)->children((uint8_t)GlobalPreferences::sharedGlobalPreferences()->tempExamMode() - 1)->label(); + myTextCell->setSubtitle(message); } } diff --git a/apps/settings/sub_menu/exam_mode_controller.h b/apps/settings/sub_menu/exam_mode_controller.h index de9b9f9ef..e2e7bb505 100644 --- a/apps/settings/sub_menu/exam_mode_controller.h +++ b/apps/settings/sub_menu/exam_mode_controller.h @@ -9,15 +9,14 @@ namespace Settings { class ExamModeController : public GenericSubController { public: ExamModeController(Responder * parentResponder); - void didEnterResponderChain(Responder * previousFirstResponder) override; bool handleEvent(Ion::Events::Event event) override; HighlightCell * reusableCell(int index, int type) override; int reusableCellCount(int type) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; - int typeAtLocation(int i, int j) override; private: MessageTableCell m_examModeCell; MessageTableCellWithChevronAndMessage m_ledCell; + MessageTableCellWithChevronAndMessage m_modeCell; PreferencesController m_preferencesController; }; diff --git a/apps/settings/sub_menu/generic_sub_controller.cpp b/apps/settings/sub_menu/generic_sub_controller.cpp index 96c0a39a4..67af6c918 100644 --- a/apps/settings/sub_menu/generic_sub_controller.cpp +++ b/apps/settings/sub_menu/generic_sub_controller.cpp @@ -26,8 +26,12 @@ View * GenericSubController::view() { return &m_selectableTableView; } +void GenericSubController::didEnterResponderChain(Responder * previousFirstResponder) { + selectCellAtLocation(0, initialSelectedRow()); + m_selectableTableView.reloadData(); +} + void GenericSubController::didBecomeFirstResponder() { - selectCellAtLocation(0, 0); Container::activeApp()->setFirstResponder(&m_selectableTableView); } @@ -75,10 +79,6 @@ void GenericSubController::setMessageTreeModel(const MessageTree * messageTreeMo m_messageTreeModel = (MessageTree *)messageTreeModel; } -void GenericSubController::viewWillAppear() { - m_selectableTableView.reloadData(); -} - void GenericSubController::viewDidDisappear() { m_selectableTableView.deselectTable(); } diff --git a/apps/settings/sub_menu/generic_sub_controller.h b/apps/settings/sub_menu/generic_sub_controller.h index 039d25ede..bcb700779 100644 --- a/apps/settings/sub_menu/generic_sub_controller.h +++ b/apps/settings/sub_menu/generic_sub_controller.h @@ -11,6 +11,7 @@ public: GenericSubController(Responder * parentResponder); const char * title() override; View * view() override; + void didEnterResponderChain(Responder * previousFirstResponder) override; void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; int numberOfRows() const override; @@ -20,10 +21,10 @@ public: virtual int typeAtLocation(int i, int j) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; void setMessageTreeModel(const MessageTree * messageTreeModel); - void viewWillAppear() override; void viewDidDisappear() override; protected: StackViewController * stackController() const; + virtual int initialSelectedRow() const { return 0; } constexpr static KDCoordinate k_topBottomMargin = 13; SelectableTableView m_selectableTableView; MessageTree * m_messageTreeModel; diff --git a/apps/settings/sub_menu/math_options_controller.cpp b/apps/settings/sub_menu/math_options_controller.cpp index c4235fbc1..5b4b42b7b 100644 --- a/apps/settings/sub_menu/math_options_controller.cpp +++ b/apps/settings/sub_menu/math_options_controller.cpp @@ -9,8 +9,7 @@ namespace Settings { MathOptionsController::MathOptionsController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate) : GenericSubController(parentResponder), m_preferencesController(this), - m_displayModeController(this, inputEventHandlerDelegate), - m_symbolController(this) + m_displayModeController(this, inputEventHandlerDelegate) { for (int i = 0; i < k_totalNumberOfCell; i++) { m_cells[i].setMessageFont(KDFont::LargeFont); @@ -22,8 +21,6 @@ bool MathOptionsController::handleEvent(Ion::Events::Event event) { GenericSubController * subController = nullptr; if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::DisplayMode) subController = &m_displayModeController; - else if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::SymbolMultiplication) - subController = &m_symbolController; else subController = &m_preferencesController; subController->setMessageTreeModel(m_messageTreeModel->children(selectedRow())); diff --git a/apps/settings/sub_menu/math_options_controller.h b/apps/settings/sub_menu/math_options_controller.h index dcd073c10..1db4c3104 100644 --- a/apps/settings/sub_menu/math_options_controller.h +++ b/apps/settings/sub_menu/math_options_controller.h @@ -4,7 +4,6 @@ #include "generic_sub_controller.h" #include #include "display_mode_controller.h" -#include "symbol_controller.h" #include "preferences_controller.h" namespace Settings { @@ -21,7 +20,6 @@ private: MessageTableCellWithChevronAndMessage m_cells[k_totalNumberOfCell]; PreferencesController m_preferencesController; DisplayModeController m_displayModeController; - SymbolController m_symbolController; }; } diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp index f335a2b32..62921e49a 100644 --- a/apps/settings/sub_menu/preferences_controller.cpp +++ b/apps/settings/sub_menu/preferences_controller.cpp @@ -23,7 +23,6 @@ PreferencesController::PreferencesController(Responder * parentResponder) : } void PreferencesController::didBecomeFirstResponder() { - selectCellAtLocation(0, valueIndexForPreference(m_messageTreeModel->label())); Container::activeApp()->setFirstResponder(&m_selectableTableView); } @@ -129,6 +128,40 @@ Layout PreferencesController::layoutForPreferences(I18n::Message message) { const char * text = " "; return LayoutHelper::String(text, strlen(text), k_layoutFont); } + + // Exam mode modes + case I18n::Message::ExamModeModeStandard: + { + const char * text = " "; + return LayoutHelper::String(text, strlen(text), k_layoutFont); + } + case I18n::Message::ExamModeModeNoSym: + { + const char * text = " "; + return LayoutHelper::String(text, strlen(text), k_layoutFont); + } + case I18n::Message::ExamModeModeDutch: + { + const char * text = " "; + return LayoutHelper::String(text, strlen(text), k_layoutFont); + } + + + // Symbol controller + case I18n::Message::SymbolMultiplicationCross: // × and · aren't single characters, so they cannot be constructed into codepoints..? + { + const char * text = "×"; + return LayoutHelper::String(text, strlen(text), k_layoutFont); + } + case I18n::Message::SymbolMultiplicationMiddleDot: + { + const char * text = "·"; + return LayoutHelper::String(text, strlen(text), k_layoutFont); + } + case I18n::Message::SymbolMultiplicationStar: + return CodePointLayout::Builder('*', k_layoutFont); + case I18n::Message::SymbolMultiplicationAutoSymbol: + return CodePointLayout::Builder(' ', k_layoutFont); default: assert(false); @@ -167,10 +200,14 @@ void PreferencesController::setPreferenceWithValueIndex(I18n::Message message, i preferences->setComplexFormat((Preferences::ComplexFormat)valueIndex); } else if (message == I18n::Message::LEDColor) { preferences->setColorOfLED((Preferences::LEDColor)valueIndex); + } else if (message == I18n::Message::ExamModeMode) { + GlobalPreferences::sharedGlobalPreferences()->setTempExamMode((GlobalPreferences::ExamMode)((uint8_t)valueIndex + 1)); + } else if (message == I18n::Message::SymbolMultiplication) { + preferences->setSymbolMultiplication((Preferences::SymbolMultiplication)valueIndex); } } -int PreferencesController::valueIndexForPreference(I18n::Message message) { +int PreferencesController::valueIndexForPreference(I18n::Message message) const { Preferences * preferences = Preferences::sharedPreferences(); if (message == I18n::Message::AngleUnit) { return (int)preferences->angleUnit(); @@ -187,6 +224,9 @@ int PreferencesController::valueIndexForPreference(I18n::Message message) { if (message == I18n::Message::LEDColor) { return (int)preferences->colorOfLED(); } + if (message == I18n::Message::SymbolMultiplication) { + return (int)preferences->symbolofMultiplication(); + } return 0; } diff --git a/apps/settings/sub_menu/preferences_controller.h b/apps/settings/sub_menu/preferences_controller.h index 01f2a66a6..56ea131b6 100644 --- a/apps/settings/sub_menu/preferences_controller.h +++ b/apps/settings/sub_menu/preferences_controller.h @@ -18,9 +18,10 @@ protected: constexpr static int k_totalNumberOfCell = 4; private: constexpr static const KDFont * k_layoutFont = KDFont::SmallFont; + int initialSelectedRow() const override { return valueIndexForPreference(m_messageTreeModel->label()); } Poincare::Layout layoutForPreferences(I18n::Message message); void setPreferenceWithValueIndex(I18n::Message message, int valueIndex); - int valueIndexForPreference(I18n::Message message); + int valueIndexForPreference(I18n::Message message) const; MessageTableCellWithExpression m_cells[k_totalNumberOfCell]; }; diff --git a/apps/settings/sub_menu/symbol_controller.cpp b/apps/settings/sub_menu/symbol_controller.cpp deleted file mode 100644 index 33cebb801..000000000 --- a/apps/settings/sub_menu/symbol_controller.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "symbol_controller.h" -#include -#include - -using namespace Shared; -using namespace Poincare; - -namespace Settings { - -SymbolController::SymbolController(Responder * parentResponder) : - GenericSubController(parentResponder) -{ - for (int i = 0; i < k_totalNumberOfSwitchCells; i++) { - m_switchCells[i].setMessageFont(KDFont::LargeFont); - } -} - -bool SymbolController::handleEvent(Ion::Events::Event event) { - Preferences * preferences = Preferences::sharedPreferences(); - Poincare::Preferences::SymbolMultiplication oldSymbolOfMultiplication = preferences->symbolofMultiplication(); - Poincare::Preferences::SymbolMultiplication newSymbolOfMultiplication = preferences->symbolofMultiplication(); - if (event == Ion::Events::OK || event == Ion::Events::EXE){ - switch(selectedRow()){ - case 0: - { - newSymbolOfMultiplication = Poincare::Preferences::SymbolMultiplication::Cross; - break; - } - case 1: - { - newSymbolOfMultiplication = Poincare::Preferences::SymbolMultiplication::MiddleDot; - break; - } - case 2: - { - newSymbolOfMultiplication = Poincare::Preferences::SymbolMultiplication::Star; - break; - } - case 3: - { - newSymbolOfMultiplication = Poincare::Preferences::SymbolMultiplication::Auto; - break; - } - default: - { - GenericSubController::handleEvent(event); - } - } - if (oldSymbolOfMultiplication == newSymbolOfMultiplication) { - if (newSymbolOfMultiplication == Poincare::Preferences::SymbolMultiplication::Auto) { - preferences->setSymbolMultiplication(Poincare::Preferences::SymbolMultiplication::Cross); - } else { - preferences->setSymbolMultiplication(Poincare::Preferences::SymbolMultiplication::Auto); - } - } else { - preferences->setSymbolMultiplication(newSymbolOfMultiplication); - } - m_selectableTableView.reloadData(); - return true; - } else { - return GenericSubController::handleEvent(event); - } -} - -HighlightCell * SymbolController::reusableCell(int index, int type) { - assert(type == 1 || type == 2); - if (type == 2) { - assert(index >= 0 && index < k_totalNumberOfSwitchCells); - return &m_switchCells[index]; - } - return nullptr; -} - -int SymbolController::reusableCellCount(int type) { - assert(type == 1 || type == 2); - if (type == 2) { - return k_totalNumberOfSwitchCells; - } - return 0; -} - -void SymbolController::willDisplayCellForIndex(HighlightCell * cell, int index) { - GenericSubController::willDisplayCellForIndex(cell, index); - - MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell; - - Preferences * preferences = Preferences::sharedPreferences(); - Poincare::Preferences::SymbolMultiplication symbolofMultiplication = preferences->symbolofMultiplication(); - - if (index == 0) { - SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView(); - if(symbolofMultiplication == Poincare::Preferences::SymbolMultiplication::Cross){ - mySwitch->setState(true); - } else { - mySwitch->setState(false); - } - } - else if (index == 1) { - SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView(); - if(symbolofMultiplication == Poincare::Preferences::SymbolMultiplication::MiddleDot){ - mySwitch->setState(true); - } else { - mySwitch->setState(false); - } - } - else if (index == 2) { - SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView(); - if (symbolofMultiplication == Poincare::Preferences::SymbolMultiplication::Star){ - mySwitch->setState(true); - } else { - mySwitch->setState(false); - } - } - else if (index == 3){ - SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView(); - if(symbolofMultiplication == Poincare::Preferences::SymbolMultiplication::Auto){ - mySwitch->setState(true); - } else { - mySwitch->setState(false); - } - } -} - -int SymbolController::typeAtLocation(int i, int j) { - switch (j) { - case 0: - case 1: - case 2: - case 3: - return 2; - default: - return 1; - } -} - -} diff --git a/apps/settings/sub_menu/symbol_controller.h b/apps/settings/sub_menu/symbol_controller.h deleted file mode 100644 index 2c01e1da2..000000000 --- a/apps/settings/sub_menu/symbol_controller.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef SETTINGS_SYMBOLCONTROLLER_CONTROLLER_H -#define SETTINGS_SYMBOLCONTROLLER_CONTROLLER_H - -#include "generic_sub_controller.h" - -namespace Settings { - -class SymbolController : public GenericSubController { -public: - SymbolController(Responder * parentResponder); - bool handleEvent(Ion::Events::Event event) override; - HighlightCell * reusableCell(int index, int type) override; - int reusableCellCount(int type) override; - void willDisplayCellForIndex(HighlightCell * cell, int index) override; - int typeAtLocation(int i, int j) override; -private: - constexpr static int k_totalNumberOfSwitchCells = 4; - MessageTableCellWithSwitch m_switchCells[k_totalNumberOfSwitchCells]; -}; - -} - -#endif \ No newline at end of file diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index 6309dac2a..e697ad584 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Aktivieren/Deaktivieren" ActiveExamModeMessage1 = "Alle Ihre Daten werden " ActiveExamModeMessage2 = "gelöscht, wenn Sie den " ActiveExamModeMessage3 = "Testmodus einschalten." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Achsen" Cancel = "Abbrechen" ClearColumn = "Spalte löschen" @@ -61,6 +64,7 @@ StorageMemoryFull1 = "Der Speicher ist voll. Löschen Sie" StorageMemoryFull2 = "von Daten und versuchen Sie es erneut." StoreExpressionNotAllowed = "'store' ist verboten" SyntaxError = "Syntaxfehler" +Sym = "sym" TEnd = "T Endwert" ThetaEnd = "θ Endwert" ThetaStart = "θ Startwert" diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index 952b615b8..b951a2a8b 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Turn on/off" ActiveExamModeMessage1 = "All your data will be " ActiveExamModeMessage2 = "deleted when you activate " ActiveExamModeMessage3 = "the exam mode." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Axes" Cancel = "Cancel" ClearColumn = "Clear column" @@ -61,6 +64,7 @@ Step = "Step" StorageMemoryFull1 = "The memory is full." StorageMemoryFull2 = "Erase data and try again." SyntaxError = "Syntax error" +Sym = "sym" TEnd = "T end" ThetaEnd = "θ end" ThetaStart = "θ start" diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index 53570691e..226b1d80c 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Activar/Desactivar" ActiveExamModeMessage1 = "Todos sus datos se " ActiveExamModeMessage2 = "eliminaran al activar " ActiveExamModeMessage3 = "el modo examen." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Ejes" Cancel = "Cancelar" ClearColumn = "Borrar la columna" @@ -61,6 +64,7 @@ StorageMemoryFull1 = "La memoria está llena." StorageMemoryFull2 = "Borre datos e intente de nuevo." StoreExpressionNotAllowed = "'store' no está permitido" SyntaxError = "Error sintáctico" +Sym = "sim" TEnd = "T fin" ThetaEnd = "θ fin" ThetaStart = "θ inicio" diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index 15e2d760c..ceec0e270 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Activer/Désactiver" ActiveExamModeMessage1 = "Toutes vos données seront " ActiveExamModeMessage2 = "supprimées si vous activez " ActiveExamModeMessage3 = "le mode examen." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Axes" Cancel = "Annuler" ClearColumn = "Effacer la colonne" @@ -61,6 +64,7 @@ StorageMemoryFull1 = "La mémoire est pleine." StorageMemoryFull2 = "Effacez des données et réessayez." StoreExpressionNotAllowed = "'store' n'est pas autorisé" SyntaxError = "Attention à la syntaxe" +Sym = "sym" TEnd = "T fin" ThetaEnd = "θ fin" ThetaStart = "θ début" diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 9d624d78d..cbef151b3 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -2,6 +2,9 @@ ActivateDeactivate = "Activar/Desactivar" ActiveExamModeMessage1 = "Todos os seus dados serão " ActiveExamModeMessage2 = "apagados se você ligar " ActiveExamModeMessage3 = "o modo de exame." +ActiveDutchExamModeMessage1 = "All your data will be deleted when" +ActiveDutchExamModeMessage2 = "you activate the exam mode. Python" +ActiveDutchExamModeMessage3 = "application will be unavailable." Axis = "Eixos" Cancel = "Cancelar" ClearColumn = "Excluir coluna" @@ -61,6 +64,7 @@ StorageMemoryFull1 = "A memoria esta cheia." StorageMemoryFull2 = "Apage dados e tente novamente." StoreExpressionNotAllowed = "'store' não está permitido" SyntaxError = "Erro de sintaxe" +Sym = "sim" TEnd = "T fim" ThetaEnd = "θ fim" ThetaStart = "θ inicio" diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index 9b88d865d..4676d5d5c 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -210,11 +210,20 @@ ElementTsMass = "294" ElementOgMass = "294" ElementUueMass = "295" ElementUbnMass = "297" -QuentinGuidee = "Quentin Guidee " +QuentinGuidee = "Quentin Guidée " +PQuentinGuidee = "@quentinguidee" DannySimmons = "Danny Simmons " +PDannySimmons = "@MixedMatched" JoachimLeFournis = "Joachim Le Fournis " +PJoachimLeFournis = "@RedGl0w" JeanBaptisteBoric = "Jean-Baptiste Boric " +PJeanBaptisteBoric = "@boricj" MaximeFriess = "Maxime Friess " +PMaximeFriess = "@M4x1m3" +David = "David " +PDavid = "@0b101" +DamienNicolet = "Damien Nicolet " +PDamienNicolet = "@zardam" SpeedOfLight = "2.998·10^8" YearLight = "9.461·10^12" Boltzmann = "1.38064852·10^-23" diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index ea3112b53..0691c77c0 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -1,6 +1,7 @@ #include "equation_store.h" #include "../constant.h" #include "../shared/poincare_helpers.h" +#include "../global_preferences.h" #include #include @@ -193,6 +194,8 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) { } } // Create the results' layouts + // In Dutch exam mode, display only approximate solutions + bool forbidExactSolutions = GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch; int solutionIndex = 0; int initialNumberOfSolutions = m_numberOfSolutions <= k_maxNumberOfExactSolutions ? m_numberOfSolutions : -1; // We iterate through the solutions and the potential delta @@ -211,7 +214,9 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) { char approximateBuffer[::Constant::MaxSerializedExpressionSize]; m_exactSolutionExactLayouts[solutionIndex].serializeForParsing(exactBuffer, ::Constant::MaxSerializedExpressionSize); m_exactSolutionApproximateLayouts[solutionIndex].serializeForParsing(approximateBuffer, ::Constant::MaxSerializedExpressionSize); - m_exactSolutionIdentity[solutionIndex] = strcmp(exactBuffer, approximateBuffer) == 0; + /* Cheat: declare exact and approximate solutions to be identical in + * Dutch exam mode to display only the approximate solutions. */ + m_exactSolutionIdentity[solutionIndex] = forbidExactSolutions || strcmp(exactBuffer, approximateBuffer) == 0; if (!m_exactSolutionIdentity[solutionIndex]) { char buffer[::Constant::MaxSerializedExpressionSize]; m_exactSolutionEquality[solutionIndex] = exactSolutions[i].isEqualToItsApproximationLayout(exactSolutionsApproximations[i], buffer, ::Constant::MaxSerializedExpressionSize, preferences->complexFormat(), preferences->angleUnit(), preferences->displayMode(), preferences->numberOfSignificantDigits(), context); diff --git a/apps/title_bar_view.cpp b/apps/title_bar_view.cpp index 577d02b62..b818db873 100644 --- a/apps/title_bar_view.cpp +++ b/apps/title_bar_view.cpp @@ -71,7 +71,7 @@ void TitleBarView::layoutSubviews() { m_preferenceView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, m_preferenceView.minimalSizeForOptimalDisplay().width(), bounds().height())); KDSize batterySize = m_batteryView.minimalSizeForOptimalDisplay(); m_batteryView.setFrame(KDRect(bounds().width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize)); - if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) { + if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { m_examModeIconView.setFrame(KDRect(k_examIconMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight)); } else { m_examModeIconView.setFrame(KDRectZero); @@ -85,6 +85,14 @@ void TitleBarView::refreshPreferences() { char buffer[bufferSize]; int numberOfChar = 0; Preferences * preferences = Preferences::sharedPreferences(); + if (GlobalPreferences::sharedGlobalPreferences()->isInExamModeSymbolic()) { + // Display "cas" if in exam mode with symbolic computation enabled + numberOfChar += strlcpy(buffer+numberOfChar, I18n::translate(I18n::Message::Sym), bufferSize - numberOfChar); + assert(numberOfChar < bufferSize-1); + assert(UTF8Decoder::CharSizeOfCodePoint('/') == 1); + buffer[numberOfChar++] = '/'; + } + assert(numberOfChar <= bufferSize); { // Display Sci/ or Eng/ if the print float mode is not decimal const Preferences::PrintFloatMode printFloatMode = preferences->displayMode(); @@ -93,7 +101,7 @@ void TitleBarView::refreshPreferences() { assert(printFloatMode == Preferences::PrintFloatMode::Scientific || printFloatMode == Preferences::PrintFloatMode::Engineering); I18n::Message printMessage = printFloatMode == Preferences::PrintFloatMode::Scientific ? I18n::Message::Sci : I18n::Message::Eng; - numberOfChar += strlcpy(buffer, I18n::translate(printMessage), bufferSize); + numberOfChar += strlcpy(buffer+numberOfChar, I18n::translate(printMessage), bufferSize - numberOfChar); assert(numberOfChar < bufferSize-1); assert(UTF8Decoder::CharSizeOfCodePoint('/') == 1); buffer[numberOfChar++] = '/'; @@ -108,6 +116,7 @@ void TitleBarView::refreshPreferences() { (angleUnit == Preferences::AngleUnit::Radian ? I18n::Message::Rad : I18n::Message::Gon); numberOfChar += strlcpy(buffer+numberOfChar, I18n::translate(angleMessage), bufferSize - numberOfChar); } + m_preferenceView.setText(buffer); // Layout the exam mode icon if needed layoutSubviews(); diff --git a/build/config.mak b/build/config.mak index f1962fb65..0d3568c60 100644 --- a/build/config.mak +++ b/build/config.mak @@ -4,13 +4,14 @@ PLATFORM ?= device DEBUG ?= 0 EPSILON_VERSION ?= 12.0.0 -EPSILON_CUSTOM_VERSION ?= 1.17.2-0 +EPSILON_CUSTOM_VERSION ?= 1.18.0-0 # USERNAME ?= N/A # Valid values are "none", "update", "beta" -EPSILON_APPS ?= calculation rpn graph code statistics probability solver atom sequence regression settings +EPSILON_APPS ?= calculation rpn graph code statistics probability solver atom sequence regression settings external EPSILON_I18N ?= en fr es de pt EPSILON_GETOPT ?= 0 ESCHER_LOG_EVENTS_BINARY ?= 0 +OMEGA_THEME ?= omega_light include build/defaults.mak include build/platform.$(PLATFORM).mak diff --git a/build/doc/Doxyfile b/build/doc/Doxyfile new file mode 100644 index 000000000..6bc017f8d --- /dev/null +++ b/build/doc/Doxyfile @@ -0,0 +1,2546 @@ +# Doxyfile 1.8.16 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Omega + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = apps/on_boarding/logo_icon.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = output/doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = NO + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = NO + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = apps \ + ion/src \ + escher/src \ + ion/include \ + escher/include \ + kandinsky/src \ + kandinsky/include \ + poincare/src \ + poincare/include + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /