Some cleanup for interactive mobjects

This commit is contained in:
Grant Sanderson 2021-01-28 12:26:05 -08:00
parent baab9ddf02
commit 5a2a363a87
4 changed files with 37 additions and 32 deletions

View file

@ -414,7 +414,7 @@ class ControlsExample(Scene):
def text_updater(old_text): def text_updater(old_text):
assert(isinstance(old_text, Text)) assert(isinstance(old_text, Text))
new_text = Text(self.textbox.get_value(), size=old_text.size) new_text = Text(self.textbox.get_value(), size=old_text.size)
new_text.align_data_and_family(old_text) # new_text.align_data_and_family(old_text)
new_text.move_to(old_text) new_text.move_to(old_text)
if self.checkbox.get_value(): if self.checkbox.get_value():
new_text.set_fill( new_text.set_fill(
@ -424,14 +424,13 @@ class ControlsExample(Scene):
else: else:
new_text.set_opacity(0) new_text.set_opacity(0)
old_text.become(new_text) old_text.become(new_text)
text.add_updater(text_updater) text.add_updater(text_updater)
self.add(MotionMobject(text)) self.add(MotionMobject(text))
self.textbox.set_value("Manim") self.textbox.set_value("Manim")
self.wait(60) # self.embed()
self.embed()
# See https://github.com/3b1b/videos for many, many more # See https://github.com/3b1b/videos for many, many more

View file

@ -353,7 +353,11 @@ class Camera(object):
if shader_wrapper.vert_indices is None: if shader_wrapper.vert_indices is None:
ibo = None ibo = None
else: else:
ibo = self.ctx.buffer(shader_wrapper.vert_indices.astype('i4').tobytes()) vert_index_data = shader_wrapper.vert_indices.astype('i4').tobytes()
if vert_index_data:
ibo = self.ctx.buffer(vert_index_data)
else:
ibo = None
# Program and vertex array # Program and vertex array
shader_program, vert_format = self.get_shader_program(shader_wrapper) shader_program, vert_format = self.get_shader_program(shader_wrapper)

View file

@ -29,7 +29,8 @@ class MotionMobject(Mobject):
def __init__(self, mobject, **kwargs): def __init__(self, mobject, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.mobject = mobject self.mobject = mobject
self.mobject.add_updater(lambda mob: None) # To avoid locking it as static mobject # To avoid locking it as static mobject
self.mobject.add_updater(lambda mob: None)
self.add(mobject) self.add(mobject)
def on_mouse_drag(self, point, d_point, buttons, modifiers): def on_mouse_drag(self, point, d_point, buttons, modifiers):
@ -40,7 +41,7 @@ class MotionMobject(Mobject):
class Button(Mobject): class Button(Mobject):
""" """
Pass any mobject and register an on_click method Pass any mobject and register an on_click method
""" """
CONFIG = { CONFIG = {
@ -69,7 +70,8 @@ class ContolMobject(ValueTracker):
super().__init__(value=value, **kwargs) super().__init__(value=value, **kwargs)
self.add(*mobjects) self.add(*mobjects)
self.add_updater(lambda mob: None) # To avoid lock_static_mobject_data while waiting in scene # To avoid lock_static_mobject_data while waiting in scene
self.add_updater(lambda mob: None)
self.fix_in_frame() self.fix_in_frame()
def set_value(self, value): def set_value(self, value):
@ -85,6 +87,7 @@ class ContolMobject(ValueTracker):
# To be implemented in subclasses # To be implemented in subclasses
pass pass
class EnableDisableButton(ContolMobject): class EnableDisableButton(ContolMobject):
CONFIG = { CONFIG = {
"value_type": np.dtype(bool), "value_type": np.dtype(bool),
@ -103,12 +106,12 @@ class EnableDisableButton(ContolMobject):
super().__init__(value, self.box, **kwargs) super().__init__(value, self.box, **kwargs)
def assert_value(self, value): def assert_value(self, value):
assert(value == True or value == False) assert(isinstance(value, bool))
def set_value_anim(self, value): def set_value_anim(self, value):
if value == True: if value:
self.box.set_fill(self.enable_color) self.box.set_fill(self.enable_color)
elif value == False: else:
self.box.set_fill(self.disable_color) self.box.set_fill(self.disable_color)
def toggle_value(self): def toggle_value(self):
@ -146,15 +149,15 @@ class Checkbox(ContolMobject):
super().__init__(value, self.box, self.box_content, **kwargs) super().__init__(value, self.box, self.box_content, **kwargs)
def assert_value(self, value): def assert_value(self, value):
assert(value == True or value == False) assert(isinstance(value, bool))
def toggle_value(self): def toggle_value(self):
super().set_value(not self.get_value()) super().set_value(not self.get_value())
def set_value_anim(self, value): def set_value_anim(self, value):
if value == True: if value:
self.box_content.become(self.get_checkmark()) self.box_content.become(self.get_checkmark())
elif value == False: else:
self.box_content.become(self.get_cross()) self.box_content.become(self.get_cross())
def on_mouse_press(self, point, button, mods): def on_mouse_press(self, point, button, mods):
@ -191,7 +194,6 @@ class Checkbox(ContolMobject):
class LinearNumberSlider(ContolMobject): class LinearNumberSlider(ContolMobject):
CONFIG = { CONFIG = {
"value_type": np.float64, "value_type": np.float64,
"min_value": -10.0, "min_value": -10.0,
"max_value": 10.0, "max_value": 10.0,
"step": 1.0, "step": 1.0,
@ -245,6 +247,7 @@ class LinearNumberSlider(ContolMobject):
value_nearest_to_step = self.min_value + no_of_steps * self.step value_nearest_to_step = self.min_value + no_of_steps * self.step
return value_nearest_to_step return value_nearest_to_step
class ColorSliders(Group): class ColorSliders(Group):
CONFIG = { CONFIG = {
"sliders_kwargs": {}, "sliders_kwargs": {},
@ -265,7 +268,7 @@ class ColorSliders(Group):
def __init__(self, **kwargs): def __init__(self, **kwargs):
digest_config(self, kwargs) digest_config(self, kwargs)
rgb_kwargs = {"value": self.default_rgb_value,"min_value": 0, "max_value": 255, "step": 1} 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} 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.r_slider = LinearNumberSlider(**self.sliders_kwargs, **rgb_kwargs)
@ -377,12 +380,16 @@ class Textbox(ContolMobject):
self.update_text(value) self.update_text(value)
def update_text(self, value): def update_text(self, value):
self.remove(self.text) text = self.text
self.text.__init__(value, **self.text_kwargs) self.remove(text)
self.text.set_width(self.box.get_width() - 2*self.text_buff, stretch=True) text.__init__(value, **self.text_kwargs)
self.text.add_updater(lambda mob: mob.move_to(self.box)) height = text.get_height()
self.text.fix_in_frame() text.set_width(self.box.get_width() - 2 * self.text_buff)
self.add(self.text) if text.get_height() > height:
text.set_height(height)
text.add_updater(lambda mob: mob.move_to(self.box))
text.fix_in_frame()
self.add(text)
def active_anim(self, isActive): def active_anim(self, isActive):
if isActive: if isActive:
@ -411,14 +418,14 @@ class Textbox(ContolMobject):
elif symbol == PygletWindowKeys.TAB: elif symbol == PygletWindowKeys.TAB:
new_value = old_value + '\t' new_value = old_value + '\t'
elif symbol == PygletWindowKeys.BACKSPACE: elif symbol == PygletWindowKeys.BACKSPACE:
new_value = old_value[:-1] or '' new_value = old_value[:-1] or ''
self.set_value(new_value) self.set_value(new_value)
return False return False
class ControlPanel(Group): class ControlPanel(Group):
CONFIG = { CONFIG = {
"listen_to_events": True, "listen_to_events": True,
"panel_kwargs": { "panel_kwargs": {
"width": FRAME_WIDTH / 4, "width": FRAME_WIDTH / 4,
"height": MED_SMALL_BUFF + FRAME_HEIGHT, "height": MED_SMALL_BUFF + FRAME_HEIGHT,
@ -478,7 +485,7 @@ class ControlPanel(Group):
direction=UP, direction=UP,
buff=MED_SMALL_BUFF buff=MED_SMALL_BUFF
) )
self.controls.set_x(controls_old_x) self.controls.set_x(controls_old_x)
def add_controls(self, *new_controls): def add_controls(self, *new_controls):
@ -502,7 +509,7 @@ class ControlPanel(Group):
self.panel_opener.set_x(panel_opener_x) self.panel_opener.set_x(panel_opener_x)
self.move_panel_and_controls_to_panel_opener() self.move_panel_and_controls_to_panel_opener()
return self return self
def on_mouse_drag(self, point, d_point, buttons, modifiers): def on_mouse_drag(self, point, d_point, buttons, modifiers):
if self.panel_opener.is_point_touching(point): if self.panel_opener.is_point_touching(point):
self.panel_opener.match_y(Dot(point)) self.panel_opener.match_y(Dot(point))
@ -514,4 +521,3 @@ class ControlPanel(Group):
factor = 10 * offset[1] factor = 10 * offset[1]
self.controls.set_y(self.controls.get_y() + factor) self.controls.set_y(self.controls.get_y() + factor)
return False return False

View file

@ -218,12 +218,8 @@ class Mobject(object):
return self return self
def is_point_touching(self, point, buff=MED_SMALL_BUFF): def is_point_touching(self, point, buff=MED_SMALL_BUFF):
self.refresh_bounding_box()
bb = self.get_bounding_box() bb = self.get_bounding_box()
if np.all(point >= (bb[0] - buff)) and np.all(point <= (bb[2] + buff)): return np.all(point >= (bb[0] - buff)) and np.all(point <= (bb[2] + buff))
return True
else:
return False
# Family matters # Family matters