This implements an iterable root-widget for Albow.   Sometimes the monolithic ‘run’ is fine, sometimes you want your own main loop.    This is basically Greg Ewings .run_modal() code, reorganized as multiple methods.  The methods to call are .run_start() once, .process_input() when relevant events are available,  and .draw_gui() at each frame (or when redrawing is necessary).

from albow import root
from pygame.locals import *
from pygame.event import Event
import pygame

class NewRootWidget(root.RootWidget):

    def __init__(self, surface):
        root.RootWidget.__init__(self, surface)
        self._progen = None
        self.bg_color = None

    def run_modal(self, modal_widget):
        #print 'new root widget'
        self.run_start(modal_widget)
        while True:
            events = [pygame.event.wait()]
            events.extend(pygame.event.get())
            self.process_input(events)
            if redraw:
                self.draw_gui()

    def run_start(self, modal_widget):
        self._progen = self._input_process_generator(modal_widget)
        self._progen.next()

    def process_input(self, events):
        """process mouse and keyboard events.
        @param events: a list or tuple of pygame events
        @returns: True if any widgets need redrawing, otherwise False
        """
        return self._progen.send(events)

    def _input_process_generator(self, modal_widget):
        is_modal = modal_widget is not None
        modal_widget = modal_widget or self

        old_top_widget = root.top_widget
        root.top_widget = modal_widget
        was_modal = modal_widget.is_modal
        modal_widget.is_modal = True
        # modal_widget.modal_result = None
        if not modal_widget.focus_switch:
            modal_widget.tab_to_first()
        # mouse_widget = None
        if root.clicked_widget:
            root.clicked_widget = modal_widget
        num_clicks = 0
        last_click_time = 0
        do_draw = True

        events = []
        while True:
            for event in events:
                type = event.type
                if type == QUIT:
                    self.quit()
                elif type == MOUSEBUTTONDOWN:
                    do_draw = True
                    t = root.get_ticks()
                    if t - last_click_time <= root.double_click_time:
                        num_clicks += 1
                    else:
                        num_clicks = 1
                    last_click_time = t
                    event.dict['num_clicks'] = num_clicks
                    root.add_modifiers(event)
                    mouse_widget = self.find_widget(event.pos)
                    if not mouse_widget.is_inside(modal_widget):
                        mouse_widget = modal_widget
                    root.clicked_widget = mouse_widget
                    root.last_mouse_event_handler = mouse_widget
                    root.last_mouse_event = event
                    mouse_widget.notify_attention_loss()
                    mouse_widget.handle_mouse('mouse_down', event)
                elif type == MOUSEMOTION:
                    root.add_modifiers(event)
                    modal_widget.dispatch_key('mouse_delta', event)
                    mouse_widget = self.find_widget(event.pos)
                    root.last_mouse_event = event
                    if root.clicked_widget:
                        root.last_mouse_event_handler = mouse_widget
                        root.clicked_widget.handle_mouse('mouse_drag', event)
                    else:
                        if not mouse_widget.is_inside(modal_widget):
                            mouse_widget = modal_widget
                        root.last_mouse_event_handler = mouse_widget
                        mouse_widget.handle_mouse('mouse_move', event)
                elif type == MOUSEBUTTONUP:
                    root.add_modifiers(event)
                    do_draw = True
                    #mouse_widget = self.find_widget(event.pos)
                    if root.clicked_widget:
                        root.last_mouse_event_handler = root.clicked_widget
                        root.last_mouse_event = event
                        root.clicked_widget = None
                        root.last_mouse_event_handler.handle_mouse('mouse_up', event)
                elif type == KEYDOWN:
                    key = event.key
                    root.set_modifier(key, True)
                    do_draw = True
                    self.send_key(modal_widget, 'key_down', event)
                    if root.last_mouse_event_handler:
                        event.dict['pos'] = root.last_mouse_event.pos
                        event.dict['local'] = root.last_mouse_event.local
                        root.last_mouse_event_handler.setup_cursor(event)
                elif type == KEYUP:
                    key = event.key
                    root.set_modifier(key, False)
                    do_draw = True
                    self.send_key(modal_widget, 'key_up', event)
                    if root.last_mouse_event_handler:
                        event.dict['pos'] = root.last_mouse_event.pos
                        event.dict['local'] = root.last_mouse_event.local
                        root.last_mouse_event_handler.setup_cursor(event)
                elif type == root.MUSIC_END_EVENT:
                    self.music_end()
                elif type == USEREVENT:
                    root.make_scheduled_calls()
                    if not is_modal:
                        do_draw = self.redraw_every_frame
                        if root.last_mouse_event_handler:
                            event.dict['pos'] = root.last_mouse_event.pos
                            event.dict['local'] = root.last_mouse_event.local
                            root.add_modifiers(event)
                            root.last_mouse_event_handler.setup_cursor(event)
                        self.begin_frame()
            events = yield do_draw

        modal_widget.is_modal = was_modal
        root.top_widget = old_top_widget
        root.clicked_widget = None

    def draw_gui(self):
        if self.is_gl:
            self.gl_clear()
            self.gl_draw_all(self, (0, 0))
        else:
            self.draw_all(self.surface)
        pygame.display.flip()
Advertisements