-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrenderer.py
More file actions
141 lines (120 loc) · 4.89 KB
/
renderer.py
File metadata and controls
141 lines (120 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import pygame
import math
from constants import (BLUEPRINT_COLOR, BLUEPRINT_LINE_COLOR, TOOLBAR_WIDTH,
BLUEPRINT_GRID_SIZE)
class GridRenderer:
def draw(self, screen, panning_state, zoom):
# Background
screen.fill(BLUEPRINT_COLOR)
# Grid with zoom
grid_size = BLUEPRINT_GRID_SIZE * zoom
screen_w = screen.get_width()
screen_h = screen.get_height()
x_start = TOOLBAR_WIDTH - (panning_state.offset_x % BLUEPRINT_GRID_SIZE) * zoom
y_start = - (panning_state.offset_y % BLUEPRINT_GRID_SIZE) * zoom
x = x_start
while x < screen_w:
pygame.draw.line(screen, BLUEPRINT_LINE_COLOR, (x, 0), (x, screen_h))
x += grid_size
y = y_start
while y < screen_h:
pygame.draw.line(screen, BLUEPRINT_LINE_COLOR, (TOOLBAR_WIDTH, y), (screen_w, y))
y += grid_size
class NodeEditorRenderer:
def __init__(self, editor):
self.editor = editor
self.grid_renderer = GridRenderer()
def draw(self, events):
self.grid_renderer.draw(
self.editor.screen,
self.editor.panning_state,
self.editor.zoom
)
self.draw_connections()
self.draw_nodes()
self.draw_toolbar()
self.draw_offscreen_indicators()
self.draw_text(events)
self.editor.fps_counter.draw(self.editor.screen)
pygame.display.flip()
def draw_connections(self):
for connection in self.editor.connections:
connection.draw(
self.editor.screen,
self.editor.panning_state.offset_x,
self.editor.panning_state.offset_y,
zoom=self.editor.zoom
)
def draw_nodes(self):
# Nodes
for node in self.editor.nodes:
node.draw(
self.editor.screen,
self.editor.panning_state.offset_x,
self.editor.panning_state.offset_y,
zoom=self.editor.zoom
)
def draw_toolbar(self):
self.editor.toolbar.draw(self.editor.screen)
def draw_offscreen_indicators(self):
screen_w = self.editor.screen.get_width()
screen_h = self.editor.screen.get_height()
color = (160, 160, 160)
margin = 0
r_size = 16 # size of the indicator rect
toolbar_width = self.editor.toolbar.width
def is_node_visible(screen_x, screen_y):
return (
toolbar_width + margin < screen_x < screen_w - margin and
margin < screen_y < screen_h - margin
)
def get_screen_coords(node):
return (
(node.x * self.editor.zoom) - self.editor.panning_state.offset_x * self.editor.zoom,
(node.y * self.editor.zoom) - self.editor.panning_state.offset_y * self.editor.zoom,
)
center_x = toolbar_width + (screen_w - toolbar_width) // 2
center_y = screen_h // 2
for node in self.editor.nodes:
# Convert world coordinates to screen coordinates
screen_x, screen_y = get_screen_coords(node)
if is_node_visible(screen_x, screen_y):
continue
dx = screen_x - center_x
dy = screen_y - center_y
# Normalize direction to the edge of the window
if dx == 0 and dy == 0:
continue # should not happen, but just in case
angle = math.atan2(dy, dx)
# Determine intersection with window edge
if abs(dx) > abs(dy * (screen_w / screen_h)):
# Left/Right edge
edge_x = screen_w - margin if dx > 0 else toolbar_width + margin
edge_y = center_y + (edge_x - center_x) * math.tan(angle)
# Top/Bottom
else:
# Top/Bottom edge
edge_y = screen_h - margin if dy > 0 else margin
edge_x = center_x + (edge_y - center_y) / math.tan(angle)
# Draw indicator rect at edge
rect_x = int(edge_x - r_size // 2)
rect_y = int(edge_y - r_size // 2)
rect = pygame.Rect(rect_x, rect_y, r_size, r_size)
pygame.draw.rect(
self.editor.screen,
color,
rect,
width=1,
border_radius=3
)
def draw_text(self, events):
if self.editor.text_input_active:
self.editor.visualizer.overlay_enabled = True
self.editor.visualizer.render_with_overlay(self.editor.screen, events)
if self.editor.visualizer.should_block_mouse():
pass
else:
self.editor.visualizer.overlay_enabled = False
# Optional: falls du das Textfeld auch ohne Overlay anzeigen willst
# self.visualizer.update(events)
# self.screen.blit(self.visualizer.surface, (200, 200))