1683 lines
58 KiB
Python
1683 lines
58 KiB
Python
|
# ----------------------------------------------------------------------------
|
||
|
# pyglet
|
||
|
# Copyright (c) 2006-2008 Alex Holkner
|
||
|
# All rights reserved.
|
||
|
#
|
||
|
# Redistribution and use in source and binary forms, with or without
|
||
|
# modification, are permitted provided that the following conditions
|
||
|
# are met:
|
||
|
#
|
||
|
# * Redistributions of source code must retain the above copyright
|
||
|
# notice, this list of conditions and the following disclaimer.
|
||
|
# * Redistributions in binary form must reproduce the above copyright
|
||
|
# notice, this list of conditions and the following disclaimer in
|
||
|
# the documentation and/or other materials provided with the
|
||
|
# distribution.
|
||
|
# * Neither the name of pyglet nor the names of its
|
||
|
# contributors may be used to endorse or promote products
|
||
|
# derived from this software without specific prior written
|
||
|
# permission.
|
||
|
#
|
||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||
|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||
|
# ----------------------------------------------------------------------------
|
||
|
|
||
|
'''Windowing and user-interface events.
|
||
|
|
||
|
This module allows applications to create and display windows with an
|
||
|
OpenGL context. Windows can be created with a variety of border styles
|
||
|
or set fullscreen.
|
||
|
|
||
|
You can register event handlers for keyboard, mouse and window events.
|
||
|
For games and kiosks you can also restrict the input to your windows,
|
||
|
for example disabling users from switching away from the application
|
||
|
with certain key combinations or capturing and hiding the mouse.
|
||
|
|
||
|
Getting started
|
||
|
---------------
|
||
|
|
||
|
Call the Window constructor to create a new window::
|
||
|
|
||
|
from pyglet.window import Window
|
||
|
win = Window(width=640, height=480)
|
||
|
|
||
|
Attach your own event handlers::
|
||
|
|
||
|
@win.event
|
||
|
def on_key_press(symbol, modifiers):
|
||
|
# ... handle this event ...
|
||
|
|
||
|
Place drawing code for the window within the `Window.on_draw` event handler::
|
||
|
|
||
|
@win.event
|
||
|
def on_draw():
|
||
|
# ... drawing code ...
|
||
|
|
||
|
Call `pyglet.app.run` to enter the main event loop (by default, this
|
||
|
returns when all open windows are closed)::
|
||
|
|
||
|
from pyglet import app
|
||
|
app.run()
|
||
|
|
||
|
Creating a game window
|
||
|
----------------------
|
||
|
|
||
|
Use `Window.set_exclusive_mouse` to hide the mouse cursor and receive relative
|
||
|
mouse movement events. Specify ``fullscreen=True`` as a keyword argument to
|
||
|
the `Window` constructor to render to the entire screen rather than opening a
|
||
|
window::
|
||
|
|
||
|
win = Window(fullscreen=True)
|
||
|
win.set_exclusive_mouse()
|
||
|
|
||
|
Working with multiple screens
|
||
|
-----------------------------
|
||
|
|
||
|
By default, fullscreen windows are opened on the primary display (typically
|
||
|
set by the user in their operating system settings). You can retrieve a list
|
||
|
of attached screens and select one manually if you prefer. This is useful for
|
||
|
opening a fullscreen window on each screen::
|
||
|
|
||
|
display = window.get_platform().get_default_display()
|
||
|
screens = display.get_screens()
|
||
|
windows = []
|
||
|
for screen in screens:
|
||
|
windows.append(window.Window(fullscreen=True, screen=screen))
|
||
|
|
||
|
Specifying a screen has no effect if the window is not fullscreen.
|
||
|
|
||
|
Specifying the OpenGL context properties
|
||
|
----------------------------------------
|
||
|
|
||
|
Each window has its own context which is created when the window is created.
|
||
|
You can specify the properties of the context before it is created
|
||
|
by creating a "template" configuration::
|
||
|
|
||
|
from pyglet import gl
|
||
|
# Create template config
|
||
|
config = gl.Config()
|
||
|
config.stencil_size = 8
|
||
|
config.aux_buffers = 4
|
||
|
# Create a window using this config
|
||
|
win = window.Window(config=config)
|
||
|
|
||
|
To determine if a given configuration is supported, query the screen (see
|
||
|
above, "Working with multiple screens")::
|
||
|
|
||
|
configs = screen.get_matching_configs(config)
|
||
|
if not configs:
|
||
|
# ... config is not supported
|
||
|
else:
|
||
|
win = window.Window(config=configs[0])
|
||
|
|
||
|
'''
|
||
|
|
||
|
__docformat__ = 'restructuredtext'
|
||
|
__version__ = '$Id: __init__.py 2215 2008-08-24 04:53:34Z Alex.Holkner $'
|
||
|
|
||
|
import pprint
|
||
|
import sys
|
||
|
|
||
|
import pyglet
|
||
|
from pyglet import gl
|
||
|
from pyglet.gl import gl_info
|
||
|
from pyglet.event import EventDispatcher
|
||
|
import pyglet.window.key
|
||
|
|
||
|
class WindowException(Exception):
|
||
|
'''The root exception for all window-related errors.'''
|
||
|
pass
|
||
|
|
||
|
class NoSuchDisplayException(WindowException):
|
||
|
'''An exception indicating the requested display is not available.'''
|
||
|
pass
|
||
|
|
||
|
class NoSuchConfigException(WindowException):
|
||
|
'''An exception indicating the requested configuration is not
|
||
|
available.'''
|
||
|
pass
|
||
|
|
||
|
class MouseCursorException(WindowException):
|
||
|
'''The root exception for all mouse cursor-related errors.'''
|
||
|
pass
|
||
|
|
||
|
class Platform(object):
|
||
|
'''Operating-system-level functionality.
|
||
|
|
||
|
The platform instance can only be obtained with `get_platform`. Use
|
||
|
the platform to obtain a `Display` instance.
|
||
|
'''
|
||
|
def get_display(self, name):
|
||
|
'''Get a display device by name.
|
||
|
|
||
|
This is meaningful only under X11, where the `name` is a
|
||
|
string including the host name and display number; for example
|
||
|
``"localhost:1"``.
|
||
|
|
||
|
On platforms other than X11, `name` is ignored and the default
|
||
|
display is returned. pyglet does not support multiple multiple
|
||
|
video devices on Windows or OS X. If more than one device is
|
||
|
attached, they will appear as a single virtual device comprising
|
||
|
all the attached screens.
|
||
|
|
||
|
:Parameters:
|
||
|
`name` : str
|
||
|
The name of the display to connect to.
|
||
|
|
||
|
:rtype: `Display`
|
||
|
'''
|
||
|
return get_default_display()
|
||
|
|
||
|
def get_default_display(self):
|
||
|
'''Get the default display device.
|
||
|
|
||
|
:rtype: `Display`
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
class Display(object):
|
||
|
'''A display device supporting one or more screens.
|
||
|
|
||
|
Use `Platform.get_display` or `Platform.get_default_display` to obtain
|
||
|
an instance of this class. Use a display to obtain `Screen` instances.
|
||
|
'''
|
||
|
def __init__(self):
|
||
|
from pyglet import app
|
||
|
app.displays.add(self)
|
||
|
|
||
|
def get_screens(self):
|
||
|
'''Get the available screens.
|
||
|
|
||
|
A typical multi-monitor workstation comprises one `Display` with
|
||
|
multiple `Screen` s. This method returns a list of screens which
|
||
|
can be enumerated to select one for full-screen display.
|
||
|
|
||
|
For the purposes of creating an OpenGL config, the default screen
|
||
|
will suffice.
|
||
|
|
||
|
:rtype: list of `Screen`
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def get_default_screen(self):
|
||
|
'''Get the default screen as specified by the user's operating system
|
||
|
preferences.
|
||
|
|
||
|
:rtype: `Screen`
|
||
|
'''
|
||
|
return self.get_screens()[0]
|
||
|
|
||
|
def get_windows(self):
|
||
|
'''Get the windows currently attached to this display.
|
||
|
|
||
|
:rtype: sequence of `Window`
|
||
|
'''
|
||
|
from pyglet import app
|
||
|
return [window for window in app.windows if window.display is self]
|
||
|
|
||
|
class Screen(object):
|
||
|
'''A virtual monitor that supports fullscreen windows.
|
||
|
|
||
|
Screens typically map onto a physical display such as a
|
||
|
monitor, television or projector. Selecting a screen for a window
|
||
|
has no effect unless the window is made fullscreen, in which case
|
||
|
the window will fill only that particular virtual screen.
|
||
|
|
||
|
The `width` and `height` attributes of a screen give the current
|
||
|
resolution of the screen. The `x` and `y` attributes give the global
|
||
|
location of the top-left corner of the screen. This is useful for
|
||
|
determining if screens arranged above or next to one another.
|
||
|
|
||
|
You cannot always rely on the origin to give the placement of monitors.
|
||
|
For example, an X server with two displays without Xinerama enabled
|
||
|
will present two logically separate screens with no relation to each
|
||
|
other.
|
||
|
|
||
|
Use `Display.get_screens` or `Display.get_default_screen` to obtain an
|
||
|
instance of this class.
|
||
|
|
||
|
:Ivariables:
|
||
|
`x` : int
|
||
|
Left edge of the screen on the virtual desktop.
|
||
|
`y` : int
|
||
|
Top edge of the screen on the virtual desktop.
|
||
|
`width` : int
|
||
|
Width of the screen, in pixels.
|
||
|
`height` : int
|
||
|
Height of the screen, in pixels.
|
||
|
|
||
|
'''
|
||
|
|
||
|
def __init__(self, x, y, width, height):
|
||
|
self.x = x
|
||
|
self.y = y
|
||
|
self.width = width
|
||
|
self.height = height
|
||
|
|
||
|
def __repr__(self):
|
||
|
return '%s(x=%d, y=%d, width=%d, height=%d)' % \
|
||
|
(self.__class__.__name__, self.x, self.y, self.width, self.height)
|
||
|
|
||
|
def get_best_config(self, template=None):
|
||
|
'''Get the best available GL config.
|
||
|
|
||
|
Any required attributes can be specified in `template`. If
|
||
|
no configuration matches the template, `NoSuchConfigException` will
|
||
|
be raised.
|
||
|
|
||
|
:Parameters:
|
||
|
`template` : `pyglet.gl.Config`
|
||
|
A configuration with desired attributes filled in.
|
||
|
|
||
|
:rtype: `pyglet.gl.Config`
|
||
|
:return: A configuration supported by the platform that best
|
||
|
fulfils the needs described by the template.
|
||
|
'''
|
||
|
if template is None:
|
||
|
template = gl.Config()
|
||
|
configs = self.get_matching_configs(template)
|
||
|
if not configs:
|
||
|
raise NoSuchConfigException()
|
||
|
return configs[0]
|
||
|
|
||
|
def get_matching_configs(self, template):
|
||
|
'''Get a list of configs that match a specification.
|
||
|
|
||
|
Any attributes specified in `template` will have values equal
|
||
|
to or greater in each returned config. If no configs satisfy
|
||
|
the template, an empty list is returned.
|
||
|
|
||
|
:Parameters:
|
||
|
`template` : `pyglet.gl.Config`
|
||
|
A configuration with desired attributes filled in.
|
||
|
|
||
|
:rtype: list of `pyglet.gl.Config`
|
||
|
:return: A list of matching configs.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
class MouseCursor(object):
|
||
|
'''An abstract mouse cursor.'''
|
||
|
|
||
|
#: Indicates if the cursor is drawn using OpenGL. This is True
|
||
|
#: for all mouse cursors except system cursors.
|
||
|
drawable = True
|
||
|
|
||
|
def draw(self, x, y):
|
||
|
'''Abstract render method.
|
||
|
|
||
|
The cursor should be drawn with the "hot" spot at the given
|
||
|
coordinates. The projection is set to the pyglet default (i.e.,
|
||
|
orthographic in window-space), however no other aspects of the
|
||
|
state can be assumed.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
X coordinate of the mouse pointer's hot spot.
|
||
|
`y` : int
|
||
|
Y coordinate of the mouse pointer's hot spot.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
class DefaultMouseCursor(MouseCursor):
|
||
|
'''The default mouse cursor used by the operating system.'''
|
||
|
drawable = False
|
||
|
|
||
|
class ImageMouseCursor(MouseCursor):
|
||
|
'''A user-defined mouse cursor created from an image.
|
||
|
|
||
|
Use this class to create your own mouse cursors and assign them
|
||
|
to windows. There are no constraints on the image size or format.
|
||
|
'''
|
||
|
drawable = True
|
||
|
|
||
|
def __init__(self, image, hot_x=0, hot_y=0):
|
||
|
'''Create a mouse cursor from an image.
|
||
|
|
||
|
:Parameters:
|
||
|
`image` : `pyglet.image.AbstractImage`
|
||
|
Image to use for the mouse cursor. It must have a
|
||
|
valid ``texture`` attribute.
|
||
|
`hot_x` : int
|
||
|
X coordinate of the "hot" spot in the image relative to the
|
||
|
image's anchor.
|
||
|
`hot_y` : int
|
||
|
Y coordinate of the "hot" spot in the image, relative to the
|
||
|
image's anchor.
|
||
|
'''
|
||
|
self.texture = image.get_texture()
|
||
|
self.hot_x = hot_x
|
||
|
self.hot_y = hot_y
|
||
|
|
||
|
def draw(self, x, y):
|
||
|
gl.glPushAttrib(gl.GL_ENABLE_BIT | gl.GL_CURRENT_BIT)
|
||
|
gl.glColor4f(1, 1, 1, 1)
|
||
|
gl.glEnable(gl.GL_BLEND)
|
||
|
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
|
||
|
self.texture.blit(x - self.hot_x, y - self.hot_y, 0)
|
||
|
gl.glPopAttrib()
|
||
|
|
||
|
def _PlatformEventHandler(data):
|
||
|
'''Decorator for platform event handlers.
|
||
|
|
||
|
Apply giving the platform-specific data needed by the window to associate
|
||
|
the method with an event. See platform-specific subclasses of this
|
||
|
decorator for examples.
|
||
|
|
||
|
The following attributes are set on the function, which is returned
|
||
|
otherwise unchanged:
|
||
|
|
||
|
_platform_event
|
||
|
True
|
||
|
_platform_event_data
|
||
|
List of data applied to the function (permitting multiple decorators
|
||
|
on the same method).
|
||
|
'''
|
||
|
def _event_wrapper(f):
|
||
|
f._platform_event = True
|
||
|
if not hasattr(f, '_platform_event_data'):
|
||
|
f._platform_event_data = []
|
||
|
f._platform_event_data.append(data)
|
||
|
return f
|
||
|
return _event_wrapper
|
||
|
|
||
|
class _WindowMetaclass(type):
|
||
|
'''Sets the _platform_event_names class variable on the window
|
||
|
subclass.
|
||
|
'''
|
||
|
def __init__(cls, name, bases, dict):
|
||
|
cls._platform_event_names = set()
|
||
|
for base in bases:
|
||
|
if hasattr(base, '_platform_event_names'):
|
||
|
cls._platform_event_names.update(base._platform_event_names)
|
||
|
for name, func in dict.items():
|
||
|
if hasattr(func, '_platform_event'):
|
||
|
cls._platform_event_names.add(name)
|
||
|
super(_WindowMetaclass, cls).__init__(name, bases, dict)
|
||
|
|
||
|
class BaseWindow(EventDispatcher):
|
||
|
'''Platform-independent application window.
|
||
|
|
||
|
A window is a "heavyweight" object occupying operating system resources.
|
||
|
The "client" or "content" area of a window is filled entirely with
|
||
|
an OpenGL viewport. Applications have no access to operating system
|
||
|
widgets or controls; all rendering must be done via OpenGL.
|
||
|
|
||
|
Windows may appear as floating regions or can be set to fill an entire
|
||
|
screen (fullscreen). When floating, windows may appear borderless or
|
||
|
decorated with a platform-specific frame (including, for example, the
|
||
|
title bar, minimize and close buttons, resize handles, and so on).
|
||
|
|
||
|
While it is possible to set the location of a window, it is recommended
|
||
|
that applications allow the platform to place it according to local
|
||
|
conventions. This will ensure it is not obscured by other windows,
|
||
|
and appears on an appropriate screen for the user.
|
||
|
|
||
|
To render into a window, you must first call `switch_to`, to make
|
||
|
it the current OpenGL context. If you use only one window in the
|
||
|
application, there is no need to do this.
|
||
|
|
||
|
:Ivariables:
|
||
|
`has_exit` : bool
|
||
|
True if the user has attempted to close the window.
|
||
|
|
||
|
:deprecated: Windows are closed immediately by the default
|
||
|
`on_close` handler when `pyglet.app.event_loop` is being
|
||
|
used.
|
||
|
|
||
|
'''
|
||
|
__metaclass__ = _WindowMetaclass
|
||
|
|
||
|
# Filled in by metaclass with the names of all methods on this (sub)class
|
||
|
# that are platform event handlers.
|
||
|
_platform_event_names = set()
|
||
|
|
||
|
#: The default window style.
|
||
|
WINDOW_STYLE_DEFAULT = None
|
||
|
#: The window style for pop-up dialogs.
|
||
|
WINDOW_STYLE_DIALOG = 'dialog'
|
||
|
#: The window style for tool windows.
|
||
|
WINDOW_STYLE_TOOL = 'tool'
|
||
|
#: A window style without any decoration.
|
||
|
WINDOW_STYLE_BORDERLESS = 'borderless'
|
||
|
|
||
|
#: The default mouse cursor.
|
||
|
CURSOR_DEFAULT = None
|
||
|
#: A crosshair mouse cursor.
|
||
|
CURSOR_CROSSHAIR = 'crosshair'
|
||
|
#: A pointing hand mouse cursor.
|
||
|
CURSOR_HAND = 'hand'
|
||
|
#: A "help" mouse cursor; typically a question mark and an arrow.
|
||
|
CURSOR_HELP = 'help'
|
||
|
#: A mouse cursor indicating that the selected operation is not permitted.
|
||
|
CURSOR_NO = 'no'
|
||
|
#: A mouse cursor indicating the element can be resized.
|
||
|
CURSOR_SIZE = 'size'
|
||
|
#: A mouse cursor indicating the element can be resized from the top
|
||
|
#: border.
|
||
|
CURSOR_SIZE_UP = 'size_up'
|
||
|
#: A mouse cursor indicating the element can be resized from the
|
||
|
#: upper-right corner.
|
||
|
CURSOR_SIZE_UP_RIGHT = 'size_up_right'
|
||
|
#: A mouse cursor indicating the element can be resized from the right
|
||
|
#: border.
|
||
|
CURSOR_SIZE_RIGHT = 'size_right'
|
||
|
#: A mouse cursor indicating the element can be resized from the lower-right
|
||
|
#: corner.
|
||
|
CURSOR_SIZE_DOWN_RIGHT = 'size_down_right'
|
||
|
#: A mouse cursor indicating the element can be resized from the bottom
|
||
|
#: border.
|
||
|
CURSOR_SIZE_DOWN = 'size_down'
|
||
|
#: A mouse cursor indicating the element can be resized from the lower-left
|
||
|
#: corner.
|
||
|
CURSOR_SIZE_DOWN_LEFT = 'size_down_left'
|
||
|
#: A mouse cursor indicating the element can be resized from the left
|
||
|
#: border.
|
||
|
CURSOR_SIZE_LEFT = 'size_left'
|
||
|
#: A mouse cursor indicating the element can be resized from the upper-left
|
||
|
#: corner.
|
||
|
CURSOR_SIZE_UP_LEFT = 'size_up_left'
|
||
|
#: A mouse cursor indicating the element can be resized vertically.
|
||
|
CURSOR_SIZE_UP_DOWN = 'size_up_down'
|
||
|
#: A mouse cursor indicating the element can be resized horizontally.
|
||
|
CURSOR_SIZE_LEFT_RIGHT = 'size_left_right'
|
||
|
#: A text input mouse cursor (I-beam).
|
||
|
CURSOR_TEXT = 'text'
|
||
|
#: A "wait" mouse cursor; typically an hourglass or watch.
|
||
|
CURSOR_WAIT = 'wait'
|
||
|
#: The "wait" mouse cursor combined with an arrow.
|
||
|
CURSOR_WAIT_ARROW = 'wait_arrow'
|
||
|
|
||
|
has_exit = False
|
||
|
|
||
|
#: Window display contents validity. The `pyglet.app` event loop
|
||
|
#: examines every window each iteration and only dispatches the `on_draw`
|
||
|
#: event to windows that have `invalid` set. By default, windows always
|
||
|
#: have `invalid` set to ``True``.
|
||
|
#:
|
||
|
#: You can prevent redundant redraws by setting this variable to ``False``
|
||
|
#: in the window's `on_draw` handler, and setting it to True again in
|
||
|
#: response to any events that actually do require a window contents
|
||
|
#: update.
|
||
|
#:
|
||
|
#: :type: bool
|
||
|
#: :since: pyglet 1.1
|
||
|
invalid = True
|
||
|
|
||
|
# Instance variables accessible only via properties
|
||
|
|
||
|
_width = None
|
||
|
_height = None
|
||
|
_caption = None
|
||
|
_resizable = False
|
||
|
_style = WINDOW_STYLE_DEFAULT
|
||
|
_fullscreen = False
|
||
|
_visible = False
|
||
|
_vsync = False
|
||
|
_screen = None
|
||
|
_config = None
|
||
|
_context = None
|
||
|
|
||
|
# Used to restore window size and position after fullscreen
|
||
|
_windowed_size = None
|
||
|
_windowed_location = None
|
||
|
|
||
|
# Subclasses should update these after relevant events
|
||
|
_mouse_cursor = DefaultMouseCursor()
|
||
|
_mouse_x = 0
|
||
|
_mouse_y = 0
|
||
|
_mouse_visible = True
|
||
|
_mouse_exclusive = False
|
||
|
_mouse_in_window = True
|
||
|
|
||
|
_event_queue = None
|
||
|
_enable_event_queue = True # overridden by EventLoop.
|
||
|
_allow_dispatch_event = False # controlled by dispatch_events stack frame
|
||
|
|
||
|
# Class attributes
|
||
|
|
||
|
_default_width = 640
|
||
|
_default_height = 480
|
||
|
|
||
|
def __init__(self,
|
||
|
width=None,
|
||
|
height=None,
|
||
|
caption=None,
|
||
|
resizable=False,
|
||
|
style=WINDOW_STYLE_DEFAULT,
|
||
|
fullscreen=False,
|
||
|
visible=True,
|
||
|
vsync=True,
|
||
|
display=None,
|
||
|
screen=None,
|
||
|
config=None,
|
||
|
context=None):
|
||
|
'''Create a window.
|
||
|
|
||
|
All parameters are optional, and reasonable defaults are assumed
|
||
|
where they are not specified.
|
||
|
|
||
|
The `display`, `screen`, `config` and `context` parameters form
|
||
|
a hierarchy of control: there is no need to specify more than
|
||
|
one of these. For example, if you specify `screen` the `display`
|
||
|
will be inferred, and a default `config` and `context` will be
|
||
|
created.
|
||
|
|
||
|
`config` is a special case; it can be a template created by the
|
||
|
user specifying the attributes desired, or it can be a complete
|
||
|
`config` as returned from `Screen.get_matching_configs` or similar.
|
||
|
|
||
|
The context will be active as soon as the window is created, as if
|
||
|
`switch_to` was just called.
|
||
|
|
||
|
:Parameters:
|
||
|
`width` : int
|
||
|
Width of the window, in pixels. Not valid if `fullscreen`
|
||
|
is True. Defaults to 640.
|
||
|
`height` : int
|
||
|
Height of the window, in pixels. Not valid if `fullscreen`
|
||
|
is True. Defaults to 480.
|
||
|
`caption` : str or unicode
|
||
|
Initial caption (title) of the window. Defaults to
|
||
|
``sys.argv[0]``.
|
||
|
`resizable` : bool
|
||
|
If True, the window will be resizable. Defaults to False.
|
||
|
`style` : int
|
||
|
One of the ``WINDOW_STYLE_*`` constants specifying the
|
||
|
border style of the window.
|
||
|
`fullscreen` : bool
|
||
|
If True, the window will cover the entire screen rather
|
||
|
than floating. Defaults to False.
|
||
|
`visible` : bool
|
||
|
Determines if the window is visible immediately after
|
||
|
creation. Defaults to True. Set this to False if you
|
||
|
would like to change attributes of the window before
|
||
|
having it appear to the user.
|
||
|
`vsync` : bool
|
||
|
If True, buffer flips are synchronised to the primary screen's
|
||
|
vertical retrace, eliminating flicker.
|
||
|
`display` : `Display`
|
||
|
The display device to use. Useful only under X11.
|
||
|
`screen` : `Screen`
|
||
|
The screen to use, if in fullscreen.
|
||
|
`config` : `pyglet.gl.Config`
|
||
|
Either a template from which to create a complete config,
|
||
|
or a complete config.
|
||
|
`context` : `pyglet.gl.Context`
|
||
|
The context to attach to this window. The context must
|
||
|
not already be attached to another window.
|
||
|
|
||
|
'''
|
||
|
EventDispatcher.__init__(self)
|
||
|
self._event_queue = []
|
||
|
|
||
|
if not display:
|
||
|
display = get_platform().get_default_display()
|
||
|
|
||
|
if not screen:
|
||
|
screen = display.get_default_screen()
|
||
|
|
||
|
if not config:
|
||
|
for template_config in [
|
||
|
gl.Config(double_buffer=True, depth_size=24),
|
||
|
gl.Config(double_buffer=True, depth_size=16)]:
|
||
|
try:
|
||
|
config = screen.get_best_config(template_config)
|
||
|
break
|
||
|
except NoSuchConfigException:
|
||
|
pass
|
||
|
if not config:
|
||
|
raise NoSuchConfigException('No standard config is available.')
|
||
|
|
||
|
if not config.is_complete():
|
||
|
config = screen.get_best_config(config)
|
||
|
|
||
|
if not context:
|
||
|
context = config.create_context(gl.current_context)
|
||
|
|
||
|
# Set these in reverse order to above, to ensure we get user
|
||
|
# preference
|
||
|
self._context = context
|
||
|
self._config = self._context.config
|
||
|
self._screen = self._config.screen
|
||
|
self._display = self._screen.display
|
||
|
|
||
|
if fullscreen:
|
||
|
if width is not None or height is not None:
|
||
|
raise WindowException(
|
||
|
'Width and height cannot be specified with fullscreen.')
|
||
|
self._windowed_size = self._default_width, self._default_height
|
||
|
width = self._screen.width
|
||
|
height = self._screen.height
|
||
|
else:
|
||
|
if width is None:
|
||
|
width = self._default_width
|
||
|
if height is None:
|
||
|
height = self._default_height
|
||
|
|
||
|
self._width = width
|
||
|
self._height = height
|
||
|
self._resizable = resizable
|
||
|
self._fullscreen = fullscreen
|
||
|
self._style = style
|
||
|
if pyglet.options['vsync'] is not None:
|
||
|
self._vsync = pyglet.options['vsync']
|
||
|
else:
|
||
|
self._vsync = vsync
|
||
|
|
||
|
|
||
|
if caption is None:
|
||
|
caption = sys.argv[0]
|
||
|
self._caption = caption
|
||
|
|
||
|
from pyglet import app
|
||
|
app.windows.add(self)
|
||
|
self._create()
|
||
|
|
||
|
self.switch_to()
|
||
|
if visible:
|
||
|
self.set_visible(True)
|
||
|
self.activate()
|
||
|
|
||
|
def _create(self):
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def _recreate(self, changes):
|
||
|
'''Recreate the window with current attributes.
|
||
|
|
||
|
:Parameters:
|
||
|
`changes` : list of str
|
||
|
List of attribute names that were changed since the last
|
||
|
`_create` or `_recreate`. For example, ``['fullscreen']``
|
||
|
is given if the window is to be toggled to or from fullscreen.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def flip(self):
|
||
|
'''Swap the OpenGL front and back buffers.
|
||
|
|
||
|
Call this method on a double-buffered window to update the
|
||
|
visible display with the back buffer. The contents of the back buffer
|
||
|
is undefined after this operation.
|
||
|
|
||
|
Windows are double-buffered by default. This method is called
|
||
|
automatically by `EventLoop` after the `on_draw` event.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def switch_to(self):
|
||
|
'''Make this window the current OpenGL rendering context.
|
||
|
|
||
|
Only one OpenGL context can be active at a time. This method sets
|
||
|
the current window's context to be current. You should use this
|
||
|
method in preference to `pyglet.gl.Context.set_current`, as it may
|
||
|
perform additional initialisation functions.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_fullscreen(self, fullscreen=True, screen=None):
|
||
|
'''Toggle to or from fullscreen.
|
||
|
|
||
|
After toggling fullscreen, the GL context should have retained its
|
||
|
state and objects, however the buffers will need to be cleared and
|
||
|
redrawn.
|
||
|
|
||
|
:Parameters:
|
||
|
`fullscreen` : bool
|
||
|
True if the window should be made fullscreen, False if it
|
||
|
should be windowed.
|
||
|
`screen` : Screen
|
||
|
If not None and fullscreen is True, the window is moved to the
|
||
|
given screen. The screen must belong to the same display as
|
||
|
the window.
|
||
|
|
||
|
'''
|
||
|
if fullscreen == self._fullscreen and screen is None:
|
||
|
return
|
||
|
|
||
|
if not self._fullscreen:
|
||
|
# Save windowed size
|
||
|
self._windowed_size = self.get_size()
|
||
|
self._windowed_location = self.get_location()
|
||
|
|
||
|
if fullscreen and screen is not None:
|
||
|
assert screen.display is self.display
|
||
|
self._screen = screen
|
||
|
|
||
|
self._fullscreen = fullscreen
|
||
|
if self._fullscreen:
|
||
|
self._width = self.screen.width
|
||
|
self._height = self.screen.height
|
||
|
else:
|
||
|
self._width, self._height = self._windowed_size
|
||
|
|
||
|
self._recreate(['fullscreen'])
|
||
|
|
||
|
if not self._fullscreen and self._windowed_location:
|
||
|
# Restore windowed location -- no effect on OS X because of
|
||
|
# deferred recreate. Move into platform _create? XXX
|
||
|
self.set_location(*self._windowed_location)
|
||
|
|
||
|
def on_resize(self, width, height):
|
||
|
'''A default resize event handler.
|
||
|
|
||
|
This default handler updates the GL viewport to cover the entire
|
||
|
window and sets the ``GL_PROJECTION`` matrix to be orthagonal in
|
||
|
window space. The bottom-left corner is (0, 0) and the top-right
|
||
|
corner is the width and height of the window in pixels.
|
||
|
|
||
|
Override this event handler with your own to create another
|
||
|
projection, for example in perspective.
|
||
|
'''
|
||
|
gl.glViewport(0, 0, width, height)
|
||
|
gl.glMatrixMode(gl.GL_PROJECTION)
|
||
|
gl.glLoadIdentity()
|
||
|
gl.glOrtho(0, width, 0, height, -1, 1)
|
||
|
gl.glMatrixMode(gl.GL_MODELVIEW)
|
||
|
|
||
|
def on_close(self):
|
||
|
'''Default on_close handler.'''
|
||
|
self.has_exit = True
|
||
|
from pyglet import app
|
||
|
if app.event_loop is not None:
|
||
|
self.close()
|
||
|
|
||
|
def on_key_press(self, symbol, modifiers):
|
||
|
'''Default on_key_press handler.'''
|
||
|
if symbol == key.ESCAPE:
|
||
|
self.dispatch_event('on_close')
|
||
|
|
||
|
def close(self):
|
||
|
'''Close the window.
|
||
|
|
||
|
After closing the window, the GL context will be invalid. The
|
||
|
window instance cannot be reused once closed (see also `set_visible`).
|
||
|
|
||
|
The `pyglet.app.EventLoop.on_window_close` event is dispatched on
|
||
|
`pyglet.app.event_loop` when this method is called.
|
||
|
'''
|
||
|
from pyglet import app
|
||
|
if not self._context:
|
||
|
return
|
||
|
app.windows.remove(self)
|
||
|
self._context.destroy()
|
||
|
self._config = None
|
||
|
self._context = None
|
||
|
if app.event_loop:
|
||
|
app.event_loop.dispatch_event('on_window_close', self)
|
||
|
|
||
|
def draw_mouse_cursor(self):
|
||
|
'''Draw the custom mouse cursor.
|
||
|
|
||
|
If the current mouse cursor has ``drawable`` set, this method
|
||
|
is called before the buffers are flipped to render it.
|
||
|
|
||
|
This method always leaves the ``GL_MODELVIEW`` matrix as current,
|
||
|
regardless of what it was set to previously. No other GL state
|
||
|
is affected.
|
||
|
|
||
|
There is little need to override this method; instead, subclass
|
||
|
``MouseCursor`` and provide your own ``draw`` method.
|
||
|
'''
|
||
|
# Draw mouse cursor if set and visible.
|
||
|
# XXX leaves state in modelview regardless of starting state
|
||
|
if (self._mouse_cursor.drawable and
|
||
|
self._mouse_visible and
|
||
|
self._mouse_in_window):
|
||
|
gl.glMatrixMode(gl.GL_PROJECTION)
|
||
|
gl.glPushMatrix()
|
||
|
gl.glLoadIdentity()
|
||
|
gl.glOrtho(0, self.width, 0, self.height, -1, 1)
|
||
|
|
||
|
gl.glMatrixMode(gl.GL_MODELVIEW)
|
||
|
gl.glPushMatrix()
|
||
|
gl.glLoadIdentity()
|
||
|
|
||
|
self._mouse_cursor.draw(self._mouse_x, self._mouse_y)
|
||
|
|
||
|
gl.glMatrixMode(gl.GL_PROJECTION)
|
||
|
gl.glPopMatrix()
|
||
|
|
||
|
gl.glMatrixMode(gl.GL_MODELVIEW)
|
||
|
gl.glPopMatrix()
|
||
|
|
||
|
# Properties provide read-only access to instance variables. Use
|
||
|
# set_* methods to change them if applicable.
|
||
|
|
||
|
caption = property(lambda self: self._caption,
|
||
|
doc='''The window caption (title). Read-only.
|
||
|
|
||
|
:type: str
|
||
|
''')
|
||
|
resizable = property(lambda self: self._resizable,
|
||
|
doc='''True if the window is resizeable. Read-only.
|
||
|
|
||
|
:type: bool
|
||
|
''')
|
||
|
style = property(lambda self: self._style,
|
||
|
doc='''The window style; one of the ``WINDOW_STYLE_*`` constants.
|
||
|
Read-only.
|
||
|
|
||
|
:type: int
|
||
|
''')
|
||
|
fullscreen = property(lambda self: self._fullscreen,
|
||
|
doc='''True if the window is currently fullscreen. Read-only.
|
||
|
|
||
|
:type: bool
|
||
|
''')
|
||
|
visible = property(lambda self: self._visible,
|
||
|
doc='''True if the window is currently visible. Read-only.
|
||
|
|
||
|
:type: bool
|
||
|
''')
|
||
|
vsync = property(lambda self: self._vsync,
|
||
|
doc='''True if buffer flips are synchronised to the screen's vertical
|
||
|
retrace. Read-only.
|
||
|
|
||
|
:type: bool
|
||
|
''')
|
||
|
display = property(lambda self: self._display,
|
||
|
doc='''The display this window belongs to. Read-only.
|
||
|
|
||
|
:type: `Display`
|
||
|
''')
|
||
|
screen = property(lambda self: self._screen,
|
||
|
doc='''The screen this window is fullscreen in. Read-only.
|
||
|
|
||
|
:type: `Screen`
|
||
|
''')
|
||
|
config = property(lambda self: self._config,
|
||
|
doc='''A GL config describing the context of this window. Read-only.
|
||
|
|
||
|
:type: `pyglet.gl.Config`
|
||
|
''')
|
||
|
context = property(lambda self: self._context,
|
||
|
doc='''The OpenGL context attached to this window. Read-only.
|
||
|
|
||
|
:type: `pyglet.gl.Context`
|
||
|
''')
|
||
|
|
||
|
# These are the only properties that can be set
|
||
|
width = property(lambda self: self.get_size()[0],
|
||
|
lambda self, width: self.set_size(width, self.height),
|
||
|
doc='''The width of the window, in pixels. Read-write.
|
||
|
|
||
|
:type: int
|
||
|
''')
|
||
|
|
||
|
height = property(lambda self: self.get_size()[1],
|
||
|
lambda self, height: self.set_size(self.width, height),
|
||
|
doc='''The height of the window, in pixels. Read-write.
|
||
|
|
||
|
:type: int
|
||
|
''')
|
||
|
|
||
|
def set_caption(self, caption):
|
||
|
'''Set the window's caption.
|
||
|
|
||
|
The caption appears in the titlebar of the window, if it has one,
|
||
|
and in the taskbar on Windows and many X11 window managers.
|
||
|
|
||
|
:Parameters:
|
||
|
`caption` : str or unicode
|
||
|
The caption to set.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_minimum_size(self, width, height):
|
||
|
'''Set the minimum size of the window.
|
||
|
|
||
|
Once set, the user will not be able to resize the window smaller
|
||
|
than the given dimensions. There is no way to remove the
|
||
|
minimum size constraint on a window (but you could set it to 0,0).
|
||
|
|
||
|
The behaviour is undefined if the minimum size is set larger than
|
||
|
the current size of the window.
|
||
|
|
||
|
The window size does not include the border or title bar.
|
||
|
|
||
|
:Parameters:
|
||
|
`width` : int
|
||
|
Minimum width of the window, in pixels.
|
||
|
`height` : int
|
||
|
Minimum height of the window, in pixels.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_maximum_size(self, width, height):
|
||
|
'''Set the maximum size of the window.
|
||
|
|
||
|
Once set, the user will not be able to resize the window larger
|
||
|
than the given dimensions. There is no way to remove the
|
||
|
maximum size constraint on a window (but you could set it to a large
|
||
|
value).
|
||
|
|
||
|
The behaviour is undefined if the maximum size is set smaller than
|
||
|
the current size of the window.
|
||
|
|
||
|
The window size does not include the border or title bar.
|
||
|
|
||
|
:Parameters:
|
||
|
`width` : int
|
||
|
Maximum width of the window, in pixels.
|
||
|
`height` : int
|
||
|
Maximum height of the window, in pixels.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_size(self, width, height):
|
||
|
'''Resize the window.
|
||
|
|
||
|
The behaviour is undefined if the window is not resizable, or if
|
||
|
it is currently fullscreen.
|
||
|
|
||
|
The window size does not include the border or title bar.
|
||
|
|
||
|
:Parameters:
|
||
|
`width` : int
|
||
|
New width of the window, in pixels.
|
||
|
`height` : int
|
||
|
New height of the window, in pixels.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def get_size(self):
|
||
|
'''Return the current size of the window.
|
||
|
|
||
|
The window size does not include the border or title bar.
|
||
|
|
||
|
:rtype: (int, int)
|
||
|
:return: The width and height of the window, in pixels.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_location(self, x, y):
|
||
|
'''Set the position of the window.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance of the left edge of the window from the left edge
|
||
|
of the virtual desktop, in pixels.
|
||
|
`y` : int
|
||
|
Distance of the top edge of the window from the top edge of
|
||
|
the virtual desktop, in pixels.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def get_location(self):
|
||
|
'''Return the current position of the window.
|
||
|
|
||
|
:rtype: (int, int)
|
||
|
:return: The distances of the left and top edges from their respective
|
||
|
edges on the virtual desktop, in pixels.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def activate(self):
|
||
|
'''Attempt to restore keyboard focus to the window.
|
||
|
|
||
|
Depending on the window manager or operating system, this may not
|
||
|
be successful. For example, on Windows XP an application is not
|
||
|
allowed to "steal" focus from another application. Instead, the
|
||
|
window's taskbar icon will flash, indicating it requires attention.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_visible(self, visible=True):
|
||
|
'''Show or hide the window.
|
||
|
|
||
|
:Parameters:
|
||
|
`visible` : bool
|
||
|
If True, the window will be shown; otherwise it will be
|
||
|
hidden.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def minimize(self):
|
||
|
'''Minimize the window.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def maximize(self):
|
||
|
'''Maximize the window.
|
||
|
|
||
|
The behaviour of this method is somewhat dependent on the user's
|
||
|
display setup. On a multi-monitor system, the window may maximize
|
||
|
to either a single screen or the entire virtual desktop.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_vsync(self, vsync):
|
||
|
'''Enable or disable vertical sync control.
|
||
|
|
||
|
When enabled, this option ensures flips from the back to the front
|
||
|
buffer are performed only during the vertical retrace period of the
|
||
|
primary display. This can prevent "tearing" or flickering when
|
||
|
the buffer is updated in the middle of a video scan.
|
||
|
|
||
|
Note that LCD monitors have an analagous time in which they are not
|
||
|
reading from the video buffer; while it does not correspond to
|
||
|
a vertical retrace it has the same effect.
|
||
|
|
||
|
With multi-monitor systems the secondary monitor cannot be
|
||
|
synchronised to, so tearing and flicker cannot be avoided when the
|
||
|
window is positioned outside of the primary display. In this case
|
||
|
it may be advisable to forcibly reduce the framerate (for example,
|
||
|
using `pyglet.clock.set_fps_limit`).
|
||
|
|
||
|
:Parameters:
|
||
|
`vsync` : bool
|
||
|
If True, vsync is enabled, otherwise it is disabled.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_mouse_visible(self, visible=True):
|
||
|
'''Show or hide the mouse cursor.
|
||
|
|
||
|
The mouse cursor will only be hidden while it is positioned within
|
||
|
this window. Mouse events will still be processed as usual.
|
||
|
|
||
|
:Parameters:
|
||
|
`visible` : bool
|
||
|
If True, the mouse cursor will be visible, otherwise it
|
||
|
will be hidden.
|
||
|
|
||
|
'''
|
||
|
self._mouse_visible = visible
|
||
|
self.set_mouse_platform_visible()
|
||
|
|
||
|
def set_mouse_platform_visible(self, platform_visible=None):
|
||
|
'''Set the platform-drawn mouse cursor visibility. This is called
|
||
|
automatically after changing the mouse cursor or exclusive mode.
|
||
|
|
||
|
Applications should not normally need to call this method, see
|
||
|
`set_mouse_visible` instead.
|
||
|
|
||
|
:Parameters:
|
||
|
`platform_visible` : bool or None
|
||
|
If None, sets platform visibility to the required visibility
|
||
|
for the current exclusive mode and cursor type. Otherwise,
|
||
|
a bool value will override and force a visibility.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
def set_mouse_cursor(self, cursor=None):
|
||
|
'''Change the appearance of the mouse cursor.
|
||
|
|
||
|
The appearance of the mouse cursor is only changed while it is
|
||
|
within this window.
|
||
|
|
||
|
:Parameters:
|
||
|
`cursor` : `MouseCursor`
|
||
|
The cursor to set, or None to restore the default cursor.
|
||
|
|
||
|
'''
|
||
|
if cursor is None:
|
||
|
cursor = DefaultMouseCursor()
|
||
|
self._mouse_cursor = cursor
|
||
|
self.set_mouse_platform_visible()
|
||
|
|
||
|
def set_exclusive_mouse(self, exclusive=True):
|
||
|
'''Hide the mouse cursor and direct all mouse events to this
|
||
|
window.
|
||
|
|
||
|
When enabled, this feature prevents the mouse leaving the window. It
|
||
|
is useful for certain styles of games that require complete control of
|
||
|
the mouse. The position of the mouse as reported in subsequent events
|
||
|
is meaningless when exclusive mouse is enabled; you should only use
|
||
|
the relative motion parameters ``dx`` and ``dy``.
|
||
|
|
||
|
:Parameters:
|
||
|
`exclusive` : bool
|
||
|
If True, exclusive mouse is enabled, otherwise it is disabled.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def set_exclusive_keyboard(self, exclusive=True):
|
||
|
'''Prevent the user from switching away from this window using
|
||
|
keyboard accelerators.
|
||
|
|
||
|
When enabled, this feature disables certain operating-system specific
|
||
|
key combinations such as Alt+Tab (Command+Tab on OS X). This can be
|
||
|
useful in certain kiosk applications, it should be avoided in general
|
||
|
applications or games.
|
||
|
|
||
|
:Parameters:
|
||
|
`exclusive` : bool
|
||
|
If True, exclusive keyboard is enabled, otherwise it is
|
||
|
disabled.
|
||
|
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
def get_system_mouse_cursor(self, name):
|
||
|
'''Obtain a system mouse cursor.
|
||
|
|
||
|
Use `set_mouse_cursor` to make the cursor returned by this method
|
||
|
active. The names accepted by this method are the ``CURSOR_*``
|
||
|
constants defined on this class.
|
||
|
|
||
|
:Parameters:
|
||
|
`name` : str
|
||
|
Name describing the mouse cursor to return. For example,
|
||
|
``CURSOR_WAIT``, ``CURSOR_HELP``, etc.
|
||
|
|
||
|
:rtype: `MouseCursor`
|
||
|
:return: A mouse cursor which can be used with `set_mouse_cursor`.
|
||
|
'''
|
||
|
raise NotImplementedError()
|
||
|
|
||
|
def set_icon(self, *images):
|
||
|
'''Set the window icon.
|
||
|
|
||
|
If multiple images are provided, one with an appropriate size
|
||
|
will be selected (if the correct size is not provided, the image
|
||
|
will be scaled).
|
||
|
|
||
|
Useful sizes to provide are 16x16, 32x32, 64x64 (Mac only) and
|
||
|
128x128 (Mac only).
|
||
|
|
||
|
:Parameters:
|
||
|
`images` : sequence of `pyglet.image.AbstractImage`
|
||
|
List of images to use for the window icon.
|
||
|
|
||
|
'''
|
||
|
pass
|
||
|
|
||
|
def clear(self):
|
||
|
'''Clear the window.
|
||
|
|
||
|
This is a convenience method for clearing the color and depth
|
||
|
buffer. The window must be the active context (see `switch_to`).
|
||
|
'''
|
||
|
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
|
||
|
|
||
|
def dispatch_event(self, *args):
|
||
|
if not self._enable_event_queue or self._allow_dispatch_event:
|
||
|
EventDispatcher.dispatch_event(self, *args)
|
||
|
else:
|
||
|
self._event_queue.append(args)
|
||
|
|
||
|
def dispatch_events(self):
|
||
|
'''Poll the operating system event queue for new events and call
|
||
|
attached event handlers.
|
||
|
|
||
|
This method is provided for legacy applications targeting pyglet 1.0,
|
||
|
and advanced applications that must integrate their event loop
|
||
|
into another framework.
|
||
|
|
||
|
Typical applications should use `pyglet.app.run`.
|
||
|
'''
|
||
|
raise NotImplementedError('abstract')
|
||
|
|
||
|
# If documenting, show the event methods. Otherwise, leave them out
|
||
|
# as they are not really methods.
|
||
|
if hasattr(sys, 'is_epydoc') and sys.is_epydoc:
|
||
|
def on_key_press(symbol, modifiers):
|
||
|
'''A key on the keyboard was pressed (and held down).
|
||
|
|
||
|
In pyglet 1.0 the default handler sets `has_exit` to ``True`` if
|
||
|
the ``ESC`` key is pressed.
|
||
|
|
||
|
In pyglet 1.1 the default handler dispatches the `on_close`
|
||
|
event if the ``ESC`` key is pressed.
|
||
|
|
||
|
:Parameters:
|
||
|
`symbol` : int
|
||
|
The key symbol pressed.
|
||
|
`modifiers` : int
|
||
|
Bitwise combination of the key modifiers active.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_key_release(symbol, modifiers):
|
||
|
'''A key on the keyboard was released.
|
||
|
|
||
|
:Parameters:
|
||
|
`symbol` : int
|
||
|
The key symbol pressed.
|
||
|
`modifiers` : int
|
||
|
Bitwise combination of the key modifiers active.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_text(text):
|
||
|
'''The user input some text.
|
||
|
|
||
|
Typically this is called after `on_key_press` and before
|
||
|
`on_key_release`, but may also be called multiple times if the key
|
||
|
is held down (key repeating); or called without key presses if
|
||
|
another input method was used (e.g., a pen input).
|
||
|
|
||
|
You should always use this method for interpreting text, as the
|
||
|
key symbols often have complex mappings to their unicode
|
||
|
representation which this event takes care of.
|
||
|
|
||
|
:Parameters:
|
||
|
`text` : unicode
|
||
|
The text entered by the user.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_text_motion(motion):
|
||
|
'''The user moved the text input cursor.
|
||
|
|
||
|
Typically this is called after `on_key_press` and before
|
||
|
`on_key_release`, but may also be called multiple times if the key
|
||
|
is help down (key repeating).
|
||
|
|
||
|
You should always use this method for moving the text input cursor
|
||
|
(caret), as different platforms have different default keyboard
|
||
|
mappings, and key repeats are handled correctly.
|
||
|
|
||
|
The values that `motion` can take are defined in
|
||
|
`pyglet.window.key`:
|
||
|
|
||
|
* MOTION_UP
|
||
|
* MOTION_RIGHT
|
||
|
* MOTION_DOWN
|
||
|
* MOTION_LEFT
|
||
|
* MOTION_NEXT_WORD
|
||
|
* MOTION_PREVIOUS_WORD
|
||
|
* MOTION_BEGINNING_OF_LINE
|
||
|
* MOTION_END_OF_LINE
|
||
|
* MOTION_NEXT_PAGE
|
||
|
* MOTION_PREVIOUS_PAGE
|
||
|
* MOTION_BEGINNING_OF_FILE
|
||
|
* MOTION_END_OF_FILE
|
||
|
* MOTION_BACKSPACE
|
||
|
* MOTION_DELETE
|
||
|
|
||
|
:Parameters:
|
||
|
`motion` : int
|
||
|
The direction of motion; see remarks.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_text_motion_select(motion):
|
||
|
'''The user moved the text input cursor while extending the
|
||
|
selection.
|
||
|
|
||
|
Typically this is called after `on_key_press` and before
|
||
|
`on_key_release`, but may also be called multiple times if the key
|
||
|
is help down (key repeating).
|
||
|
|
||
|
You should always use this method for responding to text selection
|
||
|
events rather than the raw `on_key_press`, as different platforms
|
||
|
have different default keyboard mappings, and key repeats are
|
||
|
handled correctly.
|
||
|
|
||
|
The values that `motion` can take are defined in `pyglet.window.key`:
|
||
|
|
||
|
* MOTION_UP
|
||
|
* MOTION_RIGHT
|
||
|
* MOTION_DOWN
|
||
|
* MOTION_LEFT
|
||
|
* MOTION_NEXT_WORD
|
||
|
* MOTION_PREVIOUS_WORD
|
||
|
* MOTION_BEGINNING_OF_LINE
|
||
|
* MOTION_END_OF_LINE
|
||
|
* MOTION_NEXT_PAGE
|
||
|
* MOTION_PREVIOUS_PAGE
|
||
|
* MOTION_BEGINNING_OF_FILE
|
||
|
* MOTION_END_OF_FILE
|
||
|
|
||
|
:Parameters:
|
||
|
`motion` : int
|
||
|
The direction of selection motion; see remarks.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_mouse_motion(x, y, dx, dy):
|
||
|
'''The mouse was moved with no buttons held down.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance in pixels from the left edge of the window.
|
||
|
`y` : int
|
||
|
Distance in pixels from the bottom edge of the window.
|
||
|
`dx` : int
|
||
|
Relative X position from the previous mouse position.
|
||
|
`dy` : int
|
||
|
Relative Y position from the previous mouse position.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
|
||
|
'''The mouse was moved with one or more mouse buttons pressed.
|
||
|
|
||
|
This event will continue to be fired even if the mouse leaves
|
||
|
the window, so long as the drag buttons are continuously held down.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance in pixels from the left edge of the window.
|
||
|
`y` : int
|
||
|
Distance in pixels from the bottom edge of the window.
|
||
|
`dx` : int
|
||
|
Relative X position from the previous mouse position.
|
||
|
`dy` : int
|
||
|
Relative Y position from the previous mouse position.
|
||
|
`buttons` : int
|
||
|
Bitwise combination of the mouse buttons currently pressed.
|
||
|
`modifiers` : int
|
||
|
Bitwise combination of any keyboard modifiers currently
|
||
|
active.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_mouse_press(x, y, button, modifiers):
|
||
|
'''A mouse button was pressed (and held down).
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance in pixels from the left edge of the window.
|
||
|
`y` : int
|
||
|
Distance in pixels from the bottom edge of the window.
|
||
|
`button` : int
|
||
|
The mouse button that was pressed.
|
||
|
`modifiers` : int
|
||
|
Bitwise combination of any keyboard modifiers currently
|
||
|
active.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_mouse_release(x, y, button, modifiers):
|
||
|
'''A mouse button was released.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance in pixels from the left edge of the window.
|
||
|
`y` : int
|
||
|
Distance in pixels from the bottom edge of the window.
|
||
|
`button` : int
|
||
|
The mouse button that was released.
|
||
|
`modifiers` : int
|
||
|
Bitwise combination of any keyboard modifiers currently
|
||
|
active.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_mouse_scroll(x, y, scroll_x, scroll_y):
|
||
|
'''The mouse wheel was scrolled.
|
||
|
|
||
|
Note that most mice have only a vertical scroll wheel, so
|
||
|
`scroll_x` is usually 0. An exception to this is the Apple Mighty
|
||
|
Mouse, which has a mouse ball in place of the wheel which allows
|
||
|
both `scroll_x` and `scroll_y` movement.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance in pixels from the left edge of the window.
|
||
|
`y` : int
|
||
|
Distance in pixels from the bottom edge of the window.
|
||
|
`scroll_x` : int
|
||
|
Number of "clicks" towards the right (left if negative).
|
||
|
`scroll_y` : int
|
||
|
Number of "clicks" upwards (downwards if negative).
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_close():
|
||
|
'''The user attempted to close the window.
|
||
|
|
||
|
This event can be triggered by clicking on the "X" control box in
|
||
|
the window title bar, or by some other platform-dependent manner.
|
||
|
|
||
|
The default handler sets `has_exit` to ``True``. In pyglet 1.1, if
|
||
|
`pyglet.app.event_loop` is being used, `close` is also called,
|
||
|
closing the window immediately.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_mouse_enter(x, y):
|
||
|
'''The mouse was moved into the window.
|
||
|
|
||
|
This event will not be trigged if the mouse is currently being
|
||
|
dragged.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance in pixels from the left edge of the window.
|
||
|
`y` : int
|
||
|
Distance in pixels from the bottom edge of the window.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_mouse_leave(x, y):
|
||
|
'''The mouse was moved outside of the window.
|
||
|
|
||
|
This event will not be trigged if the mouse is currently being
|
||
|
dragged. Note that the coordinates of the mouse pointer will be
|
||
|
outside of the window rectangle.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance in pixels from the left edge of the window.
|
||
|
`y` : int
|
||
|
Distance in pixels from the bottom edge of the window.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_expose():
|
||
|
'''A portion of the window needs to be redrawn.
|
||
|
|
||
|
This event is triggered when the window first appears, and any time
|
||
|
the contents of the window is invalidated due to another window
|
||
|
obscuring it.
|
||
|
|
||
|
There is no way to determine which portion of the window needs
|
||
|
redrawing. Note that the use of this method is becoming
|
||
|
increasingly uncommon, as newer window managers composite windows
|
||
|
automatically and keep a backing store of the window contents.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_resize(width, height):
|
||
|
'''The window was resized.
|
||
|
|
||
|
The window will have the GL context when this event is dispatched;
|
||
|
there is no need to call `switch_to` in this handler.
|
||
|
|
||
|
:Parameters:
|
||
|
`width` : int
|
||
|
The new width of the window, in pixels.
|
||
|
`height` : int
|
||
|
The new height of the window, in pixels.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_move(x, y):
|
||
|
'''The window was moved.
|
||
|
|
||
|
:Parameters:
|
||
|
`x` : int
|
||
|
Distance from the left edge of the screen to the left edge
|
||
|
of the window.
|
||
|
`y` : int
|
||
|
Distance from the top edge of the screen to the top edge of
|
||
|
the window. Note that this is one of few methods in pyglet
|
||
|
which use a Y-down coordinate system.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_activate():
|
||
|
'''The window was activated.
|
||
|
|
||
|
This event can be triggered by clicking on the title bar, bringing
|
||
|
it to the foreground; or by some platform-specific method.
|
||
|
|
||
|
When a window is "active" it has the keyboard focus.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_deactivate():
|
||
|
'''The window was deactivated.
|
||
|
|
||
|
This event can be triggered by clicking on another application
|
||
|
window. When a window is deactivated it no longer has the
|
||
|
keyboard focus.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_show():
|
||
|
'''The window was shown.
|
||
|
|
||
|
This event is triggered when a window is restored after being
|
||
|
minimised, or after being displayed for the first time.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_hide():
|
||
|
'''The window was hidden.
|
||
|
|
||
|
This event is triggered when a window is minimised or (on Mac OS X)
|
||
|
hidden by the user.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_context_lost():
|
||
|
'''The window's GL context was lost.
|
||
|
|
||
|
When the context is lost no more GL methods can be called until it
|
||
|
is recreated. This is a rare event, triggered perhaps by the user
|
||
|
switching to an incompatible video mode. When it occurs, an
|
||
|
application will need to reload all objects (display lists, texture
|
||
|
objects, shaders) as well as restore the GL state.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_context_state_lost():
|
||
|
'''The state of the window's GL context was lost.
|
||
|
|
||
|
pyglet may sometimes need to recreate the window's GL context if
|
||
|
the window is moved to another video device, or between fullscreen
|
||
|
or windowed mode. In this case it will try to share the objects
|
||
|
(display lists, texture objects, shaders) between the old and new
|
||
|
contexts. If this is possible, only the current state of the GL
|
||
|
context is lost, and the application should simply restore state.
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
def on_draw():
|
||
|
'''The window contents must be redrawn.
|
||
|
|
||
|
The `EventLoop` will dispatch this event when the window
|
||
|
should be redrawn. This will happen during idle time after
|
||
|
any window events and after any scheduled functions were called.
|
||
|
|
||
|
The window will already have the GL context, so there is no
|
||
|
need to call `switch_to`. The window's `flip` method will
|
||
|
be called after this event, so your event handler should not.
|
||
|
|
||
|
You should make no assumptions about the window contents when
|
||
|
this event is triggered; a resize or expose event may have
|
||
|
invalidated the framebuffer since the last time it was drawn.
|
||
|
|
||
|
:since: pyglet 1.1
|
||
|
|
||
|
:event:
|
||
|
'''
|
||
|
|
||
|
BaseWindow.register_event_type('on_key_press')
|
||
|
BaseWindow.register_event_type('on_key_release')
|
||
|
BaseWindow.register_event_type('on_text')
|
||
|
BaseWindow.register_event_type('on_text_motion')
|
||
|
BaseWindow.register_event_type('on_text_motion_select')
|
||
|
BaseWindow.register_event_type('on_mouse_motion')
|
||
|
BaseWindow.register_event_type('on_mouse_drag')
|
||
|
BaseWindow.register_event_type('on_mouse_press')
|
||
|
BaseWindow.register_event_type('on_mouse_release')
|
||
|
BaseWindow.register_event_type('on_mouse_scroll')
|
||
|
BaseWindow.register_event_type('on_mouse_enter')
|
||
|
BaseWindow.register_event_type('on_mouse_leave')
|
||
|
BaseWindow.register_event_type('on_close')
|
||
|
BaseWindow.register_event_type('on_expose')
|
||
|
BaseWindow.register_event_type('on_resize')
|
||
|
BaseWindow.register_event_type('on_move')
|
||
|
BaseWindow.register_event_type('on_activate')
|
||
|
BaseWindow.register_event_type('on_deactivate')
|
||
|
BaseWindow.register_event_type('on_show')
|
||
|
BaseWindow.register_event_type('on_hide')
|
||
|
BaseWindow.register_event_type('on_context_lost')
|
||
|
BaseWindow.register_event_type('on_context_state_lost')
|
||
|
BaseWindow.register_event_type('on_draw')
|
||
|
|
||
|
def get_platform():
|
||
|
'''Get an instance of the Platform most appropriate for this
|
||
|
system.
|
||
|
|
||
|
:rtype: `Platform`
|
||
|
:return: The platform instance.
|
||
|
'''
|
||
|
return _platform
|
||
|
|
||
|
_is_epydoc = hasattr(sys, 'is_epydoc') and sys.is_epydoc
|
||
|
|
||
|
if _is_epydoc:
|
||
|
# We are building documentation
|
||
|
Window = BaseWindow
|
||
|
Window.__name__ = 'Window'
|
||
|
del BaseWindow
|
||
|
else:
|
||
|
# Try to determine which platform to use.
|
||
|
if sys.platform == 'darwin':
|
||
|
from pyglet.window.carbon import CarbonPlatform, CarbonWindow
|
||
|
_platform = CarbonPlatform()
|
||
|
Window = CarbonWindow
|
||
|
elif sys.platform in ('win32', 'cygwin'):
|
||
|
from pyglet.window.win32 import Win32Platform, Win32Window
|
||
|
_platform = Win32Platform()
|
||
|
Window = Win32Window
|
||
|
else:
|
||
|
from pyglet.window.xlib import XlibPlatform, XlibWindow
|
||
|
_platform = XlibPlatform()
|
||
|
Window = XlibWindow
|
||
|
|
||
|
# Create shadow window. (trickery is for circular import)
|
||
|
if not _is_epydoc:
|
||
|
pyglet.window = sys.modules[__name__]
|
||
|
gl._create_shadow_window()
|