1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/components/ThemePageControl.cpp
Martin Prikryl d1bb298c70 Merge branch 'master' into dev
# Conflicts:
#	source/core/Common.cpp
#	source/core/Http.cpp
#	source/core/PuttyIntf.cpp

Source commit: 1ebaa60a257791f90bbc04243bd8a6a7696546de
2026-04-28 07:06:11 +02:00

768 lines
25 KiB
C++

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <Common.h>
#include <vsstyle.h>
#include <memory>
#include <PasTools.hpp>
#include <TBXOfficeXPTheme.hpp>
#include <StrUtils.hpp>
#include <CustomWinConfiguration.h>
#include "ThemePageControl.h"
#include <algorithm>
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Based on
// https://web.archive.org/web/20250809094534/https://www.codeproject.com/Articles/6355/XP-Themes-Tab-Control-in-any-orientation
//---------------------------------------------------------------------------
#define IDS_UTIL_TAB L"TAB"
//---------------------------------------------------------------------------
__fastcall TThemeTabSheet::TThemeTabSheet(TComponent * Owner) :
TTabSheet(Owner)
{
FShadowed = false;
FButton = ttbNone;
FCaptionTruncation = tttNone;
}
//----------------------------------------------------------------------------------------------------------
TThemePageControl * TThemeTabSheet::GetParentPageControl()
{
return DebugNotNull(dynamic_cast<TThemePageControl *>(Parent));
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemeTabSheet::Invalidate()
{
TThemePageControl * ThemePageControl = GetParentPageControl();
if (DebugAlwaysTrue(ThemePageControl != NULL))
{
ThemePageControl->InvalidateTab(TabIndex);
}
else
{
Parent->Invalidate();
}
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemeTabSheet::SetShadowed(bool Value)
{
if (Shadowed != Value)
{
FShadowed = Value;
Invalidate();
}
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemeTabSheet::SetButton(TThemeTabSheetButtons Value)
{
if (Button != Value)
{
FButton = Value;
Invalidate();
}
}
//----------------------------------------------------------------------------------------------------------
void TThemeTabSheet::SetBaseCaption(const UnicodeString & value)
{
if (FBaseCaption != value)
{
FBaseCaption = value;
UpdateCaption();
}
}
//----------------------------------------------------------------------------------------------------------
UnicodeString TThemeTabSheet::TruncatedCaption()
{
UnicodeString Result = FBaseCaption;
TThemePageControl * ParentPageControl = GetParentPageControl();
if (ParentPageControl->FSessionTabShrink > 0)
{
if (FCaptionTruncation == tttNone)
{
// noop
}
else if (FCaptionTruncation == tttEllipsis)
{
if (ParentPageControl->FSessionTabShrink == 1)
{
Result = Result.SubString(1, 1);
}
else if (ParentPageControl->FSessionTabShrink < Result.Length())
{
Result = Result.SubString(1, ParentPageControl->FSessionTabShrink - 1) + Ellipsis;
}
}
else if (DebugAlwaysTrue(FCaptionTruncation == tttNoText))
{
Result = EmptyStr;
}
}
return Result;
}
//----------------------------------------------------------------------------------------------------------
void TThemeTabSheet::UpdateCaption()
{
UnicodeString ACaption = TruncatedCaption();
TThemePageControl * ParentPageControl = GetParentPageControl();
if (UseThemes() && (Button != ttbNone))
{
ParentPageControl->Canvas->Font = ParentPageControl->Font;
int OrigWidth = ParentPageControl->Canvas->TextWidth(ACaption);
int TabButtonWidth = ParentPageControl->TabButtonSize();
int Padding = ScaleByTextHeight(this, 2);
while (ParentPageControl->Canvas->TextWidth(ACaption) < OrigWidth + Padding + TabButtonWidth)
{
ACaption += L" ";
}
}
Caption = ACaption;
ParentPageControl->TabChanged(TabIndex);
}
//----------------------------------------------------------------------------------------------------------
UnicodeString TThemeTabSheet::GetBaseCaption()
{
DebugAssert(StartsStr(FBaseCaption, Caption));
DebugAssert(RightStr(Caption, Caption.Length() - FBaseCaption.Length()).Trim().Length() == 0);
return FBaseCaption;
}
//----------------------------------------------------------------------------------------------------------
void TThemeTabSheet::SetCaptionTruncation(TThemeTabCaptionTruncation Value)
{
if (FCaptionTruncation != Value)
{
FCaptionTruncation = Value;
UpdateCaption();
}
}
//----------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------
__fastcall TThemePageControl::TThemePageControl(TComponent * Owner) :
TPageControl(Owner)
{
FOldTabIndex = -1;
FHotTabButton = -1;
FClickedButton = -1;
FSessionTabShrink = 0;
FOnTabButtonClick = NULL;
FOnTabHint = NULL;
FTabTheme = NULL;
FActiveTabTheme = NULL;
FTextHeight = -1;
}
//----------------------------------------------------------------------------------------------------------
int __fastcall TThemePageControl::GetTabsHeight()
{
// The Calculated height includes tab/contents separator line on Windows 7/8,
// but not on Windows XP
TRect Rect = GetClientRect();
::SendMessage(Handle, TCM_ADJUSTRECT, FALSE, reinterpret_cast<LPARAM>(&Rect));
int Result = Rect.Top - 1;
// Two different ways to calculate the same, not sure which one is more reliable,
// so we want to know in case they differ.
if (DebugAlwaysTrue(PageCount >= 0))
{
TRect Rect2 = TabRect(0);
int Result2 = Rect2.Bottom + 1;
// On Windows 10 with 200% scaling, the first is 40, the second is 42.
// With 250% scaling it's 50 vs 53.
// Using the larger.
if (Result2 > Result)
{
DebugAssert(IsWin10());
Result = Result2;
}
}
return Result;
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::PaintWindow(HDC DC)
{
// Themes not enabled, give up
if (!UseThemes())
{
TPageControl::PaintWindow(DC);
return;
}
HTHEME Theme = OpenThemeData(NULL, IDS_UTIL_TAB);
// TODO use GetClipBox
TRect PageRect = GetClientRect();
// 1st paint the tab body
TRect ClientRect = PageRect;
::SendMessage(Handle, TCM_ADJUSTRECT, FALSE, reinterpret_cast<LPARAM>(&PageRect));
ClientRect.Top = PageRect.Top - 2;
DrawThemeBackground(Theme, DC, TABP_PANE, 0, &ClientRect, NULL);
// 2nd paint the inactive tabs
int SelectedIndex = TabIndex; // optimization
std::unique_ptr<TCanvas> ACanvas(new TCanvas());
ACanvas->Handle = DC;
ACanvas->Font = Font;
FTextHeight = CalculateTextHeight(ACanvas.get());
for (int Tab = 0; Tab < PageCount; Tab++)
{
if (Tab != SelectedIndex)
{
DrawThemesXpTab(DC, Theme, Tab);
}
}
if (SelectedIndex >= 0)
{
DrawThemesXpTab(DC, Theme, SelectedIndex);
}
CloseThemeData(Theme);
}
//----------------------------------------------------------------------------------------------------------
TThemeTabSheetButtons __fastcall TThemePageControl::GetTabButton(int Index)
{
TThemeTabSheet * ThemeTabSheet = dynamic_cast<TThemeTabSheet *>(Pages[Index]);
return (UseThemes() && (ThemeTabSheet != NULL)) ? ThemeTabSheet->Button : ttbNone;
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::DrawThemesXpTab(HDC DC, HTHEME Theme, int Tab)
{
TThemeTabSheet * ThemeTabSheet = dynamic_cast<TThemeTabSheet *>(Pages[Tab]);
bool Shadowed = (ThemeTabSheet != NULL) ? ThemeTabSheet->Shadowed : false;
TRect Rect = TabRect(Tab);
ItemTabRect(Tab, Rect);
int State;
TTBXTheme * ATabTheme;
if (Tab != TabIndex)
{
TPoint Point = ScreenToClient(Mouse->CursorPos);
int HotIndex = IndexOfTabAt(Point.X, Point.Y);
State = (Tab == HotIndex ? TIS_HOT : (Shadowed ? TIS_DISABLED : TIS_NORMAL));
ATabTheme = TabTheme;
}
else
{
State = TIS_SELECTED;
ATabTheme = (ActiveTabTheme != NULL) ? ActiveTabTheme : TabTheme;
}
DrawThemesXpTabItem(DC, Theme, Tab, Rect, State, Shadowed, ATabTheme);
}
//----------------------------------------------------------------------------------------------------------
static TTBXItemInfo GetItemInfo(int State)
{
TTBXItemInfo ItemInfo;
memset(&ItemInfo, 0, sizeof(ItemInfo));
ItemInfo.Enabled = true;
ItemInfo.ViewType =
VT_TOOLBAR | TVT_EMBEDDED |
FLAGMASK(State == TIS_SELECTED, ISF_SELECTED);
return ItemInfo;
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::DrawThemesXpTabItem(
HDC DC, HTHEME Theme, int Item, const TRect & Rect, int State, bool Shadowed, TTBXTheme * ATabTheme)
{
TRect PaintRect = Rect;
if ((State == TIS_SELECTED) || (ATabTheme != NULL))
{
PaintRect.Bottom++;
}
if (ATabTheme != NULL)
{
std::unique_ptr<TCanvas> CanvasMem(new TCanvas());
CanvasMem->Handle = DC;
ATabTheme->PaintFrame(CanvasMem.get(), PaintRect, GetItemInfo(State));
}
else
{
int PartID = (Item == 0) ? TABP_TABITEMLEFTEDGE : TABP_TABITEM;
DrawThemeBackground(Theme, DC, PartID, State, &PaintRect, NULL);
}
if (Item >= 0)
{
DrawTabItem(DC, Item, Rect, State, Shadowed, ATabTheme);
}
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::ItemTabRect(int Item, TRect & Rect)
{
if (Item == TabIndex)
{
// Countered in TabButtonRect
Rect.Inflate(2, 2);
Rect.Bottom--;
}
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::ItemContentsRect(int Item, TRect & Rect)
{
Rect.Left += 6;
Rect.Right -= 3;
if (Item == TabIndex)
{
// to counter the ItemTabRect
Rect.Left += 2;
Rect.Right -= 2;
Rect.Bottom++;
Rect.Bottom -= 2;
}
}
//----------------------------------------------------------------------------------------------------------
bool __fastcall TThemePageControl::HasItemImage(int Item)
{
return (Images != NULL) && (Pages[Item]->ImageIndex >= 0);
}
//----------------------------------------------------------------------------------------------------------
void TThemePageControl::DrawCross(HDC DC, int Width, COLORREF Color, const TRect & Rect)
{
HPEN Pen = CreatePen(PS_SOLID, Width, Color);
HPEN OldPen = static_cast<HPEN>(SelectObject(DC, Pen));
// To-and-back - to make both ends look the same
MoveToEx(DC, Rect.Left, Rect.Bottom - 1, NULL);
LineTo(DC, Rect.Right - 1, Rect.Top);
LineTo(DC, Rect.Left, Rect.Bottom - 1);
MoveToEx(DC, Rect.Left, Rect.Top, NULL);
LineTo(DC, Rect.Right - 1, Rect.Bottom - 1);
LineTo(DC, Rect.Left, Rect.Top);
SelectObject(DC, OldPen);
DeleteObject(Pen);
}
//----------------------------------------------------------------------------------------------------------
void TThemePageControl::DrawDropDown(HDC DC, int Radius, int X, int Y, COLORREF Color, int Grow)
{
// Optimized for even-sized Rect (100% scaling), may need adjustments for even-sized to correctly center
TPoint Points[] = {
Point(X - Radius - 1 - Grow, Y), Point(X + Radius + Grow, Y),
Point(X, Y + Radius + Grow), Point(X - 1, Y + Radius + Grow)
};
HBRUSH Brush = CreateSolidBrush(Color);
HPEN Pen = CreatePen(PS_SOLID, 1, Color);
HGDIOBJ OldBrush = SelectObject(DC, Brush);
HGDIOBJ OldPen = SelectObject(DC, Pen);
Polygon(DC, Points, std::size(Points));
SelectObject(DC, OldPen);
SelectObject(DC, OldBrush);
DeleteObject(Brush);
DeleteObject(Pen);
}
//----------------------------------------------------------------------------------------------------------
static int VCenter(const TRect & Rect, int Height)
{
int A = (Rect.Top + Rect.Bottom - Height);
return (A / 2) + (A % 2);
}
//----------------------------------------------------------------------------------------------------------
// Draw tab item context: possible icon and text
void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect, int State, bool Shadowed, TTBXTheme * ATabTheme)
{
TRect OrigRect = Rect;
ItemContentsRect(Item, Rect);
UnicodeString Text = Pages[Item]->Caption;
std::unique_ptr<TCanvas> Canvas(new TCanvas());
Canvas->Handle = DC;
if (HasItemImage(Item))
{
int Left;
if (!Text.IsEmpty())
{
Left = Rect.Left;
Rect.Left += Images->Width + 3;
}
else
{
Left = OrigRect.Left + (OrigRect.Right - Images->Width - OrigRect.Left) / 2;
}
int Top = VCenter(Rect, Images->Height);
Images->Draw(Canvas.get(), Left, Top, Pages[Item]->ImageIndex, !Shadowed);
}
int OldMode = SetBkMode(DC, TRANSPARENT);
if (!Text.IsEmpty())
{
if (ATabTheme != NULL)
{
SetTextColor(DC, static_cast<COLORREF>(ATabTheme->GetItemTextColor(GetItemInfo(State))));
}
HGDIOBJ OldFont = SelectObject(DC, Font->Handle);
wchar_t * Buf = new wchar_t[static_cast<size_t>(Text.Length() + 1 + 4)];
wcscpy(Buf, Text.c_str());
TRect TextRect(0, 0, Rect.Width(), 20);
// Truncates too long texts with ellipsis
::DrawText(DC, Buf, -1, &TextRect, DT_CALCRECT | DT_SINGLELINE | DT_MODIFYSTRING | DT_END_ELLIPSIS);
DebugAssert(FTextHeight == TextRect.Height());
Rect.Top = VCenter(Rect, FTextHeight);
DrawText(DC, Buf, -1, &Rect, DT_NOPREFIX | DT_CENTER);
delete[] Buf;
TThemeTabSheetButtons Button = GetTabButton(Item);
if (Button != ttbNone)
{
Rect = TabButtonRect(Item);
TTBXItemInfo ButtonItemInfo = GetItemInfo(State);
if (IsHotButton(Item))
{
ButtonItemInfo.HoverKind = hkMouseHover;
CurrentTheme->PaintFrame(Canvas.get(), Rect, ButtonItemInfo);
}
COLORREF BackColor = GetPixel(DC, Rect.Left + (Rect.Width() / 2), Rect.Top + (Rect.Height() / 2));
COLORREF ShapeColor;
if (ATabTheme != NULL)
{
ShapeColor = static_cast<COLORREF>(ColorToRGB(ATabTheme->GetItemTextColor(ButtonItemInfo)));
}
else
{
ShapeColor = static_cast<COLORREF>(ColorToRGB(Font->Color));
}
#define BlendValue(FN) (((4 * static_cast<int>(FN(BackColor))) + static_cast<int>(FN(ShapeColor))) / 5)
COLORREF BlendColor = RGB(BlendValue(GetRValue), BlendValue(GetGValue), BlendValue(GetBValue));
#undef BlendValue
if (Button == ttbClose)
{
int CrossPadding = GetCrossPadding();
TRect CrossRect(Rect);
CrossRect.Inflate(-CrossPadding, -CrossPadding);
int CrossWidth = ScaleByTextHeight(this, 1);
DrawCross(DC, CrossWidth + 1, BlendColor, CrossRect);
DrawCross(DC, CrossWidth, ShapeColor, CrossRect);
}
else if (DebugAlwaysTrue(Button == ttbDropDown))
{
// See TTBXOfficeXPTheme.PaintDropDownArrow
int Radius = ScaleByTextHeight(this, 2);
int X = ((Rect.Left + Rect.Right)) / 2;
int Y = ((Rect.Top + Rect.Bottom) / 2) - (Radius * 2 / 3);
DrawDropDown(DC, Radius, X, Y, BlendColor, 1);
DrawDropDown(DC, Radius, X, Y, ShapeColor, 0);
}
}
SelectObject(DC, OldFont);
}
SetBkMode(DC, OldMode);
}
//----------------------------------------------------------------------------------------------------------
int __fastcall TThemePageControl::TabButtonSize()
{
return MulDiv(GetTabsHeight(), 8, 13);
}
//----------------------------------------------------------------------------------------------------------
int __fastcall TThemePageControl::GetCrossPadding()
{
return MulDiv(GetTabsHeight(), 2, 13);
}
//----------------------------------------------------------------------------------------------------------
TRect __fastcall TThemePageControl::TabButtonRect(int Index)
{
TRect Rect = TabRect(Index);
ItemTabRect(Index, Rect);
ItemContentsRect(Index, Rect);
int ATabButtonSize = TabButtonSize();
Rect.Top = VCenter(Rect, ATabButtonSize);
Rect.Left = Rect.Right - ATabButtonSize - ScaleByTextHeight(this, 1);
Rect.Right = Rect.Left + ATabButtonSize;
Rect.Bottom = Rect.Top + ATabButtonSize;
return Rect;
}
//----------------------------------------------------------------------------------------------------------
bool TThemePageControl::IsHotButton(int Index)
{
// This was an attempt to allow tracking close buttons, even while drop down button menu is popped,
// but MouseMove does not trigger then.
return (Index == FClickedButton) || (Index == FHotTabButton);
}
//----------------------------------------------------------------------------------------------------------
void TThemePageControl::TabChanged(int Index)
{
// When the "clicked" tab changes, it's probably not anymore the tab that was actually clicked.
// For example, when the last tab is closed, it's replaced with either local-local tab (without the X button),
// or removed altogether. The Login dialog pops up and when new session is opened, its tab's X button is rendered clicked,
// until connection openning finishes (and WMLButtonDown finishes).
if (Index == FClickedButton)
{
UpdateHotButton(FClickedButton, -1);
}
}
//----------------------------------------------------------------------------------------------------------
void TThemePageControl::UpdateHotButton(int & Ref, int Index)
{
if (Ref != Index)
{
bool WasHot = (Index >= 0) && IsHotButton(Index);
int Prev = Ref;
Ref = Index;
if ((Prev >= 0) && !IsHotButton(Prev))
{
InvalidateTab(Prev);
}
if ((Index >= 0) && !WasHot)
{
InvalidateTab(Index);
}
}
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::MouseMove(TShiftState Shift, int X, int Y)
{
TPageControl::MouseMove(Shift, X, Y);
UpdateHotButton(FHotTabButton, IndexOfTabButtonAt(X, Y));
}
//----------------------------------------------------------------------------------------------------------
int __fastcall TThemePageControl::IndexOfTabButtonAt(int X, int Y)
{
int Result = IndexOfTabAt(X, Y);
if ((Result < 0) ||
!GetTabButton(Result) ||
!TabButtonRect(Result).Contains(TPoint(X, Y)))
{
Result = -1;
}
return Result;
}
//----------------------------------------------------------------------------------------------------------
bool __fastcall TThemePageControl::CanChange()
{
FOldTabIndex = ActivePageIndex;
return TPageControl::CanChange();
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::InvalidateTab(int Index)
{
if (HandleAllocated())
{
TRect Rect = TabRect(Index);
if (Index == TabIndex)
{
Rect.Inflate(2, 2);
}
// Original code was invalidating range against parent window
// (recalculating coordinates first)
InvalidateRect(Handle, &Rect, true);
}
}
//----------------------------------------------------------------------------------------------------------
void __fastcall TThemePageControl::Change()
{
// note that TabIndex yields correct value already here,
// while ActivePageIndex is not updated yet
if ((FOldTabIndex >= 0) && (FOldTabIndex != TabIndex) && UseThemes())
{
InvalidateTab(FOldTabIndex);
}
TPageControl::Change();
}
//---------------------------------------------------------------------------
void __fastcall TThemePageControl::WMLButtonDown(TWMLButtonDown & Message)
{
int Index = IndexOfTabButtonAt(Message.XPos, Message.YPos);
if (Index >= 0)
{
Message.Result = 1;
if (FOnTabButtonClick != NULL)
{
UpdateHotButton(FClickedButton, Index);
try
{
FOnTabButtonClick(this, Index);
}
__finally
{
UpdateHotButton(FClickedButton, -1);
}
}
}
else
{
TPageControl::Dispatch(&Message);
}
}
//---------------------------------------------------------------------------
void TThemePageControl::CMHintShow(TCMHintShow & HintShow)
{
TPageControl::Dispatch(&HintShow);
if (OnTabHint != NULL)
{
int Tab = IndexOfTabAt(HintShow.HintInfo->CursorPos.x, HintShow.HintInfo->CursorPos.y);
OnTabHint(this, Tab, HintShow.HintInfo->HintStr);
HintShow.HintInfo->CursorRect = TabRect(Tab);
}
}
//---------------------------------------------------------------------------
void __fastcall TThemePageControl::Dispatch(void * Message)
{
TMessage * M = reinterpret_cast<TMessage*>(Message);
if (M->Msg == CM_MOUSELEAVE)
{
UpdateHotButton(FHotTabButton, -1);
TPageControl::Dispatch(Message);
}
else if (M->Msg == WM_LBUTTONDOWN)
{
WMLButtonDown(*reinterpret_cast<TWMLButtonDown *>(M));
}
else if (M->Msg == WM_WANTS_SCREEN_TIPS)
{
M->Result = 1;
}
else if (M->Msg == CM_HINTSHOW)
{
CMHintShow(*reinterpret_cast<TCMHintShow *>(M));
}
else
{
TPageControl::Dispatch(Message);
}
}
//----------------------------------------------------------------------------------------------------------
TThemeTabSheet * TThemePageControl::GetPage(int Index)
{
return DebugNotNull(dynamic_cast<TThemeTabSheet *>(TPageControl::Pages[Index]));
}
//----------------------------------------------------------------------------------------------------------
TThemeTabSheet * TThemePageControl::GetActivePage()
{
TTabSheet * TabSheet = TPageControl::ActivePage;
TThemeTabSheet * Result = NULL;
if (TabSheet != NULL)
{
Result = DebugNotNull(dynamic_cast<TThemeTabSheet *>(TabSheet));
}
return Result;
}
//----------------------------------------------------------------------------------------------------------
int TThemePageControl::TotalTabsWidth()
{
TRect FirstTabRect = TabRect(0);
TRect LastTabRect = TabRect(PageCount - 1);
return -FirstTabRect.Left + LastTabRect.Right;
}
//----------------------------------------------------------------------------------------------------------
void TThemePageControl::UpdateTabsCaptionTruncation()
{
DisableAlign();
Tabs->BeginUpdate();
try
{
FSessionTabShrink = 0;
for (int Index = 0; Index < PageCount; Index++)
{
Pages[Index]->UpdateCaption();
}
int TabsWidth = TotalTabsWidth();
int MaxWidth = ClientWidth - ScaleByTextHeight(this, 8); // arbitrary margin to avoid left/right buttons flicker
Canvas->Font = Font;
if (TabsWidth > MaxWidth)
{
int NeedWidth = (TabsWidth - MaxWidth);
int MaxLen = 0;
int CaptionsWidth = 0;
for (int Index = 0; Index < PageCount; Index++)
{
UnicodeString TabCaption = Pages[Index]->BaseCaption;
MaxLen = std::max(MaxLen, TabCaption.Length());
CaptionsWidth += Canvas->TextWidth(TabCaption);
}
bool Repeat;
do
{
int NewShrink;
if (FSessionTabShrink == 0)
{
NewShrink = MaxLen; // remove only new tab caption
}
else
{
NewShrink = FSessionTabShrink - 1;
}
if (NewShrink < 1)
{
Repeat = false;
}
else
{
FSessionTabShrink = NewShrink;
int NewCaptionsWidth = 0;
for (int Index = 0; Index < PageCount; Index++)
{
UnicodeString TabCaption = Pages[Index]->TruncatedCaption();
NewCaptionsWidth += Canvas->TextWidth(TabCaption);
}
int GainedWidth = (CaptionsWidth - NewCaptionsWidth);
Repeat = (GainedWidth < NeedWidth);
}
}
while (Repeat);
for (int Index = 0; Index < PageCount; Index++)
{
Pages[Index]->UpdateCaption();
}
}
}
__finally
{
Tabs->BeginUpdate();
EnableAlign();
}
}
//----------------------------------------------------------------------------------------------------------
void TThemePageControl::SetActiveTabTheme(TTBXTheme * value)
{
if (FActiveTabTheme != value)
{
FActiveTabTheme = value;
if (ActivePage != NULL)
{
ActivePage->Invalidate();
}
}
}
//----------------------------------------------------------------------------------------------------------
void TThemePageControl::SetTabTheme(TTBXTheme * value)
{
if (FTabTheme != value)
{
FTabTheme = value;
Invalidate();
}
}
//----------------------------------------------------------------------------------------------------------
#ifdef _DEBUG
void __fastcall TThemePageControl::RequestAlign()
{
TPageControl::RequestAlign();
}
#endif
//----------------------------------------------------------------------------------------------------------