AronaSlate/Source/Arona/UI/Widget/SChildWindow.cpp
2024-01-25 11:21:15 +08:00

210 lines
5.7 KiB
C++

// 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<SConstraintCanvas> Parent = StaticCastSharedPtr<SConstraintCanvas>(GetParentWidget()))
Parent->RemoveSlot(AsShared());
}
OnClose.ExecuteIfBound();
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION