diff --git a/.gitignore b/.gitignore index 5019cb014..c8a0d0c92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /output/ +/build/artifacts/ build/device/**/*.pyc epsilon.elf .vscode diff --git a/Makefile b/Makefile index baa2d3734..c260884d4 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ info: @echo "BUILD_DIR = $(BUILD_DIR)" @echo "PLATFORM" = $(PLATFORM) @echo "DEBUG" = $(DEBUG) + @echo "LEDS_CHOICE" = $(LEDS_CHOICE) @echo "EPSILON_GETOPT" = $(EPSILON_GETOPT) @echo "ESCHER_LOG_EVENTS_BINARY" = $(ESCHER_LOG_EVENTS_BINARY) @echo "QUIZ_USE_CONSOLE" = $(QUIZ_USE_CONSOLE) @@ -125,8 +126,7 @@ include build/struct_layout/Makefile 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) - +all_src = $(apps_all_src) $(escher_src) $(ion_all_src) $(kandinsky_src) $(liba_src) $(libaxx_src) $(poincare_src) $(python_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 diff --git a/apps/Makefile b/apps/Makefile index 15d4774da..b6d6ae189 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -94,7 +94,7 @@ $(BUILD_DIR)/apps/i18n.h: $(BUILD_DIR)/apps/i18n.cpp $(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_prompt_update_src) $(apps_prompt_beta_src) $(apps_official) $(apps_non_official) $(tests_src) +all_app_src = $(app_src)(apps_launch_on_boarding_src) $(apps_launch_default_src) $(apps_prompt_none_src) $(apps_prompt_update_src) $(apps_prompt_beta_src) $(apps_official) $(apps_non_official) $(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 diff --git a/apps/calculation/additional_outputs/expressions_list_controller.cpp b/apps/calculation/additional_outputs/expressions_list_controller.cpp index 515ec3b4a..555de4433 100644 --- a/apps/calculation/additional_outputs/expressions_list_controller.cpp +++ b/apps/calculation/additional_outputs/expressions_list_controller.cpp @@ -24,6 +24,14 @@ int ExpressionsListController::reusableCellCount(int type) { return k_maxNumberOfCells; } +void ExpressionsListController::viewDidDisappear() { + ListController::viewDidDisappear(); + // Reset cell memoization to avoid taking extra space in the pool + for (int i = 0; i < k_maxNumberOfCells; i++) { + m_cells[i].setLayout(Layout()); + } +} + HighlightCell * ExpressionsListController::reusableCell(int index, int type) { return &m_cells[index]; } diff --git a/apps/calculation/additional_outputs/expressions_list_controller.h b/apps/calculation/additional_outputs/expressions_list_controller.h index 64152f6be..afc59e9c1 100644 --- a/apps/calculation/additional_outputs/expressions_list_controller.h +++ b/apps/calculation/additional_outputs/expressions_list_controller.h @@ -13,6 +13,7 @@ public: ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController); // Responder + void viewDidDisappear() override; void didEnterResponderChain(Responder * previousFirstResponder) override; //ListViewDataSource diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.cpp b/apps/calculation/additional_outputs/illustrated_list_controller.cpp index 67bc939e6..80ea4f52a 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.cpp +++ b/apps/calculation/additional_outputs/illustrated_list_controller.cpp @@ -26,7 +26,7 @@ void IllustratedListController::didEnterResponderChain(Responder * previousFirst } void IllustratedListController::viewDidDisappear() { - StackViewController::viewDidDisappear(); + ListController::viewDidDisappear(); // Reset the context as it was before displaying the IllustratedListController Poincare::Context * context = App::app()->localContext(); if (m_savedExpression.isUninitialized()) { @@ -42,6 +42,10 @@ void IllustratedListController::viewDidDisappear() { Poincare::Symbol s = Poincare::Symbol::Builder(expressionSymbol()); context->setExpressionForSymbolAbstract(m_savedExpression, s); } + // Reset cell memoization to avoid taking extra space in the pool + for (int i = 0; i < k_maxNumberOfAdditionalCalculations; i++) { + m_additionalCalculationCells[i].resetMemoization(); + } } int IllustratedListController::numberOfRows() const { diff --git a/apps/calculation/additional_outputs/list_controller.cpp b/apps/calculation/additional_outputs/list_controller.cpp index 788bdea1e..fe2836fed 100644 --- a/apps/calculation/additional_outputs/list_controller.cpp +++ b/apps/calculation/additional_outputs/list_controller.cpp @@ -32,8 +32,12 @@ bool ListController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { char buffer[Constant::MaxSerializedExpressionSize]; textAtIndex(buffer, Constant::MaxSerializedExpressionSize, selectedRow()); - m_editExpressionController->insertTextBody(buffer); + /* The order is important here: we dismiss the pop-up first because it + * clears the Poincare pool from the layouts used to display the pop-up. + * Thereby it frees memory to do Poincare computations required by + * insertTextBody. */ Container::activeApp()->dismissModalViewController(); + m_editExpressionController->insertTextBody(buffer); Container::activeApp()->setFirstResponder(m_editExpressionController); return true; } diff --git a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp index e5bc0b540..d90fc628d 100644 --- a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp +++ b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp @@ -4,11 +4,15 @@ namespace Calculation { +void ScrollableThreeExpressionsView::resetMemoization() { + setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout()); +} + void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) { Poincare::Context * context = App::app()->localContext(); // Clean the layouts to make room in the pool - setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout()); + resetMemoization(); // Create the input layout Poincare::Layout inputLayout = calculation->createInputLayout(); diff --git a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h index 6bb8155f1..42c18becb 100644 --- a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h +++ b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h @@ -14,6 +14,7 @@ public: setMargins(Metric::CommonSmallMargin, Metric::CommonSmallMargin, Metric::CommonSmallMargin, Metric::CommonSmallMargin); // Left Right margins are already added by TableCell setBackgroundColor(KDColorWhite); } + void resetMemoization(); void setCalculation(Calculation * calculation); private: class ContentCell : public Shared::AbstractScrollableMultipleExpressionsView::ContentCell { @@ -50,6 +51,7 @@ public: View * labelView() const override { return (View *)&m_view; } void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); } + void resetMemoization() { m_view.resetMemoization(); } void setCalculation(Calculation * calculation); void setDisplayCenter(bool display); ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); } diff --git a/apps/calculation/base.de.i18n b/apps/calculation/base.de.i18n index e71cdc958..ebb1bd928 100644 --- a/apps/calculation/base.de.i18n +++ b/apps/calculation/base.de.i18n @@ -1,9 +1,9 @@ CalculApp = "Berechnung" CalculAppCapital = "BERECHNUNG" -AdditionalResults = "????" -DecimalBase = "????" -HexadecimalBase = "????" -BinaryBase = "????" -PrimeFactors = "????" -MixedFraction = "????" -EuclideanDivision = "????" +AdditionalResults = "Weitere Ergebnisse" +DecimalBase = "Dezimal" +HexadecimalBase = "Hexadezimal" +BinaryBase = "Binär" +PrimeFactors = "Primfaktor" +MixedFraction = "Gemischte Fraktion" +EuclideanDivision = "Euklidische Division" diff --git a/apps/calculation/base.hu.i18n b/apps/calculation/base.hu.i18n index 511055f9f..d877a794c 100644 --- a/apps/calculation/base.hu.i18n +++ b/apps/calculation/base.hu.i18n @@ -2,8 +2,8 @@ CalculApp = "Számolás" CalculAppCapital = "SZÁMOLÁS" AdditionalResults = "További eredmények" DecimalBase = "Decimális" -HexadecimalBase = "hexadecimális" -BinaryBase = "Binary" +HexadecimalBase = "Hexadecimális" +BinaryBase = "Kétkomponensü" PrimeFactors = "Alapvetö tényezök" MixedFraction = "Vegyes frakció" EuclideanDivision = "Euklideszi osztás" diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index d5ff68351..a7b7e0540 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -137,7 +137,7 @@ KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpre KDCoordinate inputHeight = inputLayout.layoutSize().height(); KDCoordinate inputWidth = inputLayout.layoutSize().width(); float singleMargin = 2 * Metric::CommonSmallMargin; - float doubleMargin = 2 * Metric::CommonSmallMargin; + float doubleMargin = 4 * Metric::CommonSmallMargin; bool singleLine = false; KDCoordinate inputBaseline = inputLayout.baseline(); @@ -162,19 +162,15 @@ KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpre KDCoordinate exactOutputHeight = exactLayout.layoutSize().height(); KDCoordinate exactOutputWidth = exactLayout.layoutSize().width(); singleLine = exactOutputWidth + inputWidth < maxWidth - 40; - if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) { - if (allExpressionsInline) { - KDCoordinate exactOutputBaseline = exactLayout.baseline(); - result = (inputHeight >= exactOutputHeight) ? maxCoordinate(inputBaseline, exactOutputBaseline) + singleMargin : maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline) + singleMargin; - } else { - result = (inputHeight >= exactOutputHeight) ? inputHeight + singleMargin : exactOutputHeight + singleMargin; - } + if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact && !allExpressionsInline) { + KDCoordinate exactOutputBaseline = exactLayout.baseline(); + result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline); } else { if (allExpressionsInline) { KDCoordinate exactOutputBaseline = exactLayout.baseline(); - result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline)+doubleMargin; + result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline); } else { - result = inputHeight+exactOutputHeight+doubleMargin+doubleMargin; + result = inputHeight + exactOutputHeight + doubleMargin; } } } else { @@ -200,19 +196,15 @@ KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpre KDCoordinate approximateOutputWidth = approximateLayout.layoutSize().width(); singleLine = approximateOutputWidth + inputWidth < maxWidth - 40; if (displayOutput(context) == DisplayOutput::ApproximateOnly || (!expanded && displayOutput(context) == DisplayOutput::ExactAndApproximateToggle)) { - if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) { - if (allExpressionsInline) { - KDCoordinate approximateOutputBaseline = approximateLayout.baseline(); - result = (inputHeight >= approximateOutputHeight) ? maxCoordinate(inputBaseline, approximateOutputBaseline) + singleMargin : maxCoordinate(inputHeight - inputBaseline, approximateOutputHeight-approximateOutputBaseline) + singleMargin; - } else { - result = (inputHeight >= approximateOutputHeight) ? inputHeight + singleMargin : approximateOutputHeight + singleMargin; - } + if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact && !allExpressionsInline) { + KDCoordinate approximateOutputBaseline = approximateLayout.baseline(); + result = maxCoordinate(inputBaseline, approximateOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, approximateOutputHeight-approximateOutputBaseline) + singleMargin; } else { if (allExpressionsInline) { KDCoordinate approximateOutputBaseline = approximateLayout.baseline(); - result = maxCoordinate(inputBaseline, approximateOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, approximateOutputHeight-approximateOutputBaseline) + doubleMargin + singleMargin; + result = maxCoordinate(inputBaseline, approximateOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, approximateOutputHeight-approximateOutputBaseline); } else { - result = inputHeight+approximateOutputHeight+doubleMargin+singleMargin; + result = inputHeight + approximateOutputHeight + doubleMargin; } } } else { @@ -221,21 +213,15 @@ KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpre KDCoordinate exactOutputBaseline = exactLayout.baseline(); KDCoordinate exactOutputWidth = exactLayout.layoutSize().width(); KDCoordinate approximateOutputWidth = approximateLayout.layoutSize().width(); - KDCoordinate outputWidth = exactOutputWidth + approximateOutputWidth; - singleLine = outputWidth + inputWidth < maxWidth - 70; + singleLine = exactOutputWidth + approximateOutputWidth + inputWidth < maxWidth - 70; KDCoordinate approximateOutputBaseline = approximateLayout.baseline(); if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) { - KDCoordinate outputHeight = maxCoordinate(exactOutputBaseline, approximateOutputBaseline) + maxCoordinate(exactOutputHeight-exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline); - if (allExpressionsInline) { - result = (inputHeight >= outputHeight) ? maxCoordinate(inputBaseline, maxCoordinate(exactOutputBaseline, approximateOutputBaseline)) + singleMargin : maxCoordinate(inputHeight - inputBaseline, maxCoordinate(exactOutputHeight - exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline)) + singleMargin; - } else { - result = (inputHeight >= outputHeight) ? inputHeight + singleMargin : outputHeight + singleMargin; - } + result = maxCoordinate(inputBaseline, maxCoordinate(exactOutputBaseline, approximateOutputBaseline)) + maxCoordinate(inputHeight - inputBaseline, maxCoordinate(exactOutputHeight - exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline)) + singleMargin; } else { if (allExpressionsInline) { result = maxCoordinate(inputBaseline, maxCoordinate(exactOutputBaseline, approximateOutputBaseline)) + maxCoordinate(inputHeight - inputBaseline, maxCoordinate(exactOutputHeight - exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline)); } else { - KDCoordinate outputHeight = maxCoordinate(exactOutputBaseline, approximateOutputBaseline) + maxCoordinate(exactOutputHeight-exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline) + doubleMargin; + KDCoordinate outputHeight = maxCoordinate(exactOutputBaseline, approximateOutputBaseline) + maxCoordinate(exactOutputHeight-exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline); result = inputHeight + outputHeight + doubleMargin; } } @@ -313,6 +299,12 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { return m_displayOutput; } +void Calculation::forceDisplayOutput(DisplayOutput d) { + m_displayOutput = d; + // Reset heights memoization as it might have changed when we modify the display output + m_height = -1; + m_expandedHeight = -1; +} bool Calculation::shouldOnlyDisplayExactOutput() { /* If the input is a "store in a function", do not display the approximate * result. This prevents x->f(x) from displaying x = undef. */ diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index 5dec4fc0a..b084226df 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -88,7 +88,7 @@ public: // Displayed output DisplayOutput displayOutput(Poincare::Context * context); - void forceDisplayOutput(DisplayOutput d) { m_displayOutput = d; } + void forceDisplayOutput(DisplayOutput d); bool shouldOnlyDisplayExactOutput(); EqualSign exactAndApproximateDisplayedOutputsAreEqual(Poincare::Context * context); diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 2cb9b9ab8..292a6199e 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -24,6 +24,13 @@ HistoryController::HistoryController(EditExpressionController * editExpressionCo } void HistoryController::reload() { + /* When reloading, we might not used anymore cell that hold previous layouts. + * We clean them all before reloading their content to avoid taking extra + * useless space in the Poincare pool. */ + for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { + m_calculationHistory[i].resetMemoization(); + } + m_selectableTableView.reloadData(); /* TODO * Replace the following by selectCellAtLocation in order to avoid laying out @@ -224,6 +231,10 @@ void HistoryController::historyViewCellDidChangeSelection(HistoryViewCell ** cel m_selectableTableView.reloadData(); } + // It might be necessary to scroll to the sub type if the cell overflows the screen + if (selectedRow() >= 0) { + m_selectableTableView.scrollToSubviewOfTypeOfCellAtLocation(type, m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()); + } // Fill the selected cell and the previous selected cell because cells repartition might have changed *cell = static_cast(m_selectableTableView.selectedCell()); *previousCell = static_cast(m_selectableTableView.cellAtLocation(previousSelectedCellX, previousSelectedCellY)); diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index 0007c0bac..ff41c7b3e 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -185,19 +185,22 @@ void HistoryViewCell::layoutSubviews(bool force) { inputSize.height()), force); KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay(); - int outputY = (oneLine() && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) ? maxCoordinate(0, inputSize.height() - outputSize.height()) / 2 : inputSize.height(); + int singleLine = outputSize.width() + inputSize.width() < bounds().width() - 6; + int outputHeight = (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) ? (maxCoordinate(0, inputSize.height() - outputSize.height()) / 2) + maxCoordinate(0, (inputSize.height() - outputSize.height()) / 2) : inputSize.height(); m_scrollableOutputView.setFrame(KDRect( maxCoordinate(0, maxFrameWidth - outputSize.width()), - outputY, + outputHeight, minCoordinate(maxFrameWidth, outputSize.width()), - oneLine() ? outputSize.height() : (bounds().height() - inputSize.height())), + outputSize.height()), force); } -bool HistoryViewCell::oneLine() { - KDSize inputSize = m_inputView.minimalSizeForOptimalDisplay(); - KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay(); - return outputSize.width() + inputSize.width() < bounds().width() - 6; +void HistoryViewCell::resetMemoization() { + // Clean the layouts to make room in the pool + // TODO: maybe do this only when the layout won't change to avoid blinking + m_inputView.setLayout(Poincare::Layout()); + m_scrollableOutputView.setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout()); + m_calculationCRC32 = 0; } void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) { @@ -207,10 +210,8 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) { } Poincare::Context * context = App::app()->localContext(); - // Clean the layouts to make room in the pool // TODO: maybe do this only when the layout won't change to avoid blinking - m_inputView.setLayout(Poincare::Layout()); - m_scrollableOutputView.setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout()); + resetMemoization(); // Memoization m_calculationCRC32 = newCalculationCRC; @@ -303,9 +304,6 @@ bool HistoryViewCell::handleEvent(Ion::Events::Event event) { otherSubviewType = HistoryViewCellDataSource::SubviewType::Output; } m_dataSource->setSelectedSubviewType(otherSubviewType, true); - CalculationSelectableTableView * tableView = (CalculationSelectableTableView *)parentResponder(); - tableView->scrollToSubviewOfTypeOfCellAtLocation(otherSubviewType, tableView->selectedColumn(), tableView->selectedRow()); - Container::activeApp()->setFirstResponder(this); return true; } return false; diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index b831e49ed..7d6c12b45 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -42,6 +42,7 @@ public: } Poincare::Layout layout() const override; KDColor backgroundColor() const override; + void resetMemoization(); void setCalculation(Calculation * calculation, bool expanded); int numberOfSubviews() const override; View * subviewAtIndex(int index) override; @@ -51,7 +52,6 @@ public: Shared::ScrollableTwoExpressionsView * outputView(); Calculation::AdditionalInformationType additionalInformationType() const { return m_calculationAdditionInformation; } private: - bool oneLine(); constexpr static KDCoordinate k_resultWidth = 80; void reloadScroll(); void reloadOutputSelection(HistoryViewCellDataSource::SubviewType previousType); diff --git a/apps/calculation/selectable_table_view.cpp b/apps/calculation/selectable_table_view.cpp index c00bed4b1..e2d81e53c 100644 --- a/apps/calculation/selectable_table_view.cpp +++ b/apps/calculation/selectable_table_view.cpp @@ -24,18 +24,6 @@ void CalculationSelectableTableView::scrollToCell(int i, int j) { KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling(); setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); } - if (dataSource()->numberOfRows() > j && dataSource()->numberOfColumns() > i && dataSource()->rowHeight(j) > bounds().height()) { - KDCoordinate contentOffsetX = contentOffset().x(); - KDCoordinate contentOffsetY = contentOffset().y(); - if (contentOffsetY > dataSource()->cumulatedHeightFromIndex(j) && contentOffsetY > dataSource()->cumulatedHeightFromIndex(j+1)) { - // Let's scroll the tableView to align the top of the cell to the top - contentOffsetY = dataSource()->cumulatedHeightFromIndex(j); - } else { - // Let's scroll the tableView to align the bottom of the cell to the bottom - contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling(); - } - setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); - } } void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(HistoryViewCellDataSource::SubviewType subviewType, int i, int j) { @@ -44,10 +32,8 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo } /* As we scroll, the selected calculation does not use the same history view * cell, thus, we want to deselect the previous used history view cell. */ - if (selectedRow() >= 0) { - HighlightCell * previousCell = selectedCell(); - previousCell->setHighlighted(false); - } + unhighlightSelectedCell(); + /* Main part of the scroll */ KDCoordinate contentOffsetX = contentOffset().x(); KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling(); @@ -58,16 +44,13 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo contentOffsetY = dataSource()->cumulatedHeightFromIndex(j); } } - /* For the same reason, we have to rehighlight the new history view cell and - * inform the delegate which history view cell is highlighted even if the - * selected calculation has not changed. */ setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); - HighlightCell * cell = cellAtLocation(i, j); + /* For the same reason, we have to rehighlight the new history view cell and + * reselect the first responder. */ + HistoryViewCell * cell = (HistoryViewCell *)(selectedCell()); assert(cell); cell->setHighlighted(true); - if (m_delegate) { - m_delegate->tableViewDidChangeSelection(this, selectedColumn(), selectedRow()); - } + Container::activeApp()->setFirstResponder(cell); } diff --git a/apps/code/app.cpp b/apps/code/app.cpp index 665a09ce4..10d372183 100644 --- a/apps/code/app.cpp +++ b/apps/code/app.cpp @@ -49,8 +49,10 @@ bool App::Snapshot::lockOnConsole() const { } void App::Snapshot::setOpt(const char * name, const char * value) { - if (strcmp(name, "script") == 0) { + if (strcmp(name, "wipe") == 0) { m_scriptStore.deleteAllScripts(); + } + if (strcmp(name, "script") == 0) { char * separator = const_cast(UTF8Helper::CodePointSearch(value, ':')); if (*separator == 0) { return; diff --git a/apps/code/base.hu.i18n b/apps/code/base.hu.i18n index 525d91b1a..91437ca29 100644 --- a/apps/code/base.hu.i18n +++ b/apps/code/base.hu.i18n @@ -1,4 +1,4 @@ -Console = "Console d'execution" +Console = "Konzol" AddScript = "Script hozzadáadása" ScriptOptions = "Script beállítások" ExecuteScript = "Script indítása" diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 4fc15ea09..f8a651596 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -12,105 +12,104 @@ PythonSingleQuote = "Einfaches Anführungszeichen" PythonAbs = "Absolute/r Wert/Größe" PythonAcos = "Arkuskosinus" PythonAcosh = "Hyperbelkosinus" -PythonAppend = "Add x to the end of the list" +PythonAppend = "Hängt x an das Ende der Liste" PythonAsin = "Arkussinus" PythonAsinh = "Hyperbelsinus" PythonAtan = "Arkustangens" PythonAtan2 = "Gib atan(y/x)" PythonAtanh = "Hyperbeltangens" -PythonBin = "Ganzzahl nach binär konvertieren" +PythonBin = "Ganzzahl nach binär" PythonCeil = "Aufrundung" PythonChoice = "Zufallszahl aus der Liste" -PythonClear = "Empty the list" +PythonClear = "Leere die Liste" PythonCmathFunction = "cmath-Modul-Funktionspräfix" -PythonColor = "Definiere eine RGB-Farbe" +PythonColor = "Definiert eine RGB-Farbe" PythonComplex = "a+ib zurückgeben" -PythonCopySign = "Return x with the sign of y" +PythonCopySign = "x mit dem Vorzeichen von y" PythonCos = "Kosinus" PythonCosh = "Hyperbolic cosine" -PythonCount = "Count the occurrences of x" -PythonDegrees = "Convert x from radians to degrees" -PythonDivMod = "Quotient and remainder" -PythonDrawString = "Display a text from pixel (x,y)" -PythonConstantE = "2.718281828459046" -PythonErf = "Error function" +PythonCount = "Zählt wie oft x vorkommt" +PythonDegrees = "x von Radian zu Grad umwandeln" +PythonDivMod = "Quotient und Rest" +PythonDrawString = "Schreibt Text bei (x,y)" +PythonErf = "Fehlerfunktion" PythonErfc = "Complementary error function" PythonEval = "Return the evaluated expression" -PythonExp = "Exponential function" -PythonExpm1 = "Compute exp(x)-1" -PythonFabs = "Absolute value" -PythonFillRect = "Fill a rectangle at pixel (x,y)" -PythonFloat = "Convert x to a float" +PythonExp = "Exponentialfunktion" +PythonExpm1 = "Berechne exp(x)-1" +PythonFabs = "Absoluter Wert" +PythonFillRect = "Malt ein Rechteck bei Pixel (x,y)" +PythonFloat = "Wandelt x zu float um" PythonFloor = "Floor" PythonFmod = "a modulo b" -PythonFrExp = "Mantissa and exponent of x" -PythonGamma = "Gamma function" -PythonGetPixel = "Return pixel (x,y) color" -PythonGetrandbits = "Integer with k random bits" -PythonHex = "Convert integer to hexadecimal" -PythonImportCmath = "Import cmath module" -PythonImportIon = "Import ion module" -PythonImportKandinsky = "Import kandinsky module" -PythonImportRandom = "Import random module" -PythonImportMath = "Import math module" -PythonImportTime = "Import time module" -PythonImportTurtle = "Import turtle module" -PythonIndex = "Index of the first x occurrence" -PythonInput = "Prompt a value" -PythonInsert = "Insert x at index i in the list" -PythonInt = "Convert x to an integer" +PythonFrExp = "Rest und Exponent von x" +PythonGamma = "Gammafunktion" +PythonGetPixel = "Farbe von Pixel (x,y)" +PythonGetrandbits = "Ganzzahl mit k zufälligen Bits" +PythonHex = "Ganzzahl zu Hexadecimal" +PythonImportCmath = "cmath Modul importieren" +PythonImportIon = "ion Modul importieren" +PythonImportKandinsky = "kandinsky Modul importieren" +PythonImportRandom = "random Modul importieren" +PythonImportMath = "math Modul importieren" +PythonImportTime = "time Modul importieren" +PythonImportTurtle = "turtle Modul importieren" +PythonIndex = "Index, bei dem x zuerst vorkommt" +PythonInput = "Eingabeaufforderung" +PythonInsert = "x bei index i in der Liste einsetzen" +PythonInt = "x zu Ganzzahl" PythonIonFunction = "ion module function prefix" -PythonIsFinite = "Check if x is finite" -PythonIsInfinite = "Check if x is infinity" -PythonIsNaN = "Check if x is a NaN" -PythonIsKeyDown = "Return True if the k key is down" +PythonIsFinite = "Prüft ob x endlich ist" +PythonIsInfinite = "Prüft ob x unendlich ist" +PythonIsNaN = "Prüft ob x NaN ist" +PythonIsKeyDown = "true wenn k gedrückt ist" PythonKandinskyFunction = "kandinsky module function prefix" -PythonKeyLeft = "LEFT ARROW key" -PythonKeyUp = "UP ARROW key" -PythonKeyDown = "DOWN ARROW key" -PythonKeyRight = "RIGHT ARROW key" -PythonKeyOk = "OK key" -PythonKeyBack = "BACK key" -PythonKeyHome = "HOME key" -PythonKeyOnOff = "ON/OFF key" -PythonKeyShift = "SHIFT key" -PythonKeyAlpha = "ALPHA key" -PythonKeyXnt = "X,N,T key" -PythonKeyVar = "VAR key" -PythonKeyToolbox = "TOOLBOX key" -PythonKeyBackspace = "BACKSPACE key" -PythonKeyExp = "EXPONENTIAL key" -PythonKeyLn = "NATURAL LOGARITHM key" -PythonKeyLog = "DECIMAL LOGARITHM key" -PythonKeyImaginary = "IMAGINARY I key" -PythonKeyComma = "COMMA key" -PythonKeyPower = "POWER key" -PythonKeySine = "SINE key" -PythonKeyCosine = "COSINE key" -PythonKeyTangent = "TANGENT key" -PythonKeyPi = "PI key" -PythonKeySqrt = "SQUARE ROOT key" -PythonKeySquare = "SQUARE key" -PythonKeySeven = "7 key" -PythonKeyEight = "8 key" -PythonKeyNine = "9 key" +PythonKeyLeft = "Linke Pfeiltaste" +PythonKeyUp = "Pfeiltaste nach oben" +PythonKeyDown = "Pfeiltaste nach unten" +PythonKeyRight = "Rechte Pfeiltaste" +PythonKeyOk = "OK Taste" +PythonKeyBack = "ZURÜCK Taste" +PythonKeyHome = "HOME Taste" +PythonKeyOnOff = "AN/AUS Taste" +PythonKeyShift = "SHIFT Taste" +PythonKeyAlpha = "ALPHA Taste" +PythonKeyXnt = "X,N,T Taste" +PythonKeyVar = "VAR Taste" +PythonKeyToolbox = "WERKZEUGBOX Taste" +PythonKeyBackspace = "LÖSCHEN Taste" +PythonKeyExp = "EXPONENTIAL Taste" +PythonKeyLn = "NATURAL LOGARITHM Taste" +PythonKeyLog = "DECIMAL LOGARITHM Taste" +PythonKeyImaginary = "IMAGINÄRES I Taste" +PythonKeyComma = "KOMMA Taste" +PythonKeyPower = "HOCH Taste" +PythonKeySine = "SINUS Taste" +PythonKeyCosine = "COSINUS Taste" +PythonKeyTangent = "TANGENZ Taste" +PythonKeyPi = "PI Taste" +PythonKeySqrt = "WURZEL Taste" +PythonKeySquare = "QUADRAT Taste" +PythonKeySeven = "7 Taste" +PythonKeyEight = "8 Taste" +PythonKeyNine = "9 Taste" PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" -PythonKeyFour = "4 key" -PythonKeyFive = "5 key" -PythonKeySix = "6 key" -PythonKeyMultiplication = "MULTIPLICATION key" -PythonKeyDivision = "DIVISION key" -PythonKeyOne = "1 key" -PythonKeyTwo = "2 key" -PythonKeyThree = "3 key" -PythonKeyPlus = "PLUS key" -PythonKeyMinus = "MINUS key" -PythonKeyZero = "0 key" -PythonKeyDot = "DOT key" -PythonKeyEe = "10 POWER X key" -PythonKeyAns = "ANS key" -PythonKeyExe = "EXE key" +PythonKeyFour = "4 Taste" +PythonKeyFive = "5 Taste" +PythonKeySix = "6 Taste" +PythonKeyMultiplication = "MULTIPLIKATIONSTASTE" +PythonKeyDivision = "DIVISIONSTASTE" +PythonKeyOne = "1 Taste" +PythonKeyTwo = "2 Taste" +PythonKeyThree = "3 Taste" +PythonKeyPlus = "PLUS Taste" +PythonKeyMinus = "MINUS Taste" +PythonKeyZero = "0 Taste" +PythonKeyDot = "PUNKT Taste" +PythonKeyEe = "10 HOCH X Taste" +PythonKeyAns = "ANS Taste" +PythonKeyExe = "EXE Taste" PythonLdexp = "Return x*(2**i), inverse of frexp" PythonLength = "Length of an object" PythonLgamma = "Log-gamma function" @@ -124,7 +123,6 @@ PythonModf = "Fractional and integer parts of x" PythonMonotonic = "Value of a monotonic clock" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" -PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" PythonPop = "Remove and return the last item" PythonPower = "x raised to the power y" @@ -142,27 +140,27 @@ PythonReverse = "Reverse the elements of the list" PythonRound = "Round to n digits" PythonSeed = "Initialize random number generator" PythonSetPixel = "Color pixel (x,y)" -PythonSin = "Sine" +PythonSin = "Sinus" PythonSinh = "Hyperbolic sine" PythonSleep = "Suspend the execution for t seconds" PythonSort = "Sort the list" -PythonSqrt = "Square root" +PythonSqrt = "Wurzel" PythonSum = "Sum the items of a list" -PythonTan = "Tangent" +PythonTan = "Tangens" PythonTanh = "Hyperbolic tangent" PythonTimeFunction = "time module function prefix" PythonTrunc = "x truncated to an integer" PythonTurtleBackward = "Move backward by x pixels" -PythonTurtleBlack = "Black color" -PythonTurtleBlue = "Blue color" -PythonTurtleBrown = "Brown color" +PythonTurtleBlack = "Schwarze Farbe" +PythonTurtleBlue = "Blaue Farbe" +PythonTurtleBrown = "Braune Farbe" PythonTurtleCircle = "Circle of radius r pixels" -PythonTurtleColor = "Set the pen color" +PythonTurtleColor = "Stiftfarbe setzen" PythonTurtleForward = "Move forward by x pixels" PythonTurtleFunction = "turtle module function prefix" PythonTurtleGoto = "Move to (x,y) coordinates" -PythonTurtleGreen = "Green color" -PythonTurtleGrey = "Grey color" +PythonTurtleGreen = "Grüne Farbe" +PythonTurtleGrey = "Graue Farbe" PythonTurtleHeading = "Return the current heading" PythonTurtleHideturtle = "Hide the turtle" PythonTurtleIsdown = "Return True if the pen is down" @@ -171,19 +169,19 @@ PythonTurtleOrange = "Orange color" PythonTurtlePendown = "Pull the pen down" PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePenup = "Pull the pen up" -PythonTurtlePink = "Pink color" +PythonTurtlePink = "Pinke Farbe" PythonTurtlePosition = "Return the current (x,y) location" PythonTurtlePurple = "Purple color" -PythonTurtleRed = "Red color" +PythonTurtleRed = "Rote Farbe" PythonTurtleReset = "Reset the drawing" PythonTurtleRight = "Turn right by a degrees" PythonTurtleSetheading = "Set the orientation to a degrees" -PythonTurtleSetposition = "Positionne la tortue" -PythonTurtleShowturtle = "Show the turtle" -PythonTurtleSpeed = "Drawing speed between 0 and 10" -PythonTurtleWhite = "White color" -PythonTurtleYellow = "Yellow color" -PythonUniform = "Floating point number in [a,b]" +PythonTurtleSetposition = "Position des turtles" +PythonTurtleShowturtle = "Die turtle anzeigen" +PythonTurtleSpeed = "Zeichengeschwindigkeit zwischen 0 und 10" +PythonTurtleWhite = "Weiße Farbe" +PythonTurtleYellow = "Gelbe Farbe" +PythonUniform = "Fließkommazahl in [a,b]" PythonTimeFromImport = "Import time module" PythonTimeImport = "Import time module" PythonTimePrefix = "time module function prefix" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 88a0c6954..67e6b1582 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -32,7 +32,6 @@ PythonCount = "Count the occurrences of x" PythonDegrees = "Convert x from radians to degrees" PythonDivMod = "Quotient and remainder" PythonDrawString = "Display a text from pixel (x,y)" -PythonConstantE = "2.718281828459046" PythonErf = "Error function" PythonErfc = "Complementary error function" PythonEval = "Return the evaluated expression" @@ -124,7 +123,6 @@ PythonModf = "Fractional and integer parts of x" PythonMonotonic = "Value of a monotonic clock" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" -PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" PythonPop = "Remove and return the last item" PythonPower = "x raised to the power y" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index ae9bb0b9f..074e16df1 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -32,7 +32,6 @@ PythonCount = "Count the occurrences of x" PythonDegrees = "Convert x from radians to degrees" PythonDivMod = "Quotient and remainder" PythonDrawString = "Display a text from pixel (x,y)" -PythonConstantE = "2.718281828459046" PythonErf = "Error function" PythonErfc = "Complementary error function" PythonEval = "Return the evaluated expression" @@ -124,7 +123,6 @@ PythonModf = "Fractional and integer parts of x" PythonMonotonic = "Value of a monotonic clock" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" -PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" PythonPop = "Remove and return the last item" PythonPower = "x raised to the power y" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index 4a98637cd..b326507bc 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -32,7 +32,6 @@ PythonCount = "Compte les occurrences de x" PythonDegrees = "Conversion de radians en degrés" PythonDivMod = "Quotient et reste" PythonDrawString = "Affiche un texte au pixel (x,y)" -PythonConstantE = "2.718281828459045" PythonErf = "Fonction d'erreur" PythonErfc = "Fonction d'erreur complémentaire" PythonEval = "Evalue l'expression en argument " @@ -124,7 +123,6 @@ PythonModf = "Parties fractionnaire et entière" PythonMonotonic = "Renvoie la valeur de l'horloge" PythonOct = "Conversion en octal" PythonPhase = "Argument de z" -PythonConstantPi = "3.141592653589793" PythonPolar = "Conversion en polaire" PythonPop = "Supprime le dernier élément" PythonPower = "x à la puissance y" diff --git a/apps/code/catalog.hu.i18n b/apps/code/catalog.hu.i18n index 4adf1ead2..3ff4d4663 100644 --- a/apps/code/catalog.hu.i18n +++ b/apps/code/catalog.hu.i18n @@ -32,12 +32,11 @@ PythonCount = "Számolja az x elöfordulását" PythonDegrees = "x konvertálása x-röl radiánokra fokokra" PythonDivMod = "Hányados és maradék" PythonDrawString = "Szöveg megjelenítése pixelböl (x, y)" -PythonConstantE = "2.718281828459046" PythonErf = "Hiba funkció" PythonErfc = "Kiegészítö hibafunkció" PythonEval = "Visszaadja az értékelt kifejezést" PythonExp = "Exponenciális függvény" -PythonExpm1 = "Compute exp (x) -1" +PythonExpm1 = "Számítsuk ki az exp (x) -1-et" PythonFabs = "Abszolút érték" PythonFillRect = "Töltsön meg egy téglalapot pixelnél (x, y)" PythonFloat = "x konvertálása float-ra" @@ -124,7 +123,6 @@ PythonModf = "Az x tört és egész részei" PythonMonotonic = "A monoton óra értéke" PythonOct = "Egész szám konvertálása oktális értékre" PythonPhase = "z fázis" -PythonConstantPi = "3.141592653589794" PythonPolar = "z poláris koordinátákban" PythonPop = "Az utolsó elem eltávolítása és visszaküldése" PythonPower = "x emelve az y teljesítményre" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index bc0c946ce..ff20380ab 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -32,7 +32,6 @@ PythonCount = "Count the occurrences of x" PythonDegrees = "Convert x from radians to degrees" PythonDivMod = "Quotient and remainder" PythonDrawString = "Display a text from pixel (x,y)" -PythonConstantE = "2.718281828459046" PythonErf = "Error function" PythonErfc = "Complementary error function" PythonEval = "Return the evaluated expression" @@ -124,7 +123,6 @@ PythonModf = "Fractional and integer parts of x" PythonMonotonic = "Value of a monotonic clock" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" -PythonConstantPi = "3.141592653589794" PythonPolar = "z in polar coordinates" PythonPop = "Remove and return the last item" PythonPower = "x raised to the power y" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index d501675d5..111261574 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -185,6 +185,8 @@ PythonCommandTrunc = "trunc(x)" PythonCommandTurtleFunction = "turtle.function" PythonCommandTurtleFunctionWithoutArg = "turtle.\x11" PythonCommandUniform = "uniform(a,b)" +PythonConstantE = "2.718281828459045" +PythonConstantPi = "3.141592653589793" PythonTurtleCommandBackward = "backward(x)" PythonTurtleCommandBlack = "'black'" PythonTurtleCommandBlue = "'blue'" diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 9e53b9d30..6b3c9766f 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -134,7 +134,27 @@ const char * ConsoleController::inputText(const char * prompt) { const char * previousPrompt = m_editCell.promptText(); m_editCell.setPrompt(promptText); - m_editCell.setText(""); + + /* The user will input some text that is stored in the edit cell. When the + * input is finished, we want to clear that cell and return the input text. + * We choose to shift the input in the edit cell and put a null char in first + * position, so that the cell seems cleared but we can still use it to store + * the input. + * To do so, we need to reduce the cell buffer size by one, so that the input + * can be shifted afterwards, even if it has maxSize. + * + * Illustration of a input sequence: + * | | | | | | | | | <- the edit cell buffer + * |0| | | | | | |X| <- clear and reduce the size + * |a|0| | | | | |X| <- user input + * |a|b|0| | | | |X| <- user input + * |a|b|c|0| | | |X| <- user input + * |a|b|c|d|0| | |X| <- last user input + * | |a|b|c|d|0| | | <- increase the buffer size and shift the user input by one + * |0|a|b|c|d|0| | | <- put a zero in first position: the edit cell seems empty + */ + + m_editCell.clearAndReduceSize(); // Reload the history m_selectableTableView.reloadData(); @@ -147,16 +167,18 @@ const char * ConsoleController::inputText(const char * prompt) { return c->inputRunLoopActive(); }, this); - // Handle the input text + // Print the prompt and the input text if (promptText != nullptr) { printText(promptText, s - promptText); } const char * text = m_editCell.text(); - printText(text, strlen(text)); + size_t textSize = strlen(text); + printText(text, textSize); flushOutputAccumulationBufferToStore(); + // Clear the edit cell and return the input + text = m_editCell.shiftCurrentTextAndClear(); m_editCell.setPrompt(previousPrompt); - m_editCell.setText(""); refreshPrintOutput(); return text; @@ -378,6 +400,9 @@ void ConsoleController::resetSandbox() { } void ConsoleController::refreshPrintOutput() { + if (sandboxIsDisplayed()) { + return; + } m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); if (m_preventEdition) { @@ -394,21 +419,41 @@ void ConsoleController::printText(const char * text, size_t length) { /* If there is no new line in text, just append it to the output * accumulation buffer. */ appendTextToOutputAccumulationBuffer(text, length); - return; + } else { + if (textCutIndex < length - 1) { + /* If there is a new line in the middle of the text, we have to store at + * least two new console lines in the console store. */ + printText(text, textCutIndex + 1); + printText(&text[textCutIndex+1], length - (textCutIndex + 1)); + return; + } + /* There is a new line at the end of the text, we have to store the line in + * the console store. */ + assert(textCutIndex == length - 1); + appendTextToOutputAccumulationBuffer(text, length-1); + flushOutputAccumulationBufferToStore(); + micropython_port_vm_hook_refresh_print(); } - if (textCutIndex < length - 1) { - /* If there is a new line in the middle of the text, we have to store at - * least two new console lines in the console store. */ - printText(text, textCutIndex + 1); - printText(&text[textCutIndex+1], length - (textCutIndex + 1)); - return; - } - /* There is a new line at the end of the text, we have to store the line in - * the console store. */ - assert(textCutIndex == length - 1); - appendTextToOutputAccumulationBuffer(text, length-1); - flushOutputAccumulationBufferToStore(); - micropython_port_vm_hook_refresh_print(); +#if __EMSCRIPTEN__ + /* If we called micropython_port_interrupt_if_needed here, we would need to + * put in the WHITELIST all the methods that call + * ConsoleController::printText, which means all the MicroPython methods that + * call print... This is a lot of work + might reduce the performance as + * emterpreted code is slower. + * + * We thus do not allow print interruption on the web simulator. It would be + * better to allow it, but the biggest problem was on the device anyways + * -> It is much quicker to interrupt Python on the web simulator than on the + * device. + * + * TODO: Allow print interrpution on emscripten -> maybe by using WASM=1 ? */ +#else + /* micropython_port_vm_hook_loop is not enough to detect user interruptions, + * because it calls micropython_port_interrupt_if_needed every 20000 + * operations, and a print operation is quite long. We thus explicitely call + * micropython_port_interrupt_if_needed here. */ + micropython_port_interrupt_if_needed(); +#endif } void ConsoleController::autoImportScript(Script script, bool force) { diff --git a/apps/code/console_edit_cell.cpp b/apps/code/console_edit_cell.cpp index e5a4a2708..30e0472fb 100644 --- a/apps/code/console_edit_cell.cpp +++ b/apps/code/console_edit_cell.cpp @@ -55,4 +55,21 @@ bool ConsoleEditCell::insertText(const char * text) { return m_textField.handleEventWithText(text); } +void ConsoleEditCell::clearAndReduceSize() { + setText(""); + size_t previousBufferSize = m_textField.draftTextBufferSize(); + assert(previousBufferSize > 1); + m_textField.setDraftTextBufferSize(previousBufferSize - 1); +} + +const char * ConsoleEditCell::shiftCurrentTextAndClear() { + size_t previousBufferSize = m_textField.draftTextBufferSize(); + m_textField.setDraftTextBufferSize(previousBufferSize + 1); + char * textFieldBuffer = m_textField.draftTextBuffer(); + char * newTextPosition = textFieldBuffer + 1; + strlcpy(newTextPosition, textFieldBuffer, previousBufferSize); + textFieldBuffer[0] = 0; + return newTextPosition; +} + } diff --git a/apps/code/console_edit_cell.h b/apps/code/console_edit_cell.h index fb781565e..18f16ba55 100644 --- a/apps/code/console_edit_cell.h +++ b/apps/code/console_edit_cell.h @@ -34,6 +34,8 @@ public: bool insertText(const char * text); void setPrompt(const char * prompt); const char * promptText() const { return m_promptView.text(); } + void clearAndReduceSize(); + const char * shiftCurrentTextAndClear(); private: PointerTextView m_promptView; TextField m_textField; diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 7ca525419..792abf106 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -251,7 +251,6 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAbs, I18n::Message::PythonAbs), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcos, I18n::Message::PythonAcos), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcosh, I18n::Message::PythonAcosh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAppend, I18n::Message::PythonAppend, false, I18n::Message::PythonCommandAppendWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsin, I18n::Message::PythonAsin), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsinh, I18n::Message::PythonAsinh), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan, I18n::Message::PythonAtan), @@ -265,14 +264,12 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCeil, I18n::Message::PythonCeil), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandCircle, I18n::Message::PythonTurtleCircle), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandClear, I18n::Message::PythonClear, false, I18n::Message::PythonCommandClearWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCmathFunction, I18n::Message::PythonCmathFunction, false, I18n::Message::PythonCommandCmathFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandComplex, I18n::Message::PythonComplex), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCopySign, I18n::Message::PythonCopySign), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCos, I18n::Message::PythonCos), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCosh, I18n::Message::PythonCosh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCount, I18n::Message::PythonCount, false, I18n::Message::PythonCommandCountWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDegrees, I18n::Message::PythonDegrees), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDivMod, I18n::Message::PythonDivMod), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString), @@ -312,9 +309,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIndex, I18n::Message::PythonIndex, false, I18n::Message::PythonCommandIndexWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandInput, I18n::Message::PythonInput), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandInsert, I18n::Message::PythonInsert, false, I18n::Message::PythonCommandInsertWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandInt, I18n::Message::PythonInt), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIonFunction, I18n::Message::PythonIonFunction, false, I18n::Message::PythonCommandIonFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandIsdown, I18n::Message::PythonTurtleIsdown, false), @@ -327,6 +322,15 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandLeft, I18n::Message::PythonTurtleLeft), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLength, I18n::Message::PythonLength), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLgamma, I18n::Message::PythonLgamma), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAppend, I18n::Message::PythonAppend, false, I18n::Message::PythonCommandAppendWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandClear, I18n::Message::PythonClear, false, I18n::Message::PythonCommandClearWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCount, I18n::Message::PythonCount, false, I18n::Message::PythonCommandCountWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIndex, I18n::Message::PythonIndex, false, I18n::Message::PythonCommandIndexWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandInsert, I18n::Message::PythonInsert, false, I18n::Message::PythonCommandInsertWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPop, I18n::Message::PythonPop, false, I18n::Message::PythonCommandPopWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRemove, I18n::Message::PythonRemove, false, I18n::Message::PythonCommandRemoveWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReverse, I18n::Message::PythonReverse, false, I18n::Message::PythonCommandReverseWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSort, I18n::Message::PythonSort, false, I18n::Message::PythonCommandSortWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog, I18n::Message::PythonLog), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog10, I18n::Message::PythonLog10), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog2, I18n::Message::PythonLog2), @@ -344,7 +348,6 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantPi, I18n::Message::PythonConstantPi, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPop, I18n::Message::PythonPop, false, I18n::Message::PythonCommandPopWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint), @@ -358,9 +361,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStop, I18n::Message::PythonRangeStop), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRect, I18n::Message::PythonRect), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRed, I18n::Message::PythonTurtleRed, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRemove, I18n::Message::PythonRemove, false, I18n::Message::PythonCommandRemoveWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReverse, I18n::Message::PythonReverse, false, I18n::Message::PythonCommandReverseWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSetheading, I18n::Message::PythonTurtleSetheading), @@ -370,7 +371,6 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSin, I18n::Message::PythonSin), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinh, I18n::Message::PythonSinh), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSleep, I18n::Message::PythonSleep), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSort, I18n::Message::PythonSort, false, I18n::Message::PythonCommandSortWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSorted, I18n::Message::PythonSort), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSpeed, I18n::Message::PythonTurtleSpeed), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSqrt, I18n::Message::PythonSqrt), diff --git a/apps/exam_mode_configuration.h b/apps/exam_mode_configuration.h index 9377968b8..695c2b249 100644 --- a/apps/exam_mode_configuration.h +++ b/apps/exam_mode_configuration.h @@ -2,13 +2,17 @@ #define APPS_EXAM_MODE_CONFIGURATION_H #include "global_preferences.h" -#include "settings/settings_message_tree.h" +#include "shared/settings_message_tree.h" #include namespace ExamModeConfiguration { // Settings menu -extern const Settings::SettingsMessageTree s_modelExamChildren[3]; +#if LEDS_CHOICE +extern const Shared::SettingsMessageTree s_modelExamChildren[3]; +#else +extern const Shared::SettingsMessageTree s_modelExamChildren[2]; +#endif int numberOfAvailableExamMode(); GlobalPreferences::ExamMode examModeAtIndex(int index); I18n::Message examModeActivationMessage(int index); diff --git a/apps/exam_mode_configuration_non_official.cpp b/apps/exam_mode_configuration_non_official.cpp index 8905e9a79..01307ecec 100644 --- a/apps/exam_mode_configuration_non_official.cpp +++ b/apps/exam_mode_configuration_non_official.cpp @@ -2,12 +2,20 @@ using namespace Poincare; -constexpr Settings::SettingsMessageTree s_ledColorChildren[] = {Settings::SettingsMessageTree(I18n::Message::ColorRed), Settings::SettingsMessageTree(I18n::Message::ColorWhite), Settings::SettingsMessageTree(I18n::Message::ColorGreen), Settings::SettingsMessageTree(I18n::Message::ColorBlue), Settings::SettingsMessageTree(I18n::Message::ColorYellow), Settings::SettingsMessageTree(I18n::Message::ColorPurple), Settings::SettingsMessageTree(I18n::Message::ColorOrange)}; -constexpr Settings::SettingsMessageTree s_examModeMode[] = {Settings::SettingsMessageTree(I18n::Message::ExamModeModeStandard), Settings::SettingsMessageTree(I18n::Message::ExamModeModeNoSym), Settings::SettingsMessageTree(I18n::Message::ExamModeModeNoSymNoText)}; -constexpr Settings::SettingsMessageTree ExamModeConfiguration::s_modelExamChildren[] = {Settings::SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren), Settings::SettingsMessageTree(I18n::Message::ExamModeMode, s_examModeMode), Settings::SettingsMessageTree(I18n::Message::ActivateExamMode)}; +constexpr Shared::SettingsMessageTree s_examModeMode[] = {Shared::SettingsMessageTree(I18n::Message::ExamModeModeStandard), Shared::SettingsMessageTree(I18n::Message::ExamModeModeNoSym), Shared::SettingsMessageTree(I18n::Message::ExamModeModeNoSymNoText)}; +#if LEDS_CHOICE +constexpr Shared::SettingsMessageTree s_ledColorChildren[] = {Shared::SettingsMessageTree(I18n::Message::ColorRed), Shared::SettingsMessageTree(I18n::Message::ColorWhite), Shared::SettingsMessageTree(I18n::Message::ColorGreen), Shared::SettingsMessageTree(I18n::Message::ColorBlue), Shared::SettingsMessageTree(I18n::Message::ColorYellow), Shared::SettingsMessageTree(I18n::Message::ColorPurple), Shared::SettingsMessageTree(I18n::Message::ColorOrange)}; +constexpr Shared::SettingsMessageTree ExamModeConfiguration::s_modelExamChildren[] = {Shared::SettingsMessageTree(I18n::Message::LEDColor, s_ledColorChildren), Shared::SettingsMessageTree(I18n::Message::ExamModeMode, s_examModeMode), Shared::SettingsMessageTree(I18n::Message::ActivateExamMode)}; +#else +constexpr Shared::SettingsMessageTree ExamModeConfiguration::s_modelExamChildren[] = {Shared::SettingsMessageTree(I18n::Message::ExamModeMode, s_examModeMode), Shared::SettingsMessageTree(I18n::Message::ActivateExamMode)}; +#endif int ExamModeConfiguration::numberOfAvailableExamMode() { +#if LEDS_CHOICE return 3; +#else + return 2; +#endif } GlobalPreferences::ExamMode ExamModeConfiguration::examModeAtIndex(int index) { diff --git a/apps/exam_mode_configuration_official.cpp b/apps/exam_mode_configuration_official.cpp new file mode 100644 index 000000000..860b2f65c --- /dev/null +++ b/apps/exam_mode_configuration_official.cpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: CC-BY-NC-ND-4.0 +// Caution: Dutch exam mode is subject to a compliance certification by a government agency. Distribution of a non-certified Dutch exam mode is illegal. + +#include "exam_mode_configuration.h" + +constexpr Shared::SettingsMessageTree ExamModeConfiguration::s_modelExamChildren[2] = {Shared::SettingsMessageTree(I18n::Message::ActivateExamMode), Shared::SettingsMessageTree(I18n::Message::ActivateDutchExamMode)}; + +int ExamModeConfiguration::numberOfAvailableExamMode() { + if (GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::EN || GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) { + return 1; + } + return 2; +} + +GlobalPreferences::ExamMode ExamModeConfiguration::examModeAtIndex(int index) { + return index == 0 ? GlobalPreferences::ExamMode::Standard : GlobalPreferences::ExamMode::Dutch; +} + +I18n::Message ExamModeConfiguration::examModeActivationMessage(int index) { + return index == 0 ? I18n::Message::ActivateExamMode : I18n::Message::ActivateDutchExamMode; +} + +I18n::Message ExamModeConfiguration::examModeActivationWarningMessage(GlobalPreferences::ExamMode mode, int line) { + if (mode == GlobalPreferences::ExamMode::Off) { + I18n::Message warnings[] = {I18n::Message::ExitExamMode1, I18n::Message::ExitExamMode2, I18n::Message::Default}; + return warnings[line]; + } else if (mode == GlobalPreferences::ExamMode::Standard) { + I18n::Message warnings[] = {I18n::Message::ActiveExamModeMessage1, I18n::Message::ActiveExamModeMessage2, I18n::Message::ActiveExamModeMessage3}; + return warnings[line]; + } + assert(mode == GlobalPreferences::ExamMode::Dutch); + I18n::Message warnings[] = {I18n::Message::ActiveDutchExamModeMessage1, I18n::Message::ActiveDutchExamModeMessage2, I18n::Message::ActiveDutchExamModeMessage3}; + return warnings[line]; +} + +KDColor ExamModeConfiguration::examModeColor(GlobalPreferences::ExamMode mode) { + /* 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. */ + return mode == GlobalPreferences::ExamMode::Dutch ? KDColorYellow : KDColorRed; +} + +bool ExamModeConfiguration::appIsForbiddenInExamMode(I18n::Message appName, GlobalPreferences::ExamMode mode) { + return appName == I18n::Message::CodeApp && mode == GlobalPreferences::ExamMode::Dutch; +} + +bool ExamModeConfiguration::exactExpressionsAreForbidden(GlobalPreferences::ExamMode mode) { + return mode == GlobalPreferences::ExamMode::Dutch; +} diff --git a/apps/graph/base.hu.i18n b/apps/graph/base.hu.i18n index f27548364..24e6ae435 100644 --- a/apps/graph/base.hu.i18n +++ b/apps/graph/base.hu.i18n @@ -1,12 +1,12 @@ FunctionApp = "Funkciók" FunctionAppCapital = "FUNKCIÓK" FunctionTab = "Funkciók" -AddFunction = "Add function" +AddFunction = "Funkció hozzáadása" DeleteFunction = "Funkció törlése" CurveType = "Görbe típus" -CartesianType = "Cartesian " -PolarType = "Polar " -ParametricType = "Parametric " +CartesianType = "Kartéziánus " +PolarType = "Poláris " +ParametricType = "Parametrikus " IntervalT = "t intervallum" IntervalTheta = "θ intervallum" IntervalX = "x intervallum" @@ -17,7 +17,7 @@ NoActivatedFunction = "Nincs bekapcsolt funkció" PlotOptions = "Tervezési lehetöségek" Compute = "Számítás" Zeros = "Nullák" -Tangent = "Tangent" +Tangent = "Tangens" Intersection = "Keresztezés" Preimage = "Inverz kép" SelectLowerBound = "Alsó határ kiválasztása" diff --git a/apps/home/base.de.i18n b/apps/home/base.de.i18n index 352d41520..99f705c4b 100644 --- a/apps/home/base.de.i18n +++ b/apps/home/base.de.i18n @@ -1,4 +1,4 @@ Apps = "Anwendungen" AppsCapital = "OMEGA" -ForbidenAppInExamMode1 = "This application is" -ForbidenAppInExamMode2 = "forbidden in exam mode" +ForbidenAppInExamMode1 = "Diese Anwendung ist im" +ForbidenAppInExamMode2 = "Prüfungsmodus verboten" diff --git a/apps/regression/base.hu.i18n b/apps/regression/base.hu.i18n index 8d2b1d924..a3f937e5d 100644 --- a/apps/regression/base.hu.i18n +++ b/apps/regression/base.hu.i18n @@ -12,9 +12,9 @@ Covariance = "Kovariancia" Linear = "Lineáris" Quadratic = "Másodfokú" Cubic = "Kocka" -Quartic = "Quartic" +Quartic = "Kvartikus" Logarithmic = "Logaritmikus" Power = "Teljesítmény" Trigonometrical = "Trigonometrikus" -Logistic = "Logistic" +Logistic = "Logisztikai" DataNotSuitableForRegression = " Az adat nem megfelelö ehhez a regressziós modellhez" diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index 78f8ea350..b59809bca 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -84,18 +84,7 @@ void GraphController::viewWillAppear() { /* Since *m_selectedDotIndex is altered by initCursorParameters(), * the following must absolutely come at the end. */ - if (*m_selectedDotIndex >= 0) { - setRoundCrossCursorView(false); - } else { - setRoundCrossCursorView(true); - m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); - } -} - -void GraphController::selectRegressionCurve() { - *m_selectedDotIndex = -1; - setRoundCrossCursorView(true); - m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); + setRoundCrossCursorView(); } // Private @@ -324,19 +313,22 @@ bool GraphController::moveCursorVertically(int direction) { assert(!validDot || !validRegression); + /* The model should be up to date before setting the cursor view. */ + if (validRegression) { // Select the regression *m_selectedSeriesIndex = closestRegressionSeries; - selectRegressionCurve(); + *m_selectedDotIndex = -1; + setRoundCrossCursorView(); m_cursor->moveTo(x, x, yValue(*m_selectedSeriesIndex, x, context)); return true; } if (validDot) { // Select the dot - setRoundCrossCursorView(false); *m_selectedSeriesIndex = closestDotSeries; *m_selectedDotIndex = dotSelected; + setRoundCrossCursorView(); if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { // Select the mean dot double x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); @@ -404,8 +396,16 @@ InteractiveCurveViewRangeDelegate::Range GraphController::computeYRange(Interact return range; } -void GraphController::setRoundCrossCursorView(bool round) { +void GraphController::setRoundCrossCursorView() { + /* At this point, the model (selected series and dot indices) should be up + * to date. */ + bool round = *m_selectedDotIndex < 0; + if (round) { + // Set the color although the cursor view stays round + m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); + } CursorView * nextCursorView = round ? static_cast(&m_roundCursorView) : static_cast(&m_crossCursorView); + // Escape if the cursor view stays the same if (m_view.cursorView() == nextCursorView) { return; } diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 0c35ad9ab..f1c257a12 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -21,7 +21,7 @@ public: bool isEmpty() const override; I18n::Message emptyMessage() override; void viewWillAppear() override; - void selectRegressionCurve(); + void selectRegressionCurve() { *m_selectedDotIndex = -1; } int selectedSeriesIndex() const { return *m_selectedSeriesIndex; } // moveCursorHorizontally and Vertically are public to be used in tests @@ -55,7 +55,7 @@ private: // InteractiveCurveViewRangeDelegate Shared::InteractiveCurveViewRangeDelegate::Range computeYRange(Shared::InteractiveCurveViewRange * interactiveCurveViewRange) override; - void setRoundCrossCursorView(bool round); + void setRoundCrossCursorView(); Shared::CursorView m_crossCursorView; Shared::RoundCursorView m_roundCursorView; BannerView m_bannerView; diff --git a/apps/settings/Makefile b/apps/settings/Makefile index 17229f77c..89731dd29 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -1,10 +1,6 @@ apps += Settings::App app_headers += apps/settings/app.h -app_settings_test_src = $(addprefix apps/settings/,\ - settings_message_tree.cpp \ -) - app_settings_src = $(addprefix apps/settings/,\ app.cpp \ cell_with_separator.cpp \ diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 6f377cd0a..bc10bd120 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -7,9 +7,7 @@ EditionLinear = "Linear " Edition2D = "Natürlich " ComplexFormat = "Komplex" ExamMode = "Testmodus" -ActivateExamMode = "Starten Testmodus" -ExamModeActive = "Wieder starten Testmodus" -ActivateDutchExamMode = "Activate Dutch exam mode" +ExamModeActive = "Testmodus neustarten" ToDeactivateExamMode1 = "Um den Testmodus auszuschalten," ToDeactivateExamMode2 = "schließen Sie den Rechner an einen" ToDeactivateExamMode3 = "Computer oder eine Steckdose an." @@ -38,28 +36,15 @@ SoftwareVersion = "Epsilon version" CustomSoftwareVersion = "Omega version" Username = "Name" MicroPythonVersion = "µPythonversion" -ResultDisplay = "Resultaatweergave" -DefaultResult = "Standaard " +ResultDisplay = "Ergebniswiedergabe" +DefaultResult = "Standard " CompactResult = "Compact " FontSizes = "Python Schriftgröße" -LargeFont = "Große " -SmallFont = "Kleine " +LargeFont = "Groß " +SmallFont = "Klein " SerialNumber = "Seriennummer" UpdatePopUp = "Erinnerung: Update" BetaPopUp = "Beta pop-up" -LEDColor = "LEDs farbe" -ExamModeMode = "Modus" -ExamModeModeStandard = "Standard " -ExamModeModeNoSym = "Ohne symbolisch " -ExamModeModeNoSymNoText = "No sym no text " -ExamModeModeDutch = "Niederländisch " -ColorRed = "Rot " -ColorWhite = "Weiss " -ColorBlue = "Blau " -ColorGreen = "Grün " -ColorYellow = "Gelb " -ColorPurple = "Lila " -ColorOrange = "Orange " Contributors = "Beiträger" Accessibility = "Barrierefreiheit" AccessibilityInvertColors = "Farbumkehrung" @@ -68,13 +53,13 @@ AccessibilityGamma = "Gammakorrektur" AccessibilityGammaRed = "Rotes Gamma" AccessibilityGammaGreen = "Grünes Gamma" AccessibilityGammaBlue = "Blaues Gamma" -MathOptions = "Mathe-optionen" +MathOptions = "Berechnungseinstellungen" SymbolMultiplication = "Multiplikation" SymbolMultiplicationCross = "Kreuz " SymbolMultiplicationMiddleDot = "Mittelpunkt " SymbolMultiplicationStar = "Stern " SymbolMultiplicationAutoSymbol = "automatisch " -PythonFont = "Python schriftart" +PythonFont = "Python Schriftart" Large = "Groß " Small = "Klein " MemUse = "Speicher" diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 68661574d..e09b048fa 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -7,9 +7,7 @@ EditionLinear = "Linear " Edition2D = "Natural " ComplexFormat = "Complex format" ExamMode = "Exam mode" -ActivateExamMode = "Activate exam mode" ExamModeActive = "Reactivate exam mode" -ActivateDutchExamMode = "Activate Dutch exam mode" ToDeactivateExamMode1 = "To deactivate the exam mode," ToDeactivateExamMode2 = "plug the calculator to a computer" ToDeactivateExamMode3 = "or to a power socket." @@ -47,19 +45,6 @@ SmallFont = "Small " SerialNumber = "Serial number" UpdatePopUp = "Update pop-up" BetaPopUp = "Beta pop-up" -LEDColor = "LED color" -ExamModeMode = "Mode" -ExamModeModeStandard = "Standard " -ExamModeModeNoSym = "No sym " -ExamModeModeNoSymNoText = "No sym no text " -ExamModeModeDutch = "Dutch " -ColorRed = "Red " -ColorWhite = "White " -ColorBlue = "Blue " -ColorGreen = "Green " -ColorYellow = "Yellow " -ColorPurple = "Purple " -ColorOrange = "Orange " Contributors = "Contributors" Accessibility = "Accessibility" AccessibilityInvertColors = "Invert colors" diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index f9701b2e3..c8d4a88a1 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -7,9 +7,7 @@ EditionLinear = "En línea " Edition2D = "Natural " ComplexFormat = "Forma compleja" ExamMode = "Modo examen" -ActivateExamMode = "Activar el modo examen" ExamModeActive = "Reactivar el modo examen" -ActivateDutchExamMode = "Activate Dutch exam mode" ToDeactivateExamMode1 = "Para desactivar el modo examen," ToDeactivateExamMode2 = "conecte la calculadora a un ordenador" ToDeactivateExamMode3 = "o a un enchufe eléctrico." @@ -47,19 +45,6 @@ SmallFont = "Pequeño " 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 " -ExamModeModeNoSymNoText = "sin simbolismo sin texto " -ExamModeModeDutch = "Holandés " -ColorRed = "Rojo " -ColorWhite = "Blanco " -ColorBlue = "Azul " -ColorGreen = "Verde " -ColorYellow = "Amarillo " -ColorPurple = "Púrpura " -ColorOrange = "Naranja " Contributors = "Contribuyentes" Accessibility = "Accesibilidad" AccessibilityInvertColors = "Colores invertidos" diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index b051ae002..a23f8a0b9 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -7,9 +7,7 @@ EditionLinear = "En ligne " Edition2D = "Naturelle " ComplexFormat = "Forme complexe" ExamMode = "Mode examen" -ActivateExamMode = "Activer le mode examen" ExamModeActive = "Réactiver le mode examen" -ActivateDutchExamMode = "Activate Dutch exam mode" ToDeactivateExamMode1 = "Pour désactiver le mode examen," ToDeactivateExamMode2 = "brancher la calculatrice à un" ToDeactivateExamMode3 = "ordinateur ou à une prise de courant." @@ -47,19 +45,6 @@ SmallFont = "Petit " SerialNumber = "Numéro série" UpdatePopUp = "Rappel mise à jour" BetaPopUp = "Rappel version bêta" -LEDColor = "Couleur LED" -ExamModeMode = "Mode" -ExamModeModeStandard = "Standard " -ExamModeModeNoSym = "Sans symbolique " -ExamModeModeNoSymNoText = "Sans symbolique ni texte " -ExamModeModeDutch = "Néerlandais " -ColorRed = "Rouge " -ColorWhite = "Blanc " -ColorBlue = "Bleu " -ColorGreen = "Vert " -ColorYellow = "Jaune " -ColorPurple = "Mauve " -ColorOrange = "Orange " Contributors = "Contributeurs" Accessibility = "Accessibilité" AccessibilityInvertColors = "Inverser couleurs" diff --git a/apps/settings/base.hu.i18n b/apps/settings/base.hu.i18n index 4a421bdce..b3828759e 100644 --- a/apps/settings/base.hu.i18n +++ b/apps/settings/base.hu.i18n @@ -7,9 +7,7 @@ EditionLinear = "Lineáris" Edition2D = "Természetes" ComplexFormat = "Komplex formátum" ExamMode = "Vizsga mód" -ActivateExamMode = "A vizsgálati mód aktiválása" ExamModeActive = "A vizsgamód újraaktiválása" -ActivateDutchExamMode = "A holland vizsga mód aktiválása" ToDeactivateExamMode1 = "a vizsga mód kikapcsoláshoz" ToDeactivateExamMode2 = "csatlakoztassa a számológépet a számítógéphez" ToDeactivateExamMode3 = "vagy egy konnektorhoz." @@ -24,15 +22,15 @@ AboutWarning4 = "az esetleges károkért." # ----------------------------------------------------------------------------- About = "Egyéb" Degrees = "Fokok " -Gradians = "Gradians " -Radian = "Radians " +Gradians = "Gradiens " +Radian = "Radián " Decimal = "Tizedes " Scientific = "Tudományos " Engineering = "Mérnöki " SignificantFigures = "Tizedes számok " -Real = "Real " -Cartesian = "Cartesian " -Polar = "Polar " +Real = "Valódi " +Cartesian = "Kartéziánus " +Polar = "Poláris " Brightness = "Fényerö" SoftwareVersion = "Epsilon verzió" CustomSoftwareVersion = "Omega verzió" @@ -47,19 +45,6 @@ SmallFont = "Kicsi " SerialNumber = "Sorozatszám" UpdatePopUp = "Elöugró ablak frissítése" BetaPopUp = "Béta pop-up" -LEDColor = "LED szín" -ExamModeMode = "Üzemmód" -ExamModeModeStandard = "Normál" -ExamModeModeNoSym = "Nincs sym" -ExamModeModeNoSymNoText = "No Symbolic no text " -ExamModeModeDutch = "Holland " -ColorRed = "Piros " -ColorWhite = "Fehér " -ColorBlue = "Kék " -ColorGreen = "Zöld " -ColorYellow = "Sárga " -ColorPurple = "Lila " -ColorOrange = "Narancssárga " Contributors = "Közremüködök" Accessibility = "Hozzáférhetöség" AccessibilityInvertColors = "Invertált színek" diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 6371abd2c..c3fb57e31 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -7,9 +7,7 @@ EditionLinear = "Em linha " Edition2D = "Natural " ComplexFormat = "Complexos" ExamMode = "Modo de exame" -ActivateExamMode = "Activar o modo de exame" ExamModeActive = "Reactivar o modo de exame" -ActivateDutchExamMode = "Activate Dutch exam mode" ToDeactivateExamMode1 = "Para desactivar o modo de exame," ToDeactivateExamMode2 = "ligue a calculadora a um computador" ToDeactivateExamMode3 = "ou a uma tomada eléctrica." @@ -47,19 +45,6 @@ SmallFont = "Pequeno " 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 " -ExamModeModeNoSymNoText = "Sem simbólico sem texto " -ExamModeModeDutch = "Holandês " -ColorRed = "Vermelho " -ColorWhite = "Branco " -ColorBlue = "Azul " -ColorGreen = "Verde " -ColorYellow = "Amarelo " -ColorPurple = "Roxo " -ColorOrange = "Caranja " Contributors = "Contribuidores" Accessibility = "Acessibilidade" AccessibilityInvertColors = "Cores invertidas" diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index be25f7b35..bf86296d0 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -5,6 +5,7 @@ #include using namespace Poincare; +using namespace Shared; namespace Settings { diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h index 76be4f1d9..e0e2066ef 100644 --- a/apps/settings/main_controller.h +++ b/apps/settings/main_controller.h @@ -2,7 +2,7 @@ #define SETTINGS_MAIN_CONTROLLER_H #include -#include "settings_message_tree.h" +#include #include "message_table_cell_with_gauge_with_separator.h" #include "sub_menu/about_controller.h" #include "sub_menu/accessibility_controller.h" @@ -13,22 +13,22 @@ namespace Settings { -extern const SettingsMessageTree s_modelAngleChildren[3]; -extern const SettingsMessageTree s_modelEditionModeChildren[2]; -extern const SettingsMessageTree s_modelFloatDisplayModeChildren[4]; -extern const SettingsMessageTree s_modelComplexFormatChildren[3]; -extern const SettingsMessageTree s_symbolChildren[4]; -extern const SettingsMessageTree s_modelMathOptionsChildren[5]; -extern const SettingsMessageTree s_modelResultDisplayChildren[2]; -extern const SettingsMessageTree s_modelFontChildren[2]; -extern const SettingsMessageTree s_accessibilityChildren[6]; -extern const SettingsMessageTree s_contributorsChildren[16]; +extern const Shared::SettingsMessageTree s_modelAngleChildren[3]; +extern const Shared::SettingsMessageTree s_modelEditionModeChildren[2]; +extern const Shared::SettingsMessageTree s_modelFloatDisplayModeChildren[4]; +extern const Shared::SettingsMessageTree s_modelComplexFormatChildren[3]; +extern const Shared::SettingsMessageTree s_symbolChildren[4]; +extern const Shared::SettingsMessageTree s_modelMathOptionsChildren[5]; +extern const Shared::SettingsMessageTree s_modelResultDisplayChildren[2]; +extern const Shared::SettingsMessageTree s_modelFontChildren[2]; +extern const Shared::SettingsMessageTree s_accessibilityChildren[6]; +extern const Shared::SettingsMessageTree s_contributorsChildren[16]; #ifdef USERNAME -extern const SettingsMessageTree s_modelAboutChildren[8]; +extern const Shared::SettingsMessageTree s_modelAboutChildren[8]; #else -extern const SettingsMessageTree s_modelAboutChildren[7]; +extern const Shared::SettingsMessageTree s_modelAboutChildren[7]; #endif -extern const SettingsMessageTree s_model; +extern const Shared::SettingsMessageTree s_model; class MainController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource { public: @@ -59,7 +59,7 @@ private: * k_indexOfAboutCell) */ constexpr static int k_indexOfPopUpCell = k_indexOfFontCell + 1; constexpr static int k_indexOfAboutCell = k_indexOfFontCell + 1; - static const SettingsMessageTree * model(); + static const Shared::SettingsMessageTree * model(); private: StackViewController * stackController() const; I18n::Message promptMessage() const; diff --git a/apps/settings/main_controller_prompt_beta.cpp b/apps/settings/main_controller_prompt_beta.cpp index f7546a2ce..c5eb3fef6 100644 --- a/apps/settings/main_controller_prompt_beta.cpp +++ b/apps/settings/main_controller_prompt_beta.cpp @@ -2,6 +2,8 @@ #include "../exam_mode_configuration.h" #include +using namespace Shared; + namespace Settings { constexpr SettingsMessageTree s_modelMenu[] = diff --git a/apps/settings/main_controller_prompt_none.cpp b/apps/settings/main_controller_prompt_none.cpp index d382a0b11..80c61b2c1 100644 --- a/apps/settings/main_controller_prompt_none.cpp +++ b/apps/settings/main_controller_prompt_none.cpp @@ -2,6 +2,8 @@ #include "../exam_mode_configuration.h" #include +using namespace Shared; + namespace Settings { constexpr SettingsMessageTree s_modelMenu[] = diff --git a/apps/settings/main_controller_prompt_update.cpp b/apps/settings/main_controller_prompt_update.cpp index b7586d190..77619e6f2 100644 --- a/apps/settings/main_controller_prompt_update.cpp +++ b/apps/settings/main_controller_prompt_update.cpp @@ -4,6 +4,8 @@ namespace Settings { +using namespace Shared; + constexpr SettingsMessageTree s_modelMenu[] = {SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren), SettingsMessageTree(I18n::Message::Brightness), diff --git a/apps/settings/settings_message_tree.cpp b/apps/settings/settings_message_tree.cpp deleted file mode 100644 index f481eb543..000000000 --- a/apps/settings/settings_message_tree.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "settings_message_tree.h" - -namespace Settings { - -const MessageTree * SettingsMessageTree::children(int index) const { - return &m_children[index]; -} - -} diff --git a/apps/settings/sub_menu/about_controller_official.cpp b/apps/settings/sub_menu/about_controller_official.cpp index f46c96d2e..a5b94d4d3 100644 --- a/apps/settings/sub_menu/about_controller_official.cpp +++ b/apps/settings/sub_menu/about_controller_official.cpp @@ -4,7 +4,7 @@ namespace Settings { void AboutController::viewWillAppear() { GenericSubController::viewWillAppear(); - m_view.setMessages(nullptr, 0); + //m_view.setMessages(nullptr, 0); } } diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp index c88c95575..e47766266 100644 --- a/apps/settings/sub_menu/exam_mode_controller.cpp +++ b/apps/settings/sub_menu/exam_mode_controller.cpp @@ -19,7 +19,9 @@ ExamModeController::ExamModeController(Responder * parentResponder) : m_cell{}, m_ledController(this), m_examModeModeController(this), +#if LEDS_CHOICE m_ledColorCell(KDFont::LargeFont, KDFont::SmallFont), +#endif m_examModeCell(KDFont::LargeFont, KDFont::SmallFont) { for (int i = 0; i < k_maxNumberOfCells; i++) { @@ -30,17 +32,21 @@ ExamModeController::ExamModeController(Responder * parentResponder) : bool ExamModeController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) { - if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::LEDColor) { - (&m_ledController)->setMessageTreeModel(m_messageTreeModel->children(selectedRow())); - StackViewController * stack = stackController(); - stack->push(&m_ledController); - return true; - } else if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::ExamModeMode) { + if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::ExamModeMode) { (&m_examModeModeController)->setMessageTreeModel(m_messageTreeModel->children(selectedRow())); StackViewController * stack = stackController(); stack->push(&m_examModeModeController); return true; - } else { + } +#if LEDS_CHOICE + else if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::LEDColor) { + (&m_ledController)->setMessageTreeModel(m_messageTreeModel->children(selectedRow())); + StackViewController * stack = stackController(); + stack->push(&m_ledController); + return true; + } +#endif + else { AppsContainer::sharedAppsContainer()->displayExamModePopUp(examMode()); return true; } @@ -73,9 +79,11 @@ int ExamModeController::numberOfRows() const { HighlightCell * ExamModeController::reusableCell(int index, int type) { assert(type == 0); assert(index >= 0 && index < 3); +#if LEDS_CHOICE if (m_messageTreeModel->children(index)->label() == I18n::Message::LEDColor) { return &m_ledColorCell; } +#endif if (m_messageTreeModel->children(index)->label() == I18n::Message::ExamModeMode) { return &m_examModeCell; } @@ -99,11 +107,13 @@ void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index MessageTableCell * myCell = (MessageTableCell *)cell; myCell->setMessage(I18n::Message::ExamModeActive); } +#if LEDS_CHOICE if (thisLabel == I18n::Message::LEDColor) { MessageTableCellWithChevronAndMessage * myTextCell = (MessageTableCellWithChevronAndMessage *)cell; I18n::Message message = (I18n::Message) m_messageTreeModel->children(index)->children((int)preferences->colorOfLED())->label(); myTextCell->setSubtitle(message); } +#endif 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(); diff --git a/apps/settings/sub_menu/exam_mode_controller.h b/apps/settings/sub_menu/exam_mode_controller.h index f614e025f..e81563da3 100644 --- a/apps/settings/sub_menu/exam_mode_controller.h +++ b/apps/settings/sub_menu/exam_mode_controller.h @@ -30,7 +30,9 @@ private: MessageTableCell m_cell[k_maxNumberOfCells]; PreferencesController m_ledController; PreferencesController m_examModeModeController; +#if LEDS_CHOICE MessageTableCellWithChevronAndMessage m_ledColorCell; +#endif MessageTableCellWithChevronAndMessage m_examModeCell; }; diff --git a/apps/settings/sub_menu/generic_sub_controller.h b/apps/settings/sub_menu/generic_sub_controller.h index 545a79c80..c149a2508 100644 --- a/apps/settings/sub_menu/generic_sub_controller.h +++ b/apps/settings/sub_menu/generic_sub_controller.h @@ -2,7 +2,7 @@ #define SETTINGS_GENERIC_SUB_CONTROLLER_H #include -#include "../settings_message_tree.h" +#include namespace Settings { diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp index d5603c290..c0b4b973d 100644 --- a/apps/settings/sub_menu/preferences_controller.cpp +++ b/apps/settings/sub_menu/preferences_controller.cpp @@ -267,9 +267,11 @@ int PreferencesController::valueIndexForPreference(I18n::Message message) const if (message == I18n::Message::ComplexFormat) { return (int)preferences->complexFormat(); } +#if LEDS_CHOICE if (message == I18n::Message::LEDColor) { return (int)preferences->colorOfLED(); } +#endif if (message == I18n::Message::SymbolMultiplication) { return (int)preferences->symbolofMultiplication(); } diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index a7fcd3641..353bbb86f 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -1,4 +1,6 @@ ActivateDeactivate = "Aktivieren/Deaktivieren" +ActivateDutchExamMode = "Activate Dutch exam mode" +ActivateExamMode = "Starten Testmodus" ActiveExamModeMessage1 = "Alle Ihre Daten werden " ActiveExamModeMessage2 = "gelöscht, wenn Sie den " ActiveExamModeMessage3 = "Testmodus einschalten." @@ -80,3 +82,16 @@ XStart = "X Startwert" Zoom = "Zoom" Developers = "Entwickler" BetaTesters = "Beta-Tester" +LEDColor = "LED Farbe" +ExamModeMode = "Modus" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "Ohne Symbole " +ExamModeModeNoSymNoText = "Ohne Symbole & Text " +ExamModeModeDutch = "Niederländisch " +ColorRed = "Rot " +ColorWhite = "Weiss " +ColorBlue = "Blau " +ColorGreen = "Grün " +ColorYellow = "Gelb " +ColorPurple = "Lila " +ColorOrange = "Orange " diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index 4dbe4348e..bbef03c83 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -1,4 +1,6 @@ ActivateDeactivate = "Turn on/off" +ActivateExamMode = "Activate exam mode" +ActivateDutchExamMode = "Activate Dutch exam mode" ActiveExamModeMessage1 = "All your data will be " ActiveExamModeMessage2 = "deleted when you activate " ActiveExamModeMessage3 = "the exam mode." @@ -80,3 +82,16 @@ XStart = "X start" Zoom = "Zoom" Developers = "Developers" BetaTesters = "Beta testers" +LEDColor = "LED color" +ExamModeMode = "Mode" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "No sym " +ExamModeModeNoSymNoText = "No sym no text " +ExamModeModeDutch = "Dutch " +ColorRed = "Red " +ColorWhite = "White " +ColorBlue = "Blue " +ColorGreen = "Green " +ColorYellow = "Yellow " +ColorPurple = "Purple " +ColorOrange = "Orange " diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index a693d73e6..2ac9ff491 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -1,4 +1,6 @@ ActivateDeactivate = "Activar/Desactivar" +ActivateExamMode = "Activar el modo examen" +ActivateDutchExamMode = "Activate Dutch exam mode" ActiveExamModeMessage1 = "Todos sus datos se " ActiveExamModeMessage2 = "eliminaran al activar " ActiveExamModeMessage3 = "el modo examen." @@ -80,3 +82,16 @@ XStart = "X inicio" Zoom = "Zoom" Developers = "Desarrolladores" BetaTesters = "Probadores beta" +LEDColor = "Color del LED" +ExamModeMode = "Modo" +ExamModeModeStandard = "Estándar " +ExamModeModeNoSym = "Sin simbólico " +ExamModeModeNoSymNoText = "sin simbolismo sin texto " +ExamModeModeDutch = "Holandés " +ColorRed = "Rojo " +ColorWhite = "Blanco " +ColorBlue = "Azul " +ColorGreen = "Verde " +ColorYellow = "Amarillo " +ColorPurple = "Púrpura " +ColorOrange = "Naranja " diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index 328c08283..f711cbbec 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -1,4 +1,6 @@ ActivateDeactivate = "Activer/Désactiver" +ActivateExamMode = "Activer le mode examen" +ActivateDutchExamMode = "Activate Dutch exam mode" ActiveExamModeMessage1 = "Toutes vos données seront " ActiveExamModeMessage2 = "supprimées si vous activez " ActiveExamModeMessage3 = "le mode examen." @@ -80,3 +82,16 @@ XStart = "X début" Zoom = "Zoom" Developers = "Développeurs" BetaTesters = "Beta testeurs" +LEDColor = "Couleur LED" +ExamModeMode = "Mode" +ExamModeModeStandard = "Standard " +ExamModeModeNoSym = "Sans symbolique " +ExamModeModeNoSymNoText = "Sans symbolique ni texte " +ExamModeModeDutch = "Néerlandais " +ColorRed = "Rouge " +ColorWhite = "Blanc " +ColorBlue = "Bleu " +ColorGreen = "Vert " +ColorYellow = "Jaune " +ColorPurple = "Mauve " +ColorOrange = "Orange " diff --git a/apps/shared.hu.i18n b/apps/shared.hu.i18n index fa4299942..4862d64f7 100644 --- a/apps/shared.hu.i18n +++ b/apps/shared.hu.i18n @@ -1,4 +1,6 @@ ActivateDeactivate = "Ki/Be kapcsolás" +ActivateExamMode = "A vizsgálati mód aktiválása" +ActivateDutchExamMode = "A holland vizsga mód aktiválása" ActiveExamModeMessage1 = "Az összes adatod" ActiveExamModeMessage2 = "törölve lesz ha" ActiveExamModeMessage3 = "aktiválod a vizsga módot." @@ -24,7 +26,7 @@ Exponential = "Exponenciális" FillWithFormula = "Töltse ki egy képlettel" ForbiddenValue = "Tiltott érték" FunctionColumn = "0 (0) oszlop" -FunctionOptions = "Function options" +FunctionOptions = "Funkció opciók" Goto = "Menj ide" GraphTab = "Grafikon" HardwareTestLaunch1 = "Ön elindítja a hardvert" @@ -67,11 +69,11 @@ SyntaxError = "Szintaxis hiba" Sym = "sym" TEnd = "T vég" ThetaEnd = "θ vége" -ThetaStart = "θ start" -TStart = "T start" +ThetaStart = "θ kezdete" +TStart = "T kezdete" ToZoom = "Zoom:" Trigonometric = "Trigonometrikus" -UndefinedValue = "Undefined value" +UndefinedValue = "Nincs meghatározva érték" ValueNotReachedByFunction = "Az értéket a funkció nem érte el" ValuesTab = "Táblázat" Warning = "Figyelem" @@ -80,3 +82,16 @@ XStart = "X kezdete" Zoom = "Zoom" Developers = "Fejlesztök" BetaTesters = "Béta tesztelök" +LEDColor = "LED szín" +ExamModeMode = "Üzemmód" +ExamModeModeStandard = "Normál" +ExamModeModeNoSym = "Nincs sym" +ExamModeModeNoSymNoText = "Nincs szimbolikus, nincs szöveg " +ExamModeModeDutch = "Holland " +ColorRed = "Piros " +ColorWhite = "Fehér " +ColorBlue = "Kék " +ColorGreen = "Zöld " +ColorYellow = "Sárga " +ColorPurple = "Lila " +ColorOrange = "Narancssárga " diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 8c61d7103..7ffa4a8b0 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -1,4 +1,6 @@ ActivateDeactivate = "Activar/Desactivar" +ActivateExamMode = "Activar o modo de exame" +ActivateDutchExamMode = "Activate Dutch exam mode" ActiveExamModeMessage1 = "Todos os seus dados serão " ActiveExamModeMessage2 = "apagados se você ligar " ActiveExamModeMessage3 = "o modo de exame." @@ -80,3 +82,16 @@ XStart = "X inicio" Zoom = "Zoom" Developers = "Desenvolvedores" BetaTesters = "Testadores beta" +LEDColor = "Cor LED" +ExamModeMode = "Modo" +ExamModeModeStandard = "Padrão " +ExamModeModeNoSym = "Sem simbólico " +ExamModeModeNoSymNoText = "Sem simbólico sem texto " +ExamModeModeDutch = "Holandês " +ColorRed = "Vermelho " +ColorWhite = "Branco " +ColorBlue = "Azul " +ColorGreen = "Verde " +ColorYellow = "Amarelo " +ColorPurple = "Roxo " +ColorOrange = "Caranja " diff --git a/apps/shared/expression_model.cpp b/apps/shared/expression_model.cpp index 530f7b200..c67d399b7 100644 --- a/apps/shared/expression_model.cpp +++ b/apps/shared/expression_model.cpp @@ -24,13 +24,19 @@ ExpressionModel::ExpressionModel() : void ExpressionModel::text(const Storage::Record * record, char * buffer, size_t bufferSize, CodePoint symbol) const { Expression e = expressionClone(record); - if (e.isUninitialized() && bufferSize > 0) { - buffer[0] = 0; - } else { - if (symbol != 0 && !e.isUninitialized()) { - e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), Symbol::Builder(symbol)); + if (e.isUninitialized()) { + if (bufferSize > 0) { + buffer[0] = 0; } - e.serialize(buffer, bufferSize); + return; + } + if (symbol != 0) { + e = e.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), Symbol::Builder(symbol)); + } + int serializedSize = e.serialize(buffer, bufferSize); + if (serializedSize >= bufferSize - 1) { + // It is very likely that the buffer is overflowed + buffer[0] = 0; } } diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index 5a80460b5..7cede0ee8 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -26,7 +26,7 @@ void FunctionApp::Snapshot::storageDidChangeForRecord(const Ion::Storage::Record void FunctionApp::willBecomeInactive() { if (m_modalViewController.isDisplayingModal()) { - m_modalViewController.dismissModalViewController(); + m_modalViewController.dismissModalViewController(true); } if (inputViewController()->isDisplayingModal()) { inputViewController()->abortEditionAndDismiss(); diff --git a/apps/shared/interactive_curve_view_range.cpp b/apps/shared/interactive_curve_view_range.cpp index 7e5f9680d..2db5afaa2 100644 --- a/apps/shared/interactive_curve_view_range.cpp +++ b/apps/shared/interactive_curve_view_range.cpp @@ -131,9 +131,9 @@ void InteractiveCurveViewRange::setDefault() { return; } if (!m_delegate->defautRangeIsNormalized()) { + m_yAuto = true; m_xRange.setMax(m_delegate->interestingXHalfRange(), k_lowerMaxFloat, k_upperMaxFloat); setXMin(-xMax()); - m_yAuto = true; return; } diff --git a/apps/settings/settings_message_tree.h b/apps/shared/settings_message_tree.h similarity index 71% rename from apps/settings/settings_message_tree.h rename to apps/shared/settings_message_tree.h index 10d1b5205..f3c3bf364 100644 --- a/apps/settings/settings_message_tree.h +++ b/apps/shared/settings_message_tree.h @@ -1,24 +1,26 @@ -#ifndef SETTINGS_MESSAGE_TREE_H -#define SETTINGS_MESSAGE_TREE_H +#ifndef SHARED_SETTINGS_MESSAGE_TREE_H +#define SHARED_SETTINGS_MESSAGE_TREE_H + #include #include -namespace Settings { +namespace Shared { class SettingsMessageTree : public MessageTree { public: constexpr SettingsMessageTree(I18n::Message label = I18n::Message::Default) : MessageTree(label, 0), m_children(nullptr) - { - }; + {} + template constexpr SettingsMessageTree(I18n::Message label, const SettingsMessageTree (&children)[N] = nullptr) : MessageTree(label, N), m_children(children) - { - }; - const MessageTree * children(int index) const override; + {} + + const MessageTree * children(int index) const override { return &m_children[index]; } + private: const SettingsMessageTree * m_children; }; diff --git a/apps/solver/app.cpp b/apps/solver/app.cpp index 55a2a390d..0d50e5859 100644 --- a/apps/solver/app.cpp +++ b/apps/solver/app.cpp @@ -60,7 +60,7 @@ App::App(Snapshot * snapshot) : void App::willBecomeInactive() { if (m_modalViewController.isDisplayingModal()) { - m_modalViewController.dismissModalViewController(); + m_modalViewController.dismissModalViewController(true); } if (inputViewController()->isDisplayingModal()) { inputViewController()->abortEditionAndDismiss(); diff --git a/apps/statistics/base.hu.i18n b/apps/statistics/base.hu.i18n index 26101bf85..ebe9bdc90 100644 --- a/apps/statistics/base.hu.i18n +++ b/apps/statistics/base.hu.i18n @@ -1,7 +1,7 @@ StatsApp = "Statisztika" StatsAppCapital = "STATISZTIKA" -HistogramTab = "Histogram" -BoxTab = "Box" +HistogramTab = "Hisztogram" +BoxTab = "Doboz" Values1 = "V1 értékek" Values2 = "V2 értékek" Values3 = "V3 értékek" @@ -14,7 +14,7 @@ Size = "Méret" Frequency = "Frekvencia" HistogramSet = "Hisztogram beállítások" RectangleWidth = "Tálca szélessége" -BarStart = "X start" +BarStart = "X kezdet" FirstQuartile = "Elsö kvartilis" Median = "Medián" ThirdQuartile = "Harmadik kvartilis" diff --git a/apps/statistics/histogram_controller.cpp b/apps/statistics/histogram_controller.cpp index 1f153855a..a3ad6decd 100644 --- a/apps/statistics/histogram_controller.cpp +++ b/apps/statistics/histogram_controller.cpp @@ -42,7 +42,7 @@ const char * HistogramController::title() { bool HistogramController::handleEvent(Ion::Events::Event event) { assert(selectedSeriesIndex() >= 0); - if (event == Ion::Events::OK) { + if (event == Ion::Events::OK || event == Ion::Events::EXE) { stackController()->push(histogramParameterController()); return true; } diff --git a/apps/toolbox.de.i18n b/apps/toolbox.de.i18n index 61999f5f7..c7acf774d 100644 --- a/apps/toolbox.de.i18n +++ b/apps/toolbox.de.i18n @@ -1,17 +1,17 @@ -Unit = "Units" -UnitTimeMenu = "Time" -UnitTimeSecondMenu = "Second" -UnitTimeSecond = "Second" -UnitTimeSecondMilli = "Millisecond" -UnitTimeSecondMicro = "Microsecond" -UnitTimeSecondNano = "Nanosecond" +Unit = "Einheiten" +UnitTimeMenu = "Zeit" +UnitTimeSecondMenu = "Sekunde" +UnitTimeSecond = "Sekunde" +UnitTimeSecondMilli = "Millisekunde" +UnitTimeSecondMicro = "Microsekunde" +UnitTimeSecondNano = "Nanosekunde" UnitTimeMinute = "Minute" -UnitTimeHour = "Hour" -UnitTimeDay = "Day" -UnitTimeWeek = "Week" -UnitTimeMonth = "Month" -UnitTimeYear = "Year" -UnitDistanceMenu = "Distance" +UnitTimeHour = "Stunde" +UnitTimeDay = "Tag" +UnitTimeWeek = "Woche" +UnitTimeMonth = "Monat" +UnitTimeYear = "Jahr" +UnitDistanceMenu = "Distanz" UnitDistanceMeterMenu = "Meter" UnitDistanceMeterKilo = "Kilometer" UnitDistanceMeter = "Meter" @@ -19,43 +19,43 @@ UnitDistanceMeterMilli = "Millimeter" UnitDistanceMeterMicro = "Micrometer" UnitDistanceMeterNano = "Nanometer" UnitDistanceMeterPico = "Picometer" -UnitDistanceAstronomicalUnit = "Astronomical unit" -UnitDistanceLightYear = "Light year" +UnitDistanceAstronomicalUnit = "Astronomische Einheit" +UnitDistanceLightYear = "Lichtjahr" UnitDistanceParsec = "Parsec" -UnitMassMenu = "Mass" -UnitMassGramKilo = "Kilogram" -UnitMassGram = "Gram" -UnitMassGramMilli = "Milligram" -UnitMassGramMicro = "Microgram" -UnitMassGramNano = "Nanogram" +UnitMassMenu = "Masse" +UnitMassGramKilo = "Kilogramm" +UnitMassGram = "Gramm" +UnitMassGramMilli = "Milligramm" +UnitMassGramMicro = "Microgramm" +UnitMassGramNano = "Nanogramm" UnitMassTonne = "Tonne" -UnitCurrentMenu = "Electric current" +UnitCurrentMenu = "Elektrischer Strom" UnitCurrentAmpere = "Ampere" UnitCurrentAmpereMilli = "Milliampere" UnitCurrentAmpereMicro = "Microampere" -UnitTemperatureMenu = "Temperature" +UnitTemperatureMenu = "Temperaturen" UnitTemperatureKelvin = "Kelvin" -UnitAmountMenu = "Amount of substance" -UnitAmountMole = "Mole" -UnitAmountMoleMilli = "Millimole" -UnitAmountMoleMicro = "Micromole" -UnitLuminousIntensityMenu = "Luminous intensity" +UnitAmountMenu = "Substanzmenge" +UnitAmountMole = "Mol" +UnitAmountMoleMilli = "Millimol" +UnitAmountMoleMicro = "Micromol" +UnitLuminousIntensityMenu = "Helligkeit" UnitLuminousIntensityCandela = "Candela" -UnitFrequencyMenu = "Frequency" +UnitFrequencyMenu = "Frequenz" UnitFrequencyHertzGiga = "Gigahertz" UnitFrequencyHertzMega = "Megahertz" UnitFrequencyHertzKilo = "Kilohertz" UnitFrequencyHertz = "Hertz" -UnitForceMenu = "Force" +UnitForceMenu = "Kraft" UnitForceNewtonKilo = "Kilonewton" UnitForceNewton = "Newton" UnitForceNewtonMilli = "Millinewton" -UnitPressureMenu = "Pressure" +UnitPressureMenu = "Druck" UnitPressurePascal = "Pascal" UnitPressurePascalHecto = "Hectopascal" UnitPressureBar = "Bar" UnitPressureAtm = "Atmosphere" -UnitEnergyMenu = "Energy" +UnitEnergyMenu = "Energie" UnitEnergyJouleMenu = "Joule" UnitEnergyJouleKilo = "Kilojoule" UnitEnergyJoule = "Joule" @@ -65,37 +65,37 @@ UnitEnergyElectronVoltMega = "Megaelectronvolt" UnitEnergyElectronVoltKilo = "Kiloelectronvolt" UnitEnergyElectronVolt = "Electronvolt" UnitEnergyElectronVoltMilli = "Millielectronvolt" -UnitPowerMenu = "Power" +UnitPowerMenu = "Leistung" UnitPowerWattGiga = "Gigawatt" UnitPowerWattMega = "Megawatt" UnitPowerWattKilo = "Kilowatt" UnitPowerWatt = "Watt" UnitPowerWattMilli = "Milliwatt" UnitPowerWattMicro = "Microwatt" -UnitElectricChargeMenu = "Electric charge" +UnitElectricChargeMenu = "Elektrische Ladung" UnitChargeCoulomb = "Coulomb" -UnitPotentialMenu = "Electric potential" +UnitPotentialMenu = "Elektrisches Potenzial" UnitPotentialVoltKilo = "Kilovolt" UnitPotentialVolt = "Volt" UnitPotentialVoltMilli = "Millivolt" UnitPotentialVoltMicro = "Microvolt" -UnitCapacitanceMenu = "Electrical capacitance" +UnitCapacitanceMenu = "Elektrische Kapazität" UnitCapacitanceFarad = "Farad" UnitCapacitanceFaradMilli = "Millifarad" UnitCapacitanceFaradMicro = "Microfarad" -UnitResistanceMenu = "Electrical resistance" +UnitResistanceMenu = "Elektrischer Widerstand" UnitResistanceOhmKilo = "Kiloohm" UnitResistanceOhm = "Ohm" -UnitConductanceMenu = "Electrical conductance" +UnitConductanceMenu = "Elektrische Leitfähigkeit" UnitConductanceSiemens = "Siemens" UnitConductanceSiemensMilli = "Millisiemens" -UnitMagneticFieldMenu = "Magnetic field" +UnitMagneticFieldMenu = "Magnetisches Feld" UnitMagneticFieldTesla = "Tesla" -InductanceMenu = "Electrical inductance" +InductanceMenu = "Elektrische Induktion" UnitInductanceHenry = "Henry" -UnitSurfaceMenu = "Area" -UnitSurfaceHectar = "Hectare" -UnitVolumeMenu = "Volume" +UnitSurfaceMenu = "Fläche" +UnitSurfaceHectar = "Hektar" +UnitVolumeMenu = "Volumen" UnitVolumeLiter = "Liter" UnitVolumeLiterDeci = "Deciliter" UnitVolumeLiterCenti = "Centiliter" @@ -409,9 +409,9 @@ NumberElementUue = "119 - Ununennium (Uue)" AlphaElementUue = "Uue - Ununennium (119)" NumberElementUbn = "120 - Unbinilium (Ubn)" AlphaElementUbn = "Ubn - Unbinilium (120)" -UnitOfMesurement = "Unit of mesurement" +UnitOfMesurement = "Messeinheit" SpeedOfLightTag = "Lichtgeschwindigkeit (m·s^-1)" -YearLightTag = "Ein Jahr Licht (km)" +YearLightTag = "Lichtjahr (km)" Thermodynamics = "Thermodynamik" BoltzmannTag = "Boltzmann Konstante (J·K^-1)" AvogadroTag = "Avogadro-Konstante (mol^-1)" @@ -427,4 +427,4 @@ NeutronMassTag = "Masse eines Neutrons (kg)" Gravitation = "Gravitation" ElementalChargeTag = "Elementarladung (C)" GAccelerationTag = "Beschleunigung (m·s^-2)" -GConstantTag = "Konstant (m^3·kg^-1·s^-2)" \ No newline at end of file +GConstantTag = "Konstant (m^3·kg^-1·s^-2)" diff --git a/apps/toolbox.hu.i18n b/apps/toolbox.hu.i18n index b6cdabab6..4c92616e9 100644 --- a/apps/toolbox.hu.i18n +++ b/apps/toolbox.hu.i18n @@ -12,33 +12,33 @@ UnitTimeWeek = "hét" UnitTimeMonth = "Hónap" UnitTimeYear = "Év" UnitDistanceMenu = "Távolság" -UnitDistanceMeterMenu = "Meter" +UnitDistanceMeterMenu = "Méter" UnitDistanceMeterKilo = "Kilométer" -UnitDistanceMeter = "Meter" +UnitDistanceMeter = "Méter" UnitDistanceMeterMilli = "Milliméter" UnitDistanceMeterMicro = "Mikrométer" UnitDistanceMeterNano = "Nanométer" UnitDistanceMeterPico = "Pikométer" UnitDistanceAstronomicalUnit = "Csillagászati ​​egység" -UnitDistanceLightYear = "Világos év" +UnitDistanceLightYear = "Fény év" UnitDistanceParsec = "Parsec" UnitMassMenu = "Tömeg" UnitMassGramKilo = "Kilogramm" UnitMassGram = "Gramm" -UnitMassGramMilli = "Milligram" -UnitMassGramMicro = "Mikrogram" -UnitMassGramNano = "Nanogram" +UnitMassGramMilli = "Milligramm" +UnitMassGramMicro = "Mikrogramm" +UnitMassGramNano = "Nanogramm" UnitMassTonne = "Tonna" -UnitCurrentMenu = "Elektromos áram" -UnitCurrentAmpere = "Ampere" -UnitCurrentAmpereMilli = "Milliampere" -UnitCurrentAmpereMicro = "Microampere" +UnitCurrentMenu = "Áram" +UnitCurrentAmpere = "Amper" +UnitCurrentAmpereMilli = "Milliamper" +UnitCurrentAmpereMicro = "Mikroamper" UnitTemperatureMenu = "Hömérséklet" UnitTemperatureKelvin = "Kelvin" UnitAmountMenu = "Az anyag mennyisége" -UnitAmountMole = "Mole" +UnitAmountMole = "Mól" UnitAmountMoleMilli = "Millimól" -UnitAmountMoleMicro = "Micromole" +UnitAmountMoleMicro = "Mikromól" UnitLuminousIntensityMenu = "Fényerö" UnitLuminousIntensityCandela = "Candela" UnitFrequencyMenu = "Frekvencia" diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 7d5943674..2d6d09e19 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -3,6 +3,7 @@ #include "shared/continuous_function.h" #include #include +#include #include #include #include @@ -236,7 +237,17 @@ Layout VariableBoxController::expressionLayoutForRecord(Storage::Record record, } assert(index >= m_firstMemoizedLayoutIndex && index < m_firstMemoizedLayoutIndex + k_maxNumberOfDisplayedRows); if (m_layouts[index-m_firstMemoizedLayoutIndex].isUninitialized()) { - m_layouts[index-m_firstMemoizedLayoutIndex] = GlobalContext::LayoutForRecord(record); + /* Creating the layout of a very long variable might throw a pool exception. + * We want to catch it and return a dummy layout instead, otherwise the user + * won't be able to open the variable box again, until she deletes the + * problematic variable -> and she has no help to remember its name, as she + * can't open the variable box. */ + Layout result; + Poincare::ExceptionCheckpoint ecp; + if (ExceptionRun(ecp)) { + result = GlobalContext::LayoutForRecord(record); + } + m_layouts[index-m_firstMemoizedLayoutIndex] = result; } return m_layouts[index-m_firstMemoizedLayoutIndex]; } diff --git a/build/config.mak b/build/config.mak index 3a2152112..7a5da904a 100644 --- a/build/config.mak +++ b/build/config.mak @@ -2,6 +2,7 @@ PLATFORM ?= device DEBUG ?= 0 +LEDS_CHOICE ?= 0 include build/defaults.mak include build/platform.$(PLATFORM).mak @@ -26,6 +27,7 @@ endif include build/toolchain.$(TOOLCHAIN).mak SFLAGS += -DDEBUG=$(DEBUG) +SFLAGS += -DLEDS_CHOICE=$(LEDS_CHOICE) ifdef USERNAME SFLAGS += -DUSERNAME="$(USERNAME)" endif diff --git a/build/scenario/Makefile b/build/scenario/Makefile index aafb398e8..64f65e8bf 100644 --- a/build/scenario/Makefile +++ b/build/scenario/Makefile @@ -1,11 +1,11 @@ .PHONY: scenario_logger scenario_logger: - $(Q) make -j8 PLATFORM=simulator clean && make -j8 DEBUG=1 ARCH=x86_64 PLATFORM=simulator epsilon.headless.bin + $(Q) $(MAKE) PLATFORM=simulator clean && $(MAKE) DEBUG=1 ARCH=x86_64 PLATFORM=simulator epsilon.headless.bin $(Q) cp output/debug/simulator/macos/x86_64/epsilon.headless.bin epsilon_scenario_logger.bin @echo "Run ./epsilon_scenario_logger.bin --logAfter 0 < scenario.esc to log a scenario" .PHONY: scenario_creator scenario_creator: - $(Q) make -j8 PLATFORM=simulator clean && make -j8 DEBUG=1 ESCHER_LOG_EVENTS_BINARY=1 PLATFORM=simulator + $(Q) $(MAKE) PLATFORM=simulator clean && $(MAKE) DEBUG=1 ESCHER_LOG_EVENTS_BINARY=1 PLATFORM=simulator $(Q) cp -R output/debug/simulator/macos/app/Payload/Epsilon.app epsilon_scenario_creator.app @echo "Run lldb epsilon_scenario_creator.app then process launch -o scenario.esc to create a scenario" diff --git a/build/targets.all.mak b/build/targets.all.mak new file mode 100644 index 000000000..989c4fb7b --- /dev/null +++ b/build/targets.all.mak @@ -0,0 +1,60 @@ +ANDROID_GRADLE_KEYSTORE ?= ~/.gradle/google-play-upload.keystore +ANDROID_GRADLE_PROPERTIES ?= ~/.gradle/gradle.properties +IOS_MOBILE_PROVISION ?= build/artifacts/NumWorks_Graphing_Calculator_Distribution.mobileprovision +EMCC ?= emcc + +define source_emsdk +source ~/emsdk/emsdk_env.sh > /dev/null +endef + +define file_check +@ if test ! -f $(1); \ + then \ + echo "Missing file: $(1)"; \ + exit 1; \ +fi +endef + +define command_check +@ if ! command -v $(1) > /dev/null; \ + then \ + echo "Missing command: $(1), did you forget to source?"; \ + exit 1; \ +fi +endef + +.PHONY: all_official +all_official: + $(call file_check,$(ANDROID_GRADLE_KEYSTORE)) + $(call file_check,$(ANDROID_GRADLE_PROPERTIES)) + $(call file_check,$(IOS_MOBILE_PROVISION)) + $(call command_check,$(EMCC)) + $(Q) rm -rf output/stable_release + $(Q) mkdir -p output/stable_release + $(Q) echo "BUILD_FIRMWARE DEVICE N0110" + $(Q) $(MAKE) clean + $(Q) $(MAKE) epsilon.official.onboarding.dfu + $(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu + $(Q) echo "BUILD_FIRMWARE DEVICE N0100" + $(Q) $(MAKE) MODEL=n0100 clean + $(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu + $(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP" + $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip + $(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS" + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js + $(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS" + $(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean + $(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js + $(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js + $(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID" + $(Q) $(MAKE) PLATFORM=simulator TARGET=android clean + $(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk + $(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk + $(Q) echo "BUILD_FIRMWARE SIMULATOR IOS" + $(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean + $(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa + $(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa diff --git a/build/targets.device.n0110.mak b/build/targets.device.n0110.mak index 3abc930e4..5b5078ac5 100644 --- a/build/targets.device.n0110.mak +++ b/build/targets.device.n0110.mak @@ -19,3 +19,29 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex sleep 2; \ fi $(Q) $(PYTHON) build/device/dfu.py -u $(word 1,$^) + +.PHONY: %.two_binaries +%.two_binaries: %.elf + @echo "Building an internal and an external binary for $<" + $(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).external.bin + $(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).internal.bin + @echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin" + $(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).external.bin + $(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).internal.bin + +.PHONY: binpack +binpack: + rm -rf output/binpack + mkdir -p output/binpack + $(MAKE) clean + $(MAKE) $(BUILD_DIR)/flasher.light.bin + cp $(BUILD_DIR)/flasher.light.bin output/binpack + $(MAKE) $(BUILD_DIR)/bench.flash.bin + $(MAKE) $(BUILD_DIR)/bench.ram.bin + cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack + $(MAKE) epsilon.official.onboarding.update.two_binaries + cp $(BUILD_DIR)/epsilon.official.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.official.onboarding.update.external.bin output/binpack + $(MAKE) clean + cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.official.onboarding.update.internal.bin epsilon.official.onboarding.update.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done + cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack + rm -rf output/binpack diff --git a/build/targets.mak b/build/targets.mak index 68ce3de04..ca7b9d97c 100644 --- a/build/targets.mak +++ b/build/targets.mak @@ -3,21 +3,15 @@ base_src = $(liba_src) $(kandinsky_src) $(escher_src) $(libaxx_src) $(poincare_s epsilon_src = $(base_src) $(ion_default_src) $(apps_default_src) epsilon_official_src = $(base_src) $(ion_default_src) $(apps_official_default_src) -epsilon_onboarding_src = $(base_src) $(ion_default_src) $(apps_onboarding_src) -epsilon_official_onboarding_src = $(base_src) $(ion_default_src) $(apps_official_onboarding_src) -epsilon_onboarding_update_src = $(base_src) $(ion_default_src) $(apps_onboarding_update_src) -epsilon_official_onboarding_update_src = $(base_src) $(ion_default_src) $(apps_official_onboarding_update_src) -epsilon_onboarding_beta_src = $(base_src) $(ion_default_src) $(apps_onboarding_beta_src) -epsilon_official_onboarding_beta_src = $(base_src) $(ion_default_src) $(apps_official_onboarding_beta_src) $(BUILD_DIR)/epsilon.$(EXE): $(call object_for,$(epsilon_src)) $(BUILD_DIR)/epsilon.official.$(EXE): $(call object_for,$(epsilon_official_src)) -$(BUILD_DIR)/epsilon.onboarding.$(EXE): $(call object_for,$(epsilon_onboarding_src)) -$(BUILD_DIR)/epsilon.official.onboarding.$(EXE): $(call object_for,$(epsilon_official_onboarding_src)) -$(BUILD_DIR)/epsilon.onboarding.update.$(EXE): $(call object_for,$(epsilon_onboarding_update_src)) -$(BUILD_DIR)/epsilon.official.onboarding.update.$(EXE): $(call object_for,$(epsilon_official_onboarding_update_src)) -$(BUILD_DIR)/epsilon.onboarding.beta.$(EXE): $(call object_for,$(epsilon_onboarding_beta_src)) -$(BUILD_DIR)/epsilon.official.onboarding.beta.$(EXE): $(call object_for,$(epsilon_official_onboarding_beta_src)) +$(BUILD_DIR)/epsilon.onboarding.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_src)) +$(BUILD_DIR)/epsilon.official.onboarding.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_onboarding_src)) +$(BUILD_DIR)/epsilon.onboarding.update.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_update_src)) +$(BUILD_DIR)/epsilon.official.onboarding.update.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_onboarding_update_src)) +$(BUILD_DIR)/epsilon.onboarding.beta.$(EXE): $(call object_for, $(base_src) $(ion_default_src) $(apps_onboarding_beta_src)) +$(BUILD_DIR)/epsilon.official.onboarding.beta.$(EXE): $(call object_for,$(base_src) $(ion_default_src) $(apps_official_onboarding_beta_src)) test_base_src = $(base_src) $(apps_tests_src) $(runner_src) $(tests_src) @@ -41,3 +35,5 @@ endef -include build/targets.$(PLATFORM).mak $(foreach extension,$(HANDY_TARGETS_EXTENSIONS),$(foreach executable,$(HANDY_TARGETS),$(eval $(call handy_target_rule,$(executable),$(extension))))) + +include build/targets.all.mak diff --git a/build/targets.simulator.web.mak b/build/targets.simulator.web.mak index 9011e2831..a1774a34a 100644 --- a/build/targets.simulator.web.mak +++ b/build/targets.simulator.web.mak @@ -1,17 +1,6 @@ -$(BUILD_DIR)/epsilon.js: EMSCRIPTEN_INIT_FILE = 1 +$(BUILD_DIR)/epsilon%packed.js: EMSCRIPTEN_INIT_FILE = 0 $(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0 $(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src)) - -.PHONY: workshop_python_emulator -workshop_python_emulator: - make PLATFORM=simulator TARGET=web clean_for_apps_selection - make PLATFORM=simulator TARGET=web EPSILON_APPS=code - make PLATFORM=simulator TARGET=web clean_for_apps_selection - -.PHONY: clean_for_apps_selection -clean_for_apps_selection: - @echo "CLEAN BEFORE CHANGING EPSILON_APPS" - $(Q) rm -f $(BUILD_DIR)/apps/apps_container_storage.o - $(Q) rm -f $(BUILD_DIR)/apps/i18n.* +$(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src)) diff --git a/build/toolchain.emscripten.mak b/build/toolchain.emscripten.mak index f8ec0beaa..fb6aafc39 100644 --- a/build/toolchain.emscripten.mak +++ b/build/toolchain.emscripten.mak @@ -132,7 +132,7 @@ EMFLAGS += -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 # Configure LDFLAGS EMSCRIPTEN_MODULARIZE ?= 1 LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"' -EMSCRIPTEN_INIT_FILE ?= 0 +EMSCRIPTEN_INIT_FILE ?= 1 LDFLAGS += --memory-init-file $(EMSCRIPTEN_INIT_FILE) SFLAGS += $(EMFLAGS) diff --git a/escher/include/escher/selectable_table_view.h b/escher/include/escher/selectable_table_view.h index 462041a37..f10a606be 100644 --- a/escher/include/escher/selectable_table_view.h +++ b/escher/include/escher/selectable_table_view.h @@ -32,10 +32,9 @@ public: bool selectCellAtLocation(int i, int j, bool setFirstResponder = true, bool withinTemporarySelection = false); HighlightCell * selectedCell(); protected: + void unhighlightSelectedCell(); SelectableTableViewDataSource * m_selectionDataSource; SelectableTableViewDelegate * m_delegate; -private: - void unhighlightSelectedCell(); }; #endif diff --git a/escher/include/escher/text_field.h b/escher/include/escher/text_field.h index 603c66b11..4f0a8928a 100644 --- a/escher/include/escher/text_field.h +++ b/escher/include/escher/text_field.h @@ -28,6 +28,8 @@ public: void reinitDraftTextBuffer() { m_contentView.reinitDraftTextBuffer(); } bool isEditing() const override; char * draftTextBuffer() const { return const_cast(m_contentView.editedText()); } + void setDraftTextBufferSize(size_t size) { m_contentView.setDraftTextBufferSize(size); } + size_t draftTextBufferSize() const { return m_contentView.draftTextBufferSize(); } size_t draftTextLength() const; void setText(const char * text); void setEditing(bool isEditing) override { m_contentView.setEditing(isEditing); } @@ -42,8 +44,19 @@ public: bool shouldFinishEditing(Ion::Events::Event event) override; const KDFont * font() const { return m_contentView.font(); } protected: + class ContentView : public TextInput::ContentView { public: + /* In some app (ie Calculation), text fields record expression results whose + * lengths can reach 70 (ie + * [[1.234567e-123*e^(1.234567e-123*i), 1.234567e-123*e^(1.234567e-123*i)]]). + * In order to be able to record those output text, k_maxBufferSize must be + * over 70. + * Furthermore, we want ot be able to write an adjacency matrix of size 10 + * so we need at least 2 brackets + 10 * (2 brackets + 10 digits + 9 commas) + * = 212 characters. */ + constexpr static int k_maxBufferSize = 220; + ContentView(char * textBuffer, size_t textBufferSize, size_t draftTextBufferSize, const KDFont * font, float horizontalAlignment, float verticalAlignment, KDColor textColor, KDColor backgroundColor); void setBackgroundColor(KDColor backgroundColor); KDColor backgroundColor() const { return m_backgroundColor; } @@ -56,7 +69,8 @@ protected: void setText(const char * text); void setEditing(bool isEditing); void reinitDraftTextBuffer(); - void setDraftTextBufferSize(size_t size) { m_draftTextBufferSize = size; } + void setDraftTextBufferSize(size_t size) { assert(size <= k_maxBufferSize); m_draftTextBufferSize = size; } + size_t draftTextBufferSize() const { return m_draftTextBufferSize; } /* If the text to be appended is too long to be added without overflowing the * buffer, nothing is done (not even adding few letters from the text to reach * the maximum buffer capacity) and false is returned. */ @@ -67,15 +81,6 @@ protected: void willModifyTextBuffer(); void didModifyTextBuffer(); size_t deleteSelection() override; - /* In some app (ie Calculation), text fields record expression results whose - * lengths can reach 70 (ie - * [[1.234567e-123*e^(1.234567e-123*i), 1.234567e-123*e^(1.234567e-123*i)]]). - * In order to be able to record those output text, k_maxBufferSize must be - * over 70. - * Furthermore, we want ot be able to write an adjacency matrix of size 10 - * so we need at least 2 brackets + 10 * (2 brackets + 10 digits + 9 commas) - * = 212 characters. */ - constexpr static int k_maxBufferSize = 220; private: void layoutSubviews(bool force = false) override; KDRect glyphFrameAtPosition(const char * buffer, const char * position) const override; @@ -87,8 +92,10 @@ protected: KDColor m_textColor; KDColor m_backgroundColor; }; + const ContentView * nonEditableContentView() const override { return &m_contentView; } ContentView m_contentView; + private: bool privateHandleEvent(Ion::Events::Event event); bool privateHandleMoveEvent(Ion::Events::Event event); diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 000e49808..0feeeefc8 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -196,7 +196,9 @@ bool LayoutField::ContentView::selectionIsEmpty() const { } void LayoutField::ContentView::deleteSelection() { - assert(!selectionIsEmpty()); + if (selectionIsEmpty()) { + return; + } Layout selectionParent = m_selectionStart.parent(); /* If the selected layout is the upmost layout, it must be an horizontal @@ -318,9 +320,7 @@ bool LayoutField::handleEventWithText(const char * text, bool indentation, bool * - the result of a copy-paste. */ // Delete the selected layouts if needed - if (!m_contentView.selectionIsEmpty()) { - deleteSelection(); - } + deleteSelection(); if (text[0] == 0) { // The text is empty @@ -493,8 +493,11 @@ bool LayoutField::privateHandleEvent(Ion::Events::Event event) { } return true; } - if (event == Ion::Events::Copy && isEditing()) { + if ((event == Ion::Events::Copy || event == Ion::Events::Cut) && isEditing()) { m_contentView.copySelection(context()); + if (event == Ion::Events::Cut) { + m_contentView.deleteSelection(); + } return true; } if (event == Ion::Events::Clear && isEditing()) { diff --git a/escher/src/scroll_view.cpp b/escher/src/scroll_view.cpp index 77a7a8855..332e9dfe2 100644 --- a/escher/src/scroll_view.cpp +++ b/escher/src/scroll_view.cpp @@ -81,8 +81,33 @@ void ScrollView::scrollToContentPoint(KDPoint p, bool allowOverscroll) { } void ScrollView::scrollToContentRect(KDRect rect, bool allowOverscroll) { - scrollToContentPoint(rect.topLeft(), allowOverscroll); - scrollToContentPoint(rect.bottomRight(), allowOverscroll); + KDPoint tl = rect.topLeft(); + KDPoint br = rect.bottomRight(); + KDRect visibleRect = visibleContentRect(); + /* We first check that we can display the whole rect. If we can't, we focus + * the croll to the closest part of the rect. */ + if (visibleRect.height() < rect.height()) { + // The visible rect is too small to display 'rect' + if (rect.top() >= visibleRect.top()) { + // We scroll to display the top part of rect + br = KDPoint(br.x(), rect.top() + visibleRect.height()); + } else { + // We scroll to display the bottom part of rect + tl = KDPoint(tl.x(), rect.bottom() - visibleRect.height()); + } + } + if (visibleRect.width() < rect.width()) { + // The visible rect is too small to display 'rect' + if (rect.left() >= visibleRect.left()) { + // We scroll to display the left part of rect + br = KDPoint(rect.left() + visibleRect.width(), br.y()); + } else { + // We scroll to display the right part of rect + tl = KDPoint(rect.right() - visibleRect.width(), tl.y()); + } + } + scrollToContentPoint(tl, allowOverscroll); + scrollToContentPoint(br, allowOverscroll); } KDRect ScrollView::visibleContentRect() { diff --git a/escher/src/text_area.cpp b/escher/src/text_area.cpp index e549b9dc5..837e341b7 100644 --- a/escher/src/text_area.cpp +++ b/escher/src/text_area.cpp @@ -116,14 +116,18 @@ bool TextArea::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::ShiftUp || event == Ion::Events::ShiftDown) { selectUpDown(event == Ion::Events::ShiftUp); return true; - } else if (event == Ion::Events::ShiftLeft) { + } else if (event == Ion::Events::AlphaLeft) { contentView()->moveCursorGeo(-INT_MAX/2, 0); - } else if (event == Ion::Events::ShiftRight) { + TextInput::scrollToCursor(); + } else if (event == Ion::Events::AlphaRight) { contentView()->moveCursorGeo(INT_MAX/2, 0); - } else if (event == Ion::Events::ShiftUp) { + TextInput::scrollToCursor(); + } else if (event == Ion::Events::AlphaUp) { contentView()->moveCursorGeo(0, -INT_MAX/2); - } else if (event == Ion::Events::ShiftDown) { + TextInput::scrollToCursor(); + } else if (event == Ion::Events::AlphaDown) { contentView()->moveCursorGeo(0, INT_MAX/2); + TextInput::scrollToCursor(); } else if (event == Ion::Events::Left) { if (contentView()->resetSelection()) { return true; diff --git a/escher/src/text_field.cpp b/escher/src/text_field.cpp index 6e8cd0303..b9043448d 100644 --- a/escher/src/text_field.cpp +++ b/escher/src/text_field.cpp @@ -78,6 +78,12 @@ void TextField::ContentView::setText(const char * text) { maxBufferSize = m_draftTextBufferSize; buffer = s_draftTextBuffer; } + if (textRealLength > maxBufferSize - 1) { + // The text was too long to be copied + // TODO Maybe add a warning for the user? + buffer[0] = 0; + return; + } int textLength = minInt(textRealLength, maxBufferSize - 1); // Copy the text strlcpy(buffer, text, maxBufferSize); diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index 1d4cee1b8..def5dfe56 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -182,6 +182,11 @@ constexpr Event ShiftThree = Event::ShiftKey(Keyboard::Key::Three); // Alpha +constexpr Event AlphaLeft = Event::AlphaKey(Keyboard::Key::Left); +constexpr Event AlphaRight = Event::AlphaKey(Keyboard::Key::Right); +constexpr Event AlphaUp = Event::AlphaKey(Keyboard::Key::Up); +constexpr Event AlphaDown = Event::AlphaKey(Keyboard::Key::Down); + constexpr Event Colon = Event::AlphaKey(Keyboard::Key::XNT); constexpr Event SemiColon = Event::AlphaKey(Keyboard::Key::Var); constexpr Event DoubleQuotes = Event::AlphaKey(Keyboard::Key::Toolbox); diff --git a/ion/include/ion/keyboard/layout_B2/layout_events.h b/ion/include/ion/keyboard/layout_B2/layout_events.h index f6c773b79..b67988907 100644 --- a/ion/include/ion/keyboard/layout_B2/layout_events.h +++ b/ion/include/ion/keyboard/layout_B2/layout_events.h @@ -30,7 +30,7 @@ static constexpr EventData s_dataForEvent[4*Event::PageSize] = { TL(), TL(), TL(), TL(), TL(), U(), TL(), TL(), TL(), TL(), U(), U(), // Alpha - U(), U(), U(), U(), U(), U(), + TL(), TL(), TL(), TL(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), T(":"), T(";"), T("\""), T("%"), T("a"), T("b"), T("c"), T("d"), T("e"), T("f"), @@ -75,7 +75,7 @@ static constexpr const char * s_nameForEvent[255] = { nullptr, nullptr, nullptr, "BrightnessPlus", "BrightnessMinus", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //Alpha, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "AlphaLeft", "AlphaUp", "AlphaDown", "AlphaRight", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "Colon", "SemiColon", "DoubleQuotes", "Percent", "LowerA", "LowerB", "LowerC", "LowerD", "LowerE", "LowerF", diff --git a/ion/include/ion/keyboard/layout_B3/layout_events.h b/ion/include/ion/keyboard/layout_B3/layout_events.h index 447881bfc..8124c3e9d 100644 --- a/ion/include/ion/keyboard/layout_B3/layout_events.h +++ b/ion/include/ion/keyboard/layout_B3/layout_events.h @@ -30,7 +30,7 @@ static constexpr EventData s_dataForEvent[4*Event::PageSize] = { TL(), TL(), TL(), TL(), TL(), U(), TL(), TL(), TL(), TL(), U(), U(), // Alpha - U(), U(), U(), U(), U(), U(), + TL(), TL(), TL(), TL(), U(), U(), U(), U(), U(), U(), U(), U(), U(), U(), T(":"), T(";"), T("\""), T("%"), T("a"), T("b"), T("c"), T("d"), T("e"), T("f"), @@ -75,7 +75,7 @@ static constexpr const char * s_nameForEvent[255] = { nullptr, nullptr, nullptr, "BrightnessPlus", "BrightnessMinus", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, //Alpha, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + "AlphaLeft", "AlphaUp", "AlphaDown", "AlphaRight", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "Colon", "SemiColon", "DoubleQuotes", "Percent", "LowerA", "LowerB", "LowerC", "LowerD", "LowerE", "LowerF", diff --git a/ion/src/device/shared/usb/stack/endpoint0.cpp b/ion/src/device/shared/usb/stack/endpoint0.cpp index 14478a086..4e1d4e980 100644 --- a/ion/src/device/shared/usb/stack/endpoint0.cpp +++ b/ion/src/device/shared/usb/stack/endpoint0.cpp @@ -259,7 +259,7 @@ void Endpoint0::clearForOutTransactions(uint16_t wLength) { setOutNAK(false); } -uint16_t Endpoint0::receiveSomeData() { +int Endpoint0::receiveSomeData() { // If it is the first chunk of data to be received, m_transferBufferLength is 0. uint16_t packetSize = MIN(k_maxPacketSize, m_request.wLength() - m_transferBufferLength); uint16_t sizeOfPacketRead = readPacket(m_largeBuffer + m_transferBufferLength, packetSize); diff --git a/ion/src/device/shared/usb/stack/endpoint0.h b/ion/src/device/shared/usb/stack/endpoint0.h index ca6809bfb..a0ef41686 100644 --- a/ion/src/device/shared/usb/stack/endpoint0.h +++ b/ion/src/device/shared/usb/stack/endpoint0.h @@ -57,7 +57,7 @@ public: void clearForOutTransactions(uint16_t wLength); private: - uint16_t receiveSomeData(); + int receiveSomeData(); uint16_t readPacket(void * buffer, uint16_t length); uint16_t writePacket(const void * buffer, uint16_t length); diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index 3b56131b5..0e6e70184 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -34,10 +34,15 @@ $(BUILD_DIR)/app/res/%.xml: ion/src/simulator/android/src/res/%.xml | $$(@D)/. .PHONY: force_remake -$(BUILD_DIR)/app/libs/%/libepsilon.so: force_remake $$(@D)/. - $(Q) echo "MAKE NDK_ABI=$*" - $(Q) $(MAKE) NDK_ABI=$* epsilon.so - $(Q) cp $(BUILD_DIR)/$*/epsilon.so $@ +define rule_for_libepsilon +$$(BUILD_DIR)/app/libs/%/lib$(1): force_remake $$$$(@D)/. + $(Q) echo "MAKE NDK_ABI=$$*" + $(Q) $$(MAKE) NDK_ABI=$$* $(1) + $(Q) cp $$(BUILD_DIR)/$$*/$(1) $$@ +endef + +$(eval $(call rule_for_libepsilon,epsilon.so)) +$(eval $(call rule_for_libepsilon,epsilon.official.so)) # If NDK_ABI is not defined, we will re-trigger a build for each avaialble ABI. # This is used to build APKs, which needs to embbed a binary for each ABI. @@ -46,22 +51,28 @@ ifndef NDK_ABI NDK_ABIS = armeabi-v7a arm64-v8a x86 x86_64 -epsilon_apk_deps = $(patsubst %,$(BUILD_DIR)/app/libs/%/libepsilon.so,$(NDK_ABIS)) -epsilon_apk_deps += $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*)) +epsilon_apk_deps = $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*)) epsilon_apk_deps += $(addprefix $(BUILD_DIR)/app/res/,mipmap/ic_launcher.png mipmap-v26/ic_launcher_foreground.png) -.PHONY: gradle_% -gradle_%: $(epsilon_apk_deps) +define rule_for_gradle +.PHONY: gradle_$1_$2 +gradle_$1_$2: $$(epsilon_apk_deps) $$(patsubst %,$$(BUILD_DIR)/app/libs/%/libepsilon$2so,$(NDK_ABIS)) @echo "GRADLE ion/src/simulator/android/build.gradle" - $(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle $* + $(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle $1 +endef + +$(eval $(call rule_for_gradle,assembleCodesigned,.)) +$(eval $(call rule_for_gradle,assembleRelease,.)) +$(eval $(call rule_for_gradle,assembleCodesigned,.official.)) +$(eval $(call rule_for_gradle,assembleRelease,.official.)) DEFAULT = epsilon.apk -.PHONY: epsilon.apk +.PHONY: epsilon%apk ifdef ANDROID_SIGNING_STORE_FILE -epsilon.apk: gradle_assembleCodesigned +epsilon%apk: gradle_assembleCodesigned_% else -epsilon.apk: gradle_assembleRelease +epsilon%apk: gradle_assembleRelease_% $(warning Building without code signing. Define ANDROID_SIGNING_STORE_FILE, ANDROID_SIGNING_STORE_PASSWORD, ANDROID_SIGNING_KEY_ALIAS and ANDROID_SIGNING_KEY_PASSWORD for a signed build.) endif diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index 876963d03..c19966b28 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -35,7 +35,7 @@ SIMULATOR_ICONSET = $(SIMULATOR_ASSETS_PATH)/AppIcon.appiconset include ion/src/simulator/shared/apple/Makefile -$(call simulator_app_plist,Info.plist): ion/src/simulator/ios/Info.plist $(call simulator_app_resource,Assets.car) +$(call simulator_app_plist,%,Info.plist): ion/src/simulator/ios/Info.plist $(call simulator_app_resource,%,Assets.car) $(call rule_label,PLUTIL) $(Q) cp $< $@ $(Q) plutil -insert "BuildMachineOSBuild" -string "$(IOS_BUILD_MACHINE_OS_BUILD)" $@ @@ -54,22 +54,23 @@ $(call simulator_app_plist,Info.plist): ion/src/simulator/ios/Info.plist $(call $(Q) plutil -replace CFBundleIcons -json `plutil -extract CFBundleIcons json -o - $(BUILD_DIR)/app/assets/partial.plist` $@ $(Q) plutil -replace CFBundleIcons~ipad -json `plutil -extract CFBundleIcons~ipad json -o - $(BUILD_DIR)/app/assets/partial.plist` $@ -$(call simulator_app_resource,launch.storyboardc): ion/src/simulator/ios/launch.storyboard | $$(@D)/. +$(call simulator_app_resource,%,launch.storyboardc): ion/src/simulator/ios/launch.storyboard | $$(@D)/. $(call rule_label,IBTOOL) $(Q) $(IBTOOL) --minimum-deployment-target $(APPLE_PLATFORM_MIN_VERSION) --compile $@ $^ ifdef IOS_PROVISIONNING_PROFILE -$(call simulator_app_resource,embedded.mobileprovision): $(IOS_PROVISIONNING_PROFILE) | $$(@D)/. +$(call simulator_app_resource,%,embedded.mobileprovision): $(IOS_PROVISIONNING_PROFILE) | $$(@D)/. $(call rule_label,COPY) $(Q) cp $^ $@ -$(BUILD_DIR)/app/entitlements.plist: $(call simulator_app_resource,embedded.mobileprovision) +$(BUILD_DIR)/app/entitlements.plist: $(IOS_PROVISIONNING_PROFILE) $(call rule_label,SCMS) $(Q) security cms -D -i $(IOS_PROVISIONNING_PROFILE) | plutil -extract Entitlements xml1 - -o $@ -SIMULATOR_APP_DEPS += $(BUILD_DIR)/app/entitlements.plist +simulator_app_deps += $(BUILD_DIR)/app/entitlements.plist +simulator_app_deps += $(call simulator_app_resource,$1,embedded.mobileprovision) else -$(call simulator_app_resource,embedded.mobileprovision): +$(call simulator_app_resource,%,embedded.mobileprovision): $(warning Building without a provisionning profile. Please define IOS_PROVISIONNING_PROFILE to point to the .mobileprovision file you want to use.) endif @@ -77,19 +78,19 @@ $(SIMULATOR_ICONSET)/Contents.json: ion/src/simulator/ios/icon_assets.json $(SIM $(call rule_label,COPY) $(Q) cp $< $@ -$(call simulator_app_resource,Assets.car): $(SIMULATOR_ICONSET)/Contents.json | $$(@D)/. +$(call simulator_app_resource,%,Assets.car): $(SIMULATOR_ICONSET)/Contents.json | $$(@D)/. $(call rule_label,ACTOOL) - $(Q) $(ACTOOL) --compile $(BUILD_DIR)/app/Payload/Epsilon.app --minimum-deployment-target $(APPLE_PLATFORM_MIN_VERSION) --platform $(APPLE_SDK) --app-icon AppIcon --output-partial-info-plist $(BUILD_DIR)/app/assets/partial.plist $(SIMULATOR_ASSETS_PATH) > /dev/null + $(Q) $(ACTOOL) --compile $(BUILD_DIR)/app/Payload/$*.app --minimum-deployment-target $(APPLE_PLATFORM_MIN_VERSION) --platform $(APPLE_SDK) --app-icon AppIcon --output-partial-info-plist $(BUILD_DIR)/app/assets/partial.plist $(SIMULATOR_ASSETS_PATH) > /dev/null -SIMULATOR_APP_DEPS += $(call simulator_app_resource,\ +simulator_app_deps += $(call simulator_app_resource,$(1), \ Assets.car \ launch.storyboardc \ ) -$(BUILD_DIR)/app/epsilon.ipa: $(SIMULATOR_APP_DEPS) +$(BUILD_DIR)/app/epsilon%ipa: $(subst ..,.,$(call simulator_app_deps,Epsilon$*)) ifdef IOS_PROVISIONNING_PROFILE $(call rule_label,SIGN) - $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "iPhone Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon.app + $(Q) codesign --force --entitlements $(BUILD_DIR)/app/entitlements.plist --sign "Apple Distribution: NumWorks" $(BUILD_DIR)/app/Payload/Epsilon.app endif $(call rule_label,ZIP) $(Q) cd $(dir $@) ; zip -qr9 $(notdir $@) Payload @@ -99,7 +100,7 @@ DEFAULT := $(BUILD_DIR)/app/epsilon.ipa endif ifeq ($(APPLE_PLATFORM),ios-simulator) -.PHONY: epsilon_run -epsilon_run: $(SIMULATOR_APP_DEPS) - xcrun simctl install booted $(BUILD_DIR)/app/Payload/Epsilon.app +.PHONY: epsilon%run +epsilon%run: $(subst _.,.,$(call simulator_app_deps,Epsilon$*)) + xcrun simctl install booted $(BUILD_DIR)/app/Payload/Epsilon$(subst _,.,$*)app endif diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index ae25b03f3..0f27650df 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -22,7 +22,7 @@ SIMULATOR_ICONSET = $(BUILD_DIR)/app/assets/app.iconset include ion/src/simulator/shared/apple/Makefile -$(call simulator_app_plist,Info.plist): ion/src/simulator/macos/Info.plist +$(call simulator_app_plist,%,Info.plist): ion/src/simulator/macos/Info.plist $(call rule_label,PLUTIL) $(Q) cp $< $@ $(Q) plutil -insert "LSMinimumSystemVersion" -string "$(MACOS_MIN_VERSION)" $@ @@ -31,12 +31,21 @@ $(call simulator_app_plist,Info.plist): ion/src/simulator/macos/Info.plist # macOS uses icns files -$(call simulator_app_resource,app.icns): $(SIMULATOR_ICONS) | $$(@D)/. +.SECONDARY: $(SIMULATOR_ICONS) | $$(@D)/. + +$(call simulator_app_resource,%,app.icns): $(SIMULATOR_ICONS) | $$(@D)/. $(call rule_label,ICNUTIL) $(Q) iconutil --convert icns --output $@ $(SIMULATOR_ICONSET) -SIMULATOR_APP_DEPS += $(call simulator_app_resource,app.icns) +simulator_app_deps += $(call simulator_app_resource,$(1),app.icns) + +simulator_app_deps_unofficial = $(call simulator_app_deps,Epsilon) +simulator_app_deps_official = $(call simulator_app_deps,Epsilon.official) + +.PHONY: Epsilon.app Epsilon.official.app +Epsilon.app: $(simulator_app_deps_unofficial) +Epsilon.official.app: $(simulator_app_deps_official) ifndef ARCH -DEFAULT := $(SIMULATOR_APP_DEPS) +DEFAULT := Epsilon.app endif diff --git a/ion/src/simulator/shared/apple/Makefile b/ion/src/simulator/shared/apple/Makefile index f5b1c77fe..22faf47d7 100644 --- a/ion/src/simulator/shared/apple/Makefile +++ b/ion/src/simulator/shared/apple/Makefile @@ -2,27 +2,37 @@ # The only things that have to be customized per platform are the icons and the # Info.plist. -SIMULATOR_APP_PATH = $(BUILD_DIR)/app/Payload/Epsilon.app +SIMULATOR_APP_PATH = $(BUILD_DIR)/app/Payload -simulator_app_binary = $(addprefix $(SIMULATOR_APP_PATH)/$(SIMULATOR_APP_BINARY_PATH),$(1)) -simulator_app_resource = $(addprefix $(SIMULATOR_APP_PATH)/$(SIMULATOR_APP_RESOURCE_PATH),$(1)) -simulator_app_plist = $(addprefix $(SIMULATOR_APP_PATH)/$(SIMULATOR_APP_PLIST_PATH),$(1)) +simulator_app_binary = $(addprefix $(SIMULATOR_APP_PATH)/$(1).app/$(SIMULATOR_APP_BINARY_PATH),$(2)) +simulator_app_resource = $(addprefix $(SIMULATOR_APP_PATH)/$(1).app/$(SIMULATOR_APP_RESOURCE_PATH),$(2)) +simulator_app_plist = $(addprefix $(SIMULATOR_APP_PATH)/$(1).app/$(SIMULATOR_APP_PLIST_PATH),$(2)) # Epsilon binary .PHONY: force_remake -$(BUILD_DIR)/%/epsilon.bin: force_remake - $(Q) echo "MAKE ARCH=$*" - $(Q) $(MAKE) ARCH=$* +define rule_for_epsilon +$$(BUILD_DIR)/%/$(1): force_remake + $(Q) echo "MAKE ARCH=$$*" + $(Q) $$(MAKE) ARCH=$$* $(1) +endef -$(call simulator_app_binary,Epsilon): $(patsubst %,$(BUILD_DIR)/%/epsilon.bin,$(ARCHS)) | $$(@D)/. - $(call rule_label,LIPO) - $(Q) $(LIPO) -create $^ -output $@ +$(eval $(call rule_for_epsilon,epsilon.bin)) +$(eval $(call rule_for_epsilon,epsilon.official.bin)) + +define rule_for_lipo +$$(call simulator_app_binary,$1,Epsilon): $$(patsubst %,$(BUILD_DIR)/%/$2.bin,$$(ARCHS)) | $$$$(@D)/. + $$(call rule_label,LIPO) + $(Q) $$(LIPO) -create $$^ -output $$@ +endef + +$(eval $(call rule_for_lipo,Epsilon,epsilon)) +$(eval $(call rule_for_lipo,Epsilon.official,epsilon.official)) # Background image -$(call simulator_app_resource,background.jpg): ion/src/simulator/assets/background.jpg | $$(@D)/. +$(call simulator_app_resource,%,background.jpg): ion/src/simulator/assets/background.jpg | $$(@D)/. $(call rule_label,COPY) $(Q) cp $^ $@ @@ -44,6 +54,6 @@ $(addprefix $(SIMULATOR_ICONSET)/,icon_%.png): ion/src/simulator/assets/logo.svg # Export simulator app dependencies -SIMULATOR_APP_DEPS += $(call simulator_app_binary,Epsilon) -SIMULATOR_APP_DEPS += $(call simulator_app_plist,Info.plist) -SIMULATOR_APP_DEPS += $(call simulator_app_resource,background.jpg) +simulator_app_deps += $(call simulator_app_binary,$(1),Epsilon) +simulator_app_deps += $(call simulator_app_plist,$(1),Info.plist) +simulator_app_deps += $(call simulator_app_resource,$(1),background.jpg) diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index ada734ed7..b31be6f0b 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -26,7 +26,7 @@ endif DEFAULT = $(BUILD_DIR)/simulator.zip -$(BUILD_DIR)/simulator.zip: $(BUILD_DIR)/epsilon.packed.js +$(BUILD_DIR)/simulator%zip: $(BUILD_DIR)/epsilon%packed.js @rm -rf $(basename $@) @mkdir -p $(basename $@) @cp $^ $(basename $@)/epsilon.js diff --git a/ion/src/simulator/web/simulator.html b/ion/src/simulator/web/simulator.html index 6a686c8de..f5514dacf 100644 --- a/ion/src/simulator/web/simulator.html +++ b/ion/src/simulator/web/simulator.html @@ -38,8 +38,8 @@ body.fullscreen .col-calculator { a.action { display: block; - width: 3%; - padding: 1% 2%; + width: 4%; + padding: 1.5% 3%; border: 1px solid black; border-radius: 100px; cursor: pointer; @@ -55,20 +55,6 @@ a.action svg { display: block; } -.actions { - position: absolute; - bottom: 2%; - text-align: left; - left: 0; - right: 0; - margin-left: 20px; /* Center the buttons - compensate the 10px margin below */ -} - -.actions a { - display: inline-block; - margin-right: 10px; -} - .calculator { margin: 0 auto; position: relative; @@ -76,7 +62,7 @@ a.action svg { text-align: left; } .calculator > img { /* Rely on the img content to set the dimensions */ - max-height: 100vh; + max-height: 92.0vh; max-width: 100%; display: block; } .calculator .screen { @@ -86,6 +72,18 @@ a.action svg { width: 67.5%; height: 26.3%; border: 0 none; } + .calculator .actions { + position: absolute; + top: 94.0vh; + text-align: center; + left: 0; + right: 0; + margin-left: 20px; /* Center the buttons - compensate the 10px margin below */ + } + .calculator .actions a { + display: inline-block; + margin-right: 10px; + } .calculator .keyboard { position: absolute; top: 38.5%; @@ -110,7 +108,7 @@ a.action svg { position: absolute; } .calculator .keyboard .nav .left { top: 36%; - left: 3%; + left: 2%; width: 15%; height: 28%; } .calculator .keyboard .nav .right { @@ -120,17 +118,17 @@ a.action svg { height: 28%; } .calculator .keyboard .nav .top { top: 7%; - left: 12.5%; + left: 12%; width: 10%; height: 40%; } .calculator .keyboard .nav .bottom { top: 53%; - left: 12.5%; + left: 12%; width: 10%; height: 40%; } .calculator .keyboard .nav .home { - top: 12%; - left: 42%; + top: 15%; + left: 41%; width: 16%; height: 33%; } .calculator .keyboard .nav .power { @@ -139,19 +137,19 @@ a.action svg { width: 16%; height: 33%; } .calculator .keyboard .nav .ok { - top: 30%; - left: 68%; + top: 31%; + left: 67%; width: 13%; height: 38%; } .calculator .keyboard .nav .back { - top: 30%; + top: 31%; left: 84%; width: 13%; height: 38%; } .calculator .keyboard .functions { position: absolute; top: 26.75%; - left: 1%; + left: 0.5%; width: 98%; } .calculator .keyboard .functions span { margin: 1.7% 1%; @@ -160,14 +158,14 @@ a.action svg { padding-top: 10%; } .calculator .keyboard .digits { position: absolute; - top: 57%; + top: 56.5%; left: 0.5%; width: 98%; } .calculator .keyboard .digits span { margin: 1.8% 2%; width: 16%; height: 0; - padding-top: 11%; } + padding-top: 11.3%; } @@ -230,20 +228,19 @@ a.action svg { +
- -