diff --git a/pulsar/__pycache__/main.cpython-312.pyc b/pulsar/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000..34ca514 Binary files /dev/null and b/pulsar/__pycache__/main.cpython-312.pyc differ diff --git a/pulsar/layouts.yaml b/pulsar/layouts.yaml new file mode 100644 index 0000000..f481770 --- /dev/null +++ b/pulsar/layouts.yaml @@ -0,0 +1,16 @@ +horizontal_indicator: + - type: line + args: + ends: [(0.4, 0.5), (0.6, 0.5)] + color: green + - type: line + name: remote + args: + ends: [(0.4, 0.5), (0.6, 0.5)] + color: green + - type: line + status: static + args: + ends: [(0.4, 0.5), (0.6, 0.5)] + color: green + \ No newline at end of file diff --git a/pulsar/main.py b/pulsar/main.py new file mode 100644 index 0000000..354e91d --- /dev/null +++ b/pulsar/main.py @@ -0,0 +1,25 @@ +import vgl +import time +window = None +def horizontal_indicator(): + global window + frame = vgl.Frame().attach(window, (0, 0), "Horizontal Indicator") + vgl.elements.Line(ends=[(0.4, 0.5), (0.6, 0.5)], color="green").attach(frame) + pass +def console(): + print("You've entered Pulsar's command console, an embbedded Python interpreter for debugging & testing") + while True: + try: + exec(input(">>> ")) + except: + print("An error caused & captured") + +if __name__ == '__main__': + print("Welcome to AiraPulsar Client") + window = vgl.Window(title="Pulsar", size=(1600, 800)) + window.start() + horizontal_indicator() + #console() + time.sleep(3) + window.kill() + exit() \ No newline at end of file diff --git a/pulsar/vgl b/pulsar/vgl new file mode 120000 index 0000000..c640883 --- /dev/null +++ b/pulsar/vgl @@ -0,0 +1 @@ +/home/ajax/Documents/Index/302A/vgl \ No newline at end of file diff --git a/testfield/vgl/test.py b/testfield/vgl/test.py deleted file mode 100644 index e69de29..0000000 diff --git a/testfield/vgl/vgllib old.py b/testfield/vgl/vgllib old.py deleted file mode 100644 index 46b1317..0000000 --- a/testfield/vgl/vgllib old.py +++ /dev/null @@ -1,189 +0,0 @@ -# Vector Graphics Library -# vgllib.py -import pygame -import uuid -import time -import threading -import math - -class Graph: - @staticmethod - def rect(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), width: int = 0): - pygame.draw.rect(frame.surface, color=color, rect=(pos[0], pos[1], size[0], size[1]), width=width) - - @staticmethod - def line(frame, start_pos: tuple, end_pos: tuple, color: tuple = (255, 255, 255)): - pygame.draw.aaline(frame.surface, color, start_pos, end_pos) - - @staticmethod - def circle(frame, center: tuple, radius: int, color: tuple = (255, 255, 255), width: int = 0): - pygame.draw.circle(frame.surface, color, center, radius, width) - - @staticmethod - def ellipse(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), width: int = 0): - rect=(pos[0], pos[1], size[0], size[1]) - pygame.draw.ellipse(frame.surface, color, rect, width) - - @staticmethod - def polygon(frame, pointlist: list, color: tuple = (255, 255, 255), width: int = 0): - pygame.draw.polygon(frame.surface, color, pointlist, width) - - @staticmethod - def arc(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), start_angle: float = 0, stop_angle: float = 3.14, width: int = 1): - rect=(pos[0], pos[1], size[0], size[1]) - pygame.draw.arc(frame.surface, color, rect, start_angle, stop_angle, width) - - @staticmethod - def point(frame, pos: tuple, color: tuple = (255, 255, 255)): - pygame.draw.point(frame.surface, color, pos) - - @staticmethod - def lines(frame, pointlist: list, color: tuple = (255, 255, 255)): - pygame.draw.aalines(frame.surface, color, closed=False, points=pointlist) - - @staticmethod - def call(frame, method, **kwargs): - if hasattr(Graph, method): - getattr(Graph, method)(frame, **kwargs) - else: - print(f"方法 {method} 不存在") - -class Frame(object): - components = dict() - components_stat = dict() - render_thread = None - motion_queue = list() - def __init__(self, name: str, size: tuple): - self.name = name - self.size = size - self.surface = pygame.Surface(size, flags=pygame.HWSURFACE) - self.is_hide = False - print("初始化子模块") - self.render_thread = threading.Thread(target=self.render) - print("启动图形渲染子线程") - self.render_thread.start() - - def move(self, subname, direction, length, duration = 0, effect="linear"): # our powerful move! - # direction: 使用角度制, 以直角笛卡尔坐标系的x正半轴方向为0度, 逆时针为加, 接受负数 - # length: 百分数 - # duration: "动画"时间, 为0则即时 - # effect: "动画"效果, linear为线性移动, 或许会在未来增加贝塞尔曲线 - # TODO: 增加 bezier 曲线 - if duration == 0: - self.components[subname]["pos"][0] += math.cos(math.radians(direction)) * length / 100 * self.size[0] - self.components[subname]["pos"][1] += math.sin(math.radians(direction)) * length / 100 * self.size[1] - return - self.motion_queue.append({"subname":subname, "direction":direction, "length":length, "start":round(time.time(), 1), "duration":duration, "effect":"linear"}) - - def render(self): - while 1: - rest = list() - while self.motion_queue: - i = self.motion_queue.pop(0) # 从队列的开头移除元素 - self.move(subname=i['subname'], direction=i['direction'], - length=((time.time() - i['start']) / i['duration']) * i['length'], - duration=0) - if ((time.time() - i['start']) / i['duration']) > 0: - i['start'] = time.time() - i['duration'] -= (time.time() - i['start']) - rest.append(i) - self.draw_all() - self.motion_queue = rest - time.sleep(0.1) - - - def show(self, window, position: tuple): - if not self.is_hide: - window.blit(self.surface, position) - - def set_visible(self, newstat=True): - self.is_hide = newstat - - def set_position(self, newposition): - self.position = newposition - - def register(self, subname="", attr=None): - if subname == "": - subname = uuid.uuid4() - # use percent of frame size instead of pixels :) - attr['pos'] = list(attr['pos']) - attr['pos'][0] = round(attr['pos'][0] / 100 * self.size[0]) - attr['pos'][1] = round(attr['pos'][1] / 100 * self.size[1]) - attr['size'] = list(attr['size']) - attr['size'][0] = round(attr['size'][0] / 100 * self.size[0]) - attr['size'][1] = round(attr['size'][1] / 100 * self.size[1]) - self.components[subname] = attr - self.components_stat[subname] = 1 # by default, not hiding - - def draw(self, attr): - Graph.call(self, **attr) - - def set_component_visible(self, subname, newstat): - self.components_stat[subname] = newstat - - def draw_all(self): - for i in self.components.keys(): - if self.components_stat[i]: - self.draw(self.components[i]) - - def refresh(self, color=(0,0,0)): - self.surface.fill(color) - - def clear(self): - components = dict() - components_stat = dict() - - def loads(self, grap_str): - # TODO: 将会重写 以替代不安全的 eval - self.register(subname="", attr=(eval(grap_str))) - - def load(self, file="default.vgld", mode="a"): - # a: 增量加载 (默认) - # w: 覆盖式加载 - # 文件扩展名: vgld (矢量图形层描述文件) - if mode == 'w': - self.clear() - with open(file=file, mode="r+", encoding="UTF-8") as f: - for i in f.readlines(): - #print(i) - self.loads(i) - - -# 示例 -if __name__ == "__main__": - frame = None - def grap(): - global frame - pygame.init() - window = pygame.display.set_mode((1200, 900)) - frame = Frame("Test", (1200, 900)) - #frame.load() - frame.register(subname="test", attr={'method': 'rect', 'pos': (33, 33), 'size': (50, 50), 'color': (255, 255, 255)}) - #frame.move(subname='test', direction=0, length=90, duration=1, effect="linear") - running = True - while running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - - window.fill((0, 0, 0)) - frame.show(window, (0, 0)) - pygame.display.flip() - pygame.time.delay(10) - pygame.quit() - def debug(): - global frame - while 1: - try: - e = input(">>>") - if e == "f": - e = "frame.move(subname='test', direction=0, length=3, duration=1, effect='linear')" - if e == "g": - e = "frame.move(subname='test', direction=180, length=3, duration=1, effect='linear')" - exec(e) - except: - print("ER") - grap_thd = threading.Thread(target=grap) - debug_thd = threading.Thread(target=debug) - grap_thd.start() - debug_thd.start() \ No newline at end of file diff --git a/testfield/vgl/README.md b/vgl/README.md similarity index 100% rename from testfield/vgl/README.md rename to vgl/README.md diff --git a/vgl/__init__.py b/vgl/__init__.py new file mode 100644 index 0000000..d1e7c50 --- /dev/null +++ b/vgl/__init__.py @@ -0,0 +1,7 @@ +import os +os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "True" +from .main import * +from . import basic_elements as elements + +version = '0.1.0' +print(f"Powered by Vector Graphic Layer, version {version}") \ No newline at end of file diff --git a/vgl/__pycache__/__init__.cpython-312.pyc b/vgl/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..6c62fbe Binary files /dev/null and b/vgl/__pycache__/__init__.cpython-312.pyc differ diff --git a/vgl/__pycache__/basic.cpython-312.pyc b/vgl/__pycache__/basic.cpython-312.pyc new file mode 100644 index 0000000..821a0f4 Binary files /dev/null and b/vgl/__pycache__/basic.cpython-312.pyc differ diff --git a/vgl/__pycache__/basic_elements.cpython-312.pyc b/vgl/__pycache__/basic_elements.cpython-312.pyc new file mode 100644 index 0000000..106fda9 Binary files /dev/null and b/vgl/__pycache__/basic_elements.cpython-312.pyc differ diff --git a/vgl/__pycache__/main.cpython-312.pyc b/vgl/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000..c66ebab Binary files /dev/null and b/vgl/__pycache__/main.cpython-312.pyc differ diff --git a/vgl/__pycache__/vgllib.cpython-312.pyc b/vgl/__pycache__/vgllib.cpython-312.pyc new file mode 100644 index 0000000..439288d Binary files /dev/null and b/vgl/__pycache__/vgllib.cpython-312.pyc differ diff --git a/testfield/vgl/elements/ basic.py b/vgl/basic_elements.py similarity index 66% rename from testfield/vgl/elements/ basic.py rename to vgl/basic_elements.py index 3810c12..9693dc9 100644 --- a/testfield/vgl/elements/ basic.py +++ b/vgl/basic_elements.py @@ -1,13 +1,55 @@ -from vgllib import * +from vgl.main import * import pygame import time class Line(Element): - angle = None + def __init__(self, ends = [(0.1, 0.1), (0.2, 0.2)], color = "#ffffff"): + self.color = color + self.ends = ends def move(self, delta, duration): self.add_task(group = "move", start_time = Aux.gettime(), duration = duration, delta = delta) def update(self): for i in self.tasks.get("move", []): self.teleport(Aux.tuple_scale(tup = i['delta'], mul = Aux.getprogress(i))) + def render(self): + pygame.draw.aaline(self.attached_frame.surface, self.color, Aux.pixelizer(self.ends[0], self.attached_window), Aux.pixelizer(self.ends[1], self.attached_window)) +class Rect(Element): + def __init__(self, nw_posc=(0.1, 0.1), se_posc=(0.2,0.2), color = "#114514", width = 0): # non-0 for "frame" + self.color = color + self.width = width + self.rect = (nw_posc[0], nw_posc[1], se_posc[0], se_posc[1]) + def move(self, delta, duration): + self.add_task(group = "move", start_time = Aux.gettime(), duration = duration, delta = delta) + def update(self): + for i in self.tasks.get("move", []): + self.teleport(Aux.tuple_scale(tup = i['delta'], mul = Aux.getprogress(i))) + def render(self): + pygame.draw.rect(surface=self.attached_frame.surface, color=self.color, rect=Aux.pixelizer(self.rect, self.attached_window), width=self.width) + + + + + + + + + + + + + + + + + + + + + + + + + + class Graph: @staticmethod def rect(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), width: int = 0): diff --git a/testfield/vgl/vgllib.py b/vgl/main.py similarity index 63% rename from testfield/vgl/vgllib.py rename to vgl/main.py index 3edc89e..101543c 100644 --- a/testfield/vgl/vgllib.py +++ b/vgl/main.py @@ -4,7 +4,6 @@ import pygame import uuid import time import threading -import math import copy class Aux(): @@ -14,58 +13,80 @@ class Aux(): return (Aux.gettime() - task["start"] / task["duration"]) def tuple_scale(tup, mul): return (tup[0]*mul, tup[1]*mul) + def pixelizer(arg, base): + if not isinstance(base, tuple): + base = base.size + if isinstance(arg, int): + return arg * base + else: + if len(arg) == 2: + return (round(arg[0] * base[0]), round(arg[1] * base[1])) + if len(arg) == 4: + return (round(arg[0] * base[0]), round(arg[1] * base[1]), round(arg[2] * base[0]), round(arg[3] * base[1])) + class Element(object): - poscale: tuple = (0, 0) is_hide = False is_template = True attached = None + attached_frame = None + attached_window = None tasks = dict() def __init__(self, name="Element"): self.name = name - def attach(self, clone_name, frame_object, poscale): + def attach(self, frame_object, clone_name=""): if clone_name == "": clone_name = str(uuid.uuid4()) clone = copy.deepcopy(self) - clone.poscale = poscale clone.is_template = False frame_object.elements[clone_name] = clone + clone.attached_frame = frame_object + clone.attached_window = frame_object.attached_window + return clone def teleport(self, delta: tuple): if not self.is_template: - self.poscale[0] += delta[0] - self.poscale[1] += delta[1] + pass def add_task(self, group, start_time, duration, **kwargs): if group not in self.tasks(): self.tasks[group] = list() self.tasks[group].append({"start": start_time, "duration":duration, "para":kwargs}) + def render(): + print("未配置渲染器") + pass def update(): pass class Frame(object): + surface = None elements = dict() is_hide = False is_template = True + attached_window = None poscale: tuple = (0, 0) # 左上角, 对于每个实例的位置矢量 - def __init__(self, name="Frame", scale: tuple=(1, 1)): + def __init__(self, name="Frame"): self.name = name - self.scale = scale - def attach(self, clone_name, window_object, poscale): + def attach(self, window_object, poscale, clone_name=""): if clone_name == "": clone_name = str(uuid.uuid4()) clone = copy.deepcopy(self) + clone.surface = pygame.Surface(window_object.size) clone.poscale = poscale clone.is_template = False + clone.attached_window = window_object window_object.frames[clone_name] = clone - def render(): - pass + return window_object.frames[clone_name] + def render(self): + for i in self.elements.values(): + i.render() + self.attached_window.screen.blit(self.surface, self.poscale) class Window(object): - frames = list() + frames = dict() def __init__(self, title="Vector Graphic Layer Window", size: tuple=(1024,768)): self.title = title self.size = size self.running = 1 pygame.init() - self.window = pygame.display.set_mode(size) + self.screen = pygame.display.set_mode(size) pygame.display.set_caption(title) def set_title(self, title): self.title = title @@ -80,10 +101,8 @@ class Window(object): for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = 0 - self.window.fill((0, 0, 0)) + for i in self.frames.values(): + i.render() pygame.display.flip() pygame.time.delay(10) pygame.quit() - -if __name__ == "__main__": - pass \ No newline at end of file diff --git a/vgl/test.py b/vgl/test.py new file mode 100644 index 0000000..3604884 --- /dev/null +++ b/vgl/test.py @@ -0,0 +1,28 @@ +import pygame +import sys + +# 初始化 Pygame +pygame.init() + +# 设置窗口大小 +screen = pygame.display.set_mode((800, 600)) + +# 设置颜色 (RGB) +background_color = (255, 255, 255) # 白色背景 +line_color = (255, 0, 0) # 红色线条 + +# 主循环 +while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + + # 填充背景 + screen.fill(background_color) + + # 绘制抗锯齿线条 + pygame.draw.aaline(screen, line_color, (100, 100), (700, 500)) + + # 更新显示 + pygame.display.flip() diff --git a/vgl/vgl b/vgl/vgl new file mode 120000 index 0000000..420a07c --- /dev/null +++ b/vgl/vgl @@ -0,0 +1 @@ +vgl \ No newline at end of file