use new pyglet local
[build skip] docs try hard link 非得更新一下是吧 [build skip]
This commit is contained in:
parent
46f21e607a
commit
f16807715c
@ -1,7 +1,5 @@
|
|||||||
# Difficult Rocket
|
# Difficult Rocket
|
||||||
|
|
||||||
[comment]: <> ([中文](./docs/README-cn.md) | English)
|
|
||||||
|
|
||||||
中文 | [English](/docs/README-en.md)
|
中文 | [English](/docs/README-en.md)
|
||||||
|
|
||||||
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# Difficult Rocket
|
# Difficult Rocket
|
||||||
|
|
||||||
[comment]: <> (中文 | [English](https://github.com/shenjackyuanjie/Difficult-Rocket).)
|
|
||||||
|
|
||||||
[中文](../README.md) | English
|
[中文](../README.md) | English
|
||||||
|
|
||||||
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# 嘿 看啥呢
|
# 嘿 看啥呢 404!
|
||||||
|
|
||||||
- 很明显,这里没有你想要的东西
|
- 很明显,这里没有你想要的东西
|
||||||
|
|
||||||
|
116
docs/src/README-en.md
Normal file
116
docs/src/README-en.md
Normal file
@ -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)
|
||||||
|
|
||||||
|
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
||||||
|
[![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.
|
110
docs/src/README.md
Symbolic link
110
docs/src/README.md
Symbolic link
@ -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)
|
||||||
|
|
||||||
|
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
||||||
|
[![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)
|
||||||
|
|
||||||
|
这是一份普通人可以理解的许可协议概要 (但不是替代) 。 免责声明.
|
||||||
|
|
||||||
|
您可以自由地:
|
||||||
|
|
||||||
|
共享 — 在任何媒介以任何形式复制、发行本作品
|
||||||
|
|
||||||
|
演绎 — 修改、转换或以本作品为基础进行创作
|
||||||
|
|
||||||
|
只要你遵守许可协议条款,许可人就无法收回你的这些权利。
|
||||||
|
|
||||||
|
惟须遵守下列条件:
|
||||||
|
|
||||||
|
署名 — 您必须给出地当的署名,提供指向本许可协议的链接,同时标明是否(对原始作品)作了修改。您可以用任何合理的方式来署名,但是不得以任何方式暗示许可人为您或您的使用背书。
|
||||||
|
|
||||||
|
非商业性使用 — 您不得将本作品用于商业目的。
|
||||||
|
|
||||||
|
相同方式共享 — 如果您再混合、转换或者基于本作品进行创作,您必须基于与原先许可协议地同的许可协议 分发您贡献的作品。
|
||||||
|
|
||||||
|
没有附加限制 — 您不得适用法律术语或者 技术措施 从而限制其他人做许可协议允许的事情。
|
||||||
|
|
||||||
|
声明:
|
||||||
|
|
||||||
|
您不必因为公共领域的作品要素而遵守许可协议,或者您的使用被可适用的 例外或限制所允许。
|
||||||
|
|
||||||
|
不提供担保。许可协议可能不会给与您意图使用的所必须的所有许可。例如,其他权利比如形象权、隐私权或人格权可能限制您如何使用作品。
|
@ -1,5 +1,8 @@
|
|||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
- [README](./README.md)
|
||||||
|
- [README-en](./README-en.md)
|
||||||
|
|
||||||
- [update logs](./update_logs.md)
|
- [update logs](./update_logs.md)
|
||||||
- [contributors](./contributors.md)
|
- [contributors](./contributors.md)
|
||||||
|
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
# 如何帮助 DR 开发
|
# 如何帮助 DR 开发
|
||||||
|
|
||||||
aaaa
|
## 需要准备的工具
|
||||||
|
|
||||||
|
1. Powershell 7+
|
||||||
|
2. Python3.8 +
|
||||||
|
3. gcc / clang 编译器
|
||||||
|
4. git
|
||||||
|
@ -415,6 +415,7 @@ objc.sel_isEqual.argtypes = [c_void_p, c_void_p]
|
|||||||
objc.sel_registerName.restype = c_void_p
|
objc.sel_registerName.restype = c_void_p
|
||||||
objc.sel_registerName.argtypes = [c_char_p]
|
objc.sel_registerName.argtypes = [c_char_p]
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# void *objc_autoreleasePoolPush(void)
|
# void *objc_autoreleasePoolPush(void)
|
||||||
objc.objc_autoreleasePoolPush.restype = c_void_p
|
objc.objc_autoreleasePoolPush.restype = c_void_p
|
||||||
@ -644,8 +645,8 @@ def parse_type_encoding(encoding):
|
|||||||
def cfunctype_for_encoding(encoding):
|
def cfunctype_for_encoding(encoding):
|
||||||
# Check if we've already created a CFUNCTYPE for this encoding.
|
# Check if we've already created a CFUNCTYPE for this encoding.
|
||||||
# If so, then return the cached CFUNCTYPE.
|
# If so, then return the cached CFUNCTYPE.
|
||||||
#if encoding in cfunctype_table:
|
if encoding in cfunctype_table:
|
||||||
# return cfunctype_table[encoding]
|
return cfunctype_table[encoding]
|
||||||
|
|
||||||
# Otherwise, create a new CFUNCTYPE for the 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,
|
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.
|
# Cache the new CFUNCTYPE in the cfunctype_table.
|
||||||
# We do this mainly because it prevents the CFUNCTYPE
|
# We do this mainly because it prevents the CFUNCTYPE
|
||||||
# from being garbage-collected while we need it.
|
# from being garbage-collected while we need it.
|
||||||
#cfunctype_table[encoding] = cfunctype
|
cfunctype_table[encoding] = cfunctype
|
||||||
return cfunctype
|
return cfunctype
|
||||||
|
|
||||||
|
|
||||||
@ -728,12 +729,12 @@ class ObjCMethod:
|
|||||||
# Note, need to map 'c' to c_byte rather than c_char, because otherwise
|
# 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
|
# 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.
|
# 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,
|
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'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'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,
|
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,
|
NSPointEncoding: NSPoint, NSSizeEncoding: NSSize, NSRectEncoding: NSRect,
|
||||||
NSRangeEncoding: NSRange,
|
NSRangeEncoding: NSRange,
|
||||||
PyObjectEncoding: py_object}
|
PyObjectEncoding: py_object}
|
||||||
|
|
||||||
cfunctype_table = {}
|
cfunctype_table = {}
|
||||||
|
@ -861,7 +861,7 @@ class Mat4(tuple):
|
|||||||
def look_at(cls: type[Mat4T], position: Vec3, target: Vec3, up: Vec3):
|
def look_at(cls: type[Mat4T], position: Vec3, target: Vec3, up: Vec3):
|
||||||
f = (target - position).normalize()
|
f = (target - position).normalize()
|
||||||
u = up.normalize()
|
u = up.normalize()
|
||||||
s = f.cross(u)
|
s = f.cross(u).normalize()
|
||||||
u = s.cross(f)
|
u = s.cross(f)
|
||||||
|
|
||||||
return cls([s.x, u.x, -f.x, 0.0,
|
return cls([s.x, u.x, -f.x, 0.0,
|
||||||
|
@ -135,17 +135,6 @@ class AudioData:
|
|||||||
self.duration -= num_bytes / audio_format.bytes_per_second
|
self.duration -= num_bytes / audio_format.bytes_per_second
|
||||||
self.timestamp += 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:
|
class SourceInfo:
|
||||||
"""Source metadata information.
|
"""Source metadata information.
|
||||||
@ -409,7 +398,7 @@ class StaticSource(Source):
|
|||||||
audio_data = source.get_audio_data(buffer_size)
|
audio_data = source.get_audio_data(buffer_size)
|
||||||
if not audio_data:
|
if not audio_data:
|
||||||
break
|
break
|
||||||
data.write(audio_data.get_string_data())
|
data.write(audio_data.data)
|
||||||
self._data = data.getvalue()
|
self._data = data.getvalue()
|
||||||
|
|
||||||
self._duration = len(self._data) / self.audio_format.bytes_per_second
|
self._duration = len(self._data) / self.audio_format.bytes_per_second
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import math
|
import math
|
||||||
import time
|
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import pyglet
|
|
||||||
from pyglet.util import with_metaclass
|
from pyglet.util import with_metaclass
|
||||||
|
|
||||||
|
|
||||||
@ -185,36 +184,3 @@ class AbstractAudioDriver(with_metaclass(ABCMeta)):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def delete(self):
|
def delete(self):
|
||||||
pass
|
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)
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import math
|
import math
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
|
import pyglet.app
|
||||||
from . import interface
|
from . import interface
|
||||||
from pyglet.util import debug_print
|
from pyglet.util import debug_print
|
||||||
from pyglet.media.mediathreads import PlayerWorkerThread
|
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
|
from pyglet.media.drivers.listener import AbstractListener
|
||||||
|
|
||||||
_debug = debug_print('debug_media')
|
_debug = debug_print('debug_media')
|
||||||
@ -75,7 +76,7 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
|
|||||||
self._play_cursor_ring = 0
|
self._play_cursor_ring = 0
|
||||||
self._write_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 = []
|
self._events = []
|
||||||
|
|
||||||
# List of (cursor, timestamp), in sort order (cursor gives expiry
|
# List of (cursor, timestamp), in sort order (cursor gives expiry
|
||||||
@ -157,9 +158,6 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
|
|||||||
return (self._eos_cursor is not None
|
return (self._eos_cursor is not None
|
||||||
and self._play_cursor > self._eos_cursor)
|
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):
|
def _get_audiodata(self):
|
||||||
if self._audiodata_buffer is None or self._audiodata_buffer.length == 0:
|
if self._audiodata_buffer is None or self._audiodata_buffer.length == 0:
|
||||||
self._get_new_audiodata()
|
self._get_new_audiodata()
|
||||||
@ -246,7 +244,7 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
|
|||||||
if self._playing and self._has_underrun():
|
if self._playing and self._has_underrun():
|
||||||
assert _debug('underrun, stopping')
|
assert _debug('underrun, stopping')
|
||||||
self.stop()
|
self.stop()
|
||||||
self._dispatch_new_event('on_eos')
|
pyglet.app.platform_event_loop.post_event(self.player, 'on_eos')
|
||||||
|
|
||||||
def _get_write_size(self):
|
def _get_write_size(self):
|
||||||
self.update_play_cursor()
|
self.update_play_cursor()
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
|
import pyglet.app
|
||||||
from . import interface
|
from . import interface
|
||||||
from pyglet.util import debug_print
|
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.mediathreads import PlayerWorkerThread
|
||||||
from pyglet.media.drivers.listener import AbstractListener
|
from pyglet.media.drivers.listener import AbstractListener
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ class OpenALAudioPlayer(AbstractAudioPlayer):
|
|||||||
# of underrun)
|
# of underrun)
|
||||||
self._underrun_timestamp = None
|
self._underrun_timestamp = None
|
||||||
|
|
||||||
# List of (cursor, MediaEvent)
|
# List of cursor
|
||||||
self._events = []
|
self._events = []
|
||||||
|
|
||||||
# Desired play state (True even if stopped due to underrun)
|
# Desired play state (True even if stopped due to underrun)
|
||||||
@ -280,7 +281,7 @@ class OpenALAudioPlayer(AbstractAudioPlayer):
|
|||||||
assert _debug('No audio data left')
|
assert _debug('No audio data left')
|
||||||
if self._has_underrun():
|
if self._has_underrun():
|
||||||
assert _debug('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):
|
def _queue_audio_data(self, audio_data, length):
|
||||||
buf = self.alsource.get_buffer()
|
buf = self.alsource.get_buffer()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import weakref
|
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.media.drivers.listener import AbstractListener
|
||||||
from pyglet.util import debug_print
|
from pyglet.util import debug_print
|
||||||
|
|
||||||
@ -217,7 +218,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
|
|||||||
if self._has_audio_data():
|
if self._has_audio_data():
|
||||||
self._write_to_stream()
|
self._write_to_stream()
|
||||||
else:
|
else:
|
||||||
self._add_event_at_write_index('on_eos')
|
self._events.append('on_eos')
|
||||||
|
|
||||||
def _process_events(self):
|
def _process_events(self):
|
||||||
assert _debug('PulseAudioPlayer: Process events')
|
assert _debug('PulseAudioPlayer: Process events')
|
||||||
@ -235,13 +236,9 @@ class PulseAudioPlayer(AbstractAudioPlayer):
|
|||||||
assert _debug('PulseAudioPlayer: Dispatch events at index {}'.format(read_index))
|
assert _debug('PulseAudioPlayer: Dispatch events at index {}'.format(read_index))
|
||||||
|
|
||||||
while self._events and self._events[0][0] <= read_index:
|
while self._events and self._events[0][0] <= read_index:
|
||||||
_, event = self._events.pop(0)
|
event_name = self._events.pop(0)
|
||||||
assert _debug('PulseAudioPlayer: Dispatch event', event)
|
assert _debug('PulseAudioPlayer: Dispatch event', event_name)
|
||||||
event._sync_dispatch_to_player(self.player)
|
pyglet.app.platform_event_loop.post_event(self.player, event_name)
|
||||||
|
|
||||||
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)))
|
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
assert _debug('Delete PulseAudioPlayer')
|
assert _debug('Delete PulseAudioPlayer')
|
||||||
@ -255,7 +252,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
|
|||||||
|
|
||||||
if driver.mainloop is None:
|
if driver.mainloop is None:
|
||||||
assert _debug('PulseAudioDriver already deleted. '
|
assert _debug('PulseAudioDriver already deleted. '
|
||||||
'PulseAudioPlayer could not clean up properly.')
|
'PulseAudioPlayer could not clean up properly.')
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._time_sync_operation is not None:
|
if self._time_sync_operation is not None:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import math
|
import math
|
||||||
|
|
||||||
import pyglet
|
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.media.drivers.listener import AbstractListener
|
||||||
from pyglet.util import debug_print
|
from pyglet.util import debug_print
|
||||||
from . import interface
|
from . import interface
|
||||||
@ -48,7 +48,7 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
|||||||
self._write_cursor = 0
|
self._write_cursor = 0
|
||||||
self._play_cursor = 0
|
self._play_cursor = 0
|
||||||
|
|
||||||
# List of (play_cursor, MediaEvent), in sort order
|
# List of play_cursor, in sort order
|
||||||
self._events = []
|
self._events = []
|
||||||
|
|
||||||
# List of (cursor, timestamp), in sort order (cursor gives expiry
|
# List of (cursor, timestamp), in sort order (cursor gives expiry
|
||||||
@ -89,7 +89,6 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
|||||||
if not self._buffers:
|
if not self._buffers:
|
||||||
self._xa2_driver.return_voice(self._xa2_source_voice)
|
self._xa2_driver.return_voice(self._xa2_source_voice)
|
||||||
|
|
||||||
|
|
||||||
def play(self):
|
def play(self):
|
||||||
assert _debug('XAudio2 play')
|
assert _debug('XAudio2 play')
|
||||||
|
|
||||||
@ -168,7 +167,7 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
|||||||
if self.buffer_end_submitted:
|
if self.buffer_end_submitted:
|
||||||
if buffers_queued == 0:
|
if buffers_queued == 0:
|
||||||
self._xa2_source_voice.stop()
|
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:
|
else:
|
||||||
current_buffers = []
|
current_buffers = []
|
||||||
while buffers_queued < self.max_buffer_count:
|
while buffers_queued < self.max_buffer_count:
|
||||||
@ -206,9 +205,6 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
|||||||
|
|
||||||
self._dispatch_pending_events()
|
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):
|
def _add_audiodata_events(self, audio_data):
|
||||||
for event in audio_data.events:
|
for event in audio_data.events:
|
||||||
event_cursor = self._write_cursor + event.timestamp * self.source.audio_format.bytes_per_second
|
event_cursor = self._write_cursor + event.timestamp * self.source.audio_format.bytes_per_second
|
||||||
|
@ -623,6 +623,80 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError('abstract')
|
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):
|
def flip(self):
|
||||||
"""Swap the OpenGL front and back buffers.
|
"""Swap the OpenGL front and back buffers.
|
||||||
|
|
||||||
@ -635,13 +709,124 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError('abstract')
|
raise NotImplementedError('abstract')
|
||||||
|
|
||||||
def switch_to(self):
|
def get_framebuffer_size(self):
|
||||||
"""Make this window the current OpenGL rendering context.
|
"""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')
|
raise NotImplementedError('abstract')
|
||||||
|
|
||||||
@ -740,69 +925,233 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
height = self.screen.height
|
height = self.screen.height
|
||||||
return width, height
|
return width, height
|
||||||
|
|
||||||
def on_resize(self, width, height):
|
def set_minimum_size(self, width: int, height: int) -> None:
|
||||||
"""A default resize event handler.
|
"""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())
|
if width < 1 or height < 1:
|
||||||
self.projection = Mat4.orthogonal_projection(0, width, 0, height, -255, 255)
|
raise ValueError('width and height must be positive integers')
|
||||||
|
|
||||||
def on_close(self):
|
self._minimum_size = width, height
|
||||||
"""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):
|
def set_maximum_size(self, width: int, height: int) -> None:
|
||||||
"""Default on_key_press handler."""
|
"""Set the maximum size of the window.
|
||||||
if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
|
|
||||||
key.MOD_CAPSLOCK |
|
|
||||||
key.MOD_SCROLLLOCK)):
|
|
||||||
self.dispatch_event('on_close')
|
|
||||||
|
|
||||||
def close(self):
|
Once set, the user will not be able to resize the window larger
|
||||||
"""Close the window.
|
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
|
The behaviour is undefined if the maximum size is set smaller than
|
||||||
window instance cannot be reused once closed (see also `set_visible`).
|
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 width < 1 or height < 1:
|
||||||
if not self._context:
|
raise ValueError('width and height must be positive integers')
|
||||||
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 draw_mouse_cursor(self):
|
self._maximum_size = width, height
|
||||||
"""Draw the custom mouse cursor.
|
|
||||||
|
|
||||||
If the current mouse cursor has ``drawable`` set, this method
|
def set_size(self, width: int, height: int) -> None:
|
||||||
is called before the buffers are flipped to render it.
|
"""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:
|
self._width, self._height = width, height
|
||||||
# TODO: consider projection differences
|
|
||||||
self._mouse_cursor.draw(self._mouse_x, self._mouse_y)
|
|
||||||
|
|
||||||
# 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
|
@property
|
||||||
def caption(self):
|
def caption(self):
|
||||||
"""The window caption (title). Read-only.
|
"""The window caption (title). Read-only.
|
||||||
@ -935,6 +1284,9 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
def projection(self):
|
def projection(self):
|
||||||
"""The OpenGL window projection matrix. Read-write.
|
"""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),
|
The default projection matrix is orthographic (2D),
|
||||||
but a custom :py:class:`pyglet.math.Mat4` instance
|
but a custom :py:class:`pyglet.math.Mat4` instance
|
||||||
can be set. Alternatively, you can supply a flat
|
can be set. Alternatively, you can supply a flat
|
||||||
@ -959,6 +1311,9 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
def view(self):
|
def view(self):
|
||||||
"""The OpenGL window view matrix. Read-write.
|
"""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
|
The default view is an identity matrix, but a custom
|
||||||
:py:class:`pyglet.math.Mat4` instance can be set.
|
:py:class:`pyglet.math.Mat4` instance can be set.
|
||||||
Alternatively, you can supply a flat tuple of 16 values.
|
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
|
# If documenting, show the event methods. Otherwise, leave them out
|
||||||
# as they are not really methods.
|
# as they are not really methods.
|
||||||
if _is_pyglet_doc_run:
|
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):
|
def on_key_press(self, symbol, modifiers):
|
||||||
"""A key on the keyboard was pressed (and held down).
|
"""A key on the keyboard was pressed (and held down).
|
||||||
|
|
||||||
@ -1371,96 +1838,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
:event:
|
: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):
|
def on_mouse_motion(self, x, y, dx, dy):
|
||||||
"""The mouse was moved with no buttons held down.
|
"""The mouse was moved with no buttons held down.
|
||||||
|
|
||||||
@ -1556,19 +1933,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
:event:
|
: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):
|
def on_mouse_enter(self, x, y):
|
||||||
"""The mouse was moved into the window.
|
"""The mouse was moved into the window.
|
||||||
|
|
||||||
@ -1600,36 +1964,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
:event:
|
: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):
|
def on_move(self, x, y):
|
||||||
"""The window was moved.
|
"""The window was moved.
|
||||||
|
|
||||||
@ -1645,99 +1979,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
:event:
|
: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):
|
def on_refresh(self, dt):
|
||||||
"""The window contents must be redrawn.
|
"""The window contents must be redrawn.
|
||||||
|
|
||||||
@ -1757,6 +1998,120 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
|||||||
:event:
|
: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_press')
|
||||||
BaseWindow.register_event_type('on_key_release')
|
BaseWindow.register_event_type('on_key_release')
|
||||||
|
Loading…
Reference in New Issue
Block a user