예제 #1
0
    def __init__(self, df, to_show, widths, wrap_around, **kwargs):
        super().__init__(**kwargs)
        self.add_class("content")
        d = Event(source=self,
                  watched_events=['wheel', "mousemove", "mouseleave"])
        d.on_dom_event(self.event_handler)

        self.to_show = to_show
        self.num_rows = min(len(df),
                            to_show if to_show % 2 == 0 else to_show + 1)
        self.idx = 0
        self.wrap_around = wrap_around
        self.df = df
        self.records = df.to_records()

        def row_on_click(event):
            if event["new"] != -1:
                self.value = event["new"]

        self.rows = deque([
            _Row(data=self.records[i],
                 widths=widths,
                 on_click=row_on_click,
                 style=["row_even", "row_odd"][i % 2])
            for i in range(self.num_rows)
        ])
        self.children = list(self.rows)[0:self.to_show]
예제 #2
0
class MouseDataWidget(MouseData):
    """Get data from mouse input, using ipywidget/ipyevent methods (Jupyter: %matplotlib inline)
        usage:  data = MouseDataWidget(); data.display(); ...
        after input, stores 'data.m' points, with locations 'data.X' and targets 'data.Y'
        plot image widget available as "data.image"
    """
    def __init__(self, *args, **kwargs):
        from ipywidgets import Image
        from ipyevents import Event
        #self.plot = None   # set in super?
        super().__init__(*args, **kwargs)
        self.image = Image(value=blank_png, format='png')
        self.no_drag = Event(source=self.image,
                             watched_events=['dragstart'],
                             prevent_default_action=True)
        self.events = Event(source=self.image,
                            watched_events=['click', 'contextmenu'],
                            prevent_default_action=True)
        self.events.on_dom_event(self.__on_click)
        self.update_plot()

    def __get_coord(self, event):
        return np.array([event['dataX'] / self.w, 1 - event['dataY'] / self.h
                         ]) * 2 / (1 - 2 * self.border) - 1 - self.border

    def update_plot(self):
        import matplotlib.pyplot as plt
        from .plot import plotClassify2D
        fig = plt.figure(figsize=(6, 6))
        plt.gcf().add_axes((self.border, self.border, 1 - 2 * self.border,
                            1 - 2 * self.border))  # full width figure
        plt.axis(self.lim)
        plt.gca().set_xticks([])
        plt.gca().set_yticks([])
        if (self.m > 0) or (self.plot is not None):
            if self.plot is not None:
                self.plot(self.X, self.Y)  # user-provided plot f'n
            else:
                fig.gca().scatter(self.X[:, 0], self.X[:, 1],
                                  c=self.Y)  # or default
        self.image.value = plot_to_png(plt.gcf())
        self.w, self.h = plt.gcf().canvas.get_renderer(
        ).get_canvas_width_height()
        fig.clear()

    def display(self, fig=None, **kwargs):
        from IPython.display import display
        if self.plot is None:
            print(
                "Default plot. Left-click to add data; shift/alt/ctrl combos determine target value; right click to remove data."
            )
        display(self.image)

    def __on_click(self, event):
        if (event['type'] == 'click'):  # left click = add point
            self.add_point(self.__get_coord(event), wkeys(event))
        elif (event['type']
              == 'contextmenu') and (self.m > 0):  # right click = remove point
            self.remove_nearest(self.__get_coord(event))
        self.update_plot()
예제 #3
0
def test_callbacks():
    # Test that the initial callbacks look right, that we can add one, and
    # that clearing removes them all.
    event_widget = Event()

    assert len(event_widget._dom_handlers.callbacks) == 0

    def noop(event):
        pass

    def noop2(event):
        pass

    event_widget.on_dom_event(noop)

    assert noop in event_widget._dom_handlers.callbacks
    assert len(event_widget._dom_handlers.callbacks) == 1

    # Add noop2....
    event_widget.on_dom_event(noop2)
    assert event_widget._dom_handlers.callbacks == [noop, noop2]

    # Try removing noop2
    event_widget.on_dom_event(noop2, remove=True)
    assert event_widget._dom_handlers.callbacks == [noop]

    # Finally, clear all callbacks
    event_widget.reset_callbacks()

    assert len(event_widget._dom_handlers.callbacks) == 0
예제 #4
0
class Icon(WidgetWrapper):
    def __init__(self, fontawesome_icon: str):
        """Clickable icon

        Parameters
        ----------
        fontawesome_icon: str
            icon string from the fontawesome https://fontawesome.com. For example, "fab fa-500px"
        """
        self.el_icon = widgets.HTML(
            value=f'<i class="{fontawesome_icon}"></i>')
        self.on_click_callback = lambda: 1
        self.event_listener = Event(source=self.el_icon,
                                    watched_events=['click'])
        self.event_listener.on_dom_event(self.fire_on_click_event)

    @property
    def widget(self):
        return self.el_icon

    def on_click(self, callback: Callable[[], None]):
        self.on_click_callback = callback

    def fire_on_click_event(self, event: dict):
        if event['type'] == 'click':
            self.on_click_callback()
예제 #5
0
def test_setting_xy_coordinates_good_value():
    # Setting to a value should just work
    event_widget = Event()
    good_name = 'data'
    event_widget.xy_coordinate_system = good_name

    assert event_widget.xy_coordinate_system == good_name
예제 #6
0
def test_negative_wait_raises_error():
    # negative wait should raise an error.
    event_widget = Event()

    with pytest.raises(ValueError) as e:
        event_widget.wait = -20

    assert 'wait must be set to a non-negative integer. ' in str(e)
예제 #7
0
def test_floating_point_wait_raises_error():
    # A floating point value should reaise a TraitletError
    event_widget = Event()

    with pytest.raises(traitlets.traitlets.TraitError) as e:
        event_widget.wait = 15.0

    assert "'wait' trait of an Event instance" in str(e)
예제 #8
0
    def construct_arrow_handler(self):
        """ Should only be run once """
        disp_events = Event(source=self, watched_events=['keydown'])

        def handle_disp(event):
            if event["type"] == "keydown":
                self.key_funcs[event["key"]]()

        disp_events.on_dom_event(handle_disp)
예제 #9
0
def test_invalid_event_name():
    # An unrecognized event name should generate a ValueError
    event_widget = Event()
    bad_name = 'this is not a valid event name'
    with pytest.raises(ValueError) as e:
        event_widget.watched_events = [bad_name]

    assert bad_name in str(e)
    assert 'not supported. The supported ' in str(e)
예제 #10
0
    def __init__(self, data, widths, on_click, style, _types=None, **kwargs):
        super().__init__(**kwargs)
        self.add_class(style)
        self.observe(on_click, "value")
        d = Event(source=self, watched_events=['click'])
        d.on_dom_event(self.on_click)

        self.data = data
        self.cells = [_Cell(x, w) for x, w in zip(data, widths)]
        self.cells[0].add_class("index")
        self.children = self.cells
예제 #11
0
파일: button.py 프로젝트: binh-vu/labext
    def __init__(self, **kwargs):
        """Same constructor as `ipywidgets.widgets.Button`"""
        self.el_btn = widgets.Button(**kwargs)
        self.el_btn.on_click(self.fire_on_click_event)
        self.on_click_callback = lambda x: x
        self.on_mouseenter_callback = lambda x: x
        self.on_mouseleave_callback = lambda x: x

        self.event_listener = Event(
            source=self.el_btn, watched_events=['mouseenter', 'mouseleave'])
        self.event_listener.on_dom_event(self.fire_mouse_event)
예제 #12
0
def test_setting_xy_coordinate_bad_value():
    # Setting xy_coordinate_system to a bad value should raise a ValueError
    event_widget = Event()

    bad_name = 'this is not a valid name'

    with pytest.raises(ValueError) as e:
        event_widget.xy_coordinate_system = bad_name

    assert "are not supported. The supported coordinates are" in str(e)
    assert bad_name in str(e)
예제 #13
0
def test_invalid_slow_method_raises_error():
    # Setting throttle_or_debounce to an invalid name should raise
    # a ValueError.
    event_widget = Event()

    bad_name = 'this is not a valid name'

    with pytest.raises(ValueError) as e:
        event_widget.throttle_or_debounce = bad_name

    assert bad_name in str(e)
    assert 'The event rate limiting method' in str(e)
예제 #14
0
 def __init__(self, scene_proxy, bridge, *args, **kw):
     super(IPyRemoteWidget, self).__init__(scene_proxy, bridge, *args, **kw)
     self.image = Image(format='PNG')
     self.event = Event(source=self.image,
                        watched_events=[
                            'dragstart', 'mouseenter', 'mouseleave',
                            'mousedown', 'mouseup', 'mousemove', 'wheel',
                            'keyup', 'keydown'
                        ],
                        prevent_default_action=True)
     self.event.on_dom_event(self.handle_ipyevent)
     self._update_image()
예제 #15
0
    def construct_click_handler(self):
        """ Should only be run once """
        disp_events = Event(source=self, watched_events=['click'])

        def handle_disp(event):
            if event["type"] == "click":
                x = self.images[self.page_index]._size[0]
                if event["relativeX"] > (x / 2):
                    self.next_page()
                elif event["relativeX"] < (x / 2):
                    self.previous_page()

        disp_events.on_dom_event(handle_disp)
예제 #16
0
    def setup_jupyter(self):
        """
        Sets up elements on the page for use with a Jupyter notebook.
        """
        self._label = Label('Move the cursor over the cell and use the left and right arrow keys to navigate')
        self._hbox = HBox()
        self._html = HTML('<h3>Label position?</h3>')

        self._inner = VBox()
        self._vbox = VBox([self._html, self._inner, self._label])
        self._event = Event(source=self._vbox, watched_events=['keydown'])
        self._event.on_dom_event(self.handle_event)
        return self
예제 #17
0
 def __init__(self, *args, **kwargs):
     from ipywidgets import Image
     from ipyevents import Event
     #self.plot = None   # set in super?
     super().__init__(*args, **kwargs)
     self.image = Image(value=blank_png, format='png')
     self.no_drag = Event(source=self.image,
                          watched_events=['dragstart'],
                          prevent_default_action=True)
     self.events = Event(source=self.image,
                         watched_events=['click', 'contextmenu'],
                         prevent_default_action=True)
     self.events.on_dom_event(self.__on_click)
     self.update_plot()
예제 #18
0
    def __init__(self, fontawesome_icon: str):
        """Clickable icon

        Parameters
        ----------
        fontawesome_icon: str
            icon string from the fontawesome https://fontawesome.com. For example, "fab fa-500px"
        """
        self.el_icon = widgets.HTML(
            value=f'<i class="{fontawesome_icon}"></i>')
        self.on_click_callback = lambda: 1
        self.event_listener = Event(source=self.el_icon,
                                    watched_events=['click'])
        self.event_listener.on_dom_event(self.fire_on_click_event)
예제 #19
0
def test_setting_wait_with_debounce_set_preserves_debounce(slow_method):
    # If debounce is set but wait is zero and wait is then set to something
    # non-zero then throttle_or_debounce should still stay debounce.
    event_widget = Event()

    event_widget.throttle_or_debounce = slow_method

    # Make sure wait is currently zero...
    assert event_widget.wait == 0

    # This shouldn't change throttle or debounce
    event_widget.wait = 20

    assert event_widget.throttle_or_debounce == slow_method
예제 #20
0
def test_setting_wait_with_no_throttle_or_debounce():
    # If wait is set to something non-zero AND neither throttle
    # nor debounce has been set then it should be set to
    # throttle.
    event_widget = Event()

    # Make sure throttle_or_debounce is not set...
    assert not event_widget.throttle_or_debounce

    # ...and that wait is currently zero
    assert event_widget.wait == 0

    # This implicitly sets throttle_or_debounce
    event_widget.wait = 20

    assert event_widget.throttle_or_debounce == 'throttle'
예제 #21
0
class HTML(WidgetWrapper):
    def __init__(self, html: str):
        self.el = widgets.HTML(value=html)
        self.on_click_callback = lambda: 1
        self.event_listener = Event(source=self.el, watched_events=['click'])
        self.event_listener.on_dom_event(self.fire_on_click_event)

    @property
    def widget(self):
        return self.el

    def on_click(self, callback: Callable[[], None]):
        self.on_click_callback = callback

    def fire_on_click_event(self, event: dict):
        if event['type'] == 'click':
            self.on_click_callback()
예제 #22
0
def test_properties_work():
    # These are a little silly, but will get this to 100% test coverage
    event_widget = Event()

    # Note the extra underscore on the right hand sides
    assert (event_widget.supported_key_events ==
            event_widget._supported_key_events)
    assert (event_widget.supported_mouse_events ==
            event_widget._supported_mouse_events)
예제 #23
0
    def __init__(self, globals_dict):
        self.status_text = display(Code(""), display_id=True)
        self._globals_dict = globals_dict
        self._methods = {}

        self.stop_button = Button(description="Stop")
        self.stop_button.on_click(self.on_stop_button_clicked)
        self._globals_dict["canvas"] = Canvas()
        self.kb_mon = Event(source=self.canvas,
                            watched_events=['keydown', 'keyup'],
                            wait=1000 // FRAME_RATE,
                            prevent_default_actions=True)
        self.output_text = ""
        self.color_strings = {"default": "#888888"}
        match_255 = r"(?:(?:2(?:(?:5[0-5])|(?:[0-4][0-9])))|(?:[01]?[0-9]{1,2}))"
        match_alpha = r"(?:(?:1(?:\.0*)?)|(?:0(?:\.[0-9]*)?))"
        match_360 = r"(?:(?:3[0-5][0-9])|(?:[0-2]?[0-9]{1,2}))"
        match_100 = r"(?:100|[0-9]{1,2})"
        self.regexes = [
            re.compile(r"#[0-9A-Fa-f]{6}"),
            re.compile(r"rgb\({},{},{}\)".format(match_255, match_255,
                                                 match_255)),
            re.compile(r"rgba\({},{},{},{}\)".format(match_255, match_255,
                                                     match_255, match_alpha)),
            re.compile(r"hsl\({},{}%,{}%\)".format(match_360, match_100,
                                                   match_100)),
            re.compile(r"hsla\({},{}%,{}%,{}\)".format(match_360, match_100,
                                                       match_100, match_alpha))
        ]
        self.width, self.height = DEFAULT_CANVAS_SIZE
        self.mouse_x = 0
        self.mouse_y = 0
        self.mouse_is_pressed = False
        self.key = ""
        self._keys_held = {}

        # Settings for drawing text (https://ipycanvas.readthedocs.io/en/latest/drawing_text.html).
        self.font_settings = {
            'size': 12.0,
            'font': 'sans-serif',
            'baseline': 'top',
            'align': 'left'
        }
예제 #24
0
파일: button.py 프로젝트: binh-vu/labext
class Button(WidgetWrapper):
    """An extended button widget that support mouse over event.
    """
    def __init__(self, **kwargs):
        """Same constructor as `ipywidgets.widgets.Button`"""
        self.el_btn = widgets.Button(**kwargs)
        self.el_btn.on_click(self.fire_on_click_event)
        self.on_click_callback = lambda x: x
        self.on_mouseenter_callback = lambda x: x
        self.on_mouseleave_callback = lambda x: x

        self.event_listener = Event(
            source=self.el_btn, watched_events=['mouseenter', 'mouseleave'])
        self.event_listener.on_dom_event(self.fire_mouse_event)

    @property
    def widget(self):
        return self.el_btn

    def on_click(self, callback: Callable[['Button'], None]):
        """Register for on click event"""
        self.on_click_callback = callback

    def on_mouseenter(self, callback: Callable[['Button'], None]):
        """Register for on mouse enter event"""
        self.on_mouseenter_callback = callback

    def on_mouseleave(self, callback: Callable[['Button'], None]):
        """Register for on mouse leave event"""
        self.on_mouseleave_callback = callback

    def fire_on_click_event(self, _btn: widgets.Button):
        """Fire the on_click event when users click the button"""
        self.on_click_callback(self)

    def fire_mouse_event(self, event: dict):
        """Show the content on mouse over"""
        if event['type'] == 'mouseenter':
            self.on_mouseenter_callback(self)
        else:
            self.on_mouseleave_callback(self)
예제 #25
0
    def __init__(self,
                 im_path=None,
                 label=None,
                 im_name=None,
                 im_index=None,
                 display_label=True,
                 image_width='50px',
                 image_height=None):

        self.display_label = display_label
        self.label = 'None'
        self.image = Image(layout=Layout(display='flex',
                                         justify_content='center',
                                         align_items='center',
                                         align_content='center',
                                         width=image_width,
                                         height=image_height), )

        if self.display_label:  # both image and label
            self.label = HTML(
                value='?',
                layout=Layout(display='flex',
                              justify_content='center',
                              align_items='center',
                              align_content='center'),
            )
        else:  # no label (capture image case)
            self.im_name = im_name
            self.im_index = im_index
            self.image.layout.border = 'solid 1px gray'
            self.image.layout.object_fit = 'contain'

        super().__init__(
            layout=Layout(align_items='center', margin='3px', padding='2px'))
        if not im_path:
            self.clear()

        self.d = Event(source=self, watched_events=['click'])
예제 #26
0
 def __init__(self, scene_proxy, bridge, *args, **kw):
     super(IPyRemoteWidget, self).__init__(scene_proxy, bridge, *args, **kw)
     self.image = Image(format='PNG')
     self.event = Event(
         source=self.image,
         watched_events=[
             'dragstart', 'mouseenter', 'mouseleave',
             'mousedown', 'mouseup', 'mousemove', 'wheel',
             'keyup', 'keydown'
         ],
         prevent_default_action=True
     )
     self.event.on_dom_event(self.handle_ipyevent)
     self._update_image()
예제 #27
0
파일: scratch.py 프로젝트: gshiba/ogel
    def __init__(self, label_name):
        self.clix = 0  # current landmark index
        self.length = len(db)
        self.n_panels = 5
        self.panels = [ImageAndLabel() for _ in range(self.n_panels)]
        self.label_name = label_name
        self.landmarks = Landmarks({k: None for k in db.keys()})

        self.c = widgets.HTML('Click or type on me!')
        button = widgets.Button(description="Save",
                                layout=widgets.Layout(width='auto'))
        button.on_click(self.save)
        w = widgets.HBox([*self.panels])
        w = widgets.VBox([w, self.c, button])
        self.widget = w

        self.d = Event(source=self.widget, watched_events=['keydown'])
        self.d.on_dom_event(self.handle_event)

        self.target_label = 'q'

        self.render()
        display(self.widget)
예제 #28
0
 def __init__(self, obj):
     self.value = obj # we should compute it -- or use it -- as a 'member'
     if hasattr(obj, '_latex_list'):
         s = obj._latex_list()
     elif hasattr(obj, '_latex_'):
         s = obj._latex_()
     else:
         s = obj.__str__()
     h = HTMLMath('$%s$' % s)
     h.add_class('explorable-value')
     self.clc = Event(source=h, watched_events=['click'])
     super(ExplorableValue, self).__init__(
         (h,),
         layout = Layout(border='1px solid green', padding='2px 50px 2px 2px')
     )
예제 #29
0
    def set_widget(self, jp_imgw):
        """Call this method with the Jupyter image widget (image_w)
        that will be used.
        """
        super(ImageViewEvent, self).set_widget(jp_imgw)

        self.jp_evt = EventListener(source=jp_imgw)
        self.jp_evt.watched_events = [
            'keydown', 'keyup', 'mouseenter', 'mouseleave', 'mousedown',
            'mouseup', 'mousemove', 'wheel', 'contextmenu'
        ]
        self.jp_evt.prevent_default_action = True

        self.jp_evt.on_dom_event(self._handle_event)
        self.logger.info("installed event handlers")

        return self.make_callback('map')
예제 #30
0
    def set_widget(self, jp_imgw):
        """Call this method with the Jupyter image widget (image_w)
        that will be used.
        """
        super(ImageViewEvent, self).set_widget(jp_imgw)

        self.jp_evt = EventListener(source=jp_imgw)
        self.jp_evt.watched_events = [
            'keydown', 'keyup', 'mouseenter', 'mouseleave',
            'mousedown', 'mouseup', 'mousemove', 'wheel',
            'contextmenu'
        ]
        self.jp_evt.prevent_default_action = True

        self.jp_evt.on_dom_event(self._handle_event)
        self.logger.info("installed event handlers")

        return self.make_callback('map')
예제 #31
0
def init(*args, **kwargs):
    global flag, downflag, shiftflag

    w = widgets.Image(value=m.system.image_data(), width=600)
    d = Event(source=w,
              watched_events=[
                  'mousedown', 'mouseup', 'mousemove', 'keyup', 'keydown',
                  'wheel'
              ])
    no_drag = Event(source=w,
                    watched_events=['dragstart'],
                    prevent_default_action=True)
    d.on_dom_event(listen_mouse)
    run = widgets.ToggleButton(
        value=False,
        description='Run',
        disabled=False,
        button_style='',  # 'success', 'info', 'warning', 'danger' or ''
        tooltip='run the simulation',
        icon='play')
    pause = widgets.ToggleButton(
        value=False,
        description='Pause',
        disabled=False,
        button_style='',  # 'success', 'info', 'warning', 'danger' or ''
        tooltip='pause the simulation',
        icon='pause')

    reset = widgets.ToggleButton(
        value=False,
        description='Reset',
        disabled=False,
        button_style='',  # 'success', 'info', 'warning', 'danger' or ''
        tooltip='reset the simulation',
        icon='stop')

    def onToggleRun(b):
        global flag
        if run.value:
            run.button_style = 'success'
            pause.value = False
            pause.button_style = ''
            reset.value = False
            reset.button_style = ''
            flag = True
        else:
            run.button_style = ''
            flag = False

    def onTogglePause(b):
        global flag
        if pause.value:
            pause.button_style = 'success'
            run.value = False
            run.button_style = ''
            reset.value = False
            reset.button_style = ''
            flag = False
        else:
            pause.button_style = ''
            flag = True

    def onToggleReset(b):
        global flag
        if reset.value:
            reset.button_style = 'success'
            pause.value = False
            pause.button_style = ''
            run.value = False
            run.button_style = ''
            flag = False
            m.Universe.reset()
        else:
            reset.button_style = ''
            #w = create_simulation()

    buttons = widgets.HBox([run, pause, reset])
    run.observe(onToggleRun, 'value')
    pause.observe(onTogglePause, 'value')
    reset.observe(onToggleReset, 'value')

    box = widgets.VBox([w, buttons])
    display(box)

    def background_threading():
        global flag
        while True:
            m.Simulator.context_make_current()
            if flag:
                m.step()
            w.value = m.system.image_data()
            m.Simulator.context_release()
            time.sleep(0.01)

    t = threading.Thread(target=background_threading)
    t.start()
예제 #32
0
class Core:
    # All constants that will be injected into global scope in the user"s cell
    global_constants = {
        "pi": pi
    }

    ignite_globals = _ignite_globals

    def __init__(self, globals_dict):
        self.status_text = display(Code(""), display_id=True)
        self._globals_dict = globals_dict
        self._methods = {}

        self.stop_button = Button(description="Stop")
        self.stop_button.on_click(self.on_stop_button_clicked)
        self._globals_dict["canvas"] = Canvas()
        self.kb_mon = Event(source=self.canvas, watched_events=['keydown', 'keyup'], wait=1000 // FRAME_RATE,
                            prevent_default_actions=True)
        self.output_text = ""
        self.color_strings = {
            "default": "#888888"
        }
        match_255 = r"(?:(?:2(?:(?:5[0-5])|(?:[0-4][0-9])))|(?:[01]?[0-9]{1,2}))"
        match_alpha = r"(?:(?:1(?:\.0*)?)|(?:0(?:\.[0-9]*)?))"
        match_360 = r"(?:(?:3[0-5][0-9])|(?:[0-2]?[0-9]{1,2}))"
        match_100 = r"(?:100|[0-9]{1,2})"
        self.regexes = [
            re.compile(r"#[0-9A-Fa-f]{6}"),
            re.compile(r"rgb\({},{},{}\)".format(match_255, match_255, match_255)),
            re.compile(r"rgba\({},{},{},{}\)".format(match_255, match_255, match_255, match_alpha)),
            re.compile(r"hsl\({},{}%,{}%\)".format(match_360, match_100, match_100)),
            re.compile(r"hsla\({},{}%,{}%,{}\)".format(match_360, match_100, match_100, match_alpha))
        ]
        self.width, self.height = DEFAULT_CANVAS_SIZE
        self.mouse_x = 0
        self.mouse_y = 0
        self.mouse_is_pressed = False
        self.key = ""
        self._keys_held = {}

        # Settings for drawing text (https://ipycanvas.readthedocs.io/en/latest/drawing_text.html).
        self.font_settings = {
            'size': 12.0,
            'font': 'sans-serif',
            'baseline': 'top',
            'align': 'left'
        }

    ### Properties ###

    @property
    @ignite_global
    def canvas(self) -> Canvas:
        return self._globals_dict["canvas"]

    @property
    @ignite_global
    def mouse_x(self):
        return self._globals_dict["mouse_x"]

    @mouse_x.setter
    def mouse_x(self, val):
        self._globals_dict["mouse_x"] = val

    @property
    @ignite_global
    def mouse_y(self):
        return self._globals_dict["mouse_y"]

    @mouse_y.setter
    def mouse_y(self, val):
        self._globals_dict["mouse_y"] = val

    @property
    @ignite_global
    def mouse_is_pressed(self):
        return self._globals_dict["mouse_is_pressed"]

    @mouse_is_pressed.setter
    def mouse_is_pressed(self, val):
        self._globals_dict["mouse_is_pressed"] = val

    @property
    @ignite_global
    def key(self):
        return self._globals_dict["key"]

    @key.setter
    def key(self, val):
        self._globals_dict["key"] = val

    @property
    @ignite_global
    def width(self):
        return self._globals_dict["width"]

    @width.setter
    def width(self, val):
        self._globals_dict["width"] = val
        self.canvas.width = val

    @property
    @ignite_global
    def height(self):
        return self._globals_dict["height"]

    @height.setter
    def height(self, val):
        self._globals_dict["height"] = val
        self.canvas.height = val

    ### Library init ###

    # Updates last activity time
    @staticmethod
    def refresh_last_activity():
        global _sparkplug_last_activity
        _sparkplug_last_activity = time.time()

    # Creates canvas and starts thread
    def start(self, methods):
        self._methods = methods
        draw = self._methods.get("draw", None)

        if draw:
            self.print_status("Running...")
            display(self.stop_button)

        display(self.canvas)

        self.output_text_code = display(Code(self.output_text), display_id=True)

        self.canvas.on_mouse_down(self.on_mouse_down)
        self.canvas.on_mouse_up(self.on_mouse_up)
        self.canvas.on_mouse_move(self.on_mouse_move)

        self.kb_mon.on_dom_event(self.handle_kb_event)

        # Initialize text drawing settings for the canvas. ()
        self.canvas.font = f"{self.font_settings['size']}px {self.font_settings['font']}"
        self.canvas.text_baseline = 'top'
        self.canvas.text_align = 'left'

        thread = threading.Thread(target=self.loop)
        thread.start()

    def stop(self, message="Stopped"):
        global _sparkplug_running

        if not _sparkplug_running:
            return

        _sparkplug_running = False
        self.print_status(message)
        self.kb_mon.reset_callbacks()
        self.kb_mon.close()

        # Assuming we're using IPython to draw the canvas through the display() function.
        # Commenting this out for now, it throws exception since it does not derive BaseException
        # raise IpyExit

    # Loop method that handles drawing and setup
    def loop(self):
        global _sparkplug_active_thread_id, _sparkplug_running

        # Set active thread to this thread. This will stop any other active thread.
        current_thread_id = threading.current_thread().native_id
        _sparkplug_active_thread_id = current_thread_id
        _sparkplug_running = True
        self.refresh_last_activity()

        draw = self._methods.get("draw", None)
        setup = self._methods.get("setup", None)

        if setup:
            try:
                setup()
            except Exception as e:
                self.stop("Error in setup() function: " + str(e))
                return

        while _sparkplug_running:
            if _sparkplug_active_thread_id != current_thread_id \
                    or time.time() - _sparkplug_last_activity > NO_ACTIVITY_THRESHOLD:
                self.stop("Stopped due to inactivity")
                return

            if not draw:
                self.stop("Done drawing.")
                return

            with hold_canvas(self.canvas):
                try:
                    draw()
                except Exception as e:
                    self.stop("Error in draw() function: " + str(e))
                    return

            time.sleep(1 / FRAME_RATE)

    # Prints status to embedded error box
    def print_status(self, msg):
        self.status_text.update(Code(msg))

    # Prints output to embedded output box
    # Can't use @validate_args decorator for functions actually accepting variable arguments
    @ignite_global
    def print(self, *args, sep=' ', end='\n', flush=True):
        global _sparkplug_running
        self.output_text += sep.join([str(arg) for arg in args]) + end

        if _sparkplug_running and flush:
            self.output_text_code.update(Code(self.output_text))

    # Update mouse_x, mouse_y, and call mouse_down handler
    def on_mouse_down(self, x, y):
        self.refresh_last_activity()
        self.mouse_x, self.mouse_y = int(x), int(y)
        self.mouse_is_pressed = True

        mouse_down = self._methods.get("mouse_down", None)
        if mouse_down:
            mouse_down()

    # Update mouse_x, mouse_y, and call mouse_up handler
    def on_mouse_up(self, x, y):
        self.refresh_last_activity()
        self.mouse_x, self.mouse_y = int(x), int(y)
        self.mouse_is_pressed = False

        mouse_up = self._methods.get("mouse_up", None)
        if mouse_up:
            mouse_up()

    # Update mouse_x, mouse_y, and call mouse_moved handler
    def on_mouse_move(self, x, y):
        self.refresh_last_activity()
        self.mouse_x, self.mouse_y = int(x), int(y)

        mouse_moved = self._methods.get("mouse_moved", None)
        if mouse_moved:
            mouse_moved()

    def on_stop_button_clicked(self, button):
        self.stop()

    @extern
    def handle_kb_event(self, event): pass

    ### User overrideable functions ###

    # The function bodies here do not matter, they are discarded
    @ignite_global(mutable=True)
    def setup(self): pass

    @ignite_global(mutable=True)
    def draw(self): pass

    @ignite_global(mutable=True)
    def mouse_up(self): pass

    @ignite_global(mutable=True)
    def mouse_down(self): pass

    @ignite_global(mutable=True)
    def mouse_moved(self): pass

    @ignite_global(mutable=True)
    def key_pressed(self): pass

    @ignite_global(mutable=True)
    def key_released(self): pass

    @ignite_global(mutable=True)
    def key_repeated(self): pass

    ### Global functions ###

    # From .util.helper_functions.keyboard_functions

    @extern
    def keys_held(self, *args): pass

    @extern
    def key_held(self, *args): pass

    # From .util.helper_functions.canvas_functions

    @extern
    def size(self, *args): pass

    @extern
    def fill_style(self): pass

    @extern
    def stroke_style(self, *args): pass

    @extern
    def clear(self, *args): pass

    @extern
    def background(self, *args): pass

    # From util.helper_functions.rect_functions

    @extern
    def rect(self, *args): pass

    @extern
    def fill_rect(self, *args): pass

    @extern
    def stroke_rect(self, *args): pass

    @extern
    def clear_rect(self, *args): pass

    # From util.helper_functions.square_functions

    @extern
    def square(self, *args): pass

    @extern
    def stroke_square(self, *args): pass

    @extern
    def fill_square(self, *args): pass

    # From util.helper_functions.circle_functions

    @extern
    def circle(self, *args): pass

    @extern
    def fill_circle(self, *args): pass

    @extern
    def stroke_circle(self, *args): pass

    # From util.helper_functions.ellipse_functions

    @extern
    def ellipse(self, *args): pass

    @extern
    def fill_ellipse(self, *args): pass

    @extern
    def stroke_ellipse(self, *args): pass

    # From util.helper_functions.arc_functions

    @extern
    def arc(self, *args): pass

    @extern
    def fill_arc(self, *args): pass

    @extern
    def stroke_arc(self, *args): pass

    # From util.helper_functions.triangle_functions

    @extern
    def triangle(self, *args): pass

    @extern
    def fill_triangle(self, *args): pass

    @extern
    def stroke_triangle(self, *args): pass

    # From util.helper_functions.text_functions

    @extern
    def text_size(self, *args): pass

    @extern
    def text_align(self, *args): pass

    @extern
    def text(self, *args): pass

    # From util.helper_functions.line_functions

    @extern
    def draw_line(self, *args): pass

    @extern
    def line(self, *args): pass

    @extern
    def line_width(self, *args): pass

    # An alias to line_width
    @extern
    def stroke_width(self, *args): pass

    ### Helper Functions ###

    # From util.helper_functions.misc_functions

    @extern
    def parse_color(self, *args, func_name="parse_color"): pass

    @extern
    def color(self, *args): pass

    @extern
    def parse_color_string(self, func_name, s): pass

    @extern
    def arc_args(self, *args): pass

    @extern
    def random(self, *args): pass

    @extern
    def randint(self, *args): pass
예제 #33
0
class IPyRemoteWidget(RemoteWidget):
    def __init__(self, scene_proxy, bridge, *args, **kw):
        super(IPyRemoteWidget, self).__init__(scene_proxy, bridge, *args, **kw)
        self.image = Image(format='PNG')
        self.event = Event(
            source=self.image,
            watched_events=[
                'dragstart', 'mouseenter', 'mouseleave',
                'mousedown', 'mouseup', 'mousemove', 'wheel',
                'keyup', 'keydown'
            ],
            prevent_default_action=True
        )
        self.event.on_dom_event(self.handle_ipyevent)
        self._update_image()

    def _ipython_display_(self):
        display(self.image)

    # ###### Public protocol ##############

    def show(self):
        pass

    def show_image(self, data, format='PNG'):
        self.image.format = format
        self.image.value = data

    # ##### VTK Event handling ##########
    def on_render(self, data):
        self.show_image(base64_to_bytes(data['data']),
                        format=data.get('format', 'PNG'))

    def on_cursor_changed(self, data):
        # self.setCursor(cursor)
        pass

    def handle_ipyevent(self, event):
        type = event['type']
        shift = event.get('shiftKey', False)
        ctrl = event.get('ctrlKey', False)
        btn_map = {0: 'left', 1: 'right', 2: 'middle'}
        if type == 'mouseenter':
            self.on_enter(ctrl, shift)
        elif type == 'mouseleave':
            self.on_leave(ctrl, shift)
        elif type == 'mouseleave':
            self.on_leave(ctrl, shift)
        elif type == 'mousedown':
            repeat = 0
            button = btn_map.get(event.get('button'), 'none')
            x, y = event.get('relativeX'), event.get('relativeY')
            self.on_mouse_press(ctrl, shift, x, y, button, repeat)
        elif type == 'mouseup':
            x, y = event.get('relativeX'), event.get('relativeY')
            self.on_mouse_release(ctrl, shift, x, y)
        elif type == 'mousemove':
            button = btn_map.get(event.get('button'), 'none')
            x, y = event.get('relativeX'), event.get('relativeY')
            self.on_mouse_move(ctrl, shift, button, x, y)
        elif type == 'wheel':
            dx = event.get('deltaX')
            dy = event.get('deltaY')
            dz = event.get('deltaZ')
            delta = dx + dy + dz
            self.on_wheel(delta)
        elif type == 'keydown':
            key = event.get('key')
            # Need to map the special keys correctly.
            key_sym = key
            self.on_key_press(ctrl, shift, key, key_sym)
        elif type == 'keyup':
            key = event.get('key')
            # Need to map the special keys correctly.
            key_sym = key
            self.on_key_release(ctrl, shift, key)
예제 #34
0
class ImageViewEvent(ImageViewJpw):

    def __init__(self, logger=None, rgbmap=None, settings=None):
        ImageViewJpw.__init__(self, logger=logger, rgbmap=rgbmap,
                              settings=settings)

        self._button = 0

        # maps EventListener events to callback handlers
        self._evt_dispatch = {
            'mousedown': self.button_press_event,
            'mouseup': self.button_release_event,
            'mousemove': self.motion_notify_event,
            'wheel': self.scroll_event,
            'mouseenter': self.enter_notify_event,
            'mouseleave': self.leave_notify_event,
            'keydown': self.key_press_event,
            'keyup': self.key_release_event,
        }

        # mapping from EventListener key events to ginga key events
        self._keytbl = {
            'shiftleft': 'shift_l',
            'shiftright': 'shift_r',
            'controlleft': 'control_l',
            'controlright': 'control_r',
            'altleft': 'alt_l',
            'altright': 'alt_r',
            'osleft': 'super_l',
            'osright': 'super_r',
            'contextmenu': 'menu_r',
            'backslash': 'backslash',
            'space': 'space',
            'escape': 'escape',
            'enter': 'return',
            'tab': 'tab',
            'arrowright': 'right',
            'arrowleft': 'left',
            'arrowup': 'up',
            'arrowdown': 'down',
            'pageup': 'page_up',
            'pagedown': 'page_down',
            'f1': 'f1',
            'f2': 'f2',
            'f3': 'f3',
            'f4': 'f4',
            'f5': 'f5',
            'f6': 'f6',
            'f7': 'f7',
            'f8': 'f8',
            'f9': 'f9',
            'f10': 'f10',
            'f11': 'f11',
            'f12': 'f12',
        }

        self._keytbl2 = {
            '`': 'backquote',
            '"': 'doublequote',
            "'": 'singlequote',
        }

        # Define cursors for pick and pan
        #hand = openHandCursor()
        hand = 'fleur'
        self.define_cursor('pan', hand)
        cross = 'cross'
        self.define_cursor('pick', cross)

        for name in ('motion', 'button-press', 'button-release',
                     'key-press', 'key-release', 'drag-drop',
                     'scroll', 'map', 'focus', 'enter', 'leave',
                     'pinch', 'rotate', 'pan', 'swipe', 'tap'):
            self.enable_callback(name)

    def set_widget(self, jp_imgw):
        """Call this method with the Jupyter image widget (image_w)
        that will be used.
        """
        super(ImageViewEvent, self).set_widget(jp_imgw)

        self.jp_evt = EventListener(source=jp_imgw)
        self.jp_evt.watched_events = [
            'keydown', 'keyup', 'mouseenter', 'mouseleave',
            'mousedown', 'mouseup', 'mousemove', 'wheel',
            'contextmenu'
        ]
        self.jp_evt.prevent_default_action = True

        self.jp_evt.on_dom_event(self._handle_event)
        self.logger.info("installed event handlers")

        return self.make_callback('map')

    def _handle_event(self, event):
        # TODO: need focus events and maybe a map event
        # TODO: Set up widget as a drag and drop destination
        evt_kind = event['type']
        handler = self._evt_dispatch.get(evt_kind, None)
        if handler is not None:
            return handler(event)
        return False

    def transkey(self, keycode, keyname=None):
        keycode = str(keycode).lower()
        if keyname is None:
            keyname = keycode
        self.logger.debug("key code in jupyter '%s'" % (keycode))
        res = self._keytbl.get(keycode, None)
        if res is None:
            res = self._keytbl2.get(keyname, keyname)
        return res

    def get_key_table(self):
        return self._keytbl

    def focus_event(self, event, has_focus):
        return self.make_callback('focus', has_focus)

    def enter_notify_event(self, event):
        enter_focus = self.t_.get('enter_focus', False)
        if enter_focus:
            # TODO: set focus on canvas
            pass
        return self.make_callback('enter')

    def leave_notify_event(self, event):
        self.logger.debug("leaving widget...")
        return self.make_callback('leave')

    def key_press_event(self, event):
        keyname = self.transkey(event['code'], keyname=event['key'])
        self.logger.debug("key press event, key=%s" % (keyname))
        return self.make_ui_callback('key-press', keyname)

    def key_release_event(self, event):
        keyname = self.transkey(event['code'], keyname=event['key'])
        self.logger.debug("key release event, key=%s" % (keyname))
        return self.make_ui_callback('key-release', keyname)

    def button_press_event(self, event):
        x, y = event['dataX'], event['dataY']
        self.last_win_x, self.last_win_y = x, y

        button = 0
        button |= 0x1 << event['button']
        self._button = button
        self.logger.debug("button event at %dx%d, button=%x" % (x, y, button))

        data_x, data_y = self.check_cursor_location()

        return self.make_ui_callback('button-press', button, data_x, data_y)

    def button_release_event(self, event):
        x, y = event['dataX'], event['dataY']
        self.last_win_x, self.last_win_y = x, y

        button = 0
        button |= 0x1 << event['button']
        self._button = 0
        self.logger.debug("button release at %dx%d button=%x" % (x, y, button))

        data_x, data_y = self.check_cursor_location()

        return self.make_ui_callback('button-release', button, data_x, data_y)

    def motion_notify_event(self, event):
        button = self._button
        x, y = event['dataX'], event['dataY']
        self.last_win_x, self.last_win_y = x, y

        self.logger.debug("motion event at %dx%d, button=%x" % (x, y, button))

        data_x, data_y = self.check_cursor_location()

        return self.make_ui_callback('motion', button, data_x, data_y)

    def scroll_event(self, event):
        x, y = event['dataX'], event['dataY']
        self.last_win_x, self.last_win_y = x, y
        dx, dy = event['deltaX'], event['deltaY']

        if (dx != 0 or dy != 0):
            # <= This browser gives us deltas for x and y
            # Synthesize this as a pan gesture event
            self.make_ui_callback('pan', 'start', 0, 0)
            self.make_ui_callback('pan', 'move', -dx, -dy)
            return self.make_ui_callback('pan', 'stop', 0, 0)

        # <= This code path should not be followed under normal
        # circumstances.
        # we leave it here in case we want to make the scroll
        # callback configurable in the future

        # TODO: calculate actual angle of direction
        if dy < 0:
            direction = 0.0   # up
        elif dy > 0:
            direction = 180.0   # down
        else:
            return False

        # 15 deg is standard 1-click turn for a wheel mouse
        num_deg = 15.0
        self.logger.debug("scroll deg=%f direction=%f" % (
            num_deg, direction))

        data_x, data_y = self.check_cursor_location()

        return self.make_ui_callback('scroll', direction, num_deg,
                                     data_x, data_y)