class ControlPanel(Group): CONFIG = { "panel_kwargs": { "width": FRAME_WIDTH / 4, "height": MED_SMALL_BUFF + FRAME_HEIGHT, "fill_color": GREY_C, "fill_opacity": 1.0, "stroke_width": 0.0 }, "opener_kwargs": { "width": FRAME_WIDTH / 8, "height": 0.5, "fill_color": GREY_C, "fill_opacity": 1.0 }, "opener_text_kwargs": { "text": "Control Panel", "font_size": 20 } } def __init__(self, *controls, **kwargs): digest_config(self, kwargs) self.panel = Rectangle(**self.panel_kwargs) self.panel.to_corner(UP + LEFT, buff=0) self.panel.shift(self.panel.get_height() * UP) self.panel.add_mouse_scroll_listner(self.panel_on_mouse_scroll) self.panel_opener_rect = Rectangle(**self.opener_kwargs) self.panel_info_text = Text(**self.opener_text_kwargs) self.panel_info_text.move_to(self.panel_opener_rect) self.panel_opener = Group(self.panel_opener_rect, self.panel_info_text) self.panel_opener.next_to(self.panel, DOWN, aligned_edge=DOWN) self.panel_opener.add_mouse_drag_listner( self.panel_opener_on_mouse_drag) self.controls = Group(*controls) self.controls.arrange(DOWN, center=False, aligned_edge=ORIGIN) self.controls.move_to(self.panel) super().__init__(self.panel, self.panel_opener, self.controls, **kwargs) self.move_panel_and_controls_to_panel_opener() self.fix_in_frame() def move_panel_and_controls_to_panel_opener(self): self.panel.next_to(self.panel_opener_rect, direction=UP, buff=0) controls_old_x = self.controls.get_x() self.controls.next_to(self.panel_opener_rect, direction=UP, buff=MED_SMALL_BUFF) self.controls.set_x(controls_old_x) def add_controls(self, *new_controls): self.controls.add(*new_controls) self.move_panel_and_controls_to_panel_opener() def remove_controls(self, *controls_to_remove): self.controls.remove(*controls_to_remove) self.move_panel_and_controls_to_panel_opener() def open_panel(self): panel_opener_x = self.panel_opener.get_x() self.panel_opener.to_corner(DOWN + LEFT, buff=0.0) self.panel_opener.set_x(panel_opener_x) self.move_panel_and_controls_to_panel_opener() return self def close_panel(self): panel_opener_x = self.panel_opener.get_x() self.panel_opener.to_corner(UP + LEFT, buff=0.0) self.panel_opener.set_x(panel_opener_x) self.move_panel_and_controls_to_panel_opener() return self def panel_opener_on_mouse_drag(self, mob, event_data): point = event_data["point"] self.panel_opener.match_y(Dot(point)) self.move_panel_and_controls_to_panel_opener() return False def panel_on_mouse_scroll(self, mob, event_data): offset = event_data["offset"] factor = 10 * offset[1] self.controls.set_y(self.controls.get_y() + factor) return False
class ColorSliders(Group): CONFIG = { "sliders_kwargs": {}, "rect_kwargs": { "width": 2.0, "height": 0.5, "stroke_opacity": 1.0 }, "background_grid_kwargs": { "colors": [GREY_A, GREY_C], "single_square_len": 0.1 }, "sliders_buff": MED_LARGE_BUFF, "default_rgb_value": 255, "default_a_value": 1, } def __init__(self, **kwargs): digest_config(self, kwargs) rgb_kwargs = { "value": self.default_rgb_value, "min_value": 0, "max_value": 255, "step": 1 } a_kwargs = { "value": self.default_a_value, "min_value": 0, "max_value": 1, "step": 0.04 } self.r_slider = LinearNumberSlider(**self.sliders_kwargs, **rgb_kwargs) self.g_slider = LinearNumberSlider(**self.sliders_kwargs, **rgb_kwargs) self.b_slider = LinearNumberSlider(**self.sliders_kwargs, **rgb_kwargs) self.a_slider = LinearNumberSlider(**self.sliders_kwargs, **a_kwargs) self.sliders = Group(self.r_slider, self.g_slider, self.b_slider, self.a_slider) self.sliders.arrange(DOWN, buff=self.sliders_buff) self.r_slider.slider.set_color(RED) self.g_slider.slider.set_color(GREEN) self.b_slider.slider.set_color(BLUE) self.a_slider.slider.set_color_by_gradient([BLACK, WHITE]) self.selected_color_box = Rectangle(**self.rect_kwargs) self.selected_color_box.add_updater(lambda mob: mob.set_fill( self.get_picked_color(), self.get_picked_opacity())) self.background = self.get_background() super().__init__( Group(self.background, self.selected_color_box).fix_in_frame(), self.sliders, **kwargs) self.arrange(DOWN) def get_background(self): single_square_len = self.background_grid_kwargs["single_square_len"] colors = self.background_grid_kwargs["colors"] width = self.rect_kwargs["width"] height = self.rect_kwargs["height"] rows = int(height / single_square_len) cols = int(width / single_square_len) cols = (cols + 1) if (cols % 2 == 0) else cols single_square = Square(single_square_len) grid = single_square.get_grid(n_rows=rows, n_cols=cols, buff=0.0) grid.stretch_to_fit_width(width) grid.stretch_to_fit_height(height) grid.move_to(self.selected_color_box) for idx, square in enumerate(grid): assert (isinstance(square, Square)) square.set_stroke(width=0.0, opacity=0.0) square.set_fill(colors[idx % len(colors)], 1.0) return grid def set_value(self, r, g, b, a): self.r_slider.set_value(r) self.g_slider.set_value(g) self.b_slider.set_value(b) self.a_slider.set_value(a) def get_value(self): r = self.r_slider.get_value() / 255 g = self.g_slider.get_value() / 255 b = self.b_slider.get_value() / 255 alpha = self.a_slider.get_value() return color_to_rgba(rgb_to_color((r, g, b)), alpha=alpha) def get_picked_color(self): rgba = self.get_value() return rgb_to_hex(rgba[:3]) def get_picked_opacity(self): rgba = self.get_value() return rgba[3]