Skip to content

Commit 2a45f4e

Browse files
committed
pybricks.parameters.Color: Make color instances iterable.
Fixes pybricks/support#1661
1 parent ed3632f commit 2a45f4e

File tree

6 files changed

+93
-22
lines changed

6 files changed

+93
-22
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
## [Unreleased]
66

7+
### Added
8+
9+
- Allow color objects to be iterated as h, s, v = color_object or indexed
10+
as color_object[0]. This allows access to these properties in block
11+
coding ([support#1661]).
12+
713
### Changed
814

915
- Relaxed speed limit from 1000 deg/s to 1200 deg/s for external Boost
@@ -18,6 +24,7 @@
1824
loops ([support#1668]).
1925

2026
[support#1623]: https://github.com/pybricks/support/issues/1623
27+
[support#1661]: https://github.com/pybricks/support/issues/1661
2128
[support#1668]: https://github.com/pybricks/support/issues/1668
2229
[support#1846]: https://github.com/pybricks/support/issues/1846
2330
[support#1858]: https://github.com/pybricks/support/issues/1858

pybricks/parameters/pb_type_color.c

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,30 +163,71 @@ void pb_type_Color_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin
163163
mp_printf(print, "Color(h=%u, s=%u, v=%d)", self->hsv.h, self->hsv.s, self->hsv.v);
164164
}
165165

166+
static mp_obj_t pb_type_Color_subscr_index(pb_type_Color_obj_t *self, size_t index) {
167+
switch (index) {
168+
case 0:
169+
return MP_OBJ_NEW_SMALL_INT(self->hsv.h);
170+
case 1:
171+
return MP_OBJ_NEW_SMALL_INT(self->hsv.s);
172+
case 2:
173+
return MP_OBJ_NEW_SMALL_INT(self->hsv.v);
174+
default:
175+
mp_raise_type(&mp_type_IndexError);
176+
}
177+
}
178+
166179
static mp_obj_t pb_type_Color_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
167180

168-
// If we're a Color instance, there is no subscr
181+
// For Color instance, use 0, 1, 2 to index h, s, v.
169182
if (MP_OBJ_TO_PTR(self_in) != &pb_type_Color_obj) {
170-
return MP_OBJ_NULL;
183+
return pb_type_Color_subscr_index(MP_OBJ_TO_PTR(self_in), mp_obj_get_int(index));
171184
}
172185

173-
// If user wants to store, ensure they store color
186+
// Otherwise this is the main Color type. Treat it like a dictionary.
187+
// If user wants to store, ensure they store color.
174188
if (value != MP_OBJ_SENTINEL && value != MP_OBJ_NULL) {
175189
pb_assert_type(value, &pb_type_Color);
176190
}
177-
178-
// Treat it like a dictionary
179191
return MP_OBJ_TYPE_GET_SLOT(&mp_type_dict, subscr)(MP_OBJ_FROM_PTR(MP_STATE_VM(pb_type_Color_dict)), index, value);
180192
}
181193

194+
typedef struct {
195+
mp_obj_base_t base;
196+
mp_fun_1_t iternext;
197+
mp_obj_t color;
198+
size_t cur;
199+
} pb_type_Color_it_t;
200+
201+
_Static_assert(sizeof(pb_type_Color_it_t) <= sizeof(mp_obj_iter_buf_t),
202+
"pb_type_Color_it_t uses memory allocated for mp_obj_iter_buf_t");
203+
204+
static mp_obj_t pb_type_Color_it_iternext(mp_obj_t self_in) {
205+
pb_type_Color_it_t *self = MP_OBJ_TO_PTR(self_in);
206+
pb_type_Color_obj_t *color = MP_OBJ_TO_PTR(self->color);
207+
if (self->cur <= 2) {
208+
return pb_type_Color_subscr_index(color, self->cur++);
209+
}
210+
return MP_OBJ_STOP_ITERATION;
211+
}
212+
213+
static mp_obj_t pb_type_Color_instance_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
214+
pb_type_Color_obj_t *color = MP_OBJ_TO_PTR(o_in);
215+
pb_type_Color_it_t *color_it = (pb_type_Color_it_t *)iter_buf;
216+
color_it->base.type = &mp_type_polymorph_iter;
217+
color_it->color = MP_OBJ_FROM_PTR(color);
218+
color_it->iternext = pb_type_Color_it_iternext;
219+
color_it->cur = 0;
220+
return MP_OBJ_FROM_PTR(color_it);
221+
}
222+
182223
static mp_obj_t pb_type_Color_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
183224

184-
// If we're a Color instance, there is no getiter
225+
// Iterate color instance as h, s, v.
185226
if (MP_OBJ_TO_PTR(self_in) != &pb_type_Color_obj) {
186-
return MP_OBJ_NULL;
227+
return pb_type_Color_instance_getiter(self_in, iter_buf);
187228
}
188229

189-
// Treat it like a dictionary
230+
// Treat the Color type like a dictionary.
190231
return ((mp_getiter_fun_t)MP_OBJ_TYPE_GET_SLOT(&mp_type_dict, iter))(MP_OBJ_FROM_PTR(MP_STATE_VM(pb_type_Color_dict)), iter_buf);
191232
}
192233

tests/ev3dev/parameters/color.py

Lines changed: 0 additions & 11 deletions
This file was deleted.

tests/ev3dev/parameters/color.py.exp

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/virtualhub/color/basic.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from pybricks.parameters import Color
2+
3+
# "enums" should be able to be used as hash values
4+
map = {
5+
Color.RED: "red",
6+
Color.GREEN: "green",
7+
Color.BLUE: "blue",
8+
}
9+
print(map[Color.RED])
10+
print(map[Color.GREEN])
11+
print(map[Color.BLUE])
12+
13+
# Iteration and subscription
14+
print(*Color.BLUE)
15+
h, s, v = Color.BLUE
16+
print(h, s, v)
17+
h = Color.BLUE[0]
18+
s = Color.BLUE[1]
19+
v = Color.BLUE[2]
20+
print(h, s, v)
21+
22+
# Shifting.
23+
print(Color.RED >> 120 == Color.GREEN)
24+
print(Color.RED >> 720 == Color.RED)
25+
26+
# Scaling
27+
light_red = Color(0, 100, 50)
28+
print(Color.RED * 0.5 == light_red)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
red
2+
green
3+
blue
4+
240 100 100
5+
240 100 100
6+
240 100 100
7+
True
8+
True
9+
True

0 commit comments

Comments
 (0)