blob: 5aaa566ff47778a7c92f637ceb602c6394d9df6b [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "xfa/fwl/core/ifwl_form.h"
#include "xfa/fde/tto/fde_textout.h"
#include "xfa/fwl/core/cfwl_message.h"
#include "xfa/fwl/core/cfwl_themebackground.h"
#include "xfa/fwl/core/cfwl_themepart.h"
#include "xfa/fwl/core/cfwl_themetext.h"
#include "xfa/fwl/core/cfwl_widgetmgr.h"
#include "xfa/fwl/core/fwl_noteimp.h"
#include "xfa/fwl/core/ifwl_app.h"
#include "xfa/fwl/core/ifwl_formproxy.h"
#include "xfa/fwl/core/ifwl_themeprovider.h"
#include "xfa/fwl/theme/cfwl_widgettp.h"
namespace {
const int kSystemButtonSize = 21;
const int kSystemButtonMargin = 5;
const int kSystemButtonSpan = 2;
} // namespace
namespace {
const uint8_t kCornerEnlarge = 10;
} // namespace
RestoreInfo::RestoreInfo() {}
RestoreInfo::~RestoreInfo() {}
IFWL_Form::IFWL_Form(const CFWL_WidgetImpProperties& properties,
IFWL_Widget* pOuter)
: IFWL_Widget(properties, pOuter),
m_pCloseBox(nullptr),
m_pMinBox(nullptr),
m_pMaxBox(nullptr),
m_pCaptionBox(nullptr),
m_pSubFocus(nullptr),
m_fCXBorder(0),
m_fCYBorder(0),
m_iCaptureBtn(-1),
m_iSysBox(0),
m_eResizeType(FORM_RESIZETYPE_None),
m_bLButtonDown(FALSE),
m_bMaximized(false),
m_bSetMaximize(FALSE),
m_bCustomizeLayout(false),
m_eFormSize(FWL_FORMSIZE_Manual),
m_bDoModalFlag(FALSE),
m_pBigIcon(nullptr),
m_pSmallIcon(nullptr),
m_bMouseIn(FALSE) {
m_rtRelative.Reset();
m_rtCaption.Reset();
m_rtRestore.Reset();
m_rtCaptionText.Reset();
m_rtIcon.Reset();
}
IFWL_Form::~IFWL_Form() {
RemoveSysButtons();
}
FWL_Type IFWL_Form::GetClassID() const {
return FWL_Type::Form;
}
FX_BOOL IFWL_Form::IsInstance(const CFX_WideStringC& wsClass) const {
if (wsClass == CFX_WideStringC(FWL_CLASS_Form))
return TRUE;
return IFWL_Widget::IsInstance(wsClass);
}
FWL_Error IFWL_Form::Initialize() {
if (IFWL_Widget::Initialize() != FWL_Error::Succeeded)
return FWL_Error::Indefinite;
RegisterForm();
RegisterEventTarget();
m_pDelegate = new CFWL_FormImpDelegate(this);
return FWL_Error::Succeeded;
}
void IFWL_Form::Finalize() {
delete m_pDelegate;
m_pDelegate = nullptr;
UnregisterEventTarget();
UnRegisterForm();
IFWL_Widget::Finalize();
}
FWL_Error IFWL_Form::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) {
if (bAutoSize) {
rect.Reset();
FX_FLOAT fCapHeight = GetCaptionHeight();
FX_FLOAT fCXBorder = GetBorderSize(TRUE);
FX_FLOAT fCYBorder = GetBorderSize(FALSE);
FX_FLOAT fEdge = GetEdgeWidth();
rect.height += fCapHeight + fCYBorder + fEdge + fEdge;
rect.width += fCXBorder + fCXBorder + fEdge + fEdge;
} else {
rect = m_pProperties->m_rtWidget;
}
return FWL_Error::Succeeded;
}
FWL_Error IFWL_Form::GetClientRect(CFX_RectF& rect) {
if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_Caption) == 0) {
rect = m_pProperties->m_rtWidget;
rect.Offset(-rect.left, -rect.top);
return FWL_Error::Succeeded;
}
#ifdef FWL_UseMacSystemBorder
rect = m_rtRelative;
CFWL_WidgetMgr* pWidgetMgr = CFWL_WidgetMgr::GetInstance();
if (!pWidgetMgr)
return FWL_Error::Indefinite;
rect.left = 0;
rect.top = 0;
return FWL_Error::Succeeded;
#else
FX_FLOAT x = 0;
FX_FLOAT y = 0;
FX_FLOAT t = 0;
IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
if (pTheme) {
CFWL_ThemePart part;
part.m_pWidget = this;
x = *static_cast<FX_FLOAT*>(
pTheme->GetCapacity(&part, CFWL_WidgetCapacity::CXBorder));
y = *static_cast<FX_FLOAT*>(
pTheme->GetCapacity(&part, CFWL_WidgetCapacity::CYBorder));
t = *static_cast<FX_FLOAT*>(
pTheme->GetCapacity(&part, CFWL_WidgetCapacity::CYCaption));
}
rect = m_pProperties->m_rtWidget;
rect.Offset(-rect.left, -rect.top);
rect.Deflate(x, t, x, y);
return FWL_Error::Succeeded;
#endif
}
FWL_Error IFWL_Form::Update() {
if (m_iLock > 0) {
return FWL_Error::Succeeded;
}
if (!m_pProperties->m_pThemeProvider) {
m_pProperties->m_pThemeProvider = GetAvailableTheme();
}
#ifdef FWL_UseMacSystemBorder
#else
SetThemeData();
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Icon) {
UpdateIcon();
}
#endif
UpdateCaption();
Layout();
return FWL_Error::Succeeded;
}
FWL_WidgetHit IFWL_Form::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
GetAvailableTheme();
if (m_pCloseBox && m_pCloseBox->m_rtBtn.Contains(fx, fy))
return FWL_WidgetHit::CloseBox;
if (m_pMaxBox && m_pMaxBox->m_rtBtn.Contains(fx, fy))
return FWL_WidgetHit::MaxBox;
if (m_pMinBox && m_pMinBox->m_rtBtn.Contains(fx, fy))
return FWL_WidgetHit::MinBox;
CFX_RectF rtCap;
rtCap.Set(m_rtCaption.left + m_fCYBorder, m_rtCaption.top + m_fCXBorder,
m_rtCaption.width - kSystemButtonSize * m_iSysBox - 2 * m_fCYBorder,
m_rtCaption.height - m_fCXBorder);
if (rtCap.Contains(fx, fy))
return FWL_WidgetHit::Titlebar;
if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) &&
(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_FRM_Resize)) {
FX_FLOAT fWidth = m_rtRelative.width - 2 * (m_fCYBorder + kCornerEnlarge);
FX_FLOAT fHeight = m_rtRelative.height - 2 * (m_fCXBorder + kCornerEnlarge);
CFX_RectF rt;
rt.Set(0, m_fCXBorder + kCornerEnlarge, m_fCYBorder, fHeight);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::Left;
rt.Set(m_rtRelative.width - m_fCYBorder, m_fCXBorder + kCornerEnlarge,
m_fCYBorder, fHeight);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::Right;
rt.Set(m_fCYBorder + kCornerEnlarge, 0, fWidth, m_fCXBorder);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::Top;
rt.Set(m_fCYBorder + kCornerEnlarge, m_rtRelative.height - m_fCXBorder,
fWidth, m_fCXBorder);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::Bottom;
rt.Set(0, 0, m_fCYBorder + kCornerEnlarge, m_fCXBorder + kCornerEnlarge);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::LeftTop;
rt.Set(0, m_rtRelative.height - m_fCXBorder - kCornerEnlarge,
m_fCYBorder + kCornerEnlarge, m_fCXBorder + kCornerEnlarge);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::LeftBottom;
rt.Set(m_rtRelative.width - m_fCYBorder - kCornerEnlarge, 0,
m_fCYBorder + kCornerEnlarge, m_fCXBorder + kCornerEnlarge);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::RightTop;
rt.Set(m_rtRelative.width - m_fCYBorder - kCornerEnlarge,
m_rtRelative.height - m_fCXBorder - kCornerEnlarge,
m_fCYBorder + kCornerEnlarge, m_fCXBorder + kCornerEnlarge);
if (rt.Contains(fx, fy))
return FWL_WidgetHit::RightBottom;
}
return FWL_WidgetHit::Client;
}
FWL_Error IFWL_Form::DrawWidget(CFX_Graphics* pGraphics,
const CFX_Matrix* pMatrix) {
if (!pGraphics)
return FWL_Error::Indefinite;
if (!m_pProperties->m_pThemeProvider)
return FWL_Error::Indefinite;
IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
FX_BOOL bInactive = !IsActive();
int32_t iState = bInactive ? CFWL_PartState_Inactive : CFWL_PartState_Normal;
if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_FRM_NoDrawClient) == 0) {
DrawBackground(pGraphics, pTheme);
}
#ifdef FWL_UseMacSystemBorder
return FWL_Error::Succeeded;
#endif
CFWL_ThemeBackground param;
param.m_pWidget = this;
param.m_dwStates = iState;
param.m_pGraphics = pGraphics;
param.m_rtPart = m_rtRelative;
if (pMatrix) {
param.m_matrix.Concat(*pMatrix);
}
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) {
param.m_iPart = CFWL_Part::Border;
pTheme->DrawBackground(&param);
}
if ((m_pProperties->m_dwStyleExes & FWL_WGTSTYLE_EdgeMask) !=
FWL_WGTSTYLE_EdgeNone) {
CFX_RectF rtEdge;
GetEdgeRect(rtEdge);
param.m_iPart = CFWL_Part::Edge;
param.m_rtPart = rtEdge;
param.m_dwStates = iState;
pTheme->DrawBackground(&param);
}
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Caption) {
param.m_iPart = CFWL_Part::Caption;
param.m_dwStates = iState;
param.m_rtPart = m_rtCaption;
pTheme->DrawBackground(&param);
DrawCaptionText(pGraphics, pTheme, pMatrix);
} else if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_NarrowCaption) {
param.m_iPart = CFWL_Part::NarrowCaption;
param.m_dwStates = iState;
param.m_rtPart = m_rtCaption;
pTheme->DrawBackground(&param);
DrawCaptionText(pGraphics, pTheme, pMatrix);
}
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Icon) {
param.m_iPart = CFWL_Part::Icon;
if (HasIcon()) {
DrawIconImage(pGraphics, pTheme, pMatrix);
}
}
#if (_FX_OS_ == _FX_MACOSX_)
{
if (m_pCloseBox) {
param.m_iPart = CFWL_Part::CloseBox;
param.m_dwStates = m_pCloseBox->GetPartState();
if (m_pProperties->m_dwStates & FWL_WGTSTATE_Deactivated) {
param.m_dwStates = CFWL_PartState_Disabled;
} else if (CFWL_PartState_Normal == param.m_dwStates && m_bMouseIn) {
param.m_dwStates = CFWL_PartState_Hovered;
}
param.m_rtPart = m_pCloseBox->m_rtBtn;
pTheme->DrawBackground(&param);
}
if (m_pMaxBox) {
param.m_iPart = CFWL_Part::MaximizeBox;
param.m_dwStates = m_pMaxBox->GetPartState();
if (m_pProperties->m_dwStates & FWL_WGTSTATE_Deactivated) {
param.m_dwStates = CFWL_PartState_Disabled;
} else if (CFWL_PartState_Normal == param.m_dwStates && m_bMouseIn) {
param.m_dwStates = CFWL_PartState_Hovered;
}
param.m_rtPart = m_pMaxBox->m_rtBtn;
param.m_bMaximize = m_bMaximized;
pTheme->DrawBackground(&param);
}
if (m_pMinBox) {
param.m_iPart = CFWL_Part::MinimizeBox;
param.m_dwStates = m_pMinBox->GetPartState();
if (m_pProperties->m_dwStates & FWL_WGTSTATE_Deactivated) {
param.m_dwStates = CFWL_PartState_Disabled;
} else if (CFWL_PartState_Normal == param.m_dwStates && m_bMouseIn) {
param.m_dwStates = CFWL_PartState_Hovered;
}
param.m_rtPart = m_pMinBox->m_rtBtn;
pTheme->DrawBackground(&param);
}
m_bMouseIn = FALSE;
}
#else
{
if (m_pCloseBox) {
param.m_iPart = CFWL_Part::CloseBox;
param.m_dwStates = m_pCloseBox->GetPartState();
param.m_rtPart = m_pCloseBox->m_rtBtn;
pTheme->DrawBackground(&param);
}
if (m_pMaxBox) {
param.m_iPart = CFWL_Part::MaximizeBox;
param.m_dwStates = m_pMaxBox->GetPartState();
param.m_rtPart = m_pMaxBox->m_rtBtn;
param.m_bMaximize = m_bMaximized;
pTheme->DrawBackground(&param);
}
if (m_pMinBox) {
param.m_iPart = CFWL_Part::MinimizeBox;
param.m_dwStates = m_pMinBox->GetPartState();
param.m_rtPart = m_pMinBox->m_rtBtn;
pTheme->DrawBackground(&param);
}
}
#endif
return FWL_Error::Succeeded;
}
FWL_FORMSIZE IFWL_Form::GetFormSize() {
return m_eFormSize;
}
FWL_Error IFWL_Form::SetFormSize(FWL_FORMSIZE eFormSize) {
m_eFormSize = eFormSize;
return FWL_Error::Succeeded;
}
IFWL_Widget* IFWL_Form::DoModal() {
IFWL_App* pApp = GetOwnerApp();
if (!pApp)
return nullptr;
CFWL_NoteDriver* pDriver = pApp->GetNoteDriver();
if (!pDriver)
return nullptr;
m_pNoteLoop.reset(new CFWL_NoteLoop(this));
pDriver->PushNoteLoop(m_pNoteLoop.get());
m_bDoModalFlag = TRUE;
SetStates(FWL_WGTSTATE_Invisible, FALSE);
pDriver->Run();
#if (_FX_OS_ == _FX_MACOSX_)
#else
pDriver->PopNoteLoop();
#endif
m_pNoteLoop.reset();
return nullptr;
}
IFWL_Widget* IFWL_Form::DoModal(uint32_t& dwCommandID) {
return DoModal();
}
FWL_Error IFWL_Form::EndDoModal() {
if (!m_pNoteLoop)
return FWL_Error::Indefinite;
m_bDoModalFlag = FALSE;
#if (_FX_OS_ == _FX_MACOSX_)
m_pNoteLoop->EndModalLoop();
IFWL_App* pApp = GetOwnerApp();
if (!pApp)
return FWL_Error::Indefinite;
CFWL_NoteDriver* pDriver =
static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
if (!pDriver)
return FWL_Error::Indefinite;
pDriver->PopNoteLoop();
SetStates(FWL_WGTSTATE_Invisible, TRUE);
return FWL_Error::Succeeded;
#else
SetStates(FWL_WGTSTATE_Invisible, TRUE);
return m_pNoteLoop->EndModalLoop();
#endif
}
FWL_Error IFWL_Form::SetBorderRegion(CFX_Path* pPath) {
return FWL_Error::Succeeded;
}
void IFWL_Form::DrawBackground(CFX_Graphics* pGraphics,
IFWL_ThemeProvider* pTheme) {
CFWL_ThemeBackground param;
param.m_pWidget = this;
param.m_iPart = CFWL_Part::Background;
param.m_pGraphics = pGraphics;
param.m_rtPart = m_rtRelative;
param.m_rtPart.Deflate(m_fCYBorder, m_rtCaption.height, m_fCYBorder,
m_fCXBorder);
pTheme->DrawBackground(&param);
}
IFWL_Widget* IFWL_Form::GetSubFocus() {
return m_pSubFocus;
}
void IFWL_Form::SetSubFocus(IFWL_Widget* pWidget) {
m_pSubFocus = pWidget;
}
void IFWL_Form::ShowChildWidget(IFWL_Widget* pParent) {
IFWL_App* pApp = FWL_GetApp();
if (!pApp)
return;
CFWL_WidgetMgr* pWidgetMgr = pApp->GetWidgetMgr();
if (!pWidgetMgr)
return;
IFWL_Widget* pChild = pWidgetMgr->GetFirstChildWidget(pParent);
while (pChild) {
ShowChildWidget(pChild);
pChild = pWidgetMgr->GetNextSiblingWidget(pChild);
}
}
void IFWL_Form::RemoveSysButtons() {
m_rtCaption.Reset();
delete m_pCloseBox;
m_pCloseBox = nullptr;
delete m_pMinBox;
m_pMinBox = nullptr;
delete m_pMaxBox;
m_pMaxBox = nullptr;
delete m_pCaptionBox;
m_pCaptionBox = nullptr;
}
void IFWL_Form::CalcContentRect(CFX_RectF& rtContent) {
#ifdef FWL_UseMacSystemBorder
rtContent = m_rtRelative;
#else
GetEdgeRect(rtContent);
if (HasEdge()) {
FX_FLOAT fEdge = GetEdgeWidth();
rtContent.Deflate(fEdge, fEdge);
}
#endif
}
CFWL_SysBtn* IFWL_Form::GetSysBtnAtPoint(FX_FLOAT fx, FX_FLOAT fy) {
if (m_pCloseBox && m_pCloseBox->m_rtBtn.Contains(fx, fy)) {
return m_pCloseBox;
}
if (m_pMaxBox && m_pMaxBox->m_rtBtn.Contains(fx, fy)) {
return m_pMaxBox;
}
if (m_pMinBox && m_pMinBox->m_rtBtn.Contains(fx, fy)) {
return m_pMinBox;
}
if (m_pCaptionBox && m_pCaptionBox->m_rtBtn.Contains(fx, fy)) {
return m_pCaptionBox;
}
return nullptr;
}
CFWL_SysBtn* IFWL_Form::GetSysBtnByState(uint32_t dwState) {
if (m_pCloseBox && (m_pCloseBox->m_dwState & dwState)) {
return m_pCloseBox;
}
if (m_pMaxBox && (m_pMaxBox->m_dwState & dwState)) {
return m_pMaxBox;
}
if (m_pMinBox && (m_pMinBox->m_dwState & dwState)) {
return m_pMinBox;
}
if (m_pCaptionBox && (m_pCaptionBox->m_dwState & dwState)) {
return m_pCaptionBox;
}
return nullptr;
}
CFWL_SysBtn* IFWL_Form::GetSysBtnByIndex(int32_t nIndex) {
if (nIndex < 0)
return nullptr;
CFX_ArrayTemplate<CFWL_SysBtn*> arrBtn;
if (m_pMinBox)
arrBtn.Add(m_pMinBox);
if (m_pMaxBox)
arrBtn.Add(m_pMaxBox);
if (m_pCloseBox)
arrBtn.Add(m_pCloseBox);
return arrBtn[nIndex];
}
int32_t IFWL_Form::GetSysBtnIndex(CFWL_SysBtn* pBtn) {
CFX_ArrayTemplate<CFWL_SysBtn*> arrBtn;
if (m_pMinBox)
arrBtn.Add(m_pMinBox);
if (m_pMaxBox)
arrBtn.Add(m_pMaxBox);
if (m_pCloseBox)
arrBtn.Add(m_pCloseBox);
return arrBtn.Find(pBtn);
}
FX_FLOAT IFWL_Form::GetCaptionHeight() {
CFWL_WidgetCapacity dwCapacity = CFWL_WidgetCapacity::None;
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Caption) {
dwCapacity = CFWL_WidgetCapacity::CYCaption;
} else if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_NarrowCaption) {
dwCapacity = CFWL_WidgetCapacity::CYNarrowCaption;
}
if (dwCapacity != CFWL_WidgetCapacity::None) {
FX_FLOAT* pfCapHeight =
static_cast<FX_FLOAT*>(GetThemeCapacity(dwCapacity));
return pfCapHeight ? *pfCapHeight : 0;
}
return 0;
}
void IFWL_Form::DrawCaptionText(CFX_Graphics* pGs,
IFWL_ThemeProvider* pTheme,
const CFX_Matrix* pMatrix) {
CFX_WideString wsText;
IFWL_DataProvider* pData = m_pProperties->m_pDataProvider;
pData->GetCaption(this, wsText);
if (wsText.IsEmpty()) {
return;
}
CFWL_ThemeText textParam;
textParam.m_pWidget = this;
textParam.m_iPart = CFWL_Part::Caption;
textParam.m_dwStates = CFWL_PartState_Normal;
textParam.m_pGraphics = pGs;
if (pMatrix) {
textParam.m_matrix.Concat(*pMatrix);
}
CFX_RectF rtText;
if (m_bCustomizeLayout) {
rtText = m_rtCaptionText;
rtText.top -= 5;
} else {
rtText = m_rtCaption;
FX_FLOAT fpos;
fpos = HasIcon() ? 29.0f : 13.0f;
rtText.left += fpos;
}
textParam.m_rtPart = rtText;
textParam.m_wsText = wsText;
textParam.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine | FDE_TTOSTYLE_Ellipsis;
textParam.m_iTTOAlign = m_bCustomizeLayout ? FDE_TTOALIGNMENT_Center
: FDE_TTOALIGNMENT_CenterLeft;
pTheme->DrawText(&textParam);
}
void IFWL_Form::DrawIconImage(CFX_Graphics* pGs,
IFWL_ThemeProvider* pTheme,
const CFX_Matrix* pMatrix) {
IFWL_FormDP* pData =
static_cast<IFWL_FormDP*>(m_pProperties->m_pDataProvider);
CFWL_ThemeBackground param;
param.m_pWidget = this;
param.m_iPart = CFWL_Part::Icon;
param.m_pGraphics = pGs;
param.m_pImage = pData->GetIcon(this, FALSE);
param.m_rtPart = m_rtIcon;
if (pMatrix) {
param.m_matrix.Concat(*pMatrix);
}
pTheme->DrawBackground(&param);
}
void IFWL_Form::GetEdgeRect(CFX_RectF& rtEdge) {
rtEdge = m_rtRelative;
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) {
FX_FLOAT fCX = GetBorderSize();
FX_FLOAT fCY = GetBorderSize(FALSE);
rtEdge.Deflate(fCX, m_rtCaption.Height(), fCX, fCY);
}
}
void IFWL_Form::SetWorkAreaRect() {
m_rtRestore = m_pProperties->m_rtWidget;
CFWL_WidgetMgr* pWidgetMgr = CFWL_WidgetMgr::GetInstance();
if (!pWidgetMgr)
return;
m_bSetMaximize = TRUE;
Repaint(&m_rtRelative);
}
void IFWL_Form::SetCursor(FX_FLOAT fx, FX_FLOAT fy) {}
void IFWL_Form::Layout() {
GetRelativeRect(m_rtRelative);
#ifndef FWL_UseMacSystemBorder
ReSetSysBtn();
#endif
}
void IFWL_Form::ReSetSysBtn() {
m_fCXBorder =
*static_cast<FX_FLOAT*>(GetThemeCapacity(CFWL_WidgetCapacity::CXBorder));
m_fCYBorder =
*static_cast<FX_FLOAT*>(GetThemeCapacity(CFWL_WidgetCapacity::CYBorder));
RemoveSysButtons();
IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
m_bCustomizeLayout = pTheme->IsCustomizedLayout(this);
FX_FLOAT fCapHeight = GetCaptionHeight();
if (fCapHeight > 0) {
m_rtCaption = m_rtRelative;
m_rtCaption.height = fCapHeight;
}
m_iSysBox = 0;
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_CloseBox) {
m_pCloseBox = new CFWL_SysBtn;
if (!m_bCustomizeLayout) {
m_pCloseBox->m_rtBtn.Set(
m_rtRelative.right() - kSystemButtonMargin - kSystemButtonSize,
kSystemButtonMargin, kSystemButtonSize, kSystemButtonSize);
}
m_iSysBox++;
}
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_MaximizeBox) {
m_pMaxBox = new CFWL_SysBtn;
if (!m_bCustomizeLayout) {
if (m_pCloseBox) {
m_pMaxBox->m_rtBtn.Set(
m_pCloseBox->m_rtBtn.left - kSystemButtonSpan - kSystemButtonSize,
m_pCloseBox->m_rtBtn.top, kSystemButtonSize, kSystemButtonSize);
} else {
m_pMaxBox->m_rtBtn.Set(
m_rtRelative.right() - kSystemButtonMargin - kSystemButtonSize,
kSystemButtonMargin, kSystemButtonSize, kSystemButtonSize);
}
}
m_iSysBox++;
}
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_MinimizeBox) {
m_pMinBox = new CFWL_SysBtn;
if (!m_bCustomizeLayout) {
if (m_pMaxBox) {
m_pMinBox->m_rtBtn.Set(
m_pMaxBox->m_rtBtn.left - kSystemButtonSpan - kSystemButtonSize,
m_pMaxBox->m_rtBtn.top, kSystemButtonSize, kSystemButtonSize);
} else if (m_pCloseBox) {
m_pMinBox->m_rtBtn.Set(
m_pCloseBox->m_rtBtn.left - kSystemButtonSpan - kSystemButtonSize,
m_pCloseBox->m_rtBtn.top, kSystemButtonSize, kSystemButtonSize);
} else {
m_pMinBox->m_rtBtn.Set(
m_rtRelative.right() - kSystemButtonMargin - kSystemButtonSize,
kSystemButtonMargin, kSystemButtonSize, kSystemButtonSize);
}
}
m_iSysBox++;
}
IFWL_FormDP* pData =
static_cast<IFWL_FormDP*>(m_pProperties->m_pDataProvider);
if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Icon &&
pData->GetIcon(this, FALSE)) {
if (!m_bCustomizeLayout) {
m_rtIcon.Set(5, (m_rtCaption.height - m_fSmallIconSz) / 2, m_fSmallIconSz,
m_fSmallIconSz);
}
}
}
void IFWL_Form::RegisterForm() {
IFWL_App* pApp = GetOwnerApp();
if (!pApp)
return;
CFWL_NoteDriver* pDriver =
static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
if (!pDriver)
return;
pDriver->RegisterForm(this);
}
void IFWL_Form::UnRegisterForm() {
IFWL_App* pApp = GetOwnerApp();
if (!pApp)
return;
CFWL_NoteDriver* pDriver =
static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
if (!pDriver)
return;
pDriver->UnRegisterForm(this);
}
FX_BOOL IFWL_Form::IsDoModal() {
return m_bDoModalFlag;
}
void IFWL_Form::SetThemeData() {
m_fSmallIconSz =
*static_cast<FX_FLOAT*>(GetThemeCapacity(CFWL_WidgetCapacity::SmallIcon));
m_fBigIconSz =
*static_cast<FX_FLOAT*>(GetThemeCapacity(CFWL_WidgetCapacity::BigIcon));
}
FX_BOOL IFWL_Form::HasIcon() {
IFWL_FormDP* pData =
static_cast<IFWL_FormDP*>(m_pProperties->m_pDataProvider);
return !!pData->GetIcon(this, FALSE);
}
void IFWL_Form::UpdateIcon() {
CFWL_WidgetMgr* pWidgetMgr = CFWL_WidgetMgr::GetInstance();
if (!pWidgetMgr)
return;
IFWL_FormDP* pData =
static_cast<IFWL_FormDP*>(m_pProperties->m_pDataProvider);
CFX_DIBitmap* pBigIcon = pData->GetIcon(this, TRUE);
CFX_DIBitmap* pSmallIcon = pData->GetIcon(this, FALSE);
if (pBigIcon)
m_pBigIcon = pBigIcon;
if (pSmallIcon)
m_pSmallIcon = pSmallIcon;
}
void IFWL_Form::UpdateCaption() {
CFWL_WidgetMgr* pWidgetMgr = CFWL_WidgetMgr::GetInstance();
if (!pWidgetMgr)
return;
IFWL_DataProvider* pData = m_pProperties->m_pDataProvider;
if (!pData)
return;
CFX_WideString text;
pData->GetCaption(this, text);
}
void IFWL_Form::DoWidthLimit(FX_FLOAT& fLeft,
FX_FLOAT& fWidth,
FX_FLOAT fCurX,
FX_FLOAT fSpace,
FX_FLOAT fLimitMin,
FX_FLOAT fLimitMax,
FX_BOOL bLeft) {
FX_FLOAT fx = fCurX;
FX_FLOAT fy = 0;
TransformTo(nullptr, fx, fy);
FX_FLOAT fTemp =
bLeft ? (fWidth - fx + fLeft + fSpace) : (fx - fLeft + fSpace);
if (fTemp >= fLimitMin && fTemp <= fLimitMax) {
fWidth = fTemp;
fLeft += bLeft ? (fx - fLeft - fSpace) : 0;
} else {
if (fTemp < fLimitMin && fWidth > fLimitMin) {
fLeft += bLeft ? (fWidth - fLimitMin) : 0;
fWidth = fLimitMin;
} else if (fTemp > fLimitMax && fWidth < fLimitMax) {
fLeft -= bLeft ? (fLimitMax - fWidth) : 0;
fWidth = fLimitMax;
}
}
}
void IFWL_Form::DoHeightLimit(FX_FLOAT& fTop,
FX_FLOAT& fHeight,
FX_FLOAT fCurY,
FX_FLOAT fSpace,
FX_FLOAT fLimitMin,
FX_FLOAT fLimitMax,
FX_BOOL bTop) {
FX_FLOAT fx = 0;
FX_FLOAT fy = fCurY;
TransformTo(nullptr, fx, fy);
FX_FLOAT fTemp = bTop ? (fHeight - fy + fTop + fSpace) : (fy - fTop + fSpace);
if (fTemp >= fLimitMin && fTemp <= fLimitMax) {
fHeight = fTemp;
fTop += bTop ? (fy - fTop - fSpace) : 0;
} else {
if (fTemp < fLimitMin && fHeight > fLimitMin) {
fTop += bTop ? (fHeight - fLimitMin) : 0;
fHeight = fLimitMin;
} else if (fTemp > fLimitMax && fHeight < fLimitMax) {
fTop -= bTop ? (fLimitMax - fHeight) : 0;
fHeight = fLimitMax;
}
}
}
CFWL_FormImpDelegate::CFWL_FormImpDelegate(IFWL_Form* pOwner)
: m_pOwner(pOwner) {}
#ifdef FWL_UseMacSystemBorder
void CFWL_FormImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
if (!pMessage)
return;
switch (pMessage->GetClassID()) {
case CFWL_MessageType::Activate: {
m_pOwner->m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Deactivated;
m_pOwner->Repaint(&m_pOwner->m_rtRelative);
break;
}
case CFWL_MessageType::Deactivate: {
m_pOwner->m_pProperties->m_dwStates |= FWL_WGTSTATE_Deactivated;
m_pOwner->Repaint(&m_pOwner->m_rtRelative);
break;
}
default:
break;
}
}
#else
void CFWL_FormImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
if (!pMessage)
return;
switch (pMessage->GetClassID()) {
case CFWL_MessageType::Activate: {
m_pOwner->m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Deactivated;
IFWL_App* pApp = m_pOwner->GetOwnerApp();
CFWL_NoteDriver* pDriver =
static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
IFWL_Widget* pSubFocus = m_pOwner->GetSubFocus();
if (pSubFocus && pSubFocus != pDriver->GetFocus())
pDriver->SetFocus(pSubFocus);
m_pOwner->Repaint(&m_pOwner->m_rtRelative);
break;
}
case CFWL_MessageType::Deactivate: {
m_pOwner->m_pProperties->m_dwStates |= FWL_WGTSTATE_Deactivated;
IFWL_App* pApp = m_pOwner->GetOwnerApp();
CFWL_NoteDriver* pDriver =
static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
IFWL_Widget* pSubFocus = m_pOwner->GetSubFocus();
if (pSubFocus) {
if (pSubFocus == pDriver->GetFocus()) {
pDriver->SetFocus(nullptr);
} else if (pSubFocus->GetStates() & FWL_WGTSTATE_Focused) {
CFWL_MsgKillFocus ms;
IFWL_WidgetDelegate* pDelegate = pSubFocus->SetDelegate(nullptr);
if (pDelegate)
pDelegate->OnProcessMessage(&ms);
}
}
m_pOwner->Repaint(&m_pOwner->m_rtRelative);
break;
}
case CFWL_MessageType::Mouse: {
CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
switch (pMsg->m_dwCmd) {
case FWL_MouseCommand::LeftButtonDown: {
OnLButtonDown(pMsg);
break;
}
case FWL_MouseCommand::LeftButtonUp: {
OnLButtonUp(pMsg);
break;
}
case FWL_MouseCommand::Move: {
OnMouseMove(pMsg);
break;
}
case FWL_MouseCommand::Hover: {
OnMouseHover(pMsg);
break;
}
case FWL_MouseCommand::Leave: {
OnMouseLeave(pMsg);
break;
}
case FWL_MouseCommand::LeftButtonDblClk: {
OnLButtonDblClk(pMsg);
break;
}
default:
break;
}
break;
}
case CFWL_MessageType::Size: {
CFWL_WidgetMgr* pWidgetMgr = CFWL_WidgetMgr::GetInstance();
if (!pWidgetMgr)
return;
pWidgetMgr->AddRedrawCounts(m_pOwner);
if (!m_pOwner->m_bSetMaximize)
break;
m_pOwner->m_bSetMaximize = FALSE;
CFWL_MsgSize* pMsg = static_cast<CFWL_MsgSize*>(pMessage);
m_pOwner->m_pProperties->m_rtWidget.left = 0;
m_pOwner->m_pProperties->m_rtWidget.top = 0;
m_pOwner->m_pProperties->m_rtWidget.width = (FX_FLOAT)pMsg->m_iWidth;
m_pOwner->m_pProperties->m_rtWidget.height = (FX_FLOAT)pMsg->m_iHeight;
m_pOwner->Update();
break;
}
case CFWL_MessageType::WindowMove: {
OnWindowMove(static_cast<CFWL_MsgWindowMove*>(pMessage));
break;
}
case CFWL_MessageType::Close: {
OnClose(static_cast<CFWL_MsgClose*>(pMessage));
break;
}
default: { break; }
}
}
#endif // FWL_UseMacSystemBorder
void CFWL_FormImpDelegate::OnProcessEvent(CFWL_Event* pEvent) {}
void CFWL_FormImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
const CFX_Matrix* pMatrix) {
m_pOwner->DrawWidget(pGraphics, pMatrix);
}
void CFWL_FormImpDelegate::OnLButtonDown(CFWL_MsgMouse* pMsg) {
m_pOwner->SetGrab(TRUE);
m_pOwner->m_bLButtonDown = TRUE;
m_pOwner->m_eResizeType = FORM_RESIZETYPE_None;
CFWL_SysBtn* pPressBtn = m_pOwner->GetSysBtnAtPoint(pMsg->m_fx, pMsg->m_fy);
m_pOwner->m_iCaptureBtn = m_pOwner->GetSysBtnIndex(pPressBtn);
CFX_RectF rtCap;
rtCap.Set(m_pOwner->m_rtCaption.left + m_pOwner->m_fCYBorder,
m_pOwner->m_rtCaption.top + m_pOwner->m_fCXBorder,
m_pOwner->m_rtCaption.width -
kSystemButtonSize * m_pOwner->m_iSysBox -
2 * m_pOwner->m_fCYBorder,
m_pOwner->m_rtCaption.height - m_pOwner->m_fCXBorder);
if (pPressBtn) {
pPressBtn->SetPressed();
m_pOwner->Repaint(&pPressBtn->m_rtBtn);
} else if (rtCap.Contains(pMsg->m_fx, pMsg->m_fy)) {
m_pOwner->m_eResizeType = FORM_RESIZETYPE_Cap;
} else if ((m_pOwner->m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) &&
(m_pOwner->m_pProperties->m_dwStyleExes &
FWL_STYLEEXT_FRM_Resize) &&
!m_pOwner->m_bMaximized) {
m_pOwner->SetCursor(pMsg->m_fx, pMsg->m_fy);
}
m_pOwner->m_InfoStart.m_ptStart = CFX_PointF(pMsg->m_fx, pMsg->m_fy);
m_pOwner->m_InfoStart.m_szStart =
CFX_SizeF(m_pOwner->m_pProperties->m_rtWidget.width,
m_pOwner->m_pProperties->m_rtWidget.height);
}
void CFWL_FormImpDelegate::OnLButtonUp(CFWL_MsgMouse* pMsg) {
m_pOwner->SetGrab(FALSE);
m_pOwner->m_bLButtonDown = FALSE;
CFWL_SysBtn* pPointBtn = m_pOwner->GetSysBtnAtPoint(pMsg->m_fx, pMsg->m_fy);
CFWL_SysBtn* pPressedBtn =
m_pOwner->GetSysBtnByIndex(m_pOwner->m_iCaptureBtn);
if (!pPressedBtn || pPointBtn != pPressedBtn) {
return;
}
if (pPressedBtn == m_pOwner->GetSysBtnByState(FWL_SYSBUTTONSTATE_Pressed)) {
pPressedBtn->SetNormal();
}
if (pPressedBtn == m_pOwner->m_pMaxBox) {
if (m_pOwner->m_bMaximized) {
m_pOwner->SetWidgetRect(m_pOwner->m_rtRestore);
m_pOwner->Update();
m_pOwner->Repaint();
} else {
m_pOwner->SetWorkAreaRect();
m_pOwner->Update();
}
m_pOwner->m_bMaximized = !m_pOwner->m_bMaximized;
} else if (pPressedBtn != m_pOwner->m_pMinBox) {
CFWL_EvtClose eClose;
eClose.m_pSrcTarget = m_pOwner;
m_pOwner->DispatchEvent(&eClose);
}
}
void CFWL_FormImpDelegate::OnMouseMove(CFWL_MsgMouse* pMsg) {
if (m_pOwner->m_bLButtonDown) {
return;
}
if ((m_pOwner->m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) &&
(m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_FRM_Resize) &&
!m_pOwner->m_bMaximized) {
m_pOwner->SetCursor(pMsg->m_fx, pMsg->m_fy);
}
CFX_RectF rtInvalidate;
rtInvalidate.Reset();
CFWL_SysBtn* pPointBtn = m_pOwner->GetSysBtnAtPoint(pMsg->m_fx, pMsg->m_fy);
CFWL_SysBtn* pOldHover = m_pOwner->GetSysBtnByState(FWL_SYSBUTTONSTATE_Hover);
#if (_FX_OS_ == _FX_MACOSX_)
{
if (pOldHover && pPointBtn != pOldHover) {
pOldHover->SetNormal();
}
if (pPointBtn && pPointBtn != pOldHover) {
pPointBtn->SetHover();
}
if (m_pOwner->m_pCloseBox) {
rtInvalidate = m_pOwner->m_pCloseBox->m_rtBtn;
}
if (m_pOwner->m_pMaxBox) {
if (rtInvalidate.IsEmpty()) {
rtInvalidate = m_pOwner->m_pMaxBox->m_rtBtn;
} else {
rtInvalidate.Union(m_pOwner->m_pMaxBox->m_rtBtn);
}
}
if (m_pOwner->m_pMinBox) {
if (rtInvalidate.IsEmpty()) {
rtInvalidate = m_pOwner->m_pMinBox->m_rtBtn;
} else {
rtInvalidate.Union(m_pOwner->m_pMinBox->m_rtBtn);
}
}
if (!rtInvalidate.IsEmpty() &&
rtInvalidate.Contains(pMsg->m_fx, pMsg->m_fy)) {
m_pOwner->m_bMouseIn = TRUE;
}
}
#else
{
if (pOldHover && pPointBtn != pOldHover) {
pOldHover->SetNormal();
rtInvalidate = pOldHover->m_rtBtn;
}
if (pPointBtn && pPointBtn != pOldHover) {
pPointBtn->SetHover();
if (rtInvalidate.IsEmpty()) {
rtInvalidate = pPointBtn->m_rtBtn;
} else {
rtInvalidate.Union(pPointBtn->m_rtBtn);
}
}
}
#endif
if (!rtInvalidate.IsEmpty()) {
m_pOwner->Repaint(&rtInvalidate);
}
}
void CFWL_FormImpDelegate::OnMouseHover(CFWL_MsgMouse* pMsg) {
m_pOwner->SetCursor(pMsg->m_fx, pMsg->m_fy);
}
void CFWL_FormImpDelegate::OnMouseLeave(CFWL_MsgMouse* pMsg) {
CFWL_SysBtn* pHover = m_pOwner->GetSysBtnByState(FWL_SYSBUTTONSTATE_Hover);
if (pHover) {
pHover->SetNormal();
m_pOwner->Repaint(&pHover->m_rtBtn);
}
if (pMsg->m_dwCmd == FWL_MouseCommand::Leave && !m_pOwner->m_bLButtonDown) {
m_pOwner->SetCursor(pMsg->m_fx, pMsg->m_fy);
}
}
void CFWL_FormImpDelegate::OnLButtonDblClk(CFWL_MsgMouse* pMsg) {
if ((m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_FRM_Resize) &&
m_pOwner->HitTest(pMsg->m_fx, pMsg->m_fy) == FWL_WidgetHit::Titlebar) {
if (m_pOwner->m_bMaximized) {
m_pOwner->SetWidgetRect(m_pOwner->m_rtRestore);
} else {
m_pOwner->SetWorkAreaRect();
}
m_pOwner->Update();
m_pOwner->m_bMaximized = !m_pOwner->m_bMaximized;
}
}
void CFWL_FormImpDelegate::OnWindowMove(CFWL_MsgWindowMove* pMsg) {
m_pOwner->m_pProperties->m_rtWidget.left = pMsg->m_fx;
m_pOwner->m_pProperties->m_rtWidget.top = pMsg->m_fy;
}
void CFWL_FormImpDelegate::OnClose(CFWL_MsgClose* pMsg) {
CFWL_EvtClose eClose;
eClose.m_pSrcTarget = m_pOwner;
m_pOwner->DispatchEvent(&eClose);
}
CFWL_SysBtn::CFWL_SysBtn() {
m_rtBtn.Set(0, 0, 0, 0);
m_dwState = 0;
}
bool CFWL_SysBtn::IsDisabled() const {
return !!(m_dwState & FWL_SYSBUTTONSTATE_Disabled);
}
void CFWL_SysBtn::SetNormal() {
m_dwState &= 0xFFF0;
}
void CFWL_SysBtn::SetPressed() {
SetNormal();
m_dwState |= FWL_SYSBUTTONSTATE_Pressed;
}
void CFWL_SysBtn::SetHover() {
SetNormal();
m_dwState |= FWL_SYSBUTTONSTATE_Hover;
}
void CFWL_SysBtn::SetDisabled(FX_BOOL bDisabled) {
bDisabled ? m_dwState |= FWL_SYSBUTTONSTATE_Disabled
: m_dwState &= ~FWL_SYSBUTTONSTATE_Disabled;
}
uint32_t CFWL_SysBtn::GetPartState() const {
if (IsDisabled())
return CFWL_PartState_Disabled;
if (m_dwState & FWL_SYSBUTTONSTATE_Pressed)
return CFWL_PartState_Pressed;
if (m_dwState & FWL_SYSBUTTONSTATE_Hover)
return CFWL_PartState_Hovered;
return CFWL_PartState_Normal;
}