0.6.1 update!
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import threading
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -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)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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']
|
||||
|
342
Difficult_Rocket/guis/format/html.py
Normal 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!
|
30
Difficult_Rocket/guis/label.py
Normal 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'
|
@ -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: # 光标位置
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021 by shenjackyuanjie
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
|
@ -5,12 +5,12 @@
|
||||
|
||||
[](https://Semver.org/)
|
||||
[](https://Python.org)
|
||||
[](https://pyglet.org)
|
||||
[](https://pyglet.org)
|
||||
[](https://Python.org)
|
||||
|
||||
## Version
|
||||
|
||||
[](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
<br/>[](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
<br/>
|
||||
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
## 版本
|
||||
|
||||
[](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
<br/>[](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
<br/>
|
||||
|
||||
@ -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
|
||||
|
Before Width: | Height: | Size: 454 KiB After Width: | Height: | Size: 454 KiB |
Before Width: | Height: | Size: 402 KiB After Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 571 KiB After Width: | Height: | Size: 571 KiB |
Before Width: | Height: | Size: 366 KiB After Width: | Height: | Size: 366 KiB |
@ -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
|
||||
[](https://Semver.org/)
|
||||

|
||||

|
||||
|
||||
- [](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||
- [](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
|
||||
- [-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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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()]
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -111,6 +111,7 @@ def add_default_media_codecs():
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
def have_ffmpeg():
|
||||
"""Check if FFmpeg library is available.
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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`
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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
@ -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
304
libs/toml/encoder.py
Normal 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
@ -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
@ -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)
|
44
test/gui/format/html_format.py
Normal 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
@ -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
@ -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
@ -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())
|