0.6.1 update!

This commit is contained in:
shenjackyuanjie 2021-12-26 23:06:03 +08:00
parent 2ed77e7c3c
commit a4c643c80a
97 changed files with 2835 additions and 208 deletions

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,3 +1,9 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
import functools
import inspect
import threading

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
@ -127,8 +127,6 @@ class ClientWindow(Window):
batch=self.label_batch) # 实例化
self.push_handlers(self.input_box)
self.input_box.enabled = True
self.label = pyglet.text.HTMLLabel(text=f'<font color=red real_size=20 face="{translate.HOS_S}">abc</font>',
x=self.width // 2, y=self.height // 2)
# fps显示
self.fps_label = pyglet.text.Label(x=10, y=self.height - 10,
width=self.width - 20, height=20,
@ -212,7 +210,6 @@ class ClientWindow(Window):
def on_draw(self, *dt):
self.clear()
self.draw_batch()
self.label.draw()
def on_resize(self, width: int, height: int):
super().on_resize(width, height)

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
@ -20,7 +20,6 @@ from decimal import Decimal
# from DR
from Difficult_Rocket import translate
from Difficult_Rocket.api import new_thread
from Difficult_Rocket.guis.widgets import InputBox
# from libs.pyglet
from libs import pyglet

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
@ -23,7 +23,7 @@ from libs.pyglet import clock
class FpsLogger:
def __init__(self,
stable_fps: int = 60,
count: int = 400):
count: int = 700):
self.stable_fps = stable_fps
self.count = count
self._fps = stable_fps
@ -46,7 +46,7 @@ class FpsLogger:
if len(self.get_fps_list) > self.count:
self.get_fps_list = self.get_fps_list[-self.count + 1:]
try:
self._fps = statistics.geometric_mean(self.fps_list[-200:])
self._fps = statistics.geometric_mean(self.fps_list[-100:])
self.middle_fps = statistics.median(self.fps_list)
except Exception:
print(self.fps_list)

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
@ -10,7 +10,3 @@ mail: 3695888@qq.com
github: @shenjackyuanjie
gitee: @shenjackyuanjie
"""
from .widgets import *
__all__ = ['widgets']

View File

@ -0,0 +1,342 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
"""
writen by shenjackyuanjie
mail: 3695888@qq.com
github: @shenjackyuanjie
gitee: @shenjackyuanjie
"""
import re
import pprint
from Difficult_Rocket import translate
default_style = {
'font_name': 'Times New Roman',
'font_size': 12,
'bold': False,
'italic': False
}
class SingleTextStyle:
"""
单个字符的字体样式
"""
def __init__(self,
font_name: str = '',
font_size: int = 12,
bold: bool = False,
italic: bool = False,
color: str = 'white',
text_tag: list = None,
show: bool = True,
prefix: str = '',
suffix: str = '',
text: str = ''):
self.font_name = font_name
self.font_size = font_size
self.bold = bold
self.italic = italic
self.color = color
self.prefix = prefix
self.suffix = suffix
if not text_tag:
self._tag = []
else:
self._tag = text_tag
self.show = show
self.text = text
@property
def tag(self) -> list:
return self._tag
@tag.setter
def tag(self, value: list):
assert type(value) == list, 'SingleTextStyle.tag must be list'
for tag in value:
if tag not in self._tag:
self._tag.append(tag)
self._tag.sort()
"""
对运算操作的支持
"""
def __add__(self, other: 'SingleTextStyle') -> 'SingleTextStyle':
"""
叠加两个字体样式 优先使用 other 的样式
:param other: 叠加的字体样式
:return: 叠加后的字体样式
"""
assert type(other) == SingleTextStyle, f'SingleTextStyle + other\n other must be the same type, not a {type(other)}'
return SingleTextStyle(
font_name=other.font_name or self.font_name,
font_size=other.font_size or self.font_size,
bold=other.bold or self.bold,
italic=other.italic or self.italic,
color=other.color or self.color,
text_tag=other.tag + self.tag,
show=other.show or self.show,
prefix=other.prefix + self.prefix,
suffix=other.suffix + self.suffix,
text=self.text
)
def __iadd__(self, other: 'SingleTextStyle') -> 'SingleTextStyle':
"""
叠加两个字体样式 优先使用 other 的样式
:param other: 叠加的字体样式
:return: 叠加后的字体样式
"""
assert type(other) == SingleTextStyle, f'SingleTextStyle += other\n other must be the same type, not a {type(other)}'
self.font_name = other.font_name or self.font_name
self.font_size = other.font_size or self.font_size
self.bold = other.bold or self.bold
self.italic = other.italic or self.italic
self.color = other.color or self.color
self.tag += other.tag
self.show = other.show or self.show
self.prefix += other.prefix
self.suffix += other.suffix
self.text = self.text
return self
"""
对各种判定的支持
"""
def have_tag(self, other: 'SingleTextStyle') -> bool:
"""
比较两个字体样式tag是否相同
:param other: 叠加的字体样式
:return: 是否相同
"""
assert type(other) == SingleTextStyle
return other.tag in self.tag
def same_font(self, other: 'SingleTextStyle') -> bool:
"""
比较两个字体样式的字体属性是否相同
:param other: 叠加的字体样式
:return: 是否相同
"""
assert type(other) == SingleTextStyle
return (self.font_name == other.font_name and
self.font_size == other.font_size and
self.color == other.color and
self.show == other.show)
def same_bold(self, other: 'SingleTextStyle') -> bool:
"""
比较两个字体样式的加粗属性是否相同
:param other: 叠加的字体样式
:return: 是否相同
"""
assert type(other) == SingleTextStyle
return self.bold == other.bold
def same_italic(self, other: 'SingleTextStyle') -> bool:
"""
比较两个字体样式的斜体属性是否相同
:param other: 叠加的字体样式
:return: 是否相同
"""
assert type(other) == SingleTextStyle
return self.italic == other.italic
"""
自动输出一些属性的支持
"""
def HTML_font(self, suffix: bool = False) -> str:
"""
输出字体样式的HTML字符
:return: HTML 格式字符
"""
if suffix:
return font_HTML_end
text = f'<font face="{self.font_name}" color={self.color}'
if self.font_size != default_style['font_size']:
text += f' real_size={self.font_size}'
text += '>'
return text
def HTML_bold(self, suffix: bool = False) -> str:
"""
输出字体粗体的HTML字符
:return: HTML 格式字符
"""
if self.bold:
if suffix:
return bold_HTML_end
return '<b>'
else:
return ''
def HTML_italic(self, suffix: bool = False) -> str:
"""
输出字体斜体的HTML字符
:return: HTML 格式字符
"""
if self.italic:
if suffix:
return italic_HTML_end
return '<i>'
else:
return ''
def HTML(self, suffix: bool = False) -> str:
"""
输出字体样式的HTML字符
:return: HTML 格式字符
"""
if not suffix:
return self.HTML_bold() + self.HTML_italic() + self.HTML_font()
else:
return font_HTML_end + (bold_HTML_end if self.bold else '') + (italic_HTML_end if self.italic else '')
# [\u4e00-\u9fa5] 中文字符
default_fonts_config = [
{
'match': re.compile(r'.'), # 匹配的字符 匹配选项是re.compile()
'shown': re.compile(r'.'), # 匹配到的字符中显示的部分 匹配选项是re.compile()
'style': SingleTextStyle(font_name=translate.鸿蒙简体, font_size=15, bold=False, italic=False, show=True, color='white'),
},
{
'match': re.compile(r'[a-zA-Z0-9]'),
'shown': re.compile(r'[a-zA-Z0-9]'),
'style': SingleTextStyle(font_name=translate.微软等宽, font_size=15)
},
# Markdown 语法规则匹配
{
# Markdown 粗体语法规则匹配
'match': re.compile(r'\*\*(.*?(?<!\s))\*\*'),
'shown': re.compile(r'(?<=\*\*)(.*?(?<!\s))(?=\*\*)'),
'tag': {
# 为 match 匹配到的字符添加标签
'match': re.compile(r'\*\*'),
'style': SingleTextStyle(text_tag=['bold'])
},
'style': SingleTextStyle(bold=True)
},
{
# Markdown 斜体语法规则匹配
'match': re.compile(r'\*(.*?(?<!\s))\*'),
'shown': re.compile(r'(?<=\*)(.*?(?<!\s))(?=\*)'),
'ignore': {
# 如果匹配到的字符含有 tag 就忽略本次解析
'match': re.compile(r'\*'),
'tag': SingleTextStyle(text_tag=['italic'])
},
'style': SingleTextStyle(italic=True)
},
{
# Markdown 链接规则匹配
# 注意:这里的匹配模式是非贪婪的,即匹配到的结果必须是完整的
# 即:链接名称不能是空格等空白字符开头,链接名称不能是空格等空白字符结尾
# 匹配的内容:[abc](def)
# 显示的内容abc
'match': re.compile(r'\[(.*?(?<!\s))\]\((.*?(?<!\s))\)'),
'shown': re.compile(r'(?<=\[)(.*?(?<!\s))(?=\]\((.*?(?<!\s))\))'),
'style': SingleTextStyle(bold=True)
}
]
font_HTML_end = '</font>'
bold_HTML = '<b>'
bold_HTML_end = '</b>'
italic_HTML = '<i>'
italic_HTML_end = '</i>'
def decode_text2HTML(text: str,
configs=None) -> str:
if text == '':
return ''
if configs is None:
configs = default_fonts_config
style_list = [SingleTextStyle(text=text[x]) for x in range(0, len(text))]
# 根据输入的配置对每一个字符进行样式设定
for config in configs:
# 根据 配置"文件"
match_texts = config['match'].finditer(text) # 使用config.match匹配
for match_text in match_texts: # 每一个匹配到的匹配项
text_match = match_text.group() # 缓存一下匹配到的字符,用于匹配显示的字符
shown_texts = config['shown'].finditer(text_match) # 使用config.shown匹配
match_start, match_end = match_text.span()
if 'ignore' in config: # 如果样式选项包含忽略某些字符的tag
ignore_texts = config['ignore']['match'].finditer(text_match) # 根据选项匹配可能忽略的字符
ignore = False # 忽略先为False
for ignore_text in ignore_texts: # 每一个可能忽略的字符
if ignore: # 为了方便退出
break
for ignore_index in range(match_start + ignore_text.span()[0], match_start + ignore_text.span()[1]): # 对每一个可能的字符进行检测
if style_list[ignore_index].have_tag(config['ignore']['tag']): # 如果确实包含要忽略的
ignore = True # 忽略为True
break
if ignore:
continue # 跳过本次匹配
if 'tag' in config: # 如果样式选项包含对部分字符添加tag
tag_texts = config['tag']['match'].finditer(text_match) # 根据配置的正则表达式匹配要添加tag的字符
for tag_text in tag_texts: # 对每一个匹配到的~~~~~~
for tag_index in range(match_start + tag_text.span()[0], match_start + tag_text.span()[1]): # 用于遍历匹配到的字符
style_list[tag_index] += config['tag']['style']
# 为匹配到的字符添加样式
for match_index in range(match_start, match_end): # 用于遍历匹配到的字符
# 这里用match index来精确读写列表里的元素毕竟re.Match返回的span是两个标点得遍历
style_list[match_index] += config['style'] # 字体样式列表的[match_index] += config['style']的样式
style_list[match_index].show = False # 设置显示属性变为False
# 为每一个显示的字符设置显示属性
for shown_text in shown_texts: # 每一个显示的匹配项
for shown_index in range(match_start + shown_text.span()[0], match_start + shown_text.span()[1]):
style_list[shown_index].show = True
# 字体样式列表的[shown_index]设置显示属性变为True
# 开始根据配置好的样式输出HTML文本
style_list[0].prefix += style_list[0].HTML() # 不管怎么说都要在最前面加一个字符标识
for style_index in range(1, len(style_list)):
if style_list[style_index].show: # 如果这个字符显示
if not style_list[style_index - 1].show: # 如果前面一个字符不显示(且这个字符显示)
style_list[style_index].prefix += style_list[style_index].HTML() # 那么就直接给这个字符的前缀添加
else: # 开始根据前面的情况处理每种单独的标签
if not style_list[style_index - 1].same_font(style_list[style_index]):
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_font(suffix=True)
style_list[style_index].prefix += style_list[style_index].HTML_font()
if not style_list[style_index - 1].same_bold(style_list[style_index]):
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_bold(suffix=True)
style_list[style_index].prefix += style_list[style_index].HTML_bold()
if not style_list[style_index - 1].same_italic(style_list[style_index]):
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_italic(suffix=True)
style_list[style_index].prefix += style_list[style_index].HTML_italic()
else: # 如果这个字符不显示
if style_list[style_index - 1].show: # 如果前面一个字符显示(且这个字符不显示)
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML(suffix=True)
# 如果前面一个字符也不显示那就直接pass
if style_list[-1].show:
style_list[-1].suffix += style_list[-1].HTML(suffix=True)
# 输出最终的HTML文本
formatted_HTML_text = '' # 初始化一下
for style in style_list: # 每一个样式
if style.show: # 如果这个字符显示
formatted_HTML_text += style.prefix + style.text + style.suffix # 文本的后面附加一下
del style_list # 主动删掉style_list 释放内存
print(formatted_HTML_text)
return formatted_HTML_text # 返回DONE

View File

@ -0,0 +1,30 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
"""
writen by shenjackyuanjie
mail: 3695888@qq.com
github: @shenjackyuanjie
gitee: @shenjackyuanjie
"""
import re
from typing import Dict, List
from Difficult_Rocket import translate
from libs.pyglet.text import DocumentLabel
class FontsLabel(DocumentLabel):
"""
一个基于HTMLLabel的 可以同时在一行字里面显示多种字体的 Label
"""
def __init__(self, x, y, width, height):
super().__init__(x, y, width, height)
self._text = 'a'
self.formatted_text = 'a'

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------
@ -12,11 +12,11 @@ gitee: @shenjackyuanjie
"""
from Difficult_Rocket import translate
from Difficult_Rocket.guis.format import html
# from libs import pyglet
from libs import pyglet
from libs.pyglet import font
from libs.pyglet.text import Label
from libs.pyglet.text import Label, HTMLLabel
from libs.pyglet.window import key
from libs.pyglet.gui import widgets
from libs.pyglet.sprite import Sprite
@ -91,6 +91,10 @@ class InputBox(widgets.WidgetBase):
font_name=font_name, font_size=font_size,
batch=batch, group=group,
text=message)
self._HTML_box = HTMLLabel(x=x + out_line, y=y + out_line + 30,
width=width, height=self.font_height + self.out_bound * 2,
batch=batch, group=group,
text=message)
self._out_box = Rectangle(x=x - out_line, y=y - out_line,
color=out_line_color,
width=width + (out_line * 2), height=height + (out_line * 2),
@ -121,6 +125,7 @@ class InputBox(widgets.WidgetBase):
assert type(value) is str, 'Input Box\'s text must be string!'
self._text = value
self._input_box.text = value
self._HTML_box.text = html.decode_text2HTML(value)
@property
def cursor_poi(self) -> int: # 光标位置

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -1,6 +1,6 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# Copyright © 2021-2022 by shenjackyuanjie
# All rights reserved
# -------------------------------

View File

@ -5,12 +5,12 @@
[![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.0dev11-blue.svg)](https://pyglet.org)
[![Generic badge](https://img.shields.io/badge/Write_with_Pyglet-2.0dev13-blue.svg)](https://pyglet.org)
[![Generic badge](https://img.shields.io/badge/Python-_3.8_|_3.9_|_3.10_-blue.svg)](https://Python.org)
## Version
[![Generic badge](https://img.shields.io/badge/Release-0.6.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![Generic badge](https://img.shields.io/badge/Release-0.6.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
<br/>[![Generic badge](https://img.shields.io/badge/Pre_Release-0.6.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
<br/>![Generic badge](https://img.shields.io/badge/Devloping-0.6.2-blue.svg)
@ -34,8 +34,9 @@
- `json5 0.9.6`
- `pillow 8.1.0`
- `pyperclip 1.8.2`
- `pyglet 2.0.dev11`
- `pyglet 2.0.dev13`
- `xmltodict 0.12.0`
- `toml 0.10.2`
- `AMD R5 5600X`
- `AMD RX 550 4G`
- `Develop platform 2 - macOS Big Sur`
@ -49,6 +50,7 @@
## Required python modules
- `json5` (pre-installed V0.9.6 path:`./libs/json5`)
- `toml` (pre-installed V0.10.2 path:`./libs/toml`)
- `pyglet` (pre-installed V2.0.dev11 path:`./libs/pyglet`)
- `xmltodict` (pre-installed V0.12.0 path:`./libs/xmltodict`)
- `pyperclip` (pre-installed V1.8.2 path: `./libs/pyperclip`)
@ -59,6 +61,7 @@
- [pyglet](https://github.com/pyglet/pyglet): GUI
- `json5`: json5 parser
- `toml` toml parser
- `xmltodict`: translate data between xml and dict
- `pyperclip`: paste board!
- [@rouxiao-you](https://github.com/ruoxiao-you) : translate chinese to English

View File

@ -1,6 +1,6 @@
[runtime]
fps = 60
version = 0.6.0
version = 0.6.1
language = zh-CN
date_fmt = %%Y-%%m-%%d %%H-%%M-%%S
write_py_v = 3.8.10
@ -8,8 +8,8 @@ fonts_folder = libs/fonts
[window]
style = None
width = 646
height = 463
width = 1299
height = 931
visible = true
caption = Difficult Rocket {version}
resizable = true

View File

@ -10,7 +10,7 @@
## 版本
[![Generic badge](https://img.shields.io/badge/Release-0.6.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![Generic badge](https://img.shields.io/badge/Release-0.6.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
<br/>[![Generic badge](https://img.shields.io/badge/Pre_Release-0.6.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
<br/>![Generic badge](https://img.shields.io/badge/Devloping-0.6.2-blue.svg)
@ -36,6 +36,7 @@
- `pyperclip 1.8.2`
- `pyglet 2.0.dev11`
- `xmltodict 0.12.0`
- `toml 0.10.2`
- `AMD R5 5600X`
- `AMD RX 550 4G`
- `开发平台 2 - macOS Big Sur`
@ -49,6 +50,7 @@
## 需要的Python模块
- `json5` (已经内置 V0.9.6 路径:`./libs/json5`)
- `toml` (已经内置 V0.10.2 路径:`./libs/toml`)
- `pyglet` (已经内置 V2.0.dev11 路径:`./libs/pyglet`)
- `xmltodict` (已经内置 V0.12.0 路径:`./libs/xmltodict`)
- `pyperclip` (已经内置 V1.8.2 路径: `./libs/pyperclip`)
@ -59,6 +61,7 @@
- [pyglet](https://github.com/pyglet/pyglet) : 图形界面
- `json5`: json5解析器
- `toml`: toml解析器
- `xmltodict`: xml 与 dict 转换器
- `pyperclip`: 剪贴板!
- [@rouxiao-you](https://github.com/ruoxiao-you) : 翻译lang

View File

Before

Width:  |  Height:  |  Size: 454 KiB

After

Width:  |  Height:  |  Size: 454 KiB

View File

Before

Width:  |  Height:  |  Size: 402 KiB

After

Width:  |  Height:  |  Size: 402 KiB

View File

Before

Width:  |  Height:  |  Size: 571 KiB

After

Width:  |  Height:  |  Size: 571 KiB

View File

Before

Width:  |  Height:  |  Size: 366 KiB

After

Width:  |  Height:  |  Size: 366 KiB

View File

@ -1,26 +1,30 @@
# Difficult Rocket Update Logs
- 感谢 `Github copilot` 的翻译(甚至这句话也是`copilot`翻译的)
- 也就意味着以后的更新日志是中文记录+`copilot`翻译的
- 也就意味着以后的更新日志是中文记录+`copilot`翻译的(当然,也有可能是`Easy Translate`翻译的)
- Thanks `Github copilot` for translate (lazy yes!)
- Means the update logs will lodge in Chinese and translated by `copilot`
## Readme First!
##### most badge can be clicked and jump
[![Generic badge](https://img.shields.io/badge/SemVer-2.0.0-blue.svg)](https://Semver.org/)
![Generic badge](https://img.shields.io/badge/Version-0.6.0-yellow.svg)
![Generic badge](https://img.shields.io/badge/Version-0.6.1-yellow.svg)
- [![Readme-github](https://img.shields.io/badge/Readme-Github-blue.svg?style=flat-square&logo=Github)](https://github.com/shenjackyuanjie/Difficult-Rocket)
- [![Readme-gitee](https://img.shields.io/badge/Readme-Gitee-blue.svg?style=flat-square&logo=Gitee)](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
- [![Readme-gitee](https://img.shields.io/badge/Readme-中文(点我!)-blue.svg?style=flat-square)](README-cn.md)
- Using [SemVer 2.0.0](https://semver.org/) to manage version
## 202112 V 0.6.1
## ~~202111 202112xx~~ 20220119 V 0.6.1
争取12月内发一个release
~~争取12月内发一个release~~
行了这都2022年了我接着摸等我考完试(20220110)再发
### Change
- 更新了所有文件的版权信息
- Update all files copyright information
- 重命名 `Difficult_Rocket.py` -> `DR.py`
- 用于修复 `Pycharm` 检测模块时总是会把主文件检测成主程序,导致一些模块总是检测不到的问题
- Rename `Difficult_Rocket.py` -> `DR.py`
@ -42,6 +46,8 @@
- also means you can directly use parsed `.config` file to modify `.config` file
- 为 `pyglet` 添加 `Ctrl+C``Ctrl+V` 的快捷键解析
- add `Ctrl+C` and `Ctrl+V` shortcut for `pyglet`
- 更新 `pyglet``2.0dev13`
- update `pyglet` to `2.0dev13`
### Command
@ -69,6 +75,12 @@
- 非常感谢上述模块的作者和维护者们
- added `json5` `pyglet` `pyperclip` `xmltodict` LICENSE
- thanks a lot to above module's author and maintainer
- 继续~~重~~新写了一个基于 `HTMLLabel``HTMLformatedLabel`
- 同时为他写了一个 `decode_text2HTML` 工具(这也是咕咕咕的一大部分原因)
- add a `HTMLformatedLabel` Label based on `HTMLLabel`
- also write a `decode_text2HTML` tool (also a big reason why lazy)
- 增加内置模块 `toml` 和对应的 `LICENSE.txt`
- Added built-in module `toml` and corresponding `LICENSE.txt`
## 20211025 V 0.6.0

View File

@ -44,7 +44,7 @@ import sys
from typing import TYPE_CHECKING
#: The release version
version = '2.0.dev11'
version = '2.0.dev13'
__version__ = version
if sys.version_info < (3, 6):

View File

@ -242,7 +242,7 @@ class COMPointer(ctypes.c_void_p, metaclass=COMPointerMeta):
@classmethod
def from_param(cls, obj):
"""Allows obj to return ctypes pointers, even if it's base is not a ctype.
"""Allows obj to return ctypes pointers, even if its base is not a ctype.
In this case, all we simply want is a ctypes pointer matching the cls interface from the obj.
"""
if obj is None:

View File

@ -167,9 +167,9 @@ class Glyph(image.TextureRegion):
`advance` : int
Distance to move the horizontal advance to the next glyph.
`offset_x` : int
Distance to move the glyph horizontally from it's default position.
Distance to move the glyph horizontally from its default position.
`offset_y` : int
Distance to move the glyph vertically from it's default position.
Distance to move the glyph vertically from its default position.
"""
self.baseline = baseline
self.lsb = left_side_bearing

View File

@ -1876,7 +1876,7 @@ class Win32DirectWriteFont(base.Font):
create_unicode_buffer(self.locale),
byref(self._text_format))
# All this work just to get a font face and it's metrics!
# All this work just to get a font face and its metrics!
font_family = IDWriteFontFamily1()
self._collection.GetFontFamily(self._font_index, byref(font_family))
@ -2096,7 +2096,7 @@ class Win32DirectWriteFont(base.Font):
@classmethod
def get_collection(cls, font_name):
"""Returns which collection this font belongs to (system or custom collection), as well as it's index in the
"""Returns which collection this font belongs to (system or custom collection), as well as its index in the
collection."""
if not cls._write_factory:
cls._initialize_direct_write()

View File

@ -165,6 +165,7 @@ import pyglet
from pyglet.gl import *
from pyglet.graphics import vertexbuffer, vertexattribute, vertexdomain
from pyglet.graphics.vertexarray import VertexArray
from pyglet.graphics.vertexbuffer import BufferObject
_debug_graphics_batch = pyglet.options['debug_graphics_batch']
@ -258,14 +259,24 @@ def draw_indexed(size, mode, indices, *data):
index_type = GL_UNSIGNED_INT
index_c_type = ctypes.c_uint
# With GL 3.3 vertex arrays indices needs to be in a buffer
# bound to the ELEMENT_ARRAY slot
index_array = (index_c_type * len(indices))(*indices)
glDrawElements(mode, len(indices), index_type, index_array)
index_buffer = BufferObject(
ctypes.sizeof(index_array),
GL_ELEMENT_ARRAY_BUFFER,
GL_DYNAMIC_DRAW,
)
index_buffer.set_data(index_array)
glDrawElements(mode, len(indices), index_type, 0)
glFlush()
# Deactivate shader program:
group.unset_state()
# Discard everything after drawing:
del buffers
del index_buffer
glBindVertexArray(0)
glDeleteVertexArrays(1, vao_id)

View File

@ -48,14 +48,20 @@ WICBitmapDitherTypeErrorDiffusion = 0x8
WICBITMAPDITHERTYPE_FORCE_DWORD = 0x7fffffff
WICBITMAPTRANSFORMOPTIONS_FORCE_DWORD = 0x7fffffff
WICDecodeOptions = UINT
WICDecodeMetadataCacheOnDemand = 0
WICDecodeMetadataCacheOnLoad = 0x1
WICMETADATACACHEOPTION_FORCE_DWORD = 0x7fffffff
WICBitmapEncoderCacheOption = UINT
WICBitmapEncoderCacheInMemory = 0x0
WICBitmapEncoderCacheTempFile = 0x1
WICBitmapEncoderNoCache = 0x2
WICBITMAPENCODERCACHEOPTION_FORCE_DWORD = 0x7fffffff
# Different pixel formats.
REFWICPixelFormatGUID = com.GUID
GUID_WICPixelFormatDontCare = com.GUID(0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x00)
GUID_WICPixelFormat1bppIndexed = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01)
GUID_WICPixelFormat2bppIndexed = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02)
GUID_WICPixelFormat4bppIndexed = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03)
@ -74,12 +80,155 @@ GUID_WICPixelFormat24bppRGB = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0
GUID_WICPixelFormat32bppBGR = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e)
GUID_WICPixelFormat32bppBGRA = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f)
GUID_WICPixelFormat32bppPBGRA = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10)
GUID_WICPixelFormat32bppRGB = com.GUID(0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c, 0xf1) # 7 platform update?
GUID_WICPixelFormat32bppRGB = com.GUID(0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c, 0xf1) # 7 platform update?
GUID_WICPixelFormat32bppRGBA = com.GUID(0xf5c7ad2d, 0x6a8d, 0x43dd, 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9)
GUID_WICPixelFormat32bppPRGBA = com.GUID(0x3cc4a650, 0xa527, 0x4d37, 0xa9, 0x16, 0x31, 0x42, 0xc7, 0xeb, 0xed, 0xba)
GUID_WICPixelFormat48bppRGB = com.GUID(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15)
GUID_WICPixelFormat48bppBGR = com.GUID(0xe605a384, 0xb468, 0x46ce, 0xbb, 0x2e, 0x36, 0xf1, 0x80, 0xe6, 0x43, 0x13)
GUID_ContainerFormatBmp = com.GUID(0x0af1d87e, 0xfcfe, 0x4188, 0xbd, 0xeb, 0xa7, 0x90, 0x64, 0x71, 0xcb, 0xe3)
GUID_ContainerFormatPng = com.GUID(0x1b7cfaf4, 0x713f, 0x473c, 0xbb, 0xcd, 0x61, 0x37, 0x42, 0x5f, 0xae, 0xaf)
GUID_ContainerFormatIco = com.GUID(0xa3a860c4, 0x338f, 0x4c17, 0x91, 0x9a, 0xfb, 0xa4, 0xb5, 0x62, 0x8f, 0x21)
GUID_ContainerFormatJpeg = com.GUID(0x19e4a5aa, 0x5662, 0x4fc5, 0xa0, 0xc0, 0x17, 0x58, 0x02, 0x8e, 0x10, 0x57)
GUID_ContainerFormatTiff = com.GUID(0x163bcc30, 0xe2e9, 0x4f0b, 0x96, 0x1d, 0xa3, 0xe9, 0xfd, 0xb7, 0x88, 0xa3)
GUID_ContainerFormatGif = com.GUID(0x1f8a5601, 0x7d4d, 0x4cbd, 0x9c, 0x82, 0x1b, 0xc8, 0xd4, 0xee, 0xb9, 0xa5)
GUID_ContainerFormatWmp = com.GUID(0x57a37caa, 0x367a, 0x4540, 0x91, 0x6b, 0xf1, 0x83, 0xc5, 0x09, 0x3a, 0x4b)
class IPropertyBag2(com.pIUnknown):
_methods_ = [
('Read',
com.STDMETHOD()),
('Write',
com.STDMETHOD()),
('CountProperties',
com.STDMETHOD()),
('GetPropertyInfo',
com.STDMETHOD()),
('LoadObject',
com.STDMETHOD())
]
# class PROPBAG2(Structure):
# _fields_ = [
# ('dwType', DWORD),
# ('vt', VARTYPE),
# ('cfType', CLIPFORMAT),
# ('dwHint', DWORD),
# ('pstrName', LPOLESTR),
# ('clsid', CLSID)
# ]
class IWICPalette(com.pIUnknown):
_methods_ = [
('InitializePredefined',
com.STDMETHOD()),
('InitializeCustom',
com.STDMETHOD()),
('InitializeFromBitmap',
com.STDMETHOD()),
('InitializeFromPalette',
com.STDMETHOD()),
('GetType',
com.STDMETHOD()),
('GetColorCount',
com.STDMETHOD()),
('GetColors',
com.STDMETHOD()),
('IsBlackWhite',
com.STDMETHOD()),
('IsGrayscale',
com.STDMETHOD()),
('HasAlpha',
com.STDMETHOD()),
]
class IWICStream(com.pIUnknown):
_methods_ = [
('Read',
com.STDMETHOD()),
('Write',
com.STDMETHOD()),
('Seek',
com.STDMETHOD()),
('SetSize',
com.STDMETHOD()),
('CopyTo',
com.STDMETHOD()),
('Commit',
com.STDMETHOD()),
('Revert',
com.STDMETHOD()),
('LockRegion',
com.STDMETHOD()),
('UnlockRegion',
com.STDMETHOD()),
('Stat',
com.STDMETHOD()),
('Clone',
com.STDMETHOD()),
('InitializeFromIStream',
com.STDMETHOD()),
('InitializeFromFilename',
com.STDMETHOD(LPCWSTR, DWORD)),
('InitializeFromMemory',
com.STDMETHOD()),
('InitializeFromIStreamRegion',
com.STDMETHOD()),
]
class IWICBitmapFrameEncode(com.pIUnknown):
_methods_ = [
('Initialize',
com.STDMETHOD(IPropertyBag2)),
('SetSize',
com.STDMETHOD(UINT, UINT)),
('SetResolution',
com.STDMETHOD()),
('SetPixelFormat',
com.STDMETHOD(REFWICPixelFormatGUID)),
('SetColorContexts',
com.STDMETHOD()),
('SetPalette',
com.STDMETHOD(IWICPalette)),
('SetThumbnail',
com.STDMETHOD()),
('WritePixels',
com.STDMETHOD(UINT, UINT, UINT, POINTER(BYTE))),
('WriteSource',
com.STDMETHOD()),
('Commit',
com.STDMETHOD()),
('GetMetadataQueryWriter',
com.STDMETHOD())
]
class IWICBitmapEncoder(com.pIUnknown):
_methods_ = [
('Initialize',
com.STDMETHOD(IWICStream, WICBitmapEncoderCacheOption)),
('GetContainerFormat',
com.STDMETHOD()),
('GetEncoderInfo',
com.STDMETHOD()),
('SetColorContexts',
com.STDMETHOD()),
('SetPalette',
com.STDMETHOD()),
('SetThumbnail',
com.STDMETHOD()),
('SetPreview',
com.STDMETHOD()),
('CreateNewFrame',
com.STDMETHOD(POINTER(IWICBitmapFrameEncode), POINTER(IPropertyBag2))),
('Commit',
com.STDMETHOD()),
('GetMetadataQueryWriter',
com.STDMETHOD())
]
class IWICComponentInfo(com.pIUnknown):
_methods_ = [
@ -135,7 +284,8 @@ class IWICBitmapSource(com.pIUnknown):
class IWICFormatConverter(IWICBitmapSource, com.pIUnknown):
_methods_ = [
('Initialize',
com.STDMETHOD(IWICBitmapSource, POINTER(REFWICPixelFormatGUID), WICBitmapDitherType, c_void_p, DOUBLE, WICBitmapPaletteType)),
com.STDMETHOD(IWICBitmapSource, POINTER(REFWICPixelFormatGUID), WICBitmapDitherType, c_void_p, DOUBLE,
WICBitmapPaletteType)),
('CanConvert',
com.STDMETHOD(POINTER(REFWICPixelFormatGUID), POINTER(REFWICPixelFormatGUID), POINTER(BOOL))),
]
@ -234,9 +384,9 @@ class IWICImagingFactory(com.pIUnknown):
('CreateDecoder',
com.STDMETHOD()),
('CreateEncoder',
com.STDMETHOD()),
com.STDMETHOD(com.GUID, POINTER(com.GUID), POINTER(IWICBitmapEncoder))),
('CreatePalette',
com.STDMETHOD()),
com.STDMETHOD(POINTER(IWICPalette))),
('CreateFormatConverter',
com.STDMETHOD(POINTER(IWICFormatConverter))),
('CreateBitmapScaler',
@ -246,7 +396,7 @@ class IWICImagingFactory(com.pIUnknown):
('CreateBitmapFlipRotator',
com.STDMETHOD(POINTER(IWICBitmapFlipRotator))),
('CreateStream',
com.STDMETHOD()),
com.STDMETHOD(POINTER(IWICStream))),
('CreateColorContext',
com.STDMETHOD()),
('CreateColorTransformer',
@ -258,7 +408,7 @@ class IWICImagingFactory(com.pIUnknown):
('CreateBitmapFromSourceRect',
com.STDMETHOD()),
('CreateBitmapFromMemory',
com.STDMETHOD()),
com.STDMETHOD(UINT, UINT, REFWICPixelFormatGUID, UINT, UINT, POINTER(BYTE), POINTER(IWICBitmap))),
('CreateBitmapFromHBITMAP',
com.STDMETHOD()),
('CreateBitmapFromHICON',
@ -276,23 +426,27 @@ class IWICImagingFactory(com.pIUnknown):
]
_factory = IWICImagingFactory()
try:
ole32.CoInitializeEx(None, COINIT_MULTITHREADED)
except OSError as err:
warnings.warn(str(err))
ole32.CoCreateInstance(CLSID_WICImagingFactory,
None,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
byref(_factory))
class WICDecoder(ImageDecoder):
"""Windows Imaging Component.
This decoder is a replacement for GDI and GDI+ starting with Windows 7 with more features up to Windows 10."""
def __init__(self):
super(ImageDecoder, self).__init__()
self._factory = IWICImagingFactory()
try:
ole32.CoInitializeEx(None, COINIT_MULTITHREADED)
except OSError as err:
warnings.warn(str(err))
ole32.CoCreateInstance(CLSID_WICImagingFactory,
None,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
byref(self._factory))
self._factory = _factory
def get_file_extensions(self):
return ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.ico', '.jxr', '.hdp', '.wdp']
@ -411,5 +565,83 @@ def get_decoders():
return [WICDecoder()]
extension_to_container = {
'.bmp': GUID_ContainerFormatBmp,
'.jpg': GUID_ContainerFormatJpeg,
'.jpeg': GUID_ContainerFormatJpeg,
'.tif': GUID_ContainerFormatTiff,
'.tiff': GUID_ContainerFormatTiff,
'.wmp': GUID_ContainerFormatWmp,
'.jxr': GUID_ContainerFormatWmp,
'.wdp': GUID_ContainerFormatWmp,
'.png': GUID_ContainerFormatPng,
}
class WICEncoder(ImageEncoder):
def get_file_extensions(self):
return [ext for ext in extension_to_container]
def encode(self, image, file, filename):
# Close default file handler.file.close()
stream = IWICStream()
encoder = IWICBitmapEncoder()
frame = IWICBitmapFrameEncode()
property_bag = IPropertyBag2()
_factory.CreateStream(byref(stream))
stream.InitializeFromFilename(filename, GENERIC_WRITE)
name, ext = os.path.splitext(filename)
# Choose container based on extension. Default to PNG.
container = extension_to_container.get(ext, GUID_ContainerFormatPng)
_factory.CreateEncoder(container, None, byref(encoder))
encoder.Initialize(stream, WICBitmapEncoderNoCache)
encoder.CreateNewFrame(byref(frame), byref(property_bag))
frame.Initialize(property_bag)
frame.SetSize(image.width, image.height)
# https://docs.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats#native-image-formats
if container == GUID_ContainerFormatJpeg:
# Expects BGR, no transparency available. Hard coded.
fmt = 'BGR'
default_format = GUID_WICPixelFormat24bppBGR
else:
# Windows encodes in BGRA.
if len(image.format) == 3:
fmt = 'BGR'
default_format = GUID_WICPixelFormat24bppBGR
else:
fmt = 'BGRA'
default_format = GUID_WICPixelFormat32bppBGRA
frame.SetPixelFormat(default_format)
pitch = image.width * len(fmt)
actual_pitch = -pitch
image_data = image.get_data(fmt, actual_pitch)
size = len(image_data)
data = (c_byte * size).from_buffer(bytearray(image_data))
frame.WritePixels(image.height, pitch, size, data)
frame.Commit()
encoder.Commit()
encoder.Release()
frame.Release()
property_bag.Release()
stream.Release()
def get_encoders():
return []
return [WICEncoder()]

View File

@ -1009,7 +1009,7 @@ class TabletCanvas(EventDispatcher):
:event:
"""
def on_motion(self, cursor, x, y, pressure):
def on_motion(self, cursor, x, y, pressure, tilt_x, tilt_y):
"""The cursor moved on the tablet surface.
If `pressure` is 0, then the cursor is actually hovering above the

View File

@ -113,7 +113,7 @@ class XInputTabletCursor(TabletCursor):
def get_tablets(display=None):
# Each cursor appears as a separate xinput device; find devices that look
# like Wacom tablet cursors and amalgamate them into a single tablet.
valid_names = ('stylus', 'cursor', 'eraser', 'wacom', 'pen', 'pad')
valid_names = ('stylus', 'cursor', 'eraser', 'pen', 'pad')
cursors = []
devices = get_devices(display)
for device in devices:

View File

@ -155,7 +155,7 @@ _kernel32.GlobalLock.argtypes = [HGLOBAL]
_kernel32.GlobalUnlock.restype = BOOL
_kernel32.GlobalUnlock.argtypes = [HGLOBAL]
_kernel32.SetLastError.restype = DWORD
_kernel32.SetLastError.argtypes = []
_kernel32.SetLastError.argtypes = [DWORD]
_kernel32.SetWaitableTimer.restype = BOOL
_kernel32.SetWaitableTimer.argtypes = [HANDLE, POINTER(LARGE_INTEGER), LONG, LPVOID, LPVOID, BOOL] # TIMERAPCPROC
_kernel32.WaitForSingleObject.restype = DWORD

View File

@ -111,6 +111,7 @@ def add_default_media_codecs():
except ImportError:
pass
def have_ffmpeg():
"""Check if FFmpeg library is available.

View File

@ -118,7 +118,7 @@ class _MessageHandler:
def new_sample(self, sink):
"""new-sample callback"""
# Pull the sample, and get it's buffer:
# Pull the sample, and get its buffer:
buffer = sink.emit('pull-sample').get_buffer()
# Extract a copy of the memory in the buffer:
mem = buffer.extract_dup(0, buffer.get_size())

View File

@ -122,6 +122,10 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
if self._xa2_source_voice:
self._deleted = True
if not self._buffers:
self._xa2_driver.return_voice(self._xa2_source_voice)
def play(self):
assert _debug('XAudio2 play')

View File

@ -287,7 +287,7 @@ class XAudio2Driver:
""" Get a source voice from the pool. Source voice creation can be slow to create/destroy. So pooling is
recommended. We pool based on audio channels as channels must be the same as well as frequency.
Source voice handles all of the audio playing and state for a single source."""
voice_key = (source.audio_format.channels, source.audio_format.sample_size)
voice_key = (source.audio_format.channels, source.audio_format.sample_size, source.audio_format.sample_rate)
if len(self._voice_pool[voice_key]) > 0:
source_voice = self._voice_pool[voice_key].pop(0)
source_voice.acquired(player)
@ -323,7 +323,7 @@ class XAudio2Driver:
def return_voice(self, voice):
"""Reset a voice and return it to the pool."""
voice.reset()
voice_key = (voice.audio_format.channels, voice.audio_format.sample_size)
voice_key = (voice.audio_format.channels, voice.audio_format.sample_size, voice.audio_format.sample_rate)
self._voice_pool[voice_key].append(voice)
if voice.is_emitter:

View File

@ -38,7 +38,7 @@ import time
from collections import deque
import pyglet
from pyglet.gl import GL_TEXTURE_RECTANGLE
from pyglet.gl import GL_TEXTURE_2D
from pyglet.media import buffered_logger as bl
from pyglet.media.drivers import get_audio_driver
from pyglet.media.codecs.base import Source, SourceGroup
@ -393,7 +393,7 @@ class Player(pyglet.event.EventDispatcher):
def _create_texture(self):
video_format = self.source.video_format
self._texture = pyglet.image.Texture.create(video_format.width, video_format.height, GL_TEXTURE_RECTANGLE)
self._texture = pyglet.image.Texture.create(video_format.width, video_format.height, GL_TEXTURE_2D)
self._texture = self._texture.get_transform(flip_y=True)
# After flipping the texture along the y axis, the anchor_y is set
# to the top of the image. We want to keep it at the bottom.

View File

@ -185,7 +185,7 @@ class Model:
a vertex list in `vertex_lists` of the same index.
`batch` : `~pyglet.graphics.Batch`
Optional batch to add the model to. If no batch is provided,
the model will maintain it's own internal batch.
the model will maintain its own internal batch.
"""
self.vertex_lists = vertex_lists
self.groups = groups
@ -199,7 +199,7 @@ class Model:
The Model can be migrated from one batch to another, or removed from
a batch (for individual drawing). If not part of any batch, the Model
will keep it's own internal batch. Note that batch migration can be
will keep its own internal batch. Note that batch migration can be
an expensive operation.
:type: :py:class:`pyglet.graphics.Batch`

View File

@ -100,7 +100,7 @@ class ResourceNotFoundException(Exception):
def __init__(self, name):
message = ("Resource '{}' was not found on the path. "
"Ensure that the filename has the correct captialisation.".format(name))
"Ensure that the filename has the correct capitalisation.".format(name))
Exception.__init__(self, message)

View File

@ -355,7 +355,7 @@ class Arc(_ShapeBase):
closed=False, color=(255, 255, 255), batch=None, group=None):
"""Create an Arc.
The Arc's anchor point (x, y) defaults to it's center.
The Arc's anchor point (x, y) defaults to its center.
:Parameters:
`x` : float
@ -475,7 +475,7 @@ class Circle(_ShapeBase):
`segments` : int
You can optionally specify how many distinct triangles
the circle should be made from. If not specified it will
be automatically calculated based using the formula:
be automatically calculated using the formula:
`max(14, int(radius / 1.25))`.
`color` : (int, int, int)
The RGB color of the circle, specified as a tuple of
@ -677,7 +677,7 @@ class Sector(_ShapeBase):
`segments` : int
You can optionally specify how many distinct triangles
the sector should be made from. If not specified it will
be automatically calculated based using the formula:
be automatically calculated using the formula:
`max(14, int(radius / 1.25))`.
`angle` : float
The angle of the sector, in radians. Defaults to tau (pi * 2),
@ -747,6 +747,19 @@ class Sector(_ShapeBase):
self._angle = value
self._update_position()
@property
def start_angle(self):
"""The start angle of the sector.
:type: float
"""
return self._start_angle
@start_angle.setter
def start_angle(self, angle):
self._start_angle = angle
self._update_position()
@property
def radius(self):
"""The radius of the sector.

View File

@ -294,8 +294,7 @@ class Sprite(event.EventDispatcher):
batch=None,
group=None,
usage='dynamic',
subpixel=False,
program=None):
subpixel=False):
"""Create a sprite.
:Parameters:
@ -322,8 +321,6 @@ class Sprite(event.EventDispatcher):
`subpixel` : bool
Allow floating-point coordinates for the sprite. By default,
coordinates are restricted to integer values.
`program` : `~pyglet.graphics.shader.ShaderProgram`
A custom ShaderProgram.
"""
self._x = x
self._y = y

View File

@ -311,7 +311,7 @@ class DocumentLabel(layout.TextLayout):
drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will
make the sprite appear translucent.
make the label appear semi-translucent.
:type: int
"""

View File

@ -189,7 +189,6 @@ class HTMLDecoder(HTMLParser, structured.StructuredTextDecoder):
attrs = {}
for key, value in case_attrs:
attrs[key.lower()] = value
print(attrs)
if element in _metadata_elements:
self.in_metadata = True

View File

@ -64,7 +64,7 @@ Usage::
from pyglet import compat_platform
class KeyStateHandler(dict):
class KeyStateHandler:
"""Simple handler that tracks the state of keys on the keyboard. If a
key is pressed then this handler holds a True value for it.
@ -82,14 +82,17 @@ class KeyStateHandler(dict):
False
"""
def __init__(self):
self.data = {}
def on_key_press(self, symbol, modifiers):
self[symbol] = True
self.data[symbol] = True
def on_key_release(self, symbol, modifiers):
self[symbol] = False
self.data[symbol] = False
def __getitem__(self, key):
return self.get(key, False)
return self.data.get(key, False)
def modifiers_string(modifiers):

View File

@ -37,7 +37,7 @@
"""
class MouseStateHandler(dict):
class MouseStateHandler:
"""Simple handler that tracks the state of buttons from the mouse. If a
button is pressed then this handler holds a True value for it.
@ -57,25 +57,27 @@ class MouseStateHandler(dict):
"""
def __init__(self):
self["x"] = 0
self["y"] = 0
self.data = {
"x": 0,
"y": 0,
}
def on_mouse_press(self, x, y, button, modifiers):
self[button] = True
self.data[button] = True
def on_mouse_release(self, x, y, button, modifiers):
self[button] = False
self.data[button] = False
def on_mouse_motion(self, x, y, dx, dy):
self["x"] = x
self["y"] = y
self.data["x"] = x
self.data["y"] = y
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
self["x"] = x
self["y"] = y
self.data["x"] = x
self.data["y"] = y
def __getitem__(self, key):
return self.get(key, False)
return self.data.get(key, False)
def buttons_string(buttons):

View File

@ -70,6 +70,8 @@ _motion_map = {
(key.END, True): key.MOTION_END_OF_FILE,
(key.BACKSPACE, False): key.MOTION_BACKSPACE,
(key.DELETE, False): key.MOTION_DELETE,
(key.C, True): key.MOTION_COPY,
(key.V, True): key.MOTION_PASTE
}
@ -98,17 +100,23 @@ class Win32Window(BaseWindow):
_hidden = False
_has_focus = False
_exclusive_keyboard = False
_exclusive_keyboard_focus = True
_exclusive_mouse = False
_exclusive_mouse_focus = True
_exclusive_mouse_screen = None
_exclusive_mouse_lpos = None
_exclusive_mouse_buttons = 0
_mouse_platform_visible = True
_pending_click = False
_in_title_bar = False
_keyboard_state = {0x02A: False, 0x036: False} # For shift keys.
_ws_style = 0
_ex_ws_style = 0
_minimum_size = None
_maximum_size = None
def __init__(self, *args, **kwargs):
# Bind event handlers
@ -213,6 +221,7 @@ class Win32Window(BaseWindow):
self._window_class.hInstance,
0)
# View Hwnd is for the client area so certain events (mouse events) don't trigger outside of area.
self._view_hwnd = _user32.CreateWindowExW(
0,
self._view_window_class.lpszClassName,
@ -224,6 +233,10 @@ class Win32Window(BaseWindow):
self._view_window_class.hInstance,
0)
if not self._view_hwnd:
last_error = _kernel32.GetLastError()
raise Exception("Failed to create handle", self, last_error, self._view_hwnd, self._hwnd)
self._dc = _user32.GetDC(self._view_hwnd)
# Only allow files being dropped if specified.
@ -235,12 +248,13 @@ class Win32Window(BaseWindow):
_user32.ChangeWindowMessageFilterEx(self._hwnd, WM_COPYGLOBALDATA, MSGFLT_ALLOW, None)
_shell32.DragAcceptFiles(self._hwnd, True)
# Register raw input keyboard to allow the window to receive input events.
raw_keyboard = RAWINPUTDEVICE(0x01, 0x06, 0, self._view_hwnd)
# Set the raw keyboard to handle shift state. This is required as legacy events cannot handle shift states
# when both keys are used together. View Hwnd as none changes focus to follow keyboard.
raw_keyboard = RAWINPUTDEVICE(0x01, 0x06, 0, None)
if not _user32.RegisterRawInputDevices(
byref(raw_keyboard), 1, sizeof(RAWINPUTDEVICE)):
print("Warning: Failed to register raw input keyboard. on_key events for shift keys will not be called.")
byref(raw_keyboard), 1, sizeof(RAWINPUTDEVICE)):
print("Warning: Failed to unregister raw input keyboard.")
else:
# Window already exists, update it with new style
@ -336,7 +350,7 @@ class Win32Window(BaseWindow):
vsync = property(_get_vsync) # overrides BaseWindow property
def set_vsync(self, vsync: bool) -> None:
def set_vsync(self, vsync):
if pyglet.options['vsync'] is not None:
vsync = pyglet.options['vsync']
@ -345,9 +359,8 @@ class Win32Window(BaseWindow):
if not self._fullscreen:
# Disable interval if composition is enabled to avoid conflict with DWM.
if self._always_dwm or self._dwm_composition_enabled():
vsync = False
vsync = 0
super().set_vsync(vsync)
self.context.set_vsync(vsync)
def switch_to(self):
@ -392,20 +405,31 @@ class Win32Window(BaseWindow):
_user32.ClientToScreen(self._hwnd, byref(point))
return point.x, point.y
def set_size(self, width: int, height: int) -> None:
super().set_size(width, height)
def set_size(self, width, height):
if self._fullscreen:
raise WindowException('Cannot set size of fullscreen window.')
width, height = self._client_to_window_size(width, height)
_user32.SetWindowPos(self._hwnd, 0, 0, 0, width, height,
(SWP_NOZORDER |
SWP_NOMOVE |
SWP_NOOWNERZORDER))
def get_size(self):
# rect = RECT()
# _user32.GetClientRect(self._hwnd, byref(rect))
# return rect.right - rect.left, rect.bottom - rect.top
return self._width, self._height
def set_minimum_size(self, width, height):
self._minimum_size = width, height
def set_maximum_size(self, width, height):
self._maximum_size = width, height
def activate(self):
_user32.SetForegroundWindow(self._hwnd)
def set_visible(self, visible: bool = True) -> None:
super().set_visible(visible)
def set_visible(self, visible=True):
if visible:
insertAfter = HWND_TOPMOST if self._fullscreen else HWND_TOP
_user32.SetWindowPos(self._hwnd, insertAfter, 0, 0, 0, 0,
@ -416,6 +440,7 @@ class Win32Window(BaseWindow):
else:
_user32.ShowWindow(self._hwnd, SW_HIDE)
self.dispatch_event('on_hide')
self._visible = visible
self.set_mouse_platform_visible()
def minimize(self):
@ -431,7 +456,7 @@ class Win32Window(BaseWindow):
def set_mouse_platform_visible(self, platform_visible=None):
if platform_visible is None:
platform_visible = (self._mouse_visible and
not self._mouse_exclusive and
not self._exclusive_mouse and
(not self._mouse_cursor.gl_drawable or self._mouse_cursor.hw_drawable)) or \
(not self._mouse_in_window or
not self._has_focus)
@ -450,6 +475,11 @@ class Win32Window(BaseWindow):
if platform_visible == self._mouse_platform_visible:
return
self._set_cursor_visibility(platform_visible)
self._mouse_platform_visible = platform_visible
def _set_cursor_visibility(self, platform_visible):
# Avoid calling ShowCursor with the current visibility (which would
# push the counter too far away from zero).
global _win32_cursor_visible
@ -457,33 +487,33 @@ class Win32Window(BaseWindow):
_user32.ShowCursor(platform_visible)
_win32_cursor_visible = platform_visible
self._mouse_platform_visible = platform_visible
def _update_clipped_cursor(self):
# Clip to client area, to prevent large mouse movements taking
# it outside the client area.
if self._in_title_bar or self._pending_click:
return
def _reset_exclusive_mouse_screen(self):
"""Recalculate screen coords of mouse warp point for exclusive
mouse."""
p = POINT()
rect = RECT()
_user32.GetClientRect(self._view_hwnd, byref(rect))
_user32.MapWindowPoints(self._view_hwnd, HWND_DESKTOP, byref(rect), 2)
p.x = (rect.left + rect.right) // 2
p.y = (rect.top + rect.bottom) // 2
_user32.MapWindowPoints(self._view_hwnd, HWND_DESKTOP,
byref(rect), 2)
# This is the point the mouse will be kept at while in exclusive
# mode.
self._exclusive_mouse_screen = p.x, p.y
# For some reason borders can be off 1 pixel, allowing cursor into frame/minimize/exit buttons?
rect.top += 1
rect.left += 1
rect.right -= 1
rect.bottom -= 1
_user32.ClipCursor(byref(rect))
def set_exclusive_mouse(self, exclusive=True):
if self._mouse_exclusive == exclusive and \
if self._exclusive_mouse == exclusive and \
self._exclusive_mouse_focus == self._has_focus:
return
# Mouse: UsagePage = 1, Usage = 2
raw_mouse = RAWINPUTDEVICE(0x01, 0x02, 0, None)
if exclusive:
raw_mouse.dwFlags = RIDEV_NOLEGACY
raw_mouse.hwndTarget = self._view_hwnd
else:
if not exclusive:
raw_mouse.dwFlags = RIDEV_REMOVE
raw_mouse.hwndTarget = None
@ -494,20 +524,12 @@ class Win32Window(BaseWindow):
self._exclusive_mouse_buttons = 0
if exclusive and self._has_focus:
# Clip to client area, to prevent large mouse movements taking
# it outside the client area.
rect = RECT()
_user32.GetClientRect(self._view_hwnd, byref(rect))
_user32.MapWindowPoints(self._view_hwnd, HWND_DESKTOP,
byref(rect), 2)
_user32.ClipCursor(byref(rect))
# Release mouse capture in case is was acquired during mouse click
_user32.ReleaseCapture()
self._update_clipped_cursor()
else:
# Release clip
_user32.ClipCursor(None)
super().set_exclusive_mouse(exclusive)
self._exclusive_mouse = exclusive
self._exclusive_mouse_focus = self._has_focus
self.set_mouse_platform_visible(not exclusive)
@ -523,7 +545,7 @@ class Win32Window(BaseWindow):
_user32.SetCursorPos(x, y)
def set_exclusive_keyboard(self, exclusive=True):
if self._keyboard_exclusive == exclusive and \
if self._exclusive_keyboard == exclusive and \
self._exclusive_keyboard_focus == self._has_focus:
return
@ -532,7 +554,7 @@ class Win32Window(BaseWindow):
else:
_user32.UnregisterHotKey(self._hwnd, 0)
super().set_exclusive_keyboard(exclusive)
self._exclusive_keyboard = exclusive
self._exclusive_keyboard_focus = self._has_focus
def get_system_mouse_cursor(self, name):
@ -723,7 +745,12 @@ class Win32Window(BaseWindow):
event_handler = event_handlers.get(msg, None)
result = None
if event_handler:
result = event_handler(msg, wParam, lParam)
if self._allow_dispatch_event or not self._enable_event_queue:
result = event_handler(msg, wParam, lParam)
else:
result = 0
self._event_queue.append((event_handler, msg,
wParam, lParam))
if result is None:
result = _user32.DefWindowProcW(hwnd, msg, wParam, lParam)
return result
@ -746,6 +773,7 @@ class Win32Window(BaseWindow):
modifiers |= key.MOD_NUMLOCK
if _user32.GetKeyState(VK_SCROLL) & 0x00ff: # toggle
modifiers |= key.MOD_SCROLLLOCK
if key_lParam:
if key_lParam & (1 << 29):
modifiers |= key.MOD_ALT
@ -783,7 +811,7 @@ class Win32Window(BaseWindow):
symbol = key.RCTRL
elif symbol == key.LALT and lParam & (1 << 24):
symbol = key.RALT
if wParam == VK_SHIFT:
return # Let raw input handle this instead.
@ -801,11 +829,33 @@ class Win32Window(BaseWindow):
self.dispatch_event('on_text_motion', motion)
# Send on to DefWindowProc if not exclusive.
if self._keyboard_exclusive:
if self._exclusive_keyboard:
return 0
else:
return None
@Win32EventHandler(WM_WINDOWPOSCHANGED)
def _event_window_pos_changed(self, msg, wParam, lParam):
if self._exclusive_mouse:
self._update_clipped_cursor()
@Win32EventHandler(WM_NCLBUTTONDOWN)
def _event_ncl_button_down(self, msg, wParam, lParam):
self._in_title_bar = True
@Win32EventHandler(WM_CAPTURECHANGED)
def _event_capture_changed(self, msg, wParam, lParam):
self._in_title_bar = False
if self._exclusive_mouse:
state = _user32.GetAsyncKeyState(VK_LBUTTON)
if not state & 0x8000: # released
if self._pending_click:
self._pending_click = False
if self._has_focus or not self._hidden:
self._update_clipped_cursor()
@Win32EventHandler(WM_CHAR)
def _event_char(self, msg, wParam, lParam):
text = chr(wParam)
@ -813,7 +863,6 @@ class Win32Window(BaseWindow):
self.dispatch_event('on_text', text)
return 0
@ViewEventHandler
@Win32EventHandler(WM_INPUT)
def _event_raw_input(self, msg, wParam, lParam):
hRawInput = cast(lParam, HRAWINPUT)
@ -823,39 +872,10 @@ class Win32Window(BaseWindow):
byref(size), sizeof(RAWINPUTHEADER))
if inp.header.dwType == RIM_TYPEMOUSE:
if not self._mouse_exclusive:
if not self._exclusive_mouse:
return 0
rmouse = inp.data.mouse
if rmouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN:
self.dispatch_event('on_mouse_press', 0, 0, mouse.LEFT,
self._get_modifiers())
self._exclusive_mouse_buttons |= mouse.LEFT
if rmouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP:
self.dispatch_event('on_mouse_release', 0, 0, mouse.LEFT,
self._get_modifiers())
self._exclusive_mouse_buttons &= ~mouse.LEFT
if rmouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN:
self.dispatch_event('on_mouse_press', 0, 0, mouse.RIGHT,
self._get_modifiers())
self._exclusive_mouse_buttons |= mouse.RIGHT
if rmouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP:
self.dispatch_event('on_mouse_release', 0, 0, mouse.RIGHT,
self._get_modifiers())
self._exclusive_mouse_buttons &= ~mouse.RIGHT
if rmouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN:
self.dispatch_event('on_mouse_press', 0, 0, mouse.MIDDLE,
self._get_modifiers())
self._exclusive_mouse_buttons |= mouse.MIDDLE
if rmouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP:
self.dispatch_event('on_mouse_release', 0, 0, mouse.MIDDLE,
self._get_modifiers())
self._exclusive_mouse_buttons &= ~mouse.MIDDLE
if rmouse.usButtonFlags & RI_MOUSE_WHEEL:
delta = SHORT(rmouse.usButtonData).value
self.dispatch_event('on_mouse_scroll',
0, 0, 0, delta / float(WHEEL_DELTA))
rmouse = inp.data.mouse
if rmouse.usFlags & 0x01 == MOUSE_MOVE_RELATIVE:
if rmouse.lLastX != 0 or rmouse.lLastY != 0:
@ -887,13 +907,13 @@ class Win32Window(BaseWindow):
self.dispatch_event('on_mouse_motion', 0, 0,
rel_x, rel_y)
self._exclusive_mouse_lpos = rmouse.lLastX, rmouse.lLastY
elif inp.header.dwType == RIM_TYPEKEYBOARD:
if inp.data.keyboard.VKey == 255:
return 0
key_up = inp.data.keyboard.Flags & RI_KEY_BREAK
if inp.data.keyboard.MakeCode == 0x02A: # LEFT_SHIFT
if not key_up and not self._keyboard_state[0x02A]:
self._keyboard_state[0x02A] = True
@ -907,17 +927,17 @@ class Win32Window(BaseWindow):
if not key_up and not self._keyboard_state[0x036]:
self._keyboard_state[0x036] = True
self.dispatch_event('on_key_press', key.RSHIFT, self._get_modifiers())
elif key_up and self._keyboard_state[0x036]:
self._keyboard_state[0x036] = False
self.dispatch_event('on_key_release', key.RSHIFT, self._get_modifiers())
self.dispatch_event('on_key_release', key.RSHIFT, self._get_modifiers())
return 0
@ViewEventHandler
@Win32EventHandler(WM_MOUSEMOVE)
def _event_mousemove(self, msg, wParam, lParam):
if self._mouse_exclusive and self._has_focus:
if self._exclusive_mouse and self._has_focus:
return 0
x, y = self._get_location(lParam)
@ -1103,62 +1123,82 @@ class Win32Window(BaseWindow):
self.dispatch_event('on_move', x, y)
return 0
@Win32EventHandler(WM_EXITSIZEMOVE)
@Win32EventHandler(WM_SETCURSOR)
def _event_setcursor(self, msg, wParam, lParam):
if self._exclusive_mouse and not self._mouse_platform_visible:
lo, hi = self._get_location(lParam)
if lo == HTCLIENT: # In frame
self._set_cursor_visibility(False)
return 1
elif lo in (HTCAPTION, HTCLOSE, HTMAXBUTTON, HTMINBUTTON): # Allow in
self._set_cursor_visibility(True)
return 1
@Win32EventHandler(WM_ENTERSIZEMOVE)
def _event_entersizemove(self, msg, wParam, lParam):
self._moving = True
from pyglet import app
if app.event_loop is not None:
app.event_loop.exit_blocking()
"""
# Alternative to using WM_SETFOCUS and WM_KILLFOCUS. Which
# is better?
@Win32EventHandler(WM_EXITSIZEMOVE)
def _event_exitsizemove(self, msg, wParam, lParam):
self._moving = False
from pyglet import app
if app.event_loop is not None:
app.event_loop.exit_blocking()
@Win32EventHandler(WM_ACTIVATE)
def _event_activate(self, msg, wParam, lParam):
if wParam & 0xffff == WA_INACTIVE:
self.dispatch_event('on_deactivate')
else:
self.dispatch_event('on_activate')
_user32.SetFocus(self._hwnd)
return 0
"""
if self._exclusive_mouse:
self._update_clipped_cursor()
@Win32EventHandler(WM_SETFOCUS)
def _event_setfocus(self, msg, wParam, lParam):
self.dispatch_event('on_activate')
self._has_focus = True
self.set_exclusive_keyboard(self._keyboard_exclusive)
self.set_exclusive_mouse(self._mouse_exclusive)
if self._exclusive_mouse:
if _user32.GetAsyncKeyState(VK_LBUTTON):
self._pending_click = True
self.set_exclusive_keyboard(self._exclusive_keyboard)
self.set_exclusive_mouse(self._exclusive_mouse)
return 0
@Win32EventHandler(WM_KILLFOCUS)
def _event_killfocus(self, msg, wParam, lParam):
self.dispatch_event('on_deactivate')
self._has_focus = False
keyboard_exclusive = self._keyboard_exclusive
mouse_exclusive = self._mouse_exclusive
exclusive_keyboard = self._exclusive_keyboard
exclusive_mouse = self._exclusive_mouse
# Disable both exclusive keyboard and mouse
self.set_exclusive_keyboard(False)
self.set_exclusive_mouse(False)
# Reset shift state on Window focus loss.
for symbol in self._keyboard_state:
self._keyboard_state[symbol] = False
# But save desired state and note that we lost focus
# This will allow to reset the correct mode once we regain focus
self._keyboard_exclusive = keyboard_exclusive
self._exclusive_keyboard = exclusive_keyboard
self._exclusive_keyboard_focus = False
self._mouse_exclusive = mouse_exclusive
self._exclusive_mouse = exclusive_mouse
self._exclusive_mouse_focus = False
return 0
@Win32EventHandler(WM_GETMINMAXINFO)
def _event_getminmaxinfo(self, msg, wParam, lParam):
info = MINMAXINFO.from_address(lParam)
if self._minimum_size:
info.ptMinTrackSize.x, info.ptMinTrackSize.y = \
self._client_to_window_size(*self._minimum_size)
if self._maximum_size:
info.ptMaxTrackSize.x, info.ptMaxTrackSize.y = \
self._client_to_window_size(*self._maximum_size)
return 0
@Win32EventHandler(WM_ERASEBKGND)

View File

@ -101,6 +101,8 @@ _motion_map = {
(key.END, True): key.MOTION_END_OF_FILE,
(key.BACKSPACE, False): key.MOTION_BACKSPACE,
(key.DELETE, False): key.MOTION_DELETE,
(key.C, True): key.MOTION_COPY,
(key.V, True): key.MOTION_PASTE
}
@ -410,7 +412,7 @@ class XlibWindow(BaseWindow):
xlib.XFlush(self._x_display)
# Need to set argtypes on this function because it's vararg,
# Need to set argtypes on this function because its vararg,
# and ctypes guesses wrong.
xlib.XCreateIC.argtypes = [xlib.XIM,
c_char_p, c_int,

27
libs/toml/LICENSE.txt Normal file
View File

@ -0,0 +1,27 @@
The MIT License
Copyright 2013-2019 William Pearson
Copyright 2015-2016 Julien Enselme
Copyright 2016 Google Inc.
Copyright 2017 Samuel Vasko
Copyright 2017 Nate Prewitt
Copyright 2017 Jack Evans
Copyright 2019 Filippo Broggini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

25
libs/toml/__init__.py Normal file
View File

@ -0,0 +1,25 @@
"""Python module which parses and emits TOML.
Released under the MIT license.
"""
from toml import encoder
from toml import decoder
__version__ = "0.10.2"
_spec_ = "0.5.0"
load = decoder.load
loads = decoder.loads
TomlDecoder = decoder.TomlDecoder
TomlDecodeError = decoder.TomlDecodeError
TomlPreserveCommentDecoder = decoder.TomlPreserveCommentDecoder
dump = encoder.dump
dumps = encoder.dumps
TomlEncoder = encoder.TomlEncoder
TomlArraySeparatorEncoder = encoder.TomlArraySeparatorEncoder
TomlPreserveInlineDictEncoder = encoder.TomlPreserveInlineDictEncoder
TomlNumpyEncoder = encoder.TomlNumpyEncoder
TomlPreserveCommentEncoder = encoder.TomlPreserveCommentEncoder
TomlPathlibEncoder = encoder.TomlPathlibEncoder

1057
libs/toml/decoder.py Normal file

File diff suppressed because it is too large Load Diff

304
libs/toml/encoder.py Normal file
View File

@ -0,0 +1,304 @@
import datetime
import re
import sys
from decimal import Decimal
from toml.decoder import InlineTableDict
if sys.version_info >= (3,):
unicode = str
def dump(o, f, encoder=None):
"""Writes out dict as toml to a file
Args:
o: Object to dump into toml
f: File descriptor where the toml should be stored
encoder: The ``TomlEncoder`` to use for constructing the output string
Returns:
String containing the toml corresponding to dictionary
Raises:
TypeError: When anything other than file descriptor is passed
"""
if not f.write:
raise TypeError("You can only dump an object to a file descriptor")
d = dumps(o, encoder=encoder)
f.write(d)
return d
def dumps(o, encoder=None):
"""Stringifies input dict as toml
Args:
o: Object to dump into toml
encoder: The ``TomlEncoder`` to use for constructing the output string
Returns:
String containing the toml corresponding to dict
Examples:
```python
>>> import toml
>>> output = {
... 'a': "I'm a string",
... 'b': ["I'm", "a", "list"],
... 'c': 2400
... }
>>> toml.dumps(output)
'a = "I\'m a string"\nb = [ "I\'m", "a", "list",]\nc = 2400\n'
```
"""
retval = ""
if encoder is None:
encoder = TomlEncoder(o.__class__)
addtoretval, sections = encoder.dump_sections(o, "")
retval += addtoretval
outer_objs = [id(o)]
while sections:
section_ids = [id(section) for section in sections.values()]
for outer_obj in outer_objs:
if outer_obj in section_ids:
raise ValueError("Circular reference detected")
outer_objs += section_ids
newsections = encoder.get_empty_table()
for section in sections:
addtoretval, addtosections = encoder.dump_sections(
sections[section], section)
if addtoretval or (not addtoretval and not addtosections):
if retval and retval[-2:] != "\n\n":
retval += "\n"
retval += "[" + section + "]\n"
if addtoretval:
retval += addtoretval
for s in addtosections:
newsections[section + "." + s] = addtosections[s]
sections = newsections
return retval
def _dump_str(v):
if sys.version_info < (3,) and hasattr(v, 'decode') and isinstance(v, str):
v = v.decode('utf-8')
v = "%r" % v
if v[0] == 'u':
v = v[1:]
singlequote = v.startswith("'")
if singlequote or v.startswith('"'):
v = v[1:-1]
if singlequote:
v = v.replace("\\'", "'")
v = v.replace('"', '\\"')
v = v.split("\\x")
while len(v) > 1:
i = -1
if not v[0]:
v = v[1:]
v[0] = v[0].replace("\\\\", "\\")
# No, I don't know why != works and == breaks
joinx = v[0][i] != "\\"
while v[0][:i] and v[0][i] == "\\":
joinx = not joinx
i -= 1
if joinx:
joiner = "x"
else:
joiner = "u00"
v = [v[0] + joiner + v[1]] + v[2:]
return unicode('"' + v[0] + '"')
def _dump_float(v):
return "{}".format(v).replace("e+0", "e+").replace("e-0", "e-")
def _dump_time(v):
utcoffset = v.utcoffset()
if utcoffset is None:
return v.isoformat()
# The TOML norm specifies that it's local time thus we drop the offset
return v.isoformat()[:-6]
class TomlEncoder(object):
def __init__(self, _dict=dict, preserve=False):
self._dict = _dict
self.preserve = preserve
self.dump_funcs = {
str: _dump_str,
unicode: _dump_str,
list: self.dump_list,
bool: lambda v: unicode(v).lower(),
int: lambda v: v,
float: _dump_float,
Decimal: _dump_float,
datetime.datetime: lambda v: v.isoformat().replace('+00:00', 'Z'),
datetime.time: _dump_time,
datetime.date: lambda v: v.isoformat()
}
def get_empty_table(self):
return self._dict()
def dump_list(self, v):
retval = "["
for u in v:
retval += " " + unicode(self.dump_value(u)) + ","
retval += "]"
return retval
def dump_inline_table(self, section):
"""Preserve inline table in its compact syntax instead of expanding
into subsection.
https://github.com/toml-lang/toml#user-content-inline-table
"""
retval = ""
if isinstance(section, dict):
val_list = []
for k, v in section.items():
val = self.dump_inline_table(v)
val_list.append(k + " = " + val)
retval += "{ " + ", ".join(val_list) + " }\n"
return retval
else:
return unicode(self.dump_value(section))
def dump_value(self, v):
# Lookup function corresponding to v's type
dump_fn = self.dump_funcs.get(type(v))
if dump_fn is None and hasattr(v, '__iter__'):
dump_fn = self.dump_funcs[list]
# Evaluate function (if it exists) else return v
return dump_fn(v) if dump_fn is not None else self.dump_funcs[str](v)
def dump_sections(self, o, sup):
retstr = ""
if sup != "" and sup[-1] != ".":
sup += '.'
retdict = self._dict()
arraystr = ""
for section in o:
section = unicode(section)
qsection = section
if not re.match(r'^[A-Za-z0-9_-]+$', section):
qsection = _dump_str(section)
if not isinstance(o[section], dict):
arrayoftables = False
if isinstance(o[section], list):
for a in o[section]:
if isinstance(a, dict):
arrayoftables = True
if arrayoftables:
for a in o[section]:
arraytabstr = "\n"
arraystr += "[[" + sup + qsection + "]]\n"
s, d = self.dump_sections(a, sup + qsection)
if s:
if s[0] == "[":
arraytabstr += s
else:
arraystr += s
while d:
newd = self._dict()
for dsec in d:
s1, d1 = self.dump_sections(d[dsec], sup +
qsection + "." +
dsec)
if s1:
arraytabstr += ("[" + sup + qsection +
"." + dsec + "]\n")
arraytabstr += s1
for s1 in d1:
newd[dsec + "." + s1] = d1[s1]
d = newd
arraystr += arraytabstr
else:
if o[section] is not None:
retstr += (qsection + " = " +
unicode(self.dump_value(o[section])) + '\n')
elif self.preserve and isinstance(o[section], InlineTableDict):
retstr += (qsection + " = " +
self.dump_inline_table(o[section]))
else:
retdict[qsection] = o[section]
retstr += arraystr
return (retstr, retdict)
class TomlPreserveInlineDictEncoder(TomlEncoder):
def __init__(self, _dict=dict):
super(TomlPreserveInlineDictEncoder, self).__init__(_dict, True)
class TomlArraySeparatorEncoder(TomlEncoder):
def __init__(self, _dict=dict, preserve=False, separator=","):
super(TomlArraySeparatorEncoder, self).__init__(_dict, preserve)
if separator.strip() == "":
separator = "," + separator
elif separator.strip(' \t\n\r,'):
raise ValueError("Invalid separator for arrays")
self.separator = separator
def dump_list(self, v):
t = []
retval = "["
for u in v:
t.append(self.dump_value(u))
while t != []:
s = []
for u in t:
if isinstance(u, list):
for r in u:
s.append(r)
else:
retval += " " + unicode(u) + self.separator
t = s
retval += "]"
return retval
class TomlNumpyEncoder(TomlEncoder):
def __init__(self, _dict=dict, preserve=False):
import numpy as np
super(TomlNumpyEncoder, self).__init__(_dict, preserve)
self.dump_funcs[np.float16] = _dump_float
self.dump_funcs[np.float32] = _dump_float
self.dump_funcs[np.float64] = _dump_float
self.dump_funcs[np.int16] = self._dump_int
self.dump_funcs[np.int32] = self._dump_int
self.dump_funcs[np.int64] = self._dump_int
def _dump_int(self, v):
return "{}".format(int(v))
class TomlPreserveCommentEncoder(TomlEncoder):
def __init__(self, _dict=dict, preserve=False):
from toml.decoder import CommentValue
super(TomlPreserveCommentEncoder, self).__init__(_dict, preserve)
self.dump_funcs[CommentValue] = lambda v: v.dump(self.dump_value)
class TomlPathlibEncoder(TomlEncoder):
def _dump_pathlib_path(self, v):
return _dump_str(str(v))
def dump_value(self, v):
if (3, 4) <= sys.version_info:
import pathlib
if isinstance(v, pathlib.PurePath):
v = str(v)
return super(TomlPathlibEncoder, self).dump_value(v)

15
libs/toml/ordered.py Normal file
View File

@ -0,0 +1,15 @@
from collections import OrderedDict
from toml import TomlEncoder
from toml import TomlDecoder
class TomlOrderedDecoder(TomlDecoder):
def __init__(self):
super(self.__class__, self).__init__(_dict=OrderedDict)
class TomlOrderedEncoder(TomlEncoder):
def __init__(self):
super(self.__class__, self).__init__(_dict=OrderedDict)

24
libs/toml/tz.py Normal file
View File

@ -0,0 +1,24 @@
from datetime import tzinfo, timedelta
class TomlTz(tzinfo):
def __init__(self, toml_offset):
if toml_offset == "Z":
self._raw_offset = "+00:00"
else:
self._raw_offset = toml_offset
self._sign = -1 if self._raw_offset[0] == '-' else 1
self._hours = int(self._raw_offset[1:3])
self._minutes = int(self._raw_offset[4:6])
def __deepcopy__(self, memo):
return self.__class__(self._raw_offset)
def tzname(self, dt):
return "UTC" + self._raw_offset
def utcoffset(self, dt):
return self._sign * timedelta(hours=self._hours, minutes=self._minutes)
def dst(self, dt):
return timedelta(0)

View File

@ -0,0 +1,44 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# All rights reserved
# -------------------------------
"""
writen by shenjackyuanjie
mail: 3695888@qq.com
github: @shenjackyuanjie
gitee: @shenjackyuanjie
"""
import os
import cProfile
os.chdir('..')
os.chdir('..')
os.chdir('..')
from Difficult_Rocket.guis.format import html
try_texts = [
'明天天气很好',
'从前有座山,山里有座庙, **is it**?',
'啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊。阿巴巴巴',
'阿瓦达达瓦的aiwdhaihdwia.awdaiwhdahwido[12312](123131)',
'1231231dawdawd65ewwe56er56*awdadad*aaa**阿伟大的阿瓦打我的**'
]
def main_test():
for text in try_texts:
print(text)
print(html.decode_text2HTML(text))
print('------')
check = True
if check:
cProfile.run('main_test()', sort='calls')
else:
main_test()

16
try/julia/trytry.jl Normal file
View File

@ -0,0 +1,16 @@
#=
trytry:
- Julia version: 1.7.1
- Author: shenjack
- Date: 2022-01-17
=#
println("Hello, world!")
# 输入字符,然后输出输入的字符
abc = readline(stdin)
println("aaaa $abc")

397
try/pymunk/sample.py Normal file
View File

@ -0,0 +1,397 @@
"""Showcase what the output of pymunk.pyglet_util draw methods will look like.
See pygame_util_demo.py for a comparison to pygame.
"""
__docformat__ = "reStructuredText"
import sys
import pyglet
import pymunk
import pymunk.pyglet_util
from pymunk.vec2d import Vec2d
def fill_space(space, custom_color=(255, 255, 0, 255)):
captions = []
### Static
captions.append(((50, 680), "Static Shapes"))
# Static Segments
segments = [
pymunk.Segment(space.static_body, (10, 400), (10, 600), 0),
pymunk.Segment(space.static_body, (20, 400), (20, 600), 1),
pymunk.Segment(space.static_body, (30, 400), (30, 600), 3),
pymunk.Segment(space.static_body, (50, 400), (50, 600), 5),
]
space.add(*segments)
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (40, 630)
b.angle = 3.14 / 7
s = pymunk.Segment(b, (-30, 0), (30, 0), 2)
space.add(b, s)
# Static Circles
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (120, 630)
s = pymunk.Circle(b, 10)
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (120, 630)
s = pymunk.Circle(b, 10, (-30, 0))
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (120, 560)
b.angle = 3.14 / 4
s = pymunk.Circle(b, 40)
space.add(b, s)
# Static Polys
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (120, 460)
b.angle = 3.14 / 4
s = pymunk.Poly(b, [(0, -25), (30, 25), (-30, 25)])
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (120, 500)
t = pymunk.Transform(ty=-100)
s = pymunk.Poly(b, [(0, -25), (30, 25), (-30, 25)], t, radius=1)
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (50, 430)
t = pymunk.Transform(ty=-100)
s = pymunk.Poly(
b,
[
(0.0, -30.0),
(19.0, -23.0),
(30.0, -5.0),
(26.0, 15.0),
(10.0, 28.0),
(-10.0, 28.0),
(-26.0, 15.0),
(-30.0, -5.0),
(-19.0, -23.0),
],
t,
)
space.add(b, s)
### Kinematic
captions.append(((220, 680), "Kinematic Shapes"))
# Kinematic Segments
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
segments = [
pymunk.Segment(b, (180, 400), (180, 600), 0),
pymunk.Segment(b, (190, 400), (190, 600), 1),
pymunk.Segment(b, (200, 400), (200, 600), 3),
pymunk.Segment(b, (220, 400), (220, 600), 5),
]
space.add(b, *segments)
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (210, 630)
b.angle = 3.14 / 7
s = pymunk.Segment(b, (-30, 0), (30, 0), 2)
space.add(b, s)
# Kinematic Circles
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (290, 630)
s = pymunk.Circle(b, 10)
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (290, 630)
s = pymunk.Circle(b, 10, (-30, 0))
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (290, 560)
b.angle = 3.14 / 4
s = pymunk.Circle(b, 40)
space.add(b, s)
# Kinematic Polys
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (290, 460)
b.angle = 3.14 / 4
s = pymunk.Poly(b, [(0, -25), (30, 25), (-30, 25)])
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (290, 500)
t = pymunk.Transform(ty=-100)
s = pymunk.Poly(b, [(0, -25), (30, 25), (-30, 25)], t, radius=3)
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (230, 430)
t = pymunk.Transform(ty=-100)
s = pymunk.Poly(
b,
[
(19.0, -50.0),
(30.0, -5.0),
(26.0, 15.0),
(10.0, 38.0),
(-10.0, 38.0),
(-26.0, 15.0),
(-30.0, -5.0),
(-19.0, -50.0),
],
t,
)
space.add(b, s)
### Dynamic
captions.append(((390, 680), "Dynamic Shapes"))
# Dynamic Segments
b = pymunk.Body(1, 1)
segments = [
pymunk.Segment(b, (350, 400), (350, 600), 0),
pymunk.Segment(b, (360, 400), (360, 600), 1),
pymunk.Segment(b, (370, 400), (370, 600), 3),
pymunk.Segment(b, (390, 400), (390, 600), 5),
]
space.add(b, *segments)
b = pymunk.Body(1, 1)
b.position = (380, 630)
b.angle = 3.14 / 7
s = pymunk.Segment(b, (-30, 0), (30, 0), 7)
space.add(b, s)
# Dynamic Circles
b = pymunk.Body(1, 1)
b.position = (460, 630)
s = pymunk.Circle(b, 10)
space.add(b, s)
b = pymunk.Body(1, 1)
b.position = (460, 630)
s = pymunk.Circle(b, 10, (-30, 0))
space.add(b, s)
b = pymunk.Body(1, 1)
b.position = (460, 560)
b.angle = 3.14 / 4
s = pymunk.Circle(b, 40)
space.add(b, s)
# Dynamic Polys
b = pymunk.Body(1, 1)
b.position = (460, 460)
b.angle = 3.14 / 4
s = pymunk.Poly(b, [(0, -25), (30, 25), (-30, 25)])
space.add(b, s)
b = pymunk.Body(1, 1)
b.position = (460, 500)
s = pymunk.Poly(
b, [(0, -25), (30, 25), (-30, 25)], pymunk.Transform(ty=-100), radius=5
)
space.add(b, s)
b = pymunk.Body(1, 1)
b.position = (400, 430)
s = pymunk.Poly(
b, [(0, -50), (50, 0), (30, 50), (-30, 50), (-50, 0)], pymunk.Transform(ty=-100)
)
space.add(b, s)
###Constraints
# PinJoints
captions.append(((560, 660), "Pin Joint"))
a = pymunk.Body(1, 1)
a.position = (550, 600)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (650, 620)
sb = pymunk.Circle(b, 20)
j = pymunk.PinJoint(a, b, anchor_a=(0, 0), anchor_b=(0, -20))
space.add(sa, sb, a, b, j)
# SlideJoints
captions.append(((560, 560), "Slide Joint"))
a = pymunk.Body(1, 1)
a.position = (550, 500)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (650, 520)
sb = pymunk.Circle(b, 20)
j = pymunk.SlideJoint(a, b, anchor_a=(0, 20), anchor_b=(0, -20), min=10, max=30)
space.add(sa, sb, a, b, j)
# PivotJoints
captions.append(((560, 460), "Pivot Joint"))
a = pymunk.Body(1, 1)
a.position = (550, 400)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (650, 420)
sb = pymunk.Circle(b, 20)
j = pymunk.PivotJoint(a, b, (600, 390))
space.add(sa, sb, a, b, j)
# GrooveJoints
captions.append(((760, 660), "Groove Joint"))
a = pymunk.Body(1, 1)
a.position = (750, 600)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (850, 620)
sb = pymunk.Circle(b, 20)
j = pymunk.GrooveJoint(a, b, (40, 40), (40, -40), (-60, 0))
space.add(sa, sb, a, b, j)
# DampedSpring
captions.append(((760, 550), "Damped Spring"))
a = pymunk.Body(1, 1)
a.position = (750, 480)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (850, 500)
sb = pymunk.Circle(b, 20)
j = pymunk.DampedSpring(a, b, (0, 0), (0, 10), 100, 1, 1)
space.add(sa, sb, a, b, j)
# DampedRotarySpring
captions.append(((740, 430), "Damped Rotary Spring"))
a = pymunk.Body(1, 1)
a.position = (750, 350)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (850, 380)
sb = pymunk.Circle(b, 20)
j = pymunk.DampedRotarySpring(a, b, 10, 1, 1)
space.add(sa, sb, a, b, j)
# RotaryLimitJoint
captions.append(((740, 300), "Rotary Limit Joint"))
a = pymunk.Body(1, 1)
a.position = (750, 220)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (850, 250)
sb = pymunk.Circle(b, 20)
j = pymunk.RotaryLimitJoint(a, b, 1, 2)
b.angle = 3
space.add(sa, sb, a, b, j)
# RatchetJoint
captions.append(((740, 170), "Ratchet Joint"))
a = pymunk.Body(1, 1)
a.position = (750, 100)
sa = pymunk.Circle(a, 20)
b = pymunk.Body(1, 1)
b.position = (850, 120)
sb = pymunk.Circle(b, 20)
j = pymunk.RatchetJoint(a, b, 1, 0.1)
b.angle = 3
space.add(sa, sb, a, b, j)
# GearJoint and SimpleMotor omitted since they are similar to the already
# added joints
# TODO: more stuff here :)
### Other
# Objects in custom color
captions.append(((150, 150), "Custom Color (static, kinematic & dynamic)"))
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (200, 200)
s = pymunk.Circle(b, 30)
s.color = custom_color
space.add(b, s)
b = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
b.position = (300, 200)
s = pymunk.Circle(b, 30)
s.color = custom_color
space.add(b, s)
b = pymunk.Body(1, 1)
b.position = (400, 200)
s = pymunk.Circle(b, 30)
s.color = custom_color
space.add(b, s)
# Collision
captions.append(((550, 150), "Collisions"))
b = pymunk.Body(body_type=pymunk.Body.STATIC)
b.position = (570, 200)
s = pymunk.Circle(b, 40)
space.add(b, s)
b = pymunk.Body(1, 1)
b.position = (590, 250)
s = pymunk.Circle(b, 40)
space.add(b, s)
# Sleeping
captions.append(((50, 150), "Sleeping"))
b = pymunk.Body(1, 1)
b.position = (75, 200)
space.sleep_time_threshold = 0.01
s = pymunk.Circle(b, 40)
space.add(s, b)
b.sleep()
space.step(0.000001)
return captions
window = pyglet.window.Window(1000, 700, vsync=False)
space = pymunk.Space()
draw_options = pymunk.pyglet_util.DrawOptions()
captions = fill_space(space)
textbatch = pyglet.graphics.Batch()
pyglet.text.Label(
"Demo example of shapes drawn by pyglet_util.draw()",
x=5,
y=5,
batch=textbatch,
color=(100, 100, 100, 255),
)
for caption in captions:
x, y = caption[0]
y = y - 10
pyglet.text.Label(caption[1], x=x, y=y, batch=textbatch, color=(50, 50, 50, 255))
batch = pyglet.graphics.Batch()
# otherwise save screenshot wont work
_ = pyglet.window.FPSDisplay(window)
@window.event
def on_draw():
pyglet.gl.glClearColor(255, 255, 255, 255)
window.clear()
space.debug_draw(draw_options)
textbatch.draw()
@window.event
def on_key_press(symbol, modifiers):
if symbol == pyglet.window.key.P:
pyglet.image.get_buffer_manager().get_color_buffer().save(
"pyglet_util_demo.png"
)
pyglet.app.run()

21
try/sysstd.py Normal file
View File

@ -0,0 +1,21 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2021 by shenjackyuanjie
# All rights reserved
# -------------------------------
"""
writen by shenjackyuanjie
mail: 3695888@qq.com
github: @shenjackyuanjie
gitee: @shenjackyuanjie
"""
import sys
with sys.stdout as f:
print('aaaaa', file=f, flush=True)
with sys.__stdout__ as f:
print(f.readlines())