Download CommonLua/Ged/GedGraphEditor.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 21.5 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Ged/GedGraphEditor.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/Ged/GedGraphEditor.lua
-
curl -L -o GedGraphEditor.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Ged/GedGraphEditor.lua
21.5 kB
| -- TODO: | |
| -- 1. Add scrollbars to GraphEditorPanel | |
| -- 2. Undo support | |
| -- 3. Support multiple split points, serialize them | |
| local SocketLinkOffset = point(10, 0) | |
| local LinkMouseHoverDist = 7 | |
| local LinkThickness = 8 | |
| local SplineSampleStep = 10 | |
| local NodeSelectedColor = RGB(248, 220, 120) | |
| local GraphSocketColors = { | |
| number = RGB(205, 0, 205), | |
| string = RGB(0, 150, 100), | |
| boolean = RGB(0, 100, 0), | |
| any = RGB(240, 240, 240), | |
| } | |
| DefineClass.XGraphEditor = { | |
| __parents = { "XMap" }, | |
| drag_start_socket = false, | |
| drag_end_socket = false, | |
| drag_end_pt = false, | |
| last_node_pt = false, | |
| menu = false, | |
| links = false, | |
| read_only = false, | |
| selected_node = false, | |
| UseCustomTime = false, | |
| NodeClassItems = false, -- set to a table with { EditorName = ..., Class = ... } items for each node class | |
| OnGraphEdited = empty_func, | |
| OnNodeSelected = empty_func, | |
| } | |
| function XGraphEditor:Init() | |
| self.links = {} | |
| end | |
| function XGraphEditor:SelectNode(node) | |
| if self.selected_node ~= node then | |
| if self.selected_node then | |
| self.selected_node:Select(false) | |
| end | |
| self.selected_node = node | |
| if node then | |
| node:Select(true) | |
| end | |
| end | |
| self:OnNodeSelected(node) | |
| end | |
| function XGraphEditor:GetGraphData() | |
| local data = { links = {} } | |
| local node_to_idx = {} | |
| for idx, node in ipairs(self) do | |
| if IsKindOf(node, "XGraphNode") then | |
| table.insert(data, { x = node.PosX, y = node.PosY, node_class = node.node_class, handle = node.handle }) | |
| node_to_idx[node] = idx | |
| end | |
| end | |
| for _, link in ipairs(self.links) do | |
| local start_sock = link.start_socket | |
| local end_sock = link.end_socket | |
| table.insert(data.links, { | |
| start_node = node_to_idx[start_sock.parent_node], | |
| start_socket = start_sock.socket_id, | |
| end_node = node_to_idx[end_sock.parent_node], | |
| end_socket = end_sock.socket_id, | |
| }) | |
| end | |
| return data | |
| end | |
| function XGraphEditor:SetGraphData(data) | |
| self:DeleteChildren() | |
| for _, data in ipairs(data) do | |
| local node = XGraphNode:new({}, self) | |
| node:SetNodeClass(data.node_class) | |
| node:SetPos(data.x, data.y) | |
| node.handle = data.handle | |
| end | |
| self.links = {} | |
| for _, link in ipairs(data and data.links) do | |
| local start_sock = table.find_value(self[link.start_node].sockets, "socket_id", link.start_socket) | |
| local end_sock = table.find_value(self[link.end_node].sockets, "socket_id", link.end_socket) | |
| if start_sock and end_sock then | |
| self:AddLink(start_sock, end_sock) | |
| end | |
| end | |
| end | |
| function XGraphEditor:SetReadOnly(read_only) | |
| self.read_only = read_only | |
| self:CloseContextMenu() | |
| self:Invalidate() | |
| end | |
| function XGraphEditor:DrawContent() | |
| UIL.DrawSolidRect(box(0, 0, self.map_size:x(), self.map_size:y()), RGB(85, 85, 85)) | |
| local color1 = self.read_only and RGB(115, 115, 115) or RGB(175, 175, 175) | |
| local color2 = self.read_only and RGB( 95, 95, 95) or RGB(125, 125, 125) | |
| for x = 0, self.map_size:x(), 25 do | |
| local thick = x % 125 == 0 | |
| UIL.DrawLineAntialised(thick and 7 or 3, point(x, 0), point(x, self.map_size:y()), thick and color2 or color1) | |
| end | |
| for y = 0, self.map_size:y(), 25 do | |
| local thick = y % 125 == 0 | |
| UIL.DrawLineAntialised(thick and 7 or 3, point(0, y), point(self.map_size:x(), y), thick and color2 or color1) | |
| end | |
| end | |
| local function get_link_spline(start_point, end_point) | |
| local offset = start_point:x() < end_point:x() and SocketLinkOffset or -SocketLinkOffset | |
| local spline_start = start_point + offset | |
| local spline_end = end_point - offset | |
| local the_x = spline_end:x() - spline_start:x() | |
| local vector_end1 = point(spline_start:x() + the_x/4, spline_start:y()) | |
| local vector_end2 = point(spline_end:x() - the_x/4, spline_end:y()) | |
| return { spline_start, vector_end1, vector_end2, spline_end } | |
| end | |
| local function draw_link(start_point, end_point, spline, color) | |
| UIL.DrawLineAntialised(LinkThickness, start_point, spline[1], color) | |
| local spline_length = BS3_GetSplineLength2D(spline) | |
| local last_pos = spline[1] | |
| local i = SplineSampleStep | |
| while i < spline_length do | |
| local next_pos = point(BS3_GetSplinePos2D(spline, i, spline_length)) | |
| UIL.DrawLineAntialised(LinkThickness, last_pos, next_pos, color) | |
| last_pos = next_pos | |
| i = i + SplineSampleStep | |
| end | |
| UIL.DrawLineAntialised(LinkThickness, last_pos, spline[4], color) | |
| UIL.DrawLineAntialised(LinkThickness, spline[4], end_point, color) | |
| end | |
| function XGraphEditor:DrawChildren(clip_box) | |
| XMap.DrawChildren(self, clip_box) | |
| if self.drag_end_pt and self.drag_start_socket then | |
| local start_pos, end_pos = self.drag_start_socket.box:Center(), self.drag_end_pt | |
| local spline = get_link_spline(start_pos, end_pos) | |
| draw_link(start_pos, end_pos, spline, self.drag_start_socket.ImageColor) | |
| end | |
| for _, link in ipairs(self.links) do | |
| link:DrawSpline(self.drag_end_pt) | |
| end | |
| end | |
| function XGraphEditor:CloseContextMenu() | |
| if self.menu then | |
| self.menu:delete() | |
| self.menu = false | |
| end | |
| end | |
| function XGraphEditor:OnMousePos(pt, button) | |
| self.drag_end_pt = self:ScreenToMapPt(pt) | |
| self:Invalidate() -- allow connections to change color depending on mouse position | |
| return XMap.OnMousePos(self, pt, button) | |
| end | |
| function XGraphEditor:OnMouseButtonDown(pt, button) | |
| self:CloseContextMenu() | |
| local pt1 = self:ScreenToMapPt(pt) | |
| if not self.read_only and button == "L" then | |
| if #self.links > 0 then | |
| for _, spline in ipairs(self.links) do | |
| if BS3_GetSplineToPointDist2D(spline.spline1, self.drag_end_pt) <= LinkMouseHoverDist and not spline.split_point then | |
| local split = XGraphEditorSplineSplitPoint:new({ PosX = pt1:x(), PosY = pt1:y() }, self) | |
| split:OnMouseButtonDown(pt, "L") -- start dragging the split point | |
| spline.split_point = split | |
| self:OnGraphEdited() | |
| break | |
| end | |
| end | |
| end | |
| elseif not self.read_only and button == "R" then | |
| -- if there is a link under the mouse, delete it | |
| for idx, spline in ipairs(self.links) do | |
| if BS3_GetSplineToPointDist2D(spline.spline1, self.drag_end_pt) <= LinkMouseHoverDist or | |
| spline.split_point and BS3_GetSplineToPointDist2D(spline.spline2, self.drag_end_pt) <= LinkMouseHoverDist | |
| then | |
| spline:delete() | |
| table.remove(self.links, idx) | |
| self:OnGraphEdited() | |
| return "break" | |
| end | |
| end | |
| -- create context menu | |
| self.menu = XPopupList:new({ | |
| Background = RGB(196, 196, 196), | |
| }, terminal.desktop) | |
| self.menu:SetAnchorType("mouse") | |
| self.menu.Anchor = pt | |
| for _, obj in ipairs(self.NodeClassItems) do | |
| XTextButton:new({ | |
| OnPress = function() | |
| local node = XGraphNode:new({}, self) | |
| node:SetNodeClass(obj.Class) | |
| node:SetPos(pt1:x(), pt1:y()) | |
| node.handle = #self == 1 and 1 or self[#self - 1].handle + 1 | |
| node.OnLayoutComplete = function() | |
| local clip = false | |
| for _, obj in ipairs(node.map) do | |
| if obj ~= node and node.box:Intersect2D(obj.box) ~= const.irOutside then | |
| clip = true | |
| node:Move(node.box:Center(), obj.box:sizex(), 0, 100) | |
| break | |
| end | |
| end | |
| if not clip then | |
| node.last_valid_pt = node:GetPos() | |
| end | |
| node.OnLayoutComplete = nil | |
| end | |
| self:CloseContextMenu() | |
| self:OnGraphEdited() | |
| end, | |
| Text = obj.EditorName, | |
| RolloverBackground = RGB(204, 232, 255), | |
| PressedBackground = RGB(121, 189, 241), | |
| }, self.menu) | |
| end | |
| return "break" | |
| end | |
| return XMap.OnMouseButtonDown(self, pt, button) | |
| end | |
| function XGraphEditor:AddLink(sock1, sock2) | |
| if self:CanConnect(sock1, sock2) then | |
| local link = XGraphLink:new{ start_socket = sock2, end_socket = sock1 } | |
| table.insert(self.links, link) | |
| return link | |
| end | |
| end | |
| function XGraphEditor:RemoveLinks(sock) | |
| for idx = #self.links, 1, -1 do | |
| local spline = self.links[idx] | |
| if spline.end_socket == sock or spline.start_socket == sock then | |
| spline:delete() | |
| table.remove(self.links, idx) | |
| end | |
| end | |
| end | |
| function XGraphEditor:OnLayoutComplete() | |
| self:UpdateLinkSplines() | |
| return XMap.OnLayoutComplete(self) | |
| end | |
| function XGraphEditor:UpdateLinkSplines(sock) | |
| for _, spline in ipairs(self.links) do | |
| if not sock or spline.end_socket == sock or spline.start_socket == sock then | |
| spline:CalcSplinePoints() | |
| end | |
| end | |
| end | |
| function XGraphEditor:CanConnect(sock1, sock2) | |
| local data1, data2 = sock1.link_data, sock2.link_data | |
| return | |
| sock1.parent_node ~= sock2.parent_node and | |
| (data1.type == nil or data2.type == nil or data1.type == data2.type) and | |
| (data1.input == nil or data2.input == nil or data1.input ~= data2.input) | |
| end | |
| function XGraphEditor:IsConnected(sock1, sock2) | |
| for _, spline in ipairs(self.links) do | |
| if spline.start_socket == sock2 and spline.end_socket == sock1 or spline.start_socket == sock1 and spline.end_socket == sock2 then | |
| return true | |
| end | |
| end | |
| end | |
| DefineClass.XGraphNode = { | |
| __parents = { "XMapObject" }, | |
| Background = RGB(196, 196, 196), | |
| BorderColor = NodeSelectedColor, | |
| LayoutMethod = "HList", | |
| node_class = false, | |
| handle = false, -- temporary handle sent from the game to Ged, used to recognize the object when sending the data back | |
| sockets = false, -- array of XGraphSocket | |
| last_valid_pt = false, | |
| diff_x = false, | |
| diff_y = false, | |
| } | |
| function XGraphNode:SetNodeClass(node_class) | |
| self:DeleteChildren() | |
| self.sockets = {} | |
| self.node_class = node_class | |
| local class = g_Classes[node_class] | |
| local title = XText:new({ | |
| Dock = "top", | |
| TextHAlign = "center", | |
| TextStyle = "GedTitle", | |
| UseClipBox = false, | |
| Clip = false, | |
| }, self) | |
| title:SetText(class.EditorName) | |
| local inputW = XWindow:new({ | |
| HAlign = "left", | |
| LayoutMethod = "VList", | |
| UseClipBox = false, | |
| Margins = box(0, 0, 10, 0), | |
| }, self) | |
| local outputW = XWindow:new({ | |
| HAlign = "right", | |
| LayoutMethod = "VList", | |
| UseClipBox = false, | |
| Margins = box(10, 0, 0, 0), | |
| }, self) | |
| -- add input sockets | |
| for _, link_data in ipairs(class.GraphLinkSockets) do | |
| local alignment = link_data.input and "right" or "left" | |
| local socket_parent = link_data.input and inputW or outputW | |
| local inputBlock = XWindow:new({ | |
| HAlign = link_data.input and "left" or "right", | |
| UseClipBox = false, | |
| }, socket_parent) | |
| local sock = XGraphSocket:new({ | |
| HAlign = alignment, | |
| parent_node = self, | |
| link_data = link_data, | |
| }, inputBlock) | |
| local text = XText:new({ | |
| Dock = alignment, | |
| TextHAlign = alignment, | |
| TextStyle = "GedTitle", | |
| UseClipBox = false, | |
| Clip = false, | |
| }, inputBlock) | |
| text:SetText(link_data.name or link_data.id) | |
| table.insert(self.sockets, sock) | |
| end | |
| end | |
| function XGraphNode:Select(selected) | |
| self:SetBorderWidth(selected and 2 or 0) | |
| end | |
| function XGraphNode:OnMouseButtonDown(pt, button) | |
| self.map:CloseContextMenu() | |
| if not self.map.read_only and button == "L" then | |
| terminal.desktop:SetMouseCapture(self) | |
| local pt1 = self.map:ScreenToMapPt(pt) | |
| self.map.last_node_pt = self:GetPos() | |
| self.last_valid_pt = self:GetPos() | |
| self.diff_x = self.PosX - pt1:x() | |
| self.diff_y = self.PosY - pt1:y() | |
| self.map:SelectNode(self) | |
| return "break" | |
| elseif not self.map.read_only and button == "R" then | |
| local map = self.map | |
| map.menu = XPopupList:new({ | |
| Background = RGB(196, 196, 196), | |
| }, terminal.desktop) | |
| map.menu:SetAnchorType("mouse") | |
| map.menu.Anchor = pt | |
| XTextButton:new({ | |
| OnPress = function() | |
| self:DeleteLinks() | |
| self:delete() | |
| map:CloseContextMenu() | |
| map:OnGraphEdited() | |
| end, | |
| Text = "Delete Node", | |
| RolloverBackground = RGB(204, 232, 255), | |
| PressedBackground = RGB(121, 189, 241), | |
| HAlign = "left", | |
| }, self.map.menu) | |
| return "break" | |
| end | |
| end | |
| function XGraphNode:OnMousePos(pt, button) | |
| if terminal.desktop:GetMouseCapture() == self then | |
| if self:IsThreadRunning("ScrollThread") then | |
| if self.map.box:Point2DInside(pt) then | |
| self:DeleteThread("ScrollThread") | |
| end | |
| return "break" | |
| end | |
| local my_pt = self:GetPos() | |
| local pt1 = self.map:ScreenToMapPt(pt) | |
| local my_min = self.map:ScreenToMapPt(point(self.map.box:minx(),self.map.box:miny())) | |
| local my_max = self.map:ScreenToMapPt(point(self.map.box:maxx(),self.map.box:maxy())) | |
| if my_pt:x() > 0 + self.box:sizex()/2 or | |
| my_pt:x() < self.map.box:sizex() - self.box:sizex()/2 or | |
| my_pt:y() > 0 + self.box:sizey()/2 or | |
| my_pt:y() < self.map.box:sizey() - self.box:sizex()/2 | |
| then | |
| if pt1:x() < my_min:x() + self.box:sizex()/2 or | |
| pt1:x() > my_max:x() - self.box:sizex()/2 or | |
| pt1:y() < my_min:y() + self.box:sizey()/2 or | |
| pt1:y() > my_max:y() - self.box:sizey()/2 | |
| then | |
| self:CreateThread("ScrollThread", function() | |
| while true do | |
| self:Move(pt1, self.diff_x, self.diff_y, 100) | |
| Sleep(100) | |
| end | |
| end) | |
| else | |
| self:Move(pt1, self.diff_x, self.diff_y, false) | |
| end | |
| end | |
| local clip = false | |
| for i, obj in ipairs(self.map) do | |
| if obj ~= self and self.box:Intersect2D(obj.box) ~= const.irOutside then | |
| clip = true | |
| break | |
| end | |
| end | |
| if not clip then | |
| self.last_valid_pt = self:GetPos() | |
| end | |
| return "break" | |
| end | |
| end | |
| function XGraphNode:OnMouseButtonUp(pt, button) | |
| if terminal.desktop:GetMouseCapture() == self then | |
| if self:IsThreadRunning("ScrollThread") then | |
| self:DeleteThread("ScrollThread") | |
| else | |
| self:SetPos(self.last_valid_pt:x(), self.last_valid_pt:y()) | |
| end | |
| terminal.desktop:SetMouseCapture(false) | |
| self.map:OnGraphEdited() | |
| return "break" | |
| end | |
| end | |
| function XGraphNode:Move(mouse_pt, dx, dy, scroll) | |
| local my_min = self.map:ScreenToMapPt(point(self.map.box:minx(), self.map.box:miny())) | |
| local my_max = self.map:ScreenToMapPt(point(self.map.box:maxx(), self.map.box:maxy())) | |
| self:SetPos( | |
| Clamp(mouse_pt:x() + dx, self.box:sizex()/2, self.map.map_size:x() - self.box:sizex()/2), | |
| Clamp(mouse_pt:y() + dy, self.box:sizey()/2, self.map.map_size:y() - self.box:sizey()/2), | |
| scroll) | |
| if scroll then | |
| local xd = self.PosX - self.map.last_node_pt:x() | |
| local yd = self.PosY - self.map.last_node_pt:y() | |
| xd = MulDivRound(xd, 1000, self.map.scale:x()) | |
| yd = MulDivRound(yd, 1000, self.map.scale:y()) | |
| self.map:ScrollMap(-xd, -yd, scroll) | |
| end | |
| if mouse_pt:x() > self.map.map_size:x() or mouse_pt:y() > self.map.map_size:y() then | |
| if mouse_pt:x() > self.map.map_size:x() then | |
| self.map.map_size = point(self.map.map_size:x() + 25, self.map.map_size:y()) | |
| end | |
| if mouse_pt:y() > self.map.map_size:y() then | |
| self.map.map_size = point(self.map.map_size:x(), self.map.map_size:y() + 25) | |
| end | |
| end | |
| self.map.last_node_pt = self:GetPos() | |
| for _, sock in ipairs(self.sockets) do | |
| self.map:UpdateLinkSplines(sock) | |
| end | |
| end | |
| function XGraphNode:DeleteLinks() | |
| for _, sock in ipairs(self.sockets) do | |
| self.map:RemoveLinks(sock) | |
| end | |
| end | |
| DefineClass.XGraphSocket = { | |
| __parents = { "XImage" }, | |
| UseClipBox = false, | |
| Image = "CommonAssets/UI/Ged/socket_empty", | |
| ImageScale = point(500, 500), | |
| HandleMouse = true, | |
| link_data = false, -- the data for this socket from the node's GraphLinkSockets table | |
| socket_id = false, -- set to link_data.id | |
| parent_node = false, -- my parent node | |
| connections = 0, -- how many links to this socket | |
| } | |
| function XGraphSocket:Init() | |
| self.socket_id = self.link_data.id | |
| self.ImageColor = GraphSocketColors[self.link_data.type] or GraphSocketColors.any | |
| end | |
| function XGraphSocket:AddConnection() | |
| self.connections = self.connections + 1 | |
| self:SetImage("CommonAssets/UI/Ged/socket_full") | |
| end | |
| function XGraphSocket:RemoveConnection() | |
| self.connections = self.connections - 1 | |
| if self.connections == 0 then | |
| self:SetImage("CommonAssets/UI/Ged/socket_empty") | |
| end | |
| end | |
| function XGraphSocket:OnMouseButtonDown(pt, button) | |
| local map = GetParentOfKind(self, "XMap") | |
| if not map.read_only and button == "L" then | |
| map.drag_start_socket = self | |
| terminal.desktop:SetMouseCapture(self) | |
| return "break" | |
| elseif not map.read_only and button == "R" then | |
| map:RemoveLinks(self) | |
| map:OnGraphEdited() | |
| return "break" | |
| end | |
| end | |
| function XGraphSocket:OnMousePos(pt, button) | |
| if terminal.desktop:GetMouseCapture() == self then | |
| self:SetImage("CommonAssets/UI/Ged/socket_full") | |
| local map = GetParentOfKind(self, "XMap") | |
| local target = map:GetMouseTarget(pt) | |
| if IsKindOf(target, "XGraphSocket") and map:CanConnect(self, target) and target.connections == 0 then | |
| if map.drag_end_socket and map.drag_end_socket ~= target then | |
| map.drag_end_socket:SetImage("CommonAssets/UI/Ged/socket_empty") | |
| end | |
| target:SetImage("CommonAssets/UI/Ged/socket_full") | |
| map.drag_end_socket = target | |
| elseif map.drag_end_socket then | |
| map.drag_end_socket:SetImage("CommonAssets/UI/Ged/socket_empty") | |
| map.drag_end_socket = false | |
| end | |
| map.drag_end_pt = map:ScreenToMapPt(pt) | |
| map:Invalidate() | |
| return "break" | |
| end | |
| end | |
| function XGraphSocket:OnMouseButtonUp(pt, button) | |
| if terminal.desktop:GetMouseCapture() == self then | |
| terminal.desktop:SetMouseCapture(false) | |
| local map = GetParentOfKind(self, "XMap") | |
| local target = map:GetMouseTarget(pt) | |
| if IsKindOf(target, "XGraphSocket") and map:CanConnect(target, self) then | |
| map:AddLink(self, target):CalcSplinePoints() | |
| elseif self.connections == 0 then | |
| self:SetImage("CommonAssets/UI/Ged/socket_empty") | |
| end | |
| map.drag_end_socket = false | |
| map.drag_start_socket = false | |
| map:Invalidate() | |
| map:OnGraphEdited() | |
| return "break" | |
| end | |
| end | |
| function XGraphSocket:OnSetRollover(inside) | |
| if inside or self.connections > 0 then | |
| self:SetImage("CommonAssets/UI/Ged/socket_full") | |
| else | |
| self:SetImage("CommonAssets/UI/Ged/socket_empty") | |
| end | |
| end | |
| DefineClass.XGraphLink = { | |
| __parents = { "InitDone" }, | |
| spline1 = false, -- the spline before the split point | |
| spline2 = false, -- the spline after the split point | |
| start_socket = false, -- a reference to the input socket in the connection | |
| end_socket = false, -- a reference to the output socket in the connection | |
| split_point = false, | |
| } | |
| function XGraphLink:Init() | |
| self.start_socket:AddConnection() | |
| self.end_socket:AddConnection() | |
| end | |
| function XGraphLink:Done() | |
| self.start_socket:RemoveConnection() | |
| self.end_socket:RemoveConnection() | |
| if spline.split_point then | |
| spline.split_point:delete() | |
| end | |
| end | |
| function XGraphLink:CalcSplinePoints() | |
| local start_point = self.start_socket.box:Center() | |
| local end_point = self.end_socket.box:Center() | |
| if self.split_point then | |
| local midpoint = self.split_point.box:Center() | |
| self.spline1 = get_link_spline(start_point, midpoint - SocketLinkOffset) | |
| self.spline2 = get_link_spline(midpoint + SocketLinkOffset, end_point) | |
| else | |
| self.spline1 = get_link_spline(start_point, end_point) | |
| end | |
| end | |
| function XGraphLink:PointInside(mouse_pt) | |
| if self.split_point then | |
| return (BS3_GetSplineToPointDist2D(self.spline1, mouse_pt) <= LinkMouseHoverDist or | |
| BS3_GetSplineToPointDist2D(self.spline2, mouse_pt) <= LinkMouseHoverDist) | |
| else | |
| return BS3_GetSplineToPointDist2D(self.spline1, mouse_pt) <= LinkMouseHoverDist | |
| end | |
| end | |
| function XGraphLink:DrawSpline(mouse_pt) | |
| local color = GraphSocketColors[self.start_socket.link_data.type or self.end_socket.link_data.type or "any"] | |
| if mouse_pt and self:PointInside(mouse_pt) and not terminal.desktop:GetMouseCapture() then | |
| color = InterpolateRGB(color, const.clrWhite, 1, 3) -- highlighted color | |
| end | |
| local start_point = self.start_socket.box:Center() | |
| local end_point = self.end_socket.box:Center() | |
| if not self.split_point then | |
| draw_link(start_point, end_point, self.spline1, color) | |
| else | |
| local split_point = self.split_point.box:Center() | |
| draw_link(start_point, split_point, self.spline1, color) | |
| draw_link(split_point, end_point, self.spline2, color) | |
| end | |
| end | |
| DefineClass.XGraphEditorSplineSplitPoint = { | |
| __parents = { "XMapObject" }, | |
| HandleMouse = true, | |
| MinWidth = 10, | |
| MaxWidth = 10, | |
| MinHeight = 10, | |
| MaxHeight = 10, | |
| } | |
| function XGraphEditorSplineSplitPoint:OnMouseButtonDown(pt, button) | |
| if not self.map.read_only and button == "L" then | |
| terminal.desktop:SetMouseCapture(self) | |
| return "break" | |
| end | |
| end | |
| function XGraphEditorSplineSplitPoint:OnMousePos(pt, button) | |
| if terminal.desktop:GetMouseCapture() == self then | |
| local pt1 = self.map:ScreenToMapPt(pt) | |
| self:SetPos(pt1:x(), pt1:y()) | |
| self.map:Invalidate() | |
| return "break" | |
| end | |
| end | |
| function XGraphEditorSplineSplitPoint:OnMouseButtonUp(pt, button) | |
| if terminal.desktop:GetMouseCapture() == self then | |
| local pt1 = self.map:ScreenToMapPt(pt) | |
| self:SetPos(pt1:x(), pt1:y()) | |
| terminal.desktop:SetMouseCapture(false) | |
| self.map:OnGraphEdited() | |
| return "break" | |
| end | |
| end | |
| -- Classes for testing | |
| DefineClass("TestGraphNode", "PropertyObject") | |
| DefineClass.GraphNodeMath = { | |
| __parents = { "TestGraphNode" }, | |
| properties = { | |
| { id = "Operation", editor = "text", default = "" }, | |
| }, | |
| GraphLinkSockets = { | |
| { id = "input1", name = "A", input = true, type = "number", }, | |
| { id = "input2", name = "B", input = true, type = "number", }, | |
| { id = "output", name = "Output", input = false, type = "number", }, | |
| }, | |
| EditorName = "Math Node", | |
| } | |
| DefineClass.GraphNodeBooleanCheck = { | |
| __parents = { "TestGraphNode" }, | |
| GraphLinkSockets = { | |
| { id = "input1", name = "InfoCheck", input = true, }, | |
| { id = "input2", name = "InfoGot", input = true, }, | |
| { id = "output1", name = "false", input = false, type = "boolean", }, | |
| { id = "output2", name = "true", input = false, type = "boolean", }, | |
| }, | |
| EditorName = "Boolean Node", | |
| } | |
| DefineClass.GraphNodeString = { | |
| __parents = { "TestGraphNode" }, | |
| GraphLinkSockets = { | |
| { id = "input1", name = "word", input = true, type = "string", }, | |
| { id = "input2", name = "another word", input = true, type = "string", }, | |
| { id = "input3", name = "even more word", input = true, type = "string", }, | |
| { id = "input4", name = "many a word", input = true, type = "string", }, | |
| { id = "output", name = "Sentence", input = false, type = "string", }, | |
| }, | |
| EditorName = "String Node", | |
| } | |