diff --git a/.pylintrc b/.pylintrc index 0238b90..79bcfb7 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense @@ -9,11 +9,11 @@ # run arbitrary code extension-pkg-whitelist= -# Add files or directories to the blacklist. They should be base names, not +# Add files or directories to the ignore-list. They should be base names, not # paths. ignore=CVS -# Add files or directories matching the regex patterns to the blacklist. The +# Add files or directories matching the regex patterns to the ignore-list. The # regex matches against base names, not paths. ignore-patterns= @@ -55,7 +55,7 @@ confidence= # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" # disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call -disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation +disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation,pointless-string-statement # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/adafruit_displayio_layout/widgets/annotation.py b/adafruit_displayio_layout/widgets/annotation.py deleted file mode 100755 index 4e9b5e4..0000000 --- a/adafruit_displayio_layout/widgets/annotation.py +++ /dev/null @@ -1,192 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Kevin Matocha -# -# SPDX-License-Identifier: MIT -""" - -`annotation` -================================================================================ -A widget for annotating other widgets or freeform positions. - -* Author(s): Kevin Matocha - -Implementation Notes --------------------- - -**Hardware:** - -**Software and Dependencies:** - -* Adafruit CircuitPython firmware for the supported boards: - https://github.com/adafruit/circuitpython/releases - -""" - -# pylint: disable=too-many-arguments, too-many-locals, unused-argument - -from terminalio import FONT -from adafruit_display_text import bitmap_label -from adafruit_display_shapes.line import Line -from adafruit_displayio_layout.widgets.widget import Widget - - -class Annotation(Widget): - """A widget to be used to annotate other widgets with text and lines, but can also - be used freeform by using ``(x,y)`` parameter. - - :param int x: x-direction pixel position for the end of the annotation line for - freeform positioning, ``(x,y)`` will be ignored if a ``widget`` and ``anchor_point`` and/or - ``anchored_position`` are provided. - :param int y: y-direction pixel position for the end of the annotation line for - freeform positioning. - - :param Widget widget: the widget to be annotated, all dimensions are relative to - this widget. The annotation line position will be defined by either - the ``anchor_point`` (in relative dimensions of the size of the widget) - or the ``anchored_position`` (in raw pixel dimensions relative to the origin - of the widget). - - :param str text: text to be displayed in the annotation. - :param Font font: font to be used for the text. - - :param anchor_point: starting point for the annotation line, where ``anchor_point`` is an - (A,B) tuple in relative units of the size of the widget, - for example (0.0, 0.0) is the upper left corner, and (1.0, 1.0) is the lower - right corner of the widget. If ``anchor_point`` is `None`, then ``anchored_position`` - is used to set the annotation line starting point, in widget size relative units - (default is (0.0, 0.0)). - :type anchor_point: Tuple[float, float] - - :param anchored_position: pixel position starting point for the annotation line - where ``anchored_position`` is an (x,y) tuple in pixel units relative to the - upper left corner of the widget, in pixel units (default is None). - :type anchored_position: Tuple[int, int] - - :param position_offset: Used to *nudge* the line position to where you want, this - is an (x,y) pixel offset added to the annotation line starting - point, either set by ``anchor_point`` or ``anchored_position`` (in pixel units). - :type position_offset: Tuple[int, int] - - :param int delta_x: the pixel x-offset for the second end of the line where the text - will reside, in pixel units (default: -15). - :param int delta_y: the pixel y-offset for the second end of the line where the text - will reside, in pixel units (default: -10). - - :param int stroke: the annotation line width (in pixels). [NOT currently implemented] - - :param int line_color: the color of the annotation line (default: 0xFFFFFF). - :param int text_color: the color of the text, if set to `None` color will be - set to ``line_color`` (default: same as ``line_color``). - - :param text_offset: a (x,y) pixel offset to adjust text position relative - to annotation line, in pixel units (default: (0,-1)). - :type text_offset: Tuple[int, int] - - :param Boolean text_under: set `True` for text to be placed below the - annotation line (default: False). - - .. figure:: annotation_example.png - :scale: 125 % - :align: center - :alt: Example of the annotation widget. - - Example of the annotation widget showing two widget - annotations (using ``widget`` and ``anchor_point`` input parameters) and a - freeform annotation (using ``x`` and ``y`` input parameters). - - File location: *examples/displayio_layout_annotation_simpletest.py* - """ - - def __init__( - self, - x=None, - y=None, - text=None, - font=FONT, - delta_x=-15, - delta_y=-10, - widget=None, - anchor_point=(0.0, 0.0), - anchored_position=None, - position_offset=(0, 0), - stroke=3, # Not currently implemented in adafruit_display_shapes/line.py - line_color=0xFFFFFF, - text_color=None, - text_offset=(0, -1), - text_under=False, - ): - - if widget: - if (x is not None) or (y is not None): - print( - "Note: Overriding (x,y) values with widget, anchor_point" - " and/or anchored_position" - ) - widget_width = widget.bounding_box[2] - widget_height = widget.bounding_box[3] - if anchor_point is not None: - line_x0 = ( - widget.x - + round(widget_width * anchor_point[0]) - + position_offset[0] - ) - line_y0 = ( - widget.y - + round(widget_height * anchor_point[1]) - + position_offset[1] - ) - elif anchored_position is not None: - line_x0 = widget.x + anchored_position[0] + position_offset[0] - line_y0 = widget.y + anchored_position[1] + position_offset[1] - else: - raise ValueError("Must supply either anchor_point or anchored_position") - elif (x is not None) and (y is not None): - line_x0 = x - line_y0 = y - else: - raise ValueError( - "Must supply either (x,y) or widget and anchor_point or anchored_position" - ) - - line_x1 = line_x0 + delta_x - line_y1 = line_y0 + delta_y - - text_anchor_point = (0.0, 1.0) # default: set text anchor to left corner - underline_x_multiplier = 1 - - if delta_x < 0: # line is heading to the left, set text anchor to right corner - text_anchor_point = (1.0, 1.0) - underline_x_multiplier = -1 - - if ( - text_under - ): # if text is under the line, set to text_anchor_point to upper edge - text_anchor_point = (text_anchor_point[0], 0.0) - - if text_color is None: - text_color = line_color - - self._label = bitmap_label.Label( - text=text, - font=font, - color=text_color, - anchor_point=text_anchor_point, - anchored_position=(line_x1 + text_offset[0], line_y1 + text_offset[1]), - ) - - label_width = self._label.bounding_box[2] - line_x2 = line_x1 + label_width * underline_x_multiplier + text_offset[0] - # lengthen the line if the text is offset - line_y2 = line_y1 - - self._line0 = Line(line_x0, line_y0, line_x1, line_y1, color=line_color) - self._line1 = Line(line_x1, line_y1, line_x2, line_y2, color=line_color) - - super().__init__() - # Group elements: - # 0. Line0 - from (x,y) to (x+delta_x, y+delta_y) - # 1. Line1 - horizontal line for text - # 2. Label - - self.append(self._line0) - self.append(self._line1) - self.append(self._label) diff --git a/adafruit_displayio_layout/widgets/dial.py b/adafruit_displayio_layout/widgets/dial.py deleted file mode 100755 index c0e3b68..0000000 --- a/adafruit_displayio_layout/widgets/dial.py +++ /dev/null @@ -1,1130 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Kevin Matocha -# -# SPDX-License-Identifier: MIT -""" - -`dial` -================================================================================ -A dial gauge widget for displaying graphical information. - -* Author(s): Kevin Matocha - -Implementation Notes --------------------- - -**Hardware:** - -**Software and Dependencies:** - -* Adafruit CircuitPython firmware for the supported boards: - https://github.com/adafruit/circuitpython/releases - -""" - -# pylint: disable=too-many-lines, too-many-instance-attributes, too-many-arguments -# pylint: disable=too-many-locals, too-many-statements - - -import math -import displayio -import vectorio - -try: - import bitmaptools -except NameError: - pass # utilize the blit_rotate_scale function defined herein - - -from terminalio import FONT as terminalio_FONT -from adafruit_display_text import bitmap_label -from adafruit_displayio_layout.widgets.widget import Widget - - -class Dial(Widget): - """A dial widget. The origin is set using ``x`` and ``y``. - - :param int x: pixel position - :param int y: pixel position - - :param int width: requested width, in pixels - :param int height: requested height, in pixels - :param int padding: keepout padding amount around the border, in pixels, - default is 12 - - :param float sweep_angle: dial rotation, in degrees, maximum value is 360 degrees, - default is 90 degrees - :param float start_angle: starting angle, in degrees. Set to `None` for symmetry along - vertical axis. Vertical is defined as 0 degrees. - Negative values are counter-clockwise degrees; positive values - are clockwise degrees. Defaults to `None`. - - :param float min_value: the minimum value displayed on the dial, default is 0.0 - :param float max_value: the maximum value displayed the dial, default is 100.0 - :param float value: the value to display (if None, defaults to ``min_value``) - - :param Boolean display_value: set `True` to display a value label on the dial - :param Font value_font: the font for the value label, defaults to - ``terminalio.FONT`` - :param int value_color: the color for the value label, defaults to 0xFF0000 - :param str value_format_string: the format string for displaying the value label - (defaults to ':0.0f' to show the value rounded to the nearest whole number) - :param (float,float) value_label_anchor_point: anchor point on the label, default - value is (0.5, -1.0) where the y-value of -1.0 signifies the text baseline - :param (float,float) value_label_anchor_point_on_widget: anchor point on the - widget where the label will be placed, default value is (0.5, 0.5) - - :param int needle_width: requested pixel width of the triangular needle, - default = 7 - :param int needle_color: color value for the needle, defaults to red (0xFF0000) - :param Boolean limit_rotation: Set True to limit needle rotation to between the - ``min_value`` and ``max_value``, set to False for unlimited rotation, default is True - - :param int tick_color: tick line color (24-bit hex value), defaults to 0xFFFFFF - :param int major_ticks: number of major ticks, default = 5 - :param int major_tick_stroke: major tick line stroke width, in pixels, default = 3 - :param int major_tick_length: major tick length, in pixels, default = 10 - :param str major_tick_labels: array of strings for the major tick labels, - default is ("0", "25", "50", "75", "100") - :param float tick_label_scale: the scaling of the tick labels, default = 1.0 - :param Font tick_label_font: font to be used for major tick labels, default - is ``terminalio.FONT`` - :param int tick_label_color: color for the major tick labels, default is 0xFFFFFF - :param Boolean angle_tick_labels: set True to rotate the major tick labels to - match the tick angle, default is True - - :param int minor_ticks: number of minor ticks (per major tick), default = 5 - :param int minor_tick_stroke: minor tick line stroke width, in pixels, default = 1 - :param int minor_tick_length: minor tick length, in pixels, default = 5 - - :param int background_color: background color (RGB tuple - or 24-bit hex value), set `None` for transparent, default is `None` - - - :param (float,float) anchor_point: (X,Y) values from 0.0 to 1.0 to define the dial's - anchor point relative to the dial's bounding box - :param (int,int) anchored_position: (x,y) pixel value for the location - of the `anchor_point` - - - **Simple example of dial and moving needle** - - See file: ``examples/displayio_layout_dial_simpletest.py`` - - .. figure:: dial.gif - :scale: 100 % - :figwidth: 50% - :align: center - :alt: Diagram of the dial widget with needle in motion. - - This is a diagram of a dial widget with the needle moving from its - minimum to maximum positions. - - .. figure:: dial_variables_angles.png - :scale: 50 % - :figwidth: 70% - :align: center - :alt: Diagram showing the definition of ``start_angle`` and ``sweep_angle``, - both are in units of degrees. - - Diagram showing the definition of ``start_angle`` and ``sweep_angle``, - both are in units of degrees. - - .. figure:: dial_variables_min_max_values.png - :scale: 50 % - :figwidth: 70% - :align: center - :alt: Diagram showing the defintion of ``min_value`` and ``max_value``. - - Diagram showing the defintion of ``min_value`` and ``max_value``. - - .. figure:: dial_variables_ticks.png - :scale: 50 % - :figwidth: 70% - :align: center - :alt: Diagram showing the various parameters for setting the dial labels - and major and minor tick marks. - - Diagram showing the various parameters for setting the dial labels - and major and minor tick marks. - - .. figure:: dial_variables_clip_needle.png - :scale: 35 % - :figwidth: 70% - :align: center - :alt: Diagram showing the impact of ``clip_needle`` Boolean value. - - Diagram showing the impact of the ``clip_needle`` input parameter, - with the dial's boundary shown. For ``sweep_angle`` values less than - 180 degrees, the needle can protrude a long way from the dial ticks. By - setting ``clip_needle = True``, the needle graphic will be clipped at the edge - of the dial boundary (see comparison in the graphic above). The left dial is - created with ``clip_needle = False``, meaning that the dial is not clipped. The - right dial is created with ``clip_needle = True`` and the needle is clipped at - the edge of the dial. Use additional ``padding`` to expose more length of - needle, even when clipped. - """ - - # The dial is a subclass of Group->Widget. - - def __init__( - self, - width=100, - height=100, - padding=12, # keepout amount around border, in pixels - sweep_angle=90, # maximum value is 180 degrees - start_angle=None, - clip_needle=False, - # trims off the needle outside of the dial region, used for sweep_angles < 180 - needle_width=7, - # triangle with this base width, best if this is odd - needle_color=0x880000, - limit_rotation=True, - value=None, - value_font=None, - display_value=False, - value_color=0xFF0000, - value_format_string=":0.0f", - min_value=0.0, - max_value=100.0, - anchor_point=None, - anchored_position=None, - tick_color=0xFFFFFF, - major_ticks=5, # if int, the total number of major ticks - major_tick_stroke=3, - major_tick_length=10, - major_tick_labels=("0", "25", "50", "75", "100"), - minor_ticks=5, # if int, the number of minor ticks per major tick - minor_tick_stroke=1, - minor_tick_length=5, - tick_label_font=None, - tick_label_color=0xFFFFFF, - rotate_tick_labels=True, - tick_label_scale=1.0, - background_color=None, - value_label_anchor_point=( - 0.5, - -1.0, - ), # default label position uses (x-center point, y-text baseline) - value_label_anchor_on_widget=(0.5, 0.5), # default label position on widget - **kwargs, - ): - # initialize the Widget superclass (x, y, scale) - super().__init__(**kwargs) - # Group elements for SwitchRoundHorizontal: - # 0. TileGrid holding bitmap with ticks and tick label text - # 1. Value label (optional) - # 2. Needle bitmap - - self._min_value = min_value - self._max_value = max_value - if value is None: # if none, set to the minimum value - self._value = self._min_value - else: - self._value = value - - if value_font is None: - self._value_font = terminalio_FONT - else: - self._value_font = value_font - self._value_color = value_color - self._display_value = display_value - self._value_format_string = value_format_string - - self._anchor_point = anchor_point - self._anchored_position = anchored_position - - # validate sweep_angle and start_angle - if sweep_angle > 360: - raise ValueError("sweep_angle must be <= 360 degrees") - - sweep_angle = max( - 1, sweep_angle - ) # constrain to >= 1 to avoid divide by zero errors - self._sweep_angle = sweep_angle - - if start_angle is None: - start_angle = -sweep_angle / 2 - elif not -360 <= start_angle <= 360: - raise ValueError("start_angle must be between -360 and +360 degrees") - self._start_angle = start_angle - - self._clip_needle = clip_needle - self._needle_width_requested = needle_width - self._needle_color = needle_color - self._limit_rotation = limit_rotation - self._background_color = background_color - - self._major_tick_labels = major_tick_labels - - self._tick_color = tick_color - self._tick_label_color = tick_label_color - if tick_label_font is None: - self._tick_label_font = terminalio_FONT - else: - self._tick_label_font = tick_label_font - self._tick_label_scale = tick_label_scale - self._rotate_tick_labels = rotate_tick_labels - - self._major_ticks = major_ticks - self._major_tick_stroke = major_tick_stroke - self._major_tick_length = major_tick_length - self._minor_ticks = minor_ticks - self._minor_tick_stroke = minor_tick_stroke - self._minor_tick_length = minor_tick_length - - self._label_anchor_point = value_label_anchor_point - self._label_anchor_on_widget = value_label_anchor_on_widget - - self._padding = padding - - # initialize variables before creating the dial - self._dial_center = None - self._dial_radius = None - self._trim_line = None - self._needle_palette = None - self._needle = None - self._needle_vector_shape = None - self._needle_width = None - - self._initialize_dial(width, height) - - def _initialize_dial(self, width, height): - - for _ in range(len(self)): - self.pop() - - # get the tick label font height - self._font_height = self._get_font_height( - font=self._tick_label_font, scale=self._tick_label_scale - ) - - # update the dial dimensions to fit inside the requested width and height - self._adjust_dimensions(width, height) - self._bounding_box = [0, 0, self._width, self._height] - self._update_position() - - # create the dial palette and bitmaps - self.dial_bitmap = displayio.Bitmap( - self._width, self._height, 3 - ) # 3 colors: background, ticks, tick label text - - # paint the dial major and minor ticks and labels - draw_ticks( # major ticks - target_bitmap=self.dial_bitmap, - dial_center=self._dial_center, - dial_radius=self._dial_radius, - tick_count=self._major_ticks, - tick_stroke=self._major_tick_stroke, - tick_length=self._major_tick_length, - start_angle=self._start_angle, - sweep_angle=self._sweep_angle, - tick_color_index=2, - ) - - draw_ticks( # minor ticks - target_bitmap=self.dial_bitmap, - dial_center=self._dial_center, - dial_radius=self._dial_radius, - tick_count=self._minor_ticks * (self._major_ticks - 1) + 1, - tick_stroke=self._minor_tick_stroke, - tick_length=self._minor_tick_length, - start_angle=self._start_angle, - sweep_angle=self._sweep_angle, - tick_color_index=2, - ) - - draw_labels( - target_bitmap=self.dial_bitmap, - font=self._tick_label_font, - tick_labels=self._major_tick_labels, - dial_center=self._dial_center, - dial_radius=self._dial_radius, - start_angle=self._start_angle, - sweep_angle=self._sweep_angle, - rotate_labels=self._rotate_tick_labels, - font_height=self._font_height, - tick_label_scale=self._tick_label_scale, - ) - - # create the dial palette - self.dial_palette = displayio.Palette(4) - if self._background_color is None: - self.dial_palette.make_transparent(0) - self.dial_palette[0] = 0x000000 - else: - self.dial_palette[0] = self._background_color - self.dial_palette[1] = self._tick_label_color - self.dial_palette[2] = self._tick_color - - # create the dial tilegrid and append to the self Widget->Group - self.dial_tilegrid = displayio.TileGrid( - self.dial_bitmap, pixel_shader=self.dial_palette - ) - self.append(self.dial_tilegrid) - - # create the label for the display_value - if self._display_value: - self._value_label = bitmap_label.Label( - self._value_font, - text="", - color=self._value_color, - baseline_alignment=True, - ) - self._value_label.anchor_point = self._label_anchor_point - self._value_label.anchored_position = [ - round(self._width * self._label_anchor_on_widget[0]), - round(self._height * self._label_anchor_on_widget[1]), - ] - self._update_value() - self.append(self._value_label) - - # create the needle - self._create_needle() - self.append(self._needle_vector_shape) - self._update_needle(self._value) - - def _adjust_dimensions(self, width, height): - # get normalized dimensions of the dial based on start_angle and sweep_angle - # in units of diameter - - # if the sweep angle is < 180, then adjust size if needle should clipped: - if (self._sweep_angle < 180) and (self._clip_needle): - [left, top, right, bottom, x_center_calc, y_center_calc] = _getCoords( - [self._start_angle, self._start_angle + self._sweep_angle], - ignore_center=True, - ) - else: - [left, top, right, bottom, x_center_calc, y_center_calc] = _getCoords( - [self._start_angle, self._start_angle + self._sweep_angle] - ) - - # calculate the pixel dimension to fit within width/height (including padding) - if (width - 2 * self._padding < 0) or (height - 2 * self._padding < 0): - raise ValueError("Width, height, or padding size makes zero sized box") - requested_aspect_ratio = (width - 2 * self._padding) / ( - height - 2 * self._padding - ) - box_aspect_ratio = (right - left) / (bottom - top) - - if box_aspect_ratio >= requested_aspect_ratio: - # keep width and adjust the width - self._width = width - self._height = math.ceil((width - 2 * self._padding) / box_aspect_ratio) + ( - 2 * self._padding - ) - radius = round((width - 2 * self._padding) / (2 * (right - left))) - - else: - # keep height and adjust the width - self._height = height - self._width = math.ceil( - ((height - 2 * self._padding) * box_aspect_ratio) - ) + (2 * self._padding) - radius = round((height - 2 * self._padding) / (2 * (bottom - top))) - - center_x = round(x_center_calc * radius * 2) + self._padding - center_y = round(y_center_calc * radius * 2) + self._padding - self._dial_center = (center_x, center_y) - self._dial_radius = radius - - if self._clip_needle: # define the line endpoints that will trim off the needle - trim_x1 = round( - center_x - + math.sin(self._start_angle * 2 * math.pi / 360) - * (self._dial_radius - self._padding) - ) - trim_y1 = round( - center_y - - math.cos(self._start_angle * 2 * math.pi / 360) - * (self._dial_radius - self._padding) - ) - trim_x2 = round( - center_x - + math.sin((self._start_angle + self._sweep_angle) * 2 * math.pi / 360) - * (self._dial_radius - self._padding) - ) - trim_y2 = round( - center_y - - math.cos((self._start_angle + self._sweep_angle) * 2 * math.pi / 360) - * (self._dial_radius - self._padding) - ) - self._trim_line = [(trim_x1, trim_y1), (trim_x2, trim_y2)] - else: - self._trim_line = None - - def _get_font_height(self, font, scale): - if (self._major_tick_labels == []) or (font is None): - font_height = 0 - else: - if hasattr(font, "get_bounding_box"): - font_height = int(scale * font.get_bounding_box()[1]) - elif hasattr(font, "ascent"): - font_height = int(scale * font.ascent + font.ascent) - return font_height - - def _create_needle(self): - # Create the needle - self._needle_palette = displayio.Palette(2) - self._needle_palette.make_transparent(0) - self._needle_palette[1] = self._needle_color - - self._needle = vectorio.Polygon( - points=[(100, 100), (100, 50), (50, 50), (50, 100)] - ) - self._needle_vector_shape = vectorio.VectorShape( - shape=self._needle, - pixel_shader=self._needle_palette, - x=0, - y=0, - ) - - # if clipped, adjust the needle width up according to the clip amount - if ( - (self._sweep_angle < 180) - and (self._clip_needle) - and (self._trim_line is not None) - ): - # calculate the line where the needle is most visible - max_visible_angle = (2 * math.pi / 360) * ( - self._start_angle + self._sweep_angle / 2 - ) - while True: - if max_visible_angle > math.pi: - max_visible_angle -= 2 * math.pi - elif max_visible_angle < -math.pi: - max_visible_angle += 2 * math.pi - else: - break - - temp_x = self._dial_center[0] + self._dial_radius * math.sin( - max_visible_angle - ) - temp_y = self._dial_center[1] - self._dial_radius * math.cos( - max_visible_angle - ) - - temp_line = [self._dial_center, (temp_x, temp_y)] - - x, y = _line_intersection(temp_line, self._trim_line) - - needle_length_showing = math.sqrt((x - temp_x) ** 2 + (y - temp_y) ** 2) - self._needle_width = round( - self._needle_width_requested * self._dial_radius / needle_length_showing - ) - else: - self._needle_width = self._needle_width_requested - - def _update_value(self): - - if self._display_value: - format_string = ("{" + self._value_format_string + "}").format(self._value) - self._value_label.text = format_string - - def _update_position(self): - if self._anchor_point is None or self._anchored_position is None: - pass - else: - self.x = ( - -self._bounding_box[0] - + self._anchored_position[0] - - int(self._anchor_point[0] * self._bounding_box[2]) - ) - self.y = ( - -self._bounding_box[1] - + self._anchored_position[1] - - int(self._anchor_point[1] * self._bounding_box[3]) - ) - - def _get_offset_position(self, position): - # Function to calculate the offset position (x, y, angle) of the moving - # elements of an animated widget - # input parameter `position` is a value from 0.0 to 1.0 indicating start - # and end position - # - # Designed to be flexible depending upon the widget's response - # - # values should be set in the __init__ function: - # self._x_motion: x-direction movement in pixels - # self._y_motion: y-direction movement in pixels - # self._angle_motion: angle movement - # - # A linear movement function (but can be modified with "easing functions" - # for motion acceleration). - - # if multiple elements are present, they could each have their own movement functions. - angle_offset = (2 * math.pi / 360) * ( - self._start_angle + self._sweep_angle * position - ) - - return angle_offset - - def _update_needle(self, value): - if self._limit_rotation: # constrain between min_value and max_value - value = max(min(self._value, self._max_value), self._min_value) - - self._draw_position( - value / (self._max_value - self._min_value) - ) # convert to position (0.0 to 1.0) - - def _draw_position(self, position): - # Draw the position of the needle. - # The position parameter is a float between 0 and 1 (0= off, 1= on). - - # Get the position offset from the motion function - angle_offset = self._get_offset_position(position) - - d_x = (self._needle_width / 2) * math.cos(angle_offset) - d_y = (self._needle_width / 2) * math.sin(angle_offset) - - x_0 = round(self._dial_center[0] - d_x) - y_0 = round(self._dial_center[1] - d_y) - - x_1 = round(self._dial_center[0] + d_x) - y_1 = round(self._dial_center[1] + d_y) - - x_2 = round(self._dial_center[0] + self._dial_radius * math.sin(angle_offset)) - y_2 = round(self._dial_center[1] - self._dial_radius * math.cos(angle_offset)) - - if (((2 * math.pi / 360) * self._sweep_angle) < math.pi) and self._clip_needle: - # clip the needle points by adjusting (x0,y0) and (x1,y1) - x_0, y_0 = _line_intersection(self._trim_line, [(x_0, y_0), (x_2, y_2)]) - x_1, y_1 = _line_intersection(self._trim_line, [(x_1, y_1), (x_2, y_2)]) - - if (x_0 == x_1) and (y_0 == y_1): - x_1 += 1 - y_1 += 1 - - self._needle.points = [(x_0, y_0), (x_1, y_1), (x_2, y_2)] - - def resize(self, new_width, new_height): - """Resizes the dial dimensions to the maximum size that will - fit within the requested bounding box size (``new_width``, ``new_height``) - - :param int new_width: requested width, in pixels - :param int new_height: requested height, in pixels - """ - self._initialize_dial(new_width, new_height) - - @property - def value(self): - """The dial's value.""" - return self._value - - @value.setter - def value(self, new_value): - - if new_value != self._value: - self._value = new_value - self._update_value() - self._update_needle(self._value) - - @property - def value_font(self): - """The font used for the value's label.""" - return self._value_font - - @value_font.setter - def value_font(self, new_font): - if self._display_value: - self._value_label.font = new_font - self._value_font = new_font - - @property - def value_color(self): - """The font color used for the value's label.""" - return self._value_color - - @value_color.setter - def value_color(self, new_color): - if self._display_value: - self._value_label.color = new_color - self._value_color = new_color - - @property - def dial_center(self): - """The (x,y) pixel location of the dial's center of rotation.""" - return self._dial_center - - @property - def dial_radius(self): - """The length of the dial's radius, in pixels.""" - return self._dial_radius - - @property - def start_angle(self): - """The starting angle of the dial, in degrees.""" - return self._start_angle - - @property - def sweep_angle(self): - """The sweep angle of the dial, in degrees.""" - return self._sweep_angle - - -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 - ) - - -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, - ) - - -# * Copyright (c) 2017 Werner Stoop -# * -# * Permission is hereby granted, free of charge, to any person obtaining a copy -# * of this software and associated documentation files (the "Software"), to deal -# * in the Software without restriction, including without limitation the rights -# * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# * copies of the Software, and to permit persons to whom the Software is -# * furnished to do so, subject to the following conditions: -# * -# * The above copyright notice and this permission notice shall be included in all -# * copies or substantial portions of the Software. -# * -# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# * SOFTWARE. - - -# Credit from https://github.com/wernsey/bitmap -# MIT License from -# * Copyright (c) 2017 Werner Stoop -# -# /** -# * #### `void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px, -# * int py, double angle, double scale);` -# * -# * Rotates a source bitmap `src` around a pivot point `px,py` and blits it -# * onto a destination bitmap `dst`. -# * -# * The bitmap is positioned such that the point `px,py` on the source is at -# * the offset `ox,oy` on the destination. -# * -# * The `angle` is clockwise, in radians. The bitmap is also scaled by the -# * factor `scale`. -# */ -# void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px, -# int py, double angle, double scale); - - -# /* -# Reference: -# "Fast Bitmap Rotation and Scaling" By Steven Mortimer, Dr Dobbs' Journal, July 01, 2001 -# http://www.drdobbs.com/architecture-and-design/fast-bitmap-rotation-and-scaling/184416337 -# See also http://www.efg2.com/Lab/ImageProcessing/RotateScanline.htm -# */ - -# pylint: disable=invalid-name, too-many-branches, too-many-statements - -# This function is provided in case the bitmaptools.rotozoom function is not available -def _blit_rotate_scale( - destination, # destination bitmap - ox=None, - oy=None, # (ox, oy) is the destination point where the source (px,py) is placed - dest_clip0=None, - dest_clip1=None, # clip0,1 is (x,y) corners of clip window on the destination bitmap - source=None, # source bitmap - px=None, - py=None, # (px, py) is the rotation point of the source bitmap - source_clip0=None, - source_clip1=None, # clip0,1 is (x,y) corners of clip window on the source bitmap - angle=0, # in radians, clockwise - scale=1.0, # scale factor (float) - skip_index=None, # color index to ignore -): - - if source is None: - pass - - # Check the input limits - - if ox is None: - ox = destination.width / 2 - if oy is None: - oy = destination.height / 2 - if px is None: - px = source.width / 2 - if py is None: - py = source.height / 2 - - if dest_clip0 is None: - dest_clip0 = (0, 0) - if dest_clip1 is None: - dest_clip1 = (destination.width, destination.height) - - if source_clip0 is None: - source_clip0 = (0, 0) - if source_clip1 is None: - source_clip1 = (source.width, source.height) - - minx = dest_clip1[0] - miny = dest_clip1[1] - maxx = dest_clip0[0] - maxy = dest_clip0[1] - - sinAngle = math.sin(angle) - cosAngle = math.cos(angle) - - dx = -cosAngle * px * scale + sinAngle * py * scale + ox - dy = -sinAngle * px * scale - cosAngle * py * scale + oy - if dx < minx: - minx = int(round(dx)) - if dx > maxx: - maxx = int(round(dx)) - if dy < miny: - miny = int(round(dy)) - if dy > maxy: - maxy = int(dy) - dx = cosAngle * (source.width - px) * scale + sinAngle * py * scale + ox - dy = sinAngle * (source.width - px) * scale - cosAngle * py * scale + oy - if dx < minx: - minx = int(round(dx)) - if dx > maxx: - maxx = int(round(dx)) - if dy < miny: - miny = int(round(dy)) - if dy > maxy: - maxy = int(round(dy)) - - dx = ( - cosAngle * (source.width - px) * scale - - sinAngle * (source.height - py) * scale - + ox - ) - dy = ( - sinAngle * (source.width - px) * scale - + cosAngle * (source.height - py) * scale - + oy - ) - if dx < minx: - minx = int(round(dx)) - if dx > maxx: - maxx = int(round(dx)) - if dy < miny: - miny = int(round(dy)) - if dy > maxy: - maxy = int(round(dy)) - - dx = -cosAngle * px * scale - sinAngle * (source.height - py) * scale + ox - dy = -sinAngle * px * scale + cosAngle * (source.height - py) * scale + oy - if dx < minx: - minx = int(round(dx)) - if dx > maxx: - maxx = int(round(dx)) - if dy < miny: - miny = int(round(dy)) - if dy > maxy: - maxy = int(round(dy)) - - # /* Clipping */ - if minx < dest_clip0[0]: - minx = dest_clip0[0] - if maxx > dest_clip1[0] - 1: - maxx = dest_clip1[0] - 1 - if miny < dest_clip0[1]: - miny = dest_clip0[1] - if maxy > dest_clip1[1] - 1: - maxy = dest_clip1[1] - 1 - - dvCol = math.cos(angle) / scale - duCol = math.sin(angle) / scale - - duRow = dvCol - dvRow = -duCol - - startu = px - (ox * dvCol + oy * duCol) - startv = py - (ox * dvRow + oy * duRow) - - rowu = startu + miny * duCol - rowv = startv + miny * dvCol - - for y in range(miny, maxy + 1): # (y = miny, y <= maxy, y++) - u = rowu + minx * duRow - v = rowv + minx * dvRow - for x in range(minx, maxx + 1): # (x = minx, x <= maxx, x++) - if (source_clip0[0] <= u < source_clip1[0]) and ( - source_clip0[1] <= v < source_clip1[1] - ): - # get the pixel color (c) from the source bitmap at (u,v) - c = source[ - int(u) + source.width * int(v) - ] # direct index into bitmap is faster than tuple - # c = source[int(u), int(v)] - - if c != skip_index: # ignore any pixels with skip_index - # place the pixel color (c) into the destination bitmap at (x,y) - destination[ - x + y * destination.width - ] = c # direct index into bitmap is faster than tuple - # destination[x,y] = c - u += duRow - v += dvRow - - rowu += duCol - rowv += dvCol - - -# Circle size calculations based on the angle intervals requested -# Algorithm source -# https://math.stackexchange.com/questions/45303/how-to-get-rectangular-size-of-arbitrary-circular-sector -def _isInInterval(theta, interval): - theta = theta % 360 - i = interval[0] % 360 - f = interval[1] % 360 - if i < f: - return (i <= theta <= f) and (theta <= f) - return not f < theta < i - - -def _getXcoord(theta): - return (1 + math.cos(theta * 2 * math.pi / 360)) / 2 - - -def _getYcoord(theta): - return (1 + math.sin(theta * 2 * math.pi / 360)) / 2 - - -def _getCoords(interval, ignore_center=False): - # This functions gets the maximum bounary dimensions of - # a rectangle required to contain a partial circle with - # the interval of (start_angle, end_angle) - # - # Parameter: - # interval = [start_angle, end_angle] - # ignore_center = Set True to exclude the centerpoint from the boundary - # - # Coordinates for calculations - # 0 degrees is up - # Circle diameter = 1.0 - # circle center is always at (0.5, 0.5) - # upper left direction is (0.0, 0.0) - # dimensions are in units of the circle's diameter (1.0 = diameter) - # - # Returns: - # (left, top, right, bottom, xCenter_offet, yCenter_offset) - # coordinates of the minimum bounding box - # and the xCenter_offset, yCenter_offset distance between - # the upper left corner and the circle center - - i = interval[0] - f = interval[1] - - xi = _getXcoord(i) - yi = _getYcoord(i) - xf = _getXcoord(f) - yf = _getYcoord(f) - - is0 = _isInInterval(0, interval) - is90 = _isInInterval(90, interval) - is180 = _isInInterval(180, interval) - is270 = _isInInterval(270, interval) - - if is0: - top = 1.0 - else: - if ignore_center: - top = max(xi, xf) - else: - top = max(xi, xf, 0.5) - - if is90: - right = 1.0 - else: - if ignore_center: - right = max(yi, yf) - else: - right = max(yi, yf, 0.5) - - if is180: - bottom = 0 - else: - if ignore_center: - bottom = min(xi, xf) - else: - bottom = min(xi, xf, 0.5) - - if is270: - left = 0 - else: - if ignore_center: - left = min(yi, yf) - else: - left = min(yi, yf, 0.5) - - xCenter_offset = 0.5 - left - yCenter_offset = 0.5 - top - - # Correct coordinates so that upper left corner is (0,0) - # Center is always at coordinate (0.5, 0.5) - # All coordinates are in units of the circle's diameter - # x,y Center_offset is the center point's offset relative to the upper left corner - # (left, top, right, bottom, xCenter_offet, yCenter_offset) - return [left, 1 - top, right, 1 - bottom, xCenter_offset, -yCenter_offset] - - -# Calculate the intersection point between two lines -# Source: -# https://stackoverflow.com/questions/20677795/how-do-i-compute-the-intersection-point-of-two-lines - - -def _line_intersection(line1, line2): - xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0]) - ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1]) - - def _det(a, b): - return a[0] * b[1] - a[1] * b[0] - - div = _det(xdiff, ydiff) - if div == 0: - raise Exception("lines do not intersect") - - d = (_det(*line1), _det(*line2)) - x = _det(d, xdiff) / div - y = _det(d, ydiff) / div - return round(x), round(y) diff --git a/docs/annotation_example.png b/docs/annotation_example.png deleted file mode 100755 index eaa588c..0000000 Binary files a/docs/annotation_example.png and /dev/null differ diff --git a/docs/annotation_example.png.license b/docs/annotation_example.png.license deleted file mode 100644 index 74baa7b..0000000 --- a/docs/annotation_example.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2021 Kevin Matocha - -SPDX-License-Identifier: MIT diff --git a/docs/api.rst b/docs/api.rst index 8b504f8..b517167 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -23,13 +23,6 @@ .. inheritance-diagram:: adafruit_displayio_layout.widgets.switch_round -.. automodule:: adafruit_displayio_layout.widgets.dial - :members: - :member-order: bysource - :inherited-members: - -.. inheritance-diagram:: adafruit_displayio_layout.widgets.dial - .. automodule:: adafruit_displayio_layout.widgets.icon_widget :members: :member-order: bysource @@ -42,10 +35,6 @@ :members: :member-order: bysource -.. automodule:: adafruit_displayio_layout.widgets.annotation - :members: - :member-order: bysource - .. automodule:: adafruit_displayio_layout.widgets.cartesian :members: :member-order: bysource diff --git a/docs/dial.gif b/docs/dial.gif deleted file mode 100644 index 778c4ea..0000000 Binary files a/docs/dial.gif and /dev/null differ diff --git a/docs/dial.gif.license b/docs/dial.gif.license deleted file mode 100644 index 74baa7b..0000000 --- a/docs/dial.gif.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2021 Kevin Matocha - -SPDX-License-Identifier: MIT diff --git a/docs/dial_variables_angles.png b/docs/dial_variables_angles.png deleted file mode 100755 index 9441274..0000000 Binary files a/docs/dial_variables_angles.png and /dev/null differ diff --git a/docs/dial_variables_angles.png.license b/docs/dial_variables_angles.png.license deleted file mode 100644 index 74baa7b..0000000 --- a/docs/dial_variables_angles.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2021 Kevin Matocha - -SPDX-License-Identifier: MIT diff --git a/docs/dial_variables_clip_needle.png b/docs/dial_variables_clip_needle.png deleted file mode 100644 index c1e1163..0000000 Binary files a/docs/dial_variables_clip_needle.png and /dev/null differ diff --git a/docs/dial_variables_clip_needle.png.license b/docs/dial_variables_clip_needle.png.license deleted file mode 100644 index 74baa7b..0000000 --- a/docs/dial_variables_clip_needle.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2021 Kevin Matocha - -SPDX-License-Identifier: MIT diff --git a/docs/dial_variables_min_max_values.png b/docs/dial_variables_min_max_values.png deleted file mode 100755 index f110b6a..0000000 Binary files a/docs/dial_variables_min_max_values.png and /dev/null differ diff --git a/docs/dial_variables_min_max_values.png.license b/docs/dial_variables_min_max_values.png.license deleted file mode 100644 index 74baa7b..0000000 --- a/docs/dial_variables_min_max_values.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2021 Kevin Matocha - -SPDX-License-Identifier: MIT diff --git a/docs/dial_variables_ticks.png b/docs/dial_variables_ticks.png deleted file mode 100755 index 35aec45..0000000 Binary files a/docs/dial_variables_ticks.png and /dev/null differ diff --git a/docs/dial_variables_ticks.png.license b/docs/dial_variables_ticks.png.license deleted file mode 100644 index 74baa7b..0000000 --- a/docs/dial_variables_ticks.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2021 Kevin Matocha - -SPDX-License-Identifier: MIT diff --git a/docs/examples.rst b/docs/examples.rst index 2c46c7f..7ca2806 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -34,15 +34,6 @@ Create multiple sliding switch with various sizes and orientations. :caption: examples/displayio_layout_switch_multiple.py :linenos: -Dial simple test ----------------- - -Create a single dial. - -.. literalinclude:: ../examples/displayio_layout_dial_simpletest.py - :caption: examples/displayio_layout_dial_simpletest.py - :linenos: - FlipInput simple test --------------------- @@ -52,15 +43,6 @@ Create three FlipInput selectors. :caption: examples/displayio_layout_flip_input_simpletest.py :linenos: -Annotation example ------------------- - -Displays annotations, examples relative to SwitchRound widget or as freeform. - -.. literalinclude:: ../examples/displayio_layout_annotation_simpletest.py - :caption: examples/displayio_layout_annotation_simpletest.py - :linenos: - Cartesian plane simple test --------------------------- diff --git a/examples/displayio_layout_annotation_simpletest.py b/examples/displayio_layout_annotation_simpletest.py deleted file mode 100644 index 671ed1e..0000000 --- a/examples/displayio_layout_annotation_simpletest.py +++ /dev/null @@ -1,81 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Kevin Matocha -# -# SPDX-License-Identifier: MIT -""" -Example of the Annotation widget to annotate a Switch widget or -for freeform annotation. -""" - -import time -import board -import displayio -import adafruit_touchscreen -from adafruit_displayio_layout.widgets.switch_round import SwitchRound as Switch -from adafruit_displayio_layout.widgets.annotation import Annotation - -display = board.DISPLAY - -ts = adafruit_touchscreen.Touchscreen( - board.TOUCH_XL, - board.TOUCH_XR, - board.TOUCH_YD, - board.TOUCH_YU, - calibration=((5200, 59000), (5800, 57000)), - size=(display.width, display.height), -) - -# Create the switch widget -my_switch = Switch(190, 50) - -# Create several annotations - -# This annotation is positioned relative to the switch widget, with default values. -switch_annotation = Annotation( - widget=my_switch, # positions are relative to the switch - text="Widget Annotation: Switch", -) - -# This annotation is positioned relative to the switch widget, with the line -# going in the downard direction and anchored at the middle bottom of the switch. -# The position is "nudged" downward using ``position_offset`` to create a 1 pixel -# gap between the end of the line and the switch. -# The text is positioned under the line by setting ``text_under`` to True. -switch_annotation_under = Annotation( - widget=my_switch, # positions are relative to the switch - text="Annotation with: text_under = True", - delta_x=-10, - delta_y=15, # line will go in downward direction (positive y) - anchor_point=(0.5, 1.0), # middle, bottom of switch - position_offset=(0, 1), # nudge downward by one pixel - text_under=True, -) - -# This is a freeform annotation that is positioned using (x,y) values at the bottom, right -# corner of the display (display.width, display.height). -# The line direction is -freeform_annotation = Annotation( - x=display.width, # uses freeform (x,y) position - y=display.height, - text="Freeform annotation (display.width, height)", -) - -my_group = displayio.Group() -my_group.append(my_switch) -my_group.append(switch_annotation) -my_group.append(switch_annotation_under) -my_group.append(freeform_annotation) - -# Add my_group to the display -display.show(my_group) - -# Start the main loop -while True: - - p = ts.touch_point # get any touches on the screen - - if p: # Check each switch if the touch point is within the switch touch area - # If touched, then flip the switch with .selected - if my_switch.contains(p): - my_switch.selected(p) - - time.sleep(0.05) # touch response on PyPortal is more accurate with a small delay diff --git a/examples/displayio_layout_dial_simpletest.py b/examples/displayio_layout_dial_simpletest.py deleted file mode 100644 index 116b048..0000000 --- a/examples/displayio_layout_dial_simpletest.py +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Kevin Matocha -# -# SPDX-License-Identifier: MIT -############################# -""" -This is a basic demonstration of a Dial widget. -""" - -import time -import board -import displayio -import terminalio -from adafruit_displayio_layout.widgets.dial import Dial - -# Fonts used for the Dial tick labels -tick_font = terminalio.FONT - -display = board.DISPLAY # create the display on the PyPortal or Clue (for example) -# otherwise change this to setup the display -# for display chip driver and pinout you have (e.g. ILI9341) - - -# Define the minimum and maximum values for the dial -minimum_value = 0 -maximum_value = 100 - -# Create a Dial widget -my_dial = Dial( - x=20, # set x-position of the dial inside of my_group - y=20, # set y-position of the dial inside of my_group - width=180, # requested width of the dial - height=180, # requested height of the dial - padding=25, # add 25 pixels around the dial to make room for labels - start_angle=-120, # left angle position at -120 degrees - sweep_angle=240, # total sweep angle of 240 degrees - min_value=minimum_value, # set the minimum value shown on the dial - max_value=maximum_value, # set the maximum value shown on the dial - tick_label_font=tick_font, # the font used for the tick labels - tick_label_scale=2.0, # the scale factor for the tick label font -) - -my_group = displayio.Group() -my_group.append(my_dial) - -display.show(my_group) # add high level Group to the display - -step_size = 1 - -while True: - - # run the dial from minimum to maximum - for this_value in range(minimum_value, maximum_value + 1, step_size): - my_dial.value = this_value - display.refresh() # force the display to refresh - time.sleep(0.5) - - # run the dial from maximum to minimum - for this_value in range(maximum_value, minimum_value - 1, -step_size): - my_dial.value = this_value - display.refresh() # force the display to refresh - time.sleep(0.5)