2021-10-04 20:41:41 +08:00
|
|
|
|
# -------------------------------
|
|
|
|
|
# Difficult Rocket
|
2023-01-20 14:08:12 +08:00
|
|
|
|
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
2021-10-04 20:41:41 +08:00
|
|
|
|
# All rights reserved
|
|
|
|
|
# -------------------------------
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
writen by shenjackyuanjie
|
|
|
|
|
mail: 3695888@qq.com
|
|
|
|
|
github: @shenjackyuanjie
|
|
|
|
|
gitee: @shenjackyuanjie
|
|
|
|
|
"""
|
|
|
|
|
|
2022-02-07 22:14:51 +08:00
|
|
|
|
# system function
|
2021-10-06 18:36:10 +08:00
|
|
|
|
import time
|
|
|
|
|
|
2023-01-01 17:58:40 +08:00
|
|
|
|
from typing import Union, Optional, Tuple
|
2021-10-25 22:08:00 +08:00
|
|
|
|
from decimal import Decimal
|
|
|
|
|
|
2022-10-29 19:13:00 +08:00
|
|
|
|
# from pyglet
|
|
|
|
|
import pyglet
|
|
|
|
|
from pyglet.text import Label
|
|
|
|
|
from pyglet.window import key
|
|
|
|
|
from pyglet.gui import widgets
|
|
|
|
|
from pyglet.graphics import Batch, Group
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
2023-01-01 15:54:53 +08:00
|
|
|
|
# from DR
|
|
|
|
|
from Difficult_Rocket.utils import translate
|
|
|
|
|
from Difficult_Rocket.command.api import CommandText
|
2023-05-12 21:06:56 +08:00
|
|
|
|
from Difficult_Rocket.utils.thread import new_thread
|
2023-01-01 15:54:53 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CommandLineTextEntry(widgets.TextEntry):
|
|
|
|
|
"""
|
|
|
|
|
基于 Text Entry 重写的 Command Line
|
|
|
|
|
"""
|
|
|
|
|
|
2023-12-03 16:54:07 +08:00
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
x: int,
|
|
|
|
|
y: int,
|
|
|
|
|
width: int,
|
|
|
|
|
color: Optional[Tuple[int, int, int, int]] = (255, 255, 255, 255),
|
|
|
|
|
text_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0, 255),
|
|
|
|
|
caret_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0),
|
|
|
|
|
batch: Optional[Batch] = None,
|
|
|
|
|
group: Optional[Group] = None,
|
|
|
|
|
):
|
|
|
|
|
super().__init__(
|
|
|
|
|
x=x,
|
|
|
|
|
y=y,
|
|
|
|
|
width=width,
|
|
|
|
|
color=color,
|
|
|
|
|
text_color=text_color,
|
|
|
|
|
caret_color=caret_color,
|
|
|
|
|
batch=batch,
|
|
|
|
|
group=group,
|
|
|
|
|
text="",
|
|
|
|
|
)
|
2023-01-01 21:54:59 +08:00
|
|
|
|
...
|
2023-01-01 17:58:40 +08:00
|
|
|
|
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
|
|
|
|
class CommandLine(widgets.WidgetBase):
|
|
|
|
|
"""
|
|
|
|
|
command line show
|
|
|
|
|
"""
|
|
|
|
|
|
2023-12-03 16:54:07 +08:00
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
x: int,
|
|
|
|
|
y: int,
|
|
|
|
|
width: int,
|
|
|
|
|
height: int,
|
|
|
|
|
length: int,
|
|
|
|
|
batch: Batch,
|
|
|
|
|
group: Group = None,
|
|
|
|
|
command_text: str = "/",
|
|
|
|
|
font_size: int = 20,
|
|
|
|
|
):
|
2021-10-04 20:41:41 +08:00
|
|
|
|
super().__init__(x, y, width, height)
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
2021-10-04 20:41:41 +08:00
|
|
|
|
# normal values
|
|
|
|
|
self.length = length
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self._command_list = ["" for _ in range(length)]
|
2021-10-25 22:08:00 +08:00
|
|
|
|
self._command_text = command_text
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._text_position = 0
|
|
|
|
|
self._command_view = 0
|
|
|
|
|
self._value = 0
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self._text = ""
|
2021-10-10 17:21:41 +08:00
|
|
|
|
self.command_split = 25
|
|
|
|
|
self.command_distance = 20
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
|
|
|
|
# group
|
|
|
|
|
self._user_group = group
|
2021-10-04 20:41:41 +08:00
|
|
|
|
bg_group = Group(order=0, parent=group)
|
|
|
|
|
fg_group = Group(order=1, parent=group)
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
2021-10-04 20:41:41 +08:00
|
|
|
|
# hidden value
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self._text = ""
|
|
|
|
|
self._line = Label(
|
|
|
|
|
x=x,
|
|
|
|
|
y=y,
|
|
|
|
|
batch=batch,
|
|
|
|
|
text=self.text,
|
|
|
|
|
color=(100, 255, 255, 255),
|
|
|
|
|
anchor_x="left",
|
|
|
|
|
anchor_y="bottom",
|
|
|
|
|
font_size=font_size,
|
|
|
|
|
font_name=translate.微软等宽,
|
|
|
|
|
group=fg_group,
|
|
|
|
|
)
|
|
|
|
|
self._label = [
|
|
|
|
|
Label(
|
|
|
|
|
x=x + 10,
|
|
|
|
|
y=y + self.command_distance + (line * self.command_split),
|
|
|
|
|
batch=batch,
|
|
|
|
|
text="a",
|
|
|
|
|
anchor_x="left",
|
|
|
|
|
anchor_y="bottom",
|
|
|
|
|
font_size=font_size - 3,
|
|
|
|
|
font_name=translate.鸿蒙简体,
|
|
|
|
|
group=bg_group,
|
|
|
|
|
)
|
|
|
|
|
for line in range(length)
|
|
|
|
|
]
|
2021-10-06 18:36:10 +08:00
|
|
|
|
# Rectangular outline with 5-pixel pad:
|
|
|
|
|
color = (100, 100, 100, 100)
|
|
|
|
|
self._pad = p = 5
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self._outline = pyglet.shapes.Rectangle(
|
|
|
|
|
x=x - p,
|
|
|
|
|
y=y - p,
|
|
|
|
|
width=width + p,
|
|
|
|
|
height=height + p,
|
|
|
|
|
color=color[:3],
|
|
|
|
|
batch=batch,
|
|
|
|
|
group=fg_group,
|
|
|
|
|
)
|
2021-10-04 20:41:41 +08:00
|
|
|
|
self._outline.opacity = color[3]
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
|
|
|
|
self.editing = False
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
|
|
|
|
def _update_position(self):
|
2021-10-23 17:01:59 +08:00
|
|
|
|
pass
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
2021-10-06 18:36:10 +08:00
|
|
|
|
def update_groups(self, order):
|
|
|
|
|
self._line.group = Group(order=order + 1, parent=self._user_group)
|
|
|
|
|
for label in self._label:
|
|
|
|
|
label.group = Group(order=order + 1, parent=self._user_group)
|
|
|
|
|
self._outline.group = Group(order=order + 2, parent=self._user_group)
|
|
|
|
|
|
2021-10-28 06:43:35 +08:00
|
|
|
|
"""
|
|
|
|
|
values
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def value(self):
|
|
|
|
|
return self.text
|
|
|
|
|
|
2021-10-04 20:41:41 +08:00
|
|
|
|
@property
|
|
|
|
|
def text(self):
|
|
|
|
|
return self._text
|
|
|
|
|
|
|
|
|
|
@text.setter
|
|
|
|
|
def text(self, value):
|
2023-12-03 16:54:07 +08:00
|
|
|
|
assert isinstance(value, str), "CommandLine's text must be string!"
|
2021-10-04 20:41:41 +08:00
|
|
|
|
self._text = value
|
|
|
|
|
self._line.text = value
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def command_view(self):
|
|
|
|
|
return self._command_view
|
|
|
|
|
|
|
|
|
|
@command_view.setter
|
|
|
|
|
def command_view(self, value):
|
|
|
|
|
"""
|
|
|
|
|
value:
|
|
|
|
|
-1 -> 将整个列表添加一个数据
|
|
|
|
|
如果长度超过length就删掉多余的
|
|
|
|
|
将视角移动到最下面,刷新显示列表
|
|
|
|
|
0 ~ (self.length-1) -> 切换视角到对应的行数
|
|
|
|
|
实际上还有一个限制
|
|
|
|
|
"""
|
2023-12-03 16:54:07 +08:00
|
|
|
|
assert isinstance(value, int), "Command View must be integer"
|
|
|
|
|
assert (
|
|
|
|
|
-self.length < value < self.length
|
|
|
|
|
), f"Command View must be bigger than {-self.length} and smaller than {self.length}"
|
2021-10-04 20:41:41 +08:00
|
|
|
|
if value == -1: # flush command list
|
|
|
|
|
self._label.insert(0, self._label[-1])
|
|
|
|
|
self._label.pop(-1)
|
|
|
|
|
for line in range(self.length):
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self._label[line].y = (
|
|
|
|
|
self.y + self.command_distance + (line * self.command_split)
|
|
|
|
|
)
|
2021-10-04 20:41:41 +08:00
|
|
|
|
self._label[0].text = self.text
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self.text = ""
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._command_view = 0
|
2021-10-07 19:56:32 +08:00
|
|
|
|
self._text_position = 0
|
2021-10-04 20:41:41 +08:00
|
|
|
|
elif value == self._command_view: # not doing anything
|
|
|
|
|
pass
|
|
|
|
|
elif value > self._command_view: # move upwards
|
|
|
|
|
pass
|
|
|
|
|
else: # move downwards
|
|
|
|
|
pass
|
2021-10-25 22:08:00 +08:00
|
|
|
|
# self._command_view = value
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def editing(self):
|
|
|
|
|
return self._editing
|
|
|
|
|
|
|
|
|
|
@editing.setter
|
|
|
|
|
def editing(self, value):
|
2023-12-03 16:54:07 +08:00
|
|
|
|
assert isinstance(value, bool), "Command editing must be bool!"
|
2021-10-04 20:41:41 +08:00
|
|
|
|
self._editing = value
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._line.visible = value
|
|
|
|
|
self._outline.visible = value
|
|
|
|
|
for label in self._label:
|
|
|
|
|
label.visible = value
|
|
|
|
|
|
2023-12-03 16:54:07 +08:00
|
|
|
|
@new_thread("command wait", daemon=True, log_thread=False)
|
2021-10-28 06:43:35 +08:00
|
|
|
|
def wait(self, wait: Union[float, int] = 0):
|
|
|
|
|
this = self._label[0]
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._label[0].visible = True
|
|
|
|
|
time.sleep(wait)
|
|
|
|
|
if self._label[0].visible and not self.editing:
|
2023-12-03 16:54:07 +08:00
|
|
|
|
while (
|
|
|
|
|
(self._label[0].opacity >= 30)
|
|
|
|
|
and self._label[0].visible
|
|
|
|
|
and (self._label[0] is this)
|
|
|
|
|
and not self.editing
|
|
|
|
|
):
|
2021-10-28 06:43:35 +08:00
|
|
|
|
# (label 的透明度不是 0) and (label 还在显示) and (label 还是载入线程时候的那个label) and (现在不在输入新行)
|
|
|
|
|
self._label[0].opacity -= 2
|
|
|
|
|
time.sleep(0.01)
|
|
|
|
|
if self._label[0] is this: # 如果结束的时候label还是这个label
|
|
|
|
|
self._label[0].opacity = 255
|
|
|
|
|
else: # 如果不是就赶快找回来!
|
|
|
|
|
now = self._label.index(this)
|
|
|
|
|
self._label[now].opacity = 255
|
|
|
|
|
if not self.editing: # 如果不在编辑再隐藏
|
|
|
|
|
self._label[0].visible = False
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
2021-10-31 23:26:32 +08:00
|
|
|
|
@property
|
|
|
|
|
def command_list(self):
|
|
|
|
|
return self._command_list
|
|
|
|
|
|
2021-10-25 22:08:00 +08:00
|
|
|
|
"""
|
|
|
|
|
events
|
|
|
|
|
"""
|
|
|
|
|
|
2021-10-04 20:41:41 +08:00
|
|
|
|
def on_text(self, text):
|
2021-11-06 19:07:32 +08:00
|
|
|
|
# 这里的大部分东西都会在最近被重写
|
|
|
|
|
# TODO 重写成基于新的 InputBox 的解析
|
2021-10-04 20:41:41 +08:00
|
|
|
|
if self.editing:
|
2023-12-03 16:54:07 +08:00
|
|
|
|
if text in ("\r", "\n"): # goto a new line
|
2021-10-12 06:31:16 +08:00
|
|
|
|
if not self.text:
|
|
|
|
|
pass
|
2021-10-25 22:08:00 +08:00
|
|
|
|
elif self.text[0] == self._command_text:
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self.dispatch_event("on_command", CommandText(self.text[1:]))
|
2021-10-06 18:36:10 +08:00
|
|
|
|
else:
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self.dispatch_event("on_message", CommandText(self.text))
|
2021-10-25 22:08:00 +08:00
|
|
|
|
# on_message 和 on_command 可能会覆盖 self.text 需要再次判定
|
|
|
|
|
if self.text:
|
|
|
|
|
self.command_view = -1
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self.editing = False
|
2021-10-28 06:43:35 +08:00
|
|
|
|
self.wait()
|
2021-10-04 20:41:41 +08:00
|
|
|
|
else:
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self.text = f"{self.text[:self._text_position]}{text}{self.text[self._text_position:]}" # 插入字符(简单粗暴)
|
2021-10-04 20:41:41 +08:00
|
|
|
|
self._text_position += 1
|
2023-12-03 16:54:07 +08:00
|
|
|
|
elif text == "t": # open message line
|
2021-10-10 16:51:53 +08:00
|
|
|
|
self.editing = True
|
2023-12-03 16:54:07 +08:00
|
|
|
|
elif text == "/": # open command line
|
2021-10-10 16:51:53 +08:00
|
|
|
|
self.editing = True
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self.text = "/"
|
2021-10-10 16:51:53 +08:00
|
|
|
|
self._text_position = 1
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
|
|
|
|
def on_text_motion(self, motion):
|
|
|
|
|
if self.editing:
|
2021-10-06 18:36:10 +08:00
|
|
|
|
# edit motion
|
2021-10-12 06:33:16 +08:00
|
|
|
|
if motion == key.MOTION_DELETE: # 确保不越界
|
2023-12-03 16:54:07 +08:00
|
|
|
|
self.text = f"{self.text[:self._text_position]}{self.text[self._text_position + 1:]}" # 简单粗暴的删除
|
|
|
|
|
elif (
|
|
|
|
|
motion == key.MOTION_BACKSPACE and self._text_position >= 1
|
|
|
|
|
): # 确保不越界
|
|
|
|
|
self.text = f"{self.text[:self._text_position - 1]}{self.text[self._text_position:]}" # 简单粗暴的删除
|
2021-10-12 06:33:16 +08:00
|
|
|
|
self._text_position -= 1 # 记得切换光标位置
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
|
|
|
|
# move motion
|
2021-10-12 06:33:16 +08:00
|
|
|
|
elif motion == key.MOTION_LEFT and self._text_position >= 0: # 确保不越界
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._text_position -= 1
|
2023-12-03 16:54:07 +08:00
|
|
|
|
elif motion == key.MOTION_RIGHT and self._text_position <= len(
|
|
|
|
|
self.text
|
|
|
|
|
): # 确保不越界
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._text_position += 1
|
2023-12-03 16:54:07 +08:00
|
|
|
|
elif motion in (
|
|
|
|
|
key.MOTION_BEGINNING_OF_LINE,
|
|
|
|
|
key.MOTION_BEGINNING_OF_FILE,
|
|
|
|
|
key.MOTION_PREVIOUS_PAGE,
|
|
|
|
|
):
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._text_position = 0
|
2023-12-03 16:54:07 +08:00
|
|
|
|
elif motion in (
|
|
|
|
|
key.MOTION_END_OF_LINE,
|
|
|
|
|
key.MOTION_END_OF_FILE,
|
|
|
|
|
key.MOTION_NEXT_PAGE,
|
|
|
|
|
):
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self._text_position = len(self.text)
|
|
|
|
|
|
|
|
|
|
# view move motion
|
|
|
|
|
elif motion == key.MOTION_DOWN:
|
2023-01-27 21:09:37 +08:00
|
|
|
|
if self.command_view != -1:
|
2021-10-06 18:36:10 +08:00
|
|
|
|
self.command_view -= 1
|
|
|
|
|
else:
|
|
|
|
|
pass
|
2021-10-04 20:41:41 +08:00
|
|
|
|
|
|
|
|
|
def on_text_motion_select(self, motion):
|
2021-10-06 18:36:10 +08:00
|
|
|
|
if self.editing:
|
2021-10-23 17:01:59 +08:00
|
|
|
|
pass
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
|
|
|
|
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
|
|
|
|
|
if self.editing:
|
2021-10-23 17:01:59 +08:00
|
|
|
|
pass
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
|
|
|
|
def on_mouse_press(self, x, y, buttons, modifiers):
|
|
|
|
|
if self.editing:
|
2021-10-23 17:01:59 +08:00
|
|
|
|
pass
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
2021-10-25 22:08:00 +08:00
|
|
|
|
"""
|
|
|
|
|
custom event
|
|
|
|
|
"""
|
|
|
|
|
|
2021-10-23 17:01:59 +08:00
|
|
|
|
def on_command(self, command: text):
|
2021-10-06 18:36:10 +08:00
|
|
|
|
if self.editing:
|
|
|
|
|
return
|
|
|
|
|
"""give command to it"""
|
|
|
|
|
|
2021-10-23 17:01:59 +08:00
|
|
|
|
def on_message(self, message: text):
|
2021-10-06 18:36:10 +08:00
|
|
|
|
if self.editing:
|
|
|
|
|
return
|
|
|
|
|
"""give message to it"""
|
|
|
|
|
|
2021-10-25 22:08:00 +08:00
|
|
|
|
def push_line(self, line: Union[str, int, float, Decimal], block_line: bool = False):
|
|
|
|
|
_text = self.text
|
|
|
|
|
self.text = str(line)
|
|
|
|
|
self.command_view = -1
|
|
|
|
|
if not block_line:
|
|
|
|
|
self.text = _text
|
|
|
|
|
|
2021-10-06 18:36:10 +08:00
|
|
|
|
|
2023-12-03 16:54:07 +08:00
|
|
|
|
CommandLine.register_event_type("on_command")
|
|
|
|
|
CommandLine.register_event_type("on_message")
|