mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
453 lines
10 KiB
C++
453 lines
10 KiB
C++
#include "stdafx.h"
|
|
#include "ContainerControl.h"
|
|
#include "Form.h"
|
|
|
|
namespace Forms
|
|
{
|
|
ContainerControl::ContainerControl()
|
|
: Control(), _ActiveControl(nullptr), _FocusedControl(nullptr), _AutoScaleDimensions{}, _CurrentAutoScaleDimensions{}, _AutoScaleMode(AutoScaleMode::Inherit), _ScalingNeededOnLayout(false)
|
|
{
|
|
SetStyle(ControlStyles::AllPaintingInWmPaint, false);
|
|
}
|
|
|
|
Control* ContainerControl::ActiveControl()
|
|
{
|
|
return this->_ActiveControl;
|
|
}
|
|
|
|
void ContainerControl::SetActiveControl(Control* Value)
|
|
{
|
|
SetActiveControlInternal(Value);
|
|
}
|
|
|
|
bool ContainerControl::ActivateControl(Control* Value)
|
|
{
|
|
return ActivateControlInternal(Value, true);
|
|
}
|
|
|
|
Drawing::SizeF ContainerControl::AutoScaleDimensions()
|
|
{
|
|
return this->_AutoScaleDimensions;
|
|
}
|
|
|
|
void ContainerControl::SetAutoScaleDimensions(Drawing::SizeF Size)
|
|
{
|
|
this->_AutoScaleDimensions = Size;
|
|
if (!this->_AutoScaleDimensions.Empty())
|
|
{
|
|
this->LayoutScalingNeeded();
|
|
}
|
|
}
|
|
|
|
Drawing::SizeF ContainerControl::CurrentAutoScaleDimensions()
|
|
{
|
|
if (this->_CurrentAutoScaleDimensions.Empty())
|
|
{
|
|
switch (this->_AutoScaleMode)
|
|
{
|
|
case AutoScaleMode::Font:
|
|
this->_CurrentAutoScaleDimensions = this->GetFontAutoScaleDimensions();
|
|
break;
|
|
case AutoScaleMode::Dpi:
|
|
// TODO: Handle dpi related scaling values...
|
|
break;
|
|
|
|
default:
|
|
this->_CurrentAutoScaleDimensions = this->AutoScaleDimensions();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return this->_CurrentAutoScaleDimensions;
|
|
}
|
|
|
|
AutoScaleMode ContainerControl::AutoScaleMode()
|
|
{
|
|
return this->_AutoScaleMode;
|
|
}
|
|
|
|
void ContainerControl::SetAutoScaleMode(Forms::AutoScaleMode Mode)
|
|
{
|
|
bool ScalingRequired = false;
|
|
|
|
if (Mode != this->_AutoScaleMode)
|
|
{
|
|
if (_AutoScaleMode != Forms::AutoScaleMode::Inherit)
|
|
{
|
|
this->_AutoScaleDimensions = Drawing::SizeF{};
|
|
}
|
|
|
|
this->_AutoScaleMode = Mode;
|
|
ScalingRequired = true;
|
|
}
|
|
|
|
// TODO: OnAutoScaleModeChanged();
|
|
|
|
if (ScalingRequired)
|
|
this->LayoutScalingNeeded();
|
|
}
|
|
|
|
void ContainerControl::WndProc(Message& Msg)
|
|
{
|
|
switch (Msg.Msg)
|
|
{
|
|
case WM_SETFOCUS:
|
|
WmSetFocus(Msg);
|
|
break;
|
|
default:
|
|
Control::WndProc(Msg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
CreateParams ContainerControl::GetCreateParams()
|
|
{
|
|
auto Cp = Control::GetCreateParams();
|
|
Cp.ExStyle |= WS_EX_CONTROLPARENT;
|
|
|
|
return Cp;
|
|
}
|
|
|
|
bool ContainerControl::IsContainerControl()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ContainerControl::WmSetFocus(Message& Msg)
|
|
{
|
|
if (_ActiveControl != nullptr)
|
|
{
|
|
if (!_ActiveControl->Visible())
|
|
this->OnGotFocus();
|
|
|
|
FocusActiveControlInternal();
|
|
}
|
|
else
|
|
{
|
|
if (_Parent != nullptr)
|
|
{
|
|
ContainerControl* C = (ContainerControl*)_Parent->GetContainerControl();
|
|
if (C != nullptr)
|
|
{
|
|
if (!C->ActivateControlInternal(this, true))
|
|
return;
|
|
}
|
|
}
|
|
|
|
Control::WndProc(Msg);
|
|
}
|
|
}
|
|
|
|
void ContainerControl::LayoutScalingNeeded()
|
|
{
|
|
this->EnableRequiredScaling(this, true);
|
|
this->_ScalingNeededOnLayout = true;
|
|
}
|
|
|
|
void ContainerControl::EnableRequiredScaling(Control *Ctrl, bool Enable)
|
|
{
|
|
Ctrl->SetRequiredScalingEnabled(Enable);
|
|
|
|
if (!Ctrl->GetStyle(ControlStyles::ContainerControl) || Ctrl->Controls() == nullptr)
|
|
return;
|
|
|
|
uint32_t ControlCount = Ctrl->Controls()->Count();
|
|
auto& ControlList = *Ctrl->Controls().get();
|
|
|
|
for (uint32_t i = 0; i < ControlCount; i++)
|
|
{
|
|
EnableRequiredScaling(ControlList[i], Enable);
|
|
}
|
|
}
|
|
|
|
void ContainerControl::PerformNeededAutoScaleOnLayout()
|
|
{
|
|
if (this->_ScalingNeededOnLayout)
|
|
{
|
|
this->PerformAutoScale(this->_ScalingNeededOnLayout, false);
|
|
}
|
|
}
|
|
|
|
void ContainerControl::PerformAutoScale(bool IncludeBounds, bool ExcludeBounds)
|
|
{
|
|
bool Suspended = false;
|
|
|
|
if (this->_AutoScaleMode != AutoScaleMode::None && this->_AutoScaleMode != AutoScaleMode::Inherit)
|
|
{
|
|
// TODO: SuspendAllLayout(this)
|
|
Suspended = true;
|
|
|
|
Drawing::SizeF Included{};
|
|
Drawing::SizeF Excluded{};
|
|
|
|
if (IncludeBounds)
|
|
Included = this->AutoScaleFactor();
|
|
if (ExcludeBounds)
|
|
Excluded = this->AutoScaleFactor();
|
|
|
|
this->Scale(Included, Excluded, this);
|
|
this->_AutoScaleDimensions = this->CurrentAutoScaleDimensions();
|
|
}
|
|
|
|
if (IncludeBounds)
|
|
{
|
|
this->_ScalingNeededOnLayout = false;
|
|
this->EnableRequiredScaling(this, false);
|
|
}
|
|
|
|
if (Suspended)
|
|
{
|
|
// TODO: ResumeAllLayout(this, false);
|
|
}
|
|
}
|
|
|
|
Drawing::SizeF ContainerControl::GetFontAutoScaleDimensions()
|
|
{
|
|
Drawing::SizeF Result{};
|
|
|
|
auto hDC = CreateCompatibleDC(nullptr);
|
|
auto CurrentFont = this->GetFont();
|
|
auto OldFont = SelectObject(hDC, CurrentFont->GetFontHandle());
|
|
|
|
TEXTMETRICA Tm{};
|
|
GetTextMetricsA(hDC, &Tm);
|
|
|
|
Result.Height = (float)Tm.tmHeight;
|
|
|
|
if ((Tm.tmPitchAndFamily & TMPF_FIXED_PITCH) != 0)
|
|
{
|
|
constexpr const char* FontMeasureString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
const uint32_t FontMeasureSize = (uint32_t)strlen(FontMeasureString);
|
|
|
|
SIZE Sz{};
|
|
GetTextExtentPoint32A(hDC, FontMeasureString, FontMeasureSize, &Sz);
|
|
Result.Width = (float)(int)std::roundf(((float)Sz.cx) / ((float)FontMeasureSize));
|
|
}
|
|
else
|
|
{
|
|
Result.Width = (float)Tm.tmAveCharWidth;
|
|
}
|
|
|
|
SelectObject(hDC, OldFont);
|
|
DeleteDC(hDC);
|
|
|
|
return Result;
|
|
}
|
|
|
|
bool ContainerControl::ActivateControlInternal(Control* Ctrl, bool Originator)
|
|
{
|
|
bool Result = true;
|
|
bool UpdateContainerActiveControl = false;
|
|
|
|
ContainerControl* Cc = nullptr;
|
|
Control* Parent = this->_Parent;
|
|
|
|
if (Parent != nullptr)
|
|
{
|
|
Cc = (ContainerControl*)Parent->GetContainerControl();
|
|
|
|
if (Cc != nullptr)
|
|
{
|
|
UpdateContainerActiveControl = (Cc->ActiveControl() != this);
|
|
}
|
|
}
|
|
|
|
if (Ctrl != _ActiveControl || UpdateContainerActiveControl)
|
|
{
|
|
if (UpdateContainerActiveControl)
|
|
{
|
|
if (!Cc->ActivateControlInternal(this, false))
|
|
return false;
|
|
}
|
|
|
|
Result = AssignActiveControlInternal((Ctrl == this) ? nullptr : Ctrl);
|
|
}
|
|
|
|
if (Originator)
|
|
{
|
|
// TODO: ScrollActiveControlIntoView();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
bool ContainerControl::AssignActiveControlInternal(Control* Ctrl)
|
|
{
|
|
if (_ActiveControl != Ctrl)
|
|
{
|
|
_ActiveControl = Ctrl;
|
|
// TODO: UpdateFocusedControl();
|
|
|
|
if (_ActiveControl == Ctrl)
|
|
{
|
|
auto FormCtrl = (Form*)FindForm();
|
|
if (FormCtrl != nullptr)
|
|
FormCtrl->UpdateDefaultButton();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_FocusedControl = _ActiveControl;
|
|
}
|
|
|
|
return (_ActiveControl == Ctrl);
|
|
}
|
|
|
|
void ContainerControl::Select(bool Directed, bool Forward)
|
|
{
|
|
bool CorrectParentActiveControl = true;
|
|
if (this->_Parent != nullptr)
|
|
{
|
|
auto C = (ContainerControl*)this->_Parent->GetContainerControl();
|
|
if (C != nullptr)
|
|
{
|
|
C->SetActiveControl(this);
|
|
CorrectParentActiveControl = (C->ActiveControl() == this);
|
|
}
|
|
}
|
|
|
|
if (Directed && CorrectParentActiveControl)
|
|
SelectNextControl(nullptr, Forward, true, true, false);
|
|
}
|
|
|
|
void ContainerControl::Scale(Drawing::SizeF IncludedFactor, Drawing::SizeF ExcludedFactor, Control* Ctrl)
|
|
{
|
|
if (this->_AutoScaleMode == AutoScaleMode::Inherit)
|
|
{
|
|
Control::Scale(IncludedFactor, ExcludedFactor, Ctrl);
|
|
}
|
|
else
|
|
{
|
|
Drawing::SizeF OurExcludedFactor = ExcludedFactor;
|
|
Drawing::SizeF ChildIncludedFactor = IncludedFactor;
|
|
|
|
if (!OurExcludedFactor.Empty())
|
|
OurExcludedFactor = this->AutoScaleFactor();
|
|
|
|
// If we're not supposed to be scaling, don't scale the internal ones either.
|
|
if (this->AutoScaleMode() == AutoScaleMode::None)
|
|
ChildIncludedFactor = this->AutoScaleFactor();
|
|
|
|
Drawing::SizeF OurExternalContainerFactor = OurExcludedFactor;
|
|
|
|
if (!ExcludedFactor.Empty() && this->_Parent != nullptr)
|
|
{
|
|
OurExternalContainerFactor = Drawing::SizeF{};
|
|
|
|
if ((Ctrl != this))
|
|
{
|
|
OurExternalContainerFactor = ExcludedFactor;
|
|
}
|
|
}
|
|
|
|
ScaleControl(IncludedFactor, OurExternalContainerFactor, Ctrl);
|
|
ScaleChildControls(ChildIncludedFactor, OurExcludedFactor, Ctrl);
|
|
}
|
|
}
|
|
|
|
void ContainerControl::OnLayoutResuming(bool PerformLayout)
|
|
{
|
|
this->PerformNeededAutoScaleOnLayout();
|
|
Control::OnLayoutResuming(PerformLayout);
|
|
}
|
|
|
|
void ContainerControl::OnChildLayoutResuming(Control* Child, bool PerformLayout)
|
|
{
|
|
Control::OnChildLayoutResuming(Child, PerformLayout);
|
|
|
|
// Do not scale children if AutoScaleMode is set to Dpi
|
|
if (/*DpiHelper.EnableSinglePassScalingOfDpiForms &&*/ (this->_AutoScaleMode == AutoScaleMode::Dpi))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Perform scaling of the child control
|
|
if (!PerformLayout && this->_AutoScaleMode != AutoScaleMode::None && this->_AutoScaleMode != AutoScaleMode::Inherit && this->_ScalingNeededOnLayout)
|
|
{
|
|
Child->Scale(this->AutoScaleFactor(), Drawing::SizeF{}, this);
|
|
}
|
|
}
|
|
|
|
void ContainerControl::FocusActiveControlInternal()
|
|
{
|
|
if (_ActiveControl != nullptr && _ActiveControl->Visible())
|
|
{
|
|
auto FocusHandle = GetFocus();
|
|
if (FocusHandle == NULL || FocusHandle != _ActiveControl->GetHandle())
|
|
SetFocus(_ActiveControl->GetHandle());
|
|
}
|
|
else
|
|
{
|
|
ContainerControl* Cc = this;
|
|
while (Cc != nullptr && !Cc->Visible())
|
|
{
|
|
auto Parent = Cc->Parent();
|
|
if (Parent != nullptr)
|
|
Cc = (ContainerControl*)Parent->GetContainerControl();
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (Cc != nullptr && Cc->Visible())
|
|
SetFocus(Cc->GetHandle());
|
|
}
|
|
}
|
|
|
|
void ContainerControl::SetActiveControlInternal(Control* Value)
|
|
{
|
|
if (_ActiveControl != Value || (Value != nullptr && !Value->Focused()))
|
|
{
|
|
bool Result = false;
|
|
ContainerControl* Cc = nullptr;
|
|
|
|
if (Value != nullptr && Value->Parent() != nullptr)
|
|
{
|
|
Cc = (ContainerControl*)Value->Parent()->GetContainerControl();
|
|
}
|
|
|
|
if (Cc != nullptr)
|
|
{
|
|
Result = ActivateControlInternal(Value, false);
|
|
}
|
|
else
|
|
{
|
|
Result = AssignActiveControlInternal(Value);
|
|
}
|
|
|
|
if (Cc != nullptr && Result)
|
|
{
|
|
ContainerControl* CcAncestor = this;
|
|
while (CcAncestor->_Parent != nullptr && CcAncestor->_Parent->GetContainerControl() != nullptr)
|
|
CcAncestor = (ContainerControl*)CcAncestor->_Parent->GetContainerControl();
|
|
|
|
if (CcAncestor->ContainsFocus() /*&& Value is NOT USERCONTROL!!*/)
|
|
Cc->FocusActiveControlInternal();
|
|
}
|
|
}
|
|
}
|
|
|
|
Control* ContainerControl::ParentFormInternal()
|
|
{
|
|
if (this->_Parent != nullptr)
|
|
return this->_Parent->FindForm();
|
|
|
|
if (this->_RTTI == ControlTypes::Form)
|
|
return nullptr;
|
|
|
|
return FindForm();
|
|
}
|
|
|
|
Drawing::SizeF ContainerControl::AutoScaleFactor()
|
|
{
|
|
auto Current = this->CurrentAutoScaleDimensions();
|
|
auto Saved = this->AutoScaleDimensions();
|
|
|
|
if (Saved.Empty())
|
|
{
|
|
return Drawing::SizeF(1.f, 1.f);
|
|
}
|
|
|
|
return Drawing::SizeF(Current.Width / Saved.Width, Current.Height / Saved.Height);
|
|
}
|
|
}
|