
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "gallery/widgets/menu.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. meta::
        :keywords: codex

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_gallery_widgets_menu.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_gallery_widgets_menu.py:


====
Menu
====

Using texts to construct a simple menu.

.. GENERATED FROM PYTHON SOURCE LINES 8-143



.. image-sg:: /gallery/widgets/images/sphx_glr_menu_001.png
   :alt: menu
   :srcset: /gallery/widgets/images/sphx_glr_menu_001.png, /gallery/widgets/images/sphx_glr_menu_001_2_00x.png 2.00x
   :class: sphx-glr-single-img





.. code-block:: Python


    from dataclasses import dataclass

    import matplotlib.pyplot as plt

    import matplotlib.artist as artist
    import matplotlib.patches as patches
    from matplotlib.typing import ColorType


    @dataclass
    class ItemProperties:
        fontsize: float = 14
        labelcolor: ColorType = 'black'
        bgcolor: ColorType = 'yellow'
        alpha: float = 1.0


    class MenuItem(artist.Artist):
        padx = 0.05  # inches
        pady = 0.05

        def __init__(self, fig, labelstr, props=None, hoverprops=None,
                     on_select=None):
            super().__init__()

            self.set_figure(fig)
            self.labelstr = labelstr

            self.props = props if props is not None else ItemProperties()
            self.hoverprops = (
                hoverprops if hoverprops is not None else ItemProperties())
            if self.props.fontsize != self.hoverprops.fontsize:
                raise NotImplementedError(
                    'support for different font sizes not implemented')

            self.on_select = on_select

            # specify coordinates in inches.
            self.label = fig.text(0, 0, labelstr, transform=fig.dpi_scale_trans,
                                  size=props.fontsize)
            self.text_bbox = self.label.get_window_extent(
                fig.canvas.get_renderer())
            self.text_bbox = fig.dpi_scale_trans.inverted().transform_bbox(self.text_bbox)

            self.rect = patches.Rectangle(
                (0, 0), 1, 1, transform=fig.dpi_scale_trans
            )  # Will be updated later.

            self.set_hover_props(False)

            fig.canvas.mpl_connect('button_release_event', self.check_select)

        def check_select(self, event):
            over, _ = self.rect.contains(event)
            if not over:
                return
            if self.on_select is not None:
                self.on_select(self)

        def set_extent(self, x, y, w, h, depth):
            self.rect.set(x=x, y=y, width=w, height=h)
            self.label.set(position=(x + self.padx, y + depth + self.pady / 2))
            self.hover = False

        def draw(self, renderer):
            self.rect.draw(renderer)
            self.label.draw(renderer)

        def set_hover_props(self, b):
            props = self.hoverprops if b else self.props
            self.label.set(color=props.labelcolor)
            self.rect.set(facecolor=props.bgcolor, alpha=props.alpha)

        def set_hover(self, event):
            """
            Update the hover status of event and return whether it was changed.
            """
            b, _ = self.rect.contains(event)
            changed = (b != self.hover)
            if changed:
                self.set_hover_props(b)
            self.hover = b
            return changed


    class Menu:
        def __init__(self, fig, menuitems):
            self.figure = fig

            self.menuitems = menuitems

            maxw = max(item.text_bbox.width for item in menuitems)
            maxh = max(item.text_bbox.height for item in menuitems)
            depth = max(-item.text_bbox.y0 for item in menuitems)

            x0 = 1
            y0 = 4

            width = maxw + 2 * MenuItem.padx
            height = maxh + MenuItem.pady

            for item in menuitems:
                left = x0
                bottom = y0 - maxh - MenuItem.pady

                item.set_extent(left, bottom, width, height, depth)

                fig.artists.append(item)
                y0 -= maxh + MenuItem.pady

            fig.canvas.mpl_connect('motion_notify_event', self.on_move)

        def on_move(self, event):
            if any(item.set_hover(event) for item in self.menuitems):
                self.figure.canvas.draw()


    fig = plt.figure()
    fig.subplots_adjust(left=0.3)
    props = ItemProperties(labelcolor='black', bgcolor='yellow',
                           fontsize=15, alpha=0.2)
    hoverprops = ItemProperties(labelcolor='white', bgcolor='blue',
                                fontsize=15, alpha=0.2)

    menuitems = []
    for label in ('open', 'close', 'save', 'save as', 'quit'):
        def on_select(item):
            print(f'you selected {item.labelstr}')
        item = MenuItem(fig, label, props=props, hoverprops=hoverprops,
                        on_select=on_select)
        menuitems.append(item)

    menu = Menu(fig, menuitems)
    plt.show()


.. _sphx_glr_download_gallery_widgets_menu.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: menu.ipynb <menu.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: menu.py <menu.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: menu.zip <menu.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
