def __init__(self, path, partitions=10, **kwargs): VMobject.__init__(self, **kwargs) rect = Rectangle(width=path.get_width() + self.margin, height=path.get_height() + self.margin) rect.move_to(path) w = rect.get_width() h = rect.get_height() alpha = w / h hp = int(np.ceil(partitions / (2 * (alpha + 1)))) wp = int(np.ceil(alpha * hp)) sides = VGroup(*[ Line(rect.get_corner(c1), rect.get_corner(c2)) for c1, c2 in zip([UL, UR, DR, DL], [UR, DR, DL, UL]) ]) total_points = [] for side, points in zip(sides, [wp, hp, wp, hp]): for p in range(points): total_points.append(side.point_from_proportion(p / points)) total_points.append(total_points[0]) middle = int(np.floor(len(total_points) / 2)) draw_points = [] for p in range(2, middle): draw_points.append(total_points[-p * self.sign]) draw_points.append(total_points[p * self.sign]) self.set_points_smoothly(draw_points)
def __init__(self, mobject, midle_color=None, **kwargs): digest_config(self, kwargs) self.mobject = mobject self.rectangle_kwargs["color"] = self.color if midle_color == None: midle_color = self.rectangle_kwargs["color"] rectangle = Rectangle(height=mobject.get_height() + self.margin, width=mobject.get_width() + self.margin, **self.rectangle_kwargs) rectangle.move_to(mobject) rectangle.init_state = rectangle.copy() rectangle_width = rectangle.get_width() def return_updater(mob, alpha): dx = interpolate(-PI / 2, PI / 2, alpha) mob.become(mob.init_state) mob.set_width(rectangle_width * np.cos(dx), stretch=True) # dx should not be zero sign = -abs(dx) / (dx + 0.00000000001) direction = LEFT * sign reference_line = Line( rectangle.init_state.get_corner(UP + direction), rectangle.init_state.get_corner(DOWN + direction)) mob.next_to(reference_line, -direction, buff=0) opacity = self.init_opacity + (self.max_opacity - self.init_opacity) * np.cos(dx) mob.set_style(fill_opacity=opacity) mob.set_color( interpolate_color(self.rectangle_kwargs["color"], midle_color, np.cos(dx))) super().__init__(rectangle, return_updater)
def get_face_card_design(self, value, symbol): from for_3b1b_videos.pi_creature import PiCreature sub_rect = Rectangle( stroke_color=BLACK, fill_opacity=0, height=0.9 * self.get_height(), width=0.6 * self.get_width(), ) sub_rect.move_to(self) # pi_color = average_color(symbol.get_color(), GREY) pi_color = symbol.get_color() pi_mode = { "J": "plain", "Q": "thinking", "K": "hooray" }[value] pi_creature = PiCreature( mode=pi_mode, color=pi_color, ) pi_creature.set_width(0.8 * sub_rect.get_width()) if value in ["Q", "K"]: prefix = "king" if value == "K" else "queen" crown = SVGMobject(file_name=prefix + "_crown") crown.set_stroke(width=0) crown.set_fill(YELLOW, 1) crown.stretch_to_fit_width(0.5 * sub_rect.get_width()) crown.stretch_to_fit_height(0.17 * sub_rect.get_height()) crown.move_to(pi_creature.eyes.get_center(), DOWN) pi_creature.add_to_back(crown) to_top_buff = 0 else: to_top_buff = SMALL_BUFF * sub_rect.get_height() pi_creature.next_to(sub_rect.get_top(), DOWN, to_top_buff) # pi_creature.shift(0.05*sub_rect.get_width()*RIGHT) pi_copy = pi_creature.copy() pi_copy.rotate(np.pi, about_point=sub_rect.get_center()) return VGroup(sub_rect, pi_creature, pi_copy)
def get_face_card_design(self, value, symbol): from for_3b1b_videos.pi_creature import PiCreature sub_rect = Rectangle( stroke_color=BLACK, fill_opacity=0, height=0.9 * self.get_height(), width=0.6 * self.get_width(), ) sub_rect.move_to(self) # pi_color = average_color(symbol.get_color(), GREY) pi_color = symbol.get_color() pi_mode = { "J": "plain", "Q": "thinking", "K": "hooray" }[value] pi_creature = PiCreature( mode=pi_mode, color=pi_color, ) pi_creature.set_width(0.8 * sub_rect.get_width()) if value in ["Q", "K"]: prefix = "king" if value == "K" else "queen" crown = SVGMobject(file_name=prefix + "_crown") crown.set_stroke(width=0) crown.set_fill(YELLOW, 1) crown.stretch_to_fit_width(0.5 * sub_rect.get_width()) crown.stretch_to_fit_height(0.17 * sub_rect.get_height()) crown.move_to(pi_creature.eyes.get_center(), DOWN) pi_creature.add_to_back(crown) to_top_buff = 0 else: to_top_buff = SMALL_BUFF * sub_rect.get_height() pi_creature.next_to(sub_rect.get_top(), DOWN, to_top_buff) # pi_creature.shift(0.05*sub_rect.get_width()*RIGHT) pi_copy = pi_creature.copy() pi_copy.rotate(np.pi, about_point=sub_rect.get_center()) return VGroup(sub_rect, pi_creature, pi_copy)
def __init__(self, texmob, **kwargs): VMobject.__init__(self, **kwargs) rect = Rectangle(width=texmob.get_width() + self.margin, height=texmob.get_height() + self.margin) rect.move_to(texmob) w = rect.get_width() h = rect.get_height() alpha = w / h hp = np.ceil(self.partitions / (2 * (alpha + 1))) wp = np.ceil(alpha * hp) sides = VGroup(*[ Line(rect.get_corner(c1), rect.get_corner(c2)) for c1, c2 in zip([UL, UR, DR, DL], [UR, DR, DL, UL]) ]) total_points = [] for side, p in zip(sides, [wp, hp, wp, hp]): path = FreehandDraw(side, p).points for point in path: total_points.append(point) total_points.append(total_points[0]) self.set_points_smoothly(total_points)
class Textbox(ControlMobject): CONFIG = { "value_type": np.dtype(object), "box_kwargs": { "width": 2.0, "height": 1.0, "fill_color": WHITE, "fill_opacity": 1.0, }, "text_kwargs": { "color": BLUE }, "text_buff": MED_SMALL_BUFF, "isInitiallyActive": False, "active_color": BLUE, "deactive_color": RED, } def __init__(self, value="", **kwargs): digest_config(self, kwargs) self.isActive = self.isInitiallyActive self.box = Rectangle(**self.box_kwargs) self.box.add_mouse_press_listner(self.box_on_mouse_press) self.text = Text(value, **self.text_kwargs) super().__init__(value, self.box, self.text, **kwargs) self.update_text(value) self.active_anim(self.isActive) self.add_key_press_listner(self.on_key_press) def set_value_anim(self, value): self.update_text(value) def update_text(self, value): text = self.text self.remove(text) text.__init__(value, **self.text_kwargs) height = text.get_height() text.set_width(self.box.get_width() - 2 * self.text_buff) 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): if isActive: self.box.set_stroke(self.active_color) else: self.box.set_stroke(self.deactive_color) def box_on_mouse_press(self, mob, event_data): self.isActive = not self.isActive self.active_anim(self.isActive) return False def on_key_press(self, mob, event_data): symbol = event_data["symbol"] modifiers = event_data["modifiers"] char = chr(symbol) if mob.isActive: old_value = mob.get_value() new_value = old_value if char.isalnum(): if (modifiers & PygletWindowKeys.MOD_SHIFT) or ( modifiers & PygletWindowKeys.MOD_CAPSLOCK): new_value = old_value + char.upper() else: new_value = old_value + char.lower() elif symbol in [PygletWindowKeys.SPACE]: new_value = old_value + char elif symbol == PygletWindowKeys.TAB: new_value = old_value + '\t' elif symbol == PygletWindowKeys.BACKSPACE: new_value = old_value[:-1] or '' mob.set_value(new_value) return False
class Checkbox(ControlMobject): CONFIG = { "value_type": np.dtype(bool), "rect_kwargs": { "width": 0.5, "height": 0.5, "fill_opacity": 0.0 }, "checkmark_kwargs": { "stroke_color": GREEN, "stroke_width": 6, }, "cross_kwargs": { "stroke_color": RED, "stroke_width": 6, }, "box_content_buff": SMALL_BUFF } def __init__(self, value=True, **kwargs): digest_config(self, kwargs) self.box = Rectangle(**self.rect_kwargs) self.box_content = self.get_checkmark() if value else self.get_cross() super().__init__(value, self.box, self.box_content, **kwargs) self.add_mouse_press_listner(self.on_mouse_press) def assert_value(self, value): assert (isinstance(value, bool)) def toggle_value(self): super().set_value(not self.get_value()) def set_value_anim(self, value): if value: self.box_content.become(self.get_checkmark()) else: self.box_content.become(self.get_cross()) def on_mouse_press(self, mob, event_data): mob.toggle_value() return False # Helper methods def get_checkmark(self): checkmark = VGroup( Line(UP / 2 + 2 * LEFT, DOWN + LEFT, **self.checkmark_kwargs), Line(DOWN + LEFT, UP + RIGHT, **self.checkmark_kwargs)) checkmark.stretch_to_fit_width(self.box.get_width()) checkmark.stretch_to_fit_height(self.box.get_height()) checkmark.scale(0.5) checkmark.move_to(self.box) return checkmark def get_cross(self): cross = VGroup(Line(UP + LEFT, DOWN + RIGHT, **self.cross_kwargs), Line(UP + RIGHT, DOWN + LEFT, **self.cross_kwargs)) cross.stretch_to_fit_width(self.box.get_width()) cross.stretch_to_fit_height(self.box.get_height()) cross.scale(0.5) cross.move_to(self.box) return cross