// Fill out your copyright notice in the Description page of Project Settings. #include "SChildWindow.h" #include "SCanvas.h" #include "SConstraintCanvas.h" #include "SlateOptMacros.h" #include "SWindowTitleBar.h" #include "WindowManager.h" #include "Thread/MainThreadEventList.h" #include "UI/Widget/IChildWindow.h" DECLARE_THREAD_MESSAGE(FMainThreadEventList, OnWindowResized, SChildWindow* Window; FVector2f Size; ) { Args.Window->GetOnWindowResize().ExecuteIfBound(Args.Size); } BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SChildWindow::Construct(const FArguments& InArgs, SConstraintCanvas::FSlot* InSlot) { Slot = InSlot; Slot->SetAnchors(FAnchors(0.f, 0.f, 0.f, 0.f)); Slot->SetAlignment(FVector2D(0, 0)); OnClose = InArgs._OnClose; OnWindowMove = InArgs._OnWindowMove; OnWindowResize = InArgs._OnWindowResize; BorderSize = InArgs._BorderSize; ResizeHandleSize = InArgs._ResizeHandleSize; IsSingletonWindow = InArgs._IsSingletonWindow; Content = InArgs._Content; ChildSlot [ SNew(SBorder) [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ SNew(SBox) .HeightOverride(GetTitleBarHeight()) [ SAssignNew(TitleBar, SChildWindowTitleBar) .Title(InArgs._Title) .OnClose_Raw(this, &SChildWindow::OnCloseClicked) .OnWindowMoveDelta_Raw(this, &SChildWindow::MoveWindowDelta) .OnMaximize(this, &SChildWindow::OnMaximize) ] ] +SVerticalBox::Slot() .FillHeight(1.f) .Padding(BorderSize.X, BorderSize.Y, BorderSize.X, BorderSize.Y + ResizeHandleSize.Y) [ Content->GetWidget() ] ] ]; } FReply SChildWindow::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { FWindowManager::Get().FrontChildWindow(SharedThis(this)); if (GetCursor() == EMouseCursor::ResizeSouthEast) { BeginResizePos = MouseEvent.GetScreenSpacePosition(); BeginResizeMargin = Slot->GetOffset(); IsOnResize = true; return FReply::Handled().CaptureMouse(AsShared()); } return FReply::Unhandled(); } FReply SChildWindow::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { TitleBar->OnMouseButtonUp(MyGeometry, MouseEvent); if (IsOnResize) { IsOnResize = false; return FReply::Handled().ReleaseMouseCapture(); } return FReply::Unhandled(); } FReply SChildWindow::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { if (TitleBar->IsMaximized()) return FReply::Unhandled(); if (IsOnResize) { const FVector2D Offset = (BeginResizePos - MouseEvent.GetScreenSpacePosition()) / MyGeometry.Scale; FMargin Margin = BeginResizeMargin; Margin.Right = BeginResizeMargin.Right - Offset.X; Margin.Bottom = BeginResizeMargin.Bottom - Offset.Y; Margin.Right = FMath::Max(Margin.Right, 50); Margin.Bottom = FMath::Max(Margin.Bottom, GetTitleBarHeight() + ResizeHandleSize.Y); const FVector2f& Size = Margin.GetDesiredSize2f(); // PUSH_THREAD_EVENT(OnWindowResized, this, Size); OnWindowResize.ExecuteIfBound(Size); Slot->SetOffset(Margin); } else { const FVector2D LocalMousePos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); const FVector2D ResizeLU = MyGeometry.Size - ResizeHandleSize; // Resize handle left up if (LocalMousePos.ComponentwiseAllGreaterThan(ResizeLU)) { SetCursor(EMouseCursor::ResizeSouthEast); } else { SetCursor(EMouseCursor::Default); } } return FReply::Unhandled(); } void SChildWindow::MoveWindow(FVector2f Position) { Position = FVector2f::Max(Position, FVector2f::ZeroVector); Position = FVector2f::Min(Position, GetDesiredSize()); FMargin Margin = Slot->GetOffset(); Margin.Left = Position.X; Margin.Top = Position.Y; Slot->SetOffset(Margin); Position.Y += GetTitleBarHeight(); Position.X += BorderSize.X; OnWindowMove.ExecuteIfBound(Position); } float SChildWindow::GetTitleBarHeight() { return 24; } void SChildWindow::MoveWindowDelta(FVector2f Delta) { FMargin Margin = Slot->GetOffset(); Margin.Left += Delta.X; Margin.Top += Delta.Y; const FVector2f& ParentSize = GetParentWidget()->GetTickSpaceGeometry().Size; Margin.Left = FMath::Max(Margin.Left, 0); Margin.Top = FMath::Max(Margin.Top, 0); Margin.Left = FMath::Min(Margin.Left, ParentSize.X - 100); Margin.Top = FMath::Min(Margin.Top, ParentSize.Y - 100); Slot->SetOffset(Margin); FVector2f WindowPos(Margin.Left, Margin.Top); WindowPos.Y += GetTitleBarHeight(); WindowPos.X += BorderSize.X; OnWindowMove.ExecuteIfBound(WindowPos); } void SChildWindow::ResizeWindow(FVector2f Size) { const float TitleBarHeight = GetTitleBarHeight(); FMargin Margin = Slot->GetOffset(); Margin.Right = Size.X + BorderSize.X * 2; Margin.Bottom = Size.Y + TitleBarHeight + BorderSize.Y * 2; Slot->SetOffset(Margin); OnWindowResize.ExecuteIfBound(Size); } void SChildWindow::OnMaximize(bool bArg) { if (bArg) { LastMargin = Slot->GetOffset(); Slot->SetAnchors(FAnchors(0.f, 0.f, 1.f, 1.f)); Slot->SetOffset(FMargin(0, 0, 0, 0)); // PUSH_THREAD_EVENT(OnWindowResized, this, Slot->GetOwner()->GetOwner().GetTickSpaceGeometry().Size); OnWindowResize.ExecuteIfBound(Slot->GetOwner()->GetOwner().GetTickSpaceGeometry().Size); } else { Slot->SetAnchors(FAnchors(0.f, 0.f, 0.f, 0.f)); Slot->SetOffset(LastMargin); // PUSH_THREAD_EVENT(OnWindowResized, this, Slot->GetOwner()->GetOwner().GetTickSpaceGeometry().Size); OnWindowResize.ExecuteIfBound(Slot->GetOwner()->GetOwner().GetTickSpaceGeometry().Size); } } void SChildWindow::OnCloseClicked() { if (IsSingletonWindow) { SetVisibility(EVisibility::Collapsed); } else { if (const TSharedPtr Parent = StaticCastSharedPtr(GetParentWidget())) Parent->RemoveSlot(AsShared()); } OnClose.ExecuteIfBound(); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION