wxwidgets/src/aui/tabartmsw.cpp
Vadim Zeitlin 43ff845e77 Remove Windows XP and Vista support
Supporting XP requires too many hacks, and while it wouldn't be very
difficult to support Vista as long as we support Windows 7, it's still
not worth it because nobody uses this system anyhow.

Remove most of XP-specific code and don't use wxDynamicLibrary for using
the functions not present in it any longer.

Don't use <wspiapi.h> neither as we shouldn't use it any more.

Update some comments to not mention Windows versions not supported any
longer and also remove mentions of "Vista and newer Windows versions"
from the documentation as this is now always the case.

This commit is best viewed ignoring whitespace-only changes.
2022-11-12 16:57:52 +00:00

461 lines
12 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/aui/tabartmsw.cpp
// Purpose: wxAuiMSWTabArt implementation
// Author: Tobias Taschner
// Created: 2015-09-26
// Copyright: (c) 2015 wxWidgets development team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#if wxUSE_AUI && wxUSE_UXTHEME && !defined(__WXUNIVERSAL__)
#ifndef WX_PRECOMP
#include "wx/dc.h"
#include "wx/settings.h"
#endif
#include "wx/aui/tabart.h"
#include "wx/aui/auibook.h"
#include "wx/msw/uxtheme.h"
#include "wx/msw/private.h"
#include "wx/renderer.h"
wxAuiMSWTabArt::wxAuiMSWTabArt()
{
m_closeBtnSize = wxDefaultSize;
m_maxTabHeight = 0;
m_themed = wxUxThemeIsActive();
}
wxAuiMSWTabArt::~wxAuiMSWTabArt()
{
}
wxAuiTabArt* wxAuiMSWTabArt::Clone()
{
return new wxAuiMSWTabArt(*this);
}
void wxAuiMSWTabArt::DrawBorder(wxDC& dc, wxWindow* wnd, const wxRect& rect)
{
if ( !IsThemed() )
{
wxAuiGenericTabArt::DrawBorder(dc, wnd, rect);
return;
}
wxRect drawRect(rect);
drawRect.y += m_maxTabHeight + wnd->FromDIP(1);
drawRect.height -= m_maxTabHeight;
// Mask border not covered by native theme
wxRect topDrawRect(rect);
topDrawRect.height = drawRect.height;
dc.SetPen(wxPen(wnd->GetBackgroundColour(), GetBorderWidth(wnd)));
dc.DrawRectangle(topDrawRect);
RECT r;
wxCopyRectToRECT(drawRect, r);
wxUxThemeHandle hTheme(wnd, L"TAB");
::DrawThemeBackground(
hTheme,
GetHdcOf(dc.GetTempHDC()),
TABP_PANE,
0,
&r,
nullptr);
}
void wxAuiMSWTabArt::DrawBackground(wxDC& dc,
wxWindow* wnd,
const wxRect& rect)
{
if ( !IsThemed() )
{
wxAuiGenericTabArt::DrawBackground(dc, wnd, rect);
return;
}
int borderHeight = 2;
wxRect drawRect = rect;
drawRect.height -= borderHeight;
// Draw background
dc.SetBrush(wxBrush(wnd->GetBackgroundColour()));
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(drawRect);
// Draw top border
drawRect.y = drawRect.height;
drawRect.height = borderHeight + 2;
drawRect.Inflate(1, 0);
RECT r;
wxCopyRectToRECT(drawRect, r);
wxUxThemeHandle hTheme(wnd, L"TAB");
::DrawThemeBackground(
hTheme,
GetHdcOf(dc.GetTempHDC()),
TABP_PANE,
0,
&r,
nullptr);
}
void wxAuiMSWTabArt::DrawTab(wxDC& dc,
wxWindow* wnd,
const wxAuiNotebookPage& page,
const wxRect& in_rect,
int close_button_state,
wxRect* out_tab_rect,
wxRect* out_button_rect,
int* x_extent)
{
if ( !IsThemed() )
{
wxAuiGenericTabArt::DrawTab(dc, wnd, page, in_rect, close_button_state, out_tab_rect, out_button_rect, x_extent);
return;
}
if ( !m_closeBtnSize.IsFullySpecified() )
InitSizes(wnd, dc);
// figure out the size of the tab
wxSize tabSize = GetTabSize(dc,
wnd,
page.caption,
page.bitmap,
page.active,
close_button_state,
x_extent);
wxCoord tabHeight = tabSize.y;
wxCoord tabWidth = tabSize.x;
wxCoord tabX = in_rect.x;
wxCoord tabY = 0;
if (!page.active)
{
tabY += wnd->FromDIP(2);
tabHeight -= wnd->FromDIP(2);
}
else
{
tabX -= wnd->FromDIP(2);
tabWidth += wnd->FromDIP(4);
tabHeight += 2;
}
int clipWidth = tabWidth;
if ( tabX + clipWidth > in_rect.x + in_rect.width )
clipWidth = (in_rect.x + in_rect.width) - tabX;
dc.SetClippingRegion(tabX - wnd->FromDIP(2), tabY, clipWidth + wnd->FromDIP(4), tabHeight);
// draw tab
wxRect tabRect(tabX, tabY, tabWidth, tabHeight);
int tabState;
if ( page.active )
tabState = TIS_SELECTED;
else if ( page.hover )
tabState = TIS_HOT;
else
tabState = TIS_NORMAL;
wxUxThemeHandle hTabTheme(wnd, L"Tab");
RECT tabR;
wxCopyRectToRECT(tabRect, tabR);
::DrawThemeBackground(hTabTheme, GetHdcOf(dc.GetTempHDC()), TABP_TABITEM,
tabState,
&tabR, nullptr);
// Apparently, in at least some Windows 10 installations the call above
// does not draw the left edge of the first tab and it needs to be drawn
// separately, or it wouldn't be drawn at all.
if ( tabX == GetIndentSize() )
{
::DrawThemeBackground
(
hTabTheme,
GetHdcOf(dc.GetTempHDC()),
TABP_TABITEMLEFTEDGE,
tabState,
&tabR,
nullptr
);
}
wxRect textRect = tabRect;
if ( !page.active )
textRect.Offset(0, wnd->FromDIP(1));
if ( close_button_state != wxAUI_BUTTON_STATE_HIDDEN )
textRect.width -= m_closeBtnSize.x + wnd->FromDIP(3);
dc.SetFont(wnd->GetFont());
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
dc.DrawLabel(page.caption, page.bitmap.GetBitmapFor(wnd), textRect, wxALIGN_CENTRE);
// draw focus rectangle
if ( page.active && (wnd->FindFocus() == wnd) )
{
wxRect focusRect = tabRect;
focusRect.Deflate(wnd->FromDIP(2));
wxRendererNative::Get().DrawFocusRect(wnd, dc, focusRect, 0);
}
// draw close button
if ( close_button_state != wxAUI_BUTTON_STATE_HIDDEN )
{
wxUxThemeHandle hToolTipTheme(wnd, L"TOOLTIP");
int btnState;
if ( close_button_state == wxAUI_BUTTON_STATE_HOVER )
btnState = TTCS_HOT;
else if ( close_button_state == wxAUI_BUTTON_STATE_PRESSED )
btnState = TTCS_PRESSED;
else
btnState = TTCS_NORMAL;
wxRect rect(tabX + tabWidth - m_closeBtnSize.x - wnd->FromDIP(4),
tabY + (tabHeight / 2) - (m_closeBtnSize.y / 2),
m_closeBtnSize.x,
m_closeBtnSize.y);
RECT btnR;
wxCopyRectToRECT(rect, btnR);
::DrawThemeBackground(hToolTipTheme, GetHdcOf(dc.GetTempHDC()), TTP_CLOSE, btnState, &btnR, nullptr);
if ( out_button_rect )
*out_button_rect = rect;
}
*out_tab_rect = wxRect(tabX, tabY, tabWidth, tabHeight);
dc.DestroyClippingRegion();
}
int wxAuiMSWTabArt::GetIndentSize()
{
if ( IsThemed() )
return wxWindow::FromDIP(3, nullptr); // This should be 1 but we can't draw into the border from DrawTab
else
return wxAuiGenericTabArt::GetIndentSize();
}
int wxAuiMSWTabArt::GetBorderWidth(wxWindow* wnd)
{
return wxAuiGenericTabArt::GetBorderWidth(wnd);
}
int wxAuiMSWTabArt::GetAdditionalBorderSpace(wxWindow* wnd)
{
if ( IsThemed() )
{
return wnd->FromDIP(4, nullptr);
}
else
return wxAuiGenericTabArt::GetAdditionalBorderSpace(wnd);
}
wxSize wxAuiMSWTabArt::GetTabSize(wxDC& dc,
wxWindow* wnd,
const wxString& caption,
const wxBitmapBundle& bitmap,
bool active,
int close_button_state,
int* x_extent)
{
if ( !IsThemed() )
return wxAuiGenericTabArt::GetTabSize(dc, wnd, caption, bitmap, active, close_button_state, x_extent);
if ( !m_closeBtnSize.IsFullySpecified() )
InitSizes(wnd, dc);
wxCoord textWidth, textHeight, tmp;
dc.SetFont(wnd->GetFont());
dc.GetTextExtent(caption, &textWidth, &tmp);
dc.GetTextExtent("ABCDEFXj", &tmp, &textHeight);
wxCoord tabWidth = wxMax(m_tabSize.x, textWidth);
wxCoord tabHeight = wxMax(m_tabSize.y, textHeight);
// if the close button is showing, add space for it
if ( close_button_state != wxAUI_BUTTON_STATE_HIDDEN )
{
tabWidth += m_closeBtnSize.x;
tabHeight = wxMax(tabHeight, m_closeBtnSize.y);
}
// if there's a bitmap, add space for it
if ( bitmap.IsOk() )
{
const wxSize bitmapSize = bitmap.GetPreferredLogicalSizeFor(wnd);
tabWidth += bitmapSize.x + wnd->FromDIP(3); // bitmap padding
tabHeight = wxMax(tabHeight, bitmapSize.y + wnd->FromDIP(2));
}
// add padding
tabWidth += wnd->FromDIP(12);
tabHeight += wnd->FromDIP(3);
if ( m_flags & wxAUI_NB_TAB_FIXED_WIDTH )
{
tabWidth = m_fixedTabWidth;
}
else
{
int minTabWidth = wnd->FromDIP(46);
if (tabWidth < minTabWidth)
tabWidth = minTabWidth;
}
*x_extent = tabWidth;
if (tabHeight > m_maxTabHeight)
m_maxTabHeight = tabHeight;
return wxSize(tabWidth, tabHeight);
}
void wxAuiMSWTabArt::DrawButton(wxDC& dc,
wxWindow* wnd,
const wxRect& in_rect,
int bitmap_id,
int button_state,
int orientation,
wxRect* out_rect)
{
if ( !IsThemed() )
{
wxAuiGenericTabArt::DrawButton(dc, wnd, in_rect, bitmap_id, button_state, orientation, out_rect);
return;
}
const wchar_t* themeId = nullptr;
int part = 0;
switch (bitmap_id)
{
case wxAUI_BUTTON_CLOSE:
themeId = L"Window";
part = WP_CLOSEBUTTON;
break;
case wxAUI_BUTTON_LEFT:
themeId = L"Spin";
part = SPNP_DOWNHORZ;
break;
case wxAUI_BUTTON_RIGHT:
themeId = L"Spin";
part = SPNP_UPHORZ;
break;
case wxAUI_BUTTON_WINDOWLIST:
themeId = L"Combobox";
part = CP_DROPDOWNBUTTON;
break;
}
wxRect rect = in_rect;
if ( orientation == wxLEFT )
{
rect.SetX(in_rect.x);
rect.SetY(((in_rect.y + in_rect.height) / 2) - (m_closeBtnSize.GetHeight() / 2));
rect.SetWidth(m_closeBtnSize.GetWidth());
rect.SetHeight(m_closeBtnSize.GetHeight());
}
else
{
rect = wxRect(in_rect.x + in_rect.width - m_closeBtnSize.GetWidth(),
((in_rect.y + in_rect.height) / 2) - (m_closeBtnSize.GetHeight() / 2),
m_closeBtnSize.GetWidth(), m_closeBtnSize.GetHeight());
}
if ( bitmap_id == wxAUI_BUTTON_LEFT ||
bitmap_id == wxAUI_BUTTON_RIGHT )
{
rect.y = in_rect.y;
rect.height = in_rect.height - wnd->FromDIP(7);
}
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(m_baseColour));
dc.DrawRectangle(rect);
int btnState;
if ( button_state == wxAUI_BUTTON_STATE_DISABLED )
btnState = TTCS_PRESSED + 1;
else if ( button_state == wxAUI_BUTTON_STATE_HOVER )
btnState = TTCS_HOT;
else if ( button_state == wxAUI_BUTTON_STATE_PRESSED )
btnState = TTCS_PRESSED;
else
btnState = TTCS_NORMAL;
wxUxThemeHandle hTheme(wnd, themeId);
wxRect btnRect(rect);
btnRect.width -= wnd->FromDIP(1);
RECT btnR;
wxCopyRectToRECT(btnRect, btnR);
::DrawThemeBackground(hTheme, GetHdcOf(dc.GetTempHDC()), part, btnState, &btnR, nullptr);
if ( out_rect )
*out_rect = rect;
}
int wxAuiMSWTabArt::ShowDropDown(wxWindow* wnd,
const wxAuiNotebookPageArray& pages,
int active_idx)
{
return wxAuiGenericTabArt::ShowDropDown(wnd, pages, active_idx);
}
int wxAuiMSWTabArt::GetBestTabCtrlSize(wxWindow* wnd,
const wxAuiNotebookPageArray& pages,
const wxSize& requiredBmp_size)
{
return wxAuiGenericTabArt::GetBestTabCtrlSize(wnd, pages, requiredBmp_size);
}
void wxAuiMSWTabArt::InitSizes(wxWindow* wnd, wxDC& dc)
{
SIZE uxSize;
// Borrow close button from tooltip (best fit on various backgrounds)
wxUxThemeHandle hTooltipTheme(wnd, L"Tooltip");
::GetThemePartSize(hTooltipTheme, GetHdcOf(dc.GetTempHDC()),
TTP_CLOSE, 0, nullptr, TS_TRUE, &uxSize);
m_closeBtnSize.Set(uxSize.cx, uxSize.cy);
wxUxThemeHandle hTabTheme(wnd, L"Tab");
::GetThemePartSize(hTabTheme, GetHdcOf(dc.GetTempHDC()),
TABP_TABITEM, 0, nullptr, TS_TRUE, &uxSize);
m_tabSize.Set(uxSize.cx, uxSize.cy);
}
bool wxAuiMSWTabArt::IsThemed() const
{
return
m_themed &&
!(m_flags & wxAUI_NB_BOTTOM); // Native theme does not support bottom tabs
}
#endif // wxUSE_AUI && wxUSE_UXTHEME && !defined(__WXUNIVERSAL__)