[Update] Epsilon 14

This commit is contained in:
Joachim LF
2020-07-09 15:33:21 +02:00
committed by Quentin Guidée
320 changed files with 6893 additions and 2610 deletions

View File

@@ -1,3 +1,4 @@
include apps/helpers.mk
include apps/shared/Makefile
include apps/home/Makefile
include apps/on_boarding/Makefile
@@ -11,6 +12,7 @@ apps =
$(foreach i,${apps_list},${eval include apps/$(i)/Makefile})
apps_src += $(addprefix apps/,\
alternate_empty_nested_menu_controller.cpp \
apps_container.cpp \
apps_container_launch_default.cpp:-onboarding \
apps_container_launch_on_boarding.cpp:+onboarding \
@@ -32,11 +34,11 @@ apps_src += $(addprefix apps/,\
lock_view.cpp \
main.cpp \
math_toolbox.cpp \
math_variable_box_controller.cpp \
math_variable_box_empty_controller.cpp \
shift_alpha_lock_view.cpp \
suspend_timer.cpp \
title_bar_view.cpp \
variable_box_controller.cpp \
variable_box_empty_controller.cpp \
)
tests_src += apps/exam_mode_configuration_non_official.cpp
@@ -60,27 +62,10 @@ i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_
ifeq ($(EPSILON_GETOPT),1)
i18n_files += $(addprefix apps/language_,$(addsuffix _iso6391.universal.i18n, $(EPSILON_I18N)))
endif
i18n_files += $(addprefix apps/,\
shared.de.i18n\
shared.en.i18n\
shared.es.i18n\
shared.fr.i18n\
shared.pt.i18n\
shared.hu.i18n\
shared.universal.i18n\
toolbox.de.i18n\
toolbox.en.i18n\
toolbox.es.i18n\
toolbox.fr.i18n\
toolbox.pt.i18n\
toolbox.hu.i18n\
variables.de.i18n\
variables.en.i18n\
variables.es.i18n\
variables.fr.i18n\
variables.pt.i18n\
variables.hu.i18n\
)
i18n_files += $(call i18n_with_universal_for,shared)
i18n_files += $(call i18n_without_universal_for,toolbox)
i18n_files += $(call i18n_without_universal_for,variables)
$(eval $(call rule_for, \
I18N, \
@@ -104,6 +89,7 @@ $(call object_for,$(apps_src) $(tests_src)): $(BUILD_DIR)/python/port/genhdr/qst
apps_tests_src = $(app_calculation_test_src) $(app_code_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_settings_test_src) $(app_solver_test_src)
apps_tests_src += $(addprefix apps/,\
alternate_empty_nested_menu_controller.cpp \
global_preferences.cpp \
)

View File

@@ -0,0 +1,18 @@
#include "alternate_empty_nested_menu_controller.h"
void AlternateEmptyNestedMenuController::viewDidDisappear() {
if (isDisplayingEmptyController()) {
pop();
}
NestedMenuController::viewDidDisappear();
}
bool AlternateEmptyNestedMenuController::displayEmptyControllerIfNeeded() {
assert(!isDisplayingEmptyController());
// If the content is empty, we push an empty controller.
if (numberOfRows() == 0) {
push(emptyViewController());
return true;
}
return false;
}

View File

@@ -0,0 +1,19 @@
#ifndef APPS_ALTERNATE_EMPTY_NESTED_MENU_CONTROLLER_H
#define APPS_ALTERNATE_EMPTY_NESTED_MENU_CONTROLLER_H
#include <escher/nested_menu_controller.h>
class AlternateEmptyNestedMenuController : public NestedMenuController {
public:
AlternateEmptyNestedMenuController(I18n::Message title) :
NestedMenuController(nullptr, title)
{}
// View Controller
void viewDidDisappear() override;
protected:
virtual ViewController * emptyViewController() = 0;
bool isDisplayingEmptyController() { return StackViewController::depth() == 2; }
bool displayEmptyControllerIfNeeded();
};
#endif

View File

@@ -92,7 +92,7 @@ MathToolbox * AppsContainer::mathToolbox() {
return &m_mathToolbox;
}
VariableBoxController * AppsContainer::variableBoxController() {
MathVariableBoxController * AppsContainer::variableBoxController() {
return &m_variableBoxController;
}

View File

@@ -8,7 +8,7 @@
#include "apps_window.h"
#include "empty_battery_window.h"
#include "math_toolbox.h"
#include "variable_box_controller.h"
#include "math_variable_box_controller.h"
#include "exam_pop_up_controller.h"
#include "exam_pop_up_controller_delegate.h"
#include "battery_timer.h"
@@ -34,7 +34,7 @@ public:
void reset();
Poincare::Context * globalContext();
MathToolbox * mathToolbox();
VariableBoxController * variableBoxController();
MathVariableBoxController * variableBoxController();
void suspend(bool checkIfOnOffKeyReleased = false);
bool dispatchEvent(Ion::Events::Event event) override;
bool switchTo(App::Snapshot * snapshot) override;
@@ -70,7 +70,7 @@ private:
EmptyBatteryWindow m_emptyBatteryWindow;
Shared::GlobalContext m_globalContext;
MathToolbox m_mathToolbox;
VariableBoxController m_variableBoxController;
MathVariableBoxController m_variableBoxController;
ExamPopUpController m_examPopUpController;
OnBoarding::PopUpController m_promptController;
BatteryTimer m_batteryTimer;

View File

@@ -21,6 +21,7 @@ app_calculation_src = $(addprefix apps/calculation/,\
additional_outputs/trigonometry_graph_cell.cpp \
additional_outputs/trigonometry_list_controller.cpp \
additional_outputs/trigonometry_model.cpp \
additional_outputs/unit_list_controller.cpp \
app.cpp \
edit_expression_controller.cpp \
expression_field.cpp \
@@ -32,14 +33,7 @@ app_calculation_src = $(addprefix apps/calculation/,\
app_calculation_src += $(app_calculation_test_src)
apps_src += $(app_calculation_src)
i18n_files += $(addprefix apps/calculation/,\
base.de.i18n\
base.en.i18n\
base.es.i18n\
base.fr.i18n\
base.pt.i18n\
base.hu.i18n\
)
i18n_files += $(call i18n_without_universal_for,calculation/base)
tests_src += $(addprefix apps/calculation/test/,\
calculation_store.cpp\

View File

@@ -10,7 +10,7 @@ namespace Calculation {
class ComplexListController : public IllustratedListController {
public:
ComplexListController(EditExpressionController * editExpressionController) :
IllustratedListController(nullptr, editExpressionController),
IllustratedListController(editExpressionController),
m_complexGraphCell(&m_model) {}
// ViewController

View File

@@ -17,10 +17,10 @@ float ComplexModel::rangeBound(float direction, bool horizontal) const {
maxFactor = k_maxHorizontalMarginFactor;
value = real();
}
if (std::isnan(value) || std::isinf(value) || value == 0.0f) {
return direction*maxFactor;
}
float factor = direction*value >= 0.0f ? maxFactor : minFactor;
if (std::isnan(value) || std::isinf(value) || value == 0.0f) {
return direction*factor;
}
return factor*value;
}

View File

@@ -2,6 +2,7 @@
#define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_MODEL_H
#include "../../shared/curve_view_range.h"
#include "illustrated_list_controller.h"
#include <complex>
namespace Calculation {
@@ -17,11 +18,53 @@ public:
void setComplex(std::complex<float> c) { *this = ComplexModel(c); }
static constexpr float k_minVerticalMarginFactor = -0.5f;
static constexpr float k_maxVerticalMarginFactor = 1.2f;
/* The range is computed from these criteria:
* - The real part is centered horizontally
* - Both left and right margins are equal to the real length
* - The imaginary part is the same length as the real part
* - The remaining vertical margin are splitted as one third at the top, 2
* thirds at the bottom
*
* | | 1/3 * vertical_margin
* +----------+
* | / | |
* | / | | Imaginary
* | / | |
* | / | |
* ----------+----------+----------
* |
* | 2/3 * vertical_margin
* -----------
* Real
*
*/
// Horizontal range
static constexpr float k_minHorizontalMarginFactor = -1.0f;
static constexpr float k_maxHorizontalMarginFactor = 2.0f;
// Vertical range
static constexpr KDCoordinate k_width = Ion::Display::Width - Metric::PopUpRightMargin - Metric::PopUpLeftMargin;
static constexpr KDCoordinate k_height = IllustratedListController::k_illustrationHeight;
static constexpr KDCoordinate k_unit = k_width/3;
/*
* VerticalMaring = k_height - k_unit
*
* Values | Coordinates
* --------+----------------------------------
* imag | k_unit
* Ymax | k_unit + (1/3)*VerticalMargin
* Ymin | -(2/3)*VerticalMargin
*
* Thus:
* Ymin = -(2/3)*k_verticalMargin*imag/k_unit
* = -(2/3)*(k_height/k_unit - 1)*imag
* = 2/3*(1 - k_height/k_unit)*imag
* Ymax = (k_unit + (1/3)*VerticalMargin)*imag/k_unit
* = (1 + (1/3)*(k_height/k_unit - 1))*imag
* = 1/3*(2 + k_height/k_unit)*imag
*
* */
static constexpr float k_minVerticalMarginFactor = 2.0f/3.0f*(1.0f - (float)k_height/(float)k_unit);
static constexpr float k_maxVerticalMarginFactor = 1.0f/3.0f*(2.0f + (float)k_height/(float)k_unit);
private:
float rangeBound(float direction, bool horizontal) const;

View File

@@ -7,8 +7,8 @@ namespace Calculation {
/* Expressions list controller */
ExpressionsListController::ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController) :
ListController(parentResponder, editExpressionController),
ExpressionsListController::ExpressionsListController(EditExpressionController * editExpressionController) :
ListController(editExpressionController),
m_cells{}
{
for (int i = 0; i < k_maxNumberOfCells; i++) {
@@ -38,9 +38,7 @@ HighlightCell * ExpressionsListController::reusableCell(int index, int type) {
KDCoordinate ExpressionsListController::rowHeight(int j) {
Layout l = layoutAtIndex(j);
if (l.isUninitialized()) {
return 0;
}
assert(!l.isUninitialized());
return l.layoutSize().height() + 2 * Metric::CommonSmallMargin + Metric::CellSeparatorThickness;
}

View File

@@ -10,7 +10,7 @@ namespace Calculation {
class ExpressionsListController : public ListController {
public:
ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController);
ExpressionsListController(EditExpressionController * editExpressionController);
// Responder
void viewDidDisappear() override;

View File

@@ -1,4 +1,5 @@
#include "illustrated_list_controller.h"
#include <poincare/exception_checkpoint.h>
#include <poincare/symbol.h>
#include "../app.h"
@@ -8,8 +9,8 @@ namespace Calculation {
/* Illustrated list controller */
IllustratedListController::IllustratedListController(Responder * parentResponder, EditExpressionController * editExpressionController) :
ListController(parentResponder, editExpressionController, this),
IllustratedListController::IllustratedListController(EditExpressionController * editExpressionController) :
ListController(editExpressionController, this),
m_additionalCalculationCells{}
{
for (int i = 0; i < k_maxNumberOfAdditionalCalculations; i++) {
@@ -82,6 +83,10 @@ KDCoordinate IllustratedListController::rowHeight(int j) {
KDCoordinate result = calculation->memoizedHeight(expanded);
if (result < 0) {
result = ScrollableThreeExpressionsCell::Height(calculation.pointer());
if (result < 0) {
// Raise, because Height modified the calculation and failed.
Poincare::ExceptionCheckpoint::Raise();
}
calculation->setMemoizedHeight(expanded, result);
}
return result + Metric::CellSeparatorThickness;

View File

@@ -10,8 +10,10 @@
namespace Calculation {
class IllustratedListController : public ListController, public SelectableTableViewDelegate {
/* TODO There is factorizable code between this and
* Calculation::HistoryController (at least rowHeight). */
public:
IllustratedListController(Responder * parentResponder, EditExpressionController * editExpressionController);
IllustratedListController(EditExpressionController * editExpressionController);
// Responder
void viewDidDisappear() override;
@@ -31,7 +33,7 @@ public:
// IllustratedListController
void setExpression(Poincare::Expression e) override;
constexpr static KDCoordinate k_illustrationHeight = 100;
constexpr static KDCoordinate k_illustrationHeight = 120;
protected:
Poincare::Expression m_savedExpression;
CalculationStore m_calculationStore;

View File

@@ -28,9 +28,6 @@ Integer::Base baseAtIndex(int index) {
}
void IntegerListController::computeLayoutAtIndex(int index) {
if (!m_layouts[index].isUninitialized()) {
return;
}
assert(m_expression.type() == ExpressionNode::Type::BasedInteger);
// For index = k_indexOfFactorExpression, the layout is assumed to be alreday memoized because it is needed to compute the numberOfRows
assert(index < k_indexOfFactorExpression);
@@ -65,6 +62,6 @@ bool IntegerListController::factorExpressionIsComputable() const {
}
m_layouts[k_indexOfFactorExpression] = EmptyLayout::Builder();
return false;
}
}
}

View File

@@ -8,7 +8,7 @@ namespace Calculation {
class IntegerListController : public ExpressionsListController {
public:
IntegerListController(EditExpressionController * editExpressionController) :
ExpressionsListController(nullptr, editExpressionController) {}
ExpressionsListController(editExpressionController) {}
//ListViewDataSource
int numberOfRows() const override;

View File

@@ -21,8 +21,8 @@ void ListController::InnerListController::didBecomeFirstResponder() {
/* List Controller */
ListController::ListController(Responder * parentResponder, EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate) :
StackViewController(parentResponder, &m_listController, Palette::ToolboxHeaderText, Palette::ToolboxHeaderBackground, Palette::ToolboxHeaderBorder),
ListController::ListController(EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate) :
StackViewController(nullptr, &m_listController, Palette::ToolboxHeaderText, Palette::ToolboxHeaderBackground, Palette::ToolboxHeaderBorder),
m_listController(this, delegate),
m_editExpressionController(editExpressionController)
{
@@ -38,7 +38,6 @@ bool ListController::handleEvent(Ion::Events::Event event) {
* insertTextBody. */
Container::activeApp()->dismissModalViewController();
m_editExpressionController->insertTextBody(buffer);
Container::activeApp()->setFirstResponder(m_editExpressionController);
return true;
}
return false;

View File

@@ -10,7 +10,7 @@ class EditExpressionController;
class ListController : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource {
public:
ListController(Responder * parentResponder, EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate = nullptr);
ListController(EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate = nullptr);
// Responder
bool handleEvent(Ion::Events::Event event) override;

View File

@@ -8,7 +8,7 @@ namespace Calculation {
class RationalListController : public ExpressionsListController {
public:
RationalListController(EditExpressionController * editExpressionController) :
ExpressionsListController(nullptr, editExpressionController) {}
ExpressionsListController(editExpressionController) {}
//ListViewDataSource
int numberOfRows() const override;

View File

@@ -8,7 +8,8 @@ void ScrollableThreeExpressionsView::resetMemoization() {
setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout());
}
void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, bool * didForceOutput) {
assert(!didForceOutput || *didForceOutput == false);
Poincare::Context * context = App::app()->localContext();
// Clean the layouts to make room in the pool
@@ -27,6 +28,9 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
Poincare::ExceptionCheckpoint::Raise();
} else {
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
}
}
}
@@ -46,6 +50,9 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
/* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
exactOutputLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
@@ -67,7 +74,16 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
KDCoordinate ScrollableThreeExpressionsCell::Height(Calculation * calculation) {
ScrollableThreeExpressionsCell cell;
cell.setCalculation(calculation);
bool didForceOutput = false;
cell.setCalculation(calculation, &didForceOutput);
if (didForceOutput) {
/* We could not compute the height of the calculation as it is (the display
* output was forced to another value during the height computation).
* Warning: the display output of calculation was actually changed, so it
* will cause problems if we already did some computations with another
* display value. */
return -1;
}
KDRect leftFrame = KDRectZero;
KDRect centerFrame = KDRectZero;
KDRect approximateSignFrame = KDRectZero;
@@ -87,8 +103,8 @@ void ScrollableThreeExpressionsCell::reinitSelection() {
m_view.reloadScroll();
}
void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation) {
m_view.setCalculation(calculation);
void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation, bool * didForceOutput) {
m_view.setCalculation(calculation, didForceOutput);
layoutSubviews();
}

View File

@@ -9,6 +9,9 @@
namespace Calculation {
/* TODO There is factorizable code between this and Calculation::HistoryViewCell
* (at least setCalculation). */
class ScrollableThreeExpressionsView : public Shared::AbstractScrollableMultipleExpressionsView {
public:
static constexpr KDCoordinate k_margin = Metric::CommonSmallMargin;
@@ -17,7 +20,7 @@ public:
setBackgroundColor(Palette::BackgroundApps);
}
void resetMemoization();
void setCalculation(Calculation * calculation);
void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr);
void subviewFrames(KDRect * leftFrame, KDRect * centerFrame, KDRect * approximateSignFrame, KDRect * rightFrame) {
return m_contentCell.subviewFrames(leftFrame, centerFrame, approximateSignFrame, rightFrame);
}
@@ -58,7 +61,7 @@ public:
void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); }
void resetMemoization() { m_view.resetMemoization(); }
void setCalculation(Calculation * calculation);
void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr);
void setDisplayCenter(bool display);
ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); }
void setSelectedSubviewPosition(ScrollableThreeExpressionsView::SubviewPosition subviewPosition) { m_view.setSelectedSubviewPosition(subviewPosition); }

View File

@@ -10,7 +10,7 @@ namespace Calculation {
class TrigonometryListController : public IllustratedListController {
public:
TrigonometryListController(EditExpressionController * editExpressionController) :
IllustratedListController(nullptr, editExpressionController),
IllustratedListController(editExpressionController),
m_graphCell(&m_model) {}
void setExpression(Poincare::Expression e) override;
private:

View File

@@ -0,0 +1,155 @@
#include "unit_list_controller.h"
#include "../app.h"
#include "../../shared/poincare_helpers.h"
#include <poincare/unit_convert.h>
#include <poincare/multiplication.h>
#include <poincare/power.h>
#include <poincare/undefined.h>
#include <poincare/unit.h>
using namespace Poincare;
using namespace Shared;
namespace Calculation {
void UnitListController::setExpression(Poincare::Expression e) {
ExpressionsListController::setExpression(e);
assert(!m_expression.isUninitialized());
// Reinitialize m_memoizedExpressions
for (size_t i = 0; i < k_maxNumberOfCells; i++) {
m_memoizedExpressions[i] = Expression();
}
size_t numberOfMemoizedExpressions = 0;
// 1. First rows: miscellaneous classic units for some dimensions
Expression copy = m_expression.clone();
Expression units;
// Reduce to be able to recognize units
PoincareHelpers::Reduce(&copy, App::app()->localContext(), ExpressionNode::ReductionTarget::User);
copy = copy.removeUnit(&units);
bool requireSimplification = false;
bool canChangeUnitPrefix = false;
if (Unit::IsISSpeed(units)) {
// 1.a. Turn speed into km/h
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Multiplication::Builder(
Unit::Kilometer(),
Power::Builder(
Unit::Hour(),
Rational::Builder(-1)
)
)
);
requireSimplification = true; // Simplify the conversion
} else if (Unit::IsISVolume(units)) {
// 1.b. Turn volume into L
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Unit::Liter()
);
requireSimplification = true; // Simplify the conversion
canChangeUnitPrefix = true; // Pick best prefix (mL)
} else if (Unit::IsISEnergy(units)) {
// 1.c. Turn energy into Wh
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Multiplication::Builder(
Unit::Watt(),
Unit::Hour()
)
);
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Unit::ElectronVolt()
);
requireSimplification = true; // Simplify the conversion
canChangeUnitPrefix = true; // Pick best prefix (kWh)
} else if (Unit::IsISTime(units)) {
// Turn time into ? year + ? month + ? day + ? h + ? min + ? s
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(copy, App::app()->localContext());
m_memoizedExpressions[numberOfMemoizedExpressions++] = Unit::BuildTimeSplit(value, App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), Preferences::sharedPreferences()->angleUnit());
}
// 1.d. Simplify and tune prefix of all computed expressions
size_t currentExpressionIndex = 0;
while (currentExpressionIndex < numberOfMemoizedExpressions) {
assert(!m_memoizedExpressions[currentExpressionIndex].isUninitialized());
if (requireSimplification) {
Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
}
if (canChangeUnitPrefix) {
Expression newUnits;
// Reduce to be able to removeUnit
PoincareHelpers::Reduce(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
m_memoizedExpressions[currentExpressionIndex] = m_memoizedExpressions[currentExpressionIndex].removeUnit(&newUnits);
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(m_memoizedExpressions[currentExpressionIndex], App::app()->localContext());
ExpressionNode::ReductionContext reductionContext(
App::app()->localContext(),
Preferences::sharedPreferences()->complexFormat(),
Preferences::sharedPreferences()->angleUnit(),
ExpressionNode::ReductionTarget::User,
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
Unit::ChooseBestPrefixForValue(&newUnits, &value, reductionContext);
m_memoizedExpressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits);
}
currentExpressionIndex++;
}
// 2. IS units only
assert(numberOfMemoizedExpressions < k_maxNumberOfCells - 1);
m_memoizedExpressions[numberOfMemoizedExpressions] = m_expression.clone();
Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[numberOfMemoizedExpressions], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem);
numberOfMemoizedExpressions++;
// 3. Get rid of duplicates
Expression reduceExpression = m_expression.clone();
// Make m_expression compareable to m_memoizedExpressions (turn BasedInteger into Rational for instance)
Shared::PoincareHelpers::Simplify(&reduceExpression, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::None);
currentExpressionIndex = 1;
while (currentExpressionIndex < numberOfMemoizedExpressions) {
bool duplicateFound = false;
for (size_t i = 0; i < currentExpressionIndex + 1; i++) {
// Compare the currentExpression to all previous memoized expressions and to m_expression
Expression comparedExpression = i == currentExpressionIndex ? reduceExpression : m_memoizedExpressions[i];
assert(!comparedExpression.isUninitialized());
if (comparedExpression.isIdenticalTo(m_memoizedExpressions[currentExpressionIndex])) {
numberOfMemoizedExpressions--;
// Shift next expressions
for (size_t j = currentExpressionIndex; j < numberOfMemoizedExpressions; j++) {
m_memoizedExpressions[j] = m_memoizedExpressions[j+1];
}
// Remove last expression
m_memoizedExpressions[numberOfMemoizedExpressions] = Expression();
// The current expression has been discarded, no need to increment the current index
duplicateFound = true;
break;
}
}
if (!duplicateFound) {
// The current expression is not a duplicate, check next expression
currentExpressionIndex++;
}
}
}
int UnitListController::numberOfRows() const {
int nbOfRows = 0;
for (size_t i = 0; i < k_maxNumberOfCells; i++) {
if (!m_memoizedExpressions[i].isUninitialized()) {
nbOfRows++;
}
}
return nbOfRows;
}
void UnitListController::computeLayoutAtIndex(int index) {
assert(!m_memoizedExpressions[index].isUninitialized());
m_layouts[index] = Shared::PoincareHelpers::CreateLayout(m_memoizedExpressions[index]);
}
I18n::Message UnitListController::messageAtIndex(int index) {
return (I18n::Message)0;
}
}

View File

@@ -0,0 +1,26 @@
#ifndef CALCULATION_ADDITIONAL_OUTPUTS_UNIT_LIST_CONTROLLER_H
#define CALCULATION_ADDITIONAL_OUTPUTS_UNIT_LIST_CONTROLLER_H
#include "expressions_list_controller.h"
namespace Calculation {
class UnitListController : public ExpressionsListController {
public:
UnitListController(EditExpressionController * editExpressionController) :
ExpressionsListController(editExpressionController) {}
void setExpression(Poincare::Expression e) override;
//ListViewDataSource
int numberOfRows() const override;
private:
void computeLayoutAtIndex(int index) override;
I18n::Message messageAtIndex(int index) override;
// Memoization of expressions
mutable Poincare::Expression m_memoizedExpressions[k_maxNumberOfCells];
};
}
#endif

View File

@@ -1,9 +1,9 @@
CalculApp = "Cálculo"
CalculAppCapital = "CÁLCULO"
AdditionalResults = "????"
DecimalBase = "????"
HexadecimalBase = "????"
BinaryBase = "????"
PrimeFactors = "????"
MixedFraction = "????"
EuclideanDivision = "????"
AdditionalResults = "Resultados adicionales"
DecimalBase = "Decimal"
HexadecimalBase = "Hexadecimal"
BinaryBase = "Binario"
PrimeFactors = "Factores primos"
MixedFraction = "Fracción mixta"
EuclideanDivision = "División euclidiana"

View File

@@ -0,0 +1,9 @@
CalculApp = "Calcolo"
CalculAppCapital = "CALCOLO"
AdditionalResults = "Risultati complementari"
DecimalBase = "Decimale"
HexadecimalBase = "Esadecimale"
BinaryBase = "Binario"
PrimeFactors = "Fattori primi"
MixedFraction = "Frazione mista"
EuclideanDivision = "Divisione euclidea"

View File

@@ -0,0 +1,9 @@
CalculApp = "Calculatie"
CalculAppCapital = "CALCULATIE"
AdditionalResults = "Bijkomende resultaten"
DecimalBase = "Decimaal"
HexadecimalBase = "Hexadecimaal"
BinaryBase = "Binaire"
PrimeFactors = "Priemfactoren"
MixedFraction = "Gemengde breuk"
EuclideanDivision = "Geheeltallige deling"

View File

@@ -1,9 +1,9 @@
CalculApp = "Cálculo"
CalculAppCapital = "CÁLCULO"
AdditionalResults = "????"
DecimalBase = "????"
HexadecimalBase = "????"
BinaryBase = "????"
PrimeFactors = "????"
MixedFraction = "????"
EuclideanDivision = "????"
AdditionalResults = "Resultados adicionais"
DecimalBase = "Decimal"
HexadecimalBase = "Hexadecimal"
BinaryBase = "Binário"
PrimeFactors = "Fatores primos"
MixedFraction = "Fração mista"
EuclideanDivision = "Divisão euclidiana"

View File

@@ -3,8 +3,10 @@
#include "../shared/scrollable_multiple_expressions_view.h"
#include "../global_preferences.h"
#include "../exam_mode_configuration.h"
#include "app.h"
#include <poincare/exception_checkpoint.h>
#include <poincare/undefined.h>
#include <poincare/unit.h>
#include <poincare/unreal.h>
#include <string.h>
#include <cmath>
@@ -39,8 +41,7 @@ Calculation * Calculation::next() const {
void Calculation::tidy() {
/* Reset height memoization (the complex format could have changed when
* re-entering Calculation app which would impact the heights). */
m_height = -1;
m_expandedHeight = -1;
resetHeightMemoization();
}
const char * Calculation::approximateOutputText(NumberOfSignificantDigits numberOfSignificantDigits) const {
@@ -174,7 +175,7 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
ExpressionNode::Type::PredictionInterval
};
return e.isOfType(approximateOnlyTypes, sizeof(approximateOnlyTypes)/sizeof(ExpressionNode::Type));
}, context, true)
}, context)
)
{
m_displayOutput = DisplayOutput::ApproximateOnly;
@@ -194,9 +195,9 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
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;
resetHeightMemoization();
}
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. */
@@ -232,6 +233,9 @@ Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual(
}
Calculation::AdditionalInformationType Calculation::additionalInformationType(Context * context) {
if (ExamModeConfiguration::exactExpressionsAreForbidden(GlobalPreferences::sharedGlobalPreferences()->examMode())) {
return AdditionalInformationType::None;
}
Preferences * preferences = Preferences::sharedPreferences();
Preferences::ComplexFormat complexFormat = Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), m_inputText);
Expression i = input();
@@ -253,8 +257,28 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
if (input().isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit()) || o.isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit())) {
return AdditionalInformationType::Trigonometry;
}
// TODO: return AdditionalInformationType::Unit
if (o.hasUnit()) {
Expression unit;
PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User,ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None);
o = o.removeUnit(&unit);
if (Unit::IsIS(unit)) {
if (Unit::IsISSpeed(unit) || Unit::IsISVolume(unit) || Unit::IsISEnergy(unit)) {
/* All these units will provide misc. classic representatives in
* addition to the SI unit in additional information. */
return AdditionalInformationType::Unit;
}
if (Unit::IsISTime(unit)) {
/* If the number of seconds is above 60s, we can write it in the form
* of an addition: 23_min + 12_s for instance. */
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(o, App::app()->localContext());
if (value > Unit::SecondsPerMinute) {
return AdditionalInformationType::Unit;
}
}
return AdditionalInformationType::None;
}
return AdditionalInformationType::Unit;
}
if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) {
return AdditionalInformationType::Integer;
}
@@ -268,4 +292,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
return AdditionalInformationType::None;
}
void Calculation::resetHeightMemoization() {
m_height = -1;
m_expandedHeight = -1;
}
}

View File

@@ -100,6 +100,7 @@ private:
static constexpr int k_numberOfExpressions = 4;
static constexpr KDCoordinate k_heightComputationFailureHeight = 50;
static constexpr const char * k_maximalIntegerWithAdditionalInformation = "10000000000000000";
void resetHeightMemoization();
/* Buffers holding text expressions have to be longer than the text written
* by user (of maximum length TextField::maxBufferSize()) because when we
* print an expression we add omitted signs (multiplications, parenthesis...) */

View File

@@ -4,6 +4,7 @@
#include <poincare/rational.h>
#include <poincare/symbol.h>
#include <poincare/undefined.h>
#include "../exam_mode_configuration.h"
#include <assert.h>
using namespace Poincare;
@@ -98,8 +99,11 @@ ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context *
// Outputs hold exact output, approximate output and its duplicate
constexpr static int numberOfOutputs = Calculation::k_numberOfExpressions - 1;
Expression outputs[numberOfOutputs] = {Expression(), Expression(), Expression()};
// SYMBOLIC COMPUTATION <= E12: PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->isInExamModeSymbolic()); // Symbolic computation
PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->isInExamModeSymbolic() ? Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition : Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
if (ExamModeConfiguration::exactExpressionsAreForbidden(GlobalPreferences::sharedGlobalPreferences()->examMode()) && outputs[1].hasUnit()) {
// Hide results with units on units if required by the exam mode configuration
outputs[1] = Undefined::Builder();
}
outputs[2] = outputs[1];
int numberOfSignificantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits;
for (int i = 0; i < numberOfOutputs; i++) {

View File

@@ -9,7 +9,7 @@ using namespace Poincare;
namespace Calculation {
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
EditExpressionController::ContentView::ContentView(Responder * parentResponder, CalculationSelectableTableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
View(),
m_mainView(subview),
m_expressionField(parentResponder, inputEventHandlerDelegate, textFieldDelegate, layoutFieldDelegate)
@@ -42,18 +42,18 @@ EditExpressionController::EditExpressionController(Responder * parentResponder,
ViewController(parentResponder),
m_historyController(historyController),
m_calculationStore(calculationStore),
m_contentView(this, (TableView *)m_historyController->view(), inputEventHandlerDelegate, this, this)
m_contentView(this, static_cast<CalculationSelectableTableView *>(m_historyController->view()), inputEventHandlerDelegate, this, this)
{
m_cacheBuffer[0] = 0;
}
void EditExpressionController::insertTextBody(const char * text) {
Container::activeApp()->setFirstResponder(this);
m_contentView.expressionField()->handleEventWithText(text, false, true);
}
void EditExpressionController::didBecomeFirstResponder() {
int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0;
m_historyController->scrollToCell(0, lastRow);
m_contentView.mainView()->scrollToBottom();
m_contentView.expressionField()->setEditing(true, false);
Container::activeApp()->setFirstResponder(m_contentView.expressionField());
}

View File

@@ -8,6 +8,7 @@
#include "../shared/layout_field_delegate.h"
#include "history_controller.h"
#include "calculation_store.h"
#include "selectable_table_view.h"
namespace Calculation {
@@ -34,15 +35,15 @@ public:
private:
class ContentView : public View {
public:
ContentView(Responder * parentResponder, TableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate);
ContentView(Responder * parentResponder, CalculationSelectableTableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate);
void reload();
TableView * mainView() { return m_mainView; }
CalculationSelectableTableView * mainView() { return m_mainView; }
ExpressionField * expressionField() { return &m_expressionField; }
private:
int numberOfSubviews() const override { return 2; }
View * subviewAtIndex(int index) override;
void layoutSubviews(bool force = false) override;
TableView * m_mainView;
CalculationSelectableTableView * m_mainView;
ExpressionField m_expressionField;
};
void reloadView();

View File

@@ -1,5 +1,6 @@
#include "history_controller.h"
#include "app.h"
#include <poincare/exception_checkpoint.h>
#include <assert.h>
using namespace Shared;
@@ -15,7 +16,8 @@ HistoryController::HistoryController(EditExpressionController * editExpressionCo
m_complexController(editExpressionController),
m_integerController(editExpressionController),
m_rationalController(editExpressionController),
m_trigonometryController(editExpressionController)
m_trigonometryController(editExpressionController),
m_unitController(editExpressionController)
{
for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) {
m_calculationHistory[i].setParentResponder(&m_selectableTableView);
@@ -37,9 +39,9 @@ void HistoryController::reload() {
* the table view twice.
*/
if (numberOfRows() > 0) {
m_selectableTableView.scrollToCell(0, numberOfRows()-1);
m_selectableTableView.scrollToBottom();
// Force to reload last added cell (hide the burger and exact output if necessary)
tableViewDidChangeSelection(&m_selectableTableView, 0, numberOfRows()-1);
tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, numberOfRows()-1);
}
}
@@ -78,11 +80,9 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
EditExpressionController * editController = (EditExpressionController *)parentResponder();
if (subviewType == SubviewType::Input) {
m_selectableTableView.deselectTable();
Container::activeApp()->setFirstResponder(editController);
editController->insertTextBody(calculationAtIndex(focusRow)->inputText());
} else if (subviewType == SubviewType::Output) {
m_selectableTableView.deselectTable();
Container::activeApp()->setFirstResponder(editController);
Shared::ExpiringPointer<Calculation> calculation = calculationAtIndex(focusRow);
ScrollableTwoExpressionsView::SubviewPosition outputSubviewPosition = selectedCell->outputView()->selectedSubviewPosition();
if (outputSubviewPosition == ScrollableTwoExpressionsView::SubviewPosition::Right
@@ -108,6 +108,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
vc = &m_integerController;
} else if (additionalInfoType == Calculation::AdditionalInformationType::Rational) {
vc = &m_rationalController;
} else if (additionalInfoType == Calculation::AdditionalInformationType::Unit) {
vc = &m_unitController;
}
if (vc) {
vc->setExpression(e);
@@ -120,24 +122,14 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
int focusRow = selectedRow();
SubviewType subviewType = selectedSubviewType();
m_selectableTableView.deselectTable();
EditExpressionController * editController = (EditExpressionController *)parentResponder();
m_calculationStore->deleteCalculationAtIndex(storeIndex(focusRow));
reload();
if (numberOfRows()== 0) {
Container::activeApp()->setFirstResponder(editController);
Container::activeApp()->setFirstResponder(parentResponder());
return true;
}
if (focusRow > 0) {
m_selectableTableView.selectCellAtLocation(0, focusRow-1);
} else {
m_selectableTableView.selectCellAtLocation(0, 0);
}
if (subviewType == SubviewType::Input) {
tableViewDidChangeSelection(&m_selectableTableView, 0, selectedRow());
} else {
tableViewDidChangeSelection(&m_selectableTableView, 0, -1);
}
m_selectableTableView.scrollToCell(0, selectedRow());
m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0);
setSelectedSubviewType(subviewType, true, 0, selectedRow());
return true;
}
if (event == Ion::Events::Clear) {
@@ -148,9 +140,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
return true;
}
if (event == Ion::Events::Back) {
EditExpressionController * editController = (EditExpressionController *)parentResponder();
m_selectableTableView.deselectTable();
Container::activeApp()->setFirstResponder(editController);
Container::activeApp()->setFirstResponder(parentResponder());
return true;
}
return false;
@@ -160,7 +151,7 @@ Shared::ExpiringPointer<Calculation> HistoryController::calculationAtIndex(int i
return m_calculationStore->calculationAtIndex(storeIndex(i));
}
void HistoryController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
void HistoryController::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
if (withinTemporarySelection || previousSelectedCellY == selectedRow()) {
return;
}
@@ -171,7 +162,7 @@ void HistoryController::tableViewDidChangeSelection(SelectableTableView * t, int
} else {
HistoryViewCell * selectedCell = (HistoryViewCell *)(t->selectedCell());
SubviewType nextSelectedSubviewType = selectedSubviewType();
if (!selectedCell->displaysSingleLine()) {
if (selectedCell && !selectedCell->displaysSingleLine()) {
nextSelectedSubviewType = previousSelectedCellY < selectedRow() ? SubviewType::Input : SubviewType::Output;
}
setSelectedSubviewType(nextSelectedSubviewType, false, previousSelectedCellX, previousSelectedCellY);
@@ -216,8 +207,16 @@ KDCoordinate HistoryController::rowHeight(int j) {
KDCoordinate result = calculation->memoizedHeight(expanded);
if (result < 0) {
result = HistoryViewCell::Height(calculation.pointer(), expanded);
if (result < 0) {
// Raise, because Height modified the calculation and failed.
Poincare::ExceptionCheckpoint::Raise();
}
calculation->setMemoizedHeight(expanded, result);
}
/* We might want to put an assertion here to check the memoization:
* assert(result == HistoryViewCell::Height(calculation.pointer(), expanded));
* However, Height might fail due to pool memory exhaustion, in which case the
* assertion fails even if "result" had the right value. */
return result;
}
@@ -225,15 +224,21 @@ int HistoryController::typeAtLocation(int i, int j) {
return 0;
}
void HistoryController::scrollToCell(int i, int j) {
m_selectableTableView.scrollToCell(i, j);
}
bool HistoryController::calculationAtIndexToggles(int index) {
Context * context = App::app()->localContext();
return index >= 0 && index < m_calculationStore->numberOfCalculations() && calculationAtIndex(index)->displayOutput(context) == Calculation::DisplayOutput::ExactAndApproximateToggle;
}
void HistoryController::setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX, int previousSelectedY) {
// Avoid selecting non-displayed ellipsis
HistoryViewCell * selectedCell = static_cast<HistoryViewCell *>(m_selectableTableView.selectedCell());
if (subviewType == SubviewType::Ellipsis && selectedCell && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) {
subviewType = SubviewType::Output;
}
HistoryViewCellDataSource::setSelectedSubviewType(subviewType, sameCell, previousSelectedX, previousSelectedY);
}
void HistoryController::historyViewCellDidChangeSelection(HistoryViewCell ** cell, HistoryViewCell ** previousCell, int previousSelectedCellX, int previousSelectedCellY, SubviewType type, SubviewType previousType) {
/* If the selection change triggers the toggling of the outputs, we update
* the whole table as the height of the selected cell row might have changed. */

View File

@@ -9,6 +9,7 @@
#include "additional_outputs/integer_list_controller.h"
#include "additional_outputs/rational_list_controller.h"
#include "additional_outputs/trigonometry_list_controller.h"
#include "additional_outputs/unit_list_controller.h"
namespace Calculation {
@@ -30,8 +31,8 @@ public:
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
KDCoordinate rowHeight(int j) override;
int typeAtLocation(int i, int j) override;
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override;
void scrollToCell(int i, int j);
void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1) override;
void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override;
private:
int storeIndex(int i) { return numberOfRows() - i - 1; }
Shared::ExpiringPointer<Calculation> calculationAtIndex(int i);
@@ -46,6 +47,7 @@ private:
IntegerListController m_integerController;
RationalListController m_rationalController;
TrigonometryListController m_trigonometryController;
UnitListController m_unitController;
};
}

View File

@@ -36,7 +36,16 @@ void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType,
KDCoordinate HistoryViewCell::Height(Calculation * calculation, bool expanded) {
HistoryViewCell cell(nullptr);
cell.setCalculation(calculation, expanded);
bool didForceOutput = false;
cell.setCalculation(calculation, expanded, &didForceOutput);
if (didForceOutput) {
/* We could not compute the height of the calculation as it is (the display
* output was forced to another value during the height computation).
* Warning: the display output of calculation was actually changed, so it
* will cause problems if we already did some computations with another
* display value. */
return -1;
}
KDRect ellipsisFrame = KDRectZero;
KDRect inputFrame = KDRectZero;
KDRect outputFrame = KDRectZero;
@@ -204,7 +213,7 @@ void HistoryViewCell::computeSubviewFrames(KDCoordinate frameWidth, KDCoordinate
KDCoordinate inputY = k_margin;
KDCoordinate outputY = k_margin;
if (m_calculationSingleLine) {
if (m_calculationSingleLine && !m_inputView.layout().isUninitialized()) {
KDCoordinate inputBaseline = m_inputView.layout().baseline();
KDCoordinate outputBaseline = m_scrollableOutputView.baseline();
KDCoordinate baselineDifference = outputBaseline - inputBaseline;
@@ -237,7 +246,8 @@ void HistoryViewCell::resetMemoization() {
m_calculationCRC32 = 0;
}
void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput) {
assert(!didForceOutput || *didForceOutput == false);
uint32_t newCalculationCRC = Ion::crc32Byte((const uint8_t *)calculation, ((char *)calculation->next()) - ((char *) calculation));
if (newCalculationCRC == m_calculationCRC32 && m_calculationExpanded == expanded) {
return;
@@ -265,6 +275,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
if (couldNotCreateExactLayout) {
if (calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) {
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
} else {
/* We should only display the exact result, but we cannot create it
* -> raise an exception. */
@@ -287,6 +300,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
/* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
exactOutputLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);

View File

@@ -18,7 +18,7 @@ public:
Ellipsis = 3
};
HistoryViewCellDataSource() : m_selectedSubviewType(SubviewType::Output) {}
void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1);
virtual void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1);
SubviewType selectedSubviewType() const { return m_selectedSubviewType; }
private:
/* This method should belong to a delegate instead of a data source but as
@@ -51,13 +51,14 @@ public:
Poincare::Layout layout() const override;
KDColor backgroundColor() const override { return m_even ? Palette::CalculationBackgroundEven : Palette::CalculationBackgroundOdd; }
void resetMemoization();
void setCalculation(Calculation * calculation, bool expanded);
void setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput = nullptr);
int numberOfSubviews() const override { return 2 + displayedEllipsis(); }
View * subviewAtIndex(int index) override;
void layoutSubviews(bool force = false) override;
void didBecomeFirstResponder() override;
bool handleEvent(Ion::Events::Event event) override;
Shared::ScrollableTwoExpressionsView * outputView() { return &m_scrollableOutputView; }
ScrollableExpressionView * inputView() { return &m_inputView; }
Calculation::AdditionalInformationType additionalInformationType() const { return m_calculationAdditionInformation; }
private:
constexpr static KDCoordinate k_resultWidth = 80;

View File

@@ -1,4 +1,5 @@
#include "selectable_table_view.h"
#include <algorithm>
namespace Calculation {
@@ -11,6 +12,12 @@ CalculationSelectableTableView::CalculationSelectableTableView(Responder * paren
setDecoratorType(ScrollView::Decorator::Type::None);
}
void CalculationSelectableTableView::scrollToBottom() {
KDCoordinate contentOffsetX = contentOffset().x();
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling();
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
}
void CalculationSelectableTableView::scrollToCell(int i, int j) {
if (m_contentView.bounds().height() < bounds().height()) {
setTopMargin(bounds().height() - m_contentView.bounds().height());
@@ -20,9 +27,8 @@ void CalculationSelectableTableView::scrollToCell(int i, int j) {
::SelectableTableView::scrollToCell(i, j);
ScrollView::layoutSubviews();
if (m_contentView.bounds().height() - contentOffset().y() < bounds().height()) {
KDCoordinate contentOffsetX = contentOffset().x();
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling();
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
// Avoid empty space at the end of the table
scrollToBottom();
}
}
@@ -31,23 +37,63 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo
return;
}
/* 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. */
* cell, thus, we want to deselect the previous used history view cell. (*) */
unhighlightSelectedCell();
/* Main part of the scroll */
HistoryViewCell * cell = static_cast<HistoryViewCell *>(selectedCell());
assert(cell);
KDCoordinate contentOffsetX = contentOffset().x();
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling();
if (subviewType == HistoryViewCellDataSource::SubviewType::Input) {
if (j == 0) {
contentOffsetY = 0;
} else {
contentOffsetY = dataSource()->cumulatedHeightFromIndex(j);
}
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j);
if (cell->displaysSingleLine() && dataSource()->rowHeight(j) > maxContentHeightDisplayableWithoutScrolling()) {
/* If we cannot display the full calculation, we display the selected
* layout as close as possible to the top of the screen without drawing
* empty space between the history and the input field.
*
* Below are some values we can assign to contentOffsetY, and the kinds of
* display they entail :
* (the selected cell is at index j)
*
* 1 - cumulatedHeightFromIndex(j)
* Aligns the top of the cell with the top of the zone in which the
* history can be drawn.
*
* 2 - (cumulatedHeightFromIndex(j+1)
* - maxContentHeightDisplayableWithoutScrolling())
* Aligns the bottom of the cell with the top of the input field.
*
* 3 - cumulatedHeightFromIndex(j) + baseline1 - baseline2
* Aligns the top of the selected layout with the top of the screen (only
* used when the selected layout is the smallest).
*
* The following drawing shows where the calculation would be aligned with
* each value of contentOffsetY, for the calculation (1/3)/(4/2) = 1/6.
*
* (1) (2) (3)
* +--------------+ +--------------+ +--------------+
* | 1 | | --- - | | 3 1 |
* | - | | 4 6 | | --- - |
* | 3 1 | | - | | 4 6 |
* | --- - | | 2 | | - |
* +--------------+ +--------------+ +--------------+
* | (1/3)/(4/2) | | (1/3)/(4/2) | | (1/3)/(4/2) |
* +--------------+ +--------------+ +--------------+
*
* */
contentOffsetY += std::min(
dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling(),
std::max(0, (cell->inputView()->layout().baseline() - cell->outputView()->baseline()) * (subviewType == HistoryViewCellDataSource::SubviewType::Input ? -1 : 1)));
} else if (subviewType != HistoryViewCellDataSource::SubviewType::Input) {
contentOffsetY += dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling();
}
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
/* For the same reason, we have to rehighlight the new history view cell and
* reselect the first responder. */
HistoryViewCell * cell = (HistoryViewCell *)(selectedCell());
/* For the same reason as (*), we have to rehighlight the new history view
* cell and reselect the first responder.
* We have to recall "selectedCell" because when the table might have been
* relayouted in "setContentOffset".*/
cell = static_cast<HistoryViewCell *>(selectedCell());
assert(cell);
cell->setHighlighted(true);
Container::activeApp()->setFirstResponder(cell);

View File

@@ -9,6 +9,7 @@ class CalculationSelectableTableView : public ::SelectableTableView {
public:
CalculationSelectableTableView(Responder * parentResponder, TableViewDataSource * dataSource,
SelectableTableViewDataSource * selectionDataSource, SelectableTableViewDelegate * delegate = nullptr);
void scrollToBottom();
void scrollToCell(int i, int j) override;
void scrollToSubviewOfTypeOfCellAtLocation(HistoryViewCellDataSource::SubviewType subviewType, int i, int j);
};

View File

@@ -1,10 +1,6 @@
apps += Code::App
app_headers += apps/code/app.h
app_code_test_src = $(addprefix apps/code/,\
script_template.cpp \
)
app_code_src = $(addprefix apps/code/,\
app.cpp \
console_controller.cpp \
@@ -15,42 +11,31 @@ app_code_src = $(addprefix apps/code/,\
editor_view.cpp \
helpers.cpp \
menu_controller.cpp \
python_toolbox.cpp \
python_text_area.cpp \
sandbox_controller.cpp \
script.cpp \
script_name_cell.cpp \
script_node_cell.cpp \
script_parameter_controller.cpp \
)
app_code_test_src = $(addprefix apps/code/,\
python_toolbox.cpp \
script.cpp \
script_node_cell.cpp \
script_store.cpp \
script_template.cpp \
variable_box_empty_controller.cpp \
variable_box_controller.cpp \
)
tests_src += $(addprefix apps/code/test/,\
variable_box_controller.cpp\
)
app_code_src += $(app_code_test_src)
apps_src += $(app_code_src)
i18n_files += $(addprefix apps/code/,\
base.de.i18n\
base.en.i18n\
base.es.i18n\
base.fr.i18n\
base.pt.i18n\
base.hu.i18n\
base.universal.i18n\
catalog.de.i18n\
catalog.en.i18n\
catalog.es.i18n\
catalog.fr.i18n\
catalog.pt.i18n\
catalog.hu.i18n\
catalog.universal.i18n\
toolbox.de.i18n\
toolbox.en.i18n\
toolbox.es.i18n\
toolbox.fr.i18n\
toolbox.pt.i18n\
toolbox.hu.i18n\
toolbox.universal.i18n\
)
i18n_files += $(call i18n_with_universal_for,code/base)
i18n_files += $(call i18n_with_universal_for,code/catalog)
i18n_files += $(call i18n_with_universal_for,code/toolbox)
$(eval $(call depends_on_image,apps/code/app.cpp,apps/code/code_icon.png))

View File

@@ -67,7 +67,7 @@ void App::Snapshot::setOpt(const char * name, const char * value) {
const char * scriptContent = separator;
Code::ScriptTemplate script(scriptName, scriptContent);
m_scriptStore.addScriptFromTemplate(&script);
m_scriptStore.scriptNamed(scriptName).toggleImportationStatus(); // set Importation Status to 1
ScriptStore::ScriptNamed(scriptName).toggleAutoimportationStatus(); // set Importation Status to 1
return;
}
if (strcmp(name, "lock-on-console") == 0) {

View File

@@ -51,6 +51,7 @@ public:
}
StackViewController * stackViewController() { return &m_codeStackViewController; }
ConsoleController * consoleController() { return &m_consoleController; }
MenuController * menuController() { return &m_menuController; }
/* Responder */
bool handleEvent(Ion::Events::Event event) override;

View File

@@ -1,10 +1,15 @@
Console = "Interaktive Konsole"
AddScript = "Skript hinzufügen"
ScriptOptions = "Skriptoptionen"
ExecuteScript = "Skript ausführen"
AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _"
Autocomplete = "Autovervollständigung"
AutoImportScript = "Automatischer Import in Konsole"
BuiltinsAndKeywords = "Native Funktionen und Schlüsselwörter"
Console = "Interaktive Konsole"
DeleteScript = "Skript löschen"
DuplicateScript = "Skript duplizieren"
ExecuteScript = "Skript ausführen"
FunctionsAndVariables = "Funktionen und Variablen"
AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _"
ScriptSize = "Skriptgrösse"
ImportedModulesAndScripts = "Importierte Module und Skripte"
NoWordAvailableHere = "Kein Wort ist hier verfübar."
ScriptInProgress = "Aktuelle Skript"
ScriptOptions = "Skriptoptionen"
ScriptSize = "Script size"

View File

@@ -1,10 +1,15 @@
Console = "Python shell"
AddScript = "Add a script"
ScriptOptions = "Script options"
ExecuteScript = "Execute script"
AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _"
Autocomplete = "Autocomplete"
AutoImportScript = "Auto import in shell"
BuiltinsAndKeywords = "Builtins and keywords"
Console = "Python shell"
DeleteScript = "Delete script"
DuplicateScript = "Duplicate script"
ExecuteScript = "Execute script"
FunctionsAndVariables = "Functions and variables"
AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _"
ImportedModulesAndScripts = "Imported modules and scripts"
NoWordAvailableHere = "No word available here."
ScriptInProgress = "Script in progress"
ScriptOptions = "Script options"
ScriptSize = "Script size"

View File

@@ -1,10 +1,15 @@
Console = "Interprete de comandos"
AddScript = "Agregar un archivo"
ScriptOptions = "Opciones del archivo"
ExecuteScript = "Ejecutar el archivo"
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
Autocomplete = "Autocompleción"
AutoImportScript = "Importación auto en intérprete"
BuiltinsAndKeywords = "Funciones nativas y palabras clave"
Console = "Interprete de comandos"
DeleteScript = "Eliminar el archivo"
DuplicateScript = "Duplicar el guión"
ExecuteScript = "Ejecutar el archivo"
FunctionsAndVariables = "Funciones y variables"
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
ScriptSize = "tamano del script"
ImportedModulesAndScripts = "Módulos y archivos importados"
NoWordAvailableHere = "No hay ninguna palabra disponible aquí."
ScriptInProgress = "Archivo en curso"
ScriptOptions = "Opciones del archivo"
ScriptSize = "Script size"

View File

@@ -1,10 +1,15 @@
Console = "Console d'exécution"
AddScript = "Ajouter un script"
ScriptOptions = "Options de script"
ExecuteScript = "Exécuter le script"
AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _"
Autocomplete = "Auto-complétion"
AutoImportScript = "Importation auto dans la console"
BuiltinsAndKeywords = "Fonctions natives et mots-clés"
Console = "Console d'exécution"
DeleteScript = "Supprimer le script"
DuplicateScript = "Dupliquer le script"
ExecuteScript = "Exécuter le script"
FunctionsAndVariables = "Fonctions et variables"
AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _"
ScriptSize = "Taille du script"
ImportedModulesAndScripts = "Modules et scripts importés"
NoWordAvailableHere = "Aucun mot disponible à cet endroit."
ScriptInProgress = "Script en cours"
ScriptOptions = "Options de script"
ScriptSize = "Script size"

13
apps/code/base.it.i18n Normal file
View File

@@ -0,0 +1,13 @@
AddScript = "Aggiungere script"
AllowedCharactersaz09 = "Caratteri consentiti : a-z, 0-9, _"
Autocomplete = "Autocompletamento"
AutoImportScript = "Importazione automatica dello script"
BuiltinsAndKeywords = "Funzioni native e parole chiave"
Console = "Console d'esecuzione"
DeleteScript = "Eliminare lo script"
ExecuteScript = "Eseguire lo script"
FunctionsAndVariables = "Funzioni e variabili"
ImportedModulesAndScripts = "Moduli e scripts importati"
NoWordAvailableHere = "Nessuna parola disponibile qui."
ScriptInProgress = "Script in corso"
ScriptOptions = "Opzioni dello script"

13
apps/code/base.nl.i18n Normal file
View File

@@ -0,0 +1,13 @@
AddScript = "Script toevoegen"
AllowedCharactersaz09 = "Toegestane tekens: a-z, 0-9, _"
Autocomplete = "Autocomplete"
AutoImportScript = "Automatisch importeren in shell"
BuiltinsAndKeywords = "Builtins and keywords"
Console = "Python shell"
DeleteScript = "Script verwijderen"
ExecuteScript = "Script uitvoeren"
FunctionsAndVariables = "Functies en variabelen"
ImportedModulesAndScripts = "Imported modules and scripts"
NoWordAvailableHere = "No word available here."
ScriptInProgress = "Script in progress"
ScriptOptions = "Script opties"

View File

@@ -1,10 +1,14 @@
Console = "Interpretador interativo"
AddScript = "Adicionar um script"
ScriptOptions = "Opções de script"
ExecuteScript = "Executar o script"
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
Autocomplete = "Preenchimento automático"
AutoImportScript = "Importação auto no interpretador"
BuiltinsAndKeywords = "Funções nativas e palavras-chave"
Console = "Interpretador interativo"
DeleteScript = "Eliminar o script"
DuplicateScript = "Duplicar o script"
ExecuteScript = "Executar o script"
FunctionsAndVariables = "Funções e variáveis"
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
ScriptSize = "tamanho do script"
ImportedModulesAndScripts = "Módulos e scripts importados"
NoWordAvailableHere = "Nenhuma palavra disponível aqui."
ScriptInProgress = "Script em curso"
ScriptOptions = "Opções de script"

View File

@@ -26,7 +26,18 @@ PythonCeil = "Aufrundung"
PythonChoice = "Zufallszahl aus der Liste"
PythonClear = "Leere die Liste"
PythonCmathFunction = "cmath-Modul-Funktionspräfix"
PythonColor = "Definiert eine RGB-Farbe"
PythonColor = "Definiere eine RGB-Farbe"
PythonColorBlack = "Black color"
PythonColorBlue = "Blue color"
PythonColorBrown = "Brown color"
PythonColorGreen = "Green color"
PythonColorGrey = "Grey color"
PythonColorOrange = "Orange color"
PythonColorPink = "Pink color"
PythonColorPurple = "Purple color"
PythonColorRed = "Red color"
PythonColorWhite = "White color"
PythonColorYellow = "Yellow color"
PythonComplex = "a+ib zurückgeben"
PythonCopySign = "x mit dem Vorzeichen von y"
PythonCos = "Kosinus"
@@ -45,10 +56,10 @@ PythonFillRect = "Malt ein Rechteck bei Pixel (x,y)"
PythonFloat = "Wandelt x zu float um"
PythonFloor = "Floor"
PythonFmod = "a modulo b"
PythonFrExp = "Rest und Exponent von x"
PythonGamma = "Gammafunktion"
PythonGetPixel = "Farbe von Pixel (x,y)"
PythonGetrandbits = "Ganzzahl mit k zufälligen Bits"
PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Ganzzahl zu Hexadecimal"
PythonHist = "Draw the histogram of x"
@@ -162,43 +173,19 @@ PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels"
PythonTurtleBlack = "Schwarze Farbe"
PythonTurtleBlue = "Blaue Farbe"
PythonTurtleBrown = "Braune Farbe"
PythonTurtleCircle = "Circle of radius r pixels"
PythonTurtleColor = "Stiftfarbe setzen"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Move forward by x pixels"
PythonTurtleFunction = "turtle module function prefix"
PythonTurtleGoto = "Move to (x,y) coordinates"
PythonTurtleGreen = "Grüne Farbe"
PythonTurtleGrey = "Graue Farbe"
PythonTurtleHeading = "Return the current heading"
PythonTurtleHideturtle = "Hide the turtle"
PythonTurtleIsdown = "Return True if the pen is down"
PythonTurtleLeft = "Turn left by a degrees"
PythonTurtleOrange = "Orange color"
PythonTurtlePendown = "Pull the pen down"
PythonTurtlePensize = "Set the line thickness to x pixels"
PythonTurtlePenup = "Pull the pen up"
PythonTurtlePink = "Pinke Farbe"
PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtlePurple = "Purple color"
PythonTurtleRed = "Rote Farbe"
PythonTurtleReset = "Reset the drawing"
PythonTurtleRight = "Turn right by a degrees"
PythonTurtleSetheading = "Set the orientation to a degrees"
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"
PythonTimeSleep = "Warten Sie n Sekunden lang"
PythonTimeMonotonic = "Monotone Zeit zurückgeben"
PythonFileOpen = "Öffnet eine Datei"
PythonFileSeekable = "Ist eine Datei durchsuchbar?"
PythonFileSeek = "Dateicursor verschieben"
@@ -215,3 +202,12 @@ PythonFileName = "Dateiname"
PythonFileMode = "Dateiöffnungsmodus"
PythonFileReadable = "Ist die Datei lesbar?"
PythonFileWritable = "Ist die Datei beschreibbar?"
PythonTurtlePosition = "Return the current (x,y) location"
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"
PythonTurtleWrite = "Display a text"
PythonUniform = "Floating point number in [a,b]"

View File

@@ -1,7 +1,7 @@
PythonPound = "Comment"
PythonPercent = "Modulo"
Python1J = "Imaginary i"
PythonLF = "Line feed"
PythonLF = "line feed"
PythonTab = "Tabulation"
PythonAmpersand = "Bitwise and"
PythonSymbolExp = "Bitwise exclusive or"
@@ -27,6 +27,17 @@ PythonChoice = "Random number in the list"
PythonClear = "Empty the list"
PythonCmathFunction = "cmath module function prefix"
PythonColor = "Define a rgb color"
PythonColorBlack = "Black color"
PythonColorBlue = "Blue color"
PythonColorBrown = "Brown color"
PythonColorGreen = "Green color"
PythonColorGrey = "Grey color"
PythonColorOrange = "Orange color"
PythonColorPink = "Pink color"
PythonColorPurple = "Purple color"
PythonColorRed = "Red color"
PythonColorWhite = "White color"
PythonColorYellow = "Yellow color"
PythonComplex = "Return a+ib"
PythonCopySign = "Return x with the sign of y"
PythonCos = "Cosine"
@@ -45,7 +56,7 @@ PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float"
PythonFloor = "Floor"
PythonFmod = "a modulo b"
PythonFrExp = "Mantissa and exponent of x"
PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
@@ -162,43 +173,32 @@ PythonText = "Display a text at (x,y) coordinates"
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"
PythonTurtleCircle = "Circle of radius r pixels"
PythonTurtleColor = "Set the pen color"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Move forward by x pixels"
PythonTurtleFunction = "turtle module function prefix"
PythonTurtleGoto = "Move to (x,y) coordinates"
PythonTurtleGreen = "Green color"
PythonTurtleGrey = "Grey color"
PythonTurtleHeading = "Return the current heading"
PythonTurtleHideturtle = "Hide the turtle"
PythonTurtleIsdown = "Return True if the pen is down"
PythonTurtleLeft = "Turn left by a degrees"
PythonTurtleOrange = "Orange color"
PythonTurtlePendown = "Pull the pen down"
PythonTurtlePensize = "Set the line thickness to x pixels"
PythonTurtlePenup = "Pull the pen up"
PythonTurtlePink = "Pink color"
PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtlePurple = "Purple color"
PythonTurtleRed = "Red color"
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"
PythonTurtleWrite = "Display a text"
PythonUniform = "Floating point number in [a,b]"
PythonTimeFromImport = "Import time module"
PythonTimeImport = "Import time module"
PythonImportTime = "Import time module"
PythonTimePrefix = "time module function prefix"
PythonTimeSleep = "Wait for n second"
PythonTimeMonotonic = "Return monotonic time"
PythonMonotonic = "Return monotonic time"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
PythonFileSeek = "Move file's cursor"

View File

@@ -27,6 +27,17 @@ PythonChoice = "Random number in the list"
PythonClear = "Empty the list"
PythonCmathFunction = "cmath module function prefix"
PythonColor = "Define a rgb color"
PythonColorBlack = "Black color"
PythonColorBlue = "Blue color"
PythonColorBrown = "Brown color"
PythonColorGreen = "Green color"
PythonColorGrey = "Grey color"
PythonColorOrange = "Orange color"
PythonColorPink = "Pink color"
PythonColorPurple = "Purple color"
PythonColorRed = "Red color"
PythonColorWhite = "White color"
PythonColorYellow = "Yellow color"
PythonComplex = "Return a+ib"
PythonCopySign = "Return x with the sign of y"
PythonCos = "Cosine"
@@ -45,7 +56,7 @@ PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float"
PythonFloor = "Floor"
PythonFmod = "a modulo b"
PythonFrExp = "Mantissa and exponent of x"
PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
@@ -162,43 +173,32 @@ PythonText = "Display a text at (x,y) coordinates"
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"
PythonTurtleCircle = "Circle of radius r pixels"
PythonTurtleColor = "Set the pen color"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Move forward by x pixels"
PythonTurtleFunction = "turtle module function prefix"
PythonTurtleGoto = "Move to (x,y) coordinates"
PythonTurtleGreen = "Green color"
PythonTurtleGrey = "Grey color"
PythonTurtleHeading = "Return the current heading"
PythonTurtleHideturtle = "Hide the turtle"
PythonTurtleIsdown = "Return True if the pen is down"
PythonTurtleLeft = "Turn left by a degrees"
PythonTurtleOrange = "Orange color"
PythonTurtlePendown = "Pull the pen down"
PythonTurtlePensize = "Set the line thickness to x pixels"
PythonTurtlePenup = "Pull the pen up"
PythonTurtlePink = "Pink color"
PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtlePurple = "Purple color"
PythonTurtleRed = "Red color"
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"
PythonTurtleWrite = "Display a text"
PythonUniform = "Floating point number in [a,b]"
PythonTimeFromImport = "Import time module"
PythonTimeImport = "Import time module"
PythonImportTime = "Import time module"
PythonTimePrefix = "time module function prefix"
PythonTimeSleep = "Esperar n segundos"
PythonTimeMonotonic = "Tiempo monótono de retorno"
PythonMonotonic = "Tiempo monótono de retorno"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
PythonFileSeek = "Move file's internal cursor"

View File

@@ -27,6 +27,17 @@ PythonChoice = "Nombre aléatoire dans la liste"
PythonClear = "Vide la liste"
PythonCmathFunction = "Préfixe fonction du module cmath"
PythonColor = "Définit une couleur rvb"
PythonColorBlack = "Couleur noire"
PythonColorBlue = "Couleur bleue"
PythonColorBrown = "Couleur marron"
PythonColorGreen = "Couleur verte"
PythonColorGrey = "Couleur grise"
PythonColorOrange = "Couleur orange"
PythonColorPink = "Couleur rose"
PythonColorPurple = "Couleur violette"
PythonColorRed = "Couleur rouge"
PythonColorWhite = "Couleur blanche"
PythonColorYellow = "Couleur jaune"
PythonComplex = "Renvoie a+ib"
PythonCopySign = "Renvoie x avec le signe de y"
PythonCos = "Cosinus"
@@ -162,43 +173,32 @@ PythonText = "Affiche un texte en (x,y)"
PythonTimeFunction = "Préfixe fonction module time"
PythonTrunc = "Troncature entière"
PythonTurtleBackward = "Recule de x pixels"
PythonTurtleBlack = "Couleur noire"
PythonTurtleBlue = "Couleur bleue"
PythonTurtleBrown = "Couleur marron"
PythonTurtleCircle = "Cercle de rayon r pixels"
PythonTurtleColor = "Modifie la couleur du tracé"
PythonTurtleColorMode = "Met le mode de couleur à 1.0 ou 255"
PythonTurtleForward = "Avance de x pixels"
PythonTurtleFunction = "Préfixe fonction du module turtle"
PythonTurtleGoto = "Va au point de coordonnées (x,y)"
PythonTurtleGreen = "Couleur verte"
PythonTurtleGrey = "Couleur grise"
PythonTurtleHeading = "Renvoie l'orientation actuelle"
PythonTurtleHideturtle = "Masque la tortue"
PythonTurtleIsdown = "True si le crayon est abaissé"
PythonTurtleLeft = "Pivote de a degrés vers la gauche"
PythonTurtleOrange = "Couleur orange"
PythonTurtlePendown = "Abaisse le crayon"
PythonTurtlePensize = "Taille du tracé en pixels"
PythonTurtlePenup = "Relève le crayon"
PythonTurtlePink = "Couleur rose"
PythonTurtlePosition = "Renvoie la position (x,y)"
PythonTurtlePurple = "Couleur violette"
PythonTurtleRed = "Couleur rouge"
PythonTurtleReset = "Réinitialise le dessin"
PythonTurtleRight = "Pivote de a degrés vers la droite"
PythonTurtleSetheading = "Met un cap de a degrés"
PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Affiche la tortue"
PythonTurtleSpeed = "Vitesse du tracé entre 0 et 10"
PythonTurtleWhite = "Couleur blanche"
PythonTurtleYellow = "Couleur jaune"
PythonTurtleWrite = "Affiche un texte"
PythonUniform = "Nombre décimal dans [a,b]"
PythonTimeFromImport = "Importation du module temps"
PythonTimeImport = "Importation du module temps"
PythonImportTime = "Importation du module temps"
PythonTimePrefix = "Préfixe fonction du module temps"
PythonTimeSleep = "Attendre n secondes"
PythonTimeMonotonic = "Retourne le temps monotonic"
PythonMonotonic = "Retourne le temps monotonic"
PythonFileOpen = "Ouvre un fichier"
PythonFileSeekable = "Indique si seek peut être utilisé"
PythonFileSeek = "Déplace le curseur interne"

View File

@@ -194,11 +194,10 @@ PythonTurtleSpeed = "Rajzolási sebesség 0 és 10 között"
PythonTurtleWhite = "Fehér szín"
PythonTurtleYellow = "Sárga szín"
PythonUniform = "Lebegöpontos szám [a, b] -ben"
PythonTimeFromImport = "Idömodul importálása"
PythonTimeImport = "Idömodul importálása"
PythonImportTime = "Idömodul importálása"
PythonTimePrefix = "idömodul funkció elötag"
PythonTimeSleep = "Várj n másodpercet"
PythonTimeMonotonic = "Vissza a monoton idö"
PythonMonotonic = "Vissza a monoton idö"
PythonFileOpen = "Fájl megnyitása"
PythonFileSeekable = "A fájl kereshető?"
PythonFileSeek = "A fájl kurzorának áthelyezése"

197
apps/code/catalog.it.i18n Normal file
View File

@@ -0,0 +1,197 @@
PythonPound = "Commento"
PythonPercent = "Modulo"
Python1J = "Unità immaginaria"
PythonLF = "Nuova riga"
PythonTab = "Tabulazione"
PythonAmpersand = "Congiunzione"
PythonSymbolExp = "Disgiunzione esclusiva"
PythonVerticalBar = "Disgiunzione"
PythonImag = "Parte immaginaria di z"
PythonReal = "Parte reale di z"
PythonSingleQuote = "Apostrofo"
PythonAbs = "Valore assoluto/Modulo"
PythonAcos = "Coseno d'arco"
PythonAcosh = "Coseno iperbolico inverso"
PythonAppend = "Inserisce x alla fine della lista"
PythonArrow = "Freccia da (x,y) a (x+dx,y+dy)"
PythonAsin = "Arco sinusoidale"
PythonAsinh = "Arco sinusoidale iperbolico"
PythonAtan = "Arco tangente"
PythonAtan2 = "Calcolo di atan(y/x)"
PythonAtanh = "Arco tangente iperbolico"
PythonAxis = "Imposta assi (xmin,xmax,ymin,ymax)"
PythonBar = "Grafico a barre con x valori"
PythonBin = "Converte un intero in binario"
PythonCeil = "Parte intera superiore"
PythonChoice = "Numero aleatorio nella lista"
PythonClear = "Svuota la lista"
PythonCmathFunction = "Funz. prefissata modulo cmath"
PythonColor = "Definisci un colore rvb"
PythonColorBlack = "Colore nero"
PythonColorBlue = "Colore blu"
PythonColorBrown = "Colore marrone"
PythonColorGreen = "Colore verde"
PythonColorGrey = "Colore grigio"
PythonColorOrange = "Colore arancione"
PythonColorPink = "Colore rosa"
PythonColorPurple = "Colore viola"
PythonColorRed = "Colore rosso"
PythonColorWhite = "Colore bianco"
PythonColorYellow = "Colore giallo"
PythonComplex = "Restituisce a+ib"
PythonCopySign = "Restituisce x con segno di y"
PythonCos = "Coseno"
PythonCosh = "Coseno iperbolico"
PythonCount = "Conta le ricorrenze di x"
PythonDegrees = "Conversione di radianti in gradi"
PythonDivMod = "Quoziente e resto"
PythonDrawString = "Visualizza il testo dal pixel x,y"
PythonErf = "Funzione d'errore"
PythonErfc = "Funzione d'errore complementare"
PythonEval = "Valuta l'espressione nell'argomento "
PythonExp = "Funzione esponenziale"
PythonExpm1 = "Calcola exp(x)-1"
PythonFabs = "Valore assoluto"
PythonFillRect = "Riempie un rettangolo"
PythonFloat = "Conversione in flottanti"
PythonFloor = "Parte intera"
PythonFmod = "a modulo b"
PythonFrExp = "Mantissa ed esponente di x : (m,e)"
PythonGamma = "Funzione gamma"
PythonGetPixel = "Restituisce colore del pixel(x,y)"
PythonGetrandbits = "Numero aleatorio con k bit"
PythonGrid = "Attiva la visibilità della griglia"
PythonHex = "Conversione intero in esadecimale"
PythonHist = "Disegna l'istogramma di x"
PythonImportCmath = "Importa modulo cmath"
PythonImportIon = "Importa modulo ion"
PythonImportKandinsky = "Importa modulo kandinsky"
PythonImportRandom = "Importa modulo random"
PythonImportMath = "Importa modulo math"
PythonImportMatplotlibPyplot = "Importa modulo matplotlib.pyplot"
PythonImportTurtle = "Importa del modulo turtle"
PythonImportTime = "Importa del modulo time"
PythonIndex = "Indice prima occorrenza di x"
PythonInput = "Inserire un valore"
PythonInsert = "Inserire x in posizione i-esima"
PythonInt = "Conversione in intero"
PythonIonFunction = "Prefisso di funzione modulo ion"
PythonIsFinite = "Testa se x è finito"
PythonIsInfinite = "Testa se x est infinito"
PythonIsKeyDown = "Restituisce True premendo tasto k"
PythonIsNaN = "Testa se x è NaN"
PythonKandinskyFunction = "Prefisso funzione modulo kandinsky"
PythonKeyLeft = "Tasto FRECCIA SINISTRA"
PythonKeyUp = "Tasto FRECCIA ALTO"
PythonKeyDown = "Tasto FRECCIA BASSO"
PythonKeyRight = "Tasto FRECCIA DESTRA"
PythonKeyOk = "Tasto OK"
PythonKeyBack = "Tasto INDIETRO"
PythonKeyHome = "Tasto CASA"
PythonKeyOnOff = "Tasto ON/OFF"
PythonKeyShift = "Tasto SHIFT"
PythonKeyAlpha = "Tasto ALPHA"
PythonKeyXnt = "Tasto X,N,T"
PythonKeyVar = "Tasto VAR"
PythonKeyToolbox = "Tasto TOOLBOX"
PythonKeyBackspace = "Tasto CANCELLA"
PythonKeyExp = "Tasto ESPONENZIALE"
PythonKeyLn = "Tasto LOGARITMO NEPERIANO"
PythonKeyLog = "Tasto LOGARITMO DECIMALE"
PythonKeyImaginary = "Tasto I IMMAGINE"
PythonKeyComma = "Tasto VIRGOLA"
PythonKeyPower = "Tasto POTENZA"
PythonKeySine = "Tasto SENO"
PythonKeyCosine = "Tasto COSENO"
PythonKeyTangent = "Tasto TANGENTE"
PythonKeyPi = "Tasto PI"
PythonKeySqrt = "Tasto RADICE QUADRATA"
PythonKeySquare = "Tasto QUADRATO"
PythonKeySeven = "Tasto 7"
PythonKeyEight = "Tasto 8"
PythonKeyNine = "Tasto 9"
PythonKeyLeftParenthesis = "Tasto PARENTESI SINISTRA"
PythonKeyRightParenthesis = "Tasto PARENTESI DESTRA"
PythonKeyFour = "Tasto 4"
PythonKeyFive = "Tasto 5"
PythonKeySix = "Tasto 6"
PythonKeyMultiplication = "Tasto MOLTIPLICAZIONE"
PythonKeyDivision = "Tasto DIVISIONE"
PythonKeyOne = "Tasto 1"
PythonKeyTwo = "Tasto 2"
PythonKeyThree = "Tasto 3"
PythonKeyPlus = "Tasto PIÙ"
PythonKeyMinus = "Tasto MENO"
PythonKeyZero = "Tasto 0"
PythonKeyDot = "Tasto PUNTO"
PythonKeyEe = "Tasto 10 POTENZA X"
PythonKeyAns = "Tasto ANS"
PythonKeyExe = "Tasto EXE"
PythonLdexp = "Inversa di frexp : x*(2**i)"
PythonLength = "Longhezza di un oggetto"
PythonLgamma = "Logaritmo della funzione gamma"
PythonLog = "Logaritmo di base a"
PythonLog10 = "Logaritmo decimale"
PythonLog2 = "Logaritmo di base 2"
PythonMathFunction = "Prefisso funzione del modulo math"
PythonMatplotlibPyplotFunction = "Prefisso modulo matplotlib.pyplot"
PythonMax = "Massimo"
PythonMin = "Minimo"
PythonModf = "Parti frazionarie e intere"
PythonMonotonic = "Restituisce il valore dell'orologio"
PythonOct = "Conversione in ottale"
PythonPhase = "Argomento di z"
PythonPlot = "Disegna y in f. di x come linee"
PythonPolar = "Conversione in polare"
PythonPop = "Cancella l'ultimo elemento"
PythonPower = "x alla potenza y"
PythonPrint = "Visualizza l'oggetto"
PythonRadians = "Conversione da gradi a radianti"
PythonRandint = "Intero aleatorio in [a,b]"
PythonRandom = "Numero aleatorio in [0,1["
PythonRandomFunction = "Prefisso funzione modulo casuale"
PythonRandrange = "Numero dentro il range(start, stop)"
PythonRangeStartStop = "Lista da start a stop-1"
PythonRangeStop = "Lista da 0 a stop-1"
PythonRect = "Converte in coordinate algebriche"
PythonRemove = "Cancella la prima x dalla lista"
PythonReverse = "Inverte gli elementi della lista"
PythonRound = "Arrotondato a n cifre decimali"
PythonScatter = "Diagramma dispersione y in f. di x"
PythonSeed = "Inizializza il generatore random"
PythonSetPixel = "Colora il pixel (x,y)"
PythonShow = "Mostra la figura"
PythonSin = "Seno"
PythonSinh = "Seno iperbolico"
PythonSleep = "Sospende l'esecuzione t secondi"
PythonSort = "Ordina l'elenco"
PythonSqrt = "Radice quadrata"
PythonSum = "Somma degli elementi della lista"
PythonTan = "Tangente"
PythonTanh = "Tangente iperbolica"
PythonText = "Mostra un testo in (x,y)"
PythonTimeFunction = "Prefisso funzione modulo time"
PythonTrunc = "Troncamento intero"
PythonTurtleBackward = "Indietreggia di x pixels"
PythonTurtleCircle = "Cerchio di raggio r pixel"
PythonTurtleColor = "Modifica il colore del tratto"
PythonTurtleColorMode = "Imposta modalità colore a 1.0 o 255"
PythonTurtleForward = "Avanza di x pixel"
PythonTurtleFunction = "Prefisso funzione modello turtle"
PythonTurtleGoto = "Spostati alle coordinate (x,y)"
PythonTurtleHeading = "Restituisce l'orientamento attuale"
PythonTurtleHideturtle = "Nascondi la tartaruga"
PythonTurtleIsdown = "True se la penna è abbassata"
PythonTurtleLeft = "Ruota di a gradi a sinistra"
PythonTurtlePendown = "Abbassa la penna"
PythonTurtlePensize = "Dimensione del tratto in pixel"
PythonTurtlePenup = "Solleva la penna"
PythonTurtlePosition = "Fornisce posizione corrente (x,y)"
PythonTurtleReset = "Azzera il disegno"
PythonTurtleRight = "Ruota di a gradi a destra"
PythonTurtleSetheading = "Imposta l'orientamento per a gradi"
PythonTurtleSetposition = "Posiziona la tartaruga"
PythonTurtleShowturtle = "Mostra la tartaruga"
PythonTurtleSpeed = "Velocità di disegno (x tra 0 e 10)"
PythonTurtleWrite = "Mostra un testo"
PythonUniform = "Numero decimale tra [a,b]"

197
apps/code/catalog.nl.i18n Normal file
View File

@@ -0,0 +1,197 @@
PythonPound = "Opmerkingen"
PythonPercent = "Modulo"
Python1J = "Imaginaire i"
PythonLF = "Nieuwe regel"
PythonTab = "Tabulatie"
PythonAmpersand = "Bitsgewijze en"
PythonSymbolExp = "Bitsgewijze exclusieve of"
PythonVerticalBar = "Bitsgewijze of"
PythonImag = "Imaginair deel van z"
PythonReal = "Reëel deel van z"
PythonSingleQuote = "Enkele aanhalingstekens"
PythonAbs = "Absolute waarde"
PythonAcos = "Arccosinus"
PythonAcosh = "Arccosinus hyperbolicus"
PythonAppend = "Voeg x toe aan het eind van je lijst"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arcsinus"
PythonAsinh = "Arcsinus hyperbolicus"
PythonAtan = "Arctangens"
PythonAtan2 = "Geeft atan(y/x)"
PythonAtanh = "Arctangens hyperbolicus"
PythonAxis = "Set the axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Zet integer om in een binair getal"
PythonCeil = "Plafond"
PythonChoice = "Geeft willek. getal van de lijst"
PythonClear = "Lijst leegmaken"
PythonCmathFunction = "cmath module voorvoegsel"
PythonColor = "Definieer een rgb kleur"
PythonColorBlack = "Zwarte kleur"
PythonColorBlue = "Blauwe kleur"
PythonColorBrown = "Bruine kleur"
PythonColorGreen = "Groene kleur"
PythonColorGrey = "Grijze kleur"
PythonColorOrange = "Oranje kleur"
PythonColorPink = "Roze kleur"
PythonColorPurple = "Paarse kleur"
PythonColorRed = "Rode kleur"
PythonColorWhite = "Witte kleur"
PythonColorYellow = "Gele kleur"
PythonComplex = "Geeft a+ib"
PythonCopySign = "Geeft x met het teken van y"
PythonCos = "Cosinus"
PythonCosh = "Cosinus hyperbolicus"
PythonCount = "Tel voorkomen van x"
PythonDegrees = "Zet x om van radialen naar graden"
PythonDivMod = "Quotiënt en rest"
PythonDrawString = "Geef een tekst weer van pixel (x,y)"
PythonErf = "Error functie"
PythonErfc = "Complementaire error functie"
PythonEval = "Geef de geëvalueerde uitdrukking"
PythonExp = "Exponentiële functie"
PythonExpm1 = "Bereken exp(x)-1"
PythonFabs = "Absolute waarde"
PythonFillRect = "Vul een rechthoek bij pixel (x,y)"
PythonFloat = "Zet x om in een float"
PythonFloor = "Vloer"
PythonFmod = "a modulo b"
PythonFrExp = "Mantisse en exponent van x: (m,e)"
PythonGamma = "Gammafunctie"
PythonGetPixel = "Geef pixel (x,y) kleur (rgb)"
PythonGetrandbits = "Integer met k willekeurige bits"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Zet integer om in hexadecimaal"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "Importeer cmath module"
PythonImportIon = "Importeer ion module"
PythonImportKandinsky = "Importeer kandinsky module"
PythonImportRandom = "Importeer random module"
PythonImportMath = "Importeer math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
PythonImportTime = "Importeer time module"
PythonImportTurtle = "Importeer turtle module"
PythonIndex = "Index van de eerste x aanwezigheden"
PythonInput = "Wijs een waarde toe"
PythonInsert = "Voeg x toe aan index i in de lijst"
PythonInt = "Zet x om in een integer"
PythonIonFunction = "ion module voorvoegsel"
PythonIsFinite = "Controleer of x eindig is"
PythonIsInfinite = "Controleer of x oneindig is"
PythonIsKeyDown = "Geef True als k toets omlaag is"
PythonIsNaN = "Controleer of x geen nummer is"
PythonKandinskyFunction = "kandinsky module voorvoegsel"
PythonKeyLeft = "PIJL NAAR LINKS toets"
PythonKeyUp = "PIJL OMHOOG toets"
PythonKeyDown = "PIJL OMLAAG toets"
PythonKeyRight = "PIJL NAAR RECHTS toets"
PythonKeyOk = "OK toets"
PythonKeyBack = "TERUG toets"
PythonKeyHome = "HOME toets"
PythonKeyOnOff = "AAN/UIT toets"
PythonKeyShift = "SHIFT toets"
PythonKeyAlpha = "ALPHA toets"
PythonKeyXnt = "X,N,T toets"
PythonKeyVar = "VAR toets"
PythonKeyToolbox = "TOOLBOX toets"
PythonKeyBackspace = "BACKSPACE toets"
PythonKeyExp = "EXPONENTIEEL toets"
PythonKeyLn = "NATUURLIJKE LOGARITME toets"
PythonKeyLog = "BRIGGSE LOGARITME toets"
PythonKeyImaginary = "IMAGINAIRE I toets"
PythonKeyComma = "KOMMA toets"
PythonKeyPower = "MACHT toets"
PythonKeySine = "SINUS toets"
PythonKeyCosine = "COSINUS toets"
PythonKeyTangent = "TANGENS toets"
PythonKeyPi = "PI toets"
PythonKeySqrt = "VIERKANTSWORTEL toets"
PythonKeySquare = "KWADRAAT toets"
PythonKeySeven = "7 toets"
PythonKeyEight = "8 toets"
PythonKeyNine = "9 toets"
PythonKeyLeftParenthesis = "HAAKJE OPENEN toets"
PythonKeyRightParenthesis = "HAAKJE SLUITEN toets"
PythonKeyFour = "4 toets"
PythonKeyFive = "5 toets"
PythonKeySix = "6 toets"
PythonKeyMultiplication = "VERMENIGVULDIGEN toets"
PythonKeyDivision = "DELEN toets"
PythonKeyOne = "1 toets"
PythonKeyTwo = "2 toets"
PythonKeyThree = "3 toets"
PythonKeyPlus = "PLUS toets"
PythonKeyMinus = "MIN toets"
PythonKeyZero = "0 toets"
PythonKeyDot = "PUNT toets"
PythonKeyEe = "10 TOT DE MACHT X toets"
PythonKeyAns = "ANS toets"
PythonKeyExe = "EXE toets"
PythonLdexp = "Geeft x*(2**i), inversie van frexp"
PythonLength = "Lengte van een object"
PythonLgamma = "Log-gammafunctie"
PythonLog = "Logaritme met grondgetal a"
PythonLog10 = "Logaritme met grondgetal 10"
PythonLog2 = "Logaritme met grondgetal 2"
PythonMathFunction = "math module voorvoegsel"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractionele en gehele delen van x"
PythonMonotonic = "Waarde van een monotone klok"
PythonOct = "Integer omzetten naar octaal"
PythonPhase = "Fase van z in radialen"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z in poolcoördinaten"
PythonPop = "Verwijder en breng het laatste item terug"
PythonPower = "x tot de macht y"
PythonPrint = "Print object"
PythonRadians = "Zet x om van graden naar radialen"
PythonRandint = "Geeft willek. integer in [a,b]"
PythonRandom = "Een willekeurig getal in [0,1["
PythonRandomFunction = "random module voorvoegsel"
PythonRandrange = "Willek. getal in range(start, stop)"
PythonRangeStartStop = "Lijst van start tot stop-1"
PythonRangeStop = "Lijst van 0 tot stop-1"
PythonRect = "z in cartesiaanse coördinaten"
PythonRemove = "Verwijder het eerste voorkomen van x"
PythonReverse = "Keer de elementen van de lijst om"
PythonRound = "Rond af op n cijfers"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Start willek. getallengenerator"
PythonSetPixel = "Kleur pixel (x,y)"
PythonShow = "Display the figure"
PythonSin= "Sinus"
PythonSinh = "Sinus hyperbolicus"
PythonSleep = "Stel executie voor t seconden uit"
PythonSort = "Sorteer de lijst"
PythonSqrt = "Vierkantswortel"
PythonSum = "Sommeer de items van een lijst"
PythonTan = "Tangens"
PythonTanh = "Tangens hyperbolicus"
PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module voorvoegsel"
PythonTrunc = "x afgeknot tot een integer"
PythonTurtleBackward = "Ga achterwaarts met x pixels"
PythonTurtleCircle = "Cirkel van straal r pixels"
PythonTurtleColor = "Stel de kleur van de pen in"
PythonTurtleColorMode = "Stel de kleurmodus in op 1.0 of 255"
PythonTurtleForward = "Ga voorwaarts met x pixels"
PythonTurtleFunction = "turtle module voorvoegsel"
PythonTurtleGoto = "Verplaats naar (x,y) coordinaten"
PythonTurtleHeading = "Ga terug naar de huidige koers"
PythonTurtleHideturtle = "Verberg de schildpad"
PythonTurtleIsdown = "Geeft True als pen naar beneden is"
PythonTurtleLeft = "Ga linksaf met a graden"
PythonTurtlePendown = "Zet de pen naar beneden"
PythonTurtlePensize = "Stel de lijndikte in op x pixels"
PythonTurtlePenup = "Zet de pen omhoog"
PythonTurtlePosition = "Zet huidige (x,y) locatie terug"
PythonTurtleReset = "Reset de tekening"
PythonTurtleRight = "Ga rechtsaf met a graden"
PythonTurtleSetheading = "Zet de oriëntatie op a graden"
PythonTurtleSetposition = "Plaats de schildpad"
PythonTurtleShowturtle = "Laat de schildpad zien"
PythonTurtleSpeed = "Tekensnelheid tussen 0 and 10"
PythonTurtleWrite = "Display a text"
PythonUniform = "Zwevendekommagetal in [a,b]"

View File

@@ -1,208 +1,204 @@
PythonPound = "Comment"
PythonPercent = "Modulo"
Python1J = "Imaginary i"
PythonLF = "Line feed"
PythonTab = "Tabulation"
PythonAmpersand = "Bitwise and"
PythonSymbolExp = "Bitwise exclusive or"
PythonVerticalBar = "Bitwise or"
PythonSingleQuote = "Single quote"
PythonImag = "Imaginary part of z"
PythonReal = "Real part of z"
PythonAbs = "Absolute value/Magnitude"
PythonAcos = "Arc cosine"
PythonAcosh = "Arc hyperbolic cosine"
PythonAppend = "Add x to the end of the list"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arc sine"
PythonAsinh = "Arc hyperbolic sine"
PythonAtan = "Arc tangent"
PythonAtan2 = "Return atan(y/x)"
PythonAtanh = "Arc hyperbolic tangent"
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Convert integer to binary"
PythonCeil = "Ceiling"
PythonChoice = "Random number in the list"
PythonClear = "Empty the list"
PythonCmathFunction = "cmath module function prefix"
PythonColor = "Define a rgb color"
PythonComplex = "Return a+ib"
PythonCopySign = "Return x with the sign of y"
PythonCos = "Cosine"
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)"
PythonErf = "Error function"
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"
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"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Convert integer to hexadecimal"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "Import cmath module"
PythonImportIon = "Import ion module"
PythonImportKandinsky = "Import kandinsky module"
PythonImportRandom = "Import random module"
PythonImportMath = "Import math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot 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"
PythonIonFunction = "ion module function prefix"
PythonIsFinite = "Check if x is finite"
PythonIsInfinite = "Check if x is infinity"
PythonIsKeyDown = "Return True if the k key is down"
PythonIsNaN = "Check if x is a NaN"
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"
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"
PythonLdexp = "Return x*(2**i), inverse of frexp"
PythonLength = "Length of an object"
PythonLgamma = "Log-gamma function"
PythonLog = "Logarithm to base a"
PythonLog10 = "Logarithm to base 10"
PythonLog2 = "Logarithm to base 2"
PythonMathFunction = "math module function prefix"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractional and integer parts of x"
PythonMonotonic = "Value of a monotonic clock"
PythonOct = "Convert integer to octal"
PythonPhase = "Phase of z"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z in polar coordinates"
PythonPop = "Remove and return the last item"
PythonPower = "x raised to the power y"
PythonPrint = "Print object"
PythonRadians = "Convert x from degrees to radians"
PythonRandint = "Random integer in [a,b]"
PythonRandom = "Floating point number in [0,1["
PythonRandomFunction = "random module function prefix"
PythonRandrange = "Random number in range(start,stop)"
PythonRangeStartStop = "List from start to stop-1"
PythonRangeStop = "List from 0 to stop-1"
PythonRect = "Convert to cartesian coordinates"
PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Initialize random number generator"
PythonSetPixel = "Color pixel (x,y)"
PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hyperbolic sine"
PythonSleep = "Suspend the execution for t seconds"
PythonSort = "Sort the list"
PythonSqrt = "Square root"
PythonSum = "Sum the items of a list"
PythonTan = "Tangent"
PythonTanh = "Hyperbolic tangent"
PythonText = "Display a text at (x,y) coordinates"
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"
PythonTurtleCircle = "Circle of radius r pixels"
PythonTurtleColor = "Set the pen color"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Move forward by x pixels"
PythonTurtleFunction = "turtle module function prefix"
PythonTurtleGoto = "Move to (x,y) coordinates"
PythonTurtleGreen = "Green color"
PythonTurtleGrey = "Grey color"
PythonTurtleHeading = "Return the current heading"
PythonTurtleHideturtle = "Hide the turtle"
PythonTurtleIsdown = "Return True if the pen is down"
PythonTurtleLeft = "Turn left by a degrees"
PythonTurtleOrange = "Orange color"
PythonTurtlePendown = "Pull the pen down"
PythonTurtlePensize = "Set the line thickness to x pixels"
PythonTurtlePenup = "Pull the pen up"
PythonTurtlePink = "Pink color"
PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtlePurple = "Purple color"
PythonTurtleRed = "Red color"
PythonTurtleReset = "Reset the drawing"
PythonTurtleRight = "Turn right by a degrees"
PythonTurtleSetheading = "Set the orientation to a degrees"
PythonPound = "Comentário"
PythonPercent = "Módulo"
Python1J = "i Complexo"
PythonLF = "Nova linha"
PythonTab = "Tabulação"
PythonAmpersand = "Operador binário and"
PythonSymbolExp = "Operador binário exclusivo or"
PythonVerticalBar = "Operador binário or"
PythonSingleQuote = "Apóstrofo"
PythonImag = "Parte imaginária de z"
PythonReal = "Parte real de z"
PythonAbs = "Valor absoluto/módulo"
PythonAcos = "Arco cosseno"
PythonAcosh = "Arco cosseno hiperbólico"
PythonAppend = "Adicionar x no fim da lista"
PythonArrow = "Seta de (x,y) para (x+dx,y+dy)"
PythonAsin = "Arco seno"
PythonAsinh = "Arco seno hiperbólico"
PythonAtan = "Arco tangente"
PythonAtan2 = "Cálculo de atan(y/x)"
PythonAtanh = "Arco tangente hiperbólica"
PythonAxis = "Definir eixos (xmin,xmax,ymin,ymax)"
PythonBar = "Gráfico de barras com valores de x"
PythonBin = "Converter número inteiro em binário"
PythonCeil = "Teto"
PythonChoice = "Número aleatório na lista"
PythonClear = "Esvaziar a lista"
PythonCmathFunction = "Prefixo da função do módulo cmath"
PythonColor = "Define uma cor rgb"
PythonColorBlack = "Cor preta"
PythonColorBlue = "Cor azul"
PythonColorBrown = "Cor castanha"
PythonColorGreen = "Cor verde"
PythonColorGrey = "Cor cinzenta"
PythonColorOrange = "Cor laranja"
PythonColorPink = "Cor rosa"
PythonColorPurple = "Cor roxa"
PythonColorRed = "Cor vermelha"
PythonColorWhite = "Cor branca"
PythonColorYellow = "Cor amarela"
PythonComplex = "Devolve a+ib"
PythonCopySign = "Devolve x com o sinal de y"
PythonCos = "Cosseno"
PythonCosh = "Cosseno hiperbólico"
PythonCount = "Contar as ocorrências de x"
PythonDegrees = "Converter x de radianos para graus"
PythonDivMod = "Quociente e resto"
PythonDrawString = "Mostrar o texto do pixel (x,y)"
PythonErf = "Função erro"
PythonErfc = "Função erro complementar"
PythonEval = "Devolve a expressão avaliada"
PythonExp = "Função exponencial"
PythonExpm1 = "Calcular exp(x)-1"
PythonFabs = "Valor absoluto"
PythonFillRect = "Preencher um retângulo em (x,y)"
PythonFloat = "Converter x num flutuante"
PythonFloor = "Parte inteira"
PythonFmod = "a módulo b"
PythonFrExp = "Coeficiente e expoente de x: (m, e)"
PythonGamma = "Função gama"
PythonGetPixel = "Devolve a cor do pixel (x,y)"
PythonGetrandbits = "Número inteiro aleatório com k bits"
PythonGrid = "Alterar visibilidade da grelha"
PythonHex = "Converter inteiro em hexadecimal"
PythonHist = "Desenhar o histograma de x"
PythonImportCmath = "Importar módulo cmath"
PythonImportIon = "Importar módulo ion"
PythonImportKandinsky = "Importar módulo kandinsky"
PythonImportRandom = "Importar módulo random"
PythonImportMath = "Importar módulo math"
PythonImportMatplotlibPyplot = "Importar módulo matplotlib.pyplot"
PythonImportTime = "Importar módulo time"
PythonImportTurtle = "Importar módulo turtle"
PythonIndex = "Índice da primeira ocorrência de x"
PythonInput = "Adicionar um valor"
PythonInsert = "Inserir x no índice i na lista"
PythonInt = "Converter x num número inteiro"
PythonIonFunction = "Prefixo da função do módulo ion"
PythonIsFinite = "Verificar se x é finito"
PythonIsInfinite = "Verificar se x é infinito"
PythonIsKeyDown = "Devolve True se tecla k pressionada"
PythonIsNaN = "Verificar se x é um NaN"
PythonKandinskyFunction = "Prefixo da função do módulo kandinsky"
PythonKeyLeft = "tecla SETA ESQUERDA"
PythonKeyUp = "tecla SETA CIMA "
PythonKeyDown = "tecla SETA BAIXO"
PythonKeyRight = "tecla SETA DIREITA"
PythonKeyOk = "tecla OK"
PythonKeyBack = "tecla VOLTAR"
PythonKeyHome = "tecla HOME"
PythonKeyOnOff = "tecla ON/OFF"
PythonKeyShift = "tecla SHIFT"
PythonKeyAlpha = "tecla ALPHA"
PythonKeyXnt = "tecla X,N,T"
PythonKeyVar = "tecla VAR"
PythonKeyToolbox = "tecla CAIXA DE FERRAMENTAS"
PythonKeyBackspace = "tecla APAGAR"
PythonKeyExp = "tecla EXPONENCIAL"
PythonKeyLn = "tecla LOGARITMO NATURAL"
PythonKeyLog = "tecla LOGARITMO DECIMAL"
PythonKeyImaginary = "tecla I IMAGINÁRIO"
PythonKeyComma = "tecla VÍRGULA"
PythonKeyPower = "tecla EXPOENTE"
PythonKeySine = "tecla SENO"
PythonKeyCosine = "tecla COSSENO"
PythonKeyTangent = "tecla TANGENTE"
PythonKeyPi = "tecla PI"
PythonKeySqrt = "tecla RAIZ QUADRADA"
PythonKeySquare = "tecla AO QUADRADO"
PythonKeySeven = "tecla 7"
PythonKeyEight = "tecla 8"
PythonKeyNine = "tecla 9"
PythonKeyLeftParenthesis = "tecla PARÊNTESE ESQUERDO"
PythonKeyRightParenthesis = "tecla PARÊNTESE DIREITO"
PythonKeyFour = "tecla 4"
PythonKeyFive = "tecla 5"
PythonKeySix = "tecla 6"
PythonKeyMultiplication = "tecla MULTIPLICAÇÃO"
PythonKeyDivision = "tecla DIVISÃO"
PythonKeyOne = "tecla 1"
PythonKeyTwo = "tecla 2"
PythonKeyThree = "tecla 3"
PythonKeyPlus = "tecla MAIS"
PythonKeyMinus = "tecla MENOS"
PythonKeyZero = "tecla 0"
PythonKeyDot = "tecla PONTO"
PythonKeyEe = "tecla 10 expoente X"
PythonKeyAns = "tecla ANS"
PythonKeyExe = "tecla EXE"
PythonLdexp = "Devolve x*(2**i), inverso de frexp"
PythonLength = "Comprimento de um objeto"
PythonLgamma = "Logaritmo da função gama"
PythonLog = "Logaritmo de base a"
PythonLog10 = "Logaritmo de base 10"
PythonLog2 = "Logaritmo de base 2"
PythonMathFunction = "Prefixo da função do módulo math"
PythonMatplotlibPyplotFunction = "Prefixo do módulo matplotlib.pyplot"
PythonMax = "Máximo"
PythonMin = "Mínimo"
PythonModf = "Partes inteira e frácionária de x"
PythonMonotonic = "Devolve o valor do relógio"
PythonOct = "Converter número inteiro em octal"
PythonPhase = "Argumento de z"
PythonPlot = "Desenhar y em função de x"
PythonPolar = "z em coordenadas polares"
PythonPop = "Remover o último item"
PythonPower = "x levantado a y"
PythonPrint = "Mostrar o objeto"
PythonRadians = "Converter x de graus para radianos"
PythonRandint = "Número inteiro aleatório em [a,b]"
PythonRandom = "Número decimal em [0,1["
PythonRandomFunction = "Prefixo da função do módulo random"
PythonRandrange = "Número aleatório em [start,stop-1]"
PythonRangeStartStop = "Lista de start a stop-1"
PythonRangeStop = "Lista de 0 a stop-1"
PythonRect = "Converter para coordenadas cartesianas"
PythonRemove = "Remover a primeira ocorrência de x"
PythonReverse = "Inverter os elementos da lista"
PythonRound = "Arredondar para n dígitos"
PythonScatter = "Gráfico de dispersão (x,y)"
PythonSeed = "Iniciar gerador aleatório"
PythonSetPixel = "Cor do pixel (x,y)"
PythonShow = "Mostrar a figura"
PythonSin = "Seno"
PythonSinh = "Seno hiperbólico"
PythonSleep = "Suspender a execução por t segundos"
PythonSort = "Ordenar a lista"
PythonSqrt = "Raiz quadrada"
PythonSum = "Soma dos itens da lista"
PythonTan = "Tangente"
PythonTanh = "Tangente hiperbólica"
PythonText = "Mostrar um texto em (x,y)"
PythonTimeFunction = "Prefixo da função do módulo time"
PythonTrunc = "x truncado a um número inteiro"
PythonTurtleBackward = "Recuar x pixels"
PythonTurtleCircle = "Circunferência de raio r pixels"
PythonTurtleColor = "Definir a cor da caneta"
PythonTurtleColorMode = "Define modo de cor para 1.0 ou 255"
PythonTurtleForward = "Avançar x pixels"
PythonTurtleFunction = "Prefixo da função do módulo turtle"
PythonTurtleGoto = "Ir paras as coordenadas (x,y)"
PythonTurtleHeading = "Voltar para a orientação atual"
PythonTurtleHideturtle = "Esconder o turtle"
PythonTurtleIsdown = "True se a caneta está pressionada"
PythonTurtleLeft = "Vira à esquerda por a graus"
PythonTurtlePendown = "Puxar a caneta para baixo"
PythonTurtlePensize = "Definir a espessura para x pixels"
PythonTurtlePenup = "Puxar a caneta para cima"
PythonTurtlePosition = "Devolve a posição atual (x,y)"
PythonTurtleReset = "Reiniciar o desenho"
PythonTurtleRight = "Virar à esquerda por a graus"
PythonTurtleSetheading = "Definir a orientação por a graus"
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]"
PythonTimeFromImport = "Import time module"
PythonTimeImport = "Import time module"
PythonTimePrefix = "time module function prefix"
PythonTimeSleep = "Aguardar n segundos"
PythonTimeMonotonic = "Retornar tempo monotônico"
PythonTurtleShowturtle = "Mostrar o turtle"
PythonTurtleSpeed = "Velocidade do desenho entre 0 e 10"
PythonTurtleWrite = "Mostrar um texto"
PythonUniform = "Número decimal em [a,b]"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
PythonFileSeek = "Move file's internal cursor"
PythonFileTell = "Get file's internal cursor location"
PythonFileSeek = "Move file's cursor"
PythonFileTell = "Get file's cursor location"
PythonFileClose = "Closes a file"
PythonFileClosed = "True if file was closed"
PythonFileRead = "Read up to size bytes"

View File

@@ -29,6 +29,17 @@ PythonCommandClearWithoutArg = ".clear()"
PythonCommandCmathFunction = "cmath.function"
PythonCommandCmathFunctionWithoutArg = "cmath.\x11"
PythonCommandColor = "color(r,g,b)"
PythonCommandColorBlack = "'black'"
PythonCommandColorBlue = "'blue'"
PythonCommandColorBrown = "'brown'"
PythonCommandColorGreen = "'green'"
PythonCommandColorGrey = "'grey'"
PythonCommandColorOrange = "'orange'"
PythonCommandColorPink = "'pink'"
PythonCommandColorPurple = "'purple'"
PythonCommandColorRed = "'red'"
PythonCommandColorWhite = "'white'"
PythonCommandColorYellow = "'yellow'"
PythonCommandComplex = "complex(a,b)"
PythonCommandConstantPi = "pi"
PythonCommandCopySign = "copysign(x,y)"
@@ -154,7 +165,7 @@ PythonCommandModf = "modf(x)"
PythonCommandMonotonic = "monotonic()"
PythonCommandOct = "oct(x)"
PythonCommandPhase = "phase(z)"
PythonCommandPlot = "plot(x,y)"
PythonCommandPlot = "plot(x,y,color)"
PythonCommandPolar = "polar(z)"
PythonCommandPop = "list.pop()"
PythonCommandPopWithoutArg = ".pop()"
@@ -202,29 +213,19 @@ PythonCommandUniform = "uniform(a,b)"
PythonConstantE = "2.718281828459045"
PythonConstantPi = "3.141592653589793"
PythonTurtleCommandBackward = "backward(x)"
PythonTurtleCommandBlack = "'black'"
PythonTurtleCommandBlue = "'blue'"
PythonTurtleCommandBrown = "'brown'"
PythonTurtleCommandCircle = "circle(r)"
PythonTurtleCommandColor = "color('c')/color(r,g,b)"
PythonTurtleCommandColorWithoutArg = "color(\x11)"
PythonTurtleCommandColor = "color('c')"
PythonTurtleCommandColorMode = "colormode(x)"
PythonTurtleCommandForward = "forward(x)"
PythonTurtleCommandGoto = "goto(x,y)"
PythonTurtleCommandGreen = "'green'"
PythonTurtleCommandGrey = "'grey'"
PythonTurtleCommandHeading = "heading()"
PythonTurtleCommandHideturtle = "hideturtle()"
PythonTurtleCommandIsdown= "isdown()"
PythonTurtleCommandLeft = "left(a)"
PythonTurtleCommandOrange = "'orange'"
PythonTurtleCommandPendown = "pendown()"
PythonTurtleCommandPensize = "pensize(x)"
PythonTurtleCommandPenup = "penup()"
PythonTurtleCommandPink = "'pink'"
PythonTurtleCommandPosition = "position()"
PythonTurtleCommandPurple = "'purple'"
PythonTurtleCommandRed = "'red'"
PythonTurtleCommandReset = "reset()"
PythonTurtleCommandRight = "right(a)"
PythonTurtleCommandSetheading = "setheading(a)"
@@ -270,3 +271,4 @@ PythonCommandFileReadable = "file.readable()"
PythonCommandFileReadableWithoutArg = ".readable()"
PythonCommandFileWritable = "file.writable()"
PythonCommandFileWritableWithoutArg = ".writable()"
PythonTurtleCommandWrite = "write(\"text\")"

View File

@@ -31,7 +31,7 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe
m_pythonDelegate(pythonDelegate),
m_importScriptsWhenViewAppears(false),
m_selectableTableView(this, this, this, this),
m_editCell(this, pythonDelegate, this),
m_editCell(this, this, this),
m_scriptStore(scriptStore),
m_sandboxController(this),
m_inputRunLoopActive(false)
@@ -48,17 +48,13 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe
}
bool ConsoleController::loadPythonEnvironment() {
if (m_pythonDelegate->isPythonUser(this)) {
return true;
if (!m_pythonDelegate->isPythonUser(this)) {
m_scriptStore->clearConsoleFetchInformation();
emptyOutputAccumulationBuffer();
m_pythonDelegate->initPythonWithUser(this);
MicroPython::registerScriptProvider(m_scriptStore);
m_importScriptsWhenViewAppears = m_autoImportScripts;
}
emptyOutputAccumulationBuffer();
m_pythonDelegate->initPythonWithUser(this);
MicroPython::registerScriptProvider(m_scriptStore);
m_importScriptsWhenViewAppears = m_autoImportScripts;
/* We load functions and variables names in the variable box before running
* any other python code to avoid failling to load functions and variables
* due to memory exhaustion. */
App::app()->variableBoxController()->loadFunctionsAndVariables();
return true;
}
@@ -290,7 +286,7 @@ void ConsoleController::willDisplayCellAtLocation(HighlightCell * cell, int i, i
}
}
void ConsoleController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
void ConsoleController::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
if (withinTemporarySelection) {
return;
}
@@ -375,6 +371,14 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) {
return true;
}
VariableBoxController * ConsoleController::variableBoxForInputEventHandler(InputEventHandler * textInput) {
VariableBoxController * varBox = App::app()->variableBoxController();
varBox->loadVariablesImportedFromScripts();
varBox->setTitle(I18n::Message::FunctionsAndVariables);
varBox->setDisplaySubtitles(false);
return varBox;
}
void ConsoleController::resetSandbox() {
if (stackViewController()->topViewController() != sandbox()) {
return;
@@ -479,7 +483,7 @@ void ConsoleController::autoImportScript(Script script, bool force) {
* the sandbox. */
hideAnyDisplayedViewController();
if (script.importationStatus() || force) {
if (script.autoImportationStatus() || force) {
// Step 1 - Create the command "from scriptName import *".
assert(strlen(k_importCommand1) + strlen(script.fullName()) - strlen(ScriptStore::k_scriptExtension) - 1 + strlen(k_importCommand2) + 1 <= k_maxImportCommandSize);

View File

@@ -10,12 +10,14 @@
#include "console_store.h"
#include "sandbox_controller.h"
#include "script_store.h"
#include "variable_box_controller.h"
#include "../shared/input_event_handler_delegate.h"
namespace Code {
class App;
class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public MicroPython::ExecutionEnvironment {
class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public Shared::InputEventHandlerDelegate, public MicroPython::ExecutionEnvironment {
public:
ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore
#if EPSILON_GETOPT
@@ -52,7 +54,7 @@ public:
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
// SelectableTableViewDelegate
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override;
void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override;
// TextFieldDelegate
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
@@ -60,6 +62,9 @@ public:
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
bool textFieldDidAbortEditing(TextField * textField) override;
// InputEventHandlerDelegate
VariableBoxController * variableBoxForInputEventHandler(InputEventHandler * textInput) override;
// MicroPython::ExecutionEnvironment
ViewController * sandbox() override { return &m_sandboxController; }
void resetSandbox() override;

View File

@@ -13,13 +13,15 @@ EditorController::EditorController(MenuController * menuController, App * python
ViewController(nullptr),
m_editorView(this, pythonDelegate),
m_script(Ion::Storage::Record()),
m_scriptIndex(-1),
m_menuController(menuController)
{
m_editorView.setTextAreaDelegates(this, this);
}
void EditorController::setScript(Script script) {
void EditorController::setScript(Script script, int scriptIndex) {
m_script = script;
m_scriptIndex = scriptIndex;
/* We edit the script direclty in the storage buffer. We thus put all the
* storage available space at the end of the current edited script and we set
@@ -35,7 +37,7 @@ void EditorController::setScript(Script script) {
* */
size_t newScriptSize = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(m_script);
m_editorView.setText(const_cast<char *>(m_script.scriptContent()), newScriptSize - Script::k_importationStatusSize);
m_editorView.setText(const_cast<char *>(m_script.content()), newScriptSize - Script::StatusSize());
}
void EditorController::willExitApp() {
@@ -131,7 +133,24 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) {
VariableBoxController * varBox = App::app()->variableBoxController();
varBox->loadFunctionsAndVariables();
/* If the editor should be autocompleting an identifier, the variable box has
* already been loaded. We check shouldAutocomplete and not isAutocompleting,
* because the autocompletion result might be empty. */
const char * beginningOfAutocompletion = nullptr;
const char * cursor = nullptr;
PythonTextArea::AutocompletionType autocompType = m_editorView.autocompletionType(&beginningOfAutocompletion, &cursor);
if (autocompType == PythonTextArea::AutocompletionType::NoIdentifier) {
varBox->loadFunctionsAndVariables(m_scriptIndex, nullptr, 0);
} else if (autocompType == PythonTextArea::AutocompletionType::MiddleOfIdentifier) {
varBox->empty();
} else {
assert(autocompType == PythonTextArea::AutocompletionType::EndOfIdentifier);
assert(beginningOfAutocompletion != nullptr && cursor != nullptr);
assert(cursor > beginningOfAutocompletion);
varBox->loadFunctionsAndVariables(m_scriptIndex, beginningOfAutocompletion, cursor - beginningOfAutocompletion);
}
varBox->setTitle(I18n::Message::Autocomplete);
varBox->setDisplaySubtitles(true);
return varBox;
}
@@ -146,7 +165,7 @@ void EditorController::cleanStorageEmptySpace() {
Ion::Storage::Record::Data scriptValue = m_script.value();
Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord(
m_script,
scriptValue.size - Script::k_importationStatusSize - (strlen(m_script.scriptContent()) + 1)); // TODO optimize number of script fetches
scriptValue.size - Script::StatusSize() - (strlen(m_script.content()) + 1)); // TODO optimize number of script fetches
}

View File

@@ -16,7 +16,8 @@ class App;
class EditorController : public ViewController, public TextAreaDelegate, public Shared::InputEventHandlerDelegate {
public:
EditorController(MenuController * menuController, App * pythonDelegate);
void setScript(Script script);
void setScript(Script script, int scriptIndex);
int scriptIndex() const { return m_scriptIndex; }
void willExitApp();
/* ViewController */
@@ -39,6 +40,7 @@ private:
StackViewController * stackController();
EditorView m_editorView;
Script m_script;
int m_scriptIndex;
MenuController * m_menuController;
};

View File

@@ -17,6 +17,10 @@ EditorView::EditorView(Responder * parentResponder, App * pythonDelegate) :
m_textArea.setScrollViewDelegate(this);
}
bool EditorView::isAutocompleting() const {
return m_textArea.isAutocompleting();
}
void EditorView::resetSelection() {
m_textArea.resetSelection();
}

View File

@@ -9,6 +9,8 @@ namespace Code {
class EditorView : public Responder, public View, public ScrollViewDelegate {
public:
EditorView(Responder * parentResponder, App * pythonDelegate);
PythonTextArea::AutocompletionType autocompletionType(const char ** autocompletionBeginning, const char ** autocompletionEnd) const { return m_textArea.autocompletionType(nullptr, autocompletionBeginning, autocompletionEnd); }
bool isAutocompleting() const;
void resetSelection();
void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) {
m_textArea.setDelegates(inputEventHandlerDelegate, delegate);
@@ -17,6 +19,9 @@ public:
void setText(char * textBuffer, size_t textBufferSize) {
m_textArea.setText(textBuffer, textBufferSize);
}
const char * cursorLocation() {
return m_textArea.cursorLocation();
}
bool setCursorLocation(const char * location) {
return m_textArea.setCursorLocation(location);
}

View File

@@ -385,7 +385,7 @@ void MenuController::configureScript() {
void MenuController::editScriptAtIndex(int scriptIndex) {
assert(scriptIndex >=0 && scriptIndex < m_scriptStore->numberOfScripts());
Script script = m_scriptStore->scriptAtIndex(scriptIndex);
m_editorController.setScript(script);
m_editorController.setScript(script, scriptIndex);
stackViewController()->push(&m_editorController);
}

View File

@@ -25,6 +25,7 @@ public:
void openConsoleWithScript(Script script);
void scriptContentEditionDidFinish();
void willExitApp();
int editedScriptIndex() const { return m_editorController.scriptIndex(); }
/* ViewController */
View * view() override { return &m_selectableTableView; }

View File

@@ -21,6 +21,7 @@ constexpr KDColor OperatorColor = Palette::CodeOperator;
constexpr KDColor StringColor = Palette::CodeString;
constexpr KDColor BackgroundColor = Palette::CodeBackground;
constexpr KDColor HighlightColor = Palette::CodeBackgroundSelected;
constexpr KDColor AutocompleteColor = KDColor::RGB24(0xC6C6C6); // TODO Palette change
static inline KDColor TokenColor(mp_token_kind_t tokenKind) {
if (tokenKind == MP_TOKEN_STRING) {
@@ -29,13 +30,96 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) {
if (tokenKind == MP_TOKEN_INTEGER || tokenKind == MP_TOKEN_FLOAT_OR_IMAG) {
return NumberColor;
}
static_assert(MP_TOKEN_ELLIPSIS + 1 == MP_TOKEN_KW_FALSE
&& MP_TOKEN_KW_FALSE + 1 == MP_TOKEN_KW_NONE
&& MP_TOKEN_KW_NONE + 1 == MP_TOKEN_KW_TRUE
&& MP_TOKEN_KW_TRUE + 1 == MP_TOKEN_KW___DEBUG__
&& MP_TOKEN_KW___DEBUG__ + 1 == MP_TOKEN_KW_AND
&& MP_TOKEN_KW_AND + 1 == MP_TOKEN_KW_AS
&& MP_TOKEN_KW_AS + 1 == MP_TOKEN_KW_ASSERT
/* Here there are keywords that depend on MICROPY_PY_ASYNC_AWAIT, we do
* not test them */
&& MP_TOKEN_KW_BREAK + 1 == MP_TOKEN_KW_CLASS
&& MP_TOKEN_KW_CLASS + 1 == MP_TOKEN_KW_CONTINUE
&& MP_TOKEN_KW_CONTINUE + 1 == MP_TOKEN_KW_DEF
&& MP_TOKEN_KW_DEF + 1 == MP_TOKEN_KW_DEL
&& MP_TOKEN_KW_DEL + 1 == MP_TOKEN_KW_ELIF
&& MP_TOKEN_KW_ELIF + 1 == MP_TOKEN_KW_ELSE
&& MP_TOKEN_KW_ELSE + 1 == MP_TOKEN_KW_EXCEPT
&& MP_TOKEN_KW_EXCEPT + 1 == MP_TOKEN_KW_FINALLY
&& MP_TOKEN_KW_FINALLY + 1 == MP_TOKEN_KW_FOR
&& MP_TOKEN_KW_FOR + 1 == MP_TOKEN_KW_FROM
&& MP_TOKEN_KW_FROM + 1 == MP_TOKEN_KW_GLOBAL
&& MP_TOKEN_KW_GLOBAL + 1 == MP_TOKEN_KW_IF
&& MP_TOKEN_KW_IF + 1 == MP_TOKEN_KW_IMPORT
&& MP_TOKEN_KW_IMPORT + 1 == MP_TOKEN_KW_IN
&& MP_TOKEN_KW_IN + 1 == MP_TOKEN_KW_IS
&& MP_TOKEN_KW_IS + 1 == MP_TOKEN_KW_LAMBDA
&& MP_TOKEN_KW_LAMBDA + 1 == MP_TOKEN_KW_NONLOCAL
&& MP_TOKEN_KW_NONLOCAL + 1 == MP_TOKEN_KW_NOT
&& MP_TOKEN_KW_NOT + 1 == MP_TOKEN_KW_OR
&& MP_TOKEN_KW_OR + 1 == MP_TOKEN_KW_PASS
&& MP_TOKEN_KW_PASS + 1 == MP_TOKEN_KW_RAISE
&& MP_TOKEN_KW_RAISE + 1 == MP_TOKEN_KW_RETURN
&& MP_TOKEN_KW_RETURN + 1 == MP_TOKEN_KW_TRY
&& MP_TOKEN_KW_TRY + 1 == MP_TOKEN_KW_WHILE
&& MP_TOKEN_KW_WHILE + 1 == MP_TOKEN_KW_WITH
&& MP_TOKEN_KW_WITH + 1 == MP_TOKEN_KW_YIELD
&& MP_TOKEN_KW_YIELD + 1 == MP_TOKEN_OP_TILDE,
"MP_TOKEN order changed, so Code::PythonTextArea::TokenColor might need to change too.");
if (tokenKind >= MP_TOKEN_KW_FALSE && tokenKind <= MP_TOKEN_KW_YIELD) {
return KeywordColor;
}
if (tokenKind >= MP_TOKEN_OP_PLUS && tokenKind <= MP_TOKEN_OP_NOT_EQUAL) {
return OperatorColor;
}
if (tokenKind >= MP_TOKEN_DEL_EQUAL && tokenKind <= MP_TOKEN_DEL_MINUS_MORE) {
static_assert(MP_TOKEN_OP_TILDE + 1 == MP_TOKEN_OP_LESS
&& MP_TOKEN_OP_LESS + 1 == MP_TOKEN_OP_MORE
&& MP_TOKEN_OP_MORE + 1 == MP_TOKEN_OP_DBL_EQUAL
&& MP_TOKEN_OP_DBL_EQUAL + 1 == MP_TOKEN_OP_LESS_EQUAL
&& MP_TOKEN_OP_LESS_EQUAL + 1 == MP_TOKEN_OP_MORE_EQUAL
&& MP_TOKEN_OP_MORE_EQUAL + 1 == MP_TOKEN_OP_NOT_EQUAL
&& MP_TOKEN_OP_NOT_EQUAL + 1 == MP_TOKEN_OP_PIPE
&& MP_TOKEN_OP_PIPE + 1 == MP_TOKEN_OP_CARET
&& MP_TOKEN_OP_CARET + 1 == MP_TOKEN_OP_AMPERSAND
&& MP_TOKEN_OP_AMPERSAND + 1 == MP_TOKEN_OP_DBL_LESS
&& MP_TOKEN_OP_DBL_LESS + 1 == MP_TOKEN_OP_DBL_MORE
&& MP_TOKEN_OP_DBL_MORE + 1 == MP_TOKEN_OP_PLUS
&& MP_TOKEN_OP_PLUS + 1 == MP_TOKEN_OP_MINUS
&& MP_TOKEN_OP_MINUS + 1 == MP_TOKEN_OP_STAR
&& MP_TOKEN_OP_STAR + 1 == MP_TOKEN_OP_AT
&& MP_TOKEN_OP_AT + 1 == MP_TOKEN_OP_DBL_SLASH
&& MP_TOKEN_OP_DBL_SLASH + 1 == MP_TOKEN_OP_SLASH
&& MP_TOKEN_OP_SLASH + 1 == MP_TOKEN_OP_PERCENT
&& MP_TOKEN_OP_PERCENT + 1 == MP_TOKEN_OP_DBL_STAR
&& MP_TOKEN_OP_DBL_STAR + 1 == MP_TOKEN_DEL_PIPE_EQUAL
&& MP_TOKEN_DEL_PIPE_EQUAL + 1 == MP_TOKEN_DEL_CARET_EQUAL
&& MP_TOKEN_DEL_CARET_EQUAL + 1 == MP_TOKEN_DEL_AMPERSAND_EQUAL
&& MP_TOKEN_DEL_AMPERSAND_EQUAL + 1 == MP_TOKEN_DEL_DBL_LESS_EQUAL
&& MP_TOKEN_DEL_DBL_LESS_EQUAL + 1 == MP_TOKEN_DEL_DBL_MORE_EQUAL
&& MP_TOKEN_DEL_DBL_MORE_EQUAL + 1 == MP_TOKEN_DEL_PLUS_EQUAL
&& MP_TOKEN_DEL_PLUS_EQUAL + 1 == MP_TOKEN_DEL_MINUS_EQUAL
&& MP_TOKEN_DEL_MINUS_EQUAL + 1 == MP_TOKEN_DEL_STAR_EQUAL
&& MP_TOKEN_DEL_STAR_EQUAL + 1 == MP_TOKEN_DEL_AT_EQUAL
&& MP_TOKEN_DEL_AT_EQUAL + 1 == MP_TOKEN_DEL_DBL_SLASH_EQUAL
&& MP_TOKEN_DEL_DBL_SLASH_EQUAL + 1 == MP_TOKEN_DEL_SLASH_EQUAL
&& MP_TOKEN_DEL_SLASH_EQUAL + 1 == MP_TOKEN_DEL_PERCENT_EQUAL
&& MP_TOKEN_DEL_PERCENT_EQUAL + 1 == MP_TOKEN_DEL_DBL_STAR_EQUAL
&& MP_TOKEN_DEL_DBL_STAR_EQUAL + 1 == MP_TOKEN_DEL_PAREN_OPEN
&& MP_TOKEN_DEL_PAREN_OPEN + 1 == MP_TOKEN_DEL_PAREN_CLOSE
&& MP_TOKEN_DEL_PAREN_CLOSE + 1 == MP_TOKEN_DEL_BRACKET_OPEN
&& MP_TOKEN_DEL_BRACKET_OPEN + 1 == MP_TOKEN_DEL_BRACKET_CLOSE
&& MP_TOKEN_DEL_BRACKET_CLOSE + 1 == MP_TOKEN_DEL_BRACE_OPEN
&& MP_TOKEN_DEL_BRACE_OPEN + 1 == MP_TOKEN_DEL_BRACE_CLOSE
&& MP_TOKEN_DEL_BRACE_CLOSE + 1 == MP_TOKEN_DEL_COMMA
&& MP_TOKEN_DEL_COMMA + 1 == MP_TOKEN_DEL_COLON
&& MP_TOKEN_DEL_COLON + 1 == MP_TOKEN_DEL_PERIOD
&& MP_TOKEN_DEL_PERIOD + 1 == MP_TOKEN_DEL_SEMICOLON
&& MP_TOKEN_DEL_SEMICOLON + 1 == MP_TOKEN_DEL_EQUAL
&& MP_TOKEN_DEL_EQUAL + 1 == MP_TOKEN_DEL_MINUS_MORE,
"MP_TOKEN order changed, so Code::PythonTextArea::TokenColor might need to change too.");
if ((tokenKind >= MP_TOKEN_OP_TILDE && tokenKind <= MP_TOKEN_DEL_DBL_STAR_EQUAL)
|| tokenKind == MP_TOKEN_DEL_EQUAL
|| tokenKind == MP_TOKEN_DEL_MINUS_MORE)
{
return OperatorColor;
}
return Palette::CodeText;
@@ -52,6 +136,76 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) {
return lex->column - lex->tok_column;
}
PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char * autocompletionLocation, const char ** autocompletionLocationBeginning, const char ** autocompletionLocationEnd) const {
const char * location = autocompletionLocation != nullptr ? autocompletionLocation : cursorLocation();
const char * beginningOfToken = nullptr;
/* If there is already autocompleting, the cursor must be at the end of an
* identifier. Trying to compute autocompletionType will fail: because of the
* autocompletion text, the cursor seems to be in the middle of an identifier. */
AutocompletionType autocompleteType = isAutocompleting() ? AutocompletionType::EndOfIdentifier : AutocompletionType::NoIdentifier;
if (autocompletionLocationBeginning == nullptr && autocompletionLocationEnd == nullptr) {
return autocompleteType;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
const char * firstNonSpace = UTF8Helper::BeginningOfWord(m_contentView.editedText(), location);
mp_lexer_t * lex = mp_lexer_new_from_str_len(0, firstNonSpace, UTF8Helper::EndOfWord(location) - firstNonSpace, 0);
const char * tokenStart;
const char * tokenEnd;
_mp_token_kind_t currentTokenKind = lex->tok_kind;
while (currentTokenKind != MP_TOKEN_NEWLINE && currentTokenKind != MP_TOKEN_END) {
tokenStart = firstNonSpace + lex->tok_column - 1;
tokenEnd = tokenStart + TokenLength(lex, tokenStart);
if (location < tokenStart) {
// The location for autocompletion is not in an identifier
assert(autocompleteType == AutocompletionType::NoIdentifier);
break;
}
if (location <= tokenEnd) {
if (currentTokenKind == MP_TOKEN_NAME
|| (currentTokenKind >= MP_TOKEN_KW_FALSE
&& currentTokenKind <= MP_TOKEN_KW_YIELD))
{
/* The location for autocompletion is in the middle or at the end of
* an identifier. */
beginningOfToken = tokenStart;
/* If autocompleteType is already EndOfIdentifier, we are
* autocompleting, so we do not need to update autocompleteType. If we
* recomputed autocompleteType now, we might wrongly think that it is
* MiddleOfIdentifier because of the autocompetion text.
* Example : fin|ally -> the lexer is at the end of "fin", but because
* we are autocompleting with "ally", the lexer thinks the cursor is
* in the middle of an identifier. */
if (autocompleteType != AutocompletionType::EndOfIdentifier) {
autocompleteType = location < tokenEnd ? AutocompletionType::MiddleOfIdentifier : AutocompletionType::EndOfIdentifier;
}
}
break;
}
mp_lexer_to_next(lex);
currentTokenKind = lex->tok_kind;
}
mp_lexer_free(lex);
nlr_pop();
}
if (autocompletionLocationBeginning != nullptr) {
*autocompletionLocationBeginning = beginningOfToken;
}
if (autocompletionLocationEnd != nullptr) {
*autocompletionLocationEnd = location;
}
assert(!isAutocompleting() || autocompleteType == AutocompletionType::EndOfIdentifier);
return autocompleteType;
}
const char * PythonTextArea::ContentView::textToAutocomplete() const {
return UTF8Helper::BeginningOfWord(editedText(), cursorLocation());
}
void PythonTextArea::ContentView::loadSyntaxHighlighter() {
m_pythonDelegate->initPythonWithUser(this);
}
@@ -75,23 +229,7 @@ void PythonTextArea::ContentView::clearRect(KDContext * ctx, KDRect rect) const
void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t byteLength, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const {
LOG_DRAW("Drawing \"%.*s\"\n", byteLength, text);
if (!m_pythonDelegate->isPythonUser(this)) {
const char * lineStart = UTF8Helper::CodePointAtGlyphOffset(text, fromColumn);
const char * lineEnd = UTF8Helper::CodePointAtGlyphOffset(text, toColumn);
drawStringAt(
ctx,
line,
fromColumn,
lineStart,
std::min(text + byteLength, lineEnd) - lineStart,
StringColor,
BackgroundColor,
selectionStart,
selectionEnd,
HighlightColor
);
return;
}
assert(m_pythonDelegate->isPythonUser(this));
/* We're using the MicroPython lexer to do syntax highlighting on a per-line
* basis. This can work, however the MicroPython lexer won't accept a line
@@ -117,6 +255,8 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
return;
}
const char * autocompleteStart = m_autocomplete ? m_cursorLocation : nullptr;
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_lexer_t * lex = mp_lexer_new_from_str_len(0, firstNonSpace, byteLength - (firstNonSpace - text), 0);
@@ -143,12 +283,16 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
}
tokenLength = TokenLength(lex, tokenFrom);
tokenEnd = tokenFrom + tokenLength;
// If the token is being autocompleted, use DefaultColor
KDColor color = (tokenFrom <= autocompleteStart && autocompleteStart < tokenEnd) ? Palette::CodeText : TokenColor(lex->tok_kind);
LOG_DRAW("Draw \"%.*s\" for token %d\n", tokenLength, tokenFrom, lex->tok_kind);
drawStringAt(ctx, line,
UTF8Helper::GlyphOffsetAtCodePoint(text, tokenFrom),
tokenFrom,
tokenLength,
TokenColor(lex->tok_kind),
color,
BackgroundColor,
selectionStart,
selectionEnd,
@@ -160,6 +304,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
tokenFrom += tokenLength;
// Even if the token is being autocompleted, use CommentColor
if (tokenFrom < text + byteLength) {
LOG_DRAW("Draw comment \"%.*s\" from %d\n", byteLength - (tokenFrom - text), firstNonSpace, tokenFrom);
drawStringAt(ctx, line,
@@ -176,6 +321,22 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
mp_lexer_free(lex);
nlr_pop();
}
// Redraw the autocompleted word in the right color
if (m_autocomplete && autocompleteStart >= text && autocompleteStart < text + byteLength) {
assert(m_autocompletionEnd != nullptr && m_autocompletionEnd > autocompleteStart);
drawStringAt(
ctx,
line,
UTF8Helper::GlyphOffsetAtCodePoint(text, autocompleteStart),
autocompleteStart,
std::min(text + byteLength, m_autocompletionEnd) - autocompleteStart,
AutocompleteColor,
BackgroundColor,
nullptr,
nullptr,
HighlightColor);
}
}
KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position, bool includeFollowingLines) const {
@@ -193,4 +354,158 @@ KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position,
);
}
bool PythonTextArea::handleEvent(Ion::Events::Event event) {
if (m_contentView.isAutocompleting()) {
// Handle event with autocompletion
if (event == Ion::Events::Right
|| event == Ion::Events::ShiftRight
|| event == Ion::Events::OK)
{
m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false);
acceptAutocompletion(event != Ion::Events::ShiftRight);
if (event != Ion::Events::ShiftRight) {
// Do not process the event more
scrollToCursor();
return true;
}
} else if (event == Ion::Events::Toolbox
|| event == Ion::Events::Var
|| event == Ion::Events::Shift
|| event == Ion::Events::Alpha
|| event == Ion::Events::OnOff)
{
} else if(event == Ion::Events::Up
|| event == Ion::Events::Down)
{
cycleAutocompletion(event == Ion::Events::Down);
return true;
} else {
removeAutocompletion();
m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false);
if (event == Ion::Events::Back) {
// Do not process the event more
return true;
}
}
}
bool result = TextArea::handleEvent(event);
if (event == Ion::Events::Backspace && !m_contentView.isAutocompleting() && selectionIsEmpty()) {
/* We want to add autocompletion when we are editing a word (after adding or
* deleting text). So if nothing is selected, we add the autocompletion if
* the event is backspace, as autocompletion has already been added if the
* event added text, in handleEventWithText. */
addAutocompletion();
}
return result;
}
bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
if (*text == 0) {
return false;
}
if (m_contentView.isAutocompleting()) {
removeAutocompletion();
}
bool result = TextArea::handleEventWithText(text, indentation, forceCursorRightOfText);
addAutocompletion();
return result;
}
void PythonTextArea::removeAutocompletion() {
assert(m_contentView.isAutocompleting());
removeAutocompletionText();
m_contentView.setAutocompleting(false);
}
void PythonTextArea::removeAutocompletionText() {
assert(m_contentView.isAutocompleting());
assert(m_contentView.autocompletionEnd() != nullptr);
const char * autocompleteStart = m_contentView.cursorLocation();
const char * autocompleteEnd = m_contentView.autocompletionEnd();
assert(autocompleteEnd != nullptr && autocompleteEnd > autocompleteStart);
m_contentView.removeText(autocompleteStart, autocompleteEnd);
}
void PythonTextArea::addAutocompletion() {
assert(!m_contentView.isAutocompleting());
const char * autocompletionTokenBeginning = nullptr;
const char * autocompletionLocation = const_cast<char *>(cursorLocation());
m_autocompletionResultIndex = 0;
if (autocompletionType(autocompletionLocation, &autocompletionTokenBeginning) != AutocompletionType::EndOfIdentifier) {
// The cursor is not at the end of an identifier.
return;
}
// First load variables and functions that complete the textToAutocomplete
const int scriptIndex = m_contentView.pythonDelegate()->menuController()->editedScriptIndex();
m_contentView.pythonDelegate()->variableBoxController()->loadFunctionsAndVariables(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning);
if (addAutocompletionTextAtIndex(0)) {
m_contentView.setAutocompleting(true);
}
}
bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIndexToUpdate) {
// The variable box should be loaded at this point
const char * autocompletionTokenBeginning = nullptr;
const char * autocompletionLocation = const_cast<char *>(cursorLocation());
AutocompletionType type = autocompletionType(autocompletionLocation, &autocompletionTokenBeginning); // Done to get autocompletionTokenBeginning
assert(type == AutocompletionType::EndOfIdentifier);
(void)type; // Silence warnings
VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController();
int textToInsertLength = 0;
bool addParentheses = false;
const char * textToInsert = varBox->autocompletionAlternativeAtIndex(autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength, &addParentheses, nextIndex, currentIndexToUpdate);
if (textToInsert == nullptr) {
return false;
}
if (textToInsertLength > 0) {
// Try to insert the text (this might fail if the buffer is full)
if (!m_contentView.insertTextAtLocation(textToInsert, const_cast<char *>(autocompletionLocation), textToInsertLength)) {
return false;
}
autocompletionLocation += textToInsertLength;
m_contentView.setAutocompletionEnd(autocompletionLocation);
}
// Try to insert the parentheses if needed
const char * parentheses = ScriptNodeCell::k_parentheses;
constexpr int parenthesesLength = 2;
assert(strlen(parentheses) == parenthesesLength);
/* If couldInsertText is false, we should not try to add the parentheses as
* there was already not enough space to add the autocompletion. */
if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast<char *>(autocompletionLocation), parenthesesLength)) {
m_contentView.setAutocompleting(true);
m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength);
}
return true;
}
void PythonTextArea::cycleAutocompletion(bool downwards) {
assert(m_contentView.isAutocompleting());
removeAutocompletionText();
addAutocompletionTextAtIndex(m_autocompletionResultIndex + (downwards ? 1 : -1), &m_autocompletionResultIndex);
}
void PythonTextArea::acceptAutocompletion(bool moveCursorToEndOfAutocompletion) {
assert(m_contentView.isAutocompleting());
// Save the cursor location
const char * previousCursorLocation = cursorLocation();
removeAutocompletion();
m_contentView.pythonDelegate()->variableBoxController()->setSender(this);
m_contentView.pythonDelegate()->variableBoxController()->insertAutocompletionResultAtIndex(m_autocompletionResultIndex);
// insertAutocompletionResultAtIndex already added the autocompletion
// If we did not want to move the cursor, restore its position.
if (!moveCursorToEndOfAutocompletion) {
setCursorLocation(previousCursorLocation);
}
}
}

View File

@@ -9,21 +9,46 @@ class App;
class PythonTextArea : public TextArea {
public:
enum class AutocompletionType : uint8_t {
EndOfIdentifier,
MiddleOfIdentifier,
NoIdentifier
};
PythonTextArea(Responder * parentResponder, App * pythonDelegate, const KDFont * font) :
TextArea(parentResponder, &m_contentView, font),
m_contentView(pythonDelegate, font)
m_contentView(pythonDelegate, font),
m_autocompletionResultIndex(0)
{
}
void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); }
void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); }
bool handleEvent(Ion::Events::Event event) override;
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
/* autocompletionType returns:
* - EndOfIdentifier if there is currently autocompletion, or if the cursor is
* at the end of an identifier,
* - MiddleOfIdentifier is the cursor is in the middle of an identifier,
* - No identifier otherwise.
* The autocompletionLocation can be provided with autocompletionLocation, or
* retreived with autocompletionLocationBeginning and autocompletionLocationEnd. */
AutocompletionType autocompletionType(const char * autocompletionLocation = nullptr, const char ** autocompletionLocationBeginning = nullptr, const char ** autocompletionLocationEnd = nullptr) const;
bool isAutocompleting() const { return m_contentView.isAutocompleting(); }
protected:
class ContentView : public TextArea::ContentView {
public:
ContentView(App * pythonDelegate, const KDFont * font) :
TextArea::ContentView(font),
m_pythonDelegate(pythonDelegate)
m_pythonDelegate(pythonDelegate),
m_autocomplete(false),
m_autocompletionEnd(nullptr)
{
}
App * pythonDelegate() { return m_pythonDelegate; }
void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; }
bool isAutocompleting() const { return m_autocomplete; }
const char * autocompletionEnd() const { assert(m_autocomplete); return m_autocompletionEnd; }
void setAutocompletionEnd(const char * end) { m_autocompletionEnd = end; }
const char * textToAutocomplete() const;
void loadSyntaxHighlighter();
void unloadSyntaxHighlighter();
void clearRect(KDContext * ctx, KDRect rect) const override;
@@ -31,10 +56,19 @@ protected:
KDRect dirtyRectFromPosition(const char * position, bool includeFollowingLines) const override;
private:
App * m_pythonDelegate;
bool m_autocomplete;
const char * m_autocompletionEnd;
};
private:
void removeAutocompletion();
void removeAutocompletionText(); // Just removes the suggested text, not the autocompletion mode
void addAutocompletion();
bool addAutocompletionTextAtIndex(int nextIndex, int * currentIndexToUpdate = nullptr); // Assumes the var box is already loaded
void cycleAutocompletion(bool downwards);
void acceptAutocompletion(bool moveCursorToEndOfAutocompletion);
const ContentView * nonEditableContentView() const override { return &m_contentView; }
ContentView m_contentView;
int m_autocompletionResultIndex;
};
}

View File

@@ -120,7 +120,18 @@ const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText)
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false)
};
const ToolboxMessageTree TurtleModuleChildren[] = {
@@ -141,22 +152,23 @@ const ToolboxMessageTree TurtleModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandIsdown, I18n::Message::PythonTurtleIsdown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWrite, I18n::Message::PythonTurtleWrite),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColor, I18n::Message::PythonTurtleColor, false, I18n::Message::PythonTurtleCommandColorWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColor, I18n::Message::PythonTurtleColor),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColorMode, I18n::Message::PythonTurtleColorMode),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRed, I18n::Message::PythonTurtleRed, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandYellow, I18n::Message::PythonTurtleYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBrown, I18n::Message::PythonTurtleBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWhite, I18n::Message::PythonTurtleWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandOrange, I18n::Message::PythonTurtleOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false)
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false)
};
const ToolboxMessageTree RandomModuleChildren[] = {
@@ -278,9 +290,9 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBackward, I18n::Message::PythonTurtleBackward),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBin, I18n::Message::PythonBin),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBrown, I18n::Message::PythonTurtleBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCeil, I18n::Message::PythonCeil),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandCircle, I18n::Message::PythonTurtleCircle),
@@ -319,8 +331,8 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGoto, I18n::Message::PythonTurtleGoto),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex),
@@ -366,19 +378,19 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMonotonic, I18n::Message::PythonMonotonic, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandOct, I18n::Message::PythonOct),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandOrange, I18n::Message::PythonTurtleOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPendown, I18n::Message::PythonTurtlePendown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPhase, I18n::Message::PythonPhase),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantPi, I18n::Message::PythonConstantPi, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRadians, I18n::Message::PythonRadians),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
@@ -387,7 +399,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStartStop, I18n::Message::PythonRangeStartStop),
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::PythonCommandColorRed, I18n::Message::PythonColorRed, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound),
@@ -411,8 +423,9 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWhite, I18n::Message::PythonTurtleWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandYellow, I18n::Message::PythonTurtleYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWrite, I18n::Message::PythonTurtleWrite),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImag, I18n::Message::PythonImag, false, I18n::Message::PythonCommandImagWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReal, I18n::Message::PythonReal, false, I18n::Message::PythonCommandRealWithoutArg)
};
@@ -465,6 +478,20 @@ PythonToolbox::PythonToolbox() :
{
}
const ToolboxMessageTree * PythonToolbox::moduleChildren(const char * name, int * numberOfNodes) const {
for (ToolboxMessageTree t : modulesChildren) {
if (strcmp(I18n::translate(t.label()), name) == 0) {
const int childrenCount = t.numberOfChildren();
if (numberOfNodes != nullptr) {
*numberOfNodes = childrenCount;
}
assert(childrenCount > 0);
return static_cast<const ToolboxMessageTree *>(t.childAtIndex(0));
}
}
return nullptr;
}
bool PythonToolbox::handleEvent(Ion::Events::Event event) {
if (Toolbox::handleEvent(event)) {
return true;
@@ -490,7 +517,7 @@ KDCoordinate PythonToolbox::rowHeight(int j) {
* We thus decided to compute the real height only for the ifStatement
* children of the toolbox, which is the only menu that has special height
* rows. */
const ToolboxMessageTree * messageTree = static_cast<const ToolboxMessageTree *>(m_messageTreeModel->children(j));
const ToolboxMessageTree * messageTree = static_cast<const ToolboxMessageTree *>(m_messageTreeModel->childAtIndex(j));
return k_font->stringSize(I18n::translate(messageTree->label())).height() + 2*Metric::TableCellVerticalMargin + (messageTree->text() == I18n::Message::Default ? 0 : Toolbox::rowHeight(j));
}
return Toolbox::rowHeight(j);
@@ -498,7 +525,7 @@ KDCoordinate PythonToolbox::rowHeight(int j) {
bool PythonToolbox::selectLeaf(int selectedRow) {
m_selectableTableView.deselectTable();
ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->children(selectedRow);
ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow);
const char * editedText = I18n::translate(node->insertedText());
// strippedEditedText array needs to be in the same scope as editedText
char strippedEditedText[k_maxMessageSize];
@@ -539,7 +566,7 @@ void PythonToolbox::scrollToLetter(char letter) {
char lowerLetter = tolower(letter);
int index = -1;
for (int i = 0; i < m_messageTreeModel->numberOfChildren(); i++) {
char l = tolower(I18n::translate(m_messageTreeModel->children(i)->label())[0]);
char l = tolower(I18n::translate(m_messageTreeModel->childAtIndex(i)->label())[0]);
if (l == lowerLetter) {
index = i;
break;

View File

@@ -10,7 +10,11 @@ namespace Code {
class PythonToolbox : public Toolbox {
public:
// PythonToolbox
PythonToolbox();
const ToolboxMessageTree * moduleChildren(const char * name, int * numberOfNodes) const;
// Toolbox
bool handleEvent(Ion::Events::Event event) override;
const ToolboxMessageTree * rootModel() const override;
protected:

View File

@@ -65,22 +65,54 @@ bool Script::nameCompliant(const char * name) {
return false;
}
bool Script::importationStatus() const {
assert(!isNull());
Data d = value();
return (((char *)d.buffer)[0] == 1);
uint8_t * StatusFromData(Script::Data d) {
return const_cast<uint8_t *>(static_cast<const uint8_t *>(d.buffer));
}
void Script::toggleImportationStatus() {
bool Script::autoImportationStatus() const {
return getStatutBit(k_autoImportationStatusMask);
}
void Script::toggleAutoimportationStatus() {
assert(!isNull());
Data d = value();
((char *)d.buffer)[0] = (((char *)d.buffer)[0] == 1 ? 0 : 1);
*StatusFromData(d) ^= k_autoImportationStatusMask;
setValue(d);
}
const char * Script::scriptContent() const {
const char * Script::content() const {
Data d = value();
return ((const char *)d.buffer) + StatusSize();
}
bool Script::fetchedFromConsole() const {
return getStatutBit(k_fetchedFromConsoleMask);
}
void Script::setFetchedFromConsole(bool fetched) {
setStatutBit(k_fetchedFromConsoleMask, k_fetchedFromConsoleOffset, fetched);
}
bool Script::fetchedForVariableBox() const {
return getStatutBit(k_fetchedForVariableBoxMask);
}
void Script::setFetchedForVariableBox(bool fetched) {
setStatutBit(k_fetchedForVariableBoxMask, k_fetchedForVariableBoxOffset, fetched);
}
bool Script::getStatutBit(uint8_t mask) const {
assert(!isNull());
Data d = value();
return (const char *)d.buffer + k_importationStatusSize;
return ((*StatusFromData(d)) & mask) != 0;
}
void Script::setStatutBit(uint8_t mask, uint8_t offset, bool statusBit) {
assert(!isNull());
Data d = value();
uint8_t * status = StatusFromData(d);
*status = ((*status) & ~mask) | (static_cast<uint8_t>(statusBit) << offset); //TODO Create and use a bit operations library
setValue(d);
}
}

View File

@@ -5,16 +5,36 @@
namespace Code {
/* Record : | Total Size | Name | Body |
* Script: | AutoImportationStatus | Content |*/
/* Record: | Size | Name | Body |
* Script: | | | Status | Content |
*
*
* |FetchedForVariableBoxBit
* Status is one byte long: xxxxxxxx
* ^ ^
* FetchedFromConsoleBit AutoImportationBit
*
* AutoImportationBit is 1 if the script should be auto imported when the
* console opens.
*
* FetchedFromConsoleBit is 1 if its content has been fetched from the console,
* so we can retrieve the correct variables afterwards in the variable box.
*
* FetchedForVariableBoxBit is used to prevent circular importation problems,
* such as scriptA importing scriptB, which imports scriptA. Once we get the
* variables from a script to put them in the variable box, we switch the bit to
* 1 and won't reload it afterwards. */
class Script : public Ion::Storage::Record {
private:
// Default script names are chosen between script1 and script99
static constexpr int k_maxNumberOfDefaultScriptNames = 99;
static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max
// See the comment at the beginning of the file
static constexpr size_t k_statusSize = 1;
public:
static constexpr size_t k_importationStatusSize = 1;
static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1;
/* 6 = strlen("script")
* k_defaultScriptNameNumberMaxSize = maxLength of integers between 1 and 99
@@ -22,11 +42,29 @@ public:
static bool DefaultName(char buffer[], size_t bufferSize);
static bool nameCompliant(const char * name);
static constexpr size_t StatusSize() { return k_statusSize; }
Script(Ion::Storage::Record r) : Record(r) {}
bool importationStatus() const;
void toggleImportationStatus();
const char * scriptContent() const;
Script(Ion::Storage::Record r = Ion::Storage::Record()) : Record(r) {}
bool autoImportationStatus() const;
void toggleAutoimportationStatus();
const char * content() const;
/* Fetched status */
bool fetchedFromConsole() const;
void setFetchedFromConsole(bool fetched);
bool fetchedForVariableBox() const;
void setFetchedForVariableBox(bool fetched);
private:
static constexpr uint8_t k_autoImportationStatusMask = 0b1;
static constexpr uint8_t k_fetchedForVariableBoxOffset = 7;
static constexpr uint8_t k_fetchedFromConsoleOffset = 6;
static constexpr uint8_t k_fetchedForVariableBoxMask = 0b1 << k_fetchedForVariableBoxOffset;
static constexpr uint8_t k_fetchedFromConsoleMask = 0b1 << k_fetchedFromConsoleOffset;
bool getStatutBit(uint8_t offset) const;
void setStatutBit(uint8_t mask, uint8_t offset, bool value);
};
}

View File

@@ -1,33 +1,35 @@
#ifndef CODE_SCRIPT_NODE_H
#define CODE_SCRIPT_NODE_H
#include <stddef.h>
#include <stdint.h>
namespace Code {
class ScriptNode {
public:
enum class Type {
Function = 0,
Variable = 1
enum class Type : bool {
WithoutParentheses,
WithParentheses
};
ScriptNode() :
m_type(Type::Function), m_name(nullptr), m_scriptIndex(0) {}
static ScriptNode FunctionNode(const char * name, uint16_t scriptIndex) {
return ScriptNode(Type::Function, name, scriptIndex);
}
static ScriptNode VariableNode(const char * name, uint16_t scriptIndex) {
return ScriptNode(Type::Variable, name, scriptIndex);
}
ScriptNode(Type type = Type::WithoutParentheses, const char * name = nullptr, int nameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr) :
m_type(type),
m_name(name),
m_nodeSourceName(nodeSourceName),
m_description(description),
m_nameLength(nameLength)
{}
Type type() const { return m_type; }
const char * name() const { return m_name; }
uint16_t scriptIndex() const { return m_scriptIndex; }
int nameLength() const { return static_cast<int>(m_nameLength); }
const char * nodeSourceName() const { return m_nodeSourceName; }
const char * description() const { return m_description; }
private:
ScriptNode(Type type, const char * name, uint16_t scriptIndex) :
m_type(type), m_name(name), m_scriptIndex(scriptIndex) {}
Type m_type;
const char * m_name;
uint16_t m_scriptIndex;
const char * m_nodeSourceName;
const char * m_description;
size_t m_nameLength;
};
}

View File

@@ -7,47 +7,51 @@ namespace Code {
constexpr char ScriptNodeCell::k_parentheses[];
constexpr char ScriptNodeCell::k_parenthesesWithEmpty[];
ScriptNodeCell::ScriptNodeView::ScriptNodeView() :
HighlightCell(),
m_scriptNode(nullptr),
m_scriptStore(nullptr)
{
}
void ScriptNodeCell::ScriptNodeView::setScriptNode(ScriptNode * scriptNode) {
m_scriptNode = scriptNode;
}
void ScriptNodeCell::ScriptNodeView::setScriptStore(ScriptStore * scriptStore) {
m_scriptStore = scriptStore;
}
void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->drawString(m_scriptNode->name(), KDPoint(0, Metric::TableCellVerticalMargin), k_font, Palette::CodeText, isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground);
KDSize nameSize = k_font->stringSize(m_scriptNode->name());
if (m_scriptNode->type() == ScriptNode::Type::Function) {
ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), Metric::TableCellVerticalMargin), k_font, Palette::CodeText, isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground);
const KDColor backgroundColor = isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground;
// If it exists, draw the description name.
const char * descriptionName = m_scriptNode->description();
if (descriptionName != nullptr) {
ctx->drawString(descriptionName, KDPoint(0, m_frame.height() - k_bottomMargin - k_font->glyphSize().height()), k_font, Palette::GreyDark, backgroundColor);
}
// Draw the node name
const char * nodeName = m_scriptNode->name();
const int nodeNameLength = m_scriptNode->nameLength();
KDSize nameSize = k_font->stringSize(nodeName, nodeNameLength);
const KDCoordinate nodeNameY = k_topMargin;
ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, KDColorBlack, backgroundColor, nodeNameLength);
// If it is needed, draw the parentheses
if (m_scriptNode->type() == ScriptNode::Type::WithParentheses) {
ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, KDColorBlack, backgroundColor);
}
/* If it exists, draw the source name. If it did not fit, we would have put
* nullptr at the node creation. */
const char * sourceName = m_scriptNode->nodeSourceName();
if (sourceName != nullptr) {
KDSize sourceNameSize = k_font->stringSize(sourceName);
ctx->drawString(sourceName, KDPoint(m_frame.width() - sourceNameSize.width(), nodeNameY), k_font, Palette::CodeText, backgroundColor);
}
ctx->drawString(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName(), KDPoint(0, Metric::TableCellVerticalMargin + nameSize.height() + k_verticalMargin), k_font, Palette::SecondaryText, isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground);
}
KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const {
if (m_scriptNode->name() == nullptr) {
return KDSizeZero;
}
KDSize size1 = k_font->stringSize(m_scriptNode->name());
KDSize size2 = k_font->stringSize(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName());
KDSize size3 = KDSizeZero;
if (m_scriptNode->type() == ScriptNode::Type::Function) {
size3 = k_font->stringSize(ScriptNodeCell::k_parentheses);
}
return KDSize(size1.width() + size3.width() > size2.width() ? size1.width() + size3.width() : size2.width(), Metric::TableCellVerticalMargin + size1.width() + k_verticalMargin + size2.width());
return KDSize(
k_optimalWidth,
m_scriptNode->description() == nullptr ? k_simpleItemHeight : k_complexItemHeight);
}
ScriptNodeCell::ScriptNodeCell() :
TableCell(),
m_scriptNodeView()
{
bool ScriptNodeCell::CanDisplayNameAndSource(int nameLength, const char * source) {
if (source == nullptr) {
return true;
}
assert(nameLength > 0);
const KDFont * font = ScriptNodeView::k_font;
return font->glyphSize().width()*(nameLength + 1) + font->stringSize(source).width() <= ScriptNodeView::k_optimalWidth; // + 1 for the separating space
}
void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) {
@@ -55,10 +59,6 @@ void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) {
reloadCell();
}
void ScriptNodeCell::setScriptStore(ScriptStore * scriptStore) {
m_scriptNodeView.setScriptStore(scriptStore);
}
void ScriptNodeCell::setHighlighted(bool highlight) {
TableCell::setHighlighted(highlight);
m_scriptNodeView.setHighlighted(highlight);

View File

@@ -10,9 +10,18 @@ namespace Code {
class ScriptNodeCell : public TableCell {
public:
ScriptNodeCell();
static_assert('\x11' == UCodePointEmpty, "Unicode error");
constexpr static char k_parentheses[] = "()";
constexpr static char k_parenthesesWithEmpty[] = "(\x11)";
constexpr static KDCoordinate k_simpleItemHeight = 27;
constexpr static KDCoordinate k_complexItemHeight = 42;
ScriptNodeCell() :
TableCell(),
m_scriptNodeView()
{}
void setScriptNode(ScriptNode * node);
void setScriptStore(ScriptStore * scriptStore);
static bool CanDisplayNameAndSource(int nameLength, const char * source);
/* TableCell */
View * labelView() const override { return const_cast<View *>(static_cast<const View *>(&m_scriptNodeView)); }
@@ -22,26 +31,25 @@ public:
void reloadCell() override;
const char * text() const override { return m_scriptNodeView.text(); }
static_assert('\x11' == UCodePointEmpty, "Unicode error");
constexpr static char k_parentheses[] = "()";
constexpr static char k_parenthesesWithEmpty[] = "(\x11)";
protected:
class ScriptNodeView : public HighlightCell {
public:
ScriptNodeView();
void setScriptNode(ScriptNode * scriptNode);
void setScriptStore(ScriptStore * scriptStore);
constexpr static const KDFont * k_font = KDFont::SmallFont;
constexpr static KDCoordinate k_optimalWidth = Ion::Display::Width - Metric::PopUpLeftMargin - Metric::PopUpRightMargin;
ScriptNodeView() :
HighlightCell(),
m_scriptNode(nullptr)
{}
void setScriptNode(ScriptNode * node) { m_scriptNode = node; }
void drawRect(KDContext * ctx, KDRect rect) const override;
virtual KDSize minimalSizeForOptimalDisplay() const override;
const char * text() const override {
return m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName();
return m_scriptNode->description();
}
private:
constexpr static const KDFont * k_font = KDFont::SmallFont;
constexpr static KDCoordinate k_verticalMargin = 7;
constexpr static KDCoordinate k_bottomMargin = 5;
constexpr static KDCoordinate k_topMargin = k_bottomMargin + k_separatorThickness;
ScriptNode * m_scriptNode;
ScriptStore * m_scriptStore;
};
ScriptNodeView m_scriptNodeView;
};

View File

@@ -45,7 +45,7 @@ bool ScriptParameterController::handleEvent(Ion::Events::Event event) {
m_menuController->renameSelectedScript();
return true;
case 2:
m_script.toggleImportationStatus();
m_script.toggleAutoimportationStatus();
m_selectableTableView.reloadData();
m_menuController->reloadConsole();
Container::activeApp()->setFirstResponder(&m_selectableTableView);
@@ -95,7 +95,7 @@ HighlightCell * ScriptParameterController::reusableCell(int index) {
void ScriptParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (cell == &m_autoImportScript) {
SwitchView * switchView = (SwitchView *)m_autoImportScript.accessoryView();
switchView->setState(m_script.importationStatus());
switchView->setState(m_script.autoImportationStatus());
} else if (cell == &m_size) {
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)cell;
GetScriptSize(myCell);

View File

@@ -1,23 +1,14 @@
#include "script_store.h"
#include "string.h"
#include <stddef.h>
extern "C" {
#include "py/lexer.h"
#include "py/nlr.h"
}
namespace Code {
constexpr char ScriptStore::k_scriptExtension[];
bool ScriptStore::ScriptNameIsFree(const char * baseName) {
return Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(baseName, k_scriptExtension).isNull();
return ScriptBaseNamed(baseName).isNull();
}
ScriptStore::ScriptStore()
{
ScriptStore::ScriptStore() {
addScriptFromTemplate(ScriptTemplate::Squares());
addScriptFromTemplate(ScriptTemplate::Parabola());
addScriptFromTemplate(ScriptTemplate::Mandelbrot());
@@ -34,124 +25,39 @@ bool ScriptStore::isFull() {
return Ion::Storage::sharedStorage()->availableSize() < k_fullFreeSpaceSizeLimit;
}
void ScriptStore::scanScriptsForFunctionsAndVariables(void * context, ScanCallback storeFunction, ScanCallback storeVariable) {
for (int scriptIndex = 0; scriptIndex < numberOfScripts(); scriptIndex++) {
//Don't scan not loaded script
if (!scriptAtIndex(scriptIndex).importationStatus()){
continue;
}
// Handle lexer or parser errors with nlr.
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
const char * scriptContent = scriptAtIndex(scriptIndex).scriptContent();
if (scriptContent == nullptr) {
continue;
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false);
mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT);
mp_parse_node_t pn = parseTree.root;
if (!MP_PARSE_NODE_IS_STRUCT(pn)) {
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
// The script is only a single function definition.
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_functionDefinitionParseNodeStructKind) {
const char * id = structID(pns);
if (id == nullptr) {
continue;
}
storeFunction(context, id, scriptIndex);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
// The script is only a single global variable definition.
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_expressionStatementParseNodeStructKind) {
const char * id = structID(pns);
if (id == nullptr) {
continue;
}
storeVariable(context, id, scriptIndex);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) != k_fileInput2ParseNodeStructKind) {
// The script node is not of type "file_input_2", thus it will not have main
// structures of the wanted type.
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
// Count the number of structs in child nodes.
size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (size_t i = 0; i < n; i++) {
mp_parse_node_t child = pns->nodes[i];
if (MP_PARSE_NODE_IS_STRUCT(child)) {
mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child);
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_functionDefinitionParseNodeStructKind) {
const char * id = structID(child_pns);
if (id == nullptr) {
continue;
}
storeFunction(context, id, scriptIndex);
} else if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_expressionStatementParseNodeStructKind) {
const char * id = structID(child_pns);
if (id == nullptr) {
continue;
}
storeVariable(context, id, scriptIndex);
}
}
}
mp_parse_tree_clear(&parseTree);
nlr_pop();
}
}
}
const char * ScriptStore::contentOfScript(const char * name) {
Script script = scriptNamed(name);
const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched) {
Script script = ScriptNamed(name);
if (script.isNull()) {
return nullptr;
}
return script.scriptContent();
if (markAsFetched) {
script.setFetchedFromConsole(true);
}
return script.content();
}
void ScriptStore::clearVariableBoxFetchInformation() {
// TODO optimize fetches
const int scriptsCount = numberOfScripts();
for (int i = 0; i < scriptsCount; i++) {
scriptAtIndex(i).setFetchedForVariableBox(false);
}
}
void ScriptStore::clearConsoleFetchInformation() {
// TODO optimize fetches
const int scriptsCount = numberOfScripts();
for (int i = 0; i < scriptsCount; i++) {
scriptAtIndex(i).setFetchedFromConsole(false);
}
}
Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * scriptTemplate) {
size_t valueSize = strlen(scriptTemplate->content())+1+1;// scriptcontent size + 1 char for the importation status
size_t valueSize = Script::StatusSize() + strlen(scriptTemplate->content()) + 1; // (auto importation status + content fetched status) + scriptcontent size + null-terminating char
assert(Script::nameCompliant(scriptTemplate->name()));
Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithFullName(scriptTemplate->name(), scriptTemplate->value(), valueSize);
assert(err != Script::ErrorStatus::NonCompliantName);
return err;
}
const char * ScriptStore::structID(mp_parse_node_struct_t *structNode) {
// Find the id child node, which stores the struct's name
size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode);
if (childNodesCount < 1) {
return nullptr;
}
mp_parse_node_t child = structNode->nodes[0];
if (MP_PARSE_NODE_IS_LEAF(child)
&& MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID)
{
uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child);
return qstr_str(arg);
}
return nullptr;
}
}

View File

@@ -23,8 +23,11 @@ public:
Script scriptAtIndex(int index) {
return Script(Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(k_scriptExtension, index));
}
Script scriptNamed(const char * name) {
return Script(Ion::Storage::sharedStorage()->recordNamed(name));
static Script ScriptNamed(const char * fullName) {
return Script(Ion::Storage::sharedStorage()->recordNamed(fullName));
}
static Script ScriptBaseNamed(const char * baseName) {
return Script(Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(baseName, k_scriptExtension));
}
int numberOfScripts() {
return Ion::Storage::sharedStorage()->numberOfRecordsWithExtension(k_scriptExtension);
@@ -35,12 +38,10 @@ public:
void deleteAllScripts();
bool isFull();
/* Provide scripts content information */
typedef void (* ScanCallback)(void * context, const char * p, int n);
void scanScriptsForFunctionsAndVariables(void * context, ScanCallback storeFunction,ScanCallback storeVariable);
/* MicroPython::ScriptProvider */
const char * contentOfScript(const char * name) override;
const char * contentOfScript(const char * name, bool markAsFetched) override;
void clearVariableBoxFetchInformation();
void clearConsoleFetchInformation();
Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate);
private:
@@ -51,10 +52,6 @@ private:
* importation status (1 char), the default content "from math import *\n"
* (20 char) and 10 char of free space. */
static constexpr int k_fullFreeSpaceSizeLimit = sizeof(Ion::Storage::record_size_t)+Script::k_defaultScriptNameMaxSize+k_scriptExtensionLength+1+20+10;
static constexpr size_t k_fileInput2ParseNodeStructKind = 1;
static constexpr size_t k_functionDefinitionParseNodeStructKind = 3;
static constexpr size_t k_expressionStatementParseNodeStructKind = 5;
const char * structID(mp_parse_node_struct_t *structNode);
};
}

View File

@@ -1,6 +1,8 @@
#ifndef CODE_SCRIPT_TEMPLATE_H
#define CODE_SCRIPT_TEMPLATE_H
#include "script.h"
namespace Code {
class ScriptTemplate {
@@ -12,11 +14,11 @@ public:
static const ScriptTemplate * Polynomial();
static const ScriptTemplate * Parabola();
const char * name() const { return m_name; }
const char * content() const { return m_value+1; }
const char * content() const { return m_value + Script::StatusSize(); }
const char * value() const { return m_value; }
private:
const char * m_name;
const char * m_value; // hold the 'importation status' flag concatenate with the script content
const char * m_value; // holds the 'importation status' and 'current importation status' flags concatenated with the script content
};
}

View File

@@ -0,0 +1,70 @@
#include <quiz.h>
#include "../script_store.h"
#include "../variable_box_controller.h"
#include <string.h>
using namespace Code;
void assert_variables_are(const char * script, const char * nameToComplete, const char * * expectedVariables, int expectedVariablesCount) {
// Clean the store
ScriptStore store;
store.deleteAllScripts();
// Add the script
store.addNewScript();
constexpr int dataBufferSize = 500;
char dataBuffer[dataBufferSize];
Ion::Storage::Record::Data data = {
.buffer = &dataBuffer,
.size = dataBufferSize
};
strlcpy(dataBuffer, script, dataBufferSize);
constexpr int scriptIndex = 0;
store.scriptAtIndex(scriptIndex).setValue(data);
// Load the variable box
VariableBoxController varBox(&store);
const size_t nameToCompleteLength = strlen(nameToComplete);
varBox.loadFunctionsAndVariables(scriptIndex, nameToComplete, nameToCompleteLength);
// Compare the variables
int index = 0; // Index to make sure we are not cycling through the results
int textToInsertLength;
bool addParentheses;
for (int i = 0; i < expectedVariablesCount; i++) {
quiz_assert(i == index);
const char * autocompletionI = varBox.autocompletionAlternativeAtIndex(
nameToCompleteLength,
&textToInsertLength,
&addParentheses,
i,
&index);
quiz_assert(i == index); // If false, the autompletion has cycled: there are not as many results as expected
quiz_assert(strncmp(*(expectedVariables + i), autocompletionI - nameToCompleteLength, textToInsertLength + nameToCompleteLength) == 0);
index++;
}
varBox.autocompletionAlternativeAtIndex(
strlen(nameToComplete),
&textToInsertLength,
&addParentheses,
index,
&index);
/* Assert the autocompletion has cycles: otherwise, there are more results
* than expected. */
quiz_assert(index == 0);
}
QUIZ_CASE(variable_box_controller) {
const char * expectedVariables[] = {
"froo",
"from",
"frozenset()"
};
// FIXME This test does not load imported variables for now
assert_variables_are(
"\x01 from math import *\nfroo=3",
"fr",
expectedVariables,
sizeof(expectedVariables) / sizeof(const char *));
}

View File

@@ -0,0 +1,4 @@
Functions = "Funzioni"
Catalog = "Catalogo"
Modules = "Moduli"
LoopsAndTests = "Loops e test"

View File

@@ -0,0 +1,4 @@
Functions = "Functies"
Catalog = "Catalogus"
Modules = "Modules"
LoopsAndTests = "Loops and tests"

View File

@@ -1,6 +1,6 @@
Functions = "Functions"
Catalog = "Catalog"
Modules = "Modules"
LoopsAndTests = "Loops and tests"
Functions = "Funções"
Catalog = "Catálogo"
Modules = "Módulos"
LoopsAndTests = "Laços e testes"
Files = "Files"
Exceptions = "Exceptions"

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,17 @@
#ifndef CODE_VARIABLE_BOX_CONTROLLER_H
#define CODE_VARIABLE_BOX_CONTROLLER_H
#include <escher.h>
#include <apps/alternate_empty_nested_menu_controller.h>
#include <escher/message_table_cell.h>
#include <escher/toolbox_message_tree.h>
#include "script_node.h"
#include "script_node_cell.h"
#include "script_store.h"
#include "variable_box_empty_controller.h"
namespace Code {
class VariableBoxController : public NestedMenuController {
class VariableBoxController : public AlternateEmptyNestedMenuController {
public:
VariableBoxController(ScriptStore * scriptStore);
@@ -16,28 +19,98 @@ public:
bool handleEvent(Ion::Events::Event event) override;
void didEnterResponderChain(Responder * previousFirstResponder) override;
/* ListViewDataSource */
/* TableViewDataSource */
KDCoordinate rowHeight(int j) override;
int numberOfRows() const override;
HighlightCell * reusableCell(int index, int type) override;
int reusableCellCount(int type) override;
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
int typeAtLocation(int i, int j) override;
/* ListViewDataSource */
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
/* SelectableTableViewDelegate */
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override;
//AlternateEmptyNestedMenuController
ViewController * emptyViewController() override { return &m_variableBoxEmptyController; }
/* VariableBoxController */
void loadFunctionsAndVariables();
void setDisplaySubtitles(bool display) { m_displaySubtitles = display; }
void loadFunctionsAndVariables(int scriptIndex, const char * textToAutocomplete, int textToAutocompleteLength);
const char * autocompletionAlternativeAtIndex(int textToAutocompleteLength, int * textToInsertLength, bool * addParentheses, int index, int * indexToUpdate = nullptr);
void loadVariablesImportedFromScripts();
void empty();
void insertAutocompletionResultAtIndex(int index);
private:
constexpr static int k_maxScriptObjectNameSize = 100;
constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40
constexpr static int k_maxScriptNodesCount = 32;
HighlightCell * leafCellAtIndex(int index) override;
HighlightCell * nodeCellAtIndex(int index) override { return nullptr; }
constexpr static size_t k_maxNumberOfDisplayedItems = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin) / ScriptNodeCell::k_simpleItemHeight + 2; // +2 if the cells are cropped on top and at the bottom
constexpr static size_t k_maxScriptNodesCount = 32; // Chosen without particular reasons
constexpr static int k_totalBuiltinNodesCount = 107;
constexpr static uint8_t k_scriptOriginsCount = 3;
constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable
constexpr static uint8_t k_itemCellType = LeafCellType; // So that upper class NestedMenuController knows it's a leaf
constexpr static KDCoordinate k_subtitleRowHeight = 23;
enum class NodeOrigin : uint8_t {
CurrentScript = 0,
Builtins = 1,
Importation = 2
};
/* Returns:
* - a negative int if the node name is before name in alphabetical
* order
* - 0 if they are equal
* - a positive int if it is after in alphabetical order.
* strictlyStartsWith is set to True if the node name starts with name but
* they are not equal.*/
static int NodeNameCompare(ScriptNode * node, const char * name, int nameLength, bool * strictlyStartsWith = nullptr);
// Nodes and nodes count
static size_t MaxNodesCountForOrigin(NodeOrigin origin) {
return origin == NodeOrigin::Builtins ? k_totalBuiltinNodesCount : k_maxScriptNodesCount;
}
int nodesCountForOrigin(NodeOrigin origin) const;
size_t * nodesCountPointerForOrigin(NodeOrigin origin);
ScriptNode * nodesForOrigin(NodeOrigin origin);
ScriptNode * scriptNodeAtIndex(int index);
// Cell getters
int typeAndOriginAtLocation(int i, NodeOrigin * resultOrigin = nullptr, int * cumulatedOriginsCount = nullptr) const;
// NestedMenuController
HighlightCell * leafCellAtIndex(int index) override { assert(false); return nullptr; }
HighlightCell * nodeCellAtIndex(int index) override { assert(false); return nullptr; }
bool selectLeaf(int rowIndex) override;
void insertTextInCaller(const char * text);
void addFunctionAtIndex(const char * functionName, int scriptIndex);
void addVariableAtIndex(const char * variableName, int scriptIndex);
ScriptNode m_scriptNodes[k_maxScriptNodesCount];
int m_scriptNodesCount;
void insertTextInCaller(const char * text, int textLength = -1);
// Loading
void loadBuiltinNodes(const char * textToAutocomplete, int textToAutocompleteLength);
void loadImportedVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength);
void loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength);
void loadGlobalAndImportedVariablesInScriptAsImported(Script script, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true);
// Returns true if this was an import structure
bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true);
const char * importationSourceNameFromNode(mp_parse_node_t & node);
bool importationSourceIsModule(const char * sourceName, const ToolboxMessageTree * * moduleChildren = nullptr, int * numberOfModuleChildren = nullptr);
bool importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retreivedScript = nullptr);
bool addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength);
/* Add a node if it completes the text to autocomplete and if it is not
* already contained in the variable box. The returned boolean means we
* should escape the node scanning process (due to the lexicographical order
* or full node table). */
bool addNodeIfMatches(const char * textToAutocomplete, int textToAutocompleteLength, ScriptNode::Type type, NodeOrigin origin, const char * nodeName, int nodeNameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr);
VariableBoxEmptyController m_variableBoxEmptyController;
ScriptNode m_currentScriptNodes[k_maxScriptNodesCount];
ScriptNode m_builtinNodes[k_totalBuiltinNodesCount];
ScriptNode m_importedNodes[k_maxScriptNodesCount];
ScriptNodeCell m_itemCells[k_maxNumberOfDisplayedItems];
MessageTableCell m_subtitleCells[k_scriptOriginsCount];
ScriptStore * m_scriptStore;
ScriptNodeCell m_leafCells[k_maxNumberOfDisplayedRows];
size_t m_currentScriptNodesCount;
size_t m_builtinNodesCount;
size_t m_importedNodesCount;
int m_shortenResultCharCount; // This is used to send only the completing text when we are autocompleting
bool m_displaySubtitles;
};
}

View File

@@ -0,0 +1,13 @@
#include "variable_box_empty_controller.h"
#include <apps/i18n.h>
namespace Code {
VariableBoxEmptyController::VariableBoxEmptyView::VariableBoxEmptyView() :
::ModalViewEmptyController::ModalViewEmptyView()
{
initMessageViews();
m_message.setMessage(I18n::Message::NoWordAvailableHere);
}
}

View File

@@ -0,0 +1,34 @@
#ifndef APPS_CODE_VARIABLE_BOX_EMPTY_CONTROLLER_H
#define APPS_CODE_VARIABLE_BOX_EMPTY_CONTROLLER_H
#include <escher/modal_view_empty_controller.h>
namespace Code {
class VariableBoxEmptyController : public ModalViewEmptyController {
public:
VariableBoxEmptyController() :
ModalViewEmptyController(),
m_view()
{}
// View Controller
View * view() override { return &m_view; }
private:
class VariableBoxEmptyView : public ModalViewEmptyController::ModalViewEmptyView {
public:
constexpr static int k_numberOfMessages = 1;
VariableBoxEmptyView();
private:
int numberOfMessageTextViews() const override { return k_numberOfMessages; }
MessageTextView * messageTextViewAtIndex(int index) override {
assert(index >= 0 && index < k_numberOfMessages);
return &m_message;
}
MessageTextView m_message;
};
VariableBoxEmptyView m_view;
};
}
#endif

View File

@@ -6,7 +6,10 @@
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()) {
if ((GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::EN
&& GlobalPreferences::sharedGlobalPreferences()->language() != I18n::Language::NL)
|| GlobalPreferences::sharedGlobalPreferences()->isInExamMode())
{
return 1;
}
return 2;

View File

@@ -33,13 +33,6 @@ app_graph_src = $(addprefix apps/graph/,\
apps_src += $(app_graph_src)
i18n_files += $(addprefix apps/graph/,\
base.de.i18n\
base.en.i18n\
base.es.i18n\
base.fr.i18n\
base.pt.i18n\
base.hu.i18n\
)
i18n_files += $(call i18n_without_universal_for,graph/base)
$(eval $(call depends_on_image,apps/graph/app.cpp,apps/graph/graph_icon.png))

View File

@@ -81,9 +81,9 @@ CodePoint App::XNT() {
}
NestedMenuController * App::variableBoxForInputEventHandler(InputEventHandler * textInput) {
VariableBoxController * varBox = AppsContainer::sharedAppsContainer()->variableBoxController();
MathVariableBoxController * varBox = AppsContainer::sharedAppsContainer()->variableBoxController();
varBox->setSender(textInput);
varBox->lockDeleteEvent(VariableBoxController::Page::Function);
varBox->lockDeleteEvent(MathVariableBoxController::Page::Function);
return varBox;
}

33
apps/graph/base.it.i18n Normal file
View File

@@ -0,0 +1,33 @@
FunctionApp = "Funzioni"
FunctionAppCapital = "FUNZIONI"
FunctionTab = "Funzioni"
AddFunction = "Aggiungi funzione"
DeleteFunction = "Cancella funzione"
CurveType = "Tipo di curva"
CartesianType = "Cartesiana "
PolarType = "Polare "
ParametricType = "Parametrica "
IntervalT = "Intervallo t"
IntervalTheta = "Intervallo θ"
IntervalX = "Intervallo x"
FunctionDomain = "Int. tracciamento"
FunctionColor = "Colore della funzione"
NoFunction = "Nessuna funzione"
NoActivatedFunction = "Nessuna funzione attivata"
PlotOptions = "Opzioni della curva"
Compute = "Calcolare"
Zeros = "Zeri"
Tangent = "Tangente"
Intersection = "Intersezione"
Preimage = "Controimmagine"
SelectLowerBound = "Scegliere il limite inferiore"
SelectUpperBound = "Scegliere il limite superiore"
NoMaximumFound = "Nessun massimo trovato"
NoMinimumFound = "Nessun minimo trovato"
NoZeroFound = "Nessuno zero trovato"
NoIntersectionFound = "Nessuna intersezione trovata"
NoPreimageFound = "Nessuna immagine trovata"
DerivativeFunctionColumn = "Colonna della funzione derivata"
HideDerivativeColumn = "Nascondere la funzione derivata"
AllowedCharactersAZaz09 = "Caratteri consentiti : A-Z, a-z, 0-9, _"
ReservedName = "Nome riservato"

33
apps/graph/base.nl.i18n Normal file
View File

@@ -0,0 +1,33 @@
FunctionApp = "Functies"
FunctionAppCapital = "FUNCTIES"
FunctionTab = "Functies"
AddFunction = "Functie toevoegen"
DeleteFunction = "Functie verwijderen"
CurveType = "Kromme type"
CartesianType = "Cartesiaans "
PolarType = "Polair "
ParametricType = "Parametrisch "
IntervalT = "t interval"
IntervalTheta = "θ interval"
IntervalX = "x interval"
FunctionDomain = "Plotbereik"
FunctionColor = "Functiekleur"
NoFunction = "Geen functie"
NoActivatedFunction = "Geen functie is ingeschakelt"
PlotOptions = "Plot opties"
Compute = "Bereken"
Zeros = "Nulpunten"
Tangent = "Tangens"
Intersection = "Snijpunt"
Preimage = "Inverse beeld"
SelectLowerBound = "Selecteer ondergrens "
SelectUpperBound = "Selecteer bovengrens "
NoMaximumFound = "Geen maximum gevonden"
NoMinimumFound = "Geen minimum gevonden"
NoZeroFound = "Geen nulpunt gevonden"
NoIntersectionFound = "Geen snijpunt gevonden"
NoPreimageFound = "Geen inverse beeld gevonden"
DerivativeFunctionColumn = "Afgeleide functie kolom"
HideDerivativeColumn = "Verberg de afgeleide functie"
AllowedCharactersAZaz09 = "Toegestane tekens: A-Z, a-z, 0-9, _"
ReservedName = "Voorbehouden naam"

View File

@@ -1,5 +1,5 @@
FunctionApp = "Função"
FunctionAppCapital = "FUNÇÃO"
FunctionApp = "Funções"
FunctionAppCapital = "FUNÇÕES"
FunctionTab = "Funções"
AddFunction = "Adicionar uma função"
DeleteFunction = "Eliminar a função"
@@ -16,16 +16,16 @@ NoFunction = "Nenhuma função"
NoActivatedFunction = "Sem função activada"
PlotOptions = "Opções da curva"
Compute = "Calcular"
Zeros = "Raízes"
Zeros = "Zeros"
Tangent = "Tangente"
Intersection = "Intersecção"
Intersection = "Interseção"
Preimage = "Imagem inversa"
SelectLowerBound = "Selecionar limite superior "
SelectUpperBound = "Selecionar limite inferior "
SelectLowerBound = "Selecionar limite inferior"
SelectUpperBound = "Selecionar limite superior"
NoMaximumFound = "Nenhum máximo encontrado"
NoMinimumFound = "Nenhum mínimo encontrado"
NoZeroFound = "Nenhuma raiz encontrada"
NoIntersectionFound = "Nenhuma intersecção encontrada"
NoIntersectionFound = "Nenhuma interseção encontrada"
NoPreimageFound = "Nenhuma imagem inversa encontrada"
DerivativeFunctionColumn = "Coluna da função derivada"
HideDerivativeColumn = "Esconder função derivada"

View File

@@ -27,8 +27,8 @@ void TextFieldFunctionTitleCell::setEditing(bool editing) {
int extensionLength = UTF8Helper::HasCodePoint(previousText, UCodePointGreekSmallLetterTheta) ? Shared::Function::k_parenthesedThetaArgumentByteLength : Shared::Function::k_parenthesedXNTArgumentByteLength;
m_textField.setExtensionLength(extensionLength);
m_textField.setEditing(true);
m_textField.setText(previousText);
m_textField.setDraftTextBufferSize(Poincare::SymbolAbstract::k_maxNameSize+extensionLength);
m_textField.setText(previousText);
}
bool TextFieldFunctionTitleCell::isEditing() const {

19
apps/helpers.mk Normal file
View File

@@ -0,0 +1,19 @@
# i18n helpers
# Should be called as: i18n_for_locale basename locale
define i18n_for_locale
$(addprefix apps/, $(addprefix $(1), $(addprefix ., $(addsuffix .i18n,$(2)))))
endef
# Should be called as: i18n_without_universal_for basename
# Adds the basename.**.i18n for all locales in EPSILON_I18N
define i18n_without_universal_for
$(foreach LOCALE,$(EPSILON_I18N),$(call i18n_for_locale, $(1), $(LOCALE)))
endef
# Should be called as: i18n_with_universal_for basename
# Adds basename.**.i18n for all EPSILON_I18N locales + basename.universal.i18n
define i18n_with_universal_for
$(call i18n_without_universal_for,$(1))
$(call i18n_for_locale,$(1),universal)
endef

View File

@@ -6,11 +6,4 @@ app_home_src = $(addprefix apps/home/,\
apps_src += $(app_home_src)
i18n_files += $(addprefix apps/home/,\
base.de.i18n \
base.en.i18n \
base.es.i18n \
base.fr.i18n \
base.pt.i18n \
base.hu.i18n \
)
i18n_files += $(call i18n_without_universal_for,home/base)

4
apps/home/base.it.i18n Normal file
View File

@@ -0,0 +1,4 @@
Apps = "Applicazioni"
AppsCapital = "APPLICAZIONI"
ForbidenAppInExamMode1 = "Questa applicazione è"
ForbidenAppInExamMode2 = "proibita nella modalità d'esame"

4
apps/home/base.nl.i18n Normal file
View File

@@ -0,0 +1,4 @@
Apps = "Applicaties"
AppsCapital = "APPLICATIES"
ForbidenAppInExamMode1 = "Deze applicatie is"
ForbidenAppInExamMode2 = "uitgesloten in examenstand"

View File

@@ -1,4 +1,4 @@
Apps = "Aplicações"
AppsCapital = "OMEGA"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"
ForbidenAppInExamMode1 = "Esta aplicação é"
ForbidenAppInExamMode2 = "proibida no Modo de Exame"

View File

@@ -2,6 +2,8 @@
#include "app.h"
#include "../apps_container.h"
#include "../global_preferences.h"
#include "../exam_mode_configuration.h"
extern "C" {
#include <assert.h>
}
@@ -65,7 +67,6 @@ Controller::Controller(Responder * parentResponder, SelectableTableViewDataSourc
bool Controller::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
AppsContainer * container = AppsContainer::sharedAppsContainer();
int index = selectionDataSource()->selectedRow()*k_numberOfColumns+selectionDataSource()->selectedColumn()+1;
#ifdef HOME_DISPLAY_EXTERNALS
@@ -93,21 +94,16 @@ bool Controller::handleEvent(Ion::Events::Event event) {
return true;
}
}
} else {
#endif
::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(index);
if (((GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch || GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::NoSymNoText) && selectedSnapshot->descriptor()->examinationLevel() < 2) ||
((GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Standard || GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::NoSym) && selectedSnapshot->descriptor()->examinationLevel() < 1)) {
App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2);
} else {
bool switched = container->switchTo(selectedSnapshot);
assert(switched);
(void) switched; // Silence compilation warning about unused variable.
}
#ifdef HOME_DISPLAY_EXTERNALS
}
#endif
::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(index);
if (ExamModeConfiguration::appIsForbiddenInExamMode(selectedSnapshot->descriptor()->name(), GlobalPreferences::sharedGlobalPreferences()->examMode())) {
App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2);
} else {
bool switched = container->switchTo(selectedSnapshot);
assert(switched);
(void) switched; // Silence compilation warning about unused variable.
}
return true;
}
@@ -227,6 +223,18 @@ void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previo
if (withinTemporarySelection) {
return;
}
/* To prevent the selectable table view to select cells that are unvisible,
* we reselect the previous selected cell as soon as the selected cell is
* unvisible. This trick does not create an endless loop as we ensure not to
* stay on a unvisible cell and to initialize the first cell on a visible one
* (so the previous one is always visible). */
int appIndex = (t->selectedColumn()+t->selectedRow()*k_numberOfColumns)+1;
if (appIndex >= AppsContainer::sharedAppsContainer()->numberOfApps()) {
t->selectCellAtLocation(previousSelectedCellX, previousSelectedCellY);
}
}
void Controller::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
/* If the number of apps (including home) is != 3*n+1, when we display the
* lowest icons, the other(s) are empty. As no icon is thus redrawn on the
* previous ones, the cell is not cleaned. We need to redraw a white rect on
@@ -236,16 +244,7 @@ void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previo
* background complete redrawing but the code is a bit
* clumsy. */
if (t->selectedRow() == numberOfRows()-1) {
m_view.reloadBottomRow(this, this->numberOfIcons(), k_numberOfColumns);
}
/* To prevent the selectable table view to select cells that are unvisible,
* we reselect the previous selected cell as soon as the selected cell is
* unvisible. This trick does not create an endless loop as we ensure not to
* stay on a unvisible cell and to initialize the first cell on a visible one
* (so the previous one is always visible). */
int appIndex = (t->selectedColumn()+t->selectedRow()*k_numberOfColumns)+1;
if (appIndex >= this->numberOfIcons() + 1) {
t->selectCellAtLocation(previousSelectedCellX, previousSelectedCellY);
m_view.reloadBottomRow(this, AppsContainer::sharedAppsContainer()->numberOfApps()-1, k_numberOfColumns);
}
}

View File

@@ -25,6 +25,7 @@ public:
int reusableCellCount() const override;
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override;
void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override;
private:
int numberOfIcons() const;
SelectableTableViewDataSource * selectionDataSource() const;

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