Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Gauthier Quesnel
irritator
Commits
60d65a1f
Commit
60d65a1f
authored
Apr 07, 2021
by
Gauthier Quesnel
Browse files
imnodes: bump to v0.4
parent
5dec4126
Changes
4
Hide whitespace changes
Inline
Side-by-side
app/gui/imnodes.cpp
View file @
60d65a1f
...
...
@@ -16,7 +16,7 @@
#include <imgui_internal.h>
// Check minimum ImGui version
#define MINIMUM_COMPATIBLE_IMGUI_VERSION 1
6
40
1
#define MINIMUM_COMPATIBLE_IMGUI_VERSION 1
7
40
0
#if IMGUI_VERSION_NUM < MINIMUM_COMPATIBLE_IMGUI_VERSION
#error \
"Minimum ImGui version requirement not met -- please use a newer version!"
...
...
@@ -128,6 +128,16 @@ struct OptionalIndex
return
m_index
==
rhs
;
}
inline
bool
operator
!=
(
const
OptionalIndex
&
rhs
)
const
{
return
m_index
!=
rhs
.
m_index
;
}
inline
bool
operator
!=
(
const
int
rhs
)
const
{
return
m_index
!=
rhs
;
}
static
const
int
invalid_index
=
-
1
;
private:
...
...
@@ -151,6 +161,7 @@ struct NodeData
{
float
corner_rounding
;
ImVec2
padding
;
float
border_thickness
;
}
layout_style
;
ImVector
<
int
>
pin_indices
;
...
...
@@ -166,6 +177,11 @@ struct NodeData
,
pin_indices
()
,
draggable
(
true
)
{}
~
NodeData
()
{
id
=
INT_MIN
;
}
};
struct
PinData
...
...
@@ -304,10 +320,10 @@ struct StyleElement
,
value
(
value
)
{}
};
}
// namespace
// [SECTION] global struct
// this stores data which only lives for one frame
struct
struct
Context
{
EditorContext
*
default_editor_ctx
;
EditorContext
*
editor_ctx
;
...
...
@@ -317,6 +333,7 @@ struct
ImGuiStorage
node_idx_to_submission_idx
;
ImVector
<
int
>
node_idx_submission_order
;
ImVector
<
int
>
node_indices_overlapping_with_mouse
;
ImVector
<
int
>
occluded_pin_indices
;
// Canvas extents
ImVec2
canvas_origin_screen_space
;
...
...
@@ -361,24 +378,21 @@ struct
bool
left_mouse_clicked
;
bool
left_mouse_released
;
bool
middle
_mouse_clicked
;
bool
alt
_mouse_clicked
;
bool
left_mouse_dragging
;
bool
middle_mouse_dragging
;
}
g
;
bool
alt_mouse_dragging
;
};
Context
*
g
=
NULL
;
namespace
{
EditorContext
&
editor_context_get
()
{
// No editor context was set! Did you forget to call imnodes::Initialize?
assert
(
g
.
editor_ctx
!=
NULL
);
return
*
g
.
editor_ctx
;
}
inline
bool
is_mouse_hovering_near_point
(
const
ImVec2
&
point
,
float
radius
)
{
ImVec2
delta
=
g
.
mouse_pos
-
point
;
return
(
delta
.
x
*
delta
.
x
+
delta
.
y
*
delta
.
y
)
<
(
radius
*
radius
);
assert
(
g
->
editor_ctx
!=
NULL
);
return
*
g
->
editor_ctx
;
}
inline
ImVec2
...
...
@@ -438,7 +452,7 @@ get_containing_rect_for_bezier_curve(const BezierCurve& bezier)
const
ImVec2
max
=
ImVec2
(
ImMax
(
bezier
.
p0
.
x
,
bezier
.
p3
.
x
),
ImMax
(
bezier
.
p0
.
y
,
bezier
.
p3
.
y
));
const
float
hover_distance
=
g
.
style
.
link_hover_distance
;
const
float
hover_distance
=
g
->
style
.
link_hover_distance
;
ImRect
rect
(
min
,
max
);
rect
.
Add
(
bezier
.
p1
);
...
...
@@ -472,26 +486,6 @@ get_link_renderable(ImVec2 start,
return
link_data
;
}
inline
bool
is_mouse_hovering_near_link
(
const
BezierCurve
&
bezier
,
const
int
num_segments
)
{
const
ImVec2
mouse_pos
=
g
.
mouse_pos
;
// First, do a simple bounding box test against the box containing the link
// to see whether calculating the distance to the link is worth doing.
const
ImRect
link_rect
=
get_containing_rect_for_bezier_curve
(
bezier
);
if
(
link_rect
.
Contains
(
mouse_pos
))
{
const
float
distance
=
get_distance_to_cubic_bezier
(
mouse_pos
,
bezier
,
num_segments
);
if
(
distance
<
g
.
style
.
link_hover_distance
)
{
return
true
;
}
}
return
false
;
}
inline
float
eval_implicit_line_eq
(
const
ImVec2
&
p1
,
const
ImVec2
&
p2
,
const
ImVec2
&
p
)
{
...
...
@@ -601,7 +595,7 @@ rectangle_overlaps_link(const ImRect& rectangle,
// link
const
LinkBezierData
link_data
=
get_link_renderable
(
start
,
end
,
start_type
,
g
.
style
.
link_line_segments_per_length
);
start
,
end
,
start_type
,
g
->
style
.
link_line_segments_per_length
);
return
rectangle_overlaps_bezier
(
rectangle
,
link_data
);
}
...
...
@@ -722,9 +716,9 @@ ImDrawListSplitter_swap_channels(ImDrawListSplitter& splitter,
void
draw_list_set
(
ImDrawList
*
window_draw_list
)
{
g
.
canvas_draw_list
=
window_draw_list
;
g
.
node_idx_to_submission_idx
.
Clear
();
g
.
node_idx_submission_order
.
clear
();
g
->
canvas_draw_list
=
window_draw_list
;
g
->
node_idx_to_submission_idx
.
Clear
();
g
->
node_idx_submission_order
.
clear
();
}
// The draw list channels are structured as follows. First we have our base
...
...
@@ -751,10 +745,10 @@ draw_list_set(ImDrawList* window_draw_list)
void
draw_list_add_node
(
const
int
node_idx
)
{
g
.
node_idx_to_submission_idx
.
SetInt
(
static_cast
<
ImGuiID
>
(
node_idx
),
g
.
node_idx_submission_order
.
Size
);
g
.
node_idx_submission_order
.
push_back
(
node_idx
);
ImDrawList_grow_channels
(
g
.
canvas_draw_list
,
2
);
g
->
node_idx_to_submission_idx
.
SetInt
(
static_cast
<
ImGuiID
>
(
node_idx
),
g
->
node_idx_submission_order
.
Size
);
g
->
node_idx_submission_order
.
push_back
(
node_idx
);
ImDrawList_grow_channels
(
g
->
canvas_draw_list
,
2
);
}
void
...
...
@@ -762,7 +756,7 @@ draw_list_append_click_interaction_channel()
{
// NOTE: don't use this function outside of EndNodeEditor. Using this before
// all nodes have been added will screw up the node draw order.
ImDrawList_grow_channels
(
g
.
canvas_draw_list
,
1
);
ImDrawList_grow_channels
(
g
->
canvas_draw_list
,
1
);
}
int
...
...
@@ -782,8 +776,8 @@ draw_list_submission_idx_to_foreground_channel_idx(const int submission_idx)
void
draw_list_activate_click_interaction_channel
()
{
g
.
canvas_draw_list
->
_Splitter
.
SetCurrentChannel
(
g
.
canvas_draw_list
,
g
.
canvas_draw_list
->
_Splitter
.
_Count
-
1
);
g
->
canvas_draw_list
->
_Splitter
.
SetCurrentChannel
(
g
->
canvas_draw_list
,
g
->
canvas_draw_list
->
_Splitter
.
_Count
-
1
);
}
void
...
...
@@ -791,16 +785,16 @@ draw_list_activate_current_node_foreground()
{
const
int
foreground_channel_idx
=
draw_list_submission_idx_to_foreground_channel_idx
(
g
.
node_idx_submission_order
.
Size
-
1
);
g
.
canvas_draw_list
->
_Splitter
.
SetCurrentChannel
(
g
.
canvas_draw_list
,
foreground_channel_idx
);
g
->
node_idx_submission_order
.
Size
-
1
);
g
->
canvas_draw_list
->
_Splitter
.
SetCurrentChannel
(
g
->
canvas_draw_list
,
foreground_channel_idx
);
}
void
draw_list_activate_node_background
(
const
int
node_idx
)
{
const
int
submission_idx
=
g
.
node_idx_to_submission_idx
.
GetInt
(
static_cast
<
ImGuiID
>
(
node_idx
),
-
1
);
g
->
node_idx_to_submission_idx
.
GetInt
(
static_cast
<
ImGuiID
>
(
node_idx
),
-
1
);
// There is a discrepancy in the submitted node count and the rendered node
// count! Did you call one of the following functions
// * EditorContextMoveToNode
...
...
@@ -811,8 +805,8 @@ draw_list_activate_node_background(const int node_idx)
assert
(
submission_idx
!=
-
1
);
const
int
background_channel_idx
=
draw_list_submission_idx_to_background_channel_idx
(
submission_idx
);
g
.
canvas_draw_list
->
_Splitter
.
SetCurrentChannel
(
g
.
canvas_draw_list
,
background_channel_idx
);
g
->
canvas_draw_list
->
_Splitter
.
SetCurrentChannel
(
g
->
canvas_draw_list
,
background_channel_idx
);
}
void
...
...
@@ -829,10 +823,10 @@ draw_list_swap_submission_indices(const int lhs_idx, const int rhs_idx)
const
int
rhs_background_channel_idx
=
draw_list_submission_idx_to_background_channel_idx
(
rhs_idx
);
ImDrawListSplitter_swap_channels
(
g
.
canvas_draw_list
->
_Splitter
,
ImDrawListSplitter_swap_channels
(
g
->
canvas_draw_list
->
_Splitter
,
lhs_background_channel_idx
,
rhs_background_channel_idx
);
ImDrawListSplitter_swap_channels
(
g
.
canvas_draw_list
->
_Splitter
,
ImDrawListSplitter_swap_channels
(
g
->
canvas_draw_list
->
_Splitter
,
lhs_foreground_channel_idx
,
rhs_foreground_channel_idx
);
}
...
...
@@ -840,16 +834,16 @@ draw_list_swap_submission_indices(const int lhs_idx, const int rhs_idx)
void
draw_list_sort_channels_by_depth
(
const
ImVector
<
int
>&
node_idx_depth_order
)
{
if
(
g
.
node_idx_to_submission_idx
.
Data
.
Size
<
2
)
{
if
(
g
->
node_idx_to_submission_idx
.
Data
.
Size
<
2
)
{
return
;
}
assert
(
node_idx_depth_order
.
Size
==
g
.
node_idx_submission_order
.
Size
);
assert
(
node_idx_depth_order
.
Size
==
g
->
node_idx_submission_order
.
Size
);
int
start_idx
=
node_idx_depth_order
.
Size
-
1
;
while
(
node_idx_depth_order
[
start_idx
]
==
g
.
node_idx_submission_order
[
start_idx
])
{
g
->
node_idx_submission_order
[
start_idx
])
{
if
(
--
start_idx
==
0
)
{
// early out if submission order and depth order are the same
return
;
...
...
@@ -864,8 +858,8 @@ draw_list_sort_channels_by_depth(const ImVector<int>& node_idx_depth_order)
// Find the current index of the node_idx in the submission order array
int
submission_idx
=
-
1
;
for
(
int
i
=
0
;
i
<
g
.
node_idx_submission_order
.
Size
;
++
i
)
{
if
(
g
.
node_idx_submission_order
[
i
]
==
node_idx
)
{
for
(
int
i
=
0
;
i
<
g
->
node_idx_submission_order
.
Size
;
++
i
)
{
if
(
g
->
node_idx_submission_order
[
i
]
==
node_idx
)
{
submission_idx
=
i
;
break
;
}
...
...
@@ -878,8 +872,8 @@ draw_list_sort_channels_by_depth(const ImVector<int>& node_idx_depth_order)
for
(
int
j
=
submission_idx
;
j
<
depth_idx
;
++
j
)
{
draw_list_swap_submission_indices
(
j
,
j
+
1
);
ImSwap
(
g
.
node_idx_submission_order
[
j
],
g
.
node_idx_submission_order
[
j
+
1
]);
ImSwap
(
g
->
node_idx_submission_order
[
j
],
g
->
node_idx_submission_order
[
j
+
1
]);
}
}
}
...
...
@@ -903,6 +897,7 @@ object_pool_update(ObjectPool<T>& objects)
if
(
!
objects
.
in_use
[
i
])
{
objects
.
id_map
.
SetInt
(
objects
.
pool
[
i
].
id
,
-
1
);
objects
.
free_list
.
push_back
(
i
);
(
objects
.
pool
.
Data
+
i
)
->~
T
();
}
}
}
...
...
@@ -913,10 +908,14 @@ object_pool_update(ObjectPool<NodeData>& nodes)
{
nodes
.
free_list
.
clear
();
for
(
int
i
=
0
;
i
<
nodes
.
in_use
.
size
();
++
i
)
{
if
(
!
nodes
.
in_use
[
i
])
{
if
(
nodes
.
in_use
[
i
])
{
nodes
.
pool
[
i
].
pin_indices
.
clear
();
}
else
{
const
int
previous_id
=
nodes
.
pool
[
i
].
id
;
const
int
previous_idx
=
nodes
.
id_map
.
GetInt
(
previous_id
,
-
1
);
if
(
previous_idx
!=
-
1
)
{
assert
(
previous_idx
==
i
);
// Remove node idx form depth stack the first time we detect
// that this idx slot is unused
ImVector
<
int
>&
depth_stack
=
...
...
@@ -928,6 +927,7 @@ object_pool_update(ObjectPool<NodeData>& nodes)
nodes
.
id_map
.
SetInt
(
previous_id
,
-
1
);
nodes
.
free_list
.
push_back
(
i
);
(
nodes
.
pool
.
Data
+
i
)
->~
NodeData
();
}
}
}
...
...
@@ -946,18 +946,26 @@ int
object_pool_find_or_create_index
(
ObjectPool
<
T
>&
objects
,
const
int
id
)
{
int
index
=
objects
.
id_map
.
GetInt
(
static_cast
<
ImGuiID
>
(
id
),
-
1
);
// Construct new object
if
(
index
==
-
1
)
{
if
(
objects
.
free_list
.
empty
())
{
index
=
objects
.
pool
.
size
();
objects
.
pool
.
push_back
(
T
(
id
));
objects
.
in_use
.
push_back
(
true
);
IM_ASSERT
(
objects
.
pool
.
size
()
==
objects
.
in_use
.
size
());
const
int
new_size
=
objects
.
pool
.
size
()
+
1
;
objects
.
pool
.
resize
(
new_size
);
objects
.
in_use
.
resize
(
new_size
);
}
else
{
index
=
objects
.
free_list
.
back
();
objects
.
free_list
.
pop_back
();
}
IM_PLACEMENT_NEW
(
objects
.
pool
.
Data
+
index
)
T
(
id
);
objects
.
id_map
.
SetInt
(
static_cast
<
ImGuiID
>
(
id
),
index
);
}
// Flag it as used
objects
.
in_use
[
index
]
=
true
;
return
index
;
}
...
...
@@ -966,20 +974,27 @@ int
object_pool_find_or_create_index
(
ObjectPool
<
NodeData
>&
nodes
,
const
int
node_id
)
{
int
node_idx
=
nodes
.
id_map
.
GetInt
(
static_cast
<
ImGuiID
>
(
node_id
),
-
1
);
// Construct new node
if
(
node_idx
==
-
1
)
{
if
(
nodes
.
free_list
.
empty
())
{
node_idx
=
nodes
.
pool
.
size
();
nodes
.
pool
.
push_back
(
NodeData
(
node_id
));
nodes
.
in_use
.
push_back
(
true
);
IM_ASSERT
(
nodes
.
pool
.
size
()
==
nodes
.
in_use
.
size
());
const
int
new_size
=
nodes
.
pool
.
size
()
+
1
;
nodes
.
pool
.
resize
(
new_size
);
nodes
.
in_use
.
resize
(
new_size
);
}
else
{
node_idx
=
nodes
.
free_list
.
back
();
nodes
.
free_list
.
pop_back
();
}
IM_PLACEMENT_NEW
(
nodes
.
pool
.
Data
+
node_idx
)
NodeData
(
node_id
);
nodes
.
id_map
.
SetInt
(
static_cast
<
ImGuiID
>
(
node_id
),
node_idx
);
EditorContext
&
editor
=
editor_context_get
();
editor
.
node_depth_order
.
push_back
(
node_idx
);
}
// Flag node as used
nodes
.
in_use
[
node_idx
]
=
true
;
return
node_idx
;
...
...
@@ -1002,8 +1017,8 @@ get_screen_space_pin_coordinates(const ImRect& node_rect,
{
assert
(
type
==
AttributeType_Input
||
type
==
AttributeType_Output
);
const
float
x
=
type
==
AttributeType_Input
?
(
node_rect
.
Min
.
x
-
g
.
style
.
pin_offset
)
:
(
node_rect
.
Max
.
x
+
g
.
style
.
pin_offset
);
?
(
node_rect
.
Min
.
x
-
g
->
style
.
pin_offset
)
:
(
node_rect
.
Max
.
x
+
g
->
style
.
pin_offset
);
return
ImVec2
(
x
,
0.5
f
*
(
attribute_rect
.
Min
.
y
+
attribute_rect
.
Max
.
y
));
}
...
...
@@ -1017,11 +1032,17 @@ get_screen_space_pin_coordinates(const EditorContext& editor,
parent_node_rect
,
pin
.
attribute_rect
,
pin
.
type
);
}
// These functions are here, and not members of the BoxSelector struct, because
// implementing a C API in C++ is frustrating. EditorContext has a BoxSelector
// field, but the state changes depend on the editor. So, these are implemented
// as C-style free functions so that the code is not too much of a mish-mash of
// C functions and C++ method definitions.
bool
mouse_in_canvas
()
{
// This flag should be true either when hovering or clicking something in
// the canvas.
const
bool
is_window_hovered_or_focused
=
ImGui
::
IsWindowHovered
()
||
ImGui
::
IsWindowFocused
();
return
is_window_hovered_or_focused
&&
g
->
canvas_rect_screen_space
.
Contains
(
ImGui
::
GetMousePos
());
}
void
begin_node_selection
(
EditorContext
&
editor
,
const
int
node_idx
)
...
...
@@ -1075,7 +1096,7 @@ begin_link_detach(EditorContext& editor,
state
.
link_creation
.
start_pin_idx
=
detach_pin_idx
==
link
.
start_pin_idx
?
link
.
end_pin_idx
:
link
.
start_pin_idx
;
g
.
deleted_link_idx
=
link_idx
;
g
->
deleted_link_idx
=
link_idx
;
}
void
...
...
@@ -1084,9 +1105,9 @@ begin_link_interaction(EditorContext& editor, const int link_idx)
// First check if we are clicking a link in the vicinity of a pin.
// This may result in a link detach via click and drag.
if
(
editor
.
click_interaction_type
==
ClickInteractionType_LinkCreation
)
{
if
((
g
.
hovered_pin_flags
&
if
((
g
->
hovered_pin_flags
&
AttributeFlags_EnableLinkDetachWithDragClick
)
!=
0
)
{
begin_link_detach
(
editor
,
link_idx
,
g
.
hovered_pin_idx
.
value
());
begin_link_detach
(
editor
,
link_idx
,
g
->
hovered_pin_idx
.
value
());
editor
.
click_interaction_state
.
link_creation
.
link_creation_type
=
LinkCreationType_FromDetach
;
}
...
...
@@ -1095,15 +1116,15 @@ begin_link_interaction(EditorContext& editor, const int link_idx)
// modifier pressed. This may also result in a link detach via clicking.
else
{
const
bool
modifier_pressed
=
g
.
io
.
link_detach_with_modifier_click
.
modifier
==
NULL
g
->
io
.
link_detach_with_modifier_click
.
modifier
==
NULL
?
false
:
*
g
.
io
.
link_detach_with_modifier_click
.
modifier
;
:
*
g
->
io
.
link_detach_with_modifier_click
.
modifier
;
if
(
modifier_pressed
)
{
const
LinkData
&
link
=
editor
.
links
.
pool
[
link_idx
];
const
PinData
&
start_pin
=
editor
.
pins
.
pool
[
link
.
start_pin_idx
];
const
PinData
&
end_pin
=
editor
.
pins
.
pool
[
link
.
end_pin_idx
];
const
ImVec2
&
mouse_pos
=
g
.
mouse_pos
;
const
ImVec2
&
mouse_pos
=
g
->
mouse_pos
;
const
float
dist_to_start
=
ImLengthSqr
(
start_pin
.
pos
-
mouse_pos
);
const
float
dist_to_end
=
ImLengthSqr
(
end_pin
.
pos
-
mouse_pos
);
const
int
closest_pin_idx
=
dist_to_start
<
dist_to_end
...
...
@@ -1112,6 +1133,8 @@ begin_link_interaction(EditorContext& editor, const int link_idx)
editor
.
click_interaction_type
=
ClickInteractionType_LinkCreation
;
begin_link_detach
(
editor
,
link_idx
,
closest_pin_idx
);
editor
.
click_interaction_state
.
link_creation
.
link_creation_type
=
LinkCreationType_FromDetach
;
}
else
{
begin_link_selection
(
editor
,
link_idx
);
}
...
...
@@ -1127,35 +1150,30 @@ begin_link_creation(EditorContext& editor, const int hovered_pin_idx)
editor
.
click_interaction_state
.
link_creation
.
end_pin_idx
.
reset
();
editor
.
click_interaction_state
.
link_creation
.
link_creation_type
=
LinkCreationType_Standard
;
g
.
element_state_change
|=
ElementStateChange_LinkStarted
;
g
->
element_state_change
|=
ElementStateChange_LinkStarted
;
}
void
begin_canvas_interaction
(
EditorContext
&
editor
)
{
const
bool
any_ui_element_hovered
=
g
.
hovered_node_idx
.
has_value
()
||
g
.
hovered_link_idx
.
has_value
()
||
g
.
hovered_pin_idx
.
has_value
()
||
ImGui
::
IsAnyItemHovered
();
g
->
hovered_node_idx
.
has_value
()
||
g
->
hovered_link_idx
.
has_value
()
||
g
->
hovered_pin_idx
.
has_value
()
||
ImGui
::
IsAnyItemHovered
();
const
bool
mouse_not_in_canvas
=
!
(
g
.
canvas_rect_screen_space
.
Contains
(
ImGui
::
GetMousePos
())
&&
ImGui
::
IsWindowHovered
());
const
bool
mouse_not_in_canvas
=
!
mouse_in_canvas
();
if
(
any_ui_element_hovered
||
mouse_not_in_canvas
)
{
if
(
editor
.
click_interaction_type
!=
ClickInteractionType_None
||
any_ui_element_hovered
||
mouse_not_in_canvas
)
{
return
;
}
const
bool
started_panning
=
g
.
io
.
emulate_three_button_mouse
.
enabled
?
(
g
.
left_mouse_clicked
&&
*
g
.
io
.
emulate_three_button_mouse
.
modifier
)
:
g
.
middle_mouse_clicked
;
const
bool
started_panning
=
g
->
alt_mouse_clicked
;
editor
.
click_interaction_type
=
started_panning
?
ClickInteractionType_Panning
:
ClickInteractionType_BoxSelection
;
if
(
editor
.
click_interaction_type
==
ClickInteractionType_BoxSelection
)
{
editor
.
click_interaction_state
.
box_selector
.
rect
.
Min
=
g
.
mouse_pos
;
if
(
started_panning
)
{
editor
.
click_interaction_type
=
ClickInteractionType_Panning
;
}
else
if
(
g
->
left_mouse_clicked
)
{
editor
.
click_interaction_type
=
ClickInteractionType_BoxSelection
;
editor
.
click_interaction_state
.
box_selector
.
rect
.
Min
=
g
->
mouse_pos
;
}
}
...
...
@@ -1220,7 +1238,7 @@ box_selector_update_selection(EditorContext& editor, ImRect box_rect)
void
translate_selected_nodes
(
EditorContext
&
editor
)
{
if
(
g
.
left_mouse_dragging
)
{
if
(
g
->
left_mouse_dragging
)
{
const
ImGuiIO
&
io
=
ImGui
::
GetIO
();
for
(
int
i
=
0
;
i
<
editor
.
selected_node_indices
.
size
();
++
i
)
{
const
int
node_idx
=
editor
.
selected_node_indices
[
i
];
...
...
@@ -1271,7 +1289,7 @@ should_link_snap_to_pin(const EditorContext& editor,
// The link to be created must not be a duplicate, unless it is the link
// which was created on snap. In that case we want to snap, since we want it
// to appear visually as if the created link remains snapped to the pin.
if
(
duplicate_link
.
has_value
()
&&
!
(
duplicate_link
==
g
.
snap_link_idx
))
{
if
(
duplicate_link
.
has_value
()
&&
!
(
duplicate_link
==
g
->
snap_link_idx
))
{
return
false
;
}
...
...
@@ -1284,19 +1302,20 @@ click_interaction_update(EditorContext& editor)
switch
(
editor
.
click_interaction_type
)
{
case
ClickInteractionType_BoxSelection
:
{
ImRect
&
box_rect
=
editor
.
click_interaction_state
.
box_selector
.
rect
;
box_rect
.
Max
=
g
.
mouse_pos
;
box_rect
.
Max
=
g
->
mouse_pos
;
box_selector_update_selection
(
editor
,
box_rect
);
const
ImU32
box_selector_color
=
g
.
style
.
colors
[
ColorStyle_BoxSelector
];
const
ImU32
box_selector_color
=
g
->
style
.
colors
[
ColorStyle_BoxSelector
];
const
ImU32
box_selector_outline
=
g
.
style
.
colors
[
ColorStyle_BoxSelectorOutline
];
g
.
canvas_draw_list
->
AddRectFilled
(
g
->
style
.
colors
[
ColorStyle_BoxSelectorOutline
];
g
->
canvas_draw_list
->
AddRectFilled
(
box_rect
.
Min
,
box_rect
.
Max
,
box_selector_color
);
g
.
canvas_draw_list
->
AddRect
(
g
->
canvas_draw_list
->
AddRect
(
box_rect
.
Min
,
box_rect
.
Max
,
box_selector_outline
);
if
(
g
.
left_mouse_released
)
{
if
(
g
->
left_mouse_released
)
{
ImVector
<
int
>&
depth_stack
=
editor
.
node_depth_order
;
const
ImVector
<
int
>&
selected_idxs
=
editor
.
selected_node_indices
;
...
...
@@ -1332,12 +1351,12 @@ click_interaction_update(EditorContext& editor)
case
ClickInteractionType_Node
:
{
translate_selected_nodes
(
editor
);
if
(
g
.
left_mouse_released
)
{
if
(
g
->
left_mouse_released
)
{
editor
.
click_interaction_type
=
ClickInteractionType_None
;
}
}
break
;
case
ClickInteractionType_Link
:
{
if
(
g
.
left_mouse_released
)
{
if
(
g
->
left_mouse_released
)
{
editor
.
click_interaction_type
=
ClickInteractionType_None
;
}
}
break
;
...
...
@@ -1347,18 +1366,18 @@ click_interaction_update(EditorContext& editor)
.
pool
[
editor
.
click_interaction_state
.
link_creation
.
start_pin_idx
];
const
OptionalIndex
maybe_duplicate_link_idx
=
g
.
hovered_pin_idx
.
has_value
()
g
->
hovered_pin_idx
.
has_value
()
?
find_duplicate_link
(
editor
,
editor
.
click_interaction_state
.
link_creation
.
start_pin_idx
,
g
.
hovered_pin_idx
.
value
())
g
->
hovered_pin_idx
.
value
())
:
OptionalIndex
();
const
bool
should_snap
=
g
.
hovered_pin_idx
.
has_value
()
&&
g
->
hovered_pin_idx
.
has_value
()
&&
should_link_snap_to_pin
(
editor
,
start_pin
,
g
.
hovered_pin_idx
.
value
(),
g
->
hovered_pin_idx
.
value
(),
maybe_duplicate_link_idx
);
// If we created on snap and the hovered pin is empty or changed, then
...
...
@@ -1366,15 +1385,15 @@ click_interaction_update(EditorContext& editor)
const
bool
snapping_pin_changed
=
editor
.
click_interaction_state
.
link_creation
.
end_pin_idx
.
has_value
()
&&
!
(
g
.
hovered_pin_idx
==
!
(
g
->
hovered_pin_idx
==
editor
.
click_interaction_state
.
link_creation
.
end_pin_idx
);
// Detach the link that was created by this link event if it's no longer
// in snap range
if
(
snapping_pin_changed
&&
g
.
snap_link_idx
.
has_value
())
{
if
(
snapping_pin_changed
&&
g
->
snap_link_idx
.
has_value
())
{
begin_link_detach
(
editor
,
g
.
snap_link_idx
.
value
(),
g
->
snap_link_idx
.
value
(),
editor
.
click_interaction_state
.
link_creation
.
end_pin_idx
.
value
());
}
...
...
@@ -1384,25 +1403,30 @@ click_interaction_update(EditorContext& editor)
// endpoint to it
const
ImVec2
end_pos
=
should_snap
?
get_screen_space_pin_coordinates
(
editor
,
editor
.
pins
.
pool
[
g
.
hovered_pin_idx
.
value
()])
:
g
.
mouse_pos
;
editor
,
editor
.
pins
.
pool
[
g
->
hovered_pin_idx
.
value
()])
:
g
->
mouse_pos
;
const
LinkBezierData
link_data
=
get_link_renderable
(
start_pos
,
end_pos
,
start_pin
.
type
,
g
.
style
.
link_line_segments_per_length
);
g
.
canvas_draw_list
->
AddBezierCurve
(
link_data
.
bezier
.
p0
,
link_data
.
bezier
.
p1
,
link_data
.
bezier
.
p2
,
link_data
.
bezier
.
p3
,
g
.
style
.
colors
[
ColorStyle_Link
],
g
.
style
.
link_thickness
,
link_data
.
num_segments
);
g
->
style
.
link_line_segments_per_length
);
#if IMGUI_VERSION_NUM < 18000
g
->
canvas_draw_list
->
AddBezierCurve
(
#else
g
->
canvas_draw_list
->
AddBezierCubic
(
#endif
link_data
.
bezier
.
p0
,
link_data
.
bezier
.
p1
,
link_data
.
bezier
.
p2
,
link_data
.
bezier
.
p3
,
g
->
style
.
colors
[
ColorStyle_Link
],
g
->
style
.
link_thickness
,
link_data
.
num_segments
);