diff --git a/README.md b/README.md
index 2ee4ce1..633cfa0 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,5 @@
# Difficult Rocket
-[comment]: <> ([中文](./docs/README-cn.md) | English)
-
中文 | [English](/docs/README-en.md)
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
diff --git a/docs/README-en.md b/docs/README-en.md
index da02c08..3ba88d4 100644
--- a/docs/README-en.md
+++ b/docs/README-en.md
@@ -1,7 +1,5 @@
# Difficult Rocket
-[comment]: <> (中文 | [English](https://github.com/shenjackyuanjie/Difficult-Rocket).)
-
[中文](../README.md) | English
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
diff --git a/docs/src/404.md b/docs/src/404.md
index 66d2ce4..c1d985e 100644
--- a/docs/src/404.md
+++ b/docs/src/404.md
@@ -1,4 +1,4 @@
-# 嘿 看啥呢
+# 嘿 看啥呢 404!
- 很明显,这里没有你想要的东西
diff --git a/docs/src/README-en.md b/docs/src/README-en.md
new file mode 100644
index 0000000..3ba88d4
--- /dev/null
+++ b/docs/src/README-en.md
@@ -0,0 +1,116 @@
+# Difficult Rocket
+
+[中文](../README.md) | English
+
+- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
+- [gitee](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
+- [discord](https://discord.gg/kWzw2JrG6M)
+- [kook](https://kook.top/sRPjFG)
+
+
+[![Generic badge](https://img.shields.io/badge/SemVer-2.0.0-blue.svg)](https://Semver.org/)
+[![Generic badge](https://img.shields.io/badge/Write_with_Python-3.8.10-blue.svg)](https://Python.org)
+[![Generic badge](https://img.shields.io/badge/Write_with_Pyglet-2.0.4-blue.svg)](https://pyglet.org)
+[![Generic badge](https://img.shields.io/badge/Python-_3.8_|_3.9_|_3.10_|_3.11_-blue.svg)](https://Python.org)
+
+## Version
+
+[![Generic badge](https://img.shields.io/badge/Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
+[![Generic badge](https://img.shields.io/badge/Pre_Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
+[![Generic badge](https://img.shields.io/badge/Devloping-0.7.2-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
+
+## 中文README请移步 [这里](../README.md)
+
+> Difficult-rocket is a Simple Rocket liked game build with Python (in short: rocket simulator)
+
+## Advantage
+
+> Lighter than Vanilla SR
+
+## [Plan feature list](/docs/src/plan_features.md)
+
+- [microsoft TODO](https://to-do.microsoft.com/sharing?InvitationToken=Q6SN1kdtitK8cwFktFl71gSnsRMNmrH7CC7kHY_Tq6ReMRwHgInP4_q5ie2IwrHx8)
+
+## [Update logs](/docs/src/update_logs.md)
+
+## Environment (been tested / developed on)
+
+- `Develop platform 1 - Windows 10 x64 22H2`
+ - `Python 3.8.10`
+ - `pillow 9.3.0`
+ - `pyperclip 1.8.2`
+ - `pyglet 2.0`
+ - `psutil 5.9.4`
+ - `objprint 0.2.2`
+ - `rtoml 0.9.0`
+ - `xmltodict 0.13.0`
+ - `tomlkit 0.11.6`
+ - `AMD R5 5600X`
+ - `AMD RX 550 4G`
+
+## Required python modules
+
+- `rtoml`
+- `tomlkit`
+- `pyglet` (pre-installed V2.0.4 path:`./libs/pyglet`)
+- `xmltodict` (pre-installed V0.12.0 path:`./libs/xmltodict`)
+- `pyperclip` (pre-installed V1.8.2 path: `./libs/pyperclip`)
+- `pillow`
+- `defusedxml`
+- `objprint`
+- `psutil`
+
+## thanks to
+
+- Open Source Projects
+ - [pyglet](https://github.com/pyglet/pyglet): GUI and graphics
+ - `tomlkit` / `rtoml` toml parser
+ - `xmltodict`: translate data between xml and dict
+ - `pyperclip`: paste board!
+ - `rapier2d`: Phy simulate engine
+
+- Main contributors
+ - [@Rayawa](https://github.com/Rayawa) : check mistake in docs & some translates
+ - [@rouxiao-you](https://github.com/ruoxiao-you) : translate chinese to English
+ - [@Billchyi](https://github.com/Billchyi) : check mistake in docs
+
+## Other links
+
+## About License
+
+#### https://creativecommons.org/licenses/by-nc-sa/4.0/
+
+#### Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
+
+This is a human-readable summary of (and not a substitute for) the license. Disclaimer.
+
+You are free to:
+
+Share — copy and redistribute the material in any medium or format
+
+Adapt — remix, transform, and build upon the material
+
+The licensor cannot revoke these freedoms as long as you follow the license terms.
+
+Under the following terms:
+
+Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You
+may do so in any reasonable manner, but not in any way
+
+that suggests the licensor endorses you or your use.
+
+NonCommercial — You may not use the material for commercial purposes.
+
+ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same
+license as the original.
+
+No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from
+doing anything the license permits.
+
+Notices:
+
+You do not have to comply with the license for elements of the material in the public domain or where your use is
+permitted by an applicable exception or limitation.
+
+No warranties are given. The license may not give you all the permissions necessary for your intended use. For example,
+other rights such as publicity, privacy, or moral rights may limit how you use the material.
diff --git a/docs/src/README.md b/docs/src/README.md
new file mode 120000
index 0000000..633cfa0
--- /dev/null
+++ b/docs/src/README.md
@@ -0,0 +1,110 @@
+# Difficult Rocket
+
+中文 | [English](/docs/README-en.md)
+
+- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
+- [gitee](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
+- [discord](https://discord.gg/kWzw2JrG6M)
+- [kook](https://kook.top/sRPjFG)
+
+
+[![Generic badge](https://img.shields.io/badge/SemVer-2.0.0-blue.svg)](https://Semver.org/)
+[![Generic badge](https://img.shields.io/badge/编写于_Python_版本-3.8.10-blue.svg)](https://Python.org)
+[![Generic badge](https://img.shields.io/badge/编写于_Pyglet_版本-2.0.4-blue.svg)](https://pyglet.org)
+[![Generic badge](https://img.shields.io/badge/Python-_3.8_|_3.9_|_3.10_|_3.11_-blue.svg)](https://Python.org)
+
+## 版本
+
+[![Generic badge](https://img.shields.io/badge/Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
+[![Generic badge](https://img.shields.io/badge/Pre_Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
+[![Generic badge](https://img.shields.io/badge/Devloping-0.7.2-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
+
+## English README please look [here](./docs/README-en.md)
+
+> 这是一个用Python制作的类Simple Rocket游戏(简称:火箭模拟器)
+
+## 优势
+
+> 相对于原版SR比较“轻量化”
+
+## [计划特性列表](/docs/plan_features)
+
+- [microsoft TODO](https://to-do.microsoft.com/sharing?InvitationToken=Q6SN1kdtitK8cwFktFl71gSnsRMNmrH7CC7kHY_Tq6ReMRwHgInP4_q5ie2IwrHx8)
+
+## [更新日志](/docs/update_logs.md)
+
+## 环境需求 (测试过的 / 开发平台)
+
+- `开发平台 1 - Windows 10 x64 22H2`
+ - `Python 3.8.10`
+ - `pillow 9.3.0`
+ - `pyperclip 1.8.2`
+ - `pyglet 2.0`
+ - `psutil 5.9.4`
+ - `objprint 0.2.2`
+ - `rtoml 0.9.0`
+ - `xmltodict 0.13.0`
+ - `tomlkit 0.11.6`
+ - `AMD R5 5600X`
+ - `AMD RX 550 4G`
+
+## 需要的Python模块
+
+- `rtoml`
+- `tomlkit`
+- `pyglet` (已经内置 V2.0.4 路径:`./libs/pyglet`)
+- `xmltodict` (已经内置 V0.12.0 路径:`./libs/xmltodict`)
+- `pyperclip` (已经内置 V1.8.2 路径: `./libs/pyperclip`)
+- `pillow`
+- `defusedxml`
+- `objprint`
+- `psutil`
+
+## 感谢
+
+- 开源项目
+ - [pyglet](https://github.com/pyglet/pyglet) : GUI 和画面渲染
+ - `tomlkit` / `rtoml` : toml 解析器
+ - `xmltodict`: xml 与 dict 转换器
+ - `pyperclip`: 剪贴板!
+ - `rapier2d`: 物理模拟引擎
+
+- 主要贡献者
+ - [@Rayawa](https://github.com/Rayawa) : 文档矫正 & 翻译部分 lang
+ - [@rouxiao-you](https://github.com/ruoxiao-you) : 翻译 lang
+ - [@Billchyi](https://github.com/Billchyi) : 文档矫正
+ - [@MSDNicrosoft]()
+
+## 相关链接
+
+## 关于分享协议
+
+#### https://creativecommons.org/licenses/by-nc-sa/4.0/
+
+#### 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
+
+这是一份普通人可以理解的许可协议概要 (但不是替代) 。 免责声明.
+
+您可以自由地:
+
+共享 — 在任何媒介以任何形式复制、发行本作品
+
+演绎 — 修改、转换或以本作品为基础进行创作
+
+只要你遵守许可协议条款,许可人就无法收回你的这些权利。
+
+惟须遵守下列条件:
+
+署名 — 您必须给出地当的署名,提供指向本许可协议的链接,同时标明是否(对原始作品)作了修改。您可以用任何合理的方式来署名,但是不得以任何方式暗示许可人为您或您的使用背书。
+
+非商业性使用 — 您不得将本作品用于商业目的。
+
+相同方式共享 — 如果您再混合、转换或者基于本作品进行创作,您必须基于与原先许可协议地同的许可协议 分发您贡献的作品。
+
+没有附加限制 — 您不得适用法律术语或者 技术措施 从而限制其他人做许可协议允许的事情。
+
+声明:
+
+您不必因为公共领域的作品要素而遵守许可协议,或者您的使用被可适用的 例外或限制所允许。
+
+不提供担保。许可协议可能不会给与您意图使用的所必须的所有许可。例如,其他权利比如形象权、隐私权或人格权可能限制您如何使用作品。
diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md
index fc1bf29..b4871a3 100644
--- a/docs/src/SUMMARY.md
+++ b/docs/src/SUMMARY.md
@@ -1,5 +1,8 @@
# Summary
+- [README](./README.md)
+- [README-en](./README-en.md)
+
- [update logs](./update_logs.md)
- [contributors](./contributors.md)
diff --git a/docs/src/contributors.md b/docs/src/contributors.md
index 26d9672..9e3e009 100644
--- a/docs/src/contributors.md
+++ b/docs/src/contributors.md
@@ -1,3 +1,8 @@
# 如何帮助 DR 开发
-aaaa
\ No newline at end of file
+## 需要准备的工具
+
+1. Powershell 7+
+2. Python3.8 +
+3. gcc / clang 编译器
+4. git
diff --git a/libs/pyglet/libs/darwin/cocoapy/runtime.py b/libs/pyglet/libs/darwin/cocoapy/runtime.py
index 99ba096..ade2f72 100644
--- a/libs/pyglet/libs/darwin/cocoapy/runtime.py
+++ b/libs/pyglet/libs/darwin/cocoapy/runtime.py
@@ -415,6 +415,7 @@ objc.sel_isEqual.argtypes = [c_void_p, c_void_p]
objc.sel_registerName.restype = c_void_p
objc.sel_registerName.argtypes = [c_char_p]
+
######################################################################
# void *objc_autoreleasePoolPush(void)
objc.objc_autoreleasePoolPush.restype = c_void_p
@@ -644,8 +645,8 @@ def parse_type_encoding(encoding):
def cfunctype_for_encoding(encoding):
# Check if we've already created a CFUNCTYPE for this encoding.
# If so, then return the cached CFUNCTYPE.
- #if encoding in cfunctype_table:
- # return cfunctype_table[encoding]
+ if encoding in cfunctype_table:
+ return cfunctype_table[encoding]
# Otherwise, create a new CFUNCTYPE for the encoding.
typecodes = {b'c': c_char, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong,
@@ -668,7 +669,7 @@ def cfunctype_for_encoding(encoding):
# Cache the new CFUNCTYPE in the cfunctype_table.
# We do this mainly because it prevents the CFUNCTYPE
# from being garbage-collected while we need it.
- #cfunctype_table[encoding] = cfunctype
+ cfunctype_table[encoding] = cfunctype
return cfunctype
@@ -728,12 +729,12 @@ class ObjCMethod:
# Note, need to map 'c' to c_byte rather than c_char, because otherwise
# ctypes converts the value into a one-character string which is generally
# not what we want at all, especially when the 'c' represents a bool var.
- typecodes = {b'c': c_byte, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong,
- b'C': c_ubyte, b'I': c_uint, b'S': c_ushort, b'L': c_ulong, b'Q': c_ulonglong,
- b'f': c_float, b'd': c_double, b'B': c_bool, b'v': None, b'Vv': None, b'*': c_char_p,
- b'@': c_void_p, b'#': c_void_p, b':': c_void_p, b'^v': c_void_p, b'?': c_void_p,
- NSPointEncoding: NSPoint, NSSizeEncoding: NSSize, NSRectEncoding: NSRect,
- NSRangeEncoding: NSRange,
+ typecodes = {b'c': c_byte, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong,
+ b'C': c_ubyte, b'I': c_uint, b'S': c_ushort, b'L': c_ulong, b'Q': c_ulonglong,
+ b'f': c_float, b'd': c_double, b'B': c_bool, b'v': None, b'Vv': None, b'*': c_char_p,
+ b'@': c_void_p, b'#': c_void_p, b':': c_void_p, b'^v': c_void_p, b'?': c_void_p,
+ NSPointEncoding: NSPoint, NSSizeEncoding: NSSize, NSRectEncoding: NSRect,
+ NSRangeEncoding: NSRange,
PyObjectEncoding: py_object}
cfunctype_table = {}
diff --git a/libs/pyglet/math.py b/libs/pyglet/math.py
index ead4414..6647808 100644
--- a/libs/pyglet/math.py
+++ b/libs/pyglet/math.py
@@ -861,7 +861,7 @@ class Mat4(tuple):
def look_at(cls: type[Mat4T], position: Vec3, target: Vec3, up: Vec3):
f = (target - position).normalize()
u = up.normalize()
- s = f.cross(u)
+ s = f.cross(u).normalize()
u = s.cross(f)
return cls([s.x, u.x, -f.x, 0.0,
diff --git a/libs/pyglet/media/codecs/base.py b/libs/pyglet/media/codecs/base.py
index d65b23a..652a8a8 100644
--- a/libs/pyglet/media/codecs/base.py
+++ b/libs/pyglet/media/codecs/base.py
@@ -135,17 +135,6 @@ class AudioData:
self.duration -= num_bytes / audio_format.bytes_per_second
self.timestamp += num_bytes / audio_format.bytes_per_second
- def get_string_data(self):
- """Return data as a bytestring.
-
- Returns:
- bytes: Data as a (byte)string.
- """
- if self.data is None:
- return b''
-
- return memoryview(self.data).tobytes()[:self.length]
-
class SourceInfo:
"""Source metadata information.
@@ -409,7 +398,7 @@ class StaticSource(Source):
audio_data = source.get_audio_data(buffer_size)
if not audio_data:
break
- data.write(audio_data.get_string_data())
+ data.write(audio_data.data)
self._data = data.getvalue()
self._duration = len(self._data) / self.audio_format.bytes_per_second
diff --git a/libs/pyglet/media/drivers/base.py b/libs/pyglet/media/drivers/base.py
index 3c99783..6ada69d 100644
--- a/libs/pyglet/media/drivers/base.py
+++ b/libs/pyglet/media/drivers/base.py
@@ -1,9 +1,8 @@
import math
-import time
import weakref
+
from abc import ABCMeta, abstractmethod
-import pyglet
from pyglet.util import with_metaclass
@@ -185,36 +184,3 @@ class AbstractAudioDriver(with_metaclass(ABCMeta)):
@abstractmethod
def delete(self):
pass
-
-
-class MediaEvent:
- """Representation of a media event.
-
- These events are used internally by some audio driver implementation to
- communicate events to the :class:`~pyglet.media.player.Player`.
- One example is the ``on_eos`` event.
-
- Args:
- event (str): Event description.
- timestamp (float): The time when this event happens.
- *args: Any required positional argument to go along with this event.
- """
-
- __slots__ = 'event', 'timestamp', 'args'
-
- def __init__(self, event, timestamp=0, *args):
- # Meaning of timestamp is dependent on context; and not seen by application.
- self.event = event
- self.timestamp = timestamp
- self.args = args
-
- def sync_dispatch_to_player(self, player):
- pyglet.app.platform_event_loop.post_event(player, self.event, *self.args)
- time.sleep(0)
- # TODO sync with media.dispatch_events
-
- def __repr__(self):
- return f"MediaEvent({self.event}, {self.timestamp}, {self.args})"
-
- def __lt__(self, other):
- return hash(self) < hash(other)
diff --git a/libs/pyglet/media/drivers/directsound/adaptation.py b/libs/pyglet/media/drivers/directsound/adaptation.py
index af53dab..61969e6 100644
--- a/libs/pyglet/media/drivers/directsound/adaptation.py
+++ b/libs/pyglet/media/drivers/directsound/adaptation.py
@@ -1,10 +1,11 @@
import math
import ctypes
+import pyglet.app
from . import interface
from pyglet.util import debug_print
from pyglet.media.mediathreads import PlayerWorkerThread
-from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
+from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
from pyglet.media.drivers.listener import AbstractListener
_debug = debug_print('debug_media')
@@ -75,7 +76,7 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
self._play_cursor_ring = 0
self._write_cursor_ring = 0
- # List of (play_cursor, MediaEvent), in sort order
+ # List of play_cursor, in sort order
self._events = []
# List of (cursor, timestamp), in sort order (cursor gives expiry
@@ -157,9 +158,6 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
return (self._eos_cursor is not None
and self._play_cursor > self._eos_cursor)
- def _dispatch_new_event(self, event_name):
- MediaEvent(event_name).sync_dispatch_to_player(self.player)
-
def _get_audiodata(self):
if self._audiodata_buffer is None or self._audiodata_buffer.length == 0:
self._get_new_audiodata()
@@ -246,7 +244,7 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
if self._playing and self._has_underrun():
assert _debug('underrun, stopping')
self.stop()
- self._dispatch_new_event('on_eos')
+ pyglet.app.platform_event_loop.post_event(self.player, 'on_eos')
def _get_write_size(self):
self.update_play_cursor()
diff --git a/libs/pyglet/media/drivers/openal/adaptation.py b/libs/pyglet/media/drivers/openal/adaptation.py
index 0c70ce1..b093f67 100644
--- a/libs/pyglet/media/drivers/openal/adaptation.py
+++ b/libs/pyglet/media/drivers/openal/adaptation.py
@@ -1,8 +1,9 @@
import weakref
+import pyglet.app
from . import interface
from pyglet.util import debug_print
-from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
+from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
from pyglet.media.mediathreads import PlayerWorkerThread
from pyglet.media.drivers.listener import AbstractListener
@@ -111,7 +112,7 @@ class OpenALAudioPlayer(AbstractAudioPlayer):
# of underrun)
self._underrun_timestamp = None
- # List of (cursor, MediaEvent)
+ # List of cursor
self._events = []
# Desired play state (True even if stopped due to underrun)
@@ -280,7 +281,7 @@ class OpenALAudioPlayer(AbstractAudioPlayer):
assert _debug('No audio data left')
if self._has_underrun():
assert _debug('Underrun')
- MediaEvent('on_eos').sync_dispatch_to_player(self.player)
+ pyglet.app.platform_event_loop.post_event(self.player, 'on_eos')
def _queue_audio_data(self, audio_data, length):
buf = self.alsource.get_buffer()
diff --git a/libs/pyglet/media/drivers/pulse/adaptation.py b/libs/pyglet/media/drivers/pulse/adaptation.py
index 5b85114..c438fa7 100644
--- a/libs/pyglet/media/drivers/pulse/adaptation.py
+++ b/libs/pyglet/media/drivers/pulse/adaptation.py
@@ -1,6 +1,7 @@
import weakref
-from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
+import pyglet.app
+from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
from pyglet.media.drivers.listener import AbstractListener
from pyglet.util import debug_print
@@ -217,7 +218,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
if self._has_audio_data():
self._write_to_stream()
else:
- self._add_event_at_write_index('on_eos')
+ self._events.append('on_eos')
def _process_events(self):
assert _debug('PulseAudioPlayer: Process events')
@@ -235,13 +236,9 @@ class PulseAudioPlayer(AbstractAudioPlayer):
assert _debug('PulseAudioPlayer: Dispatch events at index {}'.format(read_index))
while self._events and self._events[0][0] <= read_index:
- _, event = self._events.pop(0)
- assert _debug('PulseAudioPlayer: Dispatch event', event)
- event._sync_dispatch_to_player(self.player)
-
- def _add_event_at_write_index(self, event_name):
- assert _debug('PulseAudioPlayer: Add event at index {}'.format(self._write_index))
- self._events.append((self._write_index, MediaEvent(event_name)))
+ event_name = self._events.pop(0)
+ assert _debug('PulseAudioPlayer: Dispatch event', event_name)
+ pyglet.app.platform_event_loop.post_event(self.player, event_name)
def delete(self):
assert _debug('Delete PulseAudioPlayer')
@@ -255,7 +252,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
if driver.mainloop is None:
assert _debug('PulseAudioDriver already deleted. '
- 'PulseAudioPlayer could not clean up properly.')
+ 'PulseAudioPlayer could not clean up properly.')
return
if self._time_sync_operation is not None:
diff --git a/libs/pyglet/media/drivers/xaudio2/adaptation.py b/libs/pyglet/media/drivers/xaudio2/adaptation.py
index 0287edf..53911a3 100644
--- a/libs/pyglet/media/drivers/xaudio2/adaptation.py
+++ b/libs/pyglet/media/drivers/xaudio2/adaptation.py
@@ -1,7 +1,7 @@
import math
import pyglet
-from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
+from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
from pyglet.media.drivers.listener import AbstractListener
from pyglet.util import debug_print
from . import interface
@@ -48,7 +48,7 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
self._write_cursor = 0
self._play_cursor = 0
- # List of (play_cursor, MediaEvent), in sort order
+ # List of play_cursor, in sort order
self._events = []
# List of (cursor, timestamp), in sort order (cursor gives expiry
@@ -89,7 +89,6 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
if not self._buffers:
self._xa2_driver.return_voice(self._xa2_source_voice)
-
def play(self):
assert _debug('XAudio2 play')
@@ -168,7 +167,7 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
if self.buffer_end_submitted:
if buffers_queued == 0:
self._xa2_source_voice.stop()
- MediaEvent("on_eos").sync_dispatch_to_player(self.player)
+ pyglet.app.platform_event_loop.post_event(self.player, 'on_eos')
else:
current_buffers = []
while buffers_queued < self.max_buffer_count:
@@ -206,9 +205,6 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
self._dispatch_pending_events()
- def _dispatch_new_event(self, event_name):
- MediaEvent(event_name).sync_dispatch_to_player(self.player)
-
def _add_audiodata_events(self, audio_data):
for event in audio_data.events:
event_cursor = self._write_cursor + event.timestamp * self.source.audio_format.bytes_per_second
diff --git a/libs/pyglet/window/__init__.py b/libs/pyglet/window/__init__.py
index e7f8fa7..5bc5277 100644
--- a/libs/pyglet/window/__init__.py
+++ b/libs/pyglet/window/__init__.py
@@ -623,6 +623,80 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
"""
raise NotImplementedError('abstract')
+ # Public methods (sort alphabetically):
+ 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')
+
+ @staticmethod
+ def clear():
+ """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 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)
+ self._event_queue = []
+
+ def dispatch_event(self, *args):
+ if not self._enable_event_queue or self._allow_dispatch_event:
+ super().dispatch_event(*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')
+
+ 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.
+
+ There is little need to override this method; instead, subclass
+ :py:class:`MouseCursor` and provide your own
+ :py:meth:`~MouseCursor.draw` method.
+ """
+ # Draw mouse cursor if set and visible.
+
+ if self._mouse_cursor.gl_drawable and self._mouse_visible and self._mouse_in_window:
+ # TODO: consider projection differences
+ self._mouse_cursor.draw(self._mouse_x, self._mouse_y)
+
def flip(self):
"""Swap the OpenGL front and back buffers.
@@ -635,13 +709,124 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
"""
raise NotImplementedError('abstract')
- def switch_to(self):
- """Make this window the current OpenGL rendering context.
+ def get_framebuffer_size(self):
+ """Return the size in actual pixels of the Window framebuffer.
+
+ When using HiDPI screens, the size of the Window's framebuffer
+ can be higher than that of the Window size requested. If you
+ are performing operations that require knowing the actual number
+ of pixels in the window, this method should be used instead of
+ :py:func:`Window.get_size()`. For example, setting the Window
+ projection or setting the glViewport size.
+
+ :rtype: (int, int)
+ :return: The width and height of the Window's framebuffer, in pixels.
+ """
+ return self.get_size()
+
+ 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 get_pixel_ratio(self):
+ """Return the framebuffer/window size ratio.
+
+ Some platforms and/or window systems support subpixel scaling,
+ making the framebuffer size larger than the window size.
+ Retina screens on OS X and Gnome on Linux are some examples.
+
+ On a Retina systems the returned ratio would usually be 2.0 as a
+ window of size 500 x 500 would have a framebuffer of 1000 x 1000.
+ Fractional values between 1.0 and 2.0, as well as values above
+ 2.0 may also be encountered.
+
+ :rtype: float
+ :return: The framebuffer/window size ratio
+ """
+ return self.get_framebuffer_size()[0] / self.width
+
+ def get_size(self) -> Tuple[int, int]:
+ """Return the current size of the window.
+
+ This does not include the windows' border or title bar.
+
+ :rtype: (int, int)
+ :return: The width and height of the window, in pixels.
+ """
+ return self._width, self._height
+
+ 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 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 on_close(self):
+ """Default on_close handler."""
+ self.has_exit = True
+ from pyglet import app
+ if app.event_loop.is_running:
+ self.close()
+
+ def on_key_press(self, symbol, modifiers):
+ """Default on_key_press handler."""
+ if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
+ key.MOD_CAPSLOCK |
+ key.MOD_SCROLLLOCK)):
+ self.dispatch_event('on_close')
+
+ def on_resize(self, width, height):
+ """A default resize event handler.
+
+ This default handler updates the GL viewport to cover the entire
+ window. The bottom-left corner is (0, 0) and the top-right
+ corner is the width and height of the window's framebuffer.
+ In addition, the projection matrix is set to an orghogonal
+ projection based on the same dimensions.
+ """
+ gl.glViewport(0, 0, *self.get_framebuffer_size())
+ self.projection = Mat4.orthogonal_projection(0, width, 0, height, -255, 255)
+
+ 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.
- 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')
@@ -740,69 +925,233 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
height = self.screen.height
return width, height
- def on_resize(self, width, height):
- """A default resize event handler.
+ def set_minimum_size(self, width: int, height: int) -> None:
+ """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.
- This default handler updates the GL viewport to cover the entire
- window. The bottom-left corner is (0, 0) and the top-right
- corner is the width and height of the window's framebuffer.
- In addition, the projection matrix is set to an orghogonal
- projection based on the same dimensions.
"""
- gl.glViewport(0, 0, *self.get_framebuffer_size())
- self.projection = Mat4.orthogonal_projection(0, width, 0, height, -255, 255)
+ if width < 1 or height < 1:
+ raise ValueError('width and height must be positive integers')
- def on_close(self):
- """Default on_close handler."""
- self.has_exit = True
- from pyglet import app
- if app.event_loop.is_running:
- self.close()
+ self._minimum_size = width, height
- def on_key_press(self, symbol, modifiers):
- """Default on_key_press handler."""
- if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
- key.MOD_CAPSLOCK |
- key.MOD_SCROLLLOCK)):
- self.dispatch_event('on_close')
+ def set_maximum_size(self, width: int, height: int) -> None:
+ """Set the maximum size of the window.
- def close(self):
- """Close 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).
- After closing the window, the GL context will be invalid. The
- window instance cannot be reused once closed (see also `set_visible`).
+ 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.
- 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)
- self._event_queue = []
+ if width < 1 or height < 1:
+ raise ValueError('width and height must be positive integers')
- def draw_mouse_cursor(self):
- """Draw the custom mouse cursor.
+ self._maximum_size = width, height
- If the current mouse cursor has ``drawable`` set, this method
- is called before the buffers are flipped to render it.
+ def set_size(self, width: int, height: int) -> None:
+ """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.
- There is little need to override this method; instead, subclass
- :py:class:`MouseCursor` and provide your own
- :py:meth:`~MouseCursor.draw` method.
"""
- # Draw mouse cursor if set and visible.
+ if self._fullscreen:
+ raise WindowException('Cannot set size of fullscreen window.')
+ if width < 1 or height < 1:
+ raise ValueError('width and height must be positive integers')
- if self._mouse_cursor.gl_drawable and self._mouse_visible and self._mouse_in_window:
- # TODO: consider projection differences
- self._mouse_cursor.draw(self._mouse_x, self._mouse_y)
+ self._width, self._height = width, height
- # These properties provide read-only access to instance variables.
+ 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 set_visible(self, visible: bool = True) -> None:
+ """Show or hide the window.
+
+ :Parameters:
+ `visible` : bool
+ If True, the window will be shown; otherwise it will be
+ hidden.
+ """
+ self._visible = visible
+
+ def set_vsync(self, vsync: bool) -> None:
+ """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 analogous 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.
+
+ Also note that 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.
+
+ :Parameters:
+ `vsync` : bool
+ If True, vsync is enabled, otherwise it is disabled.
+
+ """
+ self._vsync = vsync
+
+ 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.
+
+ """
+ self._mouse_exclusive = exclusive
+
+ 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.
+
+ """
+ self._keyboard_exclusive = exclusive
+
+ 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 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')
+
+ # Attributes (sort alphabetically):
@property
def caption(self):
"""The window caption (title). Read-only.
@@ -935,6 +1284,9 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
def projection(self):
"""The OpenGL window projection matrix. Read-write.
+ This matrix is used to transform vertices when using any of the built-in
+ drawable classes. `view` is done first, then `projection`.
+
The default projection matrix is orthographic (2D),
but a custom :py:class:`pyglet.math.Mat4` instance
can be set. Alternatively, you can supply a flat
@@ -959,6 +1311,9 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
def view(self):
"""The OpenGL window view matrix. Read-write.
+ This matrix is used to transform vertices when using any of the built-in
+ drawable classes. `view` is done first, then `projection`.
+
The default view is an identity matrix, but a custom
:py:class:`pyglet.math.Mat4` instance can be set.
Alternatively, you can supply a flat tuple of 16 values.
@@ -1344,6 +1699,118 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
# If documenting, show the event methods. Otherwise, leave them out
# as they are not really methods.
if _is_pyglet_doc_run:
+ def on_activate(self):
+ """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_close(self):
+ """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_context_lost(self):
+ """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(self):
+ """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_deactivate(self):
+ """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_draw(self, dt):
+ """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.
+
+ .. versionadded:: 1.1
+
+ :event:
+ """
+
+ def on_expose(self):
+ """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_file_drop(self, x, y, paths):
+ """File(s) were dropped into the window, will return the position of the cursor and
+ a list of paths to the files that were dropped.
+
+ .. versionadded:: 1.5.1
+
+ :event:
+ """
+
+ def on_hide(self):
+ """The window was hidden.
+
+ This event is triggered when a window is minimised
+ or hidden by the user.
+
+ :event:
+ """
+
def on_key_press(self, symbol, modifiers):
"""A key on the keyboard was pressed (and held down).
@@ -1371,96 +1838,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
:event:
"""
- def on_text(self, text):
- """The user input some text.
-
- Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
- :py:meth:`~pyglet.window.Window.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(self, motion):
- """The user moved the text input cursor.
-
- Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
- :py:meth:`~pyglet.window.Window.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
- :py:mod:`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(self, motion):
- """The user moved the text input cursor while extending the
- selection.
-
- Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
- :py:meth:`~pyglet.window.Window.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 :py:meth:`~pyglet.window.Window.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 :py:mod:`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(self, x, y, dx, dy):
"""The mouse was moved with no buttons held down.
@@ -1556,19 +1933,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
:event:
"""
- def on_close(self):
- """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(self, x, y):
"""The mouse was moved into the window.
@@ -1600,36 +1964,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
:event:
"""
- def on_expose(self):
- """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(self, 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(self, x, y):
"""The window was moved.
@@ -1645,99 +1979,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
:event:
"""
- def on_activate(self):
- """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(self):
- """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(self):
- """The window was shown.
-
- This event is triggered when a window is restored after being
- minimised, hidden, or after being displayed for the first time.
-
- :event:
- """
-
- def on_hide(self):
- """The window was hidden.
-
- This event is triggered when a window is minimised
- or hidden by the user.
-
- :event:
- """
-
- def on_context_lost(self):
- """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(self):
- """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_file_drop(self, x, y, paths):
- """File(s) were dropped into the window, will return the position of the cursor and
- a list of paths to the files that were dropped.
-
- .. versionadded:: 1.5.1
-
- :event:
- """
-
- def on_draw(self, dt):
- """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.
-
- .. versionadded:: 1.1
-
- :event:
- """
-
def on_refresh(self, dt):
"""The window contents must be redrawn.
@@ -1757,6 +1998,120 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
:event:
"""
+ def on_resize(self, 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_show(self):
+ """The window was shown.
+
+ This event is triggered when a window is restored after being
+ minimised, hidden, or after being displayed for the first time.
+
+ :event:
+ """
+
+ def on_text(self, text):
+ """The user input some text.
+
+ Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
+ :py:meth:`~pyglet.window.Window.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(self, motion):
+ """The user moved the text input cursor.
+
+ Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
+ :py:meth:`~pyglet.window.Window.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
+ :py:mod:`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(self, motion):
+ """The user moved the text input cursor while extending the
+ selection.
+
+ Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
+ :py:meth:`~pyglet.window.Window.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 :py:meth:`~pyglet.window.Window.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 :py:mod:`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:
+ """
+
BaseWindow.register_event_type('on_key_press')
BaseWindow.register_event_type('on_key_release')