generated from mstar/godot-template
103 lines
3.9 KiB
GDScript
103 lines
3.9 KiB
GDScript
# Position Popup near to its target while within window, solution from ColorPickerButton source code(https://github.com/godotengine/godot/blob/6d8c14f849376905e1577f9fc3f9512bcffb1e3c/scene/gui/color_picker.cpp#L878)
|
|
static func popup_on_target(popup: Popup, target: Control):
|
|
popup.reset_size()
|
|
var usable_rect = Rect2(Vector2.ZERO, DisplayServer.window_get_size_with_decorations())
|
|
var cp_rect = Rect2(Vector2.ZERO, popup.get_size())
|
|
for i in 4:
|
|
if i > 1:
|
|
cp_rect.position.y = target.global_position.y - cp_rect.size.y
|
|
else:
|
|
cp_rect.position.y = target.global_position.y + target.get_size().y
|
|
|
|
if i & 1:
|
|
cp_rect.position.x = target.global_position.x
|
|
else:
|
|
cp_rect.position.x = target.global_position.x - max(0, cp_rect.size.x - target.get_size().x)
|
|
|
|
if usable_rect.encloses(cp_rect):
|
|
break
|
|
var main_window_position = DisplayServer.window_get_position()
|
|
var popup_position = main_window_position + Vector2i(cp_rect.position) # make it work in multi-screen setups
|
|
popup.set_position(popup_position)
|
|
popup.popup()
|
|
|
|
static func get_complementary_color(color):
|
|
var r = max(color.r, max(color.b, color.g)) + min(color.r, min(color.b, color.g)) - color.r
|
|
var g = max(color.r, max(color.b, color.g)) + min(color.r, min(color.b, color.g)) - color.g
|
|
var b = max(color.r, max(color.b, color.g)) + min(color.r, min(color.b, color.g)) - color.b
|
|
return Color(r, g, b)
|
|
|
|
class CohenSutherland:
|
|
const INSIDE = 0 # 0000
|
|
const LEFT = 1 # 0001
|
|
const RIGHT = 2 # 0010
|
|
const BOTTOM = 4 # 0100
|
|
const TOP = 8 # 1000
|
|
|
|
# Compute bit code for a point(x, y) using the clip
|
|
static func compute_code(x, y, x_min, y_min, x_max, y_max):
|
|
var code = INSIDE # initialised as being inside of clip window
|
|
if x < x_min: # to the left of clip window
|
|
code |= LEFT
|
|
elif x > x_max: # to the right of clip window
|
|
code |= RIGHT
|
|
|
|
if y < y_min: # below the clip window
|
|
code |= BOTTOM
|
|
elif y > y_max: # above the clip window
|
|
code |= TOP
|
|
|
|
return code
|
|
|
|
# Cohen-Sutherland clipping algorithm clips a line from
|
|
# P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
|
|
# diagonal from start(x_min, y_min) to end(x_max, y_max)
|
|
static func line_intersect_rectangle(from, to, rect):
|
|
var x_min = rect.position.x
|
|
var y_min = rect.position.y
|
|
var x_max = rect.end.x
|
|
var y_max = rect.end.y
|
|
|
|
var code0 = compute_code(from.x, from.y, x_min, y_min, x_max, y_max)
|
|
var code1 = compute_code(to.x, to.y, x_min, y_min, x_max, y_max)
|
|
|
|
var i = 0
|
|
while true:
|
|
i += 1
|
|
if !(code0 | code1): # bitwise OR 0, both points inside window
|
|
return true
|
|
elif code0 & code1: # Bitwise AND not 0, both points share an outside zone
|
|
return false
|
|
else:
|
|
# Failed both test, so calculate line segment to clip
|
|
# from outside point to intersection with clip edge
|
|
var x
|
|
var y
|
|
var code_out = max(code0, code1) # Pick the one outside window
|
|
|
|
# Find intersection points
|
|
# slope = (y1 - y0) / (x1 - x0)
|
|
# x = x0 + (1 / slope) * (ym - y0), where ym is y_mix/y_max
|
|
# y = y0 + slope * (xm - x0), where xm is x_min/x_max
|
|
if code_out & TOP: # Point above clip window
|
|
x = from.x + (to.x - from.x) * (y_max - from.y) / (to.y - from.y)
|
|
y = y_max
|
|
elif code_out & BOTTOM: # Point below clip window
|
|
x = from.x + (to.x - from.x) * (y_min - from.y) / (to.y - from.y)
|
|
y = y_min
|
|
elif code_out & RIGHT: # Point is to the right of clip window
|
|
y = from.y + (to.y - from.y) * (x_max - from.x) / (to.x - from.x)
|
|
x = x_max
|
|
elif code_out & LEFT: # Point is to the left of clip window
|
|
y = from.y + (to.y - from.y) * (x_min - from.x) / (to.x - from.x)
|
|
x = x_min
|
|
|
|
# Now move outside point to intersection point to clip and ready for next pass
|
|
if code_out == code0:
|
|
from.x = x
|
|
from.y = y
|
|
code0 = compute_code(from.x, from.y, x_min, y_min, x_max, y_max)
|
|
else:
|
|
to.x = x
|
|
to.y = y
|
|
code1 = compute_code(to.x ,to.y, x_min, y_min, x_max, y_max)
|