<commit_before>"""
Defines the concrete top-level Enable 'Window' class for the Pyglet framework.
Uses the Kiva GL backend.
"""

import sys
import warnings

# Pyglet imports
import pyglet
from pyglet import window
from pyglet.window import key

# Enthought library imports
from enthought.traits.api import Any, Float, Instance, Trait

# Enable imports
from enthought.enable2.base import send_event_to, union_bounds
from enthought.enable2.component  import Component
from enthought.enable2.events import MouseEvent, KeyEvent, DragEvent
from enthought.enable2.graphics_context import GraphicsContextEnable
from enthought.enable2.abstract_window import AbstractWindow

# local, relative imports
from constants import BUTTON_NAME_MAP, KEY_MAP, POINTER_MAP


class PygletMouseEvent(object):
    """ Because Pyglet doesn't have a native mouse event object, we use
    this to encapsulate all the possible state when we receive any mouse-
    related event.
    """
    def __init__(self, x, y, dx=0, dy=0, buttons=None, modifiers=None,
                 scroll_x=0, scroll_y=0):
        """ **buttons** is a list of buttons """
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.modifiers = modifiers
        self.buttons = buttons
        self.scroll_x = scroll_x
        self.scroll_y = scroll_y
        
        if modifiers is not None:
            self.shift_pressed = (modifiers & key.MOD_SHIFT)
            self.ctrl_pressed = (modifiers & key.MOD_CTRL)
            self.alt_pressed = (modifiers & key.MOD_ALT)
        else:
            self.shift_pressed = self.ctrl_pressed = self.alt_pressed = False
        return 


class PygletWindow(window.Window):
    """ Pyglet recommends subclassing their base Window class as the preferred
    method for customizing behavior.  This PygletWindow class serves to bridge
    events and methods between the Enable layer and Pyglet.

    """

    def __init__(self, enable_window, **kwargs):
        """ PygletWindow needs a reference to the Enable window; other
        arguments are passed through directly to the pyglet.Window constructor.
        """
        self.enable_window = enable_window

        # Whether or not the Enable component stack has requested a redraw
        self._redraw_requested = False

        super(PygletWindow, self).__init__(**kwargs)

        # use a KeyStateHandler to remember the keyboard state.  This
        # is useful since Pyglet separates the notion of keyboard state
        # and character events, and we need to access keyboard state
        # from the on_text handler method.
        self.key_state = key.KeyStateHandler()
        self.push_handlers(self.key_state)

    #-------------------------------------------------------------------------
    # Public methods
    # These are not inherited from/part of the pyglet.window.Window interface
    #-------------------------------------------------------------------------

    def draw(self):
        "Called by the mainloop to perform the actual draw"
        self.enable_window._paint()
        

    def request_redraw(self, coordinates=None):
        """ Called by **self.enable_window** to request a redraw
        **coordinates** is a tuple (x,y,w,h) of a specific sub-region to
        redraw.
        """
        # TODO: Support the **coordinates** argument
        self._redraw_requested = True

    #-------------------------------------------------------------------------
    # Key/text handling
    #-------------------------------------------------------------------------
    
    def on_key_press(self, symbol, modifiers):
        return self._on_key_updown(symbol, modifiers, down=False)

    def on_key_release(self, symbol, modifiers):
        return self._on_key_updown(symbol, modifiers)

    def _on_key_updown(self, symbol, modifiers, down=True):
        event = PygletMouseEvent(0, 0, modifiers=modifiers)
        enable_win = self.enable_window
        enable_win.shift_pressed = bool(down & event.shift_pressed)
        enable_win.ctrl_pressed = bool(down & event.ctrl_pressed)
        enable_win.alt_pressed = bool(down & event.alt_pressed)
        # It's important to return False so that the KeyStateHandler
        # can also get this event.
        return False

    def on_text(self, text):
        if self.enable_window.focus_owner is None:
            focus_owner = self.enable_window.component
        else:
            focus_owner = self.enable_window.focus_owner

        if focus_owner is None:
            return

        keys = self.key_state
        enable_event = KeyEvent(character = key,
                          alt_down = keys[key.LALT] | keys[key.RALT],
                          control_down = keys[key.LCTRL] | keys[key.RCTRL],
                          shift_down = keys[key.LSHIFT] | keys[key.RSHIFT],
                          x = self._mouse_x,
                          y = self._mouse_y,
                          window = self.enable_window)
        focus_owner.dispatch(enable_event, "key_pressed")
        return True

    def on_text_motion(self, motion):
        # TODO: See notes.
        pass

    def on_text_motion_select(self, motion):
        # TODO: See notes.
        pass

    #-------------------------------------------------------------------------
    # Mouse handling
    #-------------------------------------------------------------------------

    def on_mouse_motion(self, x, y, dx, dy):
        event = PygletMouseEvent(x, y, dx, dy)
        self.enable_window._handle_mouse_event("mouse_move", event, set_focus=False)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        # TODO: Determine the difference between this and on_mouse_motion;
        # confirm that the correct buttons in **buttons** are down.
        event = PygletMouseEvent(x, y, dx, dy, buttons, modifiers)
        self.enable_window._handle_mouse_event("mouse_move", event, set_focus=False)

    def on_mouse_press(self, x, y, button, modifiers):
        return self._on_mouse_updown(x, y, button, modifiers, "up")

    def on_mouse_release(self, x, y, button, modifiers):
        return self._on_mouse_updown(x, y, button, modifiers, "down")

    def _on_mouse_updown(self, x, y, button, modifiers, which="down"):
        event = PygletMouseEvent(x, y, [button], modifiers)
        mouse = pyglet.window.mouse
        if button == mouse.LEFT:
            name = "left"
        elif button == mouse.MIDDLE:
            name = "middle"
        elif button == mouse.RIGHT:
            name = "right"
        self.enable_window._handle_mouse_event(name+"_"+which, event, set_focus=False)
        # TODO: Confirm that we should consume mouse press/release events
        return True

    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        # TODO: Handle scroll_x
        event = PygletMouseEvent(x, y, scroll_x=scroll_x, scroll_y=scroll_y)
        self.enable_window._handle_mouse_event("mouse_wheel", event, set_focus=False)

    def on_mouse_enter(self, x, y):
        event = PygletMouseEvent(x, y)
        self.enable_window._handle_mouse_event("mouse_enter", event, set_focus=False)

    def on_mouse_leave(self, x, y):
        event = PygletMouseEvent(x, y)
        self.enable_window._handle_mouse_event("mouse_leave", event, set_focus=False)

    #-------------------------------------------------------------------------<commit_msg>fixing stupid bug in mouse handling in pyglet backend<commit_after>"""
Defines the concrete top-level Enable 'Window' class for the Pyglet framework.
Uses the Kiva GL backend.
"""

import sys
import warnings

# Pyglet imports
import pyglet
from pyglet import window
from pyglet.window import key

# Enthought library imports
from enthought.traits.api import Any, Float, Instance, Trait

# Enable imports
from enthought.enable2.base import send_event_to, union_bounds
from enthought.enable2.component  import Component
from enthought.enable2.events import MouseEvent, KeyEvent, DragEvent
from enthought.enable2.graphics_context import GraphicsContextEnable
from enthought.enable2.abstract_window import AbstractWindow

# local, relative imports
from constants import BUTTON_NAME_MAP, KEY_MAP, POINTER_MAP


class PygletMouseEvent(object):
    """ Because Pyglet doesn't have a native mouse event object, we use
    this to encapsulate all the possible state when we receive any mouse-
    related event.
    """
    def __init__(self, x, y, dx=0, dy=0, buttons=None, modifiers=None,
                 scroll_x=0, scroll_y=0):
        """ **buttons** is a list of buttons """
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.modifiers = modifiers
        self.buttons = buttons
        self.scroll_x = scroll_x
        self.scroll_y = scroll_y
        
        if modifiers is not None:
            self.shift_pressed = (modifiers & key.MOD_SHIFT)
            self.ctrl_pressed = (modifiers & key.MOD_CTRL)
            self.alt_pressed = (modifiers & key.MOD_ALT)
        else:
            self.shift_pressed = self.ctrl_pressed = self.alt_pressed = False
        return 


class PygletWindow(window.Window):
    """ Pyglet recommends subclassing their base Window class as the preferred
    method for customizing behavior.  This PygletWindow class serves to bridge
    events and methods between the Enable layer and Pyglet.

    """

    def __init__(self, enable_window, **kwargs):
        """ PygletWindow needs a reference to the Enable window; other
        arguments are passed through directly to the pyglet.Window constructor.
        """
        self.enable_window = enable_window

        # Whether or not the Enable component stack has requested a redraw
        self._redraw_requested = False

        super(PygletWindow, self).__init__(**kwargs)

        # use a KeyStateHandler to remember the keyboard state.  This
        # is useful since Pyglet separates the notion of keyboard state
        # and character events, and we need to access keyboard state
        # from the on_text handler method.
        self.key_state = key.KeyStateHandler()
        self.push_handlers(self.key_state)

    #-------------------------------------------------------------------------
    # Public methods
    # These are not inherited from/part of the pyglet.window.Window interface
    #-------------------------------------------------------------------------

    def draw(self):
        "Called by the mainloop to perform the actual draw"
        self.enable_window._paint()
        

    def request_redraw(self, coordinates=None):
        """ Called by **self.enable_window** to request a redraw
        **coordinates** is a tuple (x,y,w,h) of a specific sub-region to
        redraw.
        """
        # TODO: Support the **coordinates** argument
        self._redraw_requested = True

    #-------------------------------------------------------------------------
    # Key/text handling
    #-------------------------------------------------------------------------
    
    def on_key_press(self, symbol, modifiers):
        return self._on_key_updown(symbol, modifiers, down=False)

    def on_key_release(self, symbol, modifiers):
        return self._on_key_updown(symbol, modifiers)

    def _on_key_updown(self, symbol, modifiers, down=True):
        event = PygletMouseEvent(0, 0, modifiers=modifiers)
        enable_win = self.enable_window
        enable_win.shift_pressed = bool(down & event.shift_pressed)
        enable_win.ctrl_pressed = bool(down & event.ctrl_pressed)
        enable_win.alt_pressed = bool(down & event.alt_pressed)
        # It's important to return False so that the KeyStateHandler
        # can also get this event.
        return False

    def on_text(self, text):
        if self.enable_window.focus_owner is None:
            focus_owner = self.enable_window.component
        else:
            focus_owner = self.enable_window.focus_owner

        if focus_owner is None:
            return

        keys = self.key_state
        enable_event = KeyEvent(character = key,
                          alt_down = keys[key.LALT] | keys[key.RALT],
                          control_down = keys[key.LCTRL] | keys[key.RCTRL],
                          shift_down = keys[key.LSHIFT] | keys[key.RSHIFT],
                          x = self._mouse_x,
                          y = self._mouse_y,
                          window = self.enable_window)
        focus_owner.dispatch(enable_event, "key_pressed")
        return True

    def on_text_motion(self, motion):
        # TODO: See notes.
        pass

    def on_text_motion_select(self, motion):
        # TODO: See notes.
        pass

    #-------------------------------------------------------------------------
    # Mouse handling
    #-------------------------------------------------------------------------

    def on_mouse_motion(self, x, y, dx, dy):
        event = PygletMouseEvent(x, y, dx, dy)
        self.enable_window._handle_mouse_event("mouse_move", event, set_focus=False)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        # TODO: Determine the difference between this and on_mouse_motion;
        # confirm that the correct buttons in **buttons** are down.
        event = PygletMouseEvent(x, y, dx, dy, buttons, modifiers)
        self.enable_window._handle_mouse_event("mouse_move", event, set_focus=False)

    def on_mouse_press(self, x, y, button, modifiers):
        return self._on_mouse_updown(x, y, button, modifiers, "down")

    def on_mouse_release(self, x, y, button, modifiers):
        return self._on_mouse_updown(x, y, button, modifiers, "up")

    def _on_mouse_updown(self, x, y, button, modifiers, which="down"):
        event = PygletMouseEvent(x, y, [button], modifiers)
        mouse = pyglet.window.mouse
        if button == mouse.LEFT:
            name = "left"
        elif button == mouse.MIDDLE:
            name = "middle"
        elif button == mouse.RIGHT:
            name = "right"
        self.enable_window._handle_mouse_event(name+"_"+which, event, set_focus=False)
        # TODO: Confirm that we should consume mouse press/release events
        return True

    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        # TODO: Handle scroll_x
        event = PygletMouseEvent(x, y, scroll_x=scroll_x, scroll_y=scroll_y)
        self.enable_window._handle_mouse_event("mouse_wheel", event, set_focus=False)

    def on_mouse_enter(self, x, y):
        event = PygletMouseEvent(x, y)
        self.enable_window._handle_mouse_event("mouse_enter", event, set_focus=False)

    def on_mouse_leave(self, x, y):
        event = PygletMouseEvent(x, y)
        self.enable_window._handle_mouse_event("mouse_leave", event, set_focus=False)

    #-------------------------------------------------------------------------
{'fraction_non_alphanumeric': 0.1471143473570658, 'fraction_numerical': 0.0014832793959007552, 'mean_word_length': 2.0703788035603394, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2754720', 'n_tokens_mistral': 4116, 'n_tokens_neox': 4025, 'n_words': 1162}