Exemplo n.º 1
0
 def painter_test2(n, lines, columns, fps = 25000):
     # test main-thread execution (previewer run as main thread): 
     preview = Preview(title = "Main-thread test without diagram", 
                       lines = lines, columns = columns, fps_limit = fps,
                       painter_class = TestPainter)
     timer = Timer(0.1)
     preview.interactive(True)
     preview.start()
     step = 0
     # create tests in different threads
     while True:
         step += 1
         preview.set_title("Test #" + str(step) + " ADD-del inverse order")
         painters = []
         for i in xrange(0,n):
             painters.append(preview.add_view(i))
             while timer.idle(): 
                 if not preview.step():
                     return
         preview.set_title("Test #" + str(step) + " add-DEL inverse order")
         while len(painters) > 0:
             preview.del_view(painters.pop())
             while timer.idle(): 
                 if not preview.step():
                     return
         preview.set_title("Test #" + str(step) + " ADD-del direct order")
         painters = []
         for i in xrange(0,n):
             painters.append(preview.add_view(i))
             while timer.idle(): 
                 if not preview.step():
                     return
         preview.set_title("Test #" + str(step) + " add-DEL direct order")
         for i in xrange(0,n):
             preview.del_view(painters[i])
             while timer.idle(): 
                 if not preview.step():
                     return
         preview.set_title("Test #" + str(step) + " ADD-del random order")
         painters = []
         for i in xrange(0,n):
             painters.append(preview.add_view(i))
             while timer.idle(): 
                 if not preview.step():
                     return
         preview.set_title("Test #" + str(step) + " add-DEL random order")
         while len(painters) > 0:
             i = random.randint(0, len(painters) - 1)
             preview.del_view(painters[i])
             del painters[i]
             while timer.idle(): 
                 if not preview.step():
                     return
Exemplo n.º 2
0
class Preview(threading.Thread): 
    '''
    Preview is a thread object that act as a pygame display control
    PyGame issue on Windows (and possibly other OS than Linux):
        In Windows OS, pygame just collects events in a main therad.
        Then, the application must instatiate the Preview 
        and maint it's controler
    '''

    NONE = -1
    STARTING = 0
    RUNNING = 1
    STOPPING = 2
    KILLED = 3
    
    preview_control = None
    
    def __init__(self, title = "Grid visualizer", 
                 width = PreviewDefaults.width, 
                 height = PreviewDefaults.height,
                 lines = 2, columns = 2, fps_limit = 0,
                 painter_class = Painter):
        # state control
        self.state = Preview.STARTING
        self.default_painter_class = painter_class
        # thread control
        self.threading = True
        # Window app control
        self.width = width
        self.height = height
        self.bgcolor = Color.BLACK
        self.display = pygame.display.set_mode((width + 
                                                VerticalScroll.BUTTOM_SIZE, 
                                                height), 
                                               pygame.HWSURFACE | 
                                               pygame.DOUBLEBUF)
        pygame.display.set_caption(title)
        # diagram selector
        lines = max([1, int(lines)])
        columns = max([1, int(columns)])
        self.grid = Grid(self.display, lines, columns)
        self.mouse_drag = False
        self.key_pressed = None
        # timer control (to pause, FPS, keyboard)
        self.fps_limit = fps_limit
        self.frame_timer = Timer(0)
        if self.fps_limit > 0:
            self.frame_timer.set_delay(1.0 / self.fps_limit)
        self.key_repeat_delay = 1.0 / 2.0
        self.key_repeat_rate  = 1.0 / 10.0
        self.keyboard_timer = Timer(0)
        # count number of painters/objects
        self.count_painters = 0
        # map object to painter
        self.views = dict()
        # multi-thread control
        self.lock = threading.Lock()
    
    def panel_dimensions(self):
        '''
        Get panel dimensions
        '''
        return self.grid.panel_width, self.grid.panel_height

    def set_title(self, title):
        '''
        Change app window caption
        '''
        pygame.display.set_caption(title)
    
    def add_view(self, view, label='', painter_class = None):
        '''
        Include a diagram in previewer
        '''
        assert view is not None
        with self.lock:
            # prevent drawing duplication of same object 
            if view in self.views:
                return False
            # create a painter to object
            if painter_class is None:
                painter = self.default_painter_class(self.count_painters, 
                                                     view, label)
            else:
                painter = painter_class(self.count_painters, view, label)
            self.count_painters += 1
            # make control 
            self.grid.add_painter(painter)
            self.views[view] = painter
            return view
        
    def del_view(self, view):
        assert view is not None
        with self.lock:
            if view in self.views:
                painter = self.views[view]
                self.grid.del_painter(painter)
                del self.views[view]

    def pause(self, delay = 0.0):
        '''
        Defines a idle time to previewer
        '''
        self.frame_timer.pause(delay)

    def stop(self):
        '''
        Request the termination of panel
        '''
        self.state = Preview.KILLED

    def is_running(self):
        '''
        Verify if previewer state is RUNNING
        '''
        return self.state == Preview.RUNNING

    def interactive(self, interact):
        '''
        Defines if previewer works as a separate thread or not
        '''
        if self.state == Preview.STARTING:
            self.threading = not interact

    def start(self):
        '''
        Starts previewer
        '''
        # Initialization
        pygame.init()
        self.state = Preview.RUNNING
        if self.threading:
            threading.Thread.__init__(self)
            threading.Thread.start(self)

    def run(self):
        '''
        Run previewer continuously until it's received a termination sign
        '''
        while self.step():
            pass

    def step(self):
        '''
        Executes a step (maybe with a frame drawing) and responds to the events
        Useful in mono threading applications (or main thread), 
        which other class controls the execution and calls this method
        '''
        # exit if don't run
        if self.state != Preview.RUNNING:
            return False
        # simple concurrence control
        with self.lock:
            # pre-process the buffered events 
            self._process_events()
            # if don't need to force, verify timer (FPS limit)
            if self.frame_timer.idle(): 
                return True
            # select a panel
            painter, panel, index, changed = self.grid.nextPainter()
            # if selector change, force to draw
            if changed:
                # if painter is None, just clear the panel
                if painter is None:
                    panel.fill(self.bgcolor)
                else:
                    painter.draw(panel, index)
            else:
                # if painter is None, there's nothing to do
                if painter is None:
                    return True
                else:
                    # painter was changed since last frame?
                    if painter.changed():
                        painter.draw(panel, index)
                    else:
                        return True  # go to next step
            panel.draw()
            pygame.display.flip()
            return True

    def _process_events(self):
        '''
        Take actions in response to the events
        '''
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.state = Preview.STOPPING
            elif event.type == pygame.MOUSEBUTTONDOWN:
                self.mouse_drag = True
                if self.grid.select(event.pos):
                    self.update_selector()
            elif  event.type == pygame.MOUSEMOTION:
                if self.mouse_drag:
                    if self.grid.select(event.pos):
                        self.update_selector()
            elif event.type == pygame.MOUSEBUTTONUP:
                self.mouse_drag = False
            elif event.type == pygame.KEYDOWN:
                self.key_pressed = event.key
                self.keyboard_timer.set_delay(self.key_repeat_delay)
                self._process_key(self.key_pressed)
            elif event.type == pygame.KEYUP:
                self.key_pressed = None
                self.keyboard_timer.set_delay(0)
        # process key events
        if self.key_pressed is not None and not self.keyboard_timer.idle():
            self.keyboard_timer.set_delay(self.key_repeat_rate)
            self._process_key(self.key_pressed)
            
    def _process_key(self, key):
        if key == pygame.K_DOWN:
            self.grid.line_down()
        elif key == pygame.K_UP:
            self.grid.line_up()
        elif key == pygame.K_PAGEDOWN:
            self.grid.page_down()
        elif key == pygame.K_PAGEUP:
            self.grid.page_up()