123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- //---------------------------------------------------------------------------
- #include <vcl.h>
- #pragma hdrstop
- #include <Common.h>
- #include <vsstyle.h>
- #include <memory>
- #include "ThemePageControl.h"
- //---------------------------------------------------------------------------
- #pragma package(smart_init)
- //---------------------------------------------------------------------------
- // Based on
- // http://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=6355
- //---------------------------------------------------------------------------
- //#define USE_DEFAULT_XP_TOPTAB // XP top tab is drawn only for test purpose. To use default, uncoment this line
- //---------------------------------------------------------------------------
- // constant string definitions here (or you can put it into resource string table)
- #define IDS_UTIL_TAB L"TAB"
- #define IDS_UTIL_UXTHEME L"UxTheme.dll"
- #define IDS_UTIL_THEMEACT "IsThemeActive"
- #define IDS_UTIL_THEMEOPN "OpenThemeData"
- #define IDS_UTIL_THEMEBCKG "DrawThemeBackground"
- //---------------------------------------------------------------------------
- static inline void ValidCtrCheck(TThemePageControl *)
- {
- new TThemePageControl(NULL);
- }
- //---------------------------------------------------------------------------
- namespace Themepagecontrol
- {
- void __fastcall PACKAGE Register()
- {
- TComponentClass classes[1] = {__classid(TThemePageControl)};
- RegisterComponents(L"Scp", classes, 0);
- }
- }
- //----------------------------------------------------------------------------------------------------------
- __fastcall TThemeTabSheet::TThemeTabSheet(TComponent * Owner) :
- TTabSheet(Owner)
- {
- FShadowed = false;
- }
- //----------------------------------------------------------------------------------------------------------
- void __fastcall TThemeTabSheet::SetShadowed(bool Value)
- {
- if (Shadowed != Value)
- {
- FShadowed = Value;
- TThemePageControl * ThemePageControl = dynamic_cast<TThemePageControl *>(Parent);
- if (ALWAYS_TRUE(ThemePageControl != NULL))
- {
- ThemePageControl->InvalidateTab(TabIndex);
- }
- else
- {
- Parent->Invalidate();
- }
- }
- }
- //----------------------------------------------------------------------------------------------------------
- //----------------------------------------------------------------------------------------------------------
- __fastcall TThemePageControl::TThemePageControl(TComponent * Owner) :
- TPageControl(Owner)
- {
- FOldTabIndex = -1;
- }
- //----------------------------------------------------------------------------------------------------------
- int __fastcall TThemePageControl::GetTabsHeight()
- {
- // Calculated height includes tab/contents separator line on Windows 7/8,
- // but not on Windows XP
- TRect Rect = GetClientRect();
- ::SendMessage(Handle, TCM_ADJUSTRECT, FALSE, (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 (ALWAYS_TRUE(PageCount >= 0))
- {
- TRect Rect = TabRect(0);
- int Result2 = Rect.Bottom + 1;
- if (ALWAYS_FALSE(Result != Result2))
- {
- Result = Result2;
- }
- }
- return Result;
- }
- //----------------------------------------------------------------------------------------------------------
- void __fastcall TThemePageControl::PaintWindow(HDC DC)
- {
- // Themes not enabled, give up
- if (!UseThemes())
- {
- TPageControl::PaintWindow(DC);
- return;
- }
- // TODO use GetClipBox
- TRect PageRect = GetClientRect();
- // 1st paint the tab body
- TRect ClientRect = PageRect;
- ::SendMessage(Handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&PageRect);
- ClientRect.Top = PageRect.Top - 2;
- DrawThemesXpTabItem(DC, -1, ClientRect, true, 0);
- // 2nd paint the inactive tabs
- TPoint Point = ScreenToClient(Mouse->CursorPos);
- int HotIndex = IndexOfTabAt(Point.X, Point.Y);
- int SelectedIndex = TabIndex;
- for (int Tab = 0; Tab < PageCount; Tab++)
- {
- if (Tab != SelectedIndex)
- {
- TThemeTabSheet * ThemeTabSheet = dynamic_cast<TThemeTabSheet *>(Pages[Tab]);
- bool Shadowed = (ThemeTabSheet != NULL) ? ThemeTabSheet->Shadowed : false;
- TRect Rect = TabRect(Tab);
- int State = (Tab == HotIndex ? TIS_HOT : (Shadowed ? TIS_DISABLED : TIS_NORMAL));
- DrawThemesXpTabItem(DC, Tab, Rect, false, State);
- }
- }
- if (SelectedIndex >= 0)
- {
- // 3rd paint the active selected tab
- TRect Rect = TabRect(SelectedIndex);
- Rect.Inflate(2, 2);
- Rect.Bottom--;
- DrawThemesXpTabItem(DC, SelectedIndex, Rect, false, TIS_SELECTED);
- }
- }
- //----------------------------------------------------------------------------------------------------------
- // This function draws Themes Tab control parts: a) Tab-Body and b) Tab-tabs
- void __fastcall TThemePageControl::DrawThemesXpTabItem(HDC DC, int Item,
- const TRect & Rect, bool Body, int State)
- {
- TSize Size = Rect.Size;
- // Draw background
- HDC DCMem = CreateCompatibleDC(DC);
- HBITMAP BitmapMem = CreateCompatibleBitmap(DC, Size.Width, Size.Height);
- HBITMAP BitmapOld = (HBITMAP)SelectObject(DCMem, BitmapMem);
- TRect RectMem(0, 0, Size.Width, Size.Height);
- if (!Body && (State == TIS_SELECTED))
- {
- RectMem.Bottom++;
- }
- if (Body)
- {
- DrawThemesPart(DCMem, TABP_PANE, State, IDS_UTIL_TAB, &RectMem);
- }
- else
- {
- DrawThemesPart(DCMem, TABP_TABITEM, State, IDS_UTIL_TAB, &RectMem);
- }
- // Init some extra parameters
- BITMAPINFO BitmapInfo;
- // Fill local pixel arrays
- ZeroMemory(&BitmapInfo, sizeof(BITMAPINFO));
- BITMAPINFOHEADER & BitmapInfoHeader = BitmapInfo.bmiHeader;
- BitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
- BitmapInfoHeader.biCompression = BI_RGB;
- BitmapInfoHeader.biPlanes = 1;
- // force as RGB: 3 bytes,24 bits -> good for rotating bitmap in any resolution
- BitmapInfoHeader.biBitCount = 24;
- BitmapInfoHeader.biWidth = Size.Width;
- BitmapInfoHeader.biHeight = Size.Height;
- if (!Body && (Item >= 0))
- {
- if ((State == TIS_SELECTED))
- {
- RectMem.Bottom--;
- }
- DrawTabItem(DCMem, Item, RectMem, (State == TIS_SELECTED), (State == TIS_DISABLED));
- }
- // Blit image to the screen
- BitBlt(DC, Rect.Left, Rect.Top, Size.Width, Size.Height, DCMem, 0, 0, SRCCOPY);
- SelectObject(DCMem, BitmapOld);
- DeleteObject(BitmapMem);
- DeleteDC(DCMem);
- }
- //----------------------------------------------------------------------------------------------------------
- // draw tab item context: possible icon and text
- void __fastcall TThemePageControl::DrawTabItem(HDC DC, int Item, TRect Rect,
- bool Selected, bool Shadowed)
- {
- if (Selected)
- {
- Rect.Bottom -= 1;
- }
- else
- {
- Rect.Bottom += 2;
- }
- Rect.Left += 6;
- Rect.Top += 2 + (Selected ? 1 : 3);
- UnicodeString Text = Pages[Item]->Caption;
- if ((Images != NULL) && (Pages[Item]->ImageIndex >= 0))
- {
- int Left;
- if (!Text.IsEmpty())
- {
- Left = Rect.Left + (Selected ? 2 : 0);
- }
- else
- {
- Left = (Rect.Right - Images->Width - Rect.Left) / 2;
- }
- int Y = ((Rect.Top + Rect.Bottom - Images->Height) / 2) - 1 + (Selected ? 0 : -2);
- std::unique_ptr<TCanvas> Canvas(new TCanvas());
- Canvas->Handle = DC;
- Images->Draw(Canvas.get(), Left, Y, Pages[Item]->ImageIndex, !Shadowed);
- //ImageList_Draw((HIMAGELIST)Images->Handle, Pages[Item]->ImageIndex, DC,
- // Left, Y, ILD_TRANSPARENT, );
- Rect.Left += Images->Width + 3;
- }
- else
- {
- Rect.Left -= 2;
- }
- int OldMode = SetBkMode(DC, TRANSPARENT);
- if (!Text.IsEmpty())
- {
- HFONT OldFont = (HFONT)SelectObject(DC, Font->Handle);
- Rect.Right -= 3;
- wchar_t * Buf = new wchar_t[Text.Length() + 1 + 4];
- wcscpy(Buf, Text.c_str());
- TRect TextRect(0, 0, Rect.Right - Rect.Left, 20);
- ::DrawText(DC, Buf, -1, &TextRect, DT_CALCRECT | DT_SINGLELINE | DT_MODIFYSTRING | DT_END_ELLIPSIS);
- OffsetRect(&Rect, 0, (Selected ? 0 : -2));
- DrawText(DC, Buf, -1, &Rect, DT_NOPREFIX | DT_CENTER);
- delete[] Buf;
- SelectObject(DC, OldFont);
- }
- SetBkMode(DC, OldMode);
- }
- //----------------------------------------------------------------------------------------------------------
- void __fastcall TThemePageControl::DrawThemesPart(HDC DC, int PartId,
- int StateId, LPCWSTR PartNameID, LPRECT Rect)
- {
- HTHEME Theme = OpenThemeData(NULL, PartNameID);
- if (Theme != 0)
- {
- DrawThemeBackground(Theme, DC, PartId, StateId, Rect, NULL);
- CloseThemeData(Theme);
- }
- }
- //==========================================================================================================
- // these two messages are necessary only to properly redraw deselected tab background, because
- 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();
- }
- //----------------------------------------------------------------------------------------------------------
|