Module albow.core.ui.AlbowEventLoop

Source code
from typing import List

import sys

import logging

from pygame.event import Event
from pygame.locals import MOUSEBUTTONDOWN
from pygame.locals import MOUSEBUTTONUP
from pygame.locals import MOUSEMOTION
from pygame.locals import K_ESCAPE
from pygame.locals import KMOD_CTRL
from pygame.locals import KMOD_SHIFT
from pygame.locals import KEYDOWN
from pygame.locals import KEYUP
from pygame.locals import USEREVENT
from pygame.locals import QUIT


from albow.core.Scheduler import Scheduler
from albow.core.CoreUtilities import CoreUtilities

from albow.core.ui.Widget import Widget
from albow.core.ui.RootWidget import RootWidget
from albow.core.ui.EventLoopParams import EventLoopParams

from albow.media.MusicUtilities import MusicUtilities


class AlbowEventLoop:

    MUSIC_END_EVENT = USEREVENT + 1
    """
    API consumer user events **MUST** start there events after this one
    """

    DOUBLE_CLICK_TIME = 300
    """
    Time is in milliseconds
    """

    def __init__(self, containingWidget: Widget, modalWidget: Widget):

        self.logger = logging.getLogger(__name__)
        self.modal_widget = modalWidget
        self.containingWidget = containingWidget

    def processEvents(self, eventList: List[Event], relativeMode: bool, deferDrawing: bool, eventLoopParams: EventLoopParams) -> EventLoopParams:

        self.logger.debug(f"Events to process: {len(eventList)}")

        use_sleep = eventLoopParams.use_sleep
        relative_pause = eventLoopParams.relative_pause
        do_draw = eventLoopParams.do_draw
        relative_warmup = eventLoopParams.relative_warmup
        last_click_time = eventLoopParams.last_click_time
        num_clicks = eventLoopParams.num_clicks

        for event in eventList:
            t = Scheduler.timestamp()
            event.dict['time'] = t
            event.dict['local'] = getattr(event, 'pos', (0, 0))
            eventType = event.type
            if eventType == QUIT:
                self.quit()
            elif eventType == MOUSEBUTTONDOWN:
                # print "RootWidget: MOUSEBUTTONDOWN: setting do_draw" ###
                do_draw = True
                if t - last_click_time <= AlbowEventLoop.DOUBLE_CLICK_TIME:
                    num_clicks += 1
                else:
                    num_clicks = 1
                last_click_time = t
                event.dict['num_clicks'] = num_clicks
                CoreUtilities.add_modifiers(event)
                RootWidget.last_mouse_event = event
                self.logger.debug(f"num_clicks: '{num_clicks}' -- t: '{t}' -- last_click_time: '{last_click_time}'")

                if relativeMode:
                    event.dict['local'] = (0, 0)
                    if relative_pause:
                        relative_pause = False
                    else:
                        #  modal_widget.dispatch_key('mouse_down', event)
                        mouse_widget = self.modal_widget.get_focus()
                        RootWidget.clicked_widget = mouse_widget
                        RootWidget.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_event('mouse_down', event)
                else:
                    mouse_widget = self.containingWidget.find_widget(event.pos)
                    if not mouse_widget.is_inside(self.modal_widget):
                        mouse_widget = self.modal_widget
                    RootWidget.clicked_widget = mouse_widget
                    RootWidget.last_mouse_event_handler = mouse_widget
                    mouse_widget.notify_attention_loss()
                    mouse_widget.handle_mouse('mouse_down', event)
            elif eventType == MOUSEMOTION:
                CoreUtilities.add_modifiers(event)
                RootWidget.last_mouse_event = event

                if relativeMode:
                    event.dict['local'] = (0, 0)
                    if not relative_pause:
                        if relative_warmup:
                            relative_warmup -= 1
                        else:
                            #  modal_widget.dispatch_key('mouse_delta', event)
                            mouse_widget = RootWidget.clicked_widget or self.modal_widget.get_focus()
                            RootWidget.last_mouse_event_handler = mouse_widget
                            mouse_widget.handle_event('mouse_delta', event)
                else:
                    mouse_widget = self.containingWidget.find_widget(event.pos)  # Do this in else branch?
                    if RootWidget.clicked_widget:
                        RootWidget.last_mouse_event_handler = mouse_widget  # Should this be clicked_widget?
                        RootWidget.clicked_widget.handle_mouse('mouse_drag', event)
                    else:
                        if not mouse_widget.is_inside(self.modal_widget):
                            mouse_widget = self.modal_widget
                        RootWidget.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_mouse('mouse_move', event)
            elif eventType == MOUSEBUTTONUP:
                CoreUtilities.add_modifiers(event)
                RootWidget.last_mouse_event = event
                do_draw = True
                if relativeMode:
                    event.dict['local'] = (0, 0)
                    if not relative_pause:

                        if RootWidget.clicked_widget:
                            mouse_widget = RootWidget.clicked_widget
                            RootWidget.clicked_widget = None
                        else:
                            mouse_widget = self.modal_widget.get_focus()
                        RootWidget.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_event('mouse_up', event)
                else:
                    if RootWidget.clicked_widget:
                        RootWidget.last_mouse_event_handler = RootWidget.clicked_widget
                        RootWidget.clicked_widget = None
                        RootWidget.last_mouse_event_handler.handle_mouse('mouse_up', event)
            elif eventType == KEYDOWN:
                key = event.key
                if key == K_ESCAPE and relativeMode and event.mod & KMOD_CTRL and event.mod & KMOD_SHIFT:
                    relative_pause = True
                elif relative_pause:
                    relative_pause = False
                else:
                    CoreUtilities.set_modifier(key, True)

                    do_draw = True
                    self.send_key(self.modal_widget, 'key_down', event)
                    if RootWidget.last_mouse_event_handler:
                        event.dict['pos'] = RootWidget.last_mouse_event.pos
                        event.dict['local'] = RootWidget.last_mouse_event.local
                        RootWidget.last_mouse_event_handler.setup_cursor(event)
            elif eventType == KEYUP:
                key = event.key
                CoreUtilities.set_modifier(key, False)

                do_draw = True
                self.send_key(self.modal_widget, 'key_up', event)
                if RootWidget.last_mouse_event_handler:
                    event.dict['pos'] = RootWidget.last_mouse_event.pos
                    event.dict['local'] = RootWidget.last_mouse_event.local
                    RootWidget.last_mouse_event_handler.setup_cursor(event)
            elif eventType == AlbowEventLoop.MUSIC_END_EVENT:
                self.music_end()
            elif eventType == USEREVENT:
                if deferDrawing and not use_sleep:
                    RootWidget.ourTimerEvent = event
            else:
                #
                # Maybe someone has registered some user events handler
                #
                userEventCallList = RootWidget.getUserEventList()
                for cb in userEventCallList:
                    if cb.userEvent == eventType:
                        self.logger.debug(f"API User eventType: {eventType}")
                        cb.func(event)

        retEventLoopParams: EventLoopParams = EventLoopParams(use_sleep=use_sleep,
                                                              relative_pause=relative_pause,
                                                              do_draw=do_draw,
                                                              relative_warmup=relative_warmup,
                                                              last_click_time=last_click_time,
                                                              num_clicks=num_clicks)

        return retEventLoopParams

    def send_key(self, theWidget: Widget, theName: str, theEvent: Event):

        CoreUtilities.add_modifiers(theEvent)
        theWidget.dispatch_key(theName, theEvent)

    def music_end(self):
        MusicUtilities.music_end()

    def quit(self):
        #
        # call quit handler
        sys.exit()

Classes

class AlbowEventLoop (containingWidget, modalWidget)
Source code
class AlbowEventLoop:

    MUSIC_END_EVENT = USEREVENT + 1
    """
    API consumer user events **MUST** start there events after this one
    """

    DOUBLE_CLICK_TIME = 300
    """
    Time is in milliseconds
    """

    def __init__(self, containingWidget: Widget, modalWidget: Widget):

        self.logger = logging.getLogger(__name__)
        self.modal_widget = modalWidget
        self.containingWidget = containingWidget

    def processEvents(self, eventList: List[Event], relativeMode: bool, deferDrawing: bool, eventLoopParams: EventLoopParams) -> EventLoopParams:

        self.logger.debug(f"Events to process: {len(eventList)}")

        use_sleep = eventLoopParams.use_sleep
        relative_pause = eventLoopParams.relative_pause
        do_draw = eventLoopParams.do_draw
        relative_warmup = eventLoopParams.relative_warmup
        last_click_time = eventLoopParams.last_click_time
        num_clicks = eventLoopParams.num_clicks

        for event in eventList:
            t = Scheduler.timestamp()
            event.dict['time'] = t
            event.dict['local'] = getattr(event, 'pos', (0, 0))
            eventType = event.type
            if eventType == QUIT:
                self.quit()
            elif eventType == MOUSEBUTTONDOWN:
                # print "RootWidget: MOUSEBUTTONDOWN: setting do_draw" ###
                do_draw = True
                if t - last_click_time <= AlbowEventLoop.DOUBLE_CLICK_TIME:
                    num_clicks += 1
                else:
                    num_clicks = 1
                last_click_time = t
                event.dict['num_clicks'] = num_clicks
                CoreUtilities.add_modifiers(event)
                RootWidget.last_mouse_event = event
                self.logger.debug(f"num_clicks: '{num_clicks}' -- t: '{t}' -- last_click_time: '{last_click_time}'")

                if relativeMode:
                    event.dict['local'] = (0, 0)
                    if relative_pause:
                        relative_pause = False
                    else:
                        #  modal_widget.dispatch_key('mouse_down', event)
                        mouse_widget = self.modal_widget.get_focus()
                        RootWidget.clicked_widget = mouse_widget
                        RootWidget.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_event('mouse_down', event)
                else:
                    mouse_widget = self.containingWidget.find_widget(event.pos)
                    if not mouse_widget.is_inside(self.modal_widget):
                        mouse_widget = self.modal_widget
                    RootWidget.clicked_widget = mouse_widget
                    RootWidget.last_mouse_event_handler = mouse_widget
                    mouse_widget.notify_attention_loss()
                    mouse_widget.handle_mouse('mouse_down', event)
            elif eventType == MOUSEMOTION:
                CoreUtilities.add_modifiers(event)
                RootWidget.last_mouse_event = event

                if relativeMode:
                    event.dict['local'] = (0, 0)
                    if not relative_pause:
                        if relative_warmup:
                            relative_warmup -= 1
                        else:
                            #  modal_widget.dispatch_key('mouse_delta', event)
                            mouse_widget = RootWidget.clicked_widget or self.modal_widget.get_focus()
                            RootWidget.last_mouse_event_handler = mouse_widget
                            mouse_widget.handle_event('mouse_delta', event)
                else:
                    mouse_widget = self.containingWidget.find_widget(event.pos)  # Do this in else branch?
                    if RootWidget.clicked_widget:
                        RootWidget.last_mouse_event_handler = mouse_widget  # Should this be clicked_widget?
                        RootWidget.clicked_widget.handle_mouse('mouse_drag', event)
                    else:
                        if not mouse_widget.is_inside(self.modal_widget):
                            mouse_widget = self.modal_widget
                        RootWidget.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_mouse('mouse_move', event)
            elif eventType == MOUSEBUTTONUP:
                CoreUtilities.add_modifiers(event)
                RootWidget.last_mouse_event = event
                do_draw = True
                if relativeMode:
                    event.dict['local'] = (0, 0)
                    if not relative_pause:

                        if RootWidget.clicked_widget:
                            mouse_widget = RootWidget.clicked_widget
                            RootWidget.clicked_widget = None
                        else:
                            mouse_widget = self.modal_widget.get_focus()
                        RootWidget.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_event('mouse_up', event)
                else:
                    if RootWidget.clicked_widget:
                        RootWidget.last_mouse_event_handler = RootWidget.clicked_widget
                        RootWidget.clicked_widget = None
                        RootWidget.last_mouse_event_handler.handle_mouse('mouse_up', event)
            elif eventType == KEYDOWN:
                key = event.key
                if key == K_ESCAPE and relativeMode and event.mod & KMOD_CTRL and event.mod & KMOD_SHIFT:
                    relative_pause = True
                elif relative_pause:
                    relative_pause = False
                else:
                    CoreUtilities.set_modifier(key, True)

                    do_draw = True
                    self.send_key(self.modal_widget, 'key_down', event)
                    if RootWidget.last_mouse_event_handler:
                        event.dict['pos'] = RootWidget.last_mouse_event.pos
                        event.dict['local'] = RootWidget.last_mouse_event.local
                        RootWidget.last_mouse_event_handler.setup_cursor(event)
            elif eventType == KEYUP:
                key = event.key
                CoreUtilities.set_modifier(key, False)

                do_draw = True
                self.send_key(self.modal_widget, 'key_up', event)
                if RootWidget.last_mouse_event_handler:
                    event.dict['pos'] = RootWidget.last_mouse_event.pos
                    event.dict['local'] = RootWidget.last_mouse_event.local
                    RootWidget.last_mouse_event_handler.setup_cursor(event)
            elif eventType == AlbowEventLoop.MUSIC_END_EVENT:
                self.music_end()
            elif eventType == USEREVENT:
                if deferDrawing and not use_sleep:
                    RootWidget.ourTimerEvent = event
            else:
                #
                # Maybe someone has registered some user events handler
                #
                userEventCallList = RootWidget.getUserEventList()
                for cb in userEventCallList:
                    if cb.userEvent == eventType:
                        self.logger.debug(f"API User eventType: {eventType}")
                        cb.func(event)

        retEventLoopParams: EventLoopParams = EventLoopParams(use_sleep=use_sleep,
                                                              relative_pause=relative_pause,
                                                              do_draw=do_draw,
                                                              relative_warmup=relative_warmup,
                                                              last_click_time=last_click_time,
                                                              num_clicks=num_clicks)

        return retEventLoopParams

    def send_key(self, theWidget: Widget, theName: str, theEvent: Event):

        CoreUtilities.add_modifiers(theEvent)
        theWidget.dispatch_key(theName, theEvent)

    def music_end(self):
        MusicUtilities.music_end()

    def quit(self):
        #
        # call quit handler
        sys.exit()

Class variables

var DOUBLE_CLICK_TIME

Time is in milliseconds

var MUSIC_END_EVENT

API consumer user events MUST start there events after this one

Methods

def music_end(self)
Source code
def music_end(self):
    MusicUtilities.music_end()
def processEvents(self, eventList, relativeMode, deferDrawing, eventLoopParams)
Source code
def processEvents(self, eventList: List[Event], relativeMode: bool, deferDrawing: bool, eventLoopParams: EventLoopParams) -> EventLoopParams:

    self.logger.debug(f"Events to process: {len(eventList)}")

    use_sleep = eventLoopParams.use_sleep
    relative_pause = eventLoopParams.relative_pause
    do_draw = eventLoopParams.do_draw
    relative_warmup = eventLoopParams.relative_warmup
    last_click_time = eventLoopParams.last_click_time
    num_clicks = eventLoopParams.num_clicks

    for event in eventList:
        t = Scheduler.timestamp()
        event.dict['time'] = t
        event.dict['local'] = getattr(event, 'pos', (0, 0))
        eventType = event.type
        if eventType == QUIT:
            self.quit()
        elif eventType == MOUSEBUTTONDOWN:
            # print "RootWidget: MOUSEBUTTONDOWN: setting do_draw" ###
            do_draw = True
            if t - last_click_time <= AlbowEventLoop.DOUBLE_CLICK_TIME:
                num_clicks += 1
            else:
                num_clicks = 1
            last_click_time = t
            event.dict['num_clicks'] = num_clicks
            CoreUtilities.add_modifiers(event)
            RootWidget.last_mouse_event = event
            self.logger.debug(f"num_clicks: '{num_clicks}' -- t: '{t}' -- last_click_time: '{last_click_time}'")

            if relativeMode:
                event.dict['local'] = (0, 0)
                if relative_pause:
                    relative_pause = False
                else:
                    #  modal_widget.dispatch_key('mouse_down', event)
                    mouse_widget = self.modal_widget.get_focus()
                    RootWidget.clicked_widget = mouse_widget
                    RootWidget.last_mouse_event_handler = mouse_widget
                    mouse_widget.handle_event('mouse_down', event)
            else:
                mouse_widget = self.containingWidget.find_widget(event.pos)
                if not mouse_widget.is_inside(self.modal_widget):
                    mouse_widget = self.modal_widget
                RootWidget.clicked_widget = mouse_widget
                RootWidget.last_mouse_event_handler = mouse_widget
                mouse_widget.notify_attention_loss()
                mouse_widget.handle_mouse('mouse_down', event)
        elif eventType == MOUSEMOTION:
            CoreUtilities.add_modifiers(event)
            RootWidget.last_mouse_event = event

            if relativeMode:
                event.dict['local'] = (0, 0)
                if not relative_pause:
                    if relative_warmup:
                        relative_warmup -= 1
                    else:
                        #  modal_widget.dispatch_key('mouse_delta', event)
                        mouse_widget = RootWidget.clicked_widget or self.modal_widget.get_focus()
                        RootWidget.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_event('mouse_delta', event)
            else:
                mouse_widget = self.containingWidget.find_widget(event.pos)  # Do this in else branch?
                if RootWidget.clicked_widget:
                    RootWidget.last_mouse_event_handler = mouse_widget  # Should this be clicked_widget?
                    RootWidget.clicked_widget.handle_mouse('mouse_drag', event)
                else:
                    if not mouse_widget.is_inside(self.modal_widget):
                        mouse_widget = self.modal_widget
                    RootWidget.last_mouse_event_handler = mouse_widget
                    mouse_widget.handle_mouse('mouse_move', event)
        elif eventType == MOUSEBUTTONUP:
            CoreUtilities.add_modifiers(event)
            RootWidget.last_mouse_event = event
            do_draw = True
            if relativeMode:
                event.dict['local'] = (0, 0)
                if not relative_pause:

                    if RootWidget.clicked_widget:
                        mouse_widget = RootWidget.clicked_widget
                        RootWidget.clicked_widget = None
                    else:
                        mouse_widget = self.modal_widget.get_focus()
                    RootWidget.last_mouse_event_handler = mouse_widget
                    mouse_widget.handle_event('mouse_up', event)
            else:
                if RootWidget.clicked_widget:
                    RootWidget.last_mouse_event_handler = RootWidget.clicked_widget
                    RootWidget.clicked_widget = None
                    RootWidget.last_mouse_event_handler.handle_mouse('mouse_up', event)
        elif eventType == KEYDOWN:
            key = event.key
            if key == K_ESCAPE and relativeMode and event.mod & KMOD_CTRL and event.mod & KMOD_SHIFT:
                relative_pause = True
            elif relative_pause:
                relative_pause = False
            else:
                CoreUtilities.set_modifier(key, True)

                do_draw = True
                self.send_key(self.modal_widget, 'key_down', event)
                if RootWidget.last_mouse_event_handler:
                    event.dict['pos'] = RootWidget.last_mouse_event.pos
                    event.dict['local'] = RootWidget.last_mouse_event.local
                    RootWidget.last_mouse_event_handler.setup_cursor(event)
        elif eventType == KEYUP:
            key = event.key
            CoreUtilities.set_modifier(key, False)

            do_draw = True
            self.send_key(self.modal_widget, 'key_up', event)
            if RootWidget.last_mouse_event_handler:
                event.dict['pos'] = RootWidget.last_mouse_event.pos
                event.dict['local'] = RootWidget.last_mouse_event.local
                RootWidget.last_mouse_event_handler.setup_cursor(event)
        elif eventType == AlbowEventLoop.MUSIC_END_EVENT:
            self.music_end()
        elif eventType == USEREVENT:
            if deferDrawing and not use_sleep:
                RootWidget.ourTimerEvent = event
        else:
            #
            # Maybe someone has registered some user events handler
            #
            userEventCallList = RootWidget.getUserEventList()
            for cb in userEventCallList:
                if cb.userEvent == eventType:
                    self.logger.debug(f"API User eventType: {eventType}")
                    cb.func(event)

    retEventLoopParams: EventLoopParams = EventLoopParams(use_sleep=use_sleep,
                                                          relative_pause=relative_pause,
                                                          do_draw=do_draw,
                                                          relative_warmup=relative_warmup,
                                                          last_click_time=last_click_time,
                                                          num_clicks=num_clicks)

    return retEventLoopParams
def quit(self)
Source code
def quit(self):
    #
    # call quit handler
    sys.exit()
def send_key(self, theWidget, theName, theEvent)
Source code
def send_key(self, theWidget: Widget, theName: str, theEvent: Event):

    CoreUtilities.add_modifiers(theEvent)
    theWidget.dispatch_key(theName, theEvent)