From 131df18b0094b74a11cd2fbb3057d63566856fbe Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 10 Mar 2020 20:54:14 -0400 Subject: [PATCH 01/77] [python] A module can now ask to present a view controller --- apps/code/console_controller.cpp | 5 +++++ apps/code/console_controller.h | 1 + python/port/port.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 5d236b337..c1ce3d886 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -183,6 +183,11 @@ const char * ConsoleController::inputText(const char * prompt) { return text; } +void ConsoleController::displayViewController(ViewController * controller) { + stackViewController()->push(controller); + Container::activeApp()->setFirstResponder(controller); // FIXME: Shouldn't this be in Escher? +} + void ConsoleController::viewWillAppear() { ViewController::viewWillAppear(); loadPythonEnvironment(); diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index a27733f74..1fe9b7d34 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -66,6 +66,7 @@ public: void refreshPrintOutput() override; void printText(const char * text, size_t length) override; const char * inputText(const char * prompt) override; + void displayViewController(ViewController * controller) override; #if EPSILON_GETOPT bool locked() const { diff --git a/python/port/port.h b/python/port/port.h index 63b721336..55441e2fb 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -4,6 +4,7 @@ extern "C" { #include } +#include namespace MicroPython { @@ -21,6 +22,7 @@ public: virtual void displaySandbox() {} virtual void hideSandbox() {} virtual void resetSandbox() {} + virtual void displayViewController(ViewController * controller) {} virtual void printText(const char * text, size_t length) {} virtual void refreshPrintOutput() {} void interrupt(); From 2b73c4c9aa913582d04f3e4d2898625ba75d95b8 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 10 Mar 2020 20:54:42 -0400 Subject: [PATCH 02/77] [apps/code] Quick hacks to allow pushing a view controller --- apps/code/console_controller.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index c1ce3d886..7bb1fc7c8 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -351,12 +351,14 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c } telemetryReportEvent("Console", text); runAndPrintForCommand(text); + Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME if (!sandboxIsDisplayed()) { m_selectableTableView.reloadData(); m_editCell.setEditing(true); textField->setText(""); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); } + Container::activeApp()->setFirstResponder(firstResponder); // FIXME return true; } @@ -436,7 +438,8 @@ void ConsoleController::printText(const char * text, size_t length) { assert(textCutIndex == length - 1); appendTextToOutputAccumulationBuffer(text, length-1); flushOutputAccumulationBufferToStore(); - micropython_port_vm_hook_refresh_print(); + // FIXME: This needs to be done *only* if the console is active! + //micropython_port_vm_hook_refresh_print(); } #if __EMSCRIPTEN__ /* If we called micropython_port_interrupt_if_needed here, we would need to From c99bed69227797e0bcc84b6daeb3181a704339ec Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 10 Mar 2020 20:55:22 -0400 Subject: [PATCH 03/77] [python] Stub a matplotlib module --- python/Makefile | 5 ++ python/port/genhdr/qstrdefs.in.h | 6 +++ python/port/mod/matplotlib/modpyplot.cpp | 17 +++++++ python/port/mod/matplotlib/modpyplot.h | 10 ++++ python/port/mod/matplotlib/modpyplot_table.c | 17 +++++++ .../port/mod/matplotlib/plot_controller.cpp | 0 python/port/mod/matplotlib/plot_controller.h | 47 +++++++++++++++++++ python/port/mod/matplotlib/plot_store.cpp | 1 + python/port/mod/matplotlib/plot_store.h | 33 +++++++++++++ python/port/mod/matplotlib/plot_view.cpp | 13 +++++ python/port/mod/matplotlib/plot_view.h | 18 +++++++ python/port/mpconfigport.h | 2 + 12 files changed, 169 insertions(+) create mode 100644 python/port/mod/matplotlib/modpyplot.cpp create mode 100644 python/port/mod/matplotlib/modpyplot.h create mode 100644 python/port/mod/matplotlib/modpyplot_table.c create mode 100644 python/port/mod/matplotlib/plot_controller.cpp create mode 100644 python/port/mod/matplotlib/plot_controller.h create mode 100644 python/port/mod/matplotlib/plot_store.cpp create mode 100644 python/port/mod/matplotlib/plot_store.h create mode 100644 python/port/mod/matplotlib/plot_view.cpp create mode 100644 python/port/mod/matplotlib/plot_view.h diff --git a/python/Makefile b/python/Makefile index c8d8fa8df..c368be85c 100644 --- a/python/Makefile +++ b/python/Makefile @@ -134,6 +134,11 @@ port_src += $(addprefix python/port/,\ mod/ion/modion_table.cpp \ mod/kandinsky/modkandinsky.cpp \ mod/kandinsky/modkandinsky_table.c \ + mod/matplotlib/modpyplot.cpp \ + mod/matplotlib/modpyplot_table.c \ + mod/matplotlib/plot_controller.cpp \ + mod/matplotlib/plot_store.cpp \ + mod/matplotlib/plot_view.cpp \ mod/time/modtime.c \ mod/time/modtime_table.c \ mod/turtle/modturtle.cpp \ diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 17b4eea5c..be88dc99e 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -73,6 +73,12 @@ Q(fill_rect) Q(get_pixel) Q(set_pixel) +// Matplotlib QSTRs +Q(plot) +Q(pyplot) +Q(show) + + // Turtle QSTRs Q(turtle) Q(forward) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp new file mode 100644 index 000000000..065d6dd5c --- /dev/null +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -0,0 +1,17 @@ +extern "C" { +#include "modpyplot.h" +} +#include "port.h" +#include "plot_controller.h" + +Matplotlib::PlotController sPlotController; + +mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { + // Ensure x and y are arrays + // "Push" x and y on bigger arrays +} + +mp_obj_t modpyplot_show() { + MicroPython::ExecutionEnvironment * env = MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); + env->displayViewController(&sPlotController); +} diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h new file mode 100644 index 000000000..e5d2853f9 --- /dev/null +++ b/python/port/mod/matplotlib/modpyplot.h @@ -0,0 +1,10 @@ +#include + +mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); +//mp_obj_t grid(); +//mp_obj_t scatter(mp_obj_t x, mp_obj_t y); +//mp_obj_t bar(); +//mp_obj_t hist(); +//mp_obj_t axis(mp_obj_t v); +//mp_obj_t text(mp_obj_t x, mp_obj_t y, mp_obj_t text); +mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c new file mode 100644 index 000000000..41f0ef6f6 --- /dev/null +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -0,0 +1,17 @@ +#include "modpyplot.h" + +MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_plot_obj, modpyplot_plot); +MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); + +STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, + { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(modpyplot_module_globals, modpyplot_module_globals_table); + +const mp_obj_module_t modpyplot_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&modpyplot_module_globals, +}; diff --git a/python/port/mod/matplotlib/plot_controller.cpp b/python/port/mod/matplotlib/plot_controller.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h new file mode 100644 index 000000000..27ab135b9 --- /dev/null +++ b/python/port/mod/matplotlib/plot_controller.h @@ -0,0 +1,47 @@ +#ifndef PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H +#define PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H + +//#include +#include +#include +#include "plot_view.h" +#include "plot_store.h" + +#include + +namespace Matplotlib { + +class PlotController : public Shared::SimpleInteractiveCurveViewController { +public: + PlotController() : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), m_store(), m_view(&m_store) {} + //virtual View * view() override { return &m_view; } + + float cursorBottomMarginRatio() override { + return 0.0f; + } + virtual void reloadBannerView() override { + } + + bool handleEvent(Ion::Events::Event event) override { + printf("EVENT!!\n"); + return Shared::SimpleInteractiveCurveViewController::handleEvent(event); + } + + virtual bool handleEnter() override { + printf("ENTER !!\n"); + return false; + } + +protected: + Shared::CurveView * curveView() override { return &m_view; } + Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return &m_store; } +private: + Shared::CurveViewCursor m_cursor; + PlotStore m_store; + PlotView m_view; +}; + +} + + +#endif diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp new file mode 100644 index 000000000..7c9680232 --- /dev/null +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -0,0 +1 @@ +#include "plot_store.h" diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h new file mode 100644 index 000000000..b7435ea9b --- /dev/null +++ b/python/port/mod/matplotlib/plot_store.h @@ -0,0 +1,33 @@ +#ifndef PYTHON_MATPLOTLIB_PLOT_STORE_H +#define PYTHON_MATPLOTLIB_PLOT_STORE_H + +//#include +#include + +namespace Matplotlib { + +class PlotStore : public Shared::InteractiveCurveViewRange { +public: + PlotStore() : Shared::InteractiveCurveViewRange() {} + /* + float xMin() const override { return 0.0f; } + float xMax() const override { return 1.0f; } + float yMin() const override { return 0.0f; } + float yMax() const override { return 1.0f; } + */ +private: + /* + mp_obj_array_t * m_plots; + mp_obj_array_t * m_arrows; + mp_obj_array_t * m_scatters; + mp_obj_array_t * m_texts; + mp_obj_array_t * m_rects; + + bool m_grid; + */ + +}; + +} + +#endif diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp new file mode 100644 index 000000000..ca6f6c35b --- /dev/null +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -0,0 +1,13 @@ +#include "plot_view.h" + +namespace Matplotlib { + +void PlotView::drawRect(KDContext * ctx, KDRect rect) const { + ctx->fillRect(rect, KDColorWhite); + drawGrid(ctx, rect); + drawAxes(ctx, rect); + drawLabelsAndGraduations(ctx, rect, Axis::Vertical, true); + drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, true); +} + +} diff --git a/python/port/mod/matplotlib/plot_view.h b/python/port/mod/matplotlib/plot_view.h new file mode 100644 index 000000000..2514c4fe2 --- /dev/null +++ b/python/port/mod/matplotlib/plot_view.h @@ -0,0 +1,18 @@ +#ifndef PYTHON_MATPLOTLIB_PLOT_VIEW_H +#define PYTHON_MATPLOTLIB_PLOT_VIEW_H + +#include +#include "plot_store.h" + +namespace Matplotlib { + +class PlotView : public Shared::LabeledCurveView { +public: + PlotView(PlotStore * s) : Shared::LabeledCurveView(s) {} + void drawRect(KDContext * ctx, KDRect rect) const override; +}; + +} + + +#endif diff --git a/python/port/mpconfigport.h b/python/port/mpconfigport.h index 8ef4cad6d..d6565ff01 100644 --- a/python/port/mpconfigport.h +++ b/python/port/mpconfigport.h @@ -130,12 +130,14 @@ typedef long mp_off_t; extern const struct _mp_obj_module_t modion_module; extern const struct _mp_obj_module_t modkandinsky_module; +extern const struct _mp_obj_module_t modpyplot_module; extern const struct _mp_obj_module_t modtime_module; extern const struct _mp_obj_module_t modturtle_module; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_ion), MP_ROM_PTR(&modion_module) }, \ { MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&modkandinsky_module) }, \ + { MP_ROM_QSTR(MP_QSTR_pyplot), MP_ROM_PTR(&modpyplot_module) }, \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&modtime_module) }, \ { MP_ROM_QSTR(MP_QSTR_turtle), MP_ROM_PTR(&modturtle_module) }, \ From 6a796f5f7c85f93e2bacf3269e8854c9a2f256b6 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 10:01:49 -0400 Subject: [PATCH 04/77] [python] Add an "axis" function to the matplotlib module --- python/port/genhdr/qstrdefs.in.h | 2 +- python/port/mod/matplotlib/modpyplot.cpp | 59 ++++++++++++++++- python/port/mod/matplotlib/modpyplot.h | 6 ++ python/port/mod/matplotlib/modpyplot_table.c | 8 ++- python/port/mod/matplotlib/plot_controller.h | 16 +---- python/port/mod/matplotlib/plot_store.cpp | 68 ++++++++++++++++++++ python/port/mod/matplotlib/plot_store.h | 36 +++++++++-- python/port/mod/matplotlib/plot_view.cpp | 9 ++- python/port/mod/matplotlib/plot_view.h | 4 +- python/port/port.cpp | 2 + 10 files changed, 183 insertions(+), 27 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index be88dc99e..b52bb5921 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -74,11 +74,11 @@ Q(get_pixel) Q(set_pixel) // Matplotlib QSTRs +Q(axis) Q(plot) Q(pyplot) Q(show) - // Turtle QSTRs Q(turtle) Q(forward) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 065d6dd5c..482afe24d 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -1,17 +1,72 @@ extern "C" { #include "modpyplot.h" } +#include #include "port.h" #include "plot_controller.h" -Matplotlib::PlotController sPlotController; +Matplotlib::PlotStore * sPlotStore = nullptr; +Matplotlib::PlotController * sPlotController = nullptr; + +// Internal functions + +mp_obj_t modpyplot___init__() { + static Matplotlib::PlotStore plotStore; + static Matplotlib::PlotController plotController(&plotStore); + sPlotStore = &plotStore; + sPlotController = &plotController; + sPlotStore->flush(); + return mp_const_none; +} + +void modpyplot_gc_collect() { + if (sPlotStore != nullptr) { + return; + } + MicroPython::collectRootsAtAddress( + reinterpret_cast(&sPlotStore), + sizeof(Matplotlib::PlotStore) + ); +} + +/* axis(arg) + * - arg = [xmin, xmax, ymin, ymax] + * - arg = True, False + * Returns : xmin, xmax, ymin, ymax : float */ + +mp_obj_t modpyplot_axis(mp_obj_t arg) { + mp_obj_is_type(arg, &mp_type_enumerate); +#warning Use mp_obj_is_bool when upgrading uPy + if (mp_obj_is_type(arg, &mp_type_bool)) { + sPlotStore->setGrid(mp_obj_is_true(arg)); + } else { + mp_obj_t * items; + mp_obj_get_array_fixed_n(arg, 4, &items); + sPlotStore->setXMin(mp_obj_get_float(items[0])); + sPlotStore->setXMax(mp_obj_get_float(items[1])); + sPlotStore->setYMin(mp_obj_get_float(items[2])); + sPlotStore->setYMax(mp_obj_get_float(items[3])); + } + + // Build the return value + mp_obj_t coords[4]; + coords[0] = mp_obj_new_float(sPlotStore->xMin()); + coords[1] = mp_obj_new_float(sPlotStore->xMax()); + coords[2] = mp_obj_new_float(sPlotStore->yMin()); + coords[3] = mp_obj_new_float(sPlotStore->yMax()); + return mp_obj_new_tuple(4, coords); +} mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { + assert(sPlotStore != nullptr); + sPlotStore->addDots(x, y); // Ensure x and y are arrays // "Push" x and y on bigger arrays + return mp_const_none; } mp_obj_t modpyplot_show() { MicroPython::ExecutionEnvironment * env = MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); - env->displayViewController(&sPlotController); + env->displayViewController(sPlotController); + return mp_const_none; } diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index e5d2853f9..1dca0b9d9 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -1,6 +1,12 @@ #include +mp_obj_t modpyplot___init__(); +void modpyplot_gc_collect(); + +mp_obj_t modpyplot_axis(mp_obj_t arg); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); + +// axis(*args, emit=True, **kwargs) //mp_obj_t grid(); //mp_obj_t scatter(mp_obj_t x, mp_obj_t y); //mp_obj_t bar(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 41f0ef6f6..92ff1fae3 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -1,10 +1,14 @@ #include "modpyplot.h" -MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_plot_obj, modpyplot_plot); -MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, + { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, }; diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h index 27ab135b9..604da207f 100644 --- a/python/port/mod/matplotlib/plot_controller.h +++ b/python/port/mod/matplotlib/plot_controller.h @@ -1,20 +1,16 @@ #ifndef PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H #define PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H -//#include #include #include #include "plot_view.h" #include "plot_store.h" -#include - namespace Matplotlib { class PlotController : public Shared::SimpleInteractiveCurveViewController { public: - PlotController() : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), m_store(), m_view(&m_store) {} - //virtual View * view() override { return &m_view; } + PlotController(PlotStore * store) : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), m_store(store), m_view(m_store) {} float cursorBottomMarginRatio() override { return 0.0f; @@ -22,22 +18,16 @@ public: virtual void reloadBannerView() override { } - bool handleEvent(Ion::Events::Event event) override { - printf("EVENT!!\n"); - return Shared::SimpleInteractiveCurveViewController::handleEvent(event); - } - virtual bool handleEnter() override { - printf("ENTER !!\n"); return false; } protected: Shared::CurveView * curveView() override { return &m_view; } - Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return &m_store; } + Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_store; } private: + PlotStore * m_store; Shared::CurveViewCursor m_cursor; - PlotStore m_store; PlotView m_view; }; diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 7c9680232..681077f44 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -1 +1,69 @@ #include "plot_store.h" + +namespace Matplotlib { + +PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), + m_grid(false) +{ + flush(); +} + +void PlotStore::flush() { + m_dots = mp_obj_new_list(0, nullptr); +} + +void PlotStore::addDots(mp_obj_t x, mp_obj_t y) { + mp_obj_t items[2] = {x, y}; + mp_obj_t tuple = mp_obj_new_tuple(2, items); + mp_obj_list_append(m_dots, tuple); + + //mp_obj_tuple_t * t = static_cast(MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL))); + //t->items[0] = MP_OBJ_NEW_SMALL_INT(r); +} + +PlotStore::Dot PlotStore::dotAtIndex(int i) { + size_t numberOfTuples; + mp_obj_t * tuples; + mp_obj_list_get(m_dots, &numberOfTuples, &tuples); + + mp_obj_t firstTuple = tuples[0]; + size_t numberOfObjects; + mp_obj_t * objects; + mp_obj_tuple_get(firstTuple, &numberOfObjects, &objects); + + mp_obj_t x = objects[0]; + mp_obj_t y = objects[1]; + + size_t numberOfX; + mp_obj_t * xValues; + mp_obj_list_get(x, &numberOfX, &xValues); + size_t numberOfY; + mp_obj_t * yValues; + mp_obj_list_get(y, &numberOfY, &yValues); + + float goodX = mp_obj_get_float(xValues[i]); + float goodY = mp_obj_get_float(yValues[i]); + + return PlotStore::Dot(goodX, goodY, KDColorRed); +} + +int PlotStore::numberOfDots() { + size_t numberOfTuples; + mp_obj_t * tuples; + mp_obj_list_get(m_dots, &numberOfTuples, &tuples); + + mp_obj_t firstTuple = tuples[0]; + size_t numberOfObjects; + mp_obj_t * objects; + mp_obj_tuple_get(firstTuple, &numberOfObjects, &objects); + + mp_obj_t x = objects[0]; + + size_t numberOfX; + mp_obj_t * xValues; + mp_obj_list_get(x, &numberOfX, &xValues); + + return numberOfX; +} + +} diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index b7435ea9b..1cca7b3b9 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -3,19 +3,41 @@ //#include #include +extern "C" { +#include +} namespace Matplotlib { class PlotStore : public Shared::InteractiveCurveViewRange { public: - PlotStore() : Shared::InteractiveCurveViewRange() {} - /* - float xMin() const override { return 0.0f; } - float xMax() const override { return 1.0f; } - float yMin() const override { return 0.0f; } - float yMax() const override { return 1.0f; } - */ + PlotStore(); + void flush(); + + class Dot { + public: + Dot(float x, float y, KDColor color) : m_x(x), m_y(y), m_color(color) {} + float x() const { return m_x; } + float y() const { return m_y; } + KDColor color() const { return m_color; } + private: + float m_x; + float m_y; + KDColor m_color; + }; + + // TODO: Use an iterator here. It will be a lot faster + Dot dotAtIndex(int i); + int numberOfDots(); + + void addDots(mp_obj_t x, mp_obj_t y); + + void setGrid(bool grid) { m_grid = grid; } + bool grid() { return m_grid; } private: + mp_obj_t m_dots; + bool m_grid; + /* mp_obj_array_t * m_plots; mp_obj_array_t * m_arrows; diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index ca6f6c35b..904953bdc 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -4,10 +4,17 @@ namespace Matplotlib { void PlotView::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(rect, KDColorWhite); - drawGrid(ctx, rect); + if (m_store->grid()) { + drawGrid(ctx, rect); + } drawAxes(ctx, rect); drawLabelsAndGraduations(ctx, rect, Axis::Vertical, true); drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, true); + + for (int i=0; inumberOfDots(); i++) { + PlotStore::Dot dot = m_store->dotAtIndex(i); + drawDot(ctx, rect, dot.x(), dot.y(), dot.color()); + } } } diff --git a/python/port/mod/matplotlib/plot_view.h b/python/port/mod/matplotlib/plot_view.h index 2514c4fe2..5e01f8ed1 100644 --- a/python/port/mod/matplotlib/plot_view.h +++ b/python/port/mod/matplotlib/plot_view.h @@ -8,8 +8,10 @@ namespace Matplotlib { class PlotView : public Shared::LabeledCurveView { public: - PlotView(PlotStore * s) : Shared::LabeledCurveView(s) {} + PlotView(PlotStore * s) : Shared::LabeledCurveView(s), m_store(s) {} void drawRect(KDContext * ctx, KDRect rect) const override; +private: + PlotStore * m_store; }; } diff --git a/python/port/port.cpp b/python/port/port.cpp index 5c56064cc..d727332a4 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -20,6 +20,7 @@ extern "C" { #include "py/stackctrl.h" #include "mphalport.h" #include "mod/turtle/modturtle.h" +#include "mod/matplotlib/modpyplot.h" } static MicroPython::ScriptProvider * sScriptProvider = nullptr; @@ -176,6 +177,7 @@ void gc_collect(void) { gc_collect_start(); modturtle_gc_collect(); + modpyplot_gc_collect(); /* get the registers. * regs is the also the last object on the stack so the stack is bound by From 6f3d3f62de96ef32efd1d606797a3e92a4a67afb Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 10:36:38 -0400 Subject: [PATCH 05/77] [python/matplotlib] Validate the plot parameters --- python/port/mod/matplotlib/modpyplot.cpp | 16 +++++++++++++--- python/port/mod/matplotlib/plot_store.cpp | 3 --- python/port/mod/matplotlib/plot_store.h | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 482afe24d..2f9e91430 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -35,7 +35,8 @@ void modpyplot_gc_collect() { * Returns : xmin, xmax, ymin, ymax : float */ mp_obj_t modpyplot_axis(mp_obj_t arg) { - mp_obj_is_type(arg, &mp_type_enumerate); + assert(sPlotStore != nullptr); + #warning Use mp_obj_is_bool when upgrading uPy if (mp_obj_is_type(arg, &mp_type_bool)) { sPlotStore->setGrid(mp_obj_is_true(arg)); @@ -59,9 +60,18 @@ mp_obj_t modpyplot_axis(mp_obj_t arg) { mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { assert(sPlotStore != nullptr); + + // Input parameter validation + size_t xLength, yLength; + mp_obj_t * xItems, yItems; + mp_obj_get_array(x, &xLength, &xItems); + mp_obj_get_array(y, &yLength, &yItems); + if (xLength != yLength) { + mp_raise_msg_varg(&mp_type_ValueError, "x and y must have same dimension"); + } + sPlotStore->addDots(x, y); - // Ensure x and y are arrays - // "Push" x and y on bigger arrays + return mp_const_none; } diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 681077f44..075174d20 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -16,9 +16,6 @@ void PlotStore::addDots(mp_obj_t x, mp_obj_t y) { mp_obj_t items[2] = {x, y}; mp_obj_t tuple = mp_obj_new_tuple(2, items); mp_obj_list_append(m_dots, tuple); - - //mp_obj_tuple_t * t = static_cast(MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL))); - //t->items[0] = MP_OBJ_NEW_SMALL_INT(r); } PlotStore::Dot PlotStore::dotAtIndex(int i) { diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index 1cca7b3b9..5b76c53a4 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -35,7 +35,7 @@ public: void setGrid(bool grid) { m_grid = grid; } bool grid() { return m_grid; } private: - mp_obj_t m_dots; + mp_obj_t m_dots; // A list of (x,y), where x and y are lists of numbers bool m_grid; /* From 5ada80d03bf7209801316138009a876eba5a800b Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 13:43:49 -0400 Subject: [PATCH 06/77] [python/matplotlib] Add a Dot iterator --- python/port/mod/matplotlib/modpyplot.cpp | 4 +- python/port/mod/matplotlib/plot_store.cpp | 115 +++++++++++++++------- python/port/mod/matplotlib/plot_store.h | 30 +++++- python/port/mod/matplotlib/plot_view.cpp | 3 +- 4 files changed, 109 insertions(+), 43 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 2f9e91430..92d950842 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -63,11 +63,11 @@ mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { // Input parameter validation size_t xLength, yLength; - mp_obj_t * xItems, yItems; + mp_obj_t * xItems, * yItems; mp_obj_get_array(x, &xLength, &xItems); mp_obj_get_array(y, &yLength, &yItems); if (xLength != yLength) { - mp_raise_msg_varg(&mp_type_ValueError, "x and y must have same dimension"); + mp_raise_msg(&mp_type_ValueError, "x and y must have same dimension"); } sPlotStore->addDots(x, y); diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 075174d20..4894766cf 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -1,4 +1,5 @@ #include "plot_store.h" +#include namespace Matplotlib { @@ -18,49 +19,91 @@ void PlotStore::addDots(mp_obj_t x, mp_obj_t y) { mp_obj_list_append(m_dots, tuple); } -PlotStore::Dot PlotStore::dotAtIndex(int i) { +PlotStore::DotIterator PlotStore::DotIterator::Begin(mp_obj_t dots) { + DotIterator it; + mp_obj_list_get(dots, &(it.m_numberOfTuples), &(it.m_tuples)); + if (it.m_numberOfTuples > 0) { + it.m_tupleIndex = 0; + it.loadValues(); + } + return it; +} + +PlotStore::DotIterator PlotStore::DotIterator::End(mp_obj_t dots) { + DotIterator it; + mp_obj_list_get(dots, &(it.m_numberOfTuples), &(it.m_tuples)); + if (it.m_numberOfTuples > 0) { + it.m_tupleIndex = it.m_numberOfTuples; + it.m_valueIndex = 0; + } + return it; +} + +PlotStore::Dot PlotStore::DotIterator::operator*() { + return PlotStore::Dot( + mp_obj_get_float(m_xValues[m_valueIndex]), + mp_obj_get_float(m_yValues[m_valueIndex]), + Palette::DataColor[m_tupleIndex] // FIXME: Share the "looping" routing + ); +}; + +bool PlotStore::DotIterator::operator!=(const DotIterator & it) const { + return (m_tupleIndex != it.m_tupleIndex || m_valueIndex != it.m_valueIndex); +}; + +PlotStore::DotIterator & PlotStore::DotIterator::operator++() { + if (m_valueIndex < m_numberOfValues - 1) { + m_valueIndex++; + } else if (m_tupleIndex < m_numberOfTuples - 1) { + m_tupleIndex++; + loadValues(); + } else { + m_tupleIndex = m_numberOfTuples; + m_valueIndex = 0; + } + + return *this; +} + + +void PlotStore::DotIterator::loadValues() { + mp_obj_t tuple = m_tuples[m_tupleIndex]; + + mp_obj_t * coordinates; + mp_obj_get_array_fixed_n(tuple, 2, &coordinates); + + mp_obj_get_array(coordinates[0], &m_numberOfValues, &m_xValues); + mp_obj_get_array(coordinates[1], &m_numberOfValues, &m_yValues); + + m_valueIndex = 0; +} + +void PlotStore::forEachDot(PlotStore::DotCallback callback) { size_t numberOfTuples; mp_obj_t * tuples; mp_obj_list_get(m_dots, &numberOfTuples, &tuples); - mp_obj_t firstTuple = tuples[0]; - size_t numberOfObjects; - mp_obj_t * objects; - mp_obj_tuple_get(firstTuple, &numberOfObjects, &objects); + for (size_t t=0; tnumberOfDots(); i++) { - PlotStore::Dot dot = m_store->dotAtIndex(i); + for (PlotStore::Dot dot : m_store->dots()) { drawDot(ctx, rect, dot.x(), dot.y(), dot.color()); } } From a6773ad73ba1606b32ccfecc9dcb56b4b448ce63 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 16:01:02 -0400 Subject: [PATCH 07/77] [python/matplotlib] Add Text, simplify Dots --- python/port/genhdr/qstrdefs.in.h | 1 + python/port/mod/matplotlib/modpyplot.cpp | 20 +++- python/port/mod/matplotlib/modpyplot.h | 1 + python/port/mod/matplotlib/modpyplot_table.c | 2 + python/port/mod/matplotlib/plot_store.cpp | 114 ++++++++----------- python/port/mod/matplotlib/plot_store.h | 86 ++++++++------ 6 files changed, 118 insertions(+), 106 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index b52bb5921..cec44f66d 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -78,6 +78,7 @@ Q(axis) Q(plot) Q(pyplot) Q(show) +Q(text) // Turtle QSTRs Q(turtle) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 92d950842..5a0b31841 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -2,11 +2,13 @@ extern "C" { #include "modpyplot.h" } #include +#include #include "port.h" #include "plot_controller.h" Matplotlib::PlotStore * sPlotStore = nullptr; Matplotlib::PlotController * sPlotController = nullptr; +static int paletteIndex = 0; // FIXME: Needs to be reset at some point // Internal functions @@ -67,10 +69,24 @@ mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { mp_obj_get_array(x, &xLength, &xItems); mp_obj_get_array(y, &yLength, &yItems); if (xLength != yLength) { - mp_raise_msg(&mp_type_ValueError, "x and y must have same dimension"); + mp_raise_ValueError("x and y must have same dimension"); } - sPlotStore->addDots(x, y); + KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + for (size_t i=0; iaddDot(xItems[i], yItems[i], color); + } + + return mp_const_none; +} + +mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s) { + // Input parameter validation + mp_obj_get_float(x); + mp_obj_get_float(y); + mp_obj_str_get_str(s); + + sPlotStore->addText(x, y, s); return mp_const_none; } diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 1dca0b9d9..cd43dbc3a 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -5,6 +5,7 @@ void modpyplot_gc_collect(); mp_obj_t modpyplot_axis(mp_obj_t arg); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); +mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); // axis(*args, emit=True, **kwargs) //mp_obj_t grid(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 92ff1fae3..87cfe8450 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -4,6 +4,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, @@ -11,6 +12,7 @@ STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&modpyplot_text_obj) }, }; STATIC MP_DEFINE_CONST_DICT(modpyplot_module_globals, modpyplot_module_globals_table); diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 4894766cf..bd892933a 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -11,99 +11,79 @@ PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), void PlotStore::flush() { m_dots = mp_obj_new_list(0, nullptr); + m_texts = mp_obj_new_list(0, nullptr); } -void PlotStore::addDots(mp_obj_t x, mp_obj_t y) { - mp_obj_t items[2] = {x, y}; - mp_obj_t tuple = mp_obj_new_tuple(2, items); - mp_obj_list_append(m_dots, tuple); -} +// Iterators -PlotStore::DotIterator PlotStore::DotIterator::Begin(mp_obj_t dots) { - DotIterator it; - mp_obj_list_get(dots, &(it.m_numberOfTuples), &(it.m_tuples)); - if (it.m_numberOfTuples > 0) { - it.m_tupleIndex = 0; - it.loadValues(); - } +template +PlotStore::ListIterator PlotStore::ListIterator::Begin(mp_obj_t list) { + ListIterator it; + mp_obj_list_get(list, &(it.m_numberOfTuples), &(it.m_tuples)); return it; } -PlotStore::DotIterator PlotStore::DotIterator::End(mp_obj_t dots) { - DotIterator it; - mp_obj_list_get(dots, &(it.m_numberOfTuples), &(it.m_tuples)); +template +PlotStore::ListIterator PlotStore::ListIterator::End(mp_obj_t list) { + ListIterator it; + mp_obj_list_get(list, &(it.m_numberOfTuples), &(it.m_tuples)); if (it.m_numberOfTuples > 0) { it.m_tupleIndex = it.m_numberOfTuples; - it.m_valueIndex = 0; } return it; } -PlotStore::Dot PlotStore::DotIterator::operator*() { - return PlotStore::Dot( - mp_obj_get_float(m_xValues[m_valueIndex]), - mp_obj_get_float(m_yValues[m_valueIndex]), - Palette::DataColor[m_tupleIndex] // FIXME: Share the "looping" routing - ); -}; - -bool PlotStore::DotIterator::operator!=(const DotIterator & it) const { - return (m_tupleIndex != it.m_tupleIndex || m_valueIndex != it.m_valueIndex); -}; - -PlotStore::DotIterator & PlotStore::DotIterator::operator++() { - if (m_valueIndex < m_numberOfValues - 1) { - m_valueIndex++; - } else if (m_tupleIndex < m_numberOfTuples - 1) { +template +PlotStore::ListIterator & PlotStore::ListIterator::operator++() { + if (m_tupleIndex < m_numberOfTuples) { m_tupleIndex++; - loadValues(); - } else { - m_tupleIndex = m_numberOfTuples; - m_valueIndex = 0; } - return *this; } +template +bool PlotStore::ListIterator::operator!=(const PlotStore::ListIterator & it) const { + return m_tupleIndex != it.m_tupleIndex; +}; -void PlotStore::DotIterator::loadValues() { - mp_obj_t tuple = m_tuples[m_tupleIndex]; +template +T PlotStore::ListIterator::operator*() { + return T(m_tuples[m_tupleIndex]); +}; - mp_obj_t * coordinates; - mp_obj_get_array_fixed_n(tuple, 2, &coordinates); +// Dots - mp_obj_get_array(coordinates[0], &m_numberOfValues, &m_xValues); - mp_obj_get_array(coordinates[1], &m_numberOfValues, &m_yValues); +template class PlotStore::ListIterator; - m_valueIndex = 0; +PlotStore::Dot::Dot(mp_obj_t tuple) { + mp_obj_t * elements; + mp_obj_get_array_fixed_n(tuple, 3, &elements); + m_x = mp_obj_get_float(elements[0]); + m_y = mp_obj_get_float(elements[1]); + m_color = KDColor::RGB16(mp_obj_get_int(elements[2])); } -void PlotStore::forEachDot(PlotStore::DotCallback callback) { - size_t numberOfTuples; - mp_obj_t * tuples; - mp_obj_list_get(m_dots, &numberOfTuples, &tuples); +void PlotStore::addDot(mp_obj_t x, mp_obj_t y, KDColor c) { + mp_obj_t color = mp_obj_new_int(c); + mp_obj_t items[3] = {x, y, color}; + mp_obj_t tuple = mp_obj_new_tuple(3, items); + mp_obj_list_append(m_dots, tuple); +} - for (size_t t=0; t + class ListIterator { + public: + static ListIterator Begin(mp_obj_t list); + static ListIterator End(mp_obj_t list); + T operator*(); + ListIterator & operator++(); + bool operator!=(const ListIterator & it) const; + private: + ListIterator() : m_tupleIndex(0) {} + mp_obj_t * m_tuples; + size_t m_numberOfTuples; + size_t m_tupleIndex; + }; + + template + class Iterable { + public: + Iterable(mp_obj_t list) : m_list(list) {} + T begin() const { return T::Begin(m_list); } + T end() const { return T::End(m_list); } + private: + mp_obj_t m_list; + }; + + // Dots + class Dot { public: - Dot(float x, float y, KDColor color) : m_x(x), m_y(y), m_color(color) {} + Dot(mp_obj_t tuple); float x() const { return m_x; } float y() const { return m_y; } KDColor color() const { return m_color; } @@ -26,52 +55,35 @@ public: KDColor m_color; }; - class DotIterator { + void addDot(mp_obj_t x, mp_obj_t y, KDColor c); + Iterable> dots() { return Iterable>(m_dots); } + + // Texts + + class Text { public: - static DotIterator Begin(mp_obj_t dots); - static DotIterator End(mp_obj_t dots); - Dot operator*(); - bool operator!=(const DotIterator & it) const; - DotIterator & operator++(); + Text(mp_obj_t tuple); + float x() const { return m_x; } + float y() const { return m_y; } + const char * string() const { return m_string; } private: - void loadValues(); - mp_obj_t * m_tuples; - size_t m_numberOfTuples; - size_t m_tupleIndex; - mp_obj_t * m_xValues; - mp_obj_t * m_yValues; - size_t m_numberOfValues; - size_t m_valueIndex; + float m_x; + float m_y; + const char * m_string; }; - class Dots { - public: - Dots(mp_obj_t dots) : m_dots(dots) {} - DotIterator begin() const { return DotIterator::Begin(m_dots); } - DotIterator end() const { return DotIterator::End(m_dots); } - private: - mp_obj_t m_dots; - }; - - void addDots(mp_obj_t x, mp_obj_t y); - Dots dots() { return Dots(m_dots); } + void addText(mp_obj_t x, mp_obj_t y, mp_obj_t string); + Iterable> texts() { return Iterable>(m_texts); } void setGrid(bool grid) { m_grid = grid; } bool grid() { return m_grid; } private: - mp_obj_t m_dots; // A list of (x,y), where x and y are lists of numbers - bool m_grid; - - /* - mp_obj_array_t * m_plots; - mp_obj_array_t * m_arrows; - mp_obj_array_t * m_scatters; - mp_obj_array_t * m_texts; - mp_obj_array_t * m_rects; + mp_obj_t m_dots; // List of (x, y, color) + mp_obj_t m_texts; // List of (x, y, string) + mp_obj_t m_rects; // List of (x, y, w, h, color) + mp_obj_t m_segments; // List of (x, y, dx, dy, style, color) bool m_grid; - */ - }; } From a3b1b51f750c1181008969ac9438e2a15ec47648 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 17:25:23 -0400 Subject: [PATCH 08/77] [pyton/matplotlib] Support plot --- apps/shared/curve_view.cpp | 8 +++++ apps/shared/curve_view.h | 4 +++ python/port/genhdr/qstrdefs.in.h | 1 + python/port/mod/matplotlib/modpyplot.cpp | 27 ++++++++++++-- python/port/mod/matplotlib/modpyplot.h | 6 +--- python/port/mod/matplotlib/modpyplot_table.c | 2 ++ python/port/mod/matplotlib/plot_store.cpp | 37 ++++++++++++++++---- python/port/mod/matplotlib/plot_store.h | 37 +++++++++++++++----- python/port/mod/matplotlib/plot_view.cpp | 19 ++++++++++ 9 files changed, 119 insertions(+), 22 deletions(-) diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 5082cf26f..2c291f978 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -417,6 +417,14 @@ void CurveView::drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coord } } +void CurveView::drawSegment2(KDContext * ctx, KDRect rect, float x, float y, float u, float v, KDColor color, bool thick) const { + float pxf = floatToPixel(Axis::Horizontal, x); + float pyf = floatToPixel(Axis::Vertical, y); + float puf = floatToPixel(Axis::Horizontal, u); + float pvf = floatToPixel(Axis::Vertical, v); + straightJoinDots(ctx, rect, pxf, pyf, puf, pvf, color, thick); +} + void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size) const { KDCoordinate diameter = 0; const uint8_t * mask = nullptr; diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 99d4ddd07..54199ffff 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -65,6 +65,10 @@ protected: void drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const; + void drawSegment2(KDContext * ctx, KDRect rect, + float x, float y, float u, float v, + KDColor color, bool thick = true + ) const; // FIXME: Name conflict? This one seems better though... enum class Size : uint8_t { Small, Medium, diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index cec44f66d..6d5a6f0fe 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -77,6 +77,7 @@ Q(set_pixel) Q(axis) Q(plot) Q(pyplot) +Q(scatter) Q(show) Q(text) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 5a0b31841..8aaaa0528 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -60,7 +60,7 @@ mp_obj_t modpyplot_axis(mp_obj_t arg) { return mp_obj_new_tuple(4, coords); } -mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { +mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { assert(sPlotStore != nullptr); // Input parameter validation @@ -80,13 +80,36 @@ mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { return mp_const_none; } +mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { + assert(sPlotStore != nullptr); + assert(sPlotStore != nullptr); + + // Input parameter validation + size_t xLength, yLength; + mp_obj_t * xItems, * yItems; + mp_obj_get_array(x, &xLength, &xItems); + mp_obj_get_array(y, &yLength, &yItems); + if (xLength != yLength) { + mp_raise_ValueError("x and y must have same dimension"); + } + + KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + for (size_t i=0; iaddSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color); + } + + return mp_const_none; +} + mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s) { + assert(sPlotStore != nullptr); + // Input parameter validation mp_obj_get_float(x); mp_obj_get_float(y); mp_obj_str_get_str(s); - sPlotStore->addText(x, y, s); + sPlotStore->addLabel(x, y, s); return mp_const_none; } diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index cd43dbc3a..8dad90017 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -5,13 +5,9 @@ void modpyplot_gc_collect(); mp_obj_t modpyplot_axis(mp_obj_t arg); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); +mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); - -// axis(*args, emit=True, **kwargs) //mp_obj_t grid(); -//mp_obj_t scatter(mp_obj_t x, mp_obj_t y); //mp_obj_t bar(); //mp_obj_t hist(); -//mp_obj_t axis(mp_obj_t v); -//mp_obj_t text(mp_obj_t x, mp_obj_t y, mp_obj_t text); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 87cfe8450..a4780152a 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -3,6 +3,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); @@ -11,6 +12,7 @@ STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, + { MP_ROM_QSTR(MP_QSTR_scatter), MP_ROM_PTR(&modpyplot_scatter_obj) }, { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&modpyplot_text_obj) }, }; diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index bd892933a..8c815843f 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -1,5 +1,4 @@ #include "plot_store.h" -#include namespace Matplotlib { @@ -11,7 +10,8 @@ PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), void PlotStore::flush() { m_dots = mp_obj_new_list(0, nullptr); - m_texts = mp_obj_new_list(0, nullptr); + m_segments = mp_obj_new_list(0, nullptr); + m_labels = mp_obj_new_list(0, nullptr); } // Iterators @@ -51,7 +51,7 @@ T PlotStore::ListIterator::operator*() { return T(m_tuples[m_tupleIndex]); }; -// Dots +// Dot template class PlotStore::ListIterator; @@ -70,9 +70,32 @@ void PlotStore::addDot(mp_obj_t x, mp_obj_t y, KDColor c) { mp_obj_list_append(m_dots, tuple); } -// Text +// Segment -PlotStore::Text::Text(mp_obj_t tuple) { +template class PlotStore::ListIterator; + +PlotStore::Segment::Segment(mp_obj_t tuple) { + mp_obj_t * elements; + mp_obj_get_array_fixed_n(tuple, 5, &elements); + m_xStart = mp_obj_get_float(elements[0]); + m_yStart = mp_obj_get_float(elements[1]); + m_xEnd = mp_obj_get_float(elements[2]); + m_yEnd = mp_obj_get_float(elements[3]); + m_color = KDColor::RGB16(mp_obj_get_int(elements[4])); +} + +void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c) { + mp_obj_t color = mp_obj_new_int(c); + mp_obj_t items[5] = {xStart, yStart, xEnd, yEnd, color}; + mp_obj_t tuple = mp_obj_new_tuple(5, items); + mp_obj_list_append(m_segments, tuple); +} + +// Label + +template class PlotStore::ListIterator; + +PlotStore::Label::Label(mp_obj_t tuple) { mp_obj_t * elements; mp_obj_get_array_fixed_n(tuple, 3, &elements); m_x = mp_obj_get_float(elements[0]); @@ -80,10 +103,10 @@ PlotStore::Text::Text(mp_obj_t tuple) { m_string = mp_obj_str_get_str(elements[2]); } -void PlotStore::addText(mp_obj_t x, mp_obj_t y, mp_obj_t string) { +void PlotStore::addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string) { mp_obj_t items[3] = {x, y, string}; mp_obj_t tuple = mp_obj_new_tuple(3, items); - mp_obj_list_append(m_texts, tuple); + mp_obj_list_append(m_labels, tuple); } } diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index 10946e636..32af94b55 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -41,7 +41,7 @@ public: mp_obj_t m_list; }; - // Dots + // Dot class Dot { public: @@ -58,11 +58,32 @@ public: void addDot(mp_obj_t x, mp_obj_t y, KDColor c); Iterable> dots() { return Iterable>(m_dots); } - // Texts + // Segment - class Text { + class Segment { public: - Text(mp_obj_t tuple); + Segment(mp_obj_t tuple); + float xStart() const { return m_xStart; } + float yStart() const { return m_yStart; } + float xEnd() const { return m_xEnd; } + float yEnd() const { return m_yEnd; } + KDColor color() const { return m_color; } + private: + float m_xStart; + float m_yStart; + float m_xEnd; + float m_yEnd; + KDColor m_color; + }; + + void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c); + Iterable> segments() { return Iterable>(m_segments); } + + // Label + + class Label { + public: + Label(mp_obj_t tuple); float x() const { return m_x; } float y() const { return m_y; } const char * string() const { return m_string; } @@ -72,16 +93,16 @@ public: const char * m_string; }; - void addText(mp_obj_t x, mp_obj_t y, mp_obj_t string); - Iterable> texts() { return Iterable>(m_texts); } + void addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string); + Iterable> labels() { return Iterable>(m_labels); } void setGrid(bool grid) { m_grid = grid; } bool grid() { return m_grid; } private: mp_obj_t m_dots; // List of (x, y, color) - mp_obj_t m_texts; // List of (x, y, string) - mp_obj_t m_rects; // List of (x, y, w, h, color) + mp_obj_t m_labels; // List of (x, y, string) mp_obj_t m_segments; // List of (x, y, dx, dy, style, color) + mp_obj_t m_rects; // List of (x, y, w, h, color) bool m_grid; }; diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index ac1839f40..4b72a7010 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -14,6 +14,25 @@ void PlotView::drawRect(KDContext * ctx, KDRect rect) const { for (PlotStore::Dot dot : m_store->dots()) { drawDot(ctx, rect, dot.x(), dot.y(), dot.color()); } + + for (PlotStore::Label label : m_store->labels()) { + drawLabel(ctx, rect, + label.x(), label.y(), label.string(), + KDColorBlack, + CurveView::RelativePosition::Before, + CurveView::RelativePosition::None + ); + } + + for (PlotStore::Segment segment : m_store->segments()) { + drawSegment2( + ctx, rect, + segment.xStart(), segment.yStart(), + segment.xEnd(), segment.yEnd(), + segment.color() + ); + } + } } From a062c570d57c7f8d57630cd576e20a346b57910b Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 17:53:19 -0400 Subject: [PATCH 09/77] [python/matplotlib] Add grid control --- python/port/genhdr/qstrdefs.in.h | 1 + python/port/mod/matplotlib/modpyplot.cpp | 14 ++++++++++++-- python/port/mod/matplotlib/modpyplot.h | 3 ++- python/port/mod/matplotlib/modpyplot_table.c | 2 ++ python/port/mod/matplotlib/plot_store.cpp | 3 ++- python/port/mod/matplotlib/plot_store.h | 11 +++++++---- python/port/mod/matplotlib/plot_view.cpp | 13 ++++++++----- 7 files changed, 34 insertions(+), 13 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 6d5a6f0fe..8168d8e69 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -75,6 +75,7 @@ Q(set_pixel) // Matplotlib QSTRs Q(axis) +Q(grid) Q(plot) Q(pyplot) Q(scatter) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 8aaaa0528..cb572ad08 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -8,7 +8,7 @@ extern "C" { Matplotlib::PlotStore * sPlotStore = nullptr; Matplotlib::PlotController * sPlotController = nullptr; -static int paletteIndex = 0; // FIXME: Needs to be reset at some point +static int paletteIndex = 0; // Internal functions @@ -18,6 +18,7 @@ mp_obj_t modpyplot___init__() { sPlotStore = &plotStore; sPlotController = &plotController; sPlotStore->flush(); + paletteIndex = 0; return mp_const_none; } @@ -41,7 +42,7 @@ mp_obj_t modpyplot_axis(mp_obj_t arg) { #warning Use mp_obj_is_bool when upgrading uPy if (mp_obj_is_type(arg, &mp_type_bool)) { - sPlotStore->setGrid(mp_obj_is_true(arg)); + sPlotStore->setAxesRequested(mp_obj_is_true(arg)); } else { mp_obj_t * items; mp_obj_get_array_fixed_n(arg, 4, &items); @@ -60,6 +61,15 @@ mp_obj_t modpyplot_axis(mp_obj_t arg) { return mp_obj_new_tuple(4, coords); } +mp_obj_t modpyplot_grid(mp_obj_t b) { + if (mp_obj_is_type(b, &mp_type_bool)) { + sPlotStore->setGridRequested(mp_obj_is_true(b)); + } else { + sPlotStore->setGridRequested(!sPlotStore->gridRequested()); + } + return mp_const_none; +} + mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { assert(sPlotStore != nullptr); diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 8dad90017..9652a637a 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -4,10 +4,11 @@ mp_obj_t modpyplot___init__(); void modpyplot_gc_collect(); mp_obj_t modpyplot_axis(mp_obj_t arg); +mp_obj_t modpyplot_grid(mp_obj_t b); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); -//mp_obj_t grid(); +//mp_obj_t arrow(); //mp_obj_t bar(); //mp_obj_t hist(); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index a4780152a..8300fb92c 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -2,6 +2,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_grid_obj, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); @@ -11,6 +12,7 @@ STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, + { MP_ROM_QSTR(MP_QSTR_grid), MP_ROM_PTR(&modpyplot_grid_obj) }, { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, { MP_ROM_QSTR(MP_QSTR_scatter), MP_ROM_PTR(&modpyplot_scatter_obj) }, { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 8c815843f..0f2cf3ccb 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -3,7 +3,8 @@ namespace Matplotlib { PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), - m_grid(false) + m_axesRequested(true), + m_gridRequested(false) { flush(); } diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index 32af94b55..8d16840f1 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -96,15 +96,18 @@ public: void addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string); Iterable> labels() { return Iterable>(m_labels); } - void setGrid(bool grid) { m_grid = grid; } - bool grid() { return m_grid; } + void setAxesRequested(bool b) { m_axesRequested = b; } + bool axesRequested() const { return m_axesRequested; } + + void setGridRequested(bool b) { m_gridRequested = b; } + bool gridRequested() const { return m_gridRequested; } private: mp_obj_t m_dots; // List of (x, y, color) mp_obj_t m_labels; // List of (x, y, string) mp_obj_t m_segments; // List of (x, y, dx, dy, style, color) mp_obj_t m_rects; // List of (x, y, w, h, color) - - bool m_grid; + bool m_axesRequested; + bool m_gridRequested; }; } diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index 4b72a7010..96aa2465f 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -4,12 +4,16 @@ namespace Matplotlib { void PlotView::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(rect, KDColorWhite); - if (m_store->grid()) { + + if (m_store->gridRequested()) { drawGrid(ctx, rect); } - drawAxes(ctx, rect); - drawLabelsAndGraduations(ctx, rect, Axis::Vertical, true); - drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, true); + + if (m_store->axesRequested()) { + drawAxes(ctx, rect); + drawLabelsAndGraduations(ctx, rect, Axis::Vertical, true); + drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, true); + } for (PlotStore::Dot dot : m_store->dots()) { drawDot(ctx, rect, dot.x(), dot.y(), dot.color()); @@ -32,7 +36,6 @@ void PlotView::drawRect(KDContext * ctx, KDRect rect) const { segment.color() ); } - } } From 3df80189432b1ef42b1a85161756fe738c8ff63b Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 17:54:25 -0400 Subject: [PATCH 10/77] [apps/code] Remove useless code --- apps/code/console_controller.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 7bb1fc7c8..64e7fbc66 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -185,7 +185,6 @@ const char * ConsoleController::inputText(const char * prompt) { void ConsoleController::displayViewController(ViewController * controller) { stackViewController()->push(controller); - Container::activeApp()->setFirstResponder(controller); // FIXME: Shouldn't this be in Escher? } void ConsoleController::viewWillAppear() { From d71ad9b28875ab9235335d5ce0d45c21322da359 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 17:54:42 -0400 Subject: [PATCH 11/77] [wip] Convenience to test matplotlib --- apps/code/console_controller.cpp | 5 +++++ apps/code/script_template.cpp | 19 +++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 64e7fbc66..5065d85ac 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -194,10 +194,13 @@ void ConsoleController::viewWillAppear() { m_importScriptsWhenViewAppears = false; autoImport(); } + + Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); m_editCell.setEditing(true); m_editCell.setText(""); + Container::activeApp()->setFirstResponder(firstResponder); // FIXME } void ConsoleController::didBecomeFirstResponder() { @@ -495,10 +498,12 @@ void ConsoleController::autoImportScript(Script script, bool force) { runAndPrintForCommand(command); } if (!sandboxIsDisplayed() && force) { + Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); m_editCell.setEditing(true); m_editCell.setText(""); + Container::activeApp()->setFirstResponder(firstResponder); // FIXME } } diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index 9ccfc6fff..dfa40a157 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -40,18 +40,13 @@ def mandelbrot(N_iteration): # Draw a pixel colored in 'col' at position (x,y) kandinsky.set_pixel(x,y,col))"); -constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from math import * -# roots(a,b,c) computes the solutions of the equation a*x**2+b*x+c=0 -def roots(a,b,c): - delta = b*b-4*a*c - if delta == 0: - return -b/(2*a) - elif delta > 0: - x_1 = (-b-sqrt(delta))/(2*a) - x_2 = (-b+sqrt(delta))/(2*a) - return x_1, x_2 - else: - return None)"); +constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from pyplot import * +x = [1,2,3,4] +y = [-1,-2,-3,-4] +scatter(x, y) +plot(y, x) +text(-1,-1,"Coucou") +show())"); const ScriptTemplate * ScriptTemplate::Empty() { return &emptyScriptTemplate; From a0319905d70c99d4efba4e4e08013a44cf256b92 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 16 Mar 2020 11:07:32 -0400 Subject: [PATCH 12/77] [wip] Clean Rect and drawing --- python/port/mod/matplotlib/modpyplot.cpp | 6 +++ python/port/mod/matplotlib/modpyplot.h | 1 + python/port/mod/matplotlib/plot_store.h | 21 ++++++++++ python/port/mod/matplotlib/plot_view.cpp | 49 +++++++++++++++++------- python/port/mod/matplotlib/plot_view.h | 4 ++ 5 files changed, 68 insertions(+), 13 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index cb572ad08..fb72bd5ca 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -61,6 +61,12 @@ mp_obj_t modpyplot_axis(mp_obj_t arg) { return mp_obj_new_tuple(4, coords); } +mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height) { + assert(sPlotStore != nullptr); + + +} + mp_obj_t modpyplot_grid(mp_obj_t b) { if (mp_obj_is_type(b, &mp_type_bool)) { sPlotStore->setGridRequested(mp_obj_is_true(b)); diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 9652a637a..777ba7684 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -4,6 +4,7 @@ mp_obj_t modpyplot___init__(); void modpyplot_gc_collect(); mp_obj_t modpyplot_axis(mp_obj_t arg); +mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height); mp_obj_t modpyplot_grid(mp_obj_t b); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index 8d16840f1..96e6511f9 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -79,6 +79,27 @@ public: void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c); Iterable> segments() { return Iterable>(m_segments); } + // Rect + + class Rect { + public: + Rect(mp_obj_t tuple); + float x() const { return m_x; } + float y() const { return m_y; } + float width() const { return m_width; } + float height() const { return m_height; } + KDColor color() const { return m_color; } + private: + float m_x; + float m_y; + float m_width; + float m_height; + KDColor m_color; + }; + + void addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c); + Iterable> rects() { return Iterable>(m_segments); } + // Label class Label { diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index 96aa2465f..3e7ae4f0c 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -16,26 +16,49 @@ void PlotView::drawRect(KDContext * ctx, KDRect rect) const { } for (PlotStore::Dot dot : m_store->dots()) { - drawDot(ctx, rect, dot.x(), dot.y(), dot.color()); + traceDot(ctx, rect, dot); } for (PlotStore::Label label : m_store->labels()) { - drawLabel(ctx, rect, - label.x(), label.y(), label.string(), - KDColorBlack, - CurveView::RelativePosition::Before, - CurveView::RelativePosition::None - ); + traceLabel(ctx, rect, label); } for (PlotStore::Segment segment : m_store->segments()) { - drawSegment2( - ctx, rect, - segment.xStart(), segment.yStart(), - segment.xEnd(), segment.yEnd(), - segment.color() - ); + traceSegment(ctx, rect, segment); } } +void PlotView::traceDot(KDContext * ctx, KDRect r, PlotStore::Dot dot) const { + drawDot(ctx, r, dot.x(), dot.y(), dot.color()); +} + +void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segment) const { + drawSegment2( + ctx, r, + segment.xStart(), segment.yStart(), + segment.xEnd(), segment.yEnd(), + segment.color() + ); +} + +void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const { + KDRect pixelRect( + floatToPixel(Axis::Horizontal, rect.x()), + floatToPixel(Axis::Vertical, rect.y()), + rect.width() / pixelWidth(), + rect.height() / pixelHeight() + ); + ctx->fillRect(pixelRect, rect.color()); +} + +void PlotView::traceLabel(KDContext * ctx, KDRect r, PlotStore::Label label) const { + drawLabel(ctx, r, + label.x(), label.y(), label.string(), + KDColorBlack, + RelativePosition::Before, + RelativePosition::None + ); +} + + } diff --git a/python/port/mod/matplotlib/plot_view.h b/python/port/mod/matplotlib/plot_view.h index 5e01f8ed1..4a804c957 100644 --- a/python/port/mod/matplotlib/plot_view.h +++ b/python/port/mod/matplotlib/plot_view.h @@ -11,6 +11,10 @@ public: PlotView(PlotStore * s) : Shared::LabeledCurveView(s), m_store(s) {} void drawRect(KDContext * ctx, KDRect rect) const override; private: + void traceDot(KDContext * ctx, KDRect r, PlotStore::Dot dot) const; + void traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segment) const; + void traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const; + void traceLabel(KDContext * ctx, KDRect r, PlotStore::Label label) const; PlotStore * m_store; }; From da1c6090b50d9509331de0a439167c7801edec34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Mar 2020 10:08:02 +0100 Subject: [PATCH 13/77] [python] matplotlib port: factorize input validation --- python/port/mod/matplotlib/modpyplot.cpp | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index fb72bd5ca..5e37539e7 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -10,6 +10,20 @@ Matplotlib::PlotStore * sPlotStore = nullptr; Matplotlib::PlotController * sPlotController = nullptr; static int paletteIndex = 0; +// Private helper + + +static size_t extract_and_validate_plot_input(mp_obj_t x, mp_obj_t y, mp_obj_t ** xItems, mp_obj_t ** yItems) { + // Input parameter validation + size_t xLength, yLength; + mp_obj_get_array(x, &xLength, xItems); + mp_obj_get_array(y, &yLength, yItems); + if (xLength != yLength) { + mp_raise_ValueError("x and y must have same dimension"); + } + return xLength; +} + // Internal functions mp_obj_t modpyplot___init__() { @@ -80,16 +94,11 @@ mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { assert(sPlotStore != nullptr); // Input parameter validation - size_t xLength, yLength; mp_obj_t * xItems, * yItems; - mp_obj_get_array(x, &xLength, &xItems); - mp_obj_get_array(y, &yLength, &yItems); - if (xLength != yLength) { - mp_raise_ValueError("x and y must have same dimension"); - } + size_t length = extract_and_validate_plot_input(x, y, &xItems, &yItems); KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine - for (size_t i=0; iaddDot(xItems[i], yItems[i], color); } @@ -101,16 +110,11 @@ mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { assert(sPlotStore != nullptr); // Input parameter validation - size_t xLength, yLength; mp_obj_t * xItems, * yItems; - mp_obj_get_array(x, &xLength, &xItems); - mp_obj_get_array(y, &yLength, &yItems); - if (xLength != yLength) { - mp_raise_ValueError("x and y must have same dimension"); - } + size_t length = extract_and_validate_plot_input(x, y, &xItems, &yItems); KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine - for (size_t i=0; iaddSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color); } From 373a85f2b7ba0afeb20973b34a1442f3ece861f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Mar 2020 10:08:49 +0100 Subject: [PATCH 14/77] [python] matplotlib port: clean duplicate --- python/port/mod/matplotlib/modpyplot.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 5e37539e7..31ab79470 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -107,7 +107,6 @@ mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { assert(sPlotStore != nullptr); - assert(sPlotStore != nullptr); // Input parameter validation mp_obj_t * xItems, * yItems; From 0ae81374d901ee8b8e4eb1fa4674f2c129d2156a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Mar 2020 13:46:08 +0100 Subject: [PATCH 15/77] [python] matplotlib port: implement bar method --- python/port/genhdr/qstrdefs.in.h | 2 ++ python/port/mod/matplotlib/modpyplot.cpp | 12 +++++++++++ python/port/mod/matplotlib/modpyplot.h | 1 - python/port/mod/matplotlib/modpyplot_table.c | 2 ++ python/port/mod/matplotlib/plot_store.cpp | 22 ++++++++++++++++++++ python/port/mod/matplotlib/plot_store.h | 2 +- python/port/mod/matplotlib/plot_view.cpp | 4 ++++ 7 files changed, 43 insertions(+), 2 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 8168d8e69..b67444ed1 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -75,6 +75,8 @@ Q(set_pixel) // Matplotlib QSTRs Q(axis) +Q(bar) +Q(grid) Q(grid) Q(plot) Q(pyplot) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 31ab79470..f17fa3926 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -78,7 +78,19 @@ mp_obj_t modpyplot_axis(mp_obj_t arg) { mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height) { assert(sPlotStore != nullptr); + // Input parameter validation + mp_obj_t * xItems, * hItems; + size_t length = extract_and_validate_plot_input(x, height, &xItems, &hItems); + mp_float_t w = 0.8; // TODO: w should be an optional parameter + KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + for (size_t i=0; iaddRect(mp_obj_new_float(rectX), mp_obj_new_float(rectY), mp_obj_new_float(w), mp_obj_new_float(std::fabs(h)), color); + } + return mp_const_none; } mp_obj_t modpyplot_grid(mp_obj_t b) { diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 777ba7684..00fa667f6 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -10,6 +10,5 @@ mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); //mp_obj_t arrow(); -//mp_obj_t bar(); //mp_obj_t hist(); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 8300fb92c..5516dcde9 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -2,6 +2,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_bar_obj, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_grid_obj, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); @@ -12,6 +13,7 @@ STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, + { MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&modpyplot_bar_obj) }, { MP_ROM_QSTR(MP_QSTR_grid), MP_ROM_PTR(&modpyplot_grid_obj) }, { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, { MP_ROM_QSTR(MP_QSTR_scatter), MP_ROM_PTR(&modpyplot_scatter_obj) }, diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 0f2cf3ccb..393087e4d 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -12,6 +12,7 @@ PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), void PlotStore::flush() { m_dots = mp_obj_new_list(0, nullptr); m_segments = mp_obj_new_list(0, nullptr); + m_rects = mp_obj_new_list(0, nullptr); m_labels = mp_obj_new_list(0, nullptr); } @@ -92,6 +93,27 @@ void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_o mp_obj_list_append(m_segments, tuple); } +// Rect + +template class PlotStore::ListIterator; + +PlotStore::Rect::Rect(mp_obj_t tuple) { + mp_obj_t * elements; + mp_obj_get_array_fixed_n(tuple, 5, &elements); + m_x = mp_obj_get_float(elements[0]); + m_y = mp_obj_get_float(elements[1]); + m_width = mp_obj_get_float(elements[2]); + m_height = mp_obj_get_float(elements[3]); + m_color = KDColor::RGB16(mp_obj_get_int(elements[4])); +} + +void PlotStore::addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c) { + mp_obj_t color = mp_obj_new_int(c); + mp_obj_t items[5] = {x, y, width, height, color}; + mp_obj_t tuple = mp_obj_new_tuple(5, items); + mp_obj_list_append(m_rects, tuple); +} + // Label template class PlotStore::ListIterator; diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index 96e6511f9..e5f027028 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -98,7 +98,7 @@ public: }; void addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c); - Iterable> rects() { return Iterable>(m_segments); } + Iterable> rects() { return Iterable>(m_rects); } // Label diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index 3e7ae4f0c..f2e5ba1d3 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -26,6 +26,10 @@ void PlotView::drawRect(KDContext * ctx, KDRect rect) const { for (PlotStore::Segment segment : m_store->segments()) { traceSegment(ctx, rect, segment); } + + for (PlotStore::Rect rectangle : m_store->rects()) { + traceRect(ctx, rect, rectangle); + } } void PlotView::traceDot(KDContext * ctx, KDRect r, PlotStore::Dot dot) const { From c69ec608e8a47a8b3c7232b871abb0d9d814f60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Mar 2020 13:50:48 +0100 Subject: [PATCH 16/77] [python] matplotlib: label are centered around their position --- python/port/mod/matplotlib/plot_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index f2e5ba1d3..ff8dccb83 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -59,7 +59,7 @@ void PlotView::traceLabel(KDContext * ctx, KDRect r, PlotStore::Label label) con drawLabel(ctx, r, label.x(), label.y(), label.string(), KDColorBlack, - RelativePosition::Before, + RelativePosition::None, RelativePosition::None ); } From 7d60c6554edd0a2b9a5640a0d2bbd1274a068a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 17 Mar 2020 19:21:13 +0100 Subject: [PATCH 17/77] [python] matplotlib port: first version of hist method --- python/port/genhdr/qstrdefs.in.h | 1 + python/port/mod/matplotlib/modpyplot.cpp | 84 ++++++++++++++++++++ python/port/mod/matplotlib/modpyplot.h | 2 +- python/port/mod/matplotlib/modpyplot_table.c | 2 + 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index b67444ed1..5c13634eb 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -78,6 +78,7 @@ Q(axis) Q(bar) Q(grid) Q(grid) +Q(hist) Q(plot) Q(pyplot) Q(scatter) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index f17fa3926..5cd0a92e9 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -102,6 +102,90 @@ mp_obj_t modpyplot_grid(mp_obj_t b) { return mp_const_none; } +// Dichotomia to find which bin a value belongs to +size_t belongs_to_bin_of_index(mp_float_t v, mp_obj_t * binsEdges, size_t minIndex, size_t maxIndex) { + assert(mp_obj_get_float(binsEdges[minIndex]) <= v && v <= mp_obj_get_float(binsEdges[maxIndex])); + if (maxIndex - minIndex < 2) { + return minIndex; + } + size_t index = (minIndex+maxIndex)/2; + mp_float_t pivot = mp_obj_get_float(binsEdges[index]); + if (pivot == v) { + return index; + } else if (pivot < v) { + return belongs_to_bin_of_index(v, binsEdges, index, maxIndex); + } else { + assert(pivot > v); + return belongs_to_bin_of_index(v, binsEdges, minIndex, index); + } +} + +mp_obj_t modpyplot_hist(mp_obj_t x) { + // Create a list of bins + // TODO: the number of bins can be given as input + size_t nBins = 10; + // TODO: the list of bins can be given as input + // TODO: skip the following computation if so, + // `bins` must increase monotonically, when an array' + mp_obj_t binsEdges = mp_obj_new_list(nBins+1, nullptr); + + // Sort data to easily get the minimal and maximal value and count bin sizes + mp_obj_t * xItems; + size_t xLength; + mp_obj_get_array(x, &xLength, &xItems); + mp_obj_t xList = mp_obj_new_list(xLength, xItems); + mp_obj_list_sort(1, &xList, (mp_map_t*)&mp_const_empty_map); + mp_obj_list_get(xList, &xLength, &xItems); + mp_float_t min = mp_obj_get_float(xItems[0]); + mp_float_t max = mp_obj_get_float(xItems[xLength - 1]); + + // Fill the bin edges list + // TODO: skip if the binEdges were given as input + mp_float_t binWidth = (max-min)/nBins; + for (int i = 0; i < nBins+1; i++) { + mp_obj_list_store(binsEdges, mp_obj_new_int(i), mp_obj_new_float(min+i*binWidth)); + } + + // Initialize bins list + mp_obj_t bins = mp_obj_new_list(nBins, nullptr); + for (size_t i=0; iaddRect(edgeItems[i], binItems[i], mp_obj_new_float(width), binItems[i], color); + } + return mp_const_none; +} + mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { assert(sPlotStore != nullptr); diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 00fa667f6..598402700 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -6,9 +6,9 @@ void modpyplot_gc_collect(); mp_obj_t modpyplot_axis(mp_obj_t arg); mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height); mp_obj_t modpyplot_grid(mp_obj_t b); +mp_obj_t modpyplot_hist(mp_obj_t x); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); //mp_obj_t arrow(); -//mp_obj_t hist(); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 5516dcde9..e3e311c0f 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -4,6 +4,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_bar_obj, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_grid_obj, modpyplot_grid); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_hist_obj, modpyplot_hist); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); @@ -15,6 +16,7 @@ STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, { MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&modpyplot_bar_obj) }, { MP_ROM_QSTR(MP_QSTR_grid), MP_ROM_PTR(&modpyplot_grid_obj) }, + { MP_ROM_QSTR(MP_QSTR_hist), MP_ROM_PTR(&modpyplot_hist_obj) }, { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, { MP_ROM_QSTR(MP_QSTR_scatter), MP_ROM_PTR(&modpyplot_scatter_obj) }, { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, From aaf71328baf30f1e39af0166b65e3f740d624426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Mar 2020 09:40:13 +0100 Subject: [PATCH 18/77] [apps/shared] CurveView: resolve name conflict - drawHorizontalOrVerticalSegment & drawSegment - --- .../calculation/additional_outputs/complex_graph_cell.cpp | 4 ++-- .../additional_outputs/trigonometry_graph_cell.cpp | 4 ++-- apps/sequence/graph/graph_view.cpp | 4 ++-- apps/shared/curve_view.cpp | 6 +++--- apps/shared/curve_view.h | 8 ++++---- apps/statistics/box_view.cpp | 8 ++++---- python/port/mod/matplotlib/plot_view.cpp | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/calculation/additional_outputs/complex_graph_cell.cpp b/apps/calculation/additional_outputs/complex_graph_cell.cpp index e4249e8f2..a2f55620c 100644 --- a/apps/calculation/additional_outputs/complex_graph_cell.cpp +++ b/apps/calculation/additional_outputs/complex_graph_cell.cpp @@ -66,8 +66,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const { }, ¶meters, &th, false, Palette::GreyDark, false); // Draw dashed segment to indicate real and imaginary - drawSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3); - drawSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3); // Draw complex position on the plan drawDot(ctx, rect, real, imag, Palette::Red, Size::Large); diff --git a/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp b/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp index 41deb62bf..f28c107f4 100644 --- a/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp +++ b/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp @@ -22,8 +22,8 @@ void TrigonometryGraphView::drawRect(KDContext * ctx, KDRect rect) const { return Poincare::Coordinate2D(std::cos(t), std::sin(t)); }, nullptr, nullptr, true, Palette::GreyDark, false); // Draw dashed segment to indicate sine and cosine - drawSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::Red, 1, 3); - drawSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::Red, 1, 3); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::Red, 1, 3); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::Red, 1, 3); // Draw angle position on the circle drawDot(ctx, rect, c, s, Palette::Red, Size::Large); // Draw graduations diff --git a/apps/sequence/graph/graph_view.cpp b/apps/sequence/graph/graph_view.cpp index 3ce352dd6..285be7482 100644 --- a/apps/sequence/graph/graph_view.cpp +++ b/apps/sequence/graph/graph_view.cpp @@ -32,9 +32,9 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { if (x >= m_highlightedStart && x <= m_highlightedEnd && record == m_selectedRecord) { KDColor color = m_shouldColorHighlighted ? s->color() : KDColorBlack; if (y >= 0.0f) { - drawSegment(ctx, rect, Axis::Vertical, x, 0.0f, y, color, 1); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, 0.0f, y, color, 1); } else { - drawSegment(ctx, rect, Axis::Vertical, x, y, 0.0f, color, 1); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, y, 0.0f, color, 1); } } } diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 2c291f978..e7337faf7 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -386,7 +386,7 @@ DrawLabel: } } -void CurveView::drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness, KDCoordinate dashSize) const { +void CurveView::drawHorizontalOrVerticalSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness, KDCoordinate dashSize) const { KDCoordinate min = (axis == Axis::Horizontal) ? rect.x() : rect.y(); KDCoordinate max = (axis == Axis::Horizontal) ? rect.x() + rect.width() : rect.y() + rect.height(); KDCoordinate start = std::isinf(lowerBound) ? min : std::round(floatToPixel(axis, lowerBound)); @@ -417,7 +417,7 @@ void CurveView::drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coord } } -void CurveView::drawSegment2(KDContext * ctx, KDRect rect, float x, float y, float u, float v, KDColor color, bool thick) const { +void CurveView::drawSegment(KDContext * ctx, KDRect rect, float x, float y, float u, float v, KDColor color, bool thick) const { float pxf = floatToPixel(Axis::Horizontal, x); float pyf = floatToPixel(Axis::Vertical, y); float puf = floatToPixel(Axis::Horizontal, u); @@ -545,7 +545,7 @@ void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd x = xy.x1(); y = xy.x2(); if (colorUnderCurve && !std::isnan(x) && colorLowerBound < x && x < colorUpperBound && !(std::isnan(y) || std::isinf(y))) { - drawSegment(ctx, rect, Axis::Vertical, x, minFloat(0.0f, y), maxFloat(0.0f, y), color, 1); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, minFloat(0.0f, y), maxFloat(0.0f, y), color, 1); } joinDots(ctx, rect, xyEvaluation, model, context, drawStraightLinesEarly, previousT, previousX, previousY, t, x, y, color, thick, k_maxNumberOfIterations); } while (true); diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 54199ffff..ee5aafbd6 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -59,16 +59,16 @@ protected: float floatToPixel(Axis axis, float f) const; void drawLine(KDContext * ctx, KDRect rect, Axis axis, float coordinate, KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const { - return drawSegment(ctx, rect, axis, coordinate, -INFINITY, INFINITY, color, + return drawHorizontalOrVerticalSegment(ctx, rect, axis, coordinate, -INFINITY, INFINITY, color, thickness, dashSize); } - void drawSegment(KDContext * ctx, KDRect rect, Axis axis, + void drawHorizontalOrVerticalSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const; - void drawSegment2(KDContext * ctx, KDRect rect, + void drawSegment(KDContext * ctx, KDRect rect, float x, float y, float u, float v, KDColor color, bool thick = true - ) const; // FIXME: Name conflict? This one seems better though... + ) const; enum class Size : uint8_t { Small, Medium, diff --git a/apps/statistics/box_view.cpp b/apps/statistics/box_view.cpp index a5882ae51..414964305 100644 --- a/apps/statistics/box_view.cpp +++ b/apps/statistics/box_view.cpp @@ -73,8 +73,8 @@ void BoxView::drawRect(KDContext * ctx, KDRect rect) const { // Draw the horizontal lines linking the box to the extreme bounds KDColor horizontalColor = isMainViewSelected() ? m_selectedHistogramColor : Palette::GreyDark; float segmentOrd = (lowBound + upBound)/ 2.0f; - drawSegment(ctx, rect, Axis::Horizontal, segmentOrd, minVal, firstQuart, horizontalColor); - drawSegment(ctx, rect, Axis::Horizontal, segmentOrd, thirdQuart, maxVal, horizontalColor); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, segmentOrd, minVal, firstQuart, horizontalColor); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, segmentOrd, thirdQuart, maxVal, horizontalColor); double calculations[5] = {minVal, firstQuart, m_store->median(m_series), thirdQuart, maxVal}; /* We then draw all the vertical lines of the box and then recolor the @@ -83,10 +83,10 @@ void BoxView::drawRect(KDContext * ctx, KDRect rect) const { * lines. This solution could hide the highlighted line by coloring the next * quantile if it has the same value. */ for (int k = 0; k < 5; k++) { - drawSegment(ctx, rect, Axis::Vertical, calculations[k], lowBound, upBound, Palette::GreyMiddle, k_quantileBarWidth); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, calculations[k], lowBound, upBound, Palette::GreyMiddle, k_quantileBarWidth); } if (isMainViewSelected()) { - drawSegment(ctx, rect, Axis::Vertical, calculations[(int)*m_selectedQuantile], lowBound, upBound, Palette::YellowDark, k_quantileBarWidth); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, calculations[(int)*m_selectedQuantile], lowBound, upBound, Palette::YellowDark, k_quantileBarWidth); } } diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index ff8dccb83..810f4fcd4 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -37,7 +37,7 @@ void PlotView::traceDot(KDContext * ctx, KDRect r, PlotStore::Dot dot) const { } void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segment) const { - drawSegment2( + drawSegment( ctx, r, segment.xStart(), segment.yStart(), segment.xEnd(), segment.yEnd(), From bc8dc0c59c8b6d42b04c444357c38ae16ea203d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Mar 2020 10:08:35 +0100 Subject: [PATCH 19/77] [apps] Use drawSegment when drawing lines instead of drawCurve or drawCartesianCurve --- .../additional_outputs/complex_graph_cell.cpp | 9 ++------- apps/graph/graph/graph_view.cpp | 13 ++++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/calculation/additional_outputs/complex_graph_cell.cpp b/apps/calculation/additional_outputs/complex_graph_cell.cpp index a2f55620c..0d0bcf6fe 100644 --- a/apps/calculation/additional_outputs/complex_graph_cell.cpp +++ b/apps/calculation/additional_outputs/complex_graph_cell.cpp @@ -24,13 +24,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const { float imag = m_complex->imag(); assert(!std::isnan(real) && !std::isnan(imag) && !std::isinf(real) && !std::isinf(imag)); - /* Draw the segment from the origin to the dot (real, imag) of equation - * x(t) = t*real and y(t) = t*imag with t in [0,1] */ - drawCurve(ctx, rect, 0.0f, 1.0f, 0.01f, - [](float t, void * model, void * context) { - ComplexModel * complexModel = (ComplexModel *)model; - return Poincare::Coordinate2D(complexModel->real()*t, complexModel->imag()*t); - }, m_complex, nullptr, false, Palette::GreyDark, false); + // Draw the segment from the origin to the dot (real, imag) + drawSegment(ctx, rect, 0.0f, 0.0f, m_complex->real(), m_complex->imag(), Palette::GreyDark, false); /* Draw the partial ellipse indicating the angle θ * - the ellipse parameters are a = |real|/5 and b = |imag|/5, diff --git a/apps/graph/graph/graph_view.cpp b/apps/graph/graph/graph_view.cpp index c8dcfbae0..10d286f7b 100644 --- a/apps/graph/graph/graph_view.cpp +++ b/apps/graph/graph/graph_view.cpp @@ -60,13 +60,12 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { }, f.operator->(), context(), f->color(), true, record == m_selectedRecord, m_highlightedStart, m_highlightedEnd); /* Draw tangent */ if (m_tangent && record == m_selectedRecord) { - float tangentParameter[2]; - tangentParameter[0] = f->approximateDerivative(m_curveViewCursor->x(), context()); - tangentParameter[1] = -tangentParameter[0]*m_curveViewCursor->x()+f->evaluateXYAtParameter(m_curveViewCursor->x(), context()).x2(); - drawCartesianCurve(ctx, rect, -INFINITY, INFINITY, [](float t, void * model, void * context) { - float * tangent = (float *)model; - return Poincare::Coordinate2D(t, tangent[0]*t+tangent[1]); - }, tangentParameter, nullptr, Palette::GreyVeryDark); + float tangentParameterA = f->approximateDerivative(m_curveViewCursor->x(), context()); + float tangentParameterB = -tangentParameterA*m_curveViewCursor->x()+f->evaluateXYAtParameter(m_curveViewCursor->x(), context()).x2(); + // To represent the tangent, we draw segment from and to abscissas at the extremity of the drawn rect + float minAbscissa = pixelToFloat(Axis::Horizontal, rect.left()); + float maxAbscissa = pixelToFloat(Axis::Horizontal, rect.right()); + drawSegment(ctx, rect, minAbscissa, tangentParameterA*minAbscissa+tangentParameterB, maxAbscissa, tangentParameterA*maxAbscissa+tangentParameterB, Palette::GreyVeryDark, false); } continue; } From 70335b7a473c956fe569b0155b577d90a4134707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Mar 2020 10:59:18 +0100 Subject: [PATCH 20/77] [python] matplotlib port: draft version of arrow method --- python/port/genhdr/qstrdefs.in.h | 1 + python/port/mod/matplotlib/modpyplot.cpp | 10 ++++++++++ python/port/mod/matplotlib/modpyplot.h | 2 +- python/port/mod/matplotlib/modpyplot_table.c | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 5c13634eb..0f6d4e4c3 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -74,6 +74,7 @@ Q(get_pixel) Q(set_pixel) // Matplotlib QSTRs +Q(arrow) Q(axis) Q(bar) Q(grid) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 5cd0a92e9..eb26002f2 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -46,6 +46,16 @@ void modpyplot_gc_collect() { ); } +mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { + assert(n_args == 4); + assert(sPlotStore != nullptr); + + KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0])+mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1])+mp_obj_get_float(args[3])), color); + + return mp_const_none; +} + /* axis(arg) * - arg = [xmin, xmax, ymin, ymax] * - arg = True, False diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 598402700..0cf40d3fc 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -3,6 +3,7 @@ mp_obj_t modpyplot___init__(); void modpyplot_gc_collect(); +mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_axis(mp_obj_t arg); mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height); mp_obj_t modpyplot_grid(mp_obj_t b); @@ -10,5 +11,4 @@ mp_obj_t modpyplot_hist(mp_obj_t x); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); -//mp_obj_t arrow(); mp_obj_t modpyplot_show(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index e3e311c0f..402b33e65 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -1,6 +1,7 @@ #include "modpyplot.h" STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_bar_obj, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_grid_obj, modpyplot_grid); @@ -13,6 +14,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, + { MP_ROM_QSTR(MP_QSTR_arrow), MP_ROM_PTR(&modpyplot_arrow_obj) }, { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, { MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&modpyplot_bar_obj) }, { MP_ROM_QSTR(MP_QSTR_grid), MP_ROM_PTR(&modpyplot_grid_obj) }, From 9e822e85e546e8ab460b65bc512a624a2d29c241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Mar 2020 16:38:29 +0100 Subject: [PATCH 21/77] [apps/shared] CurveView: implement drawArrow --- apps/shared/curve_view.cpp | 41 ++++++++++++++++++++++++++++++++++++++ apps/shared/curve_view.h | 25 +++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index e7337faf7..fd7f25090 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -452,6 +452,47 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor ctx->blendRectWithMask(dotRect, color, mask, workingBuffer); } + +void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength, float angle) const { + /* Let's call the following variables L and l: + * + * / | + * / | + * / l + * / | + * / | + * <-------------------------------------------------- + * \ + * \ + * \ + * \ + * \ + * + * ----- L ----- + * + **/ + assert(angle >= 0.0f); + /* We compute the arrow segments in pixels in order to correctly size the + * arrow without depending on the displayed range. + * Warning: the computed values are relative so we need to add/subtract the + * pixel position of 0s. */ + float x0Pixel = floatToPixel(Axis::Horizontal, 0.0f); + float y0Pixel = floatToPixel(Axis::Vertical, 0.0f); + float dxPixel = floatToPixel(Axis::Horizontal, dx) - x0Pixel; + float dyPixel = y0Pixel - floatToPixel(Axis::Vertical, dy); + float dx2dy2 = std::sqrt(dxPixel*dxPixel+dyPixel*dyPixel); + float L = pixelArrowLength; + float l = angle*L; + + float arrow1dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 + l*dyPixel/dx2dy2); + float arrow1dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 - l*dxPixel/dx2dy2)); + drawSegment(ctx, rect, x, y, x - arrow1dx, y - arrow1dy, color, false); + + float arrow2dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 - l*dyPixel/dx2dy2); + float arrow2dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 + l*dxPixel/dx2dy2)); + drawSegment(ctx, rect, x, y, x - arrow2dx, y - arrow2dy, color, false); +} + void CurveView::drawGrid(KDContext * ctx, KDRect rect) const { KDColor boldColor = Palette::GreyMiddle; KDColor lightColor = Palette::GreyWhite; diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index ee5aafbd6..9470aad49 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -75,6 +75,31 @@ protected: Large }; void drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size = Size::Small) const; + /* 'drawArrow' draws the edge of an arrow pointing to (x,y) with the + * orientation (dx,dy). + * The parameters defining the shape of the arrow are the length in pixel of + * the projection of the arrow on the segment -'pixelArrowLength'- and the + * tangent of the angle between the segment and each wing of the arrow called + * 'angle'. + * + * / | + * / | + * / L + * / | + * / | + * <-------------------------------------------------- + * \ + * \ + * \ + * \ + * \ + * + * <--- pl ---> + * + * pl = pixelArrowLength + * tan(angle) = L/pl + */ + void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength = 10, float angle = 0.4f) const; void drawGrid(KDContext * ctx, KDRect rect) const; void drawAxes(KDContext * ctx, KDRect rect) const; void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const; From b5d3070ef59f01b0c6fd753ea7c5bc6ff0c143ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 18 Mar 2020 18:02:20 +0100 Subject: [PATCH 22/77] [python] matplotlib: improve arrow method, draw arrow edge --- python/port/mod/matplotlib/modpyplot.cpp | 4 ++-- python/port/mod/matplotlib/plot_store.cpp | 9 +++++---- python/port/mod/matplotlib/plot_store.h | 4 +++- python/port/mod/matplotlib/plot_view.cpp | 5 +++++ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index eb26002f2..5c8f654ff 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -51,7 +51,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine - sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0])+mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1])+mp_obj_get_float(args[3])), color); + sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0])+mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1])+mp_obj_get_float(args[3])), color, true); return mp_const_none; } @@ -220,7 +220,7 @@ mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine for (size_t i=0; iaddSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color); + sPlotStore->addSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color, false); } return mp_const_none; diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 393087e4d..411370541 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -78,18 +78,19 @@ template class PlotStore::ListIterator; PlotStore::Segment::Segment(mp_obj_t tuple) { mp_obj_t * elements; - mp_obj_get_array_fixed_n(tuple, 5, &elements); + mp_obj_get_array_fixed_n(tuple, 6 , &elements); m_xStart = mp_obj_get_float(elements[0]); m_yStart = mp_obj_get_float(elements[1]); m_xEnd = mp_obj_get_float(elements[2]); m_yEnd = mp_obj_get_float(elements[3]); m_color = KDColor::RGB16(mp_obj_get_int(elements[4])); + m_arrow = elements[5] == mp_const_true; } -void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c) { +void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, bool arrowEdge) { mp_obj_t color = mp_obj_new_int(c); - mp_obj_t items[5] = {xStart, yStart, xEnd, yEnd, color}; - mp_obj_t tuple = mp_obj_new_tuple(5, items); + mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, color, arrowEdge ? mp_const_true : mp_const_false}; + mp_obj_t tuple = mp_obj_new_tuple(6, items); mp_obj_list_append(m_segments, tuple); } diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index e5f027028..24ebd6b49 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -67,16 +67,18 @@ public: float yStart() const { return m_yStart; } float xEnd() const { return m_xEnd; } float yEnd() const { return m_yEnd; } + bool isArrow() const { return m_arrow; } KDColor color() const { return m_color; } private: float m_xStart; float m_yStart; float m_xEnd; float m_yEnd; + bool m_arrow; KDColor m_color; }; - void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c); + void addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, bool arrowEdge); Iterable> segments() { return Iterable>(m_segments); } // Rect diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index 810f4fcd4..4269edb2d 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -43,6 +43,11 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen segment.xEnd(), segment.yEnd(), segment.color() ); + if (segment.isArrow()) { + float dx = segment.xEnd() - segment.xStart(); + float dy = segment.yEnd() - segment.yStart(); + drawArrow(ctx, r, segment.xEnd(), segment.yEnd(), dx, dy, segment.color()); + } } void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const { From 51da01aa11d3ebb199f70680db1f05cd3bdcfc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 19 Mar 2020 11:13:33 +0100 Subject: [PATCH 23/77] [apps/code] Remove 'm_preventEdition' from ConsoleController, it was always used with m_preventEdition = true. --- apps/code/console_controller.cpp | 9 ++------- apps/code/console_controller.h | 1 - 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 5065d85ac..7ab437a64 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -34,8 +34,7 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe m_editCell(this, pythonDelegate, this), m_scriptStore(scriptStore), m_sandboxController(this, this), - m_inputRunLoopActive(false), - m_preventEdition(false) + m_inputRunLoopActive(false) #if EPSILON_GETOPT , m_locked(lockOnConsole) #endif @@ -81,14 +80,12 @@ void ConsoleController::runAndPrintForCommand(const char * command) { assert(m_outputAccumulationBuffer[0] == '\0'); // Draw the console before running the code - m_preventEdition = true; m_editCell.setText(""); m_editCell.setPrompt(""); refreshPrintOutput(); runCode(storedCommand); - m_preventEdition = false; m_editCell.setPrompt(sStandardPromptText); m_editCell.setEditing(true); @@ -413,9 +410,7 @@ void ConsoleController::refreshPrintOutput() { } m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); - if (m_preventEdition) { - m_editCell.setEditing(false); - } + m_editCell.setEditing(false); AppsContainer::sharedAppsContainer()->redrawWindow(); } diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 1fe9b7d34..d3874a9ba 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -103,7 +103,6 @@ private: SandboxController m_sandboxController; bool m_inputRunLoopActive; bool m_autoImportScripts; - bool m_preventEdition; #if EPSILON_GETOPT bool m_locked; #endif From 659da1dff8c78d422a6aeeb6bf4e07341949bddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 20 Mar 2020 13:38:27 +0100 Subject: [PATCH 24/77] [apps][python] ExecutionEnvironment handles hide sand display of sandbox and plot controller the same way --- apps/code/console_controller.cpp | 68 +++++++++----------- apps/code/console_controller.h | 6 +- apps/code/sandbox_controller.cpp | 16 +---- apps/code/sandbox_controller.h | 6 +- python/port/mod/matplotlib/modpyplot.cpp | 2 +- python/port/mod/matplotlib/plot_controller.h | 9 ++- python/port/port.cpp | 16 ++++- python/port/port.h | 29 +++++++-- 8 files changed, 81 insertions(+), 71 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 7ab437a64..3a0d62dbf 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -104,9 +104,7 @@ const char * ConsoleController::inputText(const char * prompt) { m_inputRunLoopActive = true; // Hide the sandbox if it is displayed - if (sandboxIsDisplayed()) { - hideSandbox(); - } + hideAnyDisplayedViewController(); const char * promptText = prompt; char * s = const_cast(prompt); @@ -180,10 +178,6 @@ const char * ConsoleController::inputText(const char * prompt) { return text; } -void ConsoleController::displayViewController(ViewController * controller) { - stackViewController()->push(controller); -} - void ConsoleController::viewWillAppear() { ViewController::viewWillAppear(); loadPythonEnvironment(); @@ -192,12 +186,12 @@ void ConsoleController::viewWillAppear() { autoImport(); } - Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME + //Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); m_editCell.setEditing(true); m_editCell.setText(""); - Container::activeApp()->setFirstResponder(firstResponder); // FIXME + //Container::activeApp()->setFirstResponder(firstResponder); // FIXME } void ConsoleController::didBecomeFirstResponder() { @@ -350,14 +344,15 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c } telemetryReportEvent("Console", text); runAndPrintForCommand(text); - Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME - if (!sandboxIsDisplayed()) { + //Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME + if (viewControllerIsDisplayed(nullptr)) { + // TODO factorize m_selectableTableView.reloadData(); m_editCell.setEditing(true); textField->setText(""); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); } - Container::activeApp()->setFirstResponder(firstResponder); // FIXME + //Container::activeApp()->setFirstResponder(firstResponder); // FIXME return true; } @@ -383,29 +378,29 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) { return true; } -void ConsoleController::displaySandbox() { - if (sandboxIsDisplayed()) { - return; - } - stackViewController()->push(&m_sandboxController); -} - -void ConsoleController::hideSandbox() { - if (!sandboxIsDisplayed()) { - return; - } - m_sandboxController.hide(); -} - void ConsoleController::resetSandbox() { - if (!sandboxIsDisplayed()) { + if (!viewControllerIsDisplayed(sandbox())) { return; } m_sandboxController.reset(); } +void ConsoleController::displayViewController(ViewController * controller) { + if (m_displayedViewController == controller) { + return; + } + stackViewController()->push(controller); +} + +void ConsoleController::hideAnyDisplayedViewController() { + if (m_displayedViewController == nullptr) { + return; + } + stackViewController()->pop(); +} + void ConsoleController::refreshPrintOutput() { - if (sandboxIsDisplayed()) { + if (!viewControllerIsDisplayed(nullptr)) { // Displaying a controller return; } m_selectableTableView.reloadData(); @@ -461,12 +456,11 @@ void ConsoleController::printText(const char * text, size_t length) { } void ConsoleController::autoImportScript(Script script, bool force) { - if (sandboxIsDisplayed()) { - /* The sandbox might be displayed, for instance if we are auto-importing - * several scripts that draw at importation. In this case, we want to remove - * the sandbox. */ - hideSandbox(); - } + /* The sandbox might be displayed, for instance if we are auto-importing + * several scripts that draw at importation. In this case, we want to remove + * the sandbox. */ + hideAnyDisplayedViewController(); + if (script.importationStatus() || force) { // Step 1 - Create the command "from scriptName import *". @@ -492,13 +486,13 @@ void ConsoleController::autoImportScript(Script script, bool force) { // Step 2 - Run the command runAndPrintForCommand(command); } - if (!sandboxIsDisplayed() && force) { - Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME + if (viewControllerIsDisplayed(nullptr) && force) { + //Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); m_editCell.setEditing(true); m_editCell.setText(""); - Container::activeApp()->setFirstResponder(firstResponder); // FIXME + //Container::activeApp()->setFirstResponder(firstResponder); // FIXME } } diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index d3874a9ba..54caed4bb 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -60,13 +60,13 @@ public: bool textFieldDidAbortEditing(TextField * textField) override; // MicroPython::ExecutionEnvironment - void displaySandbox() override; - void hideSandbox() override; + ViewController * sandbox() override { return &m_sandboxController; } void resetSandbox() override; + void displayViewController(ViewController * controller) override; + void hideAnyDisplayedViewController() override; void refreshPrintOutput() override; void printText(const char * text, size_t length) override; const char * inputText(const char * prompt) override; - void displayViewController(ViewController * controller) override; #if EPSILON_GETOPT bool locked() const { diff --git a/apps/code/sandbox_controller.cpp b/apps/code/sandbox_controller.cpp index 5b056c53b..7ffc65f40 100644 --- a/apps/code/sandbox_controller.cpp +++ b/apps/code/sandbox_controller.cpp @@ -5,8 +5,8 @@ namespace Code { SandboxController::SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment) : ViewController(parentResponder), - m_solidColorView(KDColorWhite), - m_executionEnvironment(executionEnvironment) + ExecutionViewControllerHelper(executionEnvironment), + m_solidColorView(KDColorWhite) { assert(executionEnvironment != nullptr); } @@ -20,21 +20,11 @@ void SandboxController::reset() { redrawWindow(); } -void SandboxController::hide() { - stackViewController()->pop(); -} - void SandboxController::viewWillAppear() { - assert(m_executionEnvironment != nullptr); - m_executionEnvironment->setSandboxIsDisplayed(true); + ExecutionViewControllerHelper::viewWillAppear(this); redrawWindow(); } -void SandboxController::viewDidDisappear() { - assert(m_executionEnvironment != nullptr); - m_executionEnvironment->setSandboxIsDisplayed(false); -} - bool SandboxController::handleEvent(Ion::Events::Event event) { // The sandbox handles or "absorbs" all keyboard events except Home and OnOff if (event == Ion::Events::Home || event == Ion::Events::OnOff) { diff --git a/apps/code/sandbox_controller.h b/apps/code/sandbox_controller.h index c50725789..96b82c695 100644 --- a/apps/code/sandbox_controller.h +++ b/apps/code/sandbox_controller.h @@ -9,24 +9,22 @@ namespace Code { -class SandboxController : public ViewController { +class SandboxController : public ViewController, public MicroPython::ExecutionViewControllerHelper { public: SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment); StackViewController * stackViewController(); void reset(); - void hide(); // ViewController View * view() override { return &m_solidColorView; } void viewWillAppear() override; - void viewDidDisappear() override; + void viewDidDisappear() override { MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); } bool handleEvent(Ion::Events::Event event) override; ViewController::DisplayParameter displayParameter() override { return ViewController::DisplayParameter::WantsMaximumSpace; } private: void redrawWindow(); SolidColorView m_solidColorView; - MicroPython::ExecutionEnvironment * m_executionEnvironment; }; } diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 5c8f654ff..2310bbd58 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -28,7 +28,7 @@ static size_t extract_and_validate_plot_input(mp_obj_t x, mp_obj_t y, mp_obj_t * mp_obj_t modpyplot___init__() { static Matplotlib::PlotStore plotStore; - static Matplotlib::PlotController plotController(&plotStore); + static Matplotlib::PlotController plotController(&plotStore, MicroPython::ExecutionEnvironment::currentExecutionEnvironment()); sPlotStore = &plotStore; sPlotController = &plotController; sPlotStore->flush(); diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h index 604da207f..52dcda31c 100644 --- a/python/port/mod/matplotlib/plot_controller.h +++ b/python/port/mod/matplotlib/plot_controller.h @@ -3,14 +3,18 @@ #include #include +#include #include "plot_view.h" #include "plot_store.h" namespace Matplotlib { -class PlotController : public Shared::SimpleInteractiveCurveViewController { +class PlotController : public Shared::SimpleInteractiveCurveViewController, public MicroPython::ExecutionViewControllerHelper { public: - PlotController(PlotStore * store) : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), m_store(store), m_view(m_store) {} + PlotController(PlotStore * store, MicroPython::ExecutionEnvironment * executiveEnvironment) : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), ExecutionViewControllerHelper(executiveEnvironment), m_store(store), m_view(m_store) {} + + void viewWillAppear() override { MicroPython::ExecutionViewControllerHelper::viewWillAppear(this); } + void viewDidDisappear() override { MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); } float cursorBottomMarginRatio() override { return 0.0f; @@ -33,5 +37,4 @@ private: } - #endif diff --git a/python/port/port.cpp b/python/port/port.cpp index d727332a4..1bbff1415 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -95,11 +95,21 @@ void MicroPython::ExecutionEnvironment::interrupt() { mp_keyboard_interrupt(); } -void MicroPython::ExecutionEnvironment::setSandboxIsDisplayed(bool display) { - if (m_sandboxIsDisplayed && !display) { +void MicroPython::ExecutionEnvironment::viewControllerDidDisappear(ViewController * vc) { + if (vc == sandbox()) { modturtle_view_did_disappear(); } - m_sandboxIsDisplayed = display; + m_displayedViewController = nullptr; +} + +void MicroPython::ExecutionViewControllerHelper::viewWillAppear(ViewController * vc) { + assert(m_executionEnvironment != nullptr); + m_executionEnvironment->viewControllerWillAppear(vc); +} + +void MicroPython::ExecutionViewControllerHelper::viewDidDisappear(ViewController * vc) { + assert(m_executionEnvironment != nullptr); + m_executionEnvironment->viewControllerDidDisappear(vc); } extern "C" { diff --git a/python/port/port.h b/python/port/port.h index 55441e2fb..70181e158 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -15,22 +15,37 @@ public: class ExecutionEnvironment { public: - ExecutionEnvironment() : m_sandboxIsDisplayed(false) {} + ExecutionEnvironment() : m_displayedViewController(nullptr) {} static ExecutionEnvironment * currentExecutionEnvironment(); void runCode(const char * ); virtual const char * inputText(const char * prompt) { return nullptr; } - virtual void displaySandbox() {} - virtual void hideSandbox() {} + + // Sandbox + void displaySandbox() { displayViewController(sandbox()); } + virtual ViewController * sandbox() { return nullptr; } virtual void resetSandbox() {} + + // Generic View Controller virtual void displayViewController(ViewController * controller) {} + virtual void hideAnyDisplayedViewController() {} + void viewControllerWillAppear(ViewController * vc) { m_displayedViewController = vc; } + void viewControllerDidDisappear(ViewController * vc); + virtual void printText(const char * text, size_t length) {} virtual void refreshPrintOutput() {} void interrupt(); - void setSandboxIsDisplayed(bool display); protected: - bool sandboxIsDisplayed() const { return m_sandboxIsDisplayed; } + bool viewControllerIsDisplayed(ViewController * vc) const { return m_displayedViewController == vc; } + ViewController * m_displayedViewController; +}; + +class ExecutionViewControllerHelper { +public: + ExecutionViewControllerHelper(ExecutionEnvironment * executionEnvironment) : m_executionEnvironment(executionEnvironment) {} + void viewWillAppear(ViewController * vc); + void viewDidDisappear(ViewController * vc); private: - bool m_sandboxIsDisplayed; + ExecutionEnvironment * m_executionEnvironment; }; void init(void * heapStart, void * heapEnd); @@ -38,6 +53,6 @@ void deinit(); void registerScriptProvider(ScriptProvider * s); void collectRootsAtAddress(char * address, int len); -}; +} #endif From 53ec023ea0316e6d9545cb83f9ec7cbb10be0e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 20 Mar 2020 14:40:02 +0100 Subject: [PATCH 25/77] [apps/code] ConsoleController: factorize code to reload the table --- apps/code/console_controller.cpp | 44 +++++++++++++------------------- apps/code/console_controller.h | 1 + 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 3a0d62dbf..f2b4cf0b5 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -151,9 +151,9 @@ const char * ConsoleController::inputText(const char * prompt) { m_editCell.clearAndReduceSize(); // Reload the history - m_selectableTableView.reloadData(); - m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); - appsContainer->redrawWindow(); + if (reloadData(true)) { + appsContainer->redrawWindow(); + } // Launch a new input loop appsContainer->runWhile([](void * a){ @@ -186,12 +186,7 @@ void ConsoleController::viewWillAppear() { autoImport(); } - //Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME - m_selectableTableView.reloadData(); - m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); - m_editCell.setEditing(true); - m_editCell.setText(""); - //Container::activeApp()->setFirstResponder(firstResponder); // FIXME + reloadData(true); } void ConsoleController::didBecomeFirstResponder() { @@ -344,15 +339,9 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c } telemetryReportEvent("Console", text); runAndPrintForCommand(text); - //Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME if (viewControllerIsDisplayed(nullptr)) { - // TODO factorize - m_selectableTableView.reloadData(); - m_editCell.setEditing(true); - textField->setText(""); - m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); + reloadData(true); } - //Container::activeApp()->setFirstResponder(firstResponder); // FIXME return true; } @@ -400,13 +389,21 @@ void ConsoleController::hideAnyDisplayedViewController() { } void ConsoleController::refreshPrintOutput() { - if (!viewControllerIsDisplayed(nullptr)) { // Displaying a controller - return; + if (viewControllerIsDisplayed(nullptr) && reloadData(false)) { + AppsContainer::sharedAppsContainer()->redrawWindow(); } +} + +bool ConsoleController::reloadData(bool isEditing) { m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); - m_editCell.setEditing(false); - AppsContainer::sharedAppsContainer()->redrawWindow(); + if (isEditing) { + m_editCell.setEditing(true); + m_editCell.setText(""); + } else { + m_editCell.setEditing(false); + } + return true; } /* printText is called by the Python machine. @@ -487,12 +484,7 @@ void ConsoleController::autoImportScript(Script script, bool force) { runAndPrintForCommand(command); } if (viewControllerIsDisplayed(nullptr) && force) { - //Responder * firstResponder = Container::activeApp()->firstResponder(); // FIXME - m_selectableTableView.reloadData(); - m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); - m_editCell.setEditing(true); - m_editCell.setText(""); - //Container::activeApp()->setFirstResponder(firstResponder); // FIXME + reloadData(true); } } diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 54caed4bb..45a7e5fb6 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -82,6 +82,7 @@ private: static constexpr int k_numberOfLineCells = (Ion::Display::Height - Metric::TitleBarHeight) / 14 + 2; // 14 = KDFont::SmallFont->glyphSize().height() // k_numberOfLineCells = (240 - 18)/14 ~ 15.9. The 0.1 cell can be above and below the 15 other cells so we add +2 cells. static constexpr int k_outputAccumulationBufferSize = 100; + bool reloadData(bool isEditing); void flushOutputAccumulationBufferToStore(); void appendTextToOutputAccumulationBuffer(const char * text, size_t length); void emptyOutputAccumulationBuffer(); From 7d48d4e7c418ddda9bc4f220414da6191ff5b68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 20 Mar 2020 16:52:25 +0100 Subject: [PATCH 26/77] [apps/code] Console controller: display only one ExecutionViewController at a time --- apps/code/console_controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index f2b4cf0b5..50867ad81 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -378,6 +378,7 @@ void ConsoleController::displayViewController(ViewController * controller) { if (m_displayedViewController == controller) { return; } + hideAnyDisplayedViewController(); stackViewController()->push(controller); } From 52b6508d6c1befd4c848da0624a1f3c5d9d2bb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 23 Mar 2020 12:27:11 +0100 Subject: [PATCH 27/77] [apps/shared] Create ZoomCurveViewController: SimpleInteractiveCurveViewController inherits from ZoomCurveViewController --- apps/shared/Makefile | 1 + ...mple_interactive_curve_view_controller.cpp | 17 ----------- ...simple_interactive_curve_view_controller.h | 16 ++++------ apps/shared/zoom_curve_view_controller.cpp | 23 ++++++++++++++ apps/shared/zoom_curve_view_controller.h | 30 +++++++++++++++++++ 5 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 apps/shared/zoom_curve_view_controller.cpp create mode 100644 apps/shared/zoom_curve_view_controller.h diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 98e4a8fe6..1185cf65a 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -78,6 +78,7 @@ app_shared_src = $(addprefix apps/shared/,\ values_parameter_controller.cpp \ vertical_cursor_view.cpp \ xy_banner_view.cpp\ + zoom_curve_view_controller.cpp \ zoom_parameter_controller.cpp \ ) diff --git a/apps/shared/simple_interactive_curve_view_controller.cpp b/apps/shared/simple_interactive_curve_view_controller.cpp index 46a4673b1..374ce26a9 100644 --- a/apps/shared/simple_interactive_curve_view_controller.cpp +++ b/apps/shared/simple_interactive_curve_view_controller.cpp @@ -6,16 +6,6 @@ using namespace Poincare; namespace Shared { -SimpleInteractiveCurveViewController::SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) : - ViewController(parentResponder), - m_cursor(cursor) -{ -} - -View * SimpleInteractiveCurveViewController::view() { - return curveView(); -} - bool SimpleInteractiveCurveViewController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::Plus || event == Ion::Events::Minus) { return handleZoom(event); @@ -36,13 +26,6 @@ bool SimpleInteractiveCurveViewController::textFieldDidReceiveEvent(TextField * return TextFieldDelegate::textFieldDidReceiveEvent(textField, event); } -bool SimpleInteractiveCurveViewController::handleZoom(Ion::Events::Event event) { - float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f; - interactiveCurveViewRange()->zoom(ratio, m_cursor->x(), m_cursor->y()); - curveView()->reload(); - return true; -} - bool SimpleInteractiveCurveViewController::handleLeftRightEvent(Ion::Events::Event event) { int direction = event == Ion::Events::Left ? -1 : 1; if (moveCursorHorizontally(direction, Ion::Events::isLongRepetition())) { diff --git a/apps/shared/simple_interactive_curve_view_controller.h b/apps/shared/simple_interactive_curve_view_controller.h index fd30d2998..7827e649b 100644 --- a/apps/shared/simple_interactive_curve_view_controller.h +++ b/apps/shared/simple_interactive_curve_view_controller.h @@ -1,21 +1,17 @@ #ifndef SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H #define SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H -#include #include "text_field_delegate.h" -#include "interactive_curve_view_range.h" -#include "curve_view_cursor.h" -#include "curve_view.h" +#include "zoom_curve_view_controller.h" namespace Shared { /* SimpleInteractiveCurveViewController is a View controller with a cursor that * can handles zoom in/out and left and right events. */ -class SimpleInteractiveCurveViewController : public ViewController, public TextFieldDelegate { +class SimpleInteractiveCurveViewController : public ZoomCurveViewController, public TextFieldDelegate { public: - SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor); - View * view() override; + SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) : ZoomCurveViewController(parentResponder), m_cursor(cursor) {} bool handleEvent(Ion::Events::Event event) override; bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; protected: @@ -24,15 +20,15 @@ protected: virtual float cursorTopMarginRatio() { return 0.07f; } // (cursorHeight/2)/(graphViewHeight-1) virtual float cursorBottomMarginRatio() = 0; // (cursorHeight/2+bannerHeight)/(graphViewHeight-1) constexpr static float k_numberOfCursorStepsInGradUnit = 5.0f; - virtual bool handleZoom(Ion::Events::Event event); + // ZoomCurveViewController + float xFocus() override { return m_cursor->x(); } + float yFocus() override { return m_cursor->y(); } virtual bool handleLeftRightEvent(Ion::Events::Event event); virtual void reloadBannerView() = 0; /* the result of moveCursorVertically/Horizontally means: * false -> the cursor cannot move in this direction * true -> the cursor moved */ virtual bool moveCursorHorizontally(int direction, bool fast = false) { return false; } - virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0; - virtual CurveView * curveView() = 0; virtual bool handleEnter() = 0; CurveViewCursor * m_cursor; }; diff --git a/apps/shared/zoom_curve_view_controller.cpp b/apps/shared/zoom_curve_view_controller.cpp new file mode 100644 index 000000000..45c25078d --- /dev/null +++ b/apps/shared/zoom_curve_view_controller.cpp @@ -0,0 +1,23 @@ +#include "zoom_curve_view_controller.h" +#include +#include + +using namespace Poincare; + +namespace Shared { + +bool ZoomCurveViewController::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::Plus || event == Ion::Events::Minus) { + return handleZoom(event); + } + return false; +} + +bool ZoomCurveViewController::handleZoom(Ion::Events::Event event) { + float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f; + interactiveCurveViewRange()->zoom(ratio, xFocus(), yFocus()); + curveView()->reload(); + return true; +} + +} diff --git a/apps/shared/zoom_curve_view_controller.h b/apps/shared/zoom_curve_view_controller.h new file mode 100644 index 000000000..97698ae76 --- /dev/null +++ b/apps/shared/zoom_curve_view_controller.h @@ -0,0 +1,30 @@ +#ifndef SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H +#define SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H + +#include +#include "interactive_curve_view_range.h" +#include "curve_view_cursor.h" +#include "curve_view.h" + +namespace Shared { + +/* ZoomCurveViewController is a View controller with a cursor that can handles + * zoom in/out events. */ + +class ZoomCurveViewController : public ViewController { +public: + ZoomCurveViewController(Responder * parentResponder) : ViewController(parentResponder) {} + View * view() override { return curveView(); } + bool handleEvent(Ion::Events::Event event) override; +protected: + virtual bool handleZoom(Ion::Events::Event event); + virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0; + virtual CurveView * curveView() = 0; + virtual float xFocus() = 0; + virtual float yFocus() = 0; + CurveViewCursor * m_cursor; +}; + +} + +#endif From d504564334aa094baaaa788b480506c0f9ffaff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 23 Mar 2020 13:44:56 +0100 Subject: [PATCH 28/77] [apps/shared] Create ZoomAndPanCurveViewController, ZoomParameterController inherits from ZoomAndPanCurveViewController --- apps/shared/Makefile | 1 + .../zoom_and_pan_curve_view_controller.cpp | 35 ++++++++++++++++ .../zoom_and_pan_curve_view_controller.h | 23 +++++++++++ apps/shared/zoom_parameter_controller.cpp | 41 +------------------ apps/shared/zoom_parameter_controller.h | 16 +++++--- 5 files changed, 70 insertions(+), 46 deletions(-) create mode 100644 apps/shared/zoom_and_pan_curve_view_controller.cpp create mode 100644 apps/shared/zoom_and_pan_curve_view_controller.h diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 1185cf65a..00a676226 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -79,6 +79,7 @@ app_shared_src = $(addprefix apps/shared/,\ vertical_cursor_view.cpp \ xy_banner_view.cpp\ zoom_curve_view_controller.cpp \ + zoom_and_pan_curve_view_controller.cpp \ zoom_parameter_controller.cpp \ ) diff --git a/apps/shared/zoom_and_pan_curve_view_controller.cpp b/apps/shared/zoom_and_pan_curve_view_controller.cpp new file mode 100644 index 000000000..eff23f303 --- /dev/null +++ b/apps/shared/zoom_and_pan_curve_view_controller.cpp @@ -0,0 +1,35 @@ +#include "zoom_and_pan_curve_view_controller.h" +#include +#include + +using namespace Poincare; + +namespace Shared { + +bool ZoomAndPanCurveViewController::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::Left || event == Ion::Events::Right || event == Ion::Events::Up || event == Ion::Events::Down) { + return handlePan(event); + } + return ZoomCurveViewController::handleEvent(event); +} + +bool ZoomAndPanCurveViewController::handlePan(Ion::Events::Event event) { + float xMove = 0.0f; + float yMove = 0.0f; + if (event == Ion::Events::Up) { + yMove = interactiveCurveViewRange()->yGridUnit(); + } else if (event == Ion::Events::Down) { + yMove = -interactiveCurveViewRange()->yGridUnit(); + } else if (event == Ion::Events::Left) { + xMove = -interactiveCurveViewRange()->xGridUnit(); + } else { + assert(event == Ion::Events::Right); + xMove = interactiveCurveViewRange()->xGridUnit(); + } + interactiveCurveViewRange()->panWithVector(xMove, yMove); + curveView()->reload(); + return true; +} + +} + diff --git a/apps/shared/zoom_and_pan_curve_view_controller.h b/apps/shared/zoom_and_pan_curve_view_controller.h new file mode 100644 index 000000000..e17f9ddf5 --- /dev/null +++ b/apps/shared/zoom_and_pan_curve_view_controller.h @@ -0,0 +1,23 @@ +#ifndef SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H +#define SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H + +#include "zoom_curve_view_controller.h" + +namespace Shared { + +/* ZoomAndPanCurveViewController is a View controller with a cursor that can + * handles zoom in/out and directional pan events. */ + +class ZoomAndPanCurveViewController : public ZoomCurveViewController { +public: + ZoomAndPanCurveViewController(Responder * parentResponder) : ZoomCurveViewController(parentResponder) {} + bool handleEvent(Ion::Events::Event event) override; +protected: + virtual bool handlePan(Ion::Events::Event event); + float xFocus() override { return interactiveCurveViewRange()->xCenter(); } + float yFocus() override { return interactiveCurveViewRange()->yCenter(); } +}; + +} + +#endif diff --git a/apps/shared/zoom_parameter_controller.cpp b/apps/shared/zoom_parameter_controller.cpp index 222a63732..fffc06680 100644 --- a/apps/shared/zoom_parameter_controller.cpp +++ b/apps/shared/zoom_parameter_controller.cpp @@ -5,7 +5,7 @@ namespace Shared { ZoomParameterController::ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveRange, CurveView * curveView) : - ViewController(parentResponder), + ZoomAndPanCurveViewController(parentResponder), m_contentView(curveView), m_interactiveRange(interactiveRange) { @@ -15,45 +15,6 @@ const char * ZoomParameterController::title() { return I18n::translate(I18n::Message::Zoom); } -View * ZoomParameterController::view() { - return &m_contentView; -} - -bool ZoomParameterController::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::Plus) { - m_interactiveRange->zoom(2.0f/3.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter()); - m_contentView.curveView()->reload(); - return true; - } - if (event == Ion::Events::Minus) { - m_interactiveRange->zoom(3.0f/2.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter()); - m_contentView.curveView()->reload(); - return true; - } - if (event == Ion::Events::Up) { - m_interactiveRange->panWithVector(0.0f, m_interactiveRange->yGridUnit()); - m_contentView.curveView()->reload(); - return true; - } - if (event == Ion::Events::Down) { - m_interactiveRange->panWithVector(0.0f, -m_interactiveRange->yGridUnit()); - m_contentView.curveView()->reload(); - return true; - } - if (event == Ion::Events::Left) { - m_interactiveRange->panWithVector(-m_interactiveRange->xGridUnit(), 0.0f); - m_contentView.curveView()->reload(); - return true; - } - if (event == Ion::Events::Right) { - m_interactiveRange->panWithVector(m_interactiveRange->xGridUnit(), 0.0f); - m_contentView.curveView()->reload(); - return true; - } - - return false; -} - void ZoomParameterController::viewWillAppear() { ViewController::viewWillAppear(); m_contentView.curveView()->setOkView(nullptr); diff --git a/apps/shared/zoom_parameter_controller.h b/apps/shared/zoom_parameter_controller.h index 3f8758afa..293f166cf 100644 --- a/apps/shared/zoom_parameter_controller.h +++ b/apps/shared/zoom_parameter_controller.h @@ -1,25 +1,23 @@ #ifndef SHARED_ZOOM_PARAMETER_CONTROLLER_H #define SHARED_ZOOM_PARAMETER_CONTROLLER_H -#include -#include "interactive_curve_view_range.h" -#include "curve_view.h" +#include "zoom_and_pan_curve_view_controller.h" #include namespace Shared { -class ZoomParameterController : public ViewController { +class ZoomParameterController : public ZoomAndPanCurveViewController { public: ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveCurveViewRange, CurveView * curveView); const char * title() override; - View * view() override; - bool handleEvent(Ion::Events::Event event) override; + View * view() override { return &m_contentView; } void viewWillAppear() override; void viewDidDisappear() override; void didBecomeFirstResponder() override; TELEMETRY_ID("Zoom"); private: constexpr static KDCoordinate k_standardViewHeight = 175; + class ContentView : public View { public: constexpr static KDCoordinate k_legendHeight = 30; @@ -46,7 +44,13 @@ private: CurveView * m_curveView; LegendView m_legendView; }; + void adaptCurveRange(bool viewWillAppear); + + // ZoomAndPanCurveViewController + InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_interactiveRange; } + CurveView * curveView() override { return m_contentView.curveView(); } + ContentView m_contentView; InteractiveCurveViewRange * m_interactiveRange; }; From 4022cdfa6098dafb01f895583d1ea26115893fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 23 Mar 2020 13:53:26 +0100 Subject: [PATCH 29/77] [python] Matplotlib: plot_controller inherits from ZoomAndPanCurveViewController to be able to pan --- python/port/mod/matplotlib/plot_controller.h | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h index 52dcda31c..eba046b24 100644 --- a/python/port/mod/matplotlib/plot_controller.h +++ b/python/port/mod/matplotlib/plot_controller.h @@ -1,37 +1,25 @@ #ifndef PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H #define PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H -#include -#include +#include #include #include "plot_view.h" #include "plot_store.h" namespace Matplotlib { -class PlotController : public Shared::SimpleInteractiveCurveViewController, public MicroPython::ExecutionViewControllerHelper { +class PlotController : public Shared::ZoomAndPanCurveViewController, public MicroPython::ExecutionViewControllerHelper { public: - PlotController(PlotStore * store, MicroPython::ExecutionEnvironment * executiveEnvironment) : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), ExecutionViewControllerHelper(executiveEnvironment), m_store(store), m_view(m_store) {} + PlotController(PlotStore * store, MicroPython::ExecutionEnvironment * executiveEnvironment) : Shared::ZoomAndPanCurveViewController(nullptr), ExecutionViewControllerHelper(executiveEnvironment), m_store(store), m_view(m_store) {} void viewWillAppear() override { MicroPython::ExecutionViewControllerHelper::viewWillAppear(this); } void viewDidDisappear() override { MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); } - float cursorBottomMarginRatio() override { - return 0.0f; - } - virtual void reloadBannerView() override { - } - - virtual bool handleEnter() override { - return false; - } - protected: Shared::CurveView * curveView() override { return &m_view; } Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_store; } private: PlotStore * m_store; - Shared::CurveViewCursor m_cursor; PlotView m_view; }; From bd3fa60594ea97bd7001e5ffb8055b8037eca8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 23 Mar 2020 13:56:17 +0100 Subject: [PATCH 30/77] [app/graph] Enables zoom on CalculationGraphControllers --- apps/graph/graph/calculation_graph_controller.h | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/graph/graph/calculation_graph_controller.h b/apps/graph/graph/calculation_graph_controller.h index 46f861ddf..14f5cc797 100644 --- a/apps/graph/graph/calculation_graph_controller.h +++ b/apps/graph/graph/calculation_graph_controller.h @@ -30,7 +30,6 @@ protected: MessageTextView m_defaultBannerView; bool m_isActive; private: - bool handleZoom(Ion::Events::Event event) override { return false; } bool handleEnter() override; bool moveCursorHorizontally(int direction, bool fast = false) override; Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; } From c4847b22cc128ff8c6b3a150fe6649feac8caf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 23 Mar 2020 14:04:58 +0100 Subject: [PATCH 31/77] Coding style --- python/port/mod/matplotlib/modpyplot.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 2310bbd58..8077d6ffc 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -13,7 +13,7 @@ static int paletteIndex = 0; // Private helper -static size_t extract_and_validate_plot_input(mp_obj_t x, mp_obj_t y, mp_obj_t ** xItems, mp_obj_t ** yItems) { +static size_t extractAndValidatePlotInput(mp_obj_t x, mp_obj_t y, mp_obj_t ** xItems, mp_obj_t ** yItems) { // Input parameter validation size_t xLength, yLength; mp_obj_get_array(x, &xLength, xItems); @@ -90,7 +90,7 @@ mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height) { // Input parameter validation mp_obj_t * xItems, * hItems; - size_t length = extract_and_validate_plot_input(x, height, &xItems, &hItems); + size_t length = extractAndValidatePlotInput(x, height, &xItems, &hItems); mp_float_t w = 0.8; // TODO: w should be an optional parameter KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine @@ -201,7 +201,7 @@ mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { // Input parameter validation mp_obj_t * xItems, * yItems; - size_t length = extract_and_validate_plot_input(x, y, &xItems, &yItems); + size_t length = extractAndValidatePlotInput(x, y, &xItems, &yItems); KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine for (size_t i=0; i Date: Mon, 23 Mar 2020 18:16:29 +0100 Subject: [PATCH 32/77] [escher] Palette: factorize data color iteration --- apps/regression/calculation_controller.cpp | 1 + apps/regression/graph_controller.cpp | 1 + apps/regression/graph_view.cpp | 1 + apps/sequence/sequence_store.cpp | 1 + apps/shared/continuous_function.cpp | 3 +-- apps/shared/double_pair_store.h | 2 ++ escher/include/escher/palette.h | 5 +++++ escher/src/palette.cpp | 9 +++++++++ python/port/mod/matplotlib/modpyplot.cpp | 10 +++++----- 9 files changed, 26 insertions(+), 7 deletions(-) diff --git a/apps/regression/calculation_controller.cpp b/apps/regression/calculation_controller.cpp index 4d24c7c26..548241564 100644 --- a/apps/regression/calculation_controller.cpp +++ b/apps/regression/calculation_controller.cpp @@ -168,6 +168,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int myCell->setFirstText(buffer); buffer[0] = 'Y'; myCell->setSecondText(buffer); + assert(seriesNumber < Palette::numberOfDataColors()); myCell->setColor(Palette::DataColor[seriesNumber]); return; } diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index b6b54aaf1..93b5c5867 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -407,6 +407,7 @@ void GraphController::setRoundCrossCursorView() { bool round = *m_selectedDotIndex < 0; if (round) { // Set the color although the cursor view stays round + assert(*m_selectedSeriesIndex < Palette::numberOfDataColors()); m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]); } CursorView * nextCursorView = round ? static_cast(&m_roundCursorView) : static_cast(&m_crossCursorView); diff --git a/apps/regression/graph_view.cpp b/apps/regression/graph_view.cpp index 3b7b1371a..37ee68097 100644 --- a/apps/regression/graph_view.cpp +++ b/apps/regression/graph_view.cpp @@ -22,6 +22,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { Poincare::Context * globContext = AppsContainer::sharedAppsContainer()->globalContext(); for (int series = 0; series < Store::k_numberOfSeries; series++) { if (!m_store->seriesIsEmpty(series)) { + assert(series < Palette::numberOfDataColors()); KDColor color = Palette::DataColor[series]; Model * seriesModel = m_store->modelForSeries(series); drawCartesianCurve(ctx, rect, -INFINITY, INFINITY, [](float abscissa, void * model, void * context) { diff --git a/apps/sequence/sequence_store.cpp b/apps/sequence/sequence_store.cpp index d15543595..18012cfa6 100644 --- a/apps/sequence/sequence_store.cpp +++ b/apps/sequence/sequence_store.cpp @@ -31,6 +31,7 @@ Ion::Storage::Record::ErrorStatus SequenceStore::addEmptyModel() { const char * name = firstAvailableName(&nameIndex); assert(name); // Choose the corresponding color + assert(nameIndex < Palette::numberOfDataColors()); KDColor color = Palette::DataColor[nameIndex]; Sequence::RecordDataBuffer data(color); // m_sequences diff --git a/apps/shared/continuous_function.cpp b/apps/shared/continuous_function.cpp index 96a7cb19a..fdb4fd2cc 100644 --- a/apps/shared/continuous_function.cpp +++ b/apps/shared/continuous_function.cpp @@ -57,8 +57,7 @@ ContinuousFunction ContinuousFunction::NewModel(Ion::Storage::Record::ErrorStatu static int s_colorIndex = 0; // Create the record char nameBuffer[SymbolAbstract::k_maxNameSize]; - int numberOfColors = sizeof(Palette::DataColor)/sizeof(KDColor); - RecordDataBuffer data(Palette::DataColor[s_colorIndex++ % numberOfColors]); + RecordDataBuffer data(Palette::nextDataColor(&s_colorIndex)); if (baseName == nullptr) { DefaultName(nameBuffer, SymbolAbstract::k_maxNameSize); baseName = nameBuffer; diff --git a/apps/shared/double_pair_store.h b/apps/shared/double_pair_store.h index 9c8859612..f83e88812 100644 --- a/apps/shared/double_pair_store.h +++ b/apps/shared/double_pair_store.h @@ -55,10 +55,12 @@ public: // Colors static KDColor colorOfSeriesAtIndex(int i) { assert(i >= 0 && i < k_numberOfSeries); + assert(i < Palette::numberOfDataColors()); return Palette::DataColor[i]; } static KDColor colorLightOfSeriesAtIndex(int i) { assert(i >= 0 && i < k_numberOfSeries); + assert(i < Palette::numberOfLightDataColors()); return Palette::DataColorLight[i]; } protected: diff --git a/escher/include/escher/palette.h b/escher/include/escher/palette.h index b4c2c1a95..0ebc550a7 100644 --- a/escher/include/escher/palette.h +++ b/escher/include/escher/palette.h @@ -2,6 +2,7 @@ #define ESCHER_PALETTE_H #include +#include class Palette { public: @@ -34,6 +35,10 @@ public: constexpr static KDColor Purple = KDColor::RGB24(0x6e2d79); constexpr static KDColor DataColor[] = {Red, Blue, Green, YellowDark, Magenta, Turquoise, Pink, Orange}; constexpr static KDColor DataColorLight[] = {RedLight, BlueLight, GreenLight, YellowLight}; + + constexpr static size_t numberOfDataColors() { return sizeof(DataColor)/sizeof(KDColor); } + constexpr static size_t numberOfLightDataColors() { return sizeof(DataColorLight)/sizeof(KDColor); } + static KDColor nextDataColor(int * colorIndex); }; #endif diff --git a/escher/src/palette.cpp b/escher/src/palette.cpp index dcb617ee7..2d6e91145 100644 --- a/escher/src/palette.cpp +++ b/escher/src/palette.cpp @@ -1,4 +1,5 @@ #include +#include constexpr KDColor Palette::YellowDark; constexpr KDColor Palette::YellowLight; @@ -29,3 +30,11 @@ constexpr KDColor Palette::Brown; constexpr KDColor Palette::Purple; constexpr KDColor Palette::DataColor[]; constexpr KDColor Palette::DataColorLight[]; + +KDColor Palette::nextDataColor(int * colorIndex) { + size_t nbOfColors = numberOfDataColors(); + assert(*colorIndex < nbOfColors); + KDColor c = DataColor[*colorIndex]; + *colorIndex = (*colorIndex + 1) % nbOfColors; + return c; +} diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 8077d6ffc..81972335e 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -50,7 +50,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { assert(n_args == 4); assert(sPlotStore != nullptr); - KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + KDColor color = Palette::nextDataColor(&paletteIndex); sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0])+mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1])+mp_obj_get_float(args[3])), color, true); return mp_const_none; @@ -93,7 +93,7 @@ mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height) { size_t length = extractAndValidatePlotInput(x, height, &xItems, &hItems); mp_float_t w = 0.8; // TODO: w should be an optional parameter - KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + KDColor color = Palette::nextDataColor(&paletteIndex); for (size_t i=0; iaddRect(edgeItems[i], binItems[i], mp_obj_new_float(width), binItems[i], color); @@ -203,7 +203,7 @@ mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { mp_obj_t * xItems, * yItems; size_t length = extractAndValidatePlotInput(x, y, &xItems, &yItems); - KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + KDColor color = Palette::nextDataColor(&paletteIndex); for (size_t i=0; iaddDot(xItems[i], yItems[i], color); } @@ -218,7 +218,7 @@ mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { mp_obj_t * xItems, * yItems; size_t length = extractAndValidatePlotInput(x, y, &xItems, &yItems); - KDColor color = Palette::DataColor[paletteIndex++]; // FIXME: Share overflow routine + KDColor color = Palette::nextDataColor(&paletteIndex); for (size_t i=0; iaddSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color, false); } From 24cd5079d45059c14dc266d71f673723cc162b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 23 Mar 2020 18:16:54 +0100 Subject: [PATCH 33/77] [python] matplotlib: fix modpyplot_gc_collect --- python/port/mod/matplotlib/modpyplot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 81972335e..3ab8682bd 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -37,11 +37,11 @@ mp_obj_t modpyplot___init__() { } void modpyplot_gc_collect() { - if (sPlotStore != nullptr) { + if (sPlotStore == nullptr) { return; } MicroPython::collectRootsAtAddress( - reinterpret_cast(&sPlotStore), + reinterpret_cast(sPlotStore), sizeof(Matplotlib::PlotStore) ); } From 7e73afc654c2202fb17088fda4d35d2115353092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 24 Mar 2020 10:02:41 +0100 Subject: [PATCH 34/77] [python] Matplotlib: flush the plot store when the controller is popped --- python/port/mod/matplotlib/plot_controller.cpp | 10 ++++++++++ python/port/mod/matplotlib/plot_controller.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/plot_controller.cpp b/python/port/mod/matplotlib/plot_controller.cpp index e69de29bb..fabb0eac9 100644 --- a/python/port/mod/matplotlib/plot_controller.cpp +++ b/python/port/mod/matplotlib/plot_controller.cpp @@ -0,0 +1,10 @@ +#include "plot_controller.h" + +namespace Matplotlib { + +void PlotController::viewDidDisappear() { + MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); + m_store->flush(); +} + +} diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h index eba046b24..88dc9d213 100644 --- a/python/port/mod/matplotlib/plot_controller.h +++ b/python/port/mod/matplotlib/plot_controller.h @@ -13,7 +13,7 @@ public: PlotController(PlotStore * store, MicroPython::ExecutionEnvironment * executiveEnvironment) : Shared::ZoomAndPanCurveViewController(nullptr), ExecutionViewControllerHelper(executiveEnvironment), m_store(store), m_view(m_store) {} void viewWillAppear() override { MicroPython::ExecutionViewControllerHelper::viewWillAppear(this); } - void viewDidDisappear() override { MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); } + void viewDidDisappear() override; protected: Shared::CurveView * curveView() override { return &m_view; } From 89b54d424e1e77f1c9b184dfc1dd33ddce8c9b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 24 Mar 2020 17:13:22 +0100 Subject: [PATCH 35/77] [apps/code] ConsoleController: when becoming first responder, check if a controller is displayed and switch the first responder accordingly --- apps/code/console_controller.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 50867ad81..82baed48a 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -190,7 +190,16 @@ void ConsoleController::viewWillAppear() { } void ConsoleController::didBecomeFirstResponder() { - Container::activeApp()->setFirstResponder(&m_editCell); + if (viewControllerIsDisplayed(nullptr)) { + Container::activeApp()->setFirstResponder(&m_editCell); + } else { + /* A view controller might be displayed: for example, when pushing the + * console on the stack controller, we auto-import scripts during the + * 'viewWillAppear' and then we set the console as first responder. The + * sandbox or the matplotlib controller might have been pushed in the + * auto-import. */ + Container::activeApp()->setFirstResponder(m_displayedViewController); + } } bool ConsoleController::handleEvent(Ion::Events::Event event) { From 15e5f7a285d367cad482e8009f67919b9e1317bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 24 Mar 2020 17:17:04 +0100 Subject: [PATCH 36/77] [python] Matplotlib: reload labels in PlotController::viewWillAppear --- python/port/mod/matplotlib/plot_controller.cpp | 5 +++++ python/port/mod/matplotlib/plot_controller.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/plot_controller.cpp b/python/port/mod/matplotlib/plot_controller.cpp index fabb0eac9..8a5e329b3 100644 --- a/python/port/mod/matplotlib/plot_controller.cpp +++ b/python/port/mod/matplotlib/plot_controller.cpp @@ -2,6 +2,11 @@ namespace Matplotlib { +void PlotController::viewWillAppear() { + MicroPython::ExecutionViewControllerHelper::viewWillAppear(this); + curveView()->reload(); +} + void PlotController::viewDidDisappear() { MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); m_store->flush(); diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h index 88dc9d213..7b4390edc 100644 --- a/python/port/mod/matplotlib/plot_controller.h +++ b/python/port/mod/matplotlib/plot_controller.h @@ -12,7 +12,7 @@ class PlotController : public Shared::ZoomAndPanCurveViewController, public Micr public: PlotController(PlotStore * store, MicroPython::ExecutionEnvironment * executiveEnvironment) : Shared::ZoomAndPanCurveViewController(nullptr), ExecutionViewControllerHelper(executiveEnvironment), m_store(store), m_view(m_store) {} - void viewWillAppear() override { MicroPython::ExecutionViewControllerHelper::viewWillAppear(this); } + void viewWillAppear() override; void viewDidDisappear() override; protected: From d0c5ac03431c5f8774e5b82929fdb9a6a332e236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 09:36:43 +0100 Subject: [PATCH 37/77] [escher] StackViewController: add a method to return the topViewController --- escher/include/escher/stack_view_controller.h | 1 + escher/src/stack_view_controller.cpp | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/escher/include/escher/stack_view_controller.h b/escher/include/escher/stack_view_controller.h index 47addd0ea..02d6318fc 100644 --- a/escher/include/escher/stack_view_controller.h +++ b/escher/include/escher/stack_view_controller.h @@ -18,6 +18,7 @@ public: int depth(); View * view() override; + ViewController * topViewController(); const char * title() override; bool handleEvent(Ion::Events::Event event) override; void didBecomeFirstResponder() override; diff --git a/escher/src/stack_view_controller.cpp b/escher/src/stack_view_controller.cpp index 8aa337d17..2b88c2288 100644 --- a/escher/src/stack_view_controller.cpp +++ b/escher/src/stack_view_controller.cpp @@ -92,6 +92,13 @@ const char * StackViewController::title() { return vc->title(); } +ViewController * StackViewController::topViewController() { + if (m_numberOfChildren < 1) { + return nullptr; + } + return m_childrenFrame[m_numberOfChildren-1].viewController(); +} + void StackViewController::push(ViewController * vc, KDColor textColor, KDColor backgroundColor, KDColor separatorColor) { Frame frame = Frame(vc, textColor, backgroundColor, separatorColor); /* Add the frame to the model */ @@ -112,7 +119,7 @@ void StackViewController::push(ViewController * vc, KDColor textColor, KDColor b void StackViewController::pop() { assert(m_numberOfChildren > 0); - ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController(); + ViewController * vc = topViewController(); if (vc->title() != nullptr && vc->displayParameter() != ViewController::DisplayParameter::DoNotShowOwnTitle) { m_view.popStack(); } @@ -131,7 +138,7 @@ void StackViewController::pushModel(Frame frame) { } void StackViewController::setupActiveViewController() { - ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController(); + ViewController * vc = topViewController(); vc->setParentResponder(this); m_view.shouldDisplayStackHearders(vc->displayParameter() != ViewController::DisplayParameter::WantsMaximumSpace); m_view.setContentView(vc->view()); @@ -141,7 +148,7 @@ void StackViewController::setupActiveViewController() { } void StackViewController::didBecomeFirstResponder() { - ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController(); + ViewController * vc = topViewController(); Container::activeApp()->setFirstResponder(vc); } @@ -170,7 +177,7 @@ void StackViewController::viewWillAppear() { } } /* Load the visible controller view */ - ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController(); + ViewController * vc = topViewController(); if (m_numberOfChildren > 0 && vc) { m_view.setContentView(vc->view()); m_view.shouldDisplayStackHearders(vc->displayParameter() != ViewController::DisplayParameter::WantsMaximumSpace); @@ -180,7 +187,7 @@ void StackViewController::viewWillAppear() { } void StackViewController::viewDidDisappear() { - ViewController * vc = m_childrenFrame[m_numberOfChildren-1].viewController(); + ViewController * vc = topViewController(); if (m_numberOfChildren > 0 && vc) { vc->viewDidDisappear(); } From fb3f6ab6f3813786b9fa21a6fd5b8f1d17162d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 09:42:36 +0100 Subject: [PATCH 38/77] [apps/code][python] ConsoleController doesn't keep any pointer/boolean to know if the sandbox/matplotlib view controller is displayed. Its state won't be always right; instead, use the StackViewController depth. This fixes the following bug: when popping the sandbox/matplotlib view controller, the first responder token was not given to the console controller! --- apps/code/console_controller.cpp | 27 ++++++++++++------- apps/code/console_controller.h | 1 + apps/code/sandbox_controller.cpp | 13 ++++++--- apps/code/sandbox_controller.h | 6 ++--- python/port/mod/matplotlib/modpyplot.cpp | 2 +- .../port/mod/matplotlib/plot_controller.cpp | 2 -- python/port/mod/matplotlib/plot_controller.h | 5 ++-- python/port/port.cpp | 17 ------------ python/port/port.h | 16 +---------- 9 files changed, 35 insertions(+), 54 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 82baed48a..9a4455315 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -33,7 +33,7 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe m_selectableTableView(this, this, this, this), m_editCell(this, pythonDelegate, this), m_scriptStore(scriptStore), - m_sandboxController(this, this), + m_sandboxController(this), m_inputRunLoopActive(false) #if EPSILON_GETOPT , m_locked(lockOnConsole) @@ -190,7 +190,7 @@ void ConsoleController::viewWillAppear() { } void ConsoleController::didBecomeFirstResponder() { - if (viewControllerIsDisplayed(nullptr)) { + if (!isDisplayingViewController()) { Container::activeApp()->setFirstResponder(&m_editCell); } else { /* A view controller might be displayed: for example, when pushing the @@ -198,7 +198,7 @@ void ConsoleController::didBecomeFirstResponder() { * 'viewWillAppear' and then we set the console as first responder. The * sandbox or the matplotlib controller might have been pushed in the * auto-import. */ - Container::activeApp()->setFirstResponder(m_displayedViewController); + Container::activeApp()->setFirstResponder(stackViewController()->topViewController()); } } @@ -348,7 +348,7 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c } telemetryReportEvent("Console", text); runAndPrintForCommand(text); - if (viewControllerIsDisplayed(nullptr)) { + if (!isDisplayingViewController()) { reloadData(true); } return true; @@ -377,14 +377,14 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) { } void ConsoleController::resetSandbox() { - if (!viewControllerIsDisplayed(sandbox())) { + if (stackViewController()->topViewController() != sandbox()) { return; } m_sandboxController.reset(); } void ConsoleController::displayViewController(ViewController * controller) { - if (m_displayedViewController == controller) { + if (stackViewController()->topViewController() == controller) { return; } hideAnyDisplayedViewController(); @@ -392,14 +392,23 @@ void ConsoleController::displayViewController(ViewController * controller) { } void ConsoleController::hideAnyDisplayedViewController() { - if (m_displayedViewController == nullptr) { + if (!isDisplayingViewController()) { return; } stackViewController()->pop(); } +bool ConsoleController::isDisplayingViewController() { + /* The StackViewController model state is the best way to know wether the + * console is displaying a View Controller (Sandbox or Matplotlib). Indeed, + * keeping a boolean or a pointer raises the issue of when updating it - when + * 'viewWillAppear' or when 'didEnterResponderChain' - in both cases, the + * state would be wrong at some point... */ + return stackViewController()->depth() > 2; +} + void ConsoleController::refreshPrintOutput() { - if (viewControllerIsDisplayed(nullptr) && reloadData(false)) { + if (!isDisplayingViewController() && reloadData(false)) { AppsContainer::sharedAppsContainer()->redrawWindow(); } } @@ -493,7 +502,7 @@ void ConsoleController::autoImportScript(Script script, bool force) { // Step 2 - Run the command runAndPrintForCommand(command); } - if (viewControllerIsDisplayed(nullptr) && force) { + if (!isDisplayingViewController() && force) { reloadData(true); } } diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 45a7e5fb6..09192ce39 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -82,6 +82,7 @@ private: static constexpr int k_numberOfLineCells = (Ion::Display::Height - Metric::TitleBarHeight) / 14 + 2; // 14 = KDFont::SmallFont->glyphSize().height() // k_numberOfLineCells = (240 - 18)/14 ~ 15.9. The 0.1 cell can be above and below the 15 other cells so we add +2 cells. static constexpr int k_outputAccumulationBufferSize = 100; + bool isDisplayingViewController(); bool reloadData(bool isEditing); void flushOutputAccumulationBufferToStore(); void appendTextToOutputAccumulationBuffer(const char * text, size_t length); diff --git a/apps/code/sandbox_controller.cpp b/apps/code/sandbox_controller.cpp index 7ffc65f40..7282f0138 100644 --- a/apps/code/sandbox_controller.cpp +++ b/apps/code/sandbox_controller.cpp @@ -1,14 +1,16 @@ #include "sandbox_controller.h" #include +extern "C" { +#include +} + namespace Code { -SandboxController::SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment) : +SandboxController::SandboxController(Responder * parentResponder) : ViewController(parentResponder), - ExecutionViewControllerHelper(executionEnvironment), m_solidColorView(KDColorWhite) { - assert(executionEnvironment != nullptr); } StackViewController * SandboxController::stackViewController() { @@ -21,10 +23,13 @@ void SandboxController::reset() { } void SandboxController::viewWillAppear() { - ExecutionViewControllerHelper::viewWillAppear(this); redrawWindow(); } +void SandboxController::viewDidDisappear() { + modturtle_view_did_disappear(); +} + bool SandboxController::handleEvent(Ion::Events::Event event) { // The sandbox handles or "absorbs" all keyboard events except Home and OnOff if (event == Ion::Events::Home || event == Ion::Events::OnOff) { diff --git a/apps/code/sandbox_controller.h b/apps/code/sandbox_controller.h index 96b82c695..b5f52bc0f 100644 --- a/apps/code/sandbox_controller.h +++ b/apps/code/sandbox_controller.h @@ -9,16 +9,16 @@ namespace Code { -class SandboxController : public ViewController, public MicroPython::ExecutionViewControllerHelper { +class SandboxController : public ViewController { public: - SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment); + SandboxController(Responder * parentResponder); StackViewController * stackViewController(); void reset(); // ViewController View * view() override { return &m_solidColorView; } void viewWillAppear() override; - void viewDidDisappear() override { MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); } + void viewDidDisappear() override; bool handleEvent(Ion::Events::Event event) override; ViewController::DisplayParameter displayParameter() override { return ViewController::DisplayParameter::WantsMaximumSpace; } diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 3ab8682bd..32f156387 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -28,7 +28,7 @@ static size_t extractAndValidatePlotInput(mp_obj_t x, mp_obj_t y, mp_obj_t ** xI mp_obj_t modpyplot___init__() { static Matplotlib::PlotStore plotStore; - static Matplotlib::PlotController plotController(&plotStore, MicroPython::ExecutionEnvironment::currentExecutionEnvironment()); + static Matplotlib::PlotController plotController(&plotStore); sPlotStore = &plotStore; sPlotController = &plotController; sPlotStore->flush(); diff --git a/python/port/mod/matplotlib/plot_controller.cpp b/python/port/mod/matplotlib/plot_controller.cpp index 8a5e329b3..eb7aa0abf 100644 --- a/python/port/mod/matplotlib/plot_controller.cpp +++ b/python/port/mod/matplotlib/plot_controller.cpp @@ -3,12 +3,10 @@ namespace Matplotlib { void PlotController::viewWillAppear() { - MicroPython::ExecutionViewControllerHelper::viewWillAppear(this); curveView()->reload(); } void PlotController::viewDidDisappear() { - MicroPython::ExecutionViewControllerHelper::viewDidDisappear(this); m_store->flush(); } diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h index 7b4390edc..ed35622dc 100644 --- a/python/port/mod/matplotlib/plot_controller.h +++ b/python/port/mod/matplotlib/plot_controller.h @@ -2,15 +2,14 @@ #define PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H #include -#include #include "plot_view.h" #include "plot_store.h" namespace Matplotlib { -class PlotController : public Shared::ZoomAndPanCurveViewController, public MicroPython::ExecutionViewControllerHelper { +class PlotController : public Shared::ZoomAndPanCurveViewController { public: - PlotController(PlotStore * store, MicroPython::ExecutionEnvironment * executiveEnvironment) : Shared::ZoomAndPanCurveViewController(nullptr), ExecutionViewControllerHelper(executiveEnvironment), m_store(store), m_view(m_store) {} + PlotController(PlotStore * store) : Shared::ZoomAndPanCurveViewController(nullptr), m_store(store), m_view(m_store) {} void viewWillAppear() override; void viewDidDisappear() override; diff --git a/python/port/port.cpp b/python/port/port.cpp index 1bbff1415..6e3bc83e3 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -95,23 +95,6 @@ void MicroPython::ExecutionEnvironment::interrupt() { mp_keyboard_interrupt(); } -void MicroPython::ExecutionEnvironment::viewControllerDidDisappear(ViewController * vc) { - if (vc == sandbox()) { - modturtle_view_did_disappear(); - } - m_displayedViewController = nullptr; -} - -void MicroPython::ExecutionViewControllerHelper::viewWillAppear(ViewController * vc) { - assert(m_executionEnvironment != nullptr); - m_executionEnvironment->viewControllerWillAppear(vc); -} - -void MicroPython::ExecutionViewControllerHelper::viewDidDisappear(ViewController * vc) { - assert(m_executionEnvironment != nullptr); - m_executionEnvironment->viewControllerDidDisappear(vc); -} - extern "C" { extern const void * _stack_start; extern const void * _stack_end; diff --git a/python/port/port.h b/python/port/port.h index 70181e158..67eecd3c5 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -15,7 +15,7 @@ public: class ExecutionEnvironment { public: - ExecutionEnvironment() : m_displayedViewController(nullptr) {} + ExecutionEnvironment() {} static ExecutionEnvironment * currentExecutionEnvironment(); void runCode(const char * ); virtual const char * inputText(const char * prompt) { return nullptr; } @@ -28,24 +28,10 @@ public: // Generic View Controller virtual void displayViewController(ViewController * controller) {} virtual void hideAnyDisplayedViewController() {} - void viewControllerWillAppear(ViewController * vc) { m_displayedViewController = vc; } - void viewControllerDidDisappear(ViewController * vc); virtual void printText(const char * text, size_t length) {} virtual void refreshPrintOutput() {} void interrupt(); -protected: - bool viewControllerIsDisplayed(ViewController * vc) const { return m_displayedViewController == vc; } - ViewController * m_displayedViewController; -}; - -class ExecutionViewControllerHelper { -public: - ExecutionViewControllerHelper(ExecutionEnvironment * executionEnvironment) : m_executionEnvironment(executionEnvironment) {} - void viewWillAppear(ViewController * vc); - void viewDidDisappear(ViewController * vc); -private: - ExecutionEnvironment * m_executionEnvironment; }; void init(void * heapStart, void * heapEnd); From 8aa1930f8098dbb010e5f630da6f72062810e320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 11:41:35 +0100 Subject: [PATCH 39/77] [python] Matplotlib: handle 'auto' range computation --- python/port/mod/matplotlib/plot_store.cpp | 61 +++++++++++++++++++++++ python/port/mod/matplotlib/plot_store.h | 2 + 2 files changed, 63 insertions(+) diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 411370541..633921eae 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -4,6 +4,7 @@ namespace Matplotlib { PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), m_axesRequested(true), + m_axesAuto(true), m_gridRequested(false) { flush(); @@ -14,6 +15,9 @@ void PlotStore::flush() { m_segments = mp_obj_new_list(0, nullptr); m_rects = mp_obj_new_list(0, nullptr); m_labels = mp_obj_new_list(0, nullptr); + m_axesRequested = true; + m_axesAuto = true; + m_gridRequested = false; } // Iterators @@ -133,4 +137,61 @@ void PlotStore::addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string) { mp_obj_list_append(m_labels, tuple); } +// Axes + +static inline float minFloat(float x, float y) { return x < y ? x : y; } +static inline float maxFloat(float x, float y) { return x > y ? x : y; } + +void updateRange(float * xMin, float * xMax, float * yMin, float * yMax, float x, float y) { + if (!std::isnan(x) && !std::isinf(x) && !std::isnan(y) && !std::isinf(y)) { + *xMin = minFloat(*xMin, x); + *xMax = maxFloat(*xMax, x); + *yMin = minFloat(*yMin, y); + *yMax = maxFloat(*yMax, y); + } +} + +void checkPositiveRangeAndAddMargin(float * min, float * max) { + if (*min > *max) { + *min = - Shared::Range1D::k_default; + *max = Shared::Range1D::k_default; + return; + } + // Add margins + float margin = (*max - *min)/10.0f; + *min -= margin; + *max += margin; +} + +void PlotStore::initRange() { + if (m_axesAuto) { + float xMin = FLT_MAX; + float xMax = -FLT_MAX; + float yMin = FLT_MAX; + float yMax = -FLT_MAX; + for (PlotStore::Dot dot : dots()) { + updateRange(&xMin, &xMax, &yMin, &yMax, dot.x(), dot.y()); + } + for (PlotStore::Label label : labels()) { + updateRange(&xMin, &xMax, &yMin, &yMax, label.x(), label.y()); + } + for (PlotStore::Segment segment : segments()) { + updateRange(&xMin, &xMax, &yMin, &yMax, segment.xStart(), segment.yStart()); + updateRange(&xMin, &xMax, &yMin, &yMax, segment.xEnd(), segment.yEnd()); + } + for (PlotStore::Rect rectangle : rects()) { + float x = rectangle.x(); + float y = rectangle.y(); + updateRange(&xMin, &xMax, &yMin, &yMax, x, y); + updateRange(&xMin, &xMax, &yMin, &yMax, x + rectangle.width(), y + rectangle.height()); + } + checkPositiveRangeAndAddMargin(&xMin, &xMax); + checkPositiveRangeAndAddMargin(&yMin, &yMax); + setXMin(xMin); + setXMax(xMax); + setYMin(yMin); + setYMax(yMax); + } +} + } diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index 24ebd6b49..41eaa1bae 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -121,6 +121,7 @@ public: void setAxesRequested(bool b) { m_axesRequested = b; } bool axesRequested() const { return m_axesRequested; } + void initRange(); void setGridRequested(bool b) { m_gridRequested = b; } bool gridRequested() const { return m_gridRequested; } @@ -130,6 +131,7 @@ private: mp_obj_t m_segments; // List of (x, y, dx, dy, style, color) mp_obj_t m_rects; // List of (x, y, w, h, color) bool m_axesRequested; + bool m_axesAuto; bool m_gridRequested; }; From 81170610ebc1efc6c6fec5782c903ce19f91e510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 12:13:41 +0100 Subject: [PATCH 40/77] [python] Matplotlib: init store range depending on 'auto' parameter --- python/port/mod/matplotlib/modpyplot.cpp | 1 + python/port/mod/matplotlib/plot_controller.cpp | 1 + python/port/mod/matplotlib/plot_store.h | 1 + 3 files changed, 3 insertions(+) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 32f156387..5e634c29d 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -74,6 +74,7 @@ mp_obj_t modpyplot_axis(mp_obj_t arg) { sPlotStore->setXMax(mp_obj_get_float(items[1])); sPlotStore->setYMin(mp_obj_get_float(items[2])); sPlotStore->setYMax(mp_obj_get_float(items[3])); + sPlotStore->setAxesAuto(false); } // Build the return value diff --git a/python/port/mod/matplotlib/plot_controller.cpp b/python/port/mod/matplotlib/plot_controller.cpp index eb7aa0abf..1beb952f5 100644 --- a/python/port/mod/matplotlib/plot_controller.cpp +++ b/python/port/mod/matplotlib/plot_controller.cpp @@ -3,6 +3,7 @@ namespace Matplotlib { void PlotController::viewWillAppear() { + m_store->initRange(); curveView()->reload(); } diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index 41eaa1bae..12ff2fbf8 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -121,6 +121,7 @@ public: void setAxesRequested(bool b) { m_axesRequested = b; } bool axesRequested() const { return m_axesRequested; } + void setAxesAuto(bool b) { m_axesAuto = b; } void initRange(); void setGridRequested(bool b) { m_gridRequested = b; } From 1b768ba34acd5c2a4cf6990fb381681f4d56d322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 14:24:01 +0100 Subject: [PATCH 41/77] [python] modpyplot: improve 'axis' arguments acceptance --- python/port/mod/matplotlib/modpyplot.cpp | 43 ++++++++++++++------ python/port/mod/matplotlib/modpyplot.h | 2 +- python/port/mod/matplotlib/modpyplot_table.c | 2 +- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 5e634c29d..7a6b332f6 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -57,24 +57,41 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { } /* axis(arg) - * - arg = [xmin, xmax, ymin, ymax] + * - arg = "on", "off", "auto" * - arg = True, False - * Returns : xmin, xmax, ymin, ymax : float */ + * - arg = [xmin, xmax, ymin, ymax], (xmin, xmax, ymin, ymax) + * Returns : (xmin, xmax, ymin, ymax) : float */ -mp_obj_t modpyplot_axis(mp_obj_t arg) { +mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); + if (n_args == 1) { + mp_obj_t arg = args[0]; + if (mp_obj_is_str(arg)) { + if (mp_obj_str_equal(arg, mp_obj_new_str("on", 2))) { + sPlotStore->setAxesRequested(true); + } else if (mp_obj_str_equal(arg, mp_obj_new_str("off", 3))) { + sPlotStore->setAxesRequested(false); + } else if (mp_obj_str_equal(arg, mp_obj_new_str("auto", 4))) { + sPlotStore->setAxesRequested(true); + sPlotStore->setAxesAuto(true); + } else { + mp_raise_ValueError("Unrecognized string given to axis; try 'on', 'off' or 'auto'"); + } #warning Use mp_obj_is_bool when upgrading uPy - if (mp_obj_is_type(arg, &mp_type_bool)) { - sPlotStore->setAxesRequested(mp_obj_is_true(arg)); - } else { - mp_obj_t * items; - mp_obj_get_array_fixed_n(arg, 4, &items); - sPlotStore->setXMin(mp_obj_get_float(items[0])); - sPlotStore->setXMax(mp_obj_get_float(items[1])); - sPlotStore->setYMin(mp_obj_get_float(items[2])); - sPlotStore->setYMax(mp_obj_get_float(items[3])); - sPlotStore->setAxesAuto(false); + } else if (mp_obj_is_type(arg, &mp_type_bool)) { + sPlotStore->setAxesRequested(mp_obj_is_true(arg)); + } else if (mp_obj_is_type(arg, &mp_type_tuple) || mp_obj_is_type(arg, &mp_type_list)) { + mp_obj_t * items; + mp_obj_get_array_fixed_n(arg, 4, &items); + sPlotStore->setXMin(mp_obj_get_float(items[0])); + sPlotStore->setXMax(mp_obj_get_float(items[1])); + sPlotStore->setYMin(mp_obj_get_float(items[2])); + sPlotStore->setYMax(mp_obj_get_float(items[3])); + sPlotStore->setAxesAuto(false); + } else { + mp_raise_TypeError("the first argument to axis() must be an interable of the form [xmin, xmax, ymin, ymax]"); + } } // Build the return value diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 0cf40d3fc..c016ab042 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -4,7 +4,7 @@ mp_obj_t modpyplot___init__(); void modpyplot_gc_collect(); mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args); -mp_obj_t modpyplot_axis(mp_obj_t arg); +mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height); mp_obj_t modpyplot_grid(mp_obj_t b); mp_obj_t modpyplot_hist(mp_obj_t x); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 402b33e65..2c092dd02 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -2,7 +2,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_bar_obj, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_grid_obj, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_hist_obj, modpyplot_hist); From 9a240bb0b45b3e734cddd53dd16b4e67dc641809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 14:45:29 +0100 Subject: [PATCH 42/77] [python] matplotlib: improve 'grid' --- python/port/mod/matplotlib/modpyplot.cpp | 11 +++++++---- python/port/mod/matplotlib/modpyplot.h | 2 +- python/port/mod/matplotlib/modpyplot_table.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 7a6b332f6..9ef3cef02 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -121,11 +121,14 @@ mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height) { return mp_const_none; } -mp_obj_t modpyplot_grid(mp_obj_t b) { - if (mp_obj_is_type(b, &mp_type_bool)) { - sPlotStore->setGridRequested(mp_obj_is_true(b)); - } else { +mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { + assert(sPlotStore != nullptr); + + if (n_args == 0) { + // Toggle the grid visibility sPlotStore->setGridRequested(!sPlotStore->gridRequested()); + } else { + sPlotStore->setGridRequested(mp_obj_is_true(args[0])); } return mp_const_none; } diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index c016ab042..00499a7bd 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -6,7 +6,7 @@ void modpyplot_gc_collect(); mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height); -mp_obj_t modpyplot_grid(mp_obj_t b); +mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_hist(mp_obj_t x); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 2c092dd02..00224395a 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -4,7 +4,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_bar_obj, modpyplot_bar); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_grid_obj, modpyplot_grid); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_hist_obj, modpyplot_hist); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); From 18d59d923af83e90dcfc2af5b6765c108aef59e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 17:52:50 +0100 Subject: [PATCH 43/77] [python] matplotlib: fix automatic range initialization --- python/port/mod/matplotlib/plot_store.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 633921eae..e13d6b511 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -183,7 +183,7 @@ void PlotStore::initRange() { float x = rectangle.x(); float y = rectangle.y(); updateRange(&xMin, &xMax, &yMin, &yMax, x, y); - updateRange(&xMin, &xMax, &yMin, &yMax, x + rectangle.width(), y + rectangle.height()); + updateRange(&xMin, &xMax, &yMin, &yMax, x + rectangle.width(), y - rectangle.height()); } checkPositiveRangeAndAddMargin(&xMin, &xMax); checkPositiveRangeAndAddMargin(&yMin, &yMax); From f97f56c021963d7c759bfaf9244ba2ec72993377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 17:53:24 +0100 Subject: [PATCH 44/77] [python] matplotlib: improve 'bar' arguments acceptation --- python/port/mod/matplotlib/modpyplot.cpp | 63 ++++++++++++++++---- python/port/mod/matplotlib/modpyplot.h | 3 +- python/port/mod/matplotlib/modpyplot_table.c | 2 +- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 9ef3cef02..0da285c89 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -103,20 +103,63 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(4, coords); } -mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height) { +/* bar(x, height, width, bottom) + * 'height', 'width' and 'bottom' can either be a scalar or an array/tuple of + * scalar. + * 'width' default value is 0.8 + * 'bottom' default value is None + * */ + +// TODO: accept keyword args? + +void extract_argument(mp_obj_t arg, size_t length, mp_obj_t ** items, float * item) { + if (mp_obj_is_type(arg, &mp_type_tuple) || mp_obj_is_type(arg, &mp_type_list)) { + size_t itemLength; + mp_obj_get_array(arg, &itemLength, items); + if (itemLength != length) { + mp_raise_ValueError("Shape mismatch"); + } + } else { + *item = mp_obj_get_float(arg); + } +} + +mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - // Input parameter validation - mp_obj_t * xItems, * hItems; - size_t length = extractAndValidatePlotInput(x, height, &xItems, &hItems); - mp_float_t w = 0.8; // TODO: w should be an optional parameter + mp_obj_t * xItems; + mp_obj_t * hItems = nullptr; + float h; + mp_obj_t * wItems = nullptr; + float w = 0.8f; + mp_obj_t * bItems = nullptr; + float b = 0.0f; + + // x arg + size_t xLength; + mp_obj_get_array(args[0], &xLength, &xItems); + + // height arg + extract_argument(args[1], xLength, &hItems, &h); + + // width arg + if (n_args >= 3) { + extract_argument(args[2], xLength, &wItems, &w); + } + + // bottom arg + if (n_args >= 4) { + extract_argument(args[3], xLength, &bItems, &b); + } KDColor color = Palette::nextDataColor(&paletteIndex); - for (size_t i=0; iaddRect(mp_obj_new_float(rectX), mp_obj_new_float(rectY), mp_obj_new_float(w), mp_obj_new_float(std::fabs(h)), color); + for (size_t i=0; iaddRect(mp_obj_new_float(iX), mp_obj_new_float(iY), mp_obj_new_float(iW), mp_obj_new_float(std::fabs(iH)), color); } return mp_const_none; } diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index 00499a7bd..ed449cd22 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -2,10 +2,11 @@ mp_obj_t modpyplot___init__(); void modpyplot_gc_collect(); +void modpyplot_flush_used_heap(); mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); -mp_obj_t modpyplot_bar(mp_obj_t x, mp_obj_t height); +mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_hist(mp_obj_t x); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 00224395a..d672ee184 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -3,7 +3,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_bar_obj, modpyplot_bar); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 4, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_hist_obj, modpyplot_hist); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); From 1895b83251b5a5d47445dc31aedea24b1f028aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Thu, 26 Mar 2020 17:55:48 +0100 Subject: [PATCH 45/77] [python] Remove useless code --- python/port/mod/matplotlib/modpyplot.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 0da285c89..4352a1a74 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -176,24 +176,6 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -// Dichotomia to find which bin a value belongs to -size_t belongs_to_bin_of_index(mp_float_t v, mp_obj_t * binsEdges, size_t minIndex, size_t maxIndex) { - assert(mp_obj_get_float(binsEdges[minIndex]) <= v && v <= mp_obj_get_float(binsEdges[maxIndex])); - if (maxIndex - minIndex < 2) { - return minIndex; - } - size_t index = (minIndex+maxIndex)/2; - mp_float_t pivot = mp_obj_get_float(binsEdges[index]); - if (pivot == v) { - return index; - } else if (pivot < v) { - return belongs_to_bin_of_index(v, binsEdges, index, maxIndex); - } else { - assert(pivot > v); - return belongs_to_bin_of_index(v, binsEdges, minIndex, index); - } -} - mp_obj_t modpyplot_hist(mp_obj_t x) { // Create a list of bins // TODO: the number of bins can be given as input From dc58b9692f89f8798da7c6d4306cf3a3daa947d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 27 Mar 2020 09:38:51 +0100 Subject: [PATCH 46/77] [python] matplotlib: imporve 'hist' --- python/port/mod/matplotlib/modpyplot.cpp | 50 ++++++++++++-------- python/port/mod/matplotlib/modpyplot.h | 2 +- python/port/mod/matplotlib/modpyplot_table.c | 2 +- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 4352a1a74..6d2b9f145 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -176,31 +176,48 @@ mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t modpyplot_hist(mp_obj_t x) { - // Create a list of bins - // TODO: the number of bins can be given as input - size_t nBins = 10; - // TODO: the list of bins can be given as input - // TODO: skip the following computation if so, - // `bins` must increase monotonically, when an array' - mp_obj_t binsEdges = mp_obj_new_list(nBins+1, nullptr); +/* hist(x, bins) + * 'x' array + * 'bins': (default value 10) + * - int (number of bins) + * - sequence of bins + * */ + +mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { + assert(sPlotStore != nullptr); // Sort data to easily get the minimal and maximal value and count bin sizes mp_obj_t * xItems; size_t xLength; - mp_obj_get_array(x, &xLength, &xItems); + mp_obj_get_array(args[0], &xLength, &xItems); mp_obj_t xList = mp_obj_new_list(xLength, xItems); mp_obj_list_sort(1, &xList, (mp_map_t*)&mp_const_empty_map); mp_obj_list_get(xList, &xLength, &xItems); mp_float_t min = mp_obj_get_float(xItems[0]); mp_float_t max = mp_obj_get_float(xItems[xLength - 1]); - // Fill the bin edges list - // TODO: skip if the binEdges were given as input - mp_float_t binWidth = (max-min)/nBins; - for (int i = 0; i < nBins+1; i++) { - mp_obj_list_store(binsEdges, mp_obj_new_int(i), mp_obj_new_float(min+i*binWidth)); + mp_obj_t binsEdges; + size_t nBins = 10; + // bin arg + if (n_args >= 2 && (mp_obj_is_type(args[1], &mp_type_tuple) || mp_obj_is_type(args[1], &mp_type_list))) { + binsEdges = args[1]; + } else { + if (n_args >= 2) { + nBins = mp_obj_get_int(args[1]); + } + // Create a list of bins + binsEdges = mp_obj_new_list(nBins+1, nullptr); + + // Fill the bin edges list + mp_float_t binWidth = (max-min)/nBins; + for (int i = 0; i < nBins+1; i++) { + mp_obj_list_store(binsEdges, mp_obj_new_int(i), mp_obj_new_float(min+i*binWidth)); + } } + mp_obj_t * edgeItems; + size_t nEdges; + mp_obj_list_get(binsEdges, &nEdges, &edgeItems); + nBins = nEdges - 1; // Initialize bins list mp_obj_t bins = mp_obj_new_list(nBins, nullptr); @@ -211,11 +228,6 @@ mp_obj_t modpyplot_hist(mp_obj_t x) { mp_obj_t * binItems; mp_obj_list_get(bins, &nBins, &binItems); - mp_obj_t * edgeItems; - size_t nEdges; - mp_obj_list_get(binsEdges, &nEdges, &edgeItems); - assert(nEdges == nBins + 1); - // Fill bins list by linearly scanning the x and incrementing the bin count // Linearity is enabled thanks to sorting size_t binIndex = 0; diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index ed449cd22..623034976 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -8,7 +8,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_grid(size_t n_args, const mp_obj_t *args); -mp_obj_t modpyplot_hist(mp_obj_t x); +mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y); mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index d672ee184..3dd3e2a0d 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -5,7 +5,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 4, modpyplot_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_hist_obj, modpyplot_hist); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 2, modpyplot_hist); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); From bf7c3b1aab9f823757b035499ffa08100f8ad880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 27 Mar 2020 14:43:32 +0100 Subject: [PATCH 47/77] [python] matplotlib: implement "plot(y)' --- python/port/mod/matplotlib/modpyplot.cpp | 22 +++++++++++++++++--- python/port/mod/matplotlib/modpyplot.h | 2 +- python/port/mod/matplotlib/modpyplot_table.c | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 6d2b9f145..248030dd8 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -269,12 +269,28 @@ mp_obj_t modpyplot_scatter(mp_obj_t x, mp_obj_t y) { return mp_const_none; } -mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { +/* plot(x, y) plots the curve (x, y) + * plot(y) plots the curve x as index array ([0,1,2...],y) + * */ + +mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); - // Input parameter validation mp_obj_t * xItems, * yItems; - size_t length = extractAndValidatePlotInput(x, y, &xItems, &yItems); + size_t length; + if (n_args == 1) { + mp_obj_get_array(args[0], &length, &yItems); + + // Create the default xItems: [0, 1, 2,...] + mp_obj_t x = mp_obj_new_list(length, nullptr); + for (int i = 0; i < length; i++) { + mp_obj_list_store(x, mp_obj_new_int(i), mp_obj_new_float((float)i)); + } + mp_obj_get_array(x, &length, &xItems); + } else { + assert(n_args == 2); + length = extractAndValidatePlotInput(args[0], args[1], &xItems, &yItems); + } KDColor color = Palette::nextDataColor(&paletteIndex); for (size_t i=0; i Date: Fri, 27 Mar 2020 17:39:07 +0100 Subject: [PATCH 48/77] [python] matplotlib: improve and fix arguments checking --- python/port/mod/matplotlib/modpyplot.cpp | 134 +++++++++++++---------- 1 file changed, 75 insertions(+), 59 deletions(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 248030dd8..bbb2d965c 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -12,18 +12,44 @@ static int paletteIndex = 0; // Private helper +// Method to populate items with a scalar or an array argument -static size_t extractAndValidatePlotInput(mp_obj_t x, mp_obj_t y, mp_obj_t ** xItems, mp_obj_t ** yItems) { - // Input parameter validation - size_t xLength, yLength; - mp_obj_get_array(x, &xLength, xItems); - mp_obj_get_array(y, &yLength, yItems); +static size_t extractArgument(mp_obj_t arg, mp_obj_t ** items) { + size_t itemLength; + if (mp_obj_is_type(arg, &mp_type_tuple) || mp_obj_is_type(arg, &mp_type_list)) { + mp_obj_get_array(arg, &itemLength, items); + } else { + itemLength = 1; + *items = m_new(mp_obj_t, 1); + (*items)[0] = arg; + } + return itemLength; +} + +// Extract two scalar or array arguments and check for their strickly equal dimension + +static size_t extractArgumentsAndCheckEqualSize(mp_obj_t x, mp_obj_t y, mp_obj_t ** xItems, mp_obj_t ** yItems) { + size_t xLength = extractArgument(x, xItems); + size_t yLength = extractArgument(y, yItems); if (xLength != yLength) { - mp_raise_ValueError("x and y must have same dimension"); + mp_raise_ValueError("x and y must be the same size"); } return xLength; } +/* Extract one scalar or array arguments and check that it is either: + * - of size 1 + * - of the required size +*/ + +size_t extractArgumentAndValidateSize(mp_obj_t arg, size_t requiredlength, mp_obj_t ** items) { + size_t itemLength = extractArgument(arg, items); + if (itemLength > 1 && requiredlength > 1 && itemLength != requiredlength) { + mp_raise_ValueError("shape mismatch"); + } + return itemLength; +} + // Internal functions mp_obj_t modpyplot___init__() { @@ -51,7 +77,7 @@ mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); KDColor color = Palette::nextDataColor(&paletteIndex); - sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0])+mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1])+mp_obj_get_float(args[3])), color, true); + sPlotStore->addSegment(args[0], args[1], mp_obj_new_float(mp_obj_get_float(args[0])+mp_obj_get_float(args[2])), mp_obj_new_float(mp_obj_get_float(args[1])+mp_obj_get_float(args[3])), color, true); // TODO: use float_binary_op return mp_const_none; } @@ -104,7 +130,7 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { } /* bar(x, height, width, bottom) - * 'height', 'width' and 'bottom' can either be a scalar or an array/tuple of + * 'x', 'height', 'width' and 'bottom' can either be a scalar or an array/tuple of * scalar. * 'width' default value is 0.8 * 'bottom' default value is None @@ -112,51 +138,43 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { // TODO: accept keyword args? -void extract_argument(mp_obj_t arg, size_t length, mp_obj_t ** items, float * item) { - if (mp_obj_is_type(arg, &mp_type_tuple) || mp_obj_is_type(arg, &mp_type_list)) { - size_t itemLength; - mp_obj_get_array(arg, &itemLength, items); - if (itemLength != length) { - mp_raise_ValueError("Shape mismatch"); - } - } else { - *item = mp_obj_get_float(arg); - } -} - mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { assert(sPlotStore != nullptr); mp_obj_t * xItems; - mp_obj_t * hItems = nullptr; - float h; - mp_obj_t * wItems = nullptr; - float w = 0.8f; - mp_obj_t * bItems = nullptr; - float b = 0.0f; + mp_obj_t * hItems; + mp_obj_t * wItems; + mp_obj_t * bItems; // x arg - size_t xLength; - mp_obj_get_array(args[0], &xLength, &xItems); + size_t xLength = extractArgument(args[0], &xItems); // height arg - extract_argument(args[1], xLength, &hItems, &h); + size_t hLength = extractArgumentAndValidateSize(args[1], xLength, &hItems); // width arg + size_t wLength = 1; if (n_args >= 3) { - extract_argument(args[2], xLength, &wItems, &w); + wLength = extractArgumentAndValidateSize(args[2], xLength, &wItems); + } else { + wItems = m_new(mp_obj_t, 1); + wItems[0] = mp_obj_new_float(0.8f); } // bottom arg + size_t bLength = 1; if (n_args >= 4) { - extract_argument(args[3], xLength, &bItems, &b); + bLength = extractArgumentAndValidateSize(args[3], xLength, &bItems); + } else { + bItems = m_new(mp_obj_t, 1); + bItems[0] = mp_obj_new_float(0.0f); } KDColor color = Palette::nextDataColor(&paletteIndex); for (size_t i=0; i 1 ? i : 0]); + mp_float_t iW = mp_obj_get_float(wItems[wLength > 1 ? i : 0]); + mp_float_t iB = mp_obj_get_float(bItems[bLength > 1 ? i : 0]); mp_float_t iX = mp_obj_get_float(xItems[i])-iW/2.0; mp_float_t iY = iH < 0.0 ? iB : iB + iH; sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iY), mp_obj_new_float(iW), mp_obj_new_float(std::fabs(iH)), color); @@ -188,46 +206,41 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { // Sort data to easily get the minimal and maximal value and count bin sizes mp_obj_t * xItems; - size_t xLength; - mp_obj_get_array(args[0], &xLength, &xItems); + size_t xLength = extractArgument(args[0], &xItems); mp_obj_t xList = mp_obj_new_list(xLength, xItems); mp_obj_list_sort(1, &xList, (mp_map_t*)&mp_const_empty_map); mp_obj_list_get(xList, &xLength, &xItems); mp_float_t min = mp_obj_get_float(xItems[0]); mp_float_t max = mp_obj_get_float(xItems[xLength - 1]); - mp_obj_t binsEdges; - size_t nBins = 10; + mp_obj_t * edgeItems; + size_t nBins; // bin arg if (n_args >= 2 && (mp_obj_is_type(args[1], &mp_type_tuple) || mp_obj_is_type(args[1], &mp_type_list))) { - binsEdges = args[1]; + size_t nEdges; + mp_obj_get_array(args[1], &nEdges, &edgeItems); + nBins = nEdges -1; } else { + nBins = 10; if (n_args >= 2) { nBins = mp_obj_get_int(args[1]); } - // Create a list of bins - binsEdges = mp_obj_new_list(nBins+1, nullptr); + // Create a array of bins + edgeItems = m_new(mp_obj_t, nBins + 1); // Fill the bin edges list mp_float_t binWidth = (max-min)/nBins; for (int i = 0; i < nBins+1; i++) { - mp_obj_list_store(binsEdges, mp_obj_new_int(i), mp_obj_new_float(min+i*binWidth)); + edgeItems[i] = mp_obj_new_float(min+i*binWidth); } } - mp_obj_t * edgeItems; - size_t nEdges; - mp_obj_list_get(binsEdges, &nEdges, &edgeItems); - nBins = nEdges - 1; // Initialize bins list - mp_obj_t bins = mp_obj_new_list(nBins, nullptr); + mp_obj_t * binItems = m_new(mp_obj_t, nBins); for (size_t i=0; i Date: Fri, 27 Mar 2020 17:39:44 +0100 Subject: [PATCH 49/77] [python] matplotlib: PlotStore checks for type before accepting a new object This fixes the crash: when a non-float value is added through the tupple, the next float extraction will fail --- python/port/mod/matplotlib/plot_store.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index e13d6b511..68b61ae98 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -57,6 +57,16 @@ T PlotStore::ListIterator::operator*() { return T(m_tuples[m_tupleIndex]); }; +void checkFloatType(mp_obj_t * elements, size_t nbOfElements) { + for (int i = 0; i < nbOfElements; i++) { + // TODO: we don't take advantage of the fact that we extracted the value at the sametime... Maybe change the way things are done, build the c objects in addItem instead of allocating them on the python heap? Or use float array in python? + mp_float_t value; + if (!mp_obj_get_float_maybe(elements[i], &value)) { + mp_raise_TypeError("argument should be a number"); + } + } +} + // Dot template class PlotStore::ListIterator; @@ -72,6 +82,7 @@ PlotStore::Dot::Dot(mp_obj_t tuple) { void PlotStore::addDot(mp_obj_t x, mp_obj_t y, KDColor c) { mp_obj_t color = mp_obj_new_int(c); mp_obj_t items[3] = {x, y, color}; + checkFloatType(items, 2); mp_obj_t tuple = mp_obj_new_tuple(3, items); mp_obj_list_append(m_dots, tuple); } @@ -94,6 +105,7 @@ PlotStore::Segment::Segment(mp_obj_t tuple) { void PlotStore::addSegment(mp_obj_t xStart, mp_obj_t yStart, mp_obj_t xEnd, mp_obj_t yEnd, KDColor c, bool arrowEdge) { mp_obj_t color = mp_obj_new_int(c); mp_obj_t items[6] = {xStart, yStart, xEnd, yEnd, color, arrowEdge ? mp_const_true : mp_const_false}; + checkFloatType(items, 4); mp_obj_t tuple = mp_obj_new_tuple(6, items); mp_obj_list_append(m_segments, tuple); } @@ -115,6 +127,7 @@ PlotStore::Rect::Rect(mp_obj_t tuple) { void PlotStore::addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c) { mp_obj_t color = mp_obj_new_int(c); mp_obj_t items[5] = {x, y, width, height, color}; + checkFloatType(items, 4); mp_obj_t tuple = mp_obj_new_tuple(5, items); mp_obj_list_append(m_rects, tuple); } @@ -133,6 +146,10 @@ PlotStore::Label::Label(mp_obj_t tuple) { void PlotStore::addLabel(mp_obj_t x, mp_obj_t y, mp_obj_t string) { mp_obj_t items[3] = {x, y, string}; + checkFloatType(items, 2); + if (!mp_obj_is_str(string)) { + mp_raise_TypeError("argument should be a string"); + } mp_obj_t tuple = mp_obj_new_tuple(3, items); mp_obj_list_append(m_labels, tuple); } From 1c4f43c6655396b5cddb9925829382467f3890f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 27 Mar 2020 17:46:14 +0100 Subject: [PATCH 50/77] [python] matplotlib: handle empty range histogram --- python/port/mod/matplotlib/modpyplot.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index bbb2d965c..8d8d86baf 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -225,11 +225,17 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { if (n_args >= 2) { nBins = mp_obj_get_int(args[1]); } + + mp_float_t binWidth = (max-min)/nBins; // Create a array of bins edgeItems = m_new(mp_obj_t, nBins + 1); + // Handle empty range case + if (max - min <= FLT_EPSILON) { + binWidth = 1.0; + nBins = 1; + } // Fill the bin edges list - mp_float_t binWidth = (max-min)/nBins; for (int i = 0; i < nBins+1; i++) { edgeItems[i] = mp_obj_new_float(min+i*binWidth); } From f5e69395eee61869716bd3ce3f927e3b04a45431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Mar 2020 10:21:50 +0200 Subject: [PATCH 51/77] [apps/code] Reorder toolbox modules --- apps/code/python_toolbox.cpp | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 792abf106..e5001b536 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -92,30 +92,6 @@ const ToolboxMessageTree MathModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLgamma, I18n::Message::PythonLgamma) }; -const ToolboxMessageTree KandinskyModuleChildren[] = { - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect) -}; - -const ToolboxMessageTree RandomModuleChildren[] = { - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform) -}; - const ToolboxMessageTree CMathModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromCmath, I18n::Message::PythonImportCmath, false), @@ -167,6 +143,30 @@ const ToolboxMessageTree TurtleModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false) }; +const ToolboxMessageTree RandomModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform) +}; + +const ToolboxMessageTree KandinskyModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect) +}; + const ToolboxMessageTree IonModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false), @@ -231,8 +231,8 @@ const ToolboxMessageTree TimeModuleChildren[] = { const ToolboxMessageTree modulesChildren[] = { ToolboxMessageTree::Node(I18n::Message::MathModule, MathModuleChildren), ToolboxMessageTree::Node(I18n::Message::CmathModule, CMathModuleChildren), - ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren), ToolboxMessageTree::Node(I18n::Message::TurtleModule, TurtleModuleChildren), + ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren), ToolboxMessageTree::Node(I18n::Message::KandinskyModule, KandinskyModuleChildren), ToolboxMessageTree::Node(I18n::Message::IonModule, IonModuleChildren), ToolboxMessageTree::Node(I18n::Message::TimeModule, TimeModuleChildren) From 89ef6ec71b0f37f3981b45e204787c03b81bbc92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Mar 2020 10:52:18 +0200 Subject: [PATCH 52/77] [apps/code] Add MatplotlibPyplot in the toolbox --- apps/code/catalog.de.i18n | 11 +++++++++++ apps/code/catalog.en.i18n | 11 +++++++++++ apps/code/catalog.es.i18n | 11 +++++++++++ apps/code/catalog.fr.i18n | 11 +++++++++++ apps/code/catalog.pt.i18n | 11 +++++++++++ apps/code/catalog.universal.i18n | 13 +++++++++++++ apps/code/python_toolbox.cpp | 16 ++++++++++++++++ apps/code/toolbox.universal.i18n | 1 + 8 files changed, 85 insertions(+) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 31d7b0099..9545f659b 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -13,11 +13,14 @@ PythonAbs = "Absolute/r Wert/Größe" PythonAcos = "Arkuskosinus" PythonAcosh = "Hyperbelkosinus" PythonAppend = "Add x to the end of the list" +PythonArrow = "Draw an arrow from (x, y) to (x+dx, y+dy)" PythonAsin = "Arkussinus" PythonAsinh = "Hyperbelsinus" PythonAtan = "Arkustangens" PythonAtan2 = "Gib atan(y/x)" PythonAtanh = "Hyperbeltangens" +PythonAxis = "Set the axes to (xmin,xmax,ymin,ymax)" +PythonBar = "Make a bar plot with x values" PythonBin = "Ganzzahl nach binär konvertieren" PythonCeil = "Aufrundung" PythonChoice = "Zufallszahl aus der Liste" @@ -46,12 +49,15 @@ 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" @@ -117,12 +123,14 @@ 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" @@ -138,8 +146,10 @@ PythonRect = "z in 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" @@ -148,6 +158,7 @@ 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" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 1a222ea9d..5d7d087d9 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" PythonAppend = "Add x to the end of the list" +PythonArrow = "Draw an 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 the axes to (xmin,xmax,ymin,ymax)" +PythonBar = "Make a bar plot with x values" PythonBin = "Convert integer to binary" PythonCeil = "Ceiling" PythonChoice = "Random number in the list" @@ -46,12 +49,15 @@ 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" @@ -117,12 +123,14 @@ 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" @@ -138,8 +146,10 @@ PythonRect = "z in 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" @@ -148,6 +158,7 @@ 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" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index 1a222ea9d..5d7d087d9 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" PythonAppend = "Add x to the end of the list" +PythonArrow = "Draw an 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 the axes to (xmin,xmax,ymin,ymax)" +PythonBar = "Make a bar plot with x values" PythonBin = "Convert integer to binary" PythonCeil = "Ceiling" PythonChoice = "Random number in the list" @@ -46,12 +49,15 @@ 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" @@ -117,12 +123,14 @@ 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" @@ -138,8 +146,10 @@ PythonRect = "z in 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" @@ -148,6 +158,7 @@ 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" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index 7d2dda261..cf01b57ac 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -13,11 +13,14 @@ PythonAbs = "Valeur absolue/Module" PythonAcos = "Arc cosinus" PythonAcosh = "Arc cosinus hyperbolique" PythonAppend = "Insère x à la fin de la liste" +PythonArrow = "Flèche de (x,y) à (x+dx,y+dy)" PythonAsin = "Arc sinus" PythonAsinh = "Arc sinus hyperbolique" PythonAtan = "Arc tangente" PythonAtan2 = "Calcul de atan(y/x)" PythonAtanh = "Arc tangente hyperbolique" +PythonAxis = "Met les axes à (xmin,xmax,ymin,ymax)" +PythonBar = "Diagramme en barres de la liste x" PythonBin = "Conversion d'un entier en binaire" PythonCeil = "Plafond" PythonChoice = "Nombre aléatoire dans la liste" @@ -46,12 +49,15 @@ PythonFrExp = "Mantisse et exposant de x : (m,e)" PythonGamma = "Fonction gamma" PythonGetPixel = "Renvoie la couleur du pixel (x,y)" PythonGetrandbits = "Nombre aléatoire sur k bits" +PythonGrid = "Affiche ou masque la grille" PythonHex = "Conversion entier en hexadécimal" +PythonHist = "Histogramme de la liste x" PythonImportCmath = "Importation du module cmath" PythonImportIon = "Importation du module ion" PythonImportKandinsky = "Importation du module kandinsky" PythonImportRandom = "Importation du module random" PythonImportMath = "Importation du module math" +PythonImportMatplotlibPyplot = "Importation de matplotlib.pyplot" PythonImportTurtle = "Importation du module turtle" PythonImportTime = "Importation du module time" PythonIndex = "Indice première occurrence de x" @@ -117,12 +123,14 @@ PythonLog = "Logarithme de base a" PythonLog10 = "Logarithme décimal" PythonLog2 = "Logarithme de base 2" PythonMathFunction = "Préfixe fonction du module math" +PythonMatplotlibPyplotFunction = "Préfixe du module matplotlib.pyplot" PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "Parties fractionnaire et entière" PythonMonotonic = "Renvoie la valeur de l'horloge" PythonOct = "Conversion en octal" PythonPhase = "Argument de z" +PythonPlot = "Trace y en fonction de x" PythonPolar = "Conversion en polaire" PythonPop = "Supprime le dernier élément" PythonPower = "x à la puissance y" @@ -138,8 +146,10 @@ PythonRect = "Conversion en algébrique" PythonRemove = "Supprime le premier x de la liste" PythonReverse = "Inverse les éléments de la liste" PythonRound = "Arrondi à n décimales" +PythonScatter = "Nuage de points de coordonnées (x,y)" PythonSeed = "Initialiser générateur aléatoire" PythonSetPixel = "Colore le pixel (x,y)" +PythonShow = "Affiche la figure" PythonSin = "Sinus" PythonSinh = "Sinus hyperbolique" PythonSleep = "Suspend l'exécution t secondes" @@ -148,6 +158,7 @@ PythonSqrt = "Racine carrée" PythonSum = "Somme des éléments de la liste" PythonTan = "Tangente" PythonTanh = "Tangente hyperbolique" +PythonText = "Affiche un texte en (x,y)" PythonTimeFunction = "Préfixe fonction module time" PythonTrunc = "Troncature entière" PythonTurtleBackward = "Recule de x pixels" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 7555ecdab..065dbbe0e 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" PythonAppend = "Add x to the end of the list" +PythonArrow = "Draw an 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 the axes to (xmin,xmax,ymin,ymax)" +PythonBar = "Make a bar plot with x values" PythonBin = "Convert integer to binary" PythonCeil = "Ceiling" PythonChoice = "Random number in the list" @@ -46,12 +49,15 @@ 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" @@ -117,12 +123,14 @@ 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" @@ -138,8 +146,10 @@ PythonRect = "z in 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" @@ -148,6 +158,7 @@ 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" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 59b7fec3a..05ff33694 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -12,11 +12,14 @@ PythonCommandAcos = "acos(x)" PythonCommandAcosh = "acosh(x)" PythonCommandAppend = "list.append(x)" PythonCommandAppendWithoutArg = ".append(\x11)" +PythonCommandArrow = "arrow(x,y,dx,dy)" PythonCommandAsin = "asin(x)" PythonCommandAsinh = "asinh(x)" PythonCommandAtan = "atan(x)" PythonCommandAtan2 = "atan2(y,x)" PythonCommandAtanh = "atanh(x)" +PythonCommandAxis = "axis((xmin,xmax,ymin,ymax))" +PythonCommandBar = "bar(x,height)" PythonCommandBin = "bin(x)" PythonCommandCeil = "ceil(x)" PythonCommandChoice = "choice(list)" @@ -52,13 +55,16 @@ PythonCommandFrExp = "frexp(x)" PythonCommandGamma = "gamma(x)" PythonCommandGetPixel = "get_pixel(x,y)" PythonCommandGetrandbits = "getrandbits(k)" +PythonCommandGrid = "grid()" PythonCommandHex = "hex(x)" +PythonCommandHist = "hist(x,bins)" PythonCommandImag = "z.imag" PythonCommandImagWithoutArg = ".imag" PythonCommandImportFromCmath = "from cmath import *" PythonCommandImportFromIon = "from ion import *" PythonCommandImportFromKandinsky = "from kandinsky import *" PythonCommandImportFromMath = "from math import *" +PythonCommandImportFromMatplotlibPyplot = "from matplotlib.pyplot import *" PythonCommandImportFromRandom = "from random import *" PythonCommandImportFromTime = "from time import *" PythonCommandImportFromTurtle = "from turtle import *" @@ -66,6 +72,7 @@ PythonCommandImportCmath = "import cmath" PythonCommandImportIon = "import ion" PythonCommandImportKandinsky = "import kandinsky" PythonCommandImportMath = "import math" +PythonCommandImportMatplotlibPyplot = "import matplotlib.pyplot" PythonCommandImportRandom = "import random" PythonCommandImportTime = "import time" PythonCommandImportTurtle = "import turtle" @@ -138,12 +145,15 @@ PythonCommandLog2 = "log2(x)" PythonCommandLogComplex = "log(z,a)" PythonCommandMathFunction = "math.function" PythonCommandMathFunctionWithoutArg = "math.\x11" +PythonCommandMatplotlibPyplotFunction = "matplotlib.pyplot.function" +PythonCommandMatplotlibPyplotFunctionWithoutArg = "matplotlib.pyplot.\x11" PythonCommandMax = "max(list)" PythonCommandMin = "min(list)" PythonCommandModf = "modf(x)" PythonCommandMonotonic = "monotonic()" PythonCommandOct = "oct(x)" PythonCommandPhase = "phase(z)" +PythonCommandPlot = "plot(x,y)" PythonCommandPolar = "polar(z)" PythonCommandPop = "list.pop()" PythonCommandPopWithoutArg = ".pop()" @@ -165,8 +175,10 @@ PythonCommandRemoveWithoutArg = ".remove(\x11)" PythonCommandReverse = "list.reverse()" PythonCommandReverseWithoutArg = ".reverse()" PythonCommandRound = "round(x, n)" +PythonCommandScatter = "scatter(x,y)" PythonCommandSeed = "seed(x)" PythonCommandSetPixel = "set_pixel(x,y,color)" +PythonCommandShow = "show()" PythonCommandSin = "sin(x)" PythonCommandSinComplex = "sin(z)" PythonCommandSinh = "sinh(x)" @@ -179,6 +191,7 @@ PythonCommandSqrtComplex = "sqrt(z)" PythonCommandSum = "sum(list)" PythonCommandTan = "tan(x)" PythonCommandTanh = "tanh(x)" +PythonCommandText = "text(x,y,\"texte\")" PythonCommandTimeFunction = "time.function" PythonCommandTimeFunctionWithoutArg = "time.\x11" PythonCommandTrunc = "trunc(x)" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index e5001b536..91cb7448b 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -108,6 +108,21 @@ const ToolboxMessageTree CMathModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinComplex, I18n::Message::PythonSin) }; +const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis), //TODO LEA ? + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist), + 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) +}; + const ToolboxMessageTree TurtleModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false), @@ -231,6 +246,7 @@ const ToolboxMessageTree TimeModuleChildren[] = { const ToolboxMessageTree modulesChildren[] = { ToolboxMessageTree::Node(I18n::Message::MathModule, MathModuleChildren), ToolboxMessageTree::Node(I18n::Message::CmathModule, CMathModuleChildren), + ToolboxMessageTree::Node(I18n::Message::MatplotlibPyplotModule, MatplotlibPyplotModuleChildren), ToolboxMessageTree::Node(I18n::Message::TurtleModule, TurtleModuleChildren), ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren), ToolboxMessageTree::Node(I18n::Message::KandinskyModule, KandinskyModuleChildren), diff --git a/apps/code/toolbox.universal.i18n b/apps/code/toolbox.universal.i18n index d5afd929c..5a5072475 100644 --- a/apps/code/toolbox.universal.i18n +++ b/apps/code/toolbox.universal.i18n @@ -2,6 +2,7 @@ CmathModule = "cmath" IonModule = "ion" KandinskyModule = "kandinsky" MathModule = "math" +MatplotlibPyplotModule = "matplotlib.pyplot" TimeModule = "time" TurtleModule = "turtle" ForLoopMenu = "For" From 399cfffc83d6619639e6bc247f0c5c5bc14eeacc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Mar 2020 13:55:50 +0200 Subject: [PATCH 53/77] [apps/code] Fix toolbox texts --- apps/code/catalog.de.i18n | 6 +++--- apps/code/catalog.en.i18n | 6 +++--- apps/code/catalog.es.i18n | 6 +++--- apps/code/catalog.fr.i18n | 4 ++-- apps/code/catalog.pt.i18n | 6 +++--- apps/code/catalog.universal.i18n | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 9545f659b..7fb0c05a5 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -13,14 +13,14 @@ PythonAbs = "Absolute/r Wert/Größe" PythonAcos = "Arkuskosinus" PythonAcosh = "Hyperbelkosinus" PythonAppend = "Add x to the end of the list" -PythonArrow = "Draw an arrow from (x, y) to (x+dx, y+dy)" +PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)" PythonAsin = "Arkussinus" PythonAsinh = "Hyperbelsinus" PythonAtan = "Arkustangens" PythonAtan2 = "Gib atan(y/x)" PythonAtanh = "Hyperbeltangens" -PythonAxis = "Set the axes to (xmin,xmax,ymin,ymax)" -PythonBar = "Make a bar plot with x values" +PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)" +PythonBar = "Draw a bar plot with x values" PythonBin = "Ganzzahl nach binär konvertieren" PythonCeil = "Aufrundung" PythonChoice = "Zufallszahl aus der Liste" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 5d7d087d9..9cea9e6df 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -13,14 +13,14 @@ PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" PythonAppend = "Add x to the end of the list" -PythonArrow = "Draw an arrow from (x, y) to (x+dx, y+dy)" +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 the axes to (xmin,xmax,ymin,ymax)" -PythonBar = "Make a bar plot with x values" +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" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index 5d7d087d9..9cea9e6df 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -13,14 +13,14 @@ PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" PythonAppend = "Add x to the end of the list" -PythonArrow = "Draw an arrow from (x, y) to (x+dx, y+dy)" +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 the axes to (xmin,xmax,ymin,ymax)" -PythonBar = "Make a bar plot with x values" +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" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index cf01b57ac..e13d380bb 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -19,7 +19,7 @@ PythonAsinh = "Arc sinus hyperbolique" PythonAtan = "Arc tangente" PythonAtan2 = "Calcul de atan(y/x)" PythonAtanh = "Arc tangente hyperbolique" -PythonAxis = "Met les axes à (xmin,xmax,ymin,ymax)" +PythonAxis = "Met les axes (xmin,xmax,ymin,ymax)" PythonBar = "Diagramme en barres de la liste x" PythonBin = "Conversion d'un entier en binaire" PythonCeil = "Plafond" @@ -146,7 +146,7 @@ PythonRect = "Conversion en algébrique" PythonRemove = "Supprime le premier x de la liste" PythonReverse = "Inverse les éléments de la liste" PythonRound = "Arrondi à n décimales" -PythonScatter = "Nuage de points de coordonnées (x,y)" +PythonScatter = "Nuage des points (x,y)" PythonSeed = "Initialiser générateur aléatoire" PythonSetPixel = "Colore le pixel (x,y)" PythonShow = "Affiche la figure" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 065dbbe0e..b0c415ee9 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -13,14 +13,14 @@ PythonAbs = "Absolute value/Magnitude" PythonAcos = "Arc cosine" PythonAcosh = "Arc hyperbolic cosine" PythonAppend = "Add x to the end of the list" -PythonArrow = "Draw an arrow from (x, y) to (x+dx, y+dy)" +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 the axes to (xmin,xmax,ymin,ymax)" -PythonBar = "Make a bar plot with x values" +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" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 05ff33694..812a8c38f 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -191,7 +191,7 @@ PythonCommandSqrtComplex = "sqrt(z)" PythonCommandSum = "sum(list)" PythonCommandTan = "tan(x)" PythonCommandTanh = "tanh(x)" -PythonCommandText = "text(x,y,\"texte\")" +PythonCommandText = "text(x,y,\"text\")" PythonCommandTimeFunction = "time.function" PythonCommandTimeFunctionWithoutArg = "time.\x11" PythonCommandTrunc = "trunc(x)" From 7d5568ff1a4b2a76ff4a9f635d460d6b076b0fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 12:36:08 +0200 Subject: [PATCH 54/77] [python] WIP: change change pyplot name: pyplot --> matplotlib.pyplot --- python/port/genhdr/qstrdefs.in.h | 2 +- python/port/mod/matplotlib/modpyplot_table.c | 2 +- python/port/mpconfigport.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 0f6d4e4c3..31ea86876 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -81,7 +81,7 @@ Q(grid) Q(grid) Q(hist) Q(plot) -Q(pyplot) +Q(matplotlib.pyplot) Q(scatter) Q(show) Q(text) diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 1f4c3152b..c19aa128f 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -12,7 +12,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_matplotlib_dot_pyplot) }, { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, { MP_ROM_QSTR(MP_QSTR_arrow), MP_ROM_PTR(&modpyplot_arrow_obj) }, { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, diff --git a/python/port/mpconfigport.h b/python/port/mpconfigport.h index d6565ff01..6c95bc655 100644 --- a/python/port/mpconfigport.h +++ b/python/port/mpconfigport.h @@ -137,7 +137,7 @@ extern const struct _mp_obj_module_t modturtle_module; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_ion), MP_ROM_PTR(&modion_module) }, \ { MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&modkandinsky_module) }, \ - { MP_ROM_QSTR(MP_QSTR_pyplot), MP_ROM_PTR(&modpyplot_module) }, \ + { MP_ROM_QSTR(MP_QSTR_matplotlib_dot_pyplot), MP_ROM_PTR(&modpyplot_module) }, \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&modtime_module) }, \ { MP_ROM_QSTR(MP_QSTR_turtle), MP_ROM_PTR(&modturtle_module) }, \ From 61e7ec52e60a7d77ba9b47983b487c9759697bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 13:58:02 +0200 Subject: [PATCH 55/77] [python] matplotlib: make pyplot a submodule of matplotlib --- python/Makefile | 12 ++++--- python/port/genhdr/qstrdefs.in.h | 2 ++ python/port/mod/matplotlib/modmatplotlib.cpp | 13 ++++++++ python/port/mod/matplotlib/modmatplotlib.h | 3 ++ .../port/mod/matplotlib/modmatplotlib_table.c | 18 ++++++++++ .../mod/matplotlib/{ => pyplot}/modpyplot.cpp | 0 .../mod/matplotlib/{ => pyplot}/modpyplot.h | 0 .../mod/matplotlib/pyplot/modpyplot_table.c | 33 +++++++++++++++++++ .../{ => pyplot}/plot_controller.cpp | 0 .../matplotlib/{ => pyplot}/plot_controller.h | 0 .../matplotlib/{ => pyplot}/plot_store.cpp | 0 .../mod/matplotlib/{ => pyplot}/plot_store.h | 0 .../mod/matplotlib/{ => pyplot}/plot_view.cpp | 0 .../mod/matplotlib/{ => pyplot}/plot_view.h | 0 python/port/mpconfigport.h | 2 ++ python/port/port.cpp | 2 +- 16 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 python/port/mod/matplotlib/modmatplotlib.cpp create mode 100644 python/port/mod/matplotlib/modmatplotlib.h create mode 100644 python/port/mod/matplotlib/modmatplotlib_table.c rename python/port/mod/matplotlib/{ => pyplot}/modpyplot.cpp (100%) rename python/port/mod/matplotlib/{ => pyplot}/modpyplot.h (100%) create mode 100644 python/port/mod/matplotlib/pyplot/modpyplot_table.c rename python/port/mod/matplotlib/{ => pyplot}/plot_controller.cpp (100%) rename python/port/mod/matplotlib/{ => pyplot}/plot_controller.h (100%) rename python/port/mod/matplotlib/{ => pyplot}/plot_store.cpp (100%) rename python/port/mod/matplotlib/{ => pyplot}/plot_store.h (100%) rename python/port/mod/matplotlib/{ => pyplot}/plot_view.cpp (100%) rename python/port/mod/matplotlib/{ => pyplot}/plot_view.h (100%) diff --git a/python/Makefile b/python/Makefile index c368be85c..cb5d5a015 100644 --- a/python/Makefile +++ b/python/Makefile @@ -134,11 +134,13 @@ port_src += $(addprefix python/port/,\ mod/ion/modion_table.cpp \ mod/kandinsky/modkandinsky.cpp \ mod/kandinsky/modkandinsky_table.c \ - mod/matplotlib/modpyplot.cpp \ - mod/matplotlib/modpyplot_table.c \ - mod/matplotlib/plot_controller.cpp \ - mod/matplotlib/plot_store.cpp \ - mod/matplotlib/plot_view.cpp \ + mod/matplotlib/modmatplotlib.cpp \ + mod/matplotlib/modmatplotlib_table.c \ + mod/matplotlib/pyplot/modpyplot.cpp \ + mod/matplotlib/pyplot/modpyplot_table.c \ + mod/matplotlib/pyplot/plot_controller.cpp \ + mod/matplotlib/pyplot/plot_store.cpp \ + mod/matplotlib/pyplot/plot_view.cpp \ mod/time/modtime.c \ mod/time/modtime_table.c \ mod/turtle/modturtle.cpp \ diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 31ea86876..9e2ed605b 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -81,7 +81,9 @@ Q(grid) Q(grid) Q(hist) Q(plot) +Q(matplotlib) Q(matplotlib.pyplot) +Q(pyplot) Q(scatter) Q(show) Q(text) diff --git a/python/port/mod/matplotlib/modmatplotlib.cpp b/python/port/mod/matplotlib/modmatplotlib.cpp new file mode 100644 index 000000000..7459c28c3 --- /dev/null +++ b/python/port/mod/matplotlib/modmatplotlib.cpp @@ -0,0 +1,13 @@ +extern "C" { +#include "modmatplotlib.h" +#include "pyplot/modpyplot.h" +} +#include + + +// Internal functions + +mp_obj_t modmatplotlib___init__() { + modpyplot___init__(); + return mp_const_none; +} diff --git a/python/port/mod/matplotlib/modmatplotlib.h b/python/port/mod/matplotlib/modmatplotlib.h new file mode 100644 index 000000000..2f146e3f3 --- /dev/null +++ b/python/port/mod/matplotlib/modmatplotlib.h @@ -0,0 +1,3 @@ +#include + +mp_obj_t modmatplotlib___init__(); diff --git a/python/port/mod/matplotlib/modmatplotlib_table.c b/python/port/mod/matplotlib/modmatplotlib_table.c new file mode 100644 index 000000000..0178bd5e1 --- /dev/null +++ b/python/port/mod/matplotlib/modmatplotlib_table.c @@ -0,0 +1,18 @@ +#include "modmatplotlib.h" + +extern const mp_obj_module_t modpyplot_module; + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modmatplotlib___init___obj, modmatplotlib___init__); + +STATIC const mp_rom_map_elem_t modmatplotlib_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_matplotlib) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modmatplotlib___init___obj) }, + { MP_ROM_QSTR(MP_QSTR_pyplot), MP_ROM_PTR(&modpyplot_module) } +}; + +STATIC MP_DEFINE_CONST_DICT(modmatplotlib_module_globals, modmatplotlib_module_globals_table); + +const mp_obj_module_t modmatplotlib_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&modmatplotlib_module_globals, +}; diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp similarity index 100% rename from python/port/mod/matplotlib/modpyplot.cpp rename to python/port/mod/matplotlib/pyplot/modpyplot.cpp diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/pyplot/modpyplot.h similarity index 100% rename from python/port/mod/matplotlib/modpyplot.h rename to python/port/mod/matplotlib/pyplot/modpyplot.h diff --git a/python/port/mod/matplotlib/pyplot/modpyplot_table.c b/python/port/mod/matplotlib/pyplot/modpyplot_table.c new file mode 100644 index 000000000..1f4c3152b --- /dev/null +++ b/python/port/mod/matplotlib/pyplot/modpyplot_table.c @@ -0,0 +1,33 @@ +#include "modpyplot.h" + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_arrow_obj, 4, 4, modpyplot_arrow); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_axis_obj, 0, 1, modpyplot_axis); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_bar_obj, 2, 4, modpyplot_bar); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_grid_obj, 0, 1, modpyplot_grid); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_hist_obj, 1, 2, modpyplot_hist); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modpyplot_plot_obj, 1, 2, modpyplot_plot); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_scatter_obj, modpyplot_scatter); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(modpyplot_text_obj, modpyplot_text); + +STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, + { MP_ROM_QSTR(MP_QSTR_arrow), MP_ROM_PTR(&modpyplot_arrow_obj) }, + { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, + { MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&modpyplot_bar_obj) }, + { MP_ROM_QSTR(MP_QSTR_grid), MP_ROM_PTR(&modpyplot_grid_obj) }, + { MP_ROM_QSTR(MP_QSTR_hist), MP_ROM_PTR(&modpyplot_hist_obj) }, + { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, + { MP_ROM_QSTR(MP_QSTR_scatter), MP_ROM_PTR(&modpyplot_scatter_obj) }, + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&modpyplot_text_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(modpyplot_module_globals, modpyplot_module_globals_table); + +const mp_obj_module_t modpyplot_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&modpyplot_module_globals, +}; diff --git a/python/port/mod/matplotlib/plot_controller.cpp b/python/port/mod/matplotlib/pyplot/plot_controller.cpp similarity index 100% rename from python/port/mod/matplotlib/plot_controller.cpp rename to python/port/mod/matplotlib/pyplot/plot_controller.cpp diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/pyplot/plot_controller.h similarity index 100% rename from python/port/mod/matplotlib/plot_controller.h rename to python/port/mod/matplotlib/pyplot/plot_controller.h diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp similarity index 100% rename from python/port/mod/matplotlib/plot_store.cpp rename to python/port/mod/matplotlib/pyplot/plot_store.cpp diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/pyplot/plot_store.h similarity index 100% rename from python/port/mod/matplotlib/plot_store.h rename to python/port/mod/matplotlib/pyplot/plot_store.h diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp similarity index 100% rename from python/port/mod/matplotlib/plot_view.cpp rename to python/port/mod/matplotlib/pyplot/plot_view.cpp diff --git a/python/port/mod/matplotlib/plot_view.h b/python/port/mod/matplotlib/pyplot/plot_view.h similarity index 100% rename from python/port/mod/matplotlib/plot_view.h rename to python/port/mod/matplotlib/pyplot/plot_view.h diff --git a/python/port/mpconfigport.h b/python/port/mpconfigport.h index 6c95bc655..bfff743d6 100644 --- a/python/port/mpconfigport.h +++ b/python/port/mpconfigport.h @@ -130,6 +130,7 @@ typedef long mp_off_t; extern const struct _mp_obj_module_t modion_module; extern const struct _mp_obj_module_t modkandinsky_module; +extern const struct _mp_obj_module_t modmatplotlib_module; extern const struct _mp_obj_module_t modpyplot_module; extern const struct _mp_obj_module_t modtime_module; extern const struct _mp_obj_module_t modturtle_module; @@ -137,6 +138,7 @@ extern const struct _mp_obj_module_t modturtle_module; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_ion), MP_ROM_PTR(&modion_module) }, \ { MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&modkandinsky_module) }, \ + { MP_ROM_QSTR(MP_QSTR_matplotlib), MP_ROM_PTR(&modmatplotlib_module) }, \ { MP_ROM_QSTR(MP_QSTR_matplotlib_dot_pyplot), MP_ROM_PTR(&modpyplot_module) }, \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&modtime_module) }, \ { MP_ROM_QSTR(MP_QSTR_turtle), MP_ROM_PTR(&modturtle_module) }, \ diff --git a/python/port/port.cpp b/python/port/port.cpp index 6e3bc83e3..49a81856a 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -20,7 +20,7 @@ extern "C" { #include "py/stackctrl.h" #include "mphalport.h" #include "mod/turtle/modturtle.h" -#include "mod/matplotlib/modpyplot.h" +#include "mod/matplotlib/pyplot/modpyplot.h" } static MicroPython::ScriptProvider * sScriptProvider = nullptr; From b2c95bcbbfe079ff141826a20bd010bb0f8210d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Mar 2020 17:18:58 +0200 Subject: [PATCH 56/77] [apps/code] Parabola script --- apps/code/script_store.cpp | 1 + apps/code/script_template.cpp | 35 +++++++++++++++++++++++++++++++++++ apps/code/script_template.h | 1 + 3 files changed, 37 insertions(+) diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 705ba3506..e21047d7c 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -19,6 +19,7 @@ bool ScriptStore::ScriptNameIsFree(const char * baseName) { ScriptStore::ScriptStore() { addScriptFromTemplate(ScriptTemplate::Squares()); + addScriptFromTemplate(ScriptTemplate::Parabola()); addScriptFromTemplate(ScriptTemplate::Mandelbrot()); addScriptFromTemplate(ScriptTemplate::Polynomial()); } diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index dfa40a157..f4f22805f 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -48,6 +48,37 @@ plot(y, x) text(-1,-1,"Coucou") show())"); +constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import * +from math import * + +g=9.81 + +def x(t,v_0,alpha): + return v_0*cos(alpha)*t +def y(t,v_0,alpha,h_0): + return -0.5*g*t**2+v_0*sin(alpha)*t+h_0 + +def vx(v_0,alpha): + return v_0*cos(alpha) +def vy(t,v_0,alpha): + return -g*t+v_0*sin(alpha) + +def t_max(v_0,alpha,h_0): + return (v_0*sin(alpha)+sqrt((v_0**2)*(sin(alpha)**2)+2*g*h_0))/g + +def simulation(v_0=15,alpha=pi/4,h_0=2): + tMax=t_max(v_0,alpha,h_0) + accuracy=1/10**(floor(log10(tMax))-1) + T_MAX=floor(tMax*accuracy)+1 + X=[x(t/accuracy,v_0,alpha) for t in range(T_MAX)] + Y=[y(t/accuracy,v_0,alpha,h_0) for t in range(T_MAX)] + VX=[vx(v_0,alpha) for t in range(T_MAX)] + VY=[vy(t/accuracy,v_0,alpha) for t in range(T_MAX)] + for i in range(T_MAX): + arrow(X[i],Y[i],VX[i]/accuracy,VY[i]/accuracy) + grid() + show())"); + const ScriptTemplate * ScriptTemplate::Empty() { return &emptyScriptTemplate; } @@ -64,4 +95,8 @@ const ScriptTemplate * ScriptTemplate::Polynomial() { return &polynomialScriptTemplate; } +const ScriptTemplate * ScriptTemplate::Parabola() { + return ¶bolaScriptTemplate; +} + } diff --git a/apps/code/script_template.h b/apps/code/script_template.h index 2eb2e3472..d0d048ab1 100644 --- a/apps/code/script_template.h +++ b/apps/code/script_template.h @@ -10,6 +10,7 @@ public: static const ScriptTemplate * Squares(); static const ScriptTemplate * Mandelbrot(); 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 * value() const { return m_value; } From 2ac1396dd255a830a8ac49e25e78cf34e47b9098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Mar 2020 17:21:47 +0200 Subject: [PATCH 57/77] [apps/code] Put back the polynomial script --- apps/code/script_template.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index f4f22805f..971b44496 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -40,13 +40,18 @@ def mandelbrot(N_iteration): # Draw a pixel colored in 'col' at position (x,y) kandinsky.set_pixel(x,y,col))"); -constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from pyplot import * -x = [1,2,3,4] -y = [-1,-2,-3,-4] -scatter(x, y) -plot(y, x) -text(-1,-1,"Coucou") -show())"); +constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from math import * +# roots(a,b,c) computes the solutions of the equation a*x**2+b*x+c=0 +def roots(a,b,c): + delta = b*b-4*a*c + if delta == 0: + return -b/(2*a) + elif delta > 0: + x_1 = (-b-sqrt(delta))/(2*a) + x_2 = (-b+sqrt(delta))/(2*a) + return x_1, x_2 + else: + return None)"); constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import * from math import * From 2f4064d92ba3c52c91419920f6b86415ddd43eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 30 Mar 2020 17:40:43 +0200 Subject: [PATCH 58/77] [apps/code] Fix axis() command without arguments It inserted axis(,,,) instead of axis() --- apps/code/catalog.universal.i18n | 1 + apps/code/python_toolbox.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 812a8c38f..b01e7042b 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -19,6 +19,7 @@ PythonCommandAtan = "atan(x)" PythonCommandAtan2 = "atan2(y,x)" PythonCommandAtanh = "atanh(x)" PythonCommandAxis = "axis((xmin,xmax,ymin,ymax))" +PythonCommandAxisWithoutArg = "axis(\x11)" PythonCommandBar = "bar(x,height)" PythonCommandBin = "bin(x)" PythonCommandCeil = "ceil(x)" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 91cb7448b..709745219 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -113,7 +113,7 @@ const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis), //TODO LEA ? + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist), From 574eacb69cee9bc3b2207dbcb45f10326834196e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 14:06:35 +0200 Subject: [PATCH 59/77] [python] matplotlib: flush heap memory when any error is raised --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 6 ++++++ python/port/port.cpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 8d8d86baf..c8e67f872 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -72,6 +72,12 @@ void modpyplot_gc_collect() { ); } +void modpyplot_flush_used_heap() { + if (sPlotStore) { + // Clean the store object + sPlotStore->flush(); + } +} mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { assert(n_args == 4); assert(sPlotStore != nullptr); diff --git a/python/port/port.cpp b/python/port/port.cpp index 49a81856a..77c7b6c4a 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -82,6 +82,10 @@ void MicroPython::ExecutionEnvironment::runCode(const char * str) { mp_obj_print_helper(&mp_plat_print, (mp_obj_t)nlr.ret_val, PRINT_EXC); mp_print_str(&mp_plat_print, "\n"); /* End of mp_obj_print_exception. */ + + // Flush the store if an error is encountered to avoid being stuck with a full memory + modpyplot_flush_used_heap(); + // TODO: do the same for other modules? } // Disable the user interruption From 81284120af0a21a8b0367d92db29f2e5b056d593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 14:29:23 +0200 Subject: [PATCH 60/77] [apps/code] ConsoleController: refreshOutput is now done only when the console is active --- apps/code/console_controller.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 9a4455315..9578137af 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -446,8 +446,7 @@ void ConsoleController::printText(const char * text, size_t length) { assert(textCutIndex == length - 1); appendTextToOutputAccumulationBuffer(text, length-1); flushOutputAccumulationBufferToStore(); - // FIXME: This needs to be done *only* if the console is active! - //micropython_port_vm_hook_refresh_print(); + micropython_port_vm_hook_refresh_print(); } #if __EMSCRIPTEN__ /* If we called micropython_port_interrupt_if_needed here, we would need to From d247843da6aa6fae4ec2e122c2c3e1c7bbe6ae3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 15:54:41 +0200 Subject: [PATCH 61/77] [apps/code] Clean ConsoleController::reloadData (always returns true) --- apps/code/console_controller.cpp | 11 +++++------ apps/code/console_controller.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index 9578137af..477dda7c3 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -151,9 +151,8 @@ const char * ConsoleController::inputText(const char * prompt) { m_editCell.clearAndReduceSize(); // Reload the history - if (reloadData(true)) { - appsContainer->redrawWindow(); - } + reloadData(true); + appsContainer->redrawWindow(); // Launch a new input loop appsContainer->runWhile([](void * a){ @@ -408,12 +407,13 @@ bool ConsoleController::isDisplayingViewController() { } void ConsoleController::refreshPrintOutput() { - if (!isDisplayingViewController() && reloadData(false)) { + if (!isDisplayingViewController()) { + reloadData(false); AppsContainer::sharedAppsContainer()->redrawWindow(); } } -bool ConsoleController::reloadData(bool isEditing) { +void ConsoleController::reloadData(bool isEditing) { m_selectableTableView.reloadData(); m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines()); if (isEditing) { @@ -422,7 +422,6 @@ bool ConsoleController::reloadData(bool isEditing) { } else { m_editCell.setEditing(false); } - return true; } /* printText is called by the Python machine. diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 09192ce39..f198255a6 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -83,7 +83,7 @@ private: // k_numberOfLineCells = (240 - 18)/14 ~ 15.9. The 0.1 cell can be above and below the 15 other cells so we add +2 cells. static constexpr int k_outputAccumulationBufferSize = 100; bool isDisplayingViewController(); - bool reloadData(bool isEditing); + void reloadData(bool isEditing); void flushOutputAccumulationBufferToStore(); void appendTextToOutputAccumulationBuffer(const char * text, size_t length); void emptyOutputAccumulationBuffer(); From b290bed4094e12b83b5e6fbe2c7638d5b7defef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 15:55:04 +0200 Subject: [PATCH 62/77] [python] matplotlib: fix typo in ErrorValue --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index c8e67f872..cc99d0c5a 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -122,7 +122,7 @@ mp_obj_t modpyplot_axis(size_t n_args, const mp_obj_t *args) { sPlotStore->setYMax(mp_obj_get_float(items[3])); sPlotStore->setAxesAuto(false); } else { - mp_raise_TypeError("the first argument to axis() must be an interable of the form [xmin, xmax, ymin, ymax]"); + mp_raise_TypeError("the first argument to axis() must be an iterable of the form [xmin, xmax, ymin, ymax]"); } } From 2c82460470e8c0c1af83fab70526b947f7d3580c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 16:01:07 +0200 Subject: [PATCH 63/77] [python] matplotlib: add a comment to PlotView --- python/port/mod/matplotlib/pyplot/plot_view.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index 4269edb2d..f56b918b1 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -9,6 +9,8 @@ void PlotView::drawRect(KDContext * ctx, KDRect rect) const { drawGrid(ctx, rect); } + // Draw labels below all figures because they're drawn on a white rectangle. + // TODO: we could blend them in the background by adding a parameter to drawLabelsAndGraduations. if (m_store->axesRequested()) { drawAxes(ctx, rect); drawLabelsAndGraduations(ctx, rect, Axis::Vertical, true); From 51eabf08e1521c95d5ffbcc268964ce5c273e0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 16:04:59 +0200 Subject: [PATCH 64/77] [python] matplotlib: fix PlotStore::initRange for an only dot --- python/port/mod/matplotlib/pyplot/plot_store.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index 68b61ae98..4eeb49d63 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -176,6 +176,9 @@ void checkPositiveRangeAndAddMargin(float * min, float * max) { } // Add margins float margin = (*max - *min)/10.0f; + if (margin < FLT_EPSILON) { + margin = 1.0f; + } *min -= margin; *max += margin; } From ce33faad11e9a97d75c8b8f74667b351afbe2562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 16:17:44 +0200 Subject: [PATCH 65/77] [python] matplotlib: PlotView: rectangle are always visible despite the pixel width --- python/port/mod/matplotlib/pyplot/plot_view.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index f56b918b1..d55034be5 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -52,11 +52,12 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen } } +static inline KDCoordinate maxKDCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; } void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const { KDRect pixelRect( floatToPixel(Axis::Horizontal, rect.x()), floatToPixel(Axis::Vertical, rect.y()), - rect.width() / pixelWidth(), + maxKDCoordinate(rect.width() / pixelWidth(), 1), // Rectangle should at least be visible rect.height() / pixelHeight() ); ctx->fillRect(pixelRect, rect.color()); From b3b65654108b1735639a593f3405d4901ba036f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 16:41:25 +0200 Subject: [PATCH 66/77] [python] modpyplot: show() does nothing when the store is empty --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 3 +++ python/port/mod/matplotlib/pyplot/plot_store.cpp | 4 ++++ python/port/mod/matplotlib/pyplot/plot_store.h | 1 + 3 files changed, 8 insertions(+) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index cc99d0c5a..eea8af5e5 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -342,6 +342,9 @@ mp_obj_t modpyplot_text(mp_obj_t x, mp_obj_t y, mp_obj_t s) { } mp_obj_t modpyplot_show() { + if (sPlotStore->isEmpty()) { + return mp_const_none; + } MicroPython::ExecutionEnvironment * env = MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); env->displayViewController(sPlotController); return mp_const_none; diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index 4eeb49d63..10c09c745 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -20,6 +20,10 @@ void PlotStore::flush() { m_gridRequested = false; } +bool PlotStore::isEmpty() { + return MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_dots)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_segments)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_rects)) == 0 && MP_OBJ_SMALL_INT_VALUE(mp_obj_len(m_labels)) == 0; +} + // Iterators template diff --git a/python/port/mod/matplotlib/pyplot/plot_store.h b/python/port/mod/matplotlib/pyplot/plot_store.h index 12ff2fbf8..17329163f 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.h +++ b/python/port/mod/matplotlib/pyplot/plot_store.h @@ -13,6 +13,7 @@ class PlotStore : public Shared::InteractiveCurveViewRange { public: PlotStore(); void flush(); + bool isEmpty(); // Iterators From 84bc46ca8c6de1fd3610608fd20195d41085e0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 17:04:50 +0200 Subject: [PATCH 67/77] [python] matplotlib: PlotView: improve rect drawing (use round instead of truncating pixelFloat --- python/port/mod/matplotlib/pyplot/plot_view.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index d55034be5..1c913f0a6 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -55,10 +55,10 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen static inline KDCoordinate maxKDCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; } void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const { KDRect pixelRect( - floatToPixel(Axis::Horizontal, rect.x()), - floatToPixel(Axis::Vertical, rect.y()), - maxKDCoordinate(rect.width() / pixelWidth(), 1), // Rectangle should at least be visible - rect.height() / pixelHeight() + std::round(floatToPixel(Axis::Horizontal, rect.x())), + std::round(floatToPixel(Axis::Vertical, rect.y())), + maxKDCoordinate(std::round(rect.width() / pixelWidth()), 1), // Rectangle should at least be visible + std::round(rect.height() / pixelHeight()) ); ctx->fillRect(pixelRect, rect.color()); } From d468f5e130f9b00f1663c86760addec91793f9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 17:43:07 +0200 Subject: [PATCH 68/77] [python] WIP matplotlib: avoid empty pixel line between bars and axis line --- python/port/mod/matplotlib/pyplot/plot_view.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index 1c913f0a6..fdb4a9afb 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -57,8 +57,10 @@ void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const KDRect pixelRect( std::round(floatToPixel(Axis::Horizontal, rect.x())), std::round(floatToPixel(Axis::Vertical, rect.y())), - maxKDCoordinate(std::round(rect.width() / pixelWidth()), 1), // Rectangle should at least be visible - std::round(rect.height() / pixelHeight()) + // Use std::ceil instead of std::round to avoid empty pixel line between bars and horizontal axis line + // TODO: change stored rectangles to keep all summits? + maxKDCoordinate(std::ceil(rect.width() / pixelWidth()), 1), // Rectangle should at least be visible + std::ceil(rect.height() / pixelHeight()) ); ctx->fillRect(pixelRect, rect.color()); } From 7c612f35a8a11e7b08497731501938a3bcb7f552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 18:03:10 +0200 Subject: [PATCH 69/77] [python] matplotlib: change Store::Rectangle structure to (left, right, top, bottom) and avoid rounding error when converting flaot rect to pixel --- .../port/mod/matplotlib/pyplot/modpyplot.cpp | 10 +++++----- .../port/mod/matplotlib/pyplot/plot_store.cpp | 18 ++++++++---------- python/port/mod/matplotlib/pyplot/plot_store.h | 16 ++++++++-------- .../port/mod/matplotlib/pyplot/plot_view.cpp | 14 ++++++++------ 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index eea8af5e5..0cc1005d6 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -182,8 +182,9 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { mp_float_t iW = mp_obj_get_float(wItems[wLength > 1 ? i : 0]); mp_float_t iB = mp_obj_get_float(bItems[bLength > 1 ? i : 0]); mp_float_t iX = mp_obj_get_float(xItems[i])-iW/2.0; - mp_float_t iY = iH < 0.0 ? iB : iB + iH; - sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iY), mp_obj_new_float(iW), mp_obj_new_float(std::fabs(iH)), color); + mp_float_t iYStart = iH < 0.0 ? iB : iB + iH; + mp_float_t iYEnd = iH < 0.0 ? iB + iH : iB; + sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iX+iW), mp_obj_new_float(iYStart), mp_obj_new_float(iYEnd), color); // TODO: use float_binary_op? } return mp_const_none; } @@ -262,7 +263,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { mp_float_t upperBound = mp_obj_get_float(edgeItems[binIndex+1]); while (mp_obj_get_float(xItems[xIndex]) < upperBound || (binIndex == nBins - 1 && mp_obj_get_float(xItems[xIndex]) == upperBound)) { // Increment the bin count - binItems[binIndex] = mp_obj_new_int(mp_obj_get_int(binItems[binIndex]) + 1); // TODO: better way? + binItems[binIndex] = mp_obj_new_int(mp_obj_get_int(binItems[binIndex]) + 1); // TODO: better way? Use int_unary_op? xIndex++; if (xIndex == xLength) { break; @@ -273,8 +274,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { KDColor color = Palette::nextDataColor(&paletteIndex); for (size_t i=0; iaddRect(edgeItems[i], binItems[i], mp_obj_new_float(width), binItems[i], color); + sPlotStore->addRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color); } return mp_const_none; } diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index 10c09c745..ede1a3af4 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -121,16 +121,16 @@ template class PlotStore::ListIterator; PlotStore::Rect::Rect(mp_obj_t tuple) { mp_obj_t * elements; mp_obj_get_array_fixed_n(tuple, 5, &elements); - m_x = mp_obj_get_float(elements[0]); - m_y = mp_obj_get_float(elements[1]); - m_width = mp_obj_get_float(elements[2]); - m_height = mp_obj_get_float(elements[3]); + m_left = mp_obj_get_float(elements[0]); + m_right = mp_obj_get_float(elements[1]); + m_top = mp_obj_get_float(elements[2]); + m_bottom = mp_obj_get_float(elements[3]); m_color = KDColor::RGB16(mp_obj_get_int(elements[4])); } -void PlotStore::addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c) { +void PlotStore::addRect(mp_obj_t left, mp_obj_t right, mp_obj_t top, mp_obj_t bottom, KDColor c) { mp_obj_t color = mp_obj_new_int(c); - mp_obj_t items[5] = {x, y, width, height, color}; + mp_obj_t items[5] = {left, right, top, bottom, color}; checkFloatType(items, 4); mp_obj_t tuple = mp_obj_new_tuple(5, items); mp_obj_list_append(m_rects, tuple); @@ -204,10 +204,8 @@ void PlotStore::initRange() { updateRange(&xMin, &xMax, &yMin, &yMax, segment.xEnd(), segment.yEnd()); } for (PlotStore::Rect rectangle : rects()) { - float x = rectangle.x(); - float y = rectangle.y(); - updateRange(&xMin, &xMax, &yMin, &yMax, x, y); - updateRange(&xMin, &xMax, &yMin, &yMax, x + rectangle.width(), y - rectangle.height()); + updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.left(), rectangle.top()); + updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.right(), rectangle.bottom()); } checkPositiveRangeAndAddMargin(&xMin, &xMax); checkPositiveRangeAndAddMargin(&yMin, &yMax); diff --git a/python/port/mod/matplotlib/pyplot/plot_store.h b/python/port/mod/matplotlib/pyplot/plot_store.h index 17329163f..d74b60cb0 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.h +++ b/python/port/mod/matplotlib/pyplot/plot_store.h @@ -87,16 +87,16 @@ public: class Rect { public: Rect(mp_obj_t tuple); - float x() const { return m_x; } - float y() const { return m_y; } - float width() const { return m_width; } - float height() const { return m_height; } + float left() const { return m_left; } + float right() const { return m_right; } + float top() const { return m_top; } + float bottom() const { return m_bottom; } KDColor color() const { return m_color; } private: - float m_x; - float m_y; - float m_width; - float m_height; + float m_left; + float m_right; + float m_top; + float m_bottom; KDColor m_color; }; diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index fdb4a9afb..eef482aef 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -54,13 +54,15 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen static inline KDCoordinate maxKDCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; } void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const { + KDCoordinate left = std::round(floatToPixel(Axis::Horizontal, rect.left())); + KDCoordinate right = std::round(floatToPixel(Axis::Horizontal, rect.right())); + KDCoordinate top = std::round(floatToPixel(Axis::Vertical, rect.top())); + KDCoordinate bottom = std::round(floatToPixel(Axis::Vertical, rect.bottom())); KDRect pixelRect( - std::round(floatToPixel(Axis::Horizontal, rect.x())), - std::round(floatToPixel(Axis::Vertical, rect.y())), - // Use std::ceil instead of std::round to avoid empty pixel line between bars and horizontal axis line - // TODO: change stored rectangles to keep all summits? - maxKDCoordinate(std::ceil(rect.width() / pixelWidth()), 1), // Rectangle should at least be visible - std::ceil(rect.height() / pixelHeight()) + left, + top, + maxKDCoordinate(right - left, 1), // Rectangle should at least be visible + bottom - top ); ctx->fillRect(pixelRect, rect.color()); } From 642a7c7f61ca5f6d7689c2667f4ac01729d337d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 18:04:14 +0200 Subject: [PATCH 70/77] [apps/code] Increase python heap to 32k --- apps/code/app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code/app.h b/apps/code/app.h index 479a293fe..605beb8ea 100644 --- a/apps/code/app.h +++ b/apps/code/app.h @@ -71,7 +71,7 @@ public: VariableBoxController * variableBoxController() { return &m_variableBoxController; } - static constexpr int k_pythonHeapSize = 16384; + static constexpr int k_pythonHeapSize = 32768; private: /* Python delegate: From bc1eae17d71a1b07818e5fd5203d10d25af408ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 18:07:01 +0200 Subject: [PATCH 71/77] [python] matplotlib: change text() relative position to be similar to python3 --- python/port/mod/matplotlib/pyplot/plot_view.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index eef482aef..76daa005a 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -71,8 +71,8 @@ void PlotView::traceLabel(KDContext * ctx, KDRect r, PlotStore::Label label) con drawLabel(ctx, r, label.x(), label.y(), label.string(), KDColorBlack, - RelativePosition::None, - RelativePosition::None + RelativePosition::After, + RelativePosition::After ); } From 28224bd75ea09860285288add0a662af6aa43dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 31 Mar 2020 10:49:50 +0200 Subject: [PATCH 72/77] [python] matplotlib: fix hist implementation This fixes the following crash: input 'hist([1,2,100],[1,2]) on a Python console with matplotlib.pyplot imported --- .../port/mod/matplotlib/pyplot/modpyplot.cpp | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 0cc1005d6..c2b08b36a 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -251,23 +251,25 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { // Initialize bins list mp_obj_t * binItems = m_new(mp_obj_t, nBins); for (size_t i=0; i= lowerBound); + // Increment the bin count + binItems[binIndex] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(binItems[binIndex]) + 1); xIndex++; - if (xIndex == xLength) { - break; - } } binIndex++; } From 3987167419654b351d11ce88b717904c36cc37ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 31 Mar 2020 12:03:18 +0200 Subject: [PATCH 73/77] [python] matplotlib: add comment --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index c2b08b36a..bcbf2569b 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -78,6 +78,11 @@ void modpyplot_flush_used_heap() { sPlotStore->flush(); } } + +/* arrow(x,y,dx,dy) + * x, y, dx, dy scalars + * */ + mp_obj_t modpyplot_arrow(size_t n_args, const mp_obj_t *args) { assert(n_args == 4); assert(sPlotStore != nullptr); From e5660635d6d9da8a070cbea973b163388056360b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 31 Mar 2020 12:03:41 +0200 Subject: [PATCH 74/77] [python] matplotlib: handle case hist([]) --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index bcbf2569b..0a0c7de73 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -219,9 +219,13 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { // Sort data to easily get the minimal and maximal value and count bin sizes mp_obj_t * xItems; size_t xLength = extractArgument(args[0], &xItems); + if (xLength == 0) { + return mp_const_none; + } mp_obj_t xList = mp_obj_new_list(xLength, xItems); mp_obj_list_sort(1, &xList, (mp_map_t*)&mp_const_empty_map); mp_obj_list_get(xList, &xLength, &xItems); + assert(xLength > 0); mp_float_t min = mp_obj_get_float(xItems[0]); mp_float_t max = mp_obj_get_float(xItems[xLength - 1]); From 244b97e89b06995c2730635240f1b90fa3280ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 31 Mar 2020 12:04:19 +0200 Subject: [PATCH 75/77] [python] matplotlib: handle case plot([],[]) --- python/port/mod/matplotlib/pyplot/modpyplot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index 0a0c7de73..0b1e5a808 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -332,7 +332,7 @@ mp_obj_t modpyplot_plot(size_t n_args, const mp_obj_t *args) { } KDColor color = Palette::nextDataColor(&paletteIndex); - for (size_t i=0; iaddSegment(xItems[i], yItems[i], xItems[i+1], yItems[i+1], color, false); } From 0f00bdda331f046efb8317f6d2afe387e1e84f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 31 Mar 2020 14:11:39 +0200 Subject: [PATCH 76/77] [apps] Fix test build --- apps/shared/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 00a676226..b406d41cb 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -1,6 +1,8 @@ app_shared_test_src = $(addprefix apps/shared/,\ continuous_function.cpp\ curve_view_range.cpp \ + curve_view.cpp \ + dots.cpp \ double_pair_store.cpp \ expression_model.cpp \ expression_model_handle.cpp \ @@ -9,8 +11,11 @@ app_shared_test_src = $(addprefix apps/shared/,\ global_context.cpp \ interactive_curve_view_range_delegate.cpp \ interactive_curve_view_range.cpp \ + labeled_curve_view.cpp \ memoized_curve_view_range.cpp \ range_1D.cpp \ + zoom_and_pan_curve_view_controller.cpp \ + zoom_curve_view_controller.cpp \ ) app_shared_src = $(addprefix apps/shared/,\ @@ -18,9 +23,7 @@ app_shared_src = $(addprefix apps/shared/,\ buffer_function_title_cell.cpp \ buffer_text_view_with_text_field.cpp \ button_with_separator.cpp \ - dots.cpp \ cursor_view.cpp \ - curve_view.cpp \ curve_view_cursor.cpp \ editable_cell_table_view_controller.cpp \ expression_field_delegate_app.cpp \ @@ -45,7 +48,6 @@ app_shared_src = $(addprefix apps/shared/,\ interactive_curve_view_controller.cpp \ interval.cpp \ interval_parameter_controller.cpp \ - labeled_curve_view.cpp \ language_controller.cpp \ layout_field_delegate.cpp \ list_parameter_controller.cpp \ @@ -78,8 +80,6 @@ app_shared_src = $(addprefix apps/shared/,\ values_parameter_controller.cpp \ vertical_cursor_view.cpp \ xy_banner_view.cpp\ - zoom_curve_view_controller.cpp \ - zoom_and_pan_curve_view_controller.cpp \ zoom_parameter_controller.cpp \ ) From 511a96f464074fdbc6acfcd24b256d786cd2aea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 31 Mar 2020 17:46:55 +0200 Subject: [PATCH 77/77] [apps/code] Add matplotlib.pyplot functions to the toolbox catalog Not just in the modules submenu --- apps/code/python_toolbox.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 709745219..5043c7f7f 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -267,12 +267,15 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAbs, I18n::Message::PythonAbs), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcos, I18n::Message::PythonAcos), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcosh, I18n::Message::PythonAcosh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsin, I18n::Message::PythonAsin), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsinh, I18n::Message::PythonAsinh), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan, I18n::Message::PythonAtan), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan2, I18n::Message::PythonAtan2), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtanh, I18n::Message::PythonAtanh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg), 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), @@ -306,6 +309,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMath, I18n::Message::PythonImportMath, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTime, I18n::Message::PythonImportTime, false), @@ -315,13 +319,16 @@ const ToolboxMessageTree catalogChildren[] = { 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::PythonCommandGrid, I18n::Message::PythonGrid), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMath, I18n::Message::PythonImportMath, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, false), @@ -351,6 +358,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog10, I18n::Message::PythonLog10), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog2, I18n::Message::PythonLog2), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMathFunction, I18n::Message::PythonMathFunction, false, I18n::Message::PythonCommandMathFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMax, I18n::Message::PythonMax), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMin, I18n::Message::PythonMin), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf), @@ -366,6 +374,7 @@ const ToolboxMessageTree catalogChildren[] = { 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::PythonCommandRadians, I18n::Message::PythonRadians), @@ -380,9 +389,11 @@ const ToolboxMessageTree catalogChildren[] = { 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), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSetheading, I18n::Message::PythonTurtleSetheading), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSin, I18n::Message::PythonSin), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinh, I18n::Message::PythonSinh), @@ -393,6 +404,7 @@ const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSum, I18n::Message::PythonSum), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTan, I18n::Message::PythonTan), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTanh, I18n::Message::PythonTanh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTimeFunction, I18n::Message::PythonTimeFunction, false, I18n::Message::PythonCommandTimeFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg),