Example #1
0
    def zoom_out_animation(self, touch_point):
        """Performs un-zoom animation when icon is released.

        :param touch_point: x,y location of the screen.
        :type touch_point: Tuple[x,y]
        :return: None
        """

        if (self._animation_time > 0) and self._zoomed:
            _image, _palette = adafruit_imageload.load(self._icon)
            animation_bitmap = self.__class__.bitmap_buffer
            animation_palette = self.__class__.palette_buffer

            # store the current display refresh setting
            refresh_status = self.__class__.display.auto_refresh

            self.__class__.display.auto_refresh = False  # set auto_refresh off

            # Animation: shrink down to the original size
            start_time = time.monotonic()
            while True:
                elapsed_time = time.monotonic() - start_time
                position = max(
                    0.0, easeout(1 - (elapsed_time / self._animation_time)))
                animation_bitmap.fill(len(animation_palette) - 1)
                bitmaptools.rotozoom(
                    dest_bitmap=animation_bitmap,
                    ox=animation_bitmap.width // 2,
                    oy=animation_bitmap.height // 2,
                    source_bitmap=_image,
                    px=_image.width // 2,
                    py=_image.height // 2,
                    scale=1.0 + position * (self._scale - 1.0),
                    angle=position * self._angle,
                )
                self.__class__.display.refresh()
                if elapsed_time > self._animation_time:
                    break

            # clean up the zoom display elements
            self[0].hidden = False  # unhide the original icon
            self.pop(-1)  # remove zoom tilegrid from the group
            self.__class__.display.refresh()

            # set display.auto_refresh back to original value
            self.__class__.display.auto_refresh = refresh_status

            del _image
            del _palette
            gc.collect()

        self._zoomed = False
Example #2
0
def draw_labels(
    target_bitmap,
    *,
    font,
    font_height,
    tick_labels,
    dial_center,
    dial_radius,
    start_angle,
    sweep_angle,
    rotate_labels=True,
    tick_label_scale=1.0,
):
    """Helper function for drawing text labels on the dial widget.  Can be used
    to customize the dial face.

    :param displayio.Bitmap target_bitmap: Bitmap where ticks will be drawn into
    :param Font font: the font to be used to draw the tick mark text labels
    :param int font_height: the height of the font, used for text placement
    :param List[str] tick_labels: a list of strings for the tick text labels
    :param (int,int) dial_center: the (x,y) pixel location in the bitmap of
     the dial's center of rotation
    :param int dial_radius: the radius of the dial (not including padding), in pixels
    :param int tick_count: number of ticks to be drawn
    :param int tick_stroke: the pixel width of the line used to draw the tick
    :param float start_angle: starting angle of the dial, in degrees
    :param float sweep_angle: total sweep angle of the dial, in degrees
    :param bool rotate_labels: set to True if you want the label text to be rotated
     to align with the tick marks
    :param float tick_label_scale: scale factor for the tick text labels, default is 1.0
    """

    label_count = len(tick_labels)

    for i, this_label_text in enumerate(tick_labels):

        temp_label = bitmap_label.Label(
            font, text=this_label_text
        )  # make a tick line bitmap for blitting

        this_angle = (2 * math.pi / 360) * (
            start_angle + i * sweep_angle / (label_count - 1)
        )  # in radians

        target_position_x = dial_center[0] + (
            dial_radius + font_height // 2
        ) * math.sin(this_angle)
        target_position_y = dial_center[1] - (
            dial_radius + font_height // 2
        ) * math.cos(this_angle)

        if rotate_labels:
            pass
        else:
            this_angle = 0

        if "rotozoom" in dir(bitmaptools):  # if core function is available
            bitmaptools.rotozoom(
                target_bitmap,
                ox=round(target_position_x),
                oy=round(target_position_y),
                source_bitmap=temp_label.bitmap,
                px=round(temp_label.bitmap.width // 2),
                py=round(temp_label.bitmap.height // 2),
                angle=this_angle,
                scale=tick_label_scale,
            )

        else:
            _blit_rotate_scale(  # translate and rotate the tick into the target_bitmap
                destination=target_bitmap,
                ox=round(target_position_x),
                oy=round(target_position_y),
                source=temp_label.bitmap,
                px=round(temp_label.bitmap.width // 2),
                py=round(temp_label.bitmap.height // 2),
                angle=this_angle,
                scale=tick_label_scale,
            )
Example #3
0
def draw_ticks(
    target_bitmap,
    *,
    dial_center,
    dial_radius,
    tick_count,
    tick_stroke,
    tick_length,
    start_angle,
    sweep_angle,
    tick_color_index=2,
):
    """Helper function for drawing ticks on the dial widget.  Can be used to
    customize the dial face.

    :param displayio.Bitmap target_bitmap: Bitmap where ticks will be drawn into
    :param (int,int) dial_center: the (x,y) pixel location in the bitmap of
     the dial's center of rotation
    :param int dial_radius: the radius of the dial (not including padding), in pixels
    :param int tick_count: number of ticks to be drawn
    :param int tick_stroke: the pixel width of the line used to draw the tick
    :param float start_angle: starting angle of the dial, in degrees
    :param float sweep_angle: total sweep angle of the dial, in degrees
    :param int tick_color_index: the bitmap's color index that should be used for
     drawing the tick marks
    """

    if tick_count <= 1:
        pass
    else:
        tick_bitmap = displayio.Bitmap(
            tick_stroke, tick_length, tick_color_index + 1
        )  # make a tick line bitmap for blitting
        tick_bitmap.fill(
            tick_color_index
        )  # initialize the tick bitmap with the tick_color_index

        for i in range(tick_count):
            this_angle = round(
                (start_angle + ((i * sweep_angle / (tick_count - 1))))
                * (2 * math.pi / 360),
                4,
            )  # in radians
            target_position_x = dial_center[0] + dial_radius * math.sin(this_angle)
            target_position_y = dial_center[1] - dial_radius * math.cos(this_angle)

            if "rotozoom" in dir(bitmaptools):  # if core function is available
                bitmaptools.rotozoom(
                    target_bitmap,
                    ox=round(target_position_x),
                    oy=round(target_position_y),
                    source_bitmap=tick_bitmap,
                    px=round(tick_bitmap.width / 2),
                    py=0,
                    angle=this_angle,  # in radians
                )

            else:
                _blit_rotate_scale(  # translate and rotate the tick into the target_bitmap
                    destination=target_bitmap,
                    ox=target_position_x,
                    oy=target_position_y,
                    source=tick_bitmap,
                    px=int(tick_bitmap.width / 2),
                    py=0,
                    angle=this_angle,  # in radians
                )
Example #4
0
    def zoom_animation(self, touch_point):
        """Performs zoom animation when icon is pressed.

        :param touch_point: x,y location of the screen.
        :type touch_point: Tuple[x,y]
        :return: None
        """

        if self._animation_time > 0:
            try:
                _image, _palette = adafruit_imageload.load(self._icon)

                if len(self.__class__.palette_buffer) < len(_palette) + 1:
                    self._animation_time = 0  # skip any animation
                    print(
                        "Warning: IconAnimated - icon bitmap exceeds IconAnimated.max_color_depth;"
                        " defaulting to no animation")

            except NotImplementedError:
                self._animation_time = 0  # skip any animation
                print(
                    "Warning: IconAnimated - True color BMP unsupported for animation;"
                    " defaulting to no animation")

        if self._animation_time > 0:

            animation_bitmap = self.__class__.bitmap_buffer
            animation_palette = self.__class__.palette_buffer

            # store the current display refresh setting
            refresh_status = self.__class__.display.auto_refresh

            ###
            ## Update the zoom palette and bitmap buffers and append the tilegrid
            ###

            # copy the image palette, add a transparent color at the end
            for i, color in enumerate(_palette):
                animation_palette[i] = color
            animation_palette[len(animation_palette) - 1] = 0x000000
            animation_palette.make_transparent(len(animation_palette) - 1)

            # create the zoom bitmap larger than the original image to allow for zooming
            animation_bitmap.fill(len(animation_palette) -
                                  1)  # transparent fill
            animation_bitmap.blit(
                (animation_bitmap.width - _image.width) // 2,
                (animation_bitmap.height - _image.height) // 2,
                _image,
            )  # blit the image into the center of the zoom_bitmap

            # place zoom_bitmap at same location as image
            animation_tilegrid = TileGrid(animation_bitmap,
                                          pixel_shader=animation_palette)
            animation_tilegrid.x = -(animation_bitmap.width -
                                     _image.width) // 2
            animation_tilegrid.y = -(animation_bitmap.height -
                                     _image.height) // 2

            self.__class__.display.auto_refresh = False  # set auto_refresh off
            self[0].hidden = True  # hide the original icon
            self.append(animation_tilegrid)  # add to the self group.

            # Animation: zoom larger
            start_time = time.monotonic()

            while True:
                elapsed_time = time.monotonic() - start_time
                position = min(
                    1.0, easein(elapsed_time /
                                self._animation_time))  # fractional position
                animation_bitmap.fill(len(animation_palette) - 1)
                bitmaptools.rotozoom(
                    dest_bitmap=animation_bitmap,
                    ox=animation_bitmap.width // 2,
                    oy=animation_bitmap.height // 2,
                    source_bitmap=_image,
                    px=_image.width // 2,
                    py=_image.height // 2,
                    scale=1.0 + position *
                    (self._scale - 1.0),  # start scaling at 1.0
                    angle=position * self._angle,
                )
                self.__class__.display.refresh()
                if elapsed_time > self._animation_time:
                    break

            # set display.auto_refresh back to original value
            self.__class__.display.auto_refresh = refresh_status

            del _image
            del _palette
            gc.collect()

            self._zoomed = True
Example #5
0
percent = 0.0
last_time = time.monotonic()
while True:
    percent = map_range(analog_in.value, (200, 65400), (1, 0))
    theta = percent_to_theta(percent)

    print("dt:",
          time.monotonic() - last_time, "theta:", theta, int(percent * 100))
    last_time = time.monotonic()

    # erasing the entire bitmap is slow (~1fps, because of transparency I think)
    # instead we erase just the region we modified, after refresh below
    # bitmap_scribble.fill(0)

    # offset rotation point (15,105) for bitmap_pointer's axis of rotation
    bitmaptools.rotozoom(bitmap_scribble,
                         bitmap_pointer,
                         angle=theta,
                         px=15,
                         py=105)

    display.refresh()

    # after refresh, now "erase" the rotated pointer by doing a
    # rotozom of a "blank" bitmap with only transparency
    bitmaptools.rotozoom(bitmap_scribble,
                         bitmap_pointer_blank,
                         angle=theta,
                         px=15,
                         py=105)