mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[Python] universal colors
This commit is contained in:
@@ -430,6 +430,7 @@ Q(st)
|
||||
Q(hideturtle)
|
||||
Q(ht)
|
||||
Q(isvisible)
|
||||
Q(colormode)
|
||||
|
||||
// utime QSTRs
|
||||
Q(time)
|
||||
|
||||
@@ -1,26 +1,10 @@
|
||||
extern "C" {
|
||||
#include "modkandinsky.h"
|
||||
#include <py/objtuple.h>
|
||||
#include <py/runtime.h>
|
||||
}
|
||||
#include <kandinsky.h>
|
||||
#include "port.h"
|
||||
|
||||
static KDColor ColorForTuple(mp_obj_t tuple) {
|
||||
size_t len;
|
||||
mp_obj_t * elem;
|
||||
|
||||
mp_obj_get_array(tuple, &len, &elem);
|
||||
if (len != 3) {
|
||||
mp_raise_TypeError("color needs 3 components");
|
||||
}
|
||||
|
||||
return KDColor::RGB888(
|
||||
mp_obj_get_int(elem[0]),
|
||||
mp_obj_get_int(elem[1]),
|
||||
mp_obj_get_int(elem[2])
|
||||
);
|
||||
}
|
||||
|
||||
static mp_obj_t TupleForRGB(uint8_t r, uint8_t g, uint8_t b) {
|
||||
mp_obj_tuple_t * t = static_cast<mp_obj_tuple_t *>(MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)));
|
||||
@@ -56,19 +40,20 @@ mp_obj_t modkandinsky_get_pixel(mp_obj_t x, mp_obj_t y) {
|
||||
return TupleForRGB(c.red(), c.green(), c.blue());
|
||||
}
|
||||
|
||||
mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t color) {
|
||||
mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t input) {
|
||||
KDPoint point(mp_obj_get_int(x), mp_obj_get_int(y));
|
||||
KDColor kdColor = ColorForTuple(color);
|
||||
KDColor kdColor = MicroPython::ColorParser::ParseColor(input);
|
||||
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
|
||||
KDIonContext::sharedContext()->setPixel(point, kdColor);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
//TODO Use good colors
|
||||
mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t * args) {
|
||||
const char * text = mp_obj_str_get_str(args[0]);
|
||||
KDPoint point(mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
|
||||
KDColor textColor = (n_args >= 4) ? ColorForTuple(args[3]) : KDColorBlack;
|
||||
KDColor backgroundColor = (n_args >= 5) ? ColorForTuple(args[4]) : KDColorWhite;
|
||||
KDColor textColor = (n_args >= 4) ? MicroPython::ColorParser::ParseColor(args[3]) : KDColorBlack;
|
||||
KDColor backgroundColor = (n_args >= 5) ? MicroPython::ColorParser::ParseColor(args[4]) : KDColorWhite;
|
||||
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
|
||||
KDIonContext::sharedContext()->drawString(text, point, KDFont::LargeFont, textColor, backgroundColor);
|
||||
/* Before and after execution of "modkandinsky_draw_string",
|
||||
@@ -98,8 +83,7 @@ mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) {
|
||||
y = y - height;
|
||||
}
|
||||
KDRect rect(x, y, width, height);
|
||||
KDColor color = ColorForTuple(args[4]);
|
||||
|
||||
KDColor color = MicroPython::ColorParser::ParseColor(args[4]);
|
||||
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
|
||||
KDIonContext::sharedContext()->fillRect(rect, color);
|
||||
// Cf comment on modkandinsky_draw_string
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
extern "C" {
|
||||
#include "modturtle.h"
|
||||
#include <py/gc.h>
|
||||
#include <py/objtuple.h>
|
||||
#include <py/runtime.h>
|
||||
}
|
||||
#include "turtle.h"
|
||||
#include "../../port.h"
|
||||
@@ -131,37 +133,63 @@ mp_obj_t modturtle_isdown() {
|
||||
}
|
||||
|
||||
mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
// pencolor()
|
||||
KDColor c = sTurtle.color();
|
||||
mp_obj_t mp_col[3];
|
||||
mp_col[0] = mp_obj_new_int_from_uint(c.red());
|
||||
mp_col[1] = mp_obj_new_int_from_uint(c.green());
|
||||
mp_col[2] = mp_obj_new_int_from_uint(c.blue());
|
||||
return mp_obj_new_tuple(3, mp_col);
|
||||
}
|
||||
if (n_args == 1) {
|
||||
if (MP_OBJ_IS_STR(args[0])) {
|
||||
// pencolor("blue")
|
||||
size_t l;
|
||||
sTurtle.setColor(mp_obj_str_get_data(args[0], &l));
|
||||
} else {
|
||||
// pencolor((r, g, b))
|
||||
mp_obj_t * rgb;
|
||||
mp_obj_get_array_fixed_n(args[0], 3, &rgb);
|
||||
sTurtle.setColor(
|
||||
KDColor::RGB888(
|
||||
mp_obj_get_int(rgb[0]),
|
||||
mp_obj_get_int(rgb[1]),
|
||||
mp_obj_get_int(rgb[2])));
|
||||
switch(n_args){
|
||||
case 0:{
|
||||
// pencolor()
|
||||
KDColor c = sTurtle.color();
|
||||
mp_obj_t mp_col[3];
|
||||
if(sTurtle.colorMode() == MicroPython::ColorParser::ColorModes::MaxIntensity255){
|
||||
mp_col[0] = mp_obj_new_int_from_uint(c.red());
|
||||
mp_col[1] = mp_obj_new_int_from_uint(c.green());
|
||||
mp_col[2] = mp_obj_new_int_from_uint(c.blue());
|
||||
} else {
|
||||
mp_col[0] = mp_obj_new_float(c.red() / 255.0);
|
||||
mp_col[1] = mp_obj_new_float(c.green() / 255.0);
|
||||
mp_col[2] = mp_obj_new_float(c.blue() / 255.0);
|
||||
}
|
||||
return mp_obj_new_tuple(3, mp_col);
|
||||
}
|
||||
case 1:{
|
||||
sTurtle.setColor(MicroPython::ColorParser::ParseColor(args[0], sTurtle.colorMode()));
|
||||
break;
|
||||
}
|
||||
case 3:{
|
||||
// pencolor(r, g, b)
|
||||
if(sTurtle.colorMode() == MicroPython::ColorParser::ColorModes::MaxIntensity255){
|
||||
sTurtle.setColor(
|
||||
KDColor::RGB888(
|
||||
mp_obj_get_int(args[0]),
|
||||
mp_obj_get_int(args[1]),
|
||||
mp_obj_get_int(args[2])));
|
||||
} else {
|
||||
sTurtle.setColor(
|
||||
KDColor::RGB888(
|
||||
mp_obj_get_int(args[0]) * 255,
|
||||
mp_obj_get_int(args[1]) * 255,
|
||||
mp_obj_get_int(args[2]) * 255));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
assert(n_args == 2);
|
||||
mp_raise_TypeError("pencolor() takes 0, 1 or 3 arguments");
|
||||
}
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args){
|
||||
if(n_args == 0){
|
||||
return (sTurtle.colorMode() == MicroPython::ColorParser::ColorModes::MaxIntensity255) ? mp_obj_new_int_from_uint(255) : mp_obj_new_int_from_uint(1);
|
||||
} else{
|
||||
int colorMode = mp_obj_get_int(args[0]);
|
||||
if(colorMode == 1){
|
||||
sTurtle.setColorMode(MicroPython::ColorParser::ColorModes::MaxIntensity1);
|
||||
} else if(colorMode == 255){
|
||||
sTurtle.setColorMode(MicroPython::ColorParser::ColorModes::MaxIntensity255);
|
||||
} else {
|
||||
mp_raise_ValueError("Colormodes can be 1 or 255");
|
||||
}
|
||||
} else if (n_args == 3) {
|
||||
// pencolor(r, g, b)
|
||||
sTurtle.setColor(
|
||||
KDColor::RGB888(
|
||||
mp_obj_get_int(args[0]),
|
||||
mp_obj_get_int(args[1]),
|
||||
mp_obj_get_int(args[2])));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ mp_obj_t modturtle_pensize(size_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t modturtle_isvisible();
|
||||
|
||||
mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args);
|
||||
|
||||
mp_obj_t modturtle_showturtle();
|
||||
mp_obj_t modturtle_hideturtle();
|
||||
|
||||
@@ -18,6 +18,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_pensize_obj, 0, 1, modturtl
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_isdown_obj, modturtle_isdown);
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_pencolor_obj, 0, 3, modturtle_pencolor);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_colormode_obj, 0, 1, modturtle_colormode);
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_reset_obj, modturtle_reset);
|
||||
|
||||
@@ -64,6 +65,7 @@ STATIC const mp_rom_map_elem_t modturtle_module_globals_table[] = {
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_color), (mp_obj_t)&modturtle_pencolor_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pencolor), (mp_obj_t)&modturtle_pencolor_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_colormode), (mp_obj_t)&modturtle_colormode_obj },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset), (mp_obj_t)&modturtle_reset_obj },
|
||||
|
||||
|
||||
@@ -175,27 +175,6 @@ void Turtle::setVisible(bool visible) {
|
||||
}
|
||||
}
|
||||
|
||||
void Turtle::setColor(const char * color) {
|
||||
constexpr NameColorPair pairs[] = {
|
||||
NameColorPair("blue", KDColorBlue),
|
||||
NameColorPair("red", KDColorRed),
|
||||
NameColorPair("green", Palette::Green),
|
||||
NameColorPair("yellow", KDColorYellow),
|
||||
NameColorPair("brown", Palette::Brown),
|
||||
NameColorPair("black", KDColorBlack),
|
||||
NameColorPair("white", KDColorWhite),
|
||||
NameColorPair("pink", Palette::Pink),
|
||||
NameColorPair("orange", Palette::Orange),
|
||||
NameColorPair("purple", Palette::Purple),
|
||||
NameColorPair("grey", Palette::GreyDark)
|
||||
};
|
||||
for (NameColorPair p : pairs) {
|
||||
if (strcmp(p.name(), color) == 0) {
|
||||
m_color = p.color();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Turtle::viewDidDisappear() {
|
||||
m_drawn = false;
|
||||
|
||||
@@ -8,6 +8,7 @@ extern "C" {
|
||||
#include <escher/metric.h>
|
||||
#include <kandinsky.h>
|
||||
#include <math.h>
|
||||
#include <python/port/port.h>
|
||||
|
||||
/* We check for keyboard interruptions using micropython_port_vm_hook_loop and
|
||||
* micropython_port_interruptible_msleep, but even if we catch an interruption,
|
||||
@@ -29,6 +30,7 @@ public:
|
||||
m_y(0),
|
||||
m_heading(0),
|
||||
m_color(k_defaultColor),
|
||||
m_colorMode(MicroPython::ColorParser::ColorModes::MaxIntensity255),
|
||||
m_penDown(true),
|
||||
m_visible(true),
|
||||
m_speed(k_defaultSpeed),
|
||||
@@ -71,7 +73,10 @@ public:
|
||||
void setColor(uint8_t r, uint8_t g, uint8_t b) {
|
||||
m_color = KDColor::RGB888(r, g, b);
|
||||
}
|
||||
void setColor(const char * color);
|
||||
MicroPython::ColorParser::ColorModes colorMode() const {return m_colorMode; }
|
||||
void setColorMode(MicroPython::ColorParser::ColorModes colorMode){
|
||||
m_colorMode = colorMode;
|
||||
}
|
||||
|
||||
void viewDidDisappear();
|
||||
|
||||
@@ -102,19 +107,6 @@ private:
|
||||
Forward = 2
|
||||
};
|
||||
|
||||
class NameColorPair {
|
||||
public:
|
||||
constexpr NameColorPair(const char * name, KDColor color) :
|
||||
m_name(name),
|
||||
m_color(color)
|
||||
{}
|
||||
const char * name() const { return m_name; }
|
||||
KDColor color() const { return m_color; }
|
||||
private:
|
||||
const char * m_name;
|
||||
KDColor m_color;
|
||||
};
|
||||
|
||||
void setHeadingPrivate(mp_float_t angle);
|
||||
KDPoint position(mp_float_t x, mp_float_t y) const;
|
||||
KDPoint position() const { return position(m_x, m_y); }
|
||||
@@ -149,6 +141,7 @@ private:
|
||||
mp_float_t m_heading;
|
||||
|
||||
KDColor m_color;
|
||||
MicroPython::ColorParser::ColorModes m_colorMode;
|
||||
bool m_penDown;
|
||||
bool m_visible;
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ extern "C" {
|
||||
#include "mod/matplotlib/pyplot/modpyplot.h"
|
||||
}
|
||||
|
||||
#include <escher/palette.h>
|
||||
|
||||
static MicroPython::ScriptProvider * sScriptProvider = nullptr;
|
||||
static MicroPython::ExecutionEnvironment * sCurrentExecutionEnvironment = nullptr;
|
||||
|
||||
@@ -170,6 +172,83 @@ void MicroPython::collectRootsAtAddress(char * address, int byteLength) {
|
||||
#endif
|
||||
}
|
||||
|
||||
KDColor MicroPython::ColorParser::ParseColor(mp_obj_t input, ColorModes ColorMode){
|
||||
if(MP_OBJ_IS_STR(input)){
|
||||
size_t l;
|
||||
const char * color = mp_obj_str_get_data(input, &l);
|
||||
// TODO add cyan
|
||||
constexpr NameColorPair pairs[] = {
|
||||
NameColorPair("blue", KDColorBlue),
|
||||
NameColorPair("b", KDColorBlue),
|
||||
NameColorPair("red", KDColorRed),
|
||||
NameColorPair("r", KDColorRed),
|
||||
NameColorPair("green", Palette::Green),
|
||||
NameColorPair("g", Palette::Green),
|
||||
NameColorPair("yellow", KDColorYellow),
|
||||
NameColorPair("y", KDColorYellow),
|
||||
NameColorPair("brown", Palette::Brown),
|
||||
NameColorPair("black", KDColorBlack),
|
||||
NameColorPair("k", KDColorBlack),
|
||||
NameColorPair("white", KDColorWhite),
|
||||
NameColorPair("w", KDColorWhite),
|
||||
NameColorPair("pink", Palette::Pink),
|
||||
NameColorPair("orange", Palette::Orange),
|
||||
NameColorPair("purple", Palette::Purple),
|
||||
NameColorPair("grey", Palette::GreyDark)
|
||||
};
|
||||
for (NameColorPair p : pairs) {
|
||||
if (strcmp(p.name(), color) == 0) {
|
||||
return p.color();
|
||||
}
|
||||
}
|
||||
|
||||
if(color[0] == '#'){
|
||||
if(l != 7){
|
||||
mp_raise_ValueError("RGB hex values are 6 bytes long");
|
||||
}
|
||||
uint32_t ColorInt = mp_obj_get_int(mp_obj_new_int_via_str(color+1, 16));
|
||||
return KDColor::RGB24(ColorInt);
|
||||
}
|
||||
|
||||
mp_float_t GreyLevel = mp_obj_float_get(mp_obj_new_float_via_str(color));
|
||||
if(GreyLevel >= 0 && GreyLevel <= 1){
|
||||
return KDColor::RGB888(
|
||||
255 * (float) GreyLevel,
|
||||
255 * (float) GreyLevel,
|
||||
255 * (float) GreyLevel
|
||||
);
|
||||
}
|
||||
mp_raise_ValueError("Grey levels are between 0.0 and 1.0");
|
||||
} else if(mp_obj_is_int(input)) {
|
||||
mp_raise_TypeError("Int are not colors");
|
||||
//See https://github.com/numworks/epsilon/issues/1533#issuecomment-618443492
|
||||
} else {
|
||||
size_t len;
|
||||
mp_obj_t * elem;
|
||||
|
||||
mp_obj_get_array(input, &len, &elem);
|
||||
|
||||
if (len != 3) {
|
||||
mp_raise_TypeError("color needs 3 components");
|
||||
}
|
||||
|
||||
if(ColorMode == MicroPython::ColorParser::ColorModes::MaxIntensity1){
|
||||
return KDColor::RGB888(
|
||||
mp_obj_get_float(elem[0]),
|
||||
mp_obj_get_float(elem[1]),
|
||||
mp_obj_get_float(elem[2])
|
||||
);
|
||||
} else {
|
||||
return KDColor::RGB888(
|
||||
mp_obj_get_int(elem[0]),
|
||||
mp_obj_get_int(elem[1]),
|
||||
mp_obj_get_int(elem[2])
|
||||
);
|
||||
}
|
||||
}
|
||||
mp_raise_TypeError("Color couldn't be parsed");
|
||||
}
|
||||
|
||||
void gc_collect(void) {
|
||||
void * python_stack_top = MP_STATE_THREAD(stack_top);
|
||||
assert(python_stack_top != NULL);
|
||||
@@ -260,3 +339,4 @@ const char * mp_hal_input(const char * prompt) {
|
||||
assert(sCurrentExecutionEnvironment != nullptr);
|
||||
return sCurrentExecutionEnvironment->inputText(prompt);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
|
||||
extern "C" {
|
||||
#include <stddef.h>
|
||||
#include <py/obj.h>
|
||||
}
|
||||
#include <escher/view_controller.h>
|
||||
|
||||
|
||||
namespace MicroPython {
|
||||
|
||||
class ScriptProvider {
|
||||
@@ -39,6 +41,31 @@ void deinit();
|
||||
void registerScriptProvider(ScriptProvider * s);
|
||||
void collectRootsAtAddress(char * address, int len);
|
||||
|
||||
class ColorParser {
|
||||
private:
|
||||
class NameColorPair {
|
||||
public:
|
||||
constexpr NameColorPair(const char * name, KDColor color) :
|
||||
m_name(name),
|
||||
m_color(color)
|
||||
{}
|
||||
const char * name() const { return m_name; }
|
||||
KDColor color() const { return m_color; }
|
||||
private:
|
||||
const char * m_name;
|
||||
KDColor m_color;
|
||||
};
|
||||
|
||||
public:
|
||||
enum class ColorModes {
|
||||
MaxIntensity1,
|
||||
MaxIntensity255,
|
||||
};
|
||||
|
||||
static KDColor ParseColor(mp_obj_t input, ColorModes ColorMode = ColorModes::MaxIntensity255);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -90,6 +90,7 @@ static inline bool mp_obj_is_qstr(mp_const_obj_t o)
|
||||
{ return ((((mp_int_t)(o)) & 3) == 2); }
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2)
|
||||
#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2))
|
||||
mp_obj_t mp_obj_new_int_via_str(const char* value, int base);
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj)
|
||||
@@ -100,6 +101,7 @@ extern const struct _mp_obj_float_t mp_const_float_pi_obj;
|
||||
#define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float)
|
||||
mp_float_t mp_obj_float_get(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_new_float(mp_float_t value);
|
||||
mp_obj_t mp_obj_new_float_via_str(const char* value);
|
||||
#endif
|
||||
|
||||
static inline bool mp_obj_is_obj(mp_const_obj_t o)
|
||||
|
||||
@@ -201,6 +201,24 @@ mp_obj_t mp_obj_new_float(mp_float_t value) {
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_float_via_str(const char* value) {
|
||||
mp_obj_float_t *o = m_new(mp_obj_float_t, 1);
|
||||
o->base.type = &mp_type_float;
|
||||
//Avoid \x0
|
||||
int length = 0;
|
||||
for(int i = 0; i <= sizeof(value); i++){
|
||||
if(value[i] == '\x0'){
|
||||
length = i;
|
||||
break;
|
||||
}
|
||||
};
|
||||
if(length == 0){
|
||||
length = (int) sizeof(value);
|
||||
}
|
||||
o->value = mp_obj_float_get(mp_parse_num_decimal(value, length, false, false, NULL));
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
mp_float_t mp_obj_float_get(mp_obj_t self_in) {
|
||||
assert(mp_obj_is_float(self_in));
|
||||
mp_obj_float_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
@@ -462,3 +462,17 @@ const mp_obj_type_t mp_type_int = {
|
||||
.binary_op = mp_obj_int_binary_op,
|
||||
.locals_dict = (mp_obj_dict_t*)&int_locals_dict,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_int_via_str(const char* value, int base) {
|
||||
int length = 0;
|
||||
for(int i = 0; i <= sizeof(value); i++){
|
||||
if(value[i] == '\x0'){
|
||||
length = i;
|
||||
break;
|
||||
}
|
||||
};
|
||||
if(length == 0){
|
||||
length = (int) sizeof(value);
|
||||
}
|
||||
return mp_parse_num_integer(value, length, base, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user