6#include <wx/dcbuffer.h>
23 : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL | wxVSCROLL | wxTAB_TRAVERSAL),
24 behavior_tree_(tree), layout_algorithm_(LayoutAlgorithm::Vertical), interaction_mode_(InteractionMode::View),
25 zoom_level_(1.0), view_offset_(0, 0), tree_size_(800, 600), node_render_style_(
NodeWidget::RenderStyle::Normal),
26 zoom_step_(0.1), mouse_wheel_sensitivity_(1.0), pan_sensitivity_(1.0), zoom_follows_cursor_(true),
27 background_color_(wxColour(250, 250, 250)), grid_color_(wxColour(200, 200, 200)),
28 connection_color_(wxColour(100, 100, 100)), connection_width_(2), grid_visible_(true), connections_visible_(true),
29 is_dragging_(false), is_selecting_(false), node_spacing_x_(DEFAULT_NODE_SPACING_X),
30 node_spacing_y_(DEFAULT_NODE_SPACING_Y), level_spacing_(DEFAULT_LEVEL_SPACING), tree_root_position_(50, 50),
31 animation_timer_(
nullptr) {
108 wxSize size = pair.second->GetSize();
109 wxRect nodeRect(pos, size);
112 boundingBox = nodeRect;
115 boundingBox = boundingBox.Union(nodeRect);
119 if (!boundingBox.IsEmpty()) {
121 boundingBox.Inflate(50);
135 SetCursor(wxCursor(wxCURSOR_CROSS));
138 SetCursor(wxCursor(wxCURSOR_HAND));
141 SetCursor(wxCursor(wxCURSOR_ARROW));
149 return it->second.get();
155 std::vector<NodeWidget *> widgets;
157 widgets.push_back(pair.second.get());
163 std::vector<EmberForge::NodeWidget *> widgets;
167 widgets.push_back(widget);
177 if (!add_to_selection) {
233 wxSize clientSize = GetClientSize();
236 if (contentSize.x > 0 && contentSize.y > 0) {
237 double zoomX =
static_cast<double>(clientSize.x) / contentSize.x;
238 double zoomY =
static_cast<double>(clientSize.y) / contentSize.y;
239 double newZoom = std::min(zoomX, zoomY) * 0.9;
258 wxRect nodeRect = widget->GetRect();
260 boundingBox = nodeRect;
263 boundingBox = boundingBox.Union(nodeRect);
268 if (!boundingBox.IsEmpty()) {
269 wxSize clientSize = GetClientSize();
270 double zoomX =
static_cast<double>(clientSize.x) / boundingBox.width;
271 double zoomY =
static_cast<double>(clientSize.y) / boundingBox.height;
272 double newZoom = std::min(zoomX, zoomY) * 0.8;
277 wxPoint center(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
278 view_offset_ = center - wxPoint(clientSize.x / 2, clientSize.y / 2);
295 wxRect nodeRect = widget->GetRect();
296 wxPoint nodeCenter(nodeRect.x + nodeRect.width / 2, nodeRect.y + nodeRect.height / 2);
297 wxSize clientSize = GetClientSize();
298 view_offset_ = nodeCenter - wxPoint(clientSize.x / 2, clientSize.y / 2);
311 wxSize clientSize = GetClientSize();
314 view_offset_ = wxPoint((contentSize.x - clientSize.x) / 2, (contentSize.y - clientSize.y) / 2);
406 pair.second->SetRenderStyle(style);
444 bool highlighted = std::find(path.begin(), path.end(), pair.first) != path.end();
445 pair.second->SetHighlighted(highlighted);
455 pair.second->SetHighlighted(
false);
472 wxSize exportSize = size.IsFullySpecified() ? size : GetSize();
473 wxBitmap bitmap(exportSize);
474 wxMemoryDC dc(bitmap);
487 wxAutoBufferedPaintDC dc(
this);
526 bool addToSelection =
event.ControlDown();
528 if (!addToSelection ||
537 if (!event.ControlDown()) {
561 wxRect nodeRect = pair.second->GetRect();
562 if (selectionRect.Intersects(nodeRect)) {
585 if (event.ControlDown()) {
591 wxPoint mousePos =
event.GetPosition();
592 wxPoint scrollPos = GetViewStart();
593 int pixelsPerUnitX, pixelsPerUnitY;
594 GetScrollPixelsPerUnit(&pixelsPerUnitX, &pixelsPerUnitY);
597 double worldX = (mousePos.x + scrollPos.x * pixelsPerUnitX) /
zoom_level_;
598 double worldY = (mousePos.y + scrollPos.y * pixelsPerUnitY) /
zoom_level_;
605 int newScrollX =
static_cast<int>((worldX *
zoom_level_ - mousePos.x) / pixelsPerUnitX);
606 int newScrollY =
static_cast<int>((worldY *
zoom_level_ - mousePos.y) / pixelsPerUnitY);
607 Scroll(newScrollX, newScrollY);
622 switch (event.GetKeyCode()) {
677 if (!children.empty()) {
680 int startX = x - totalWidth / 2;
682 for (
size_t i = 0; i < children.size(); ++i) {
691 wxRect clientRect = GetClientRect();
694 dc.DrawRectangle(clientRect);
698 wxRect clientRect = GetClientRect();
703 wxColour gridBgColor(mainPanelSettings.gridBackgroundColor.r, mainPanelSettings.gridBackgroundColor.g,
704 mainPanelSettings.gridBackgroundColor.b);
707 dc.SetBrush(wxBrush(gridBgColor));
708 dc.SetPen(*wxTRANSPARENT_PEN);
709 dc.DrawRectangle(clientRect);
713 dc.SetBrush(*wxTRANSPARENT_BRUSH);
716 for (
int x = 0; x < clientRect.width; x +=
GRID_SIZE) {
717 dc.DrawLine(x, 0, x, clientRect.height);
721 for (
int y = 0; y < clientRect.height; y +=
GRID_SIZE) {
722 dc.DrawLine(0, y, clientRect.width, y);
747 if (!parent || !child)
750 wxRect parentRect = parent->GetRect();
751 wxRect childRect = child->GetRect();
752 wxPoint parentCenter(parentRect.x + parentRect.width / 2, parentRect.y + parentRect.height / 2);
753 wxPoint childCenter(childRect.x + childRect.width / 2, childRect.y + childRect.height / 2);
756 dc.DrawLine(parentCenter, childCenter);
761 dc.SetPen(wxPen(wxColour(0, 0, 255), 1, wxPENSTYLE_DOT));
762 dc.SetBrush(wxBrush(wxColour(0, 0, 255, 50)));
772 std::vector<EmberCore::Node *> allNodes =
behavior_tree_->GetAllNodes();
783 pair.second->UpdateFromNode();
798 widget->SetNodeDoubleClickCallback(
803 widget->SetNodeEditCallback([
this](
NodeWidget *w,
const wxString &newName) {
OnNodeEdited(w, newName); });
811 if (pair.second->GetRect().Contains(point)) {
812 return pair.second.get();
827 pair.second->SetSelected(selected);
846 return wxPoint(0, 0);
863 widget->SetPosition(pos);
864 widget->SetSize(size);
871 virtualSize.x =
static_cast<int>(virtualSize.x *
zoom_level_);
872 virtualSize.y =
static_cast<int>(virtualSize.y *
zoom_level_);
874 SetVirtualSize(virtualSize);
875 SetScrollRate(20, 20);
880 wxPoint screenPoint = tree_point;
887 wxPoint treePoint = screen_point;
895 wxPoint bottomRight =
TreeToScreen(tree_rect.GetBottomRight());
896 return wxRect(topLeft, bottomRight);
900 wxPoint topLeft =
ScreenToTree(screen_rect.GetTopLeft());
901 wxPoint bottomRight =
ScreenToTree(screen_rect.GetBottomRight());
902 return wxRect(topLeft, bottomRight);
907 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
923 menu.Append(wxID_ANY,
"Delete Selected",
"Delete selected nodes");
924 menu.Append(wxID_ANY,
"Duplicate Selected",
"Duplicate selected nodes");
925 menu.AppendSeparator();
928 menu.Append(wxID_ANY,
"Add Node",
"Add a new node");
929 menu.AppendSeparator();
930 menu.Append(wxID_ANY,
"Zoom to Fit",
"Zoom to fit all nodes");
931 menu.Append(wxID_ANY,
"Reset Zoom",
"Reset zoom to 100%");
933 PopupMenu(&menu, position);
950 wxPoint currentPos = widget->GetPosition();
951 widget->SetPosition(currentPos + delta);
974 "Loaded preferences: zoom_step=%.2f, wheel_sens=%.2f, pan_sens=%.2f, zoom_follows_cursor=%s",
BehaviorTreeProjectDialog::OnProjectNameChanged BehaviorTreeProjectDialog::OnRemoveFiles wxEND_EVENT_TABLE() BehaviorTreeProjectDialog
#define LOG_INFO(category, message)
Represents a node in a behavior tree structure.
const String & GetName() const
std::vector< Node * > GetAllChildren()
AppPreferences & GetPreferences()
static AppPreferencesManager & GetInstance()
BehaviorTreeViewSettings & GetBehaviorTreeViewSettings()
MainPanelSettings & GetMainPanelSettings()
Main types header for EmberCore.
wxBEGIN_EVENT_TABLE(LogTab, wxPanel) EVT_CHOICE(ID_LEVEL_FILTER
PerformancePanel::OnUpdateTimer EVT_PAINT(PerformancePanel::OnPaint) EVT_SIZE(PerformancePanel