You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

666 lines
17 KiB
C++

// XTPMarkupButton.cpp: implementation of the CXTPMarkupButton class.
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPWinThemeWrapper.h"
#include "XTPMarkupObject.h"
#include "XTPMarkupInputElement.h"
#include "XTPMarkupUIElement.h"
#include "XTPMarkupFrameworkElement.h"
#include "XTPMarkupControl.h"
#include "XTPMarkupButton.h"
#include "XTPMarkupDrawingContext.h"
#include "XTPMarkupThickness.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////////
// CXTPMarkupButtonBase
CXTPMarkupRoutedEvent* CXTPMarkupButtonBase::m_pClickEvent = NULL;
CXTPMarkupDependencyProperty* CXTPMarkupButtonBase::m_pIsPressedProperty = NULL;
IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupButtonBase, CXTPMarkupContentControl)
void CXTPMarkupButtonBase::RegisterMarkupClass()
{
m_pClickEvent = CXTPMarkupRoutedEvent::RegisterRoutedEvent(L"Click", CXTPMarkupRoutedEvent::routingBubble, MARKUP_TYPE(CXTPMarkupButtonBase));
m_pIsPressedProperty = CXTPMarkupDependencyProperty::Register(L"IsPressed", MARKUP_TYPE(CXTPMarkupBool), MARKUP_TYPE(CXTPMarkupButtonBase),
new CXTPMarkupPropertyMetadata(CXTPMarkupBool::CreateFalseValue(), CXTPMarkupPropertyMetadata::flagAffectsArrange));
}
CXTPMarkupButtonBase::CXTPMarkupButtonBase()
{
m_bPushed = FALSE;
m_bMouseOver = FALSE;
m_themeButton = new CXTPWinThemeWrapper();
SetValue(m_pFocusableProperty, CXTPMarkupBool::CreateTrueValue());
}
CXTPMarkupButtonBase::~CXTPMarkupButtonBase()
{
SAFE_DELETE(m_themeButton);
}
void CXTPMarkupButtonBase::OnMouseLeave(CXTPMarkupMouseEventArgs* e)
{
m_bMouseOver = FALSE;
if (m_bPushed)
{
SetValue(m_pIsPressedProperty, NULL);
}
else
{
CXTPMarkupContentControl::OnMouseLeave(e);
InvalidateVisual();
}
}
void CXTPMarkupButtonBase::OnMouseEnter(CXTPMarkupMouseEventArgs* e)
{
m_bMouseOver = TRUE;
if (m_bPushed)
{
SetValue(m_pIsPressedProperty, CXTPMarkupBool::CreateTrueValue());
}
else
{
CXTPMarkupContentControl::OnMouseEnter(e);
InvalidateVisual();
}
}
void CXTPMarkupButtonBase::OnLostMouseCapture(CXTPMarkupMouseEventArgs* /*e*/)
{
SetPressed(FALSE);
}
void CXTPMarkupButtonBase::SetPressed(BOOL bPressed)
{
if (!bPressed && m_bPushed)
{
m_bPushed = FALSE;
SetValue(m_pIsPressedProperty, NULL);
if (!m_bMouseOver && IsMouseOver())
{
SetValue(m_pIsMouseOverProperty, NULL);
InvalidateVisual();
}
}
else if (bPressed && !m_bPushed)
{
m_bPushed = TRUE;
SetValue(m_pIsPressedProperty, CXTPMarkupBool::CreateTrueValue());
}
}
void CXTPMarkupButtonBase::OnMouseLeftButtonUp(CXTPMarkupMouseButtonEventArgs* e)
{
if (m_bPushed)
{
ReleaseMouseCapture();
SetPressed(FALSE);
if (m_bMouseOver)
{
OnClick();
}
e->SetHandled();
}
}
void CXTPMarkupButtonBase::OnMouseLeftButtonDown(CXTPMarkupMouseButtonEventArgs* e)
{
e->SetHandled();
if (!IsEnabled())
return;
Focus();
SetPressed(TRUE);
CaptureMouse();
}
void CXTPMarkupButtonBase::OnClick()
{
CXTPMarkupRoutedEventArgs* e = new CXTPMarkupRoutedEventArgs(m_pClickEvent, this);
RaiseEvent(e);
e->Release();
}
//////////////////////////////////////////////////////////////////////////
// CXTPMarkupButton
CXTPMarkupButton::CXTPMarkupButton()
{
}
CXTPMarkupButton::~CXTPMarkupButton()
{
}
IMPLEMENT_MARKUPCLASS(L"Button", CXTPMarkupButton, CXTPMarkupButtonBase)
void CXTPMarkupButton::RegisterMarkupClass()
{
}
CSize CXTPMarkupButton::ArrangeOverride(CSize szFinalSize)
{
CXTPMarkupUIElement* pContent = GetContent();
if (pContent != NULL)
{
CRect rt(0, 0, szFinalSize.cx, szFinalSize.cy);
if (IsPressed() && (!m_themeButton->IsAppThemed() || GetValue(m_pBackgroundProperty) != NULL))
{
rt.OffsetRect(1, 1);
}
CRect finalRect = CXTPMarkupThickness::HelperDeflateRect(rt, GetPadding());
finalRect.DeflateRect(4, 4);
pContent->Arrange(finalRect);
}
return szFinalSize;
}
CSize CXTPMarkupButton::MeasureOverride(CXTPMarkupDrawingContext* pDC, CSize szAvailableSize)
{
m_themeButton->OpenTheme(0, L"BUTTON");
CSize size3 = GetPadding()->GetSize();
size3.cx += 8;
size3.cy += 8;
CXTPMarkupUIElement* pContent = GetContent();
if (pContent != NULL)
{
CSize availableSize(max(0, szAvailableSize.cx - size3.cx), max(0, szAvailableSize.cy - size3.cy));
pContent->Measure(pDC, availableSize);
CSize desiredSize = pContent->GetDesiredSize();
return CSize(desiredSize.cx + size3.cx, desiredSize.cy + size3.cy);
}
return size3;
}
void CXTPMarkupButton::OnRender(CXTPMarkupDrawingContext* pDC)
{
BOOL bPressed = IsPressed();
BOOL bHot = IsMouseOver();
BOOL bDefault = FALSE;
BOOL bEnabled = IsEnabled();
BOOL bChecked = FALSE;
CRect rc(0, 0, GetRenderSize().cx, GetRenderSize().cy);
CXTPMarkupBrush* pBackground = MARKUP_STATICCAST(CXTPMarkupBrush, GetValue(m_pBackgroundProperty));
if (pBackground == NULL && m_themeButton->IsAppThemed())
{
HDC hDC = pDC->GetDC();
int nState = !bEnabled? PBS_DISABLED: bPressed? PBS_PRESSED: bHot? PBS_HOT: bChecked ? PBS_PRESSED : bDefault? PBS_DEFAULTED: PBS_NORMAL;
m_themeButton->DrawThemeBackground(hDC, BP_PUSHBUTTON, nState, rc, NULL);
pDC->ReleaseDC(hDC);
}
else
{
COLORREF clrLight, clrDark, clrDarkDark, clrBackground;
if (pBackground)
{
clrBackground = pBackground->GetHintColor();
DWORD dwHSLBackground = CXTPDrawHelpers::RGBtoHSL(clrBackground);
DWORD dwL = GetBValue(dwHSLBackground);
DWORD dwLight = (dwL + 240) / 2;
clrLight = CXTPDrawHelpers::HSLtoRGB(RGB(GetRValue(dwHSLBackground), GetGValue(dwHSLBackground), dwLight));
DWORD dwDark = MulDiv(dwL, 2, 3);
clrDark = CXTPDrawHelpers::HSLtoRGB(RGB(GetRValue(dwHSLBackground), GetGValue(dwHSLBackground), dwDark));
clrDarkDark = RGB(GetRValue(clrDark) / 2, GetGValue(clrDark) / 2, GetBValue(clrDark) / 2);
pDC->FillRectangle(rc, pBackground);
}
else
{
clrBackground = GetSysColor(COLOR_3DFACE);
clrLight = GetSysColor(COLOR_WINDOW);
clrDark = GetSysColor(COLOR_BTNSHADOW);
clrDarkDark = GetSysColor(COLOR_3DDKSHADOW);
CXTPMarkupSolidColorBrush brushBackground(clrBackground);
pDC->FillRectangle(rc, &brushBackground);
}
CXTPMarkupSolidColorBrush brushDark(clrDark);
if (bPressed)
{
CXTPMarkupSolidColorBrush brushFrame(GetSysColor(COLOR_WINDOWFRAME));
pDC->DrawFrame(rc, &brushFrame);
rc.DeflateRect(1, 1);
pDC->DrawFrame(rc, &brushDark);
}
else
{
CXTPMarkupSolidColorBrush brushLight(clrLight);
CXTPMarkupSolidColorBrush brushDarkDark(clrDarkDark);
pDC->FillRectangle(CRect(rc.left, rc.top, rc.right, 1), &brushLight);
pDC->FillRectangle(CRect(rc.left, rc.top, rc.left + 1, rc.bottom), &brushLight);
pDC->FillRectangle(CRect(rc.left + 1, rc.bottom - 2, rc.right - 1, rc.bottom - 1), &brushDark);
pDC->FillRectangle(CRect(rc.right - 2, rc.top + 1, rc.right - 1, rc.bottom - 1), &brushDark);
pDC->FillRectangle(CRect(rc.left, rc.bottom - 1, rc.right - 1, rc.bottom), &brushDarkDark);
pDC->FillRectangle(CRect(rc.right - 1, rc.top, rc.right, rc.bottom), &brushDarkDark);
}
}
}
void CXTPMarkupButton::OnRenderFocusVisual(CXTPMarkupDrawingContext* drawingContext)
{
CRect rc(0, 0, GetRenderSize().cx, GetRenderSize().cy);
rc.DeflateRect(3, 3);
HDC hDC = drawingContext->GetDC();
SetTextColor(hDC, 0xFFFFFF);
SetBkColor(hDC, 0);
DrawFocusRect(hDC, rc);
drawingContext->ReleaseDC(hDC);
}
//////////////////////////////////////////////////////////////////////////
// CXTPMarkupToggleButton
CXTPMarkupDependencyProperty* CXTPMarkupToggleButton::m_pIsThreeStateProperty = NULL;
CXTPMarkupDependencyProperty* CXTPMarkupToggleButton::m_pIsCheckedProperty = NULL;
CXTPMarkupRoutedEvent* CXTPMarkupToggleButton::m_pCheckedEvent = NULL;
CXTPMarkupRoutedEvent* CXTPMarkupToggleButton::m_pUncheckedEvent = NULL;
CXTPMarkupRoutedEvent* CXTPMarkupToggleButton::m_pIndeterminateEvent = NULL;
IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupToggleButton, CXTPMarkupButtonBase)
void CXTPMarkupToggleButton::RegisterMarkupClass()
{
m_pCheckedEvent = CXTPMarkupRoutedEvent::RegisterRoutedEvent(L"Checked", CXTPMarkupRoutedEvent::routingBubble, MARKUP_TYPE(CXTPMarkupToggleButton));
m_pUncheckedEvent = CXTPMarkupRoutedEvent::RegisterRoutedEvent(L"Unchecked", CXTPMarkupRoutedEvent::routingBubble, MARKUP_TYPE(CXTPMarkupToggleButton));
m_pIndeterminateEvent = CXTPMarkupRoutedEvent::RegisterRoutedEvent(L"Indeterminate", CXTPMarkupRoutedEvent::routingBubble, MARKUP_TYPE(CXTPMarkupToggleButton));
m_pIsCheckedProperty = CXTPMarkupDependencyProperty::Register(L"IsChecked", MARKUP_TYPE(CXTPMarkupEnum), MARKUP_TYPE(CXTPMarkupToggleButton),
new CXTPMarkupPropertyMetadata(CXTPMarkupEnum::CreateValue(0), &CXTPMarkupToggleButton::ConvertIsChecked, &CXTPMarkupToggleButton::OnIsCheckedChanged, CXTPMarkupPropertyMetadata::flagAffectsRender));
m_pIsThreeStateProperty = CXTPMarkupDependencyProperty::Register(L"IsThreeState", MARKUP_TYPE(CXTPMarkupBool), MARKUP_TYPE(CXTPMarkupToggleButton),
new CXTPMarkupPropertyMetadata(CXTPMarkupBool::CreateFalseValue(), CXTPMarkupPropertyMetadata::flagAffectsRender));
}
CXTPMarkupObject* CXTPMarkupToggleButton::ConvertIsChecked(CXTPMarkupBuilder* /*pBuilder*/, CXTPMarkupObject* pObject)
{
if (IsStringObject(pObject))
{
if (_wcsicmp(*((CXTPMarkupString*)pObject), L"True") == 0)
{
return CXTPMarkupEnum::CreateValue(BST_CHECKED);
}
if (_wcsicmp(*((CXTPMarkupString*)pObject), L"False") == 0)
{
return CXTPMarkupEnum::CreateValue(BST_UNCHECKED);
}
if (_wcsicmp(*((CXTPMarkupString*)pObject), L"") == 0)
{
return CXTPMarkupEnum::CreateValue(BST_INDETERMINATE);
}
}
return NULL;
}
void CXTPMarkupToggleButton::OnClick()
{
OnToggle();
CXTPMarkupButtonBase::OnClick();
}
void CXTPMarkupToggleButton::OnToggle()
{
if (GetChecked() == BST_CHECKED)
{
SetChecked(IsThreeState() ? BST_INDETERMINATE : BST_UNCHECKED);
}
else
{
SetChecked(GetChecked() == BST_INDETERMINATE ? BST_UNCHECKED : BST_CHECKED);
}
}
void CXTPMarkupToggleButton::OnChecked(CXTPMarkupRoutedEventArgs* e)
{
RaiseEvent(e);
}
void CXTPMarkupToggleButton::OnUnchecked(CXTPMarkupRoutedEventArgs* e)
{
RaiseEvent(e);
}
void CXTPMarkupToggleButton::OnIndeterminate(CXTPMarkupRoutedEventArgs* e)
{
RaiseEvent(e);
}
void CXTPMarkupToggleButton::OnIsCheckedChanged(CXTPMarkupObject* d, CXTPMarkupPropertyChangedEventArgs* e)
{
CXTPMarkupToggleButton* pButton = MARKUP_DYNAMICCAST(CXTPMarkupToggleButton, d);
if (!pButton)
return;
CXTPMarkupEnum* pValue = MARKUP_STATICCAST(CXTPMarkupEnum, e->m_pNewValue);
int bValue = pValue != NULL ? (int)*pValue : FALSE;
if (bValue == BST_CHECKED)
{
CXTPMarkupRoutedEventArgs args(CXTPMarkupToggleButton::m_pCheckedEvent, pButton);
pButton->OnChecked(&args);
}
else if (bValue == BST_UNCHECKED)
{
CXTPMarkupRoutedEventArgs args(CXTPMarkupToggleButton::m_pUncheckedEvent, pButton);
pButton->OnUnchecked(&args);
}
else
{
CXTPMarkupRoutedEventArgs args(CXTPMarkupToggleButton::m_pIndeterminateEvent, pButton);
pButton->OnIndeterminate(&args);
}
}
//////////////////////////////////////////////////////////////////////////
// CXTPMarkupCheckBox
IMPLEMENT_MARKUPCLASS(L"CheckBox", CXTPMarkupCheckBox, CXTPMarkupToggleButton)
void CXTPMarkupCheckBox::RegisterMarkupClass()
{
}
CXTPMarkupCheckBox::CXTPMarkupCheckBox()
{
}
CXTPMarkupCheckBox::~CXTPMarkupCheckBox()
{
}
CSize CXTPMarkupCheckBox::ArrangeOverride(CSize szFinalSize)
{
CXTPMarkupUIElement* pContent = GetContent();
if (pContent != NULL)
{
CRect rt(0, 0, szFinalSize.cx, szFinalSize.cy);
CRect finalRect = CXTPMarkupThickness::HelperDeflateRect(rt, GetPadding());
finalRect.DeflateRect(13 + 3, 0, 0, 0);
pContent->Arrange(finalRect);
}
return szFinalSize;
}
CSize CXTPMarkupCheckBox::MeasureOverride(CXTPMarkupDrawingContext* pDC, CSize szAvailableSize)
{
m_themeButton->OpenTheme(0, L"BUTTON");
CSize size3 = GetPadding()->GetSize();
size3.cx += 13 + 3;
CXTPMarkupUIElement* pContent = GetContent();
if (pContent != NULL)
{
CSize availableSize(max(0, szAvailableSize.cx - size3.cx), max(0, szAvailableSize.cy - size3.cy));
pContent->Measure(pDC, availableSize);
CSize desiredSize = pContent->GetDesiredSize();
return CSize(desiredSize.cx + size3.cx, max(13, desiredSize.cy + size3.cy));
}
return size3;
}
void CXTPMarkupCheckBox::OnRender(CXTPMarkupDrawingContext* pDC)
{
BOOL bPressed = IsPressed();
BOOL bHot = IsMouseOver();
BOOL bEnabled = IsEnabled();
BOOL bChecked = GetChecked();
CRect rc(0, GetRenderSize().cy / 2 - 6, 13, GetRenderSize().cy / 2 + 7);
HDC hDC = pDC->GetDC();
if (m_themeButton->IsAppThemed())
{
int nState = !bEnabled? CBS_UNCHECKEDDISABLED: bPressed? CBS_UNCHECKEDPRESSED: bHot?
CBS_UNCHECKEDHOT: CBS_UNCHECKEDNORMAL;
if (bChecked == BST_CHECKED)
nState += 4;
if (bChecked == BST_INDETERMINATE)
nState += 8;
m_themeButton->DrawThemeBackground(hDC, BP_CHECKBOX, nState, rc, NULL);
}
else
{
DrawFrameControl(hDC, rc, DFC_BUTTON, DFCS_BUTTONCHECK | (bPressed ? DFCS_PUSHED : 0)
| (bChecked == BST_CHECKED ? DFCS_CHECKED : 0) | (bChecked == BST_INDETERMINATE ? DFCS_BUTTON3STATE | DFCS_CHECKED : 0));
}
pDC->ReleaseDC(hDC);
}
void CXTPMarkupCheckBox::OnRenderFocusVisual(CXTPMarkupDrawingContext* drawingContext)
{
CRect rc(0, 0, GetRenderSize().cx, GetRenderSize().cy);
CXTPMarkupVisual* pContent = GetContent();
if (!pContent)
return;
rc.left += 13 + 2;
HDC hDC = drawingContext->GetDC();
SetTextColor(hDC, 0xFFFFFF);
SetBkColor(hDC, 0);
DrawFocusRect(hDC, rc);
drawingContext->ReleaseDC(hDC);
}
//////////////////////////////////////////////////////////////////////////
// CXTPMarkupRadioButton
IMPLEMENT_MARKUPCLASS(L"RadioButton", CXTPMarkupRadioButton, CXTPMarkupToggleButton)
void CXTPMarkupRadioButton::RegisterMarkupClass()
{
}
CXTPMarkupRadioButton::CXTPMarkupRadioButton()
{
}
CXTPMarkupRadioButton::~CXTPMarkupRadioButton()
{
}
CSize CXTPMarkupRadioButton::ArrangeOverride(CSize szFinalSize)
{
CXTPMarkupUIElement* pContent = GetContent();
if (pContent != NULL)
{
CRect rt(0, 0, szFinalSize.cx, szFinalSize.cy);
CRect finalRect = CXTPMarkupThickness::HelperDeflateRect(rt, GetPadding());
finalRect.DeflateRect(13 + 3, 0, 0, 0);
pContent->Arrange(finalRect);
}
return szFinalSize;
}
CSize CXTPMarkupRadioButton::MeasureOverride(CXTPMarkupDrawingContext* pDC, CSize szAvailableSize)
{
m_themeButton->OpenTheme(0, L"BUTTON");
CSize size3 = GetPadding()->GetSize();
size3.cx += 13 + 3;
CXTPMarkupUIElement* pContent = GetContent();
if (pContent != NULL)
{
CSize availableSize(max(0, szAvailableSize.cx - size3.cx), max(0, szAvailableSize.cy - size3.cy));
pContent->Measure(pDC, availableSize);
CSize desiredSize = pContent->GetDesiredSize();
return CSize(desiredSize.cx + size3.cx, max(13, desiredSize.cy + size3.cy));
}
return CSize(size3.cx, max(13, size3.cy));
}
void CXTPMarkupRadioButton::OnRender(CXTPMarkupDrawingContext* pDC)
{
BOOL bPressed = IsPressed();
BOOL bHot = IsMouseOver();
BOOL bEnabled = IsEnabled();
BOOL bChecked = GetChecked();
CRect rc(0, GetRenderSize().cy / 2 - 6, 13, GetRenderSize().cy / 2 + 7);
HDC hDC = pDC->GetDC();
if (m_themeButton->IsAppThemed())
{
int nState = !bEnabled? RBS_UNCHECKEDDISABLED: bPressed? RBS_UNCHECKEDPRESSED: bHot?
RBS_UNCHECKEDHOT: RBS_UNCHECKEDNORMAL;
if (bChecked)
nState += 4;
m_themeButton->DrawThemeBackground(hDC, BP_RADIOBUTTON, nState, rc, NULL);
}
else
{
DrawFrameControl(hDC, rc, DFC_BUTTON, DFCS_BUTTONRADIO | (bPressed ? DFCS_PUSHED : 0)
| (bChecked ? DFCS_CHECKED : 0));
}
pDC->ReleaseDC(hDC);
}
void CXTPMarkupRadioButton::OnRenderFocusVisual(CXTPMarkupDrawingContext* drawingContext)
{
CRect rc(0, 0, GetRenderSize().cx, GetRenderSize().cy);
CXTPMarkupVisual* pContent = GetContent();
if (!pContent)
return;
rc.left += 13 + 2;
HDC hDC = drawingContext->GetDC();
SetTextColor(hDC, 0xFFFFFF);
SetBkColor(hDC, 0);
DrawFocusRect(hDC, rc);
drawingContext->ReleaseDC(hDC);
}
void CXTPMarkupRadioButton::OnToggle()
{
SetChecked(TRUE);
}
void CXTPMarkupRadioButton::OnChecked(CXTPMarkupRoutedEventArgs* e)
{
UpdateRadioButtonGroup();
CXTPMarkupToggleButton::OnChecked(e);
}
void CXTPMarkupRadioButton::UpdateRadioButtonGroup()
{
CXTPMarkupVisual* pParent = GetVisualParent();
if (!pParent)
return;
int nCount = pParent->GetVisualChildrenCount();
for (int i = 0; i < nCount; i++)
{
CXTPMarkupRadioButton* pButton = MARKUP_DYNAMICCAST(CXTPMarkupRadioButton, pParent->GetVisualChild(i));
if (pButton && pButton != this && pButton->GetChecked())
{
pButton->SetChecked(FALSE);
}
}
}