Merge branch 'omega-hotfix' into omega-master

This commit is contained in:
Quentin Guidée
2020-02-29 19:52:54 +01:00
109 changed files with 1111 additions and 771 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/output/
/build/artifacts/
build/device/**/*.pyc
epsilon.elf
.vscode

View File

@@ -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

View File

@@ -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

View File

@@ -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];
}

View File

@@ -13,6 +13,7 @@ public:
ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController);
// Responder
void viewDidDisappear() override;
void didEnterResponderChain(Responder * previousFirstResponder) override;
//ListViewDataSource

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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(); }

View File

@@ -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"

View File

@@ -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"

View File

@@ -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. */

View File

@@ -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);

View File

@@ -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<HistoryViewCell *>(m_selectableTableView.selectedCell());
*previousCell = static_cast<HistoryViewCell *>(m_selectableTableView.cellAtLocation(previousSelectedCellX, previousSelectedCellY));

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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<char *>(UTF8Helper::CodePointSearch(value, ':'));
if (*separator == 0) {
return;

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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'"

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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),

View File

@@ -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 <apps/i18n.h>
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);

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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<Shared::CursorView *>(&m_roundCursorView) : static_cast<Shared::CursorView *>(&m_crossCursorView);
// Escape if the cursor view stays the same
if (m_view.cursorView() == nextCursorView) {
return;
}

View File

@@ -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;

View File

@@ -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 \

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -5,6 +5,7 @@
#include <ion/backlight.h>
using namespace Poincare;
using namespace Shared;
namespace Settings {

View File

@@ -2,7 +2,7 @@
#define SETTINGS_MAIN_CONTROLLER_H
#include <escher.h>
#include "settings_message_tree.h"
#include <apps/shared/settings_message_tree.h>
#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;

View File

@@ -2,6 +2,8 @@
#include "../exam_mode_configuration.h"
#include <apps/i18n.h>
using namespace Shared;
namespace Settings {
constexpr SettingsMessageTree s_modelMenu[] =

View File

@@ -2,6 +2,8 @@
#include "../exam_mode_configuration.h"
#include <apps/i18n.h>
using namespace Shared;
namespace Settings {
constexpr SettingsMessageTree s_modelMenu[] =

View File

@@ -4,6 +4,8 @@
namespace Settings {
using namespace Shared;
constexpr SettingsMessageTree s_modelMenu[] =
{SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren),
SettingsMessageTree(I18n::Message::Brightness),

View File

@@ -1,9 +0,0 @@
#include "settings_message_tree.h"
namespace Settings {
const MessageTree * SettingsMessageTree::children(int index) const {
return &m_children[index];
}
}

View File

@@ -4,7 +4,7 @@ namespace Settings {
void AboutController::viewWillAppear() {
GenericSubController::viewWillAppear();
m_view.setMessages(nullptr, 0);
//m_view.setMessages(nullptr, 0);
}
}

View File

@@ -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();

View File

@@ -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;
};

View File

@@ -2,7 +2,7 @@
#define SETTINGS_GENERIC_SUB_CONTROLLER_H
#include <escher.h>
#include "../settings_message_tree.h"
#include <apps/shared/settings_message_tree.h>
namespace Settings {

View File

@@ -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();
}

View File

@@ -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 "

View File

@@ -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 "

View File

@@ -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 "

View File

@@ -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 "

View File

@@ -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 "

View File

@@ -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 "

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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 <escher/message_tree.h>
#include <apps/i18n.h>
namespace Settings {
namespace Shared {
class SettingsMessageTree : public MessageTree {
public:
constexpr SettingsMessageTree(I18n::Message label = I18n::Message::Default) :
MessageTree(label, 0),
m_children(nullptr)
{
};
{}
template <int N>
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;
};

View File

@@ -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();

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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)"
GConstantTag = "Konstant (m^3·kg^-1·s^-2)"

View File

@@ -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"

View File

@@ -3,6 +3,7 @@
#include "shared/continuous_function.h"
#include <escher/metric.h>
#include <ion/unicode/utf8_decoder.h>
#include <poincare/exception_checkpoint.h>
#include <poincare/layout_helper.h>
#include <poincare/matrix_layout.h>
#include <poincare/preferences.h>
@@ -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];
}

View File

@@ -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

View File

@@ -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"

60
build/targets.all.mak Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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)

View File

@@ -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

View File

@@ -28,6 +28,8 @@ public:
void reinitDraftTextBuffer() { m_contentView.reinitDraftTextBuffer(); }
bool isEditing() const override;
char * draftTextBuffer() const { return const_cast<char *>(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);

View File

@@ -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()) {

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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",

View File

@@ -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",

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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%; }
</style>
</head>
<body>
@@ -230,20 +228,19 @@ a.action svg {
<span data-key="52"></span>
</div>
</div>
<div class="actions">
<a id="action-fullscreen" class="action">
<svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g fill="#434343"><path d="M5.075,6.95 L6.918,5.088 L3.938,2.062 L5.955,0.018 L0.052,0.018 L0.052,6.004 L2.098,3.928 L5.075,6.95 Z" class="si-glyph-fill"></path><path d="M16.0034788,9.916 L13.832,12.013 L10.799,8.96 L8.918,10.841 L11.957,13.897 L9.961,15.9813842 L16.0034788,15.9813842 L16.0034788,9.916 Z"></path></g></g></svg>
</a>
<a id="action-screenshot" class="action">
<svg viewBox="0 1.5 17 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>871</title><defs></defs><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g transform="translate(0.995000, 2.980000)" fill="#434343"><circle cx="7.958" cy="6.958" r="2.958" class="si-glyph-fill"></circle><path d="M14.666,2.042 L10.953,2.042 L9.937,0.031 L6,0.031 L5,2.042 L1.333,2.042 C0.597,2.042 0,2.639 0,3.375 L0,10.625 C0,11.361 0.597,11.959 1.333,11.959 L14.666,11.959 C15.402,11.959 16,11.361 16,10.625 L16,3.375 C16,2.639 15.402,2.042 14.666,2.042 L14.666,2.042 Z M6.953,0.969 L9.047,0.969 L9.047,2.031 L6.953,2.031 L6.953,0.969 L6.953,0.969 Z M8.002,11.033 C5.764,11.033 3.947,9.221 3.947,6.985 C3.947,4.749 5.763,2.937 8.002,2.937 C10.242,2.937 12.057,4.749 12.057,6.985 C12.057,9.221 10.242,11.033 8.002,11.033 L8.002,11.033 Z M14,4.031 L11.953,4.031 L11.953,2.969 L14,2.969 L14,4.031 L14,4.031 Z" class="si-glyph-fill"></path></g></g></svg>
</a>
</div>
</div>
</div>
<div class="col-fullscreen">
<canvas class="screen-magnified" width="320" height="240"></canvas>
</div>
<div class="actions">
<a id="action-fullscreen" class="action">
<svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g fill="#434343"><path d="M5.075,6.95 L6.918,5.088 L3.938,2.062 L5.955,0.018 L0.052,0.018 L0.052,6.004 L2.098,3.928 L5.075,6.95 Z" class="si-glyph-fill"></path><path d="M16.0034788,9.916 L13.832,12.013 L10.799,8.96 L8.918,10.841 L11.957,13.897 L9.961,15.9813842 L16.0034788,15.9813842 L16.0034788,9.916 Z"></path></g></g></svg>
</a>
<a id="action-screenshot" class="action">
<svg viewBox="0 1.5 17 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>871</title><defs></defs><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g transform="translate(0.995000, 2.980000)" fill="#434343"><circle cx="7.958" cy="6.958" r="2.958" class="si-glyph-fill"></circle><path d="M14.666,2.042 L10.953,2.042 L9.937,0.031 L6,0.031 L5,2.042 L1.333,2.042 C0.597,2.042 0,2.639 0,3.375 L0,10.625 C0,11.361 0.597,11.959 1.333,11.959 L14.666,11.959 C15.402,11.959 16,11.361 16,10.625 L16,3.375 C16,2.639 15.402,2.042 14.666,2.042 L14.666,2.042 Z M6.953,0.969 L9.047,0.969 L9.047,2.031 L6.953,2.031 L6.953,0.969 L6.953,0.969 Z M8.002,11.033 C5.764,11.033 3.947,9.221 3.947,6.985 C3.947,4.749 5.763,2.937 8.002,2.937 C10.242,2.937 12.057,4.749 12.057,6.985 C12.057,9.221 10.242,11.033 8.002,11.033 L8.002,11.033 Z M14,4.031 L11.953,4.031 L11.953,2.969 L14,2.969 L14,4.031 L14,4.031 Z" class="si-glyph-fill"></path></g></g></svg>
</a>
</div>
</div>
<script src="epsilon.js"></script>
<script>

View File

@@ -413,10 +413,8 @@ private:
constexpr static double k_maxFloat = 1e100;
Coordinate2D<double> nextMinimumOfExpression(const char * symbol, double start, double step, double max, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression(), bool lookForRootMinimum = false) const;
void bracketMinimum(const char * symbol, double start, double step, double max, double result[3], Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression()) const;
Coordinate2D<double> brentMinimum(const char * symbol, double ax, double bx, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression()) const;
double nextIntersectionWithExpression(const char * symbol, double start, double step, double max, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const;
void bracketRoot(const char * symbol, double start, double step, double max, double result[2], Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const;
double brentRoot(const char * symbol, double ax, double bx, double precision, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const;
};
}

View File

@@ -128,7 +128,7 @@ protected:
void setIdentifierAndRetain(uint16_t newId);
void setTo(const TreeHandle & tr);
static bool hasNode(uint16_t identifier) { return identifier < TreeNode::NoNodeIdentifier; }
static bool hasNode(uint16_t identifier) { return TreeNode::IsValidIdentifier(identifier); }
/* Hierarchy operations */
// Add

View File

@@ -172,6 +172,8 @@ public:
void log(std::ostream & stream, bool recursive = true);
#endif
static bool IsValidIdentifier(uint16_t id) { return id < NoNodeIdentifier; }
protected:
TreeNode() :
m_identifier(NoNodeIdentifier),

View File

@@ -27,7 +27,7 @@ public:
// Node
TreeNode * node(uint16_t identifier) const {
assert(identifier >= 0 && identifier < MaxNumberOfNodes);
assert(TreeNode::IsValidIdentifier(identifier) && identifier < MaxNumberOfNodes);
if (m_nodeForIdentifierOffset[identifier] != UINT16_MAX) {
return const_cast<TreeNode *>(reinterpret_cast<const TreeNode *>(m_alignedBuffer + m_nodeForIdentifierOffset[identifier]));
}
@@ -125,7 +125,7 @@ private:
}
}
void push(uint16_t i) {
assert(m_currentIndex >= 0 && m_currentIndex < MaxNumberOfNodes);
assert(TreeNode::IsValidIdentifier(m_currentIndex) && m_currentIndex < MaxNumberOfNodes);
m_availableIdentifiers[m_currentIndex++] = i;
}
uint16_t pop() {

Some files were not shown because too many files have changed in this diff Show More