199
157
class function GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; override;
202
procedure NotebookFocusNewControl(const ANotebook: TCustomNotebook; NewIndex: integer);
203
function NotebookPageRealToLCLIndex(const ANotebook: TCustomNotebook; AIndex: integer): integer;
208
163
Forms, LMessages, ShellAPI;
211
TCustomPageAccess = class(TCustomPage)
214
function IsNotebookGroupFocused(const ANotebook: TCustomNotebook): boolean;
216
lNotebookHandle, lWindow: HWND;
219
if not ANotebook.HandleAllocated then exit;
220
lNotebookHandle := ANotebook.Handle;
221
lWindow := Windows.GetFocus;
222
while (lWindow <> 0) and (lWindow <> lNotebookHandle) do
223
lWindow := Windows.GetParent(lWindow);
224
if lWindow = 0 then exit;
228
{ sets focus to a control on the newly focused tab page }
229
procedure NotebookFocusNewControl(const ANotebook: TCustomNotebook; NewIndex: integer);
232
AWinControl: TWinControl;
233
ParentForm: TCustomForm;
235
{ see if currently focused control is within notebook }
236
if not IsNotebookGroupFocused(ANotebook) then exit;
238
{ focus was/is within notebook, pick a new control to focus }
239
Page := ANotebook.CustomPage(NewIndex);
240
ParentForm := GetParentForm(ANotebook);
241
if ParentForm <> nil then
243
if ANotebook.ContainsControl(ParentForm.ActiveControl) and (ParentForm.ActiveControl <> ANotebook) then
246
if Page.CanFocus then
247
AWinControl := TCustomPageAccess(Page).FindNextControl(nil, True, True, False);
248
// if nothing to focus then focus notebook then we can traverse pages by keys
249
if AWinControl = nil then
250
AWinControl := ANotebook;
251
AWinControl.SetFocus;
256
function NotebookPageRealToLCLIndex(const ANotebook: TCustomNotebook; AIndex: integer): integer;
261
if csDesigning in ANotebook.ComponentState then exit;
263
while (I < ANotebook.PageCount) and (I <= Result) do
265
if not ANotebook.Page[I].TabVisible then Inc(Result);
270
function PageWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
271
LParam: Windows.LParam): LResult; stdcall;
273
if Msg = WM_THEMECHANGED then
275
ThemeServices.UpdateThemes;
276
TWin32WSCustomPage.ThemeChange(Window);
278
Result := WindowProc(Window, Msg, WParam, LParam);
281
{ TWin32WSCustomPage }
283
class function TWin32WSCustomPage.CreateHandle(const AWinControl: TWinControl;
284
const AParams: TCreateParams): HWND;
286
Params: TCreateWindowExParams;
288
// general initialization of Params
289
PrepareCreateWindow(AWinControl, AParams, Params);
290
// customization of Params
293
pClassName := @ClsName[0];
294
SubClassWndProc := @PageWindowProc;
297
FinishCreateWindow(AWinControl, Params, false);
298
// return window handle
299
Result := Params.Window;
303
class procedure TWin32WSCustomPage.DestroyHandle(const AWinControl: TWinControl);
305
PageIndex, RealIndex: integer;
306
PageControlHandle: HWND;
308
// remove tab from pagecontrol only if not pfRemoving is set
309
// if pfRemoving is set then Tab has been deleted by RemovePage
310
if (AWinControl.Parent <> nil) and (AWinControl.Parent.HandleAllocated) and
311
not (pfRemoving in TCustomPageAccess(AWinControl).Flags) then
313
PageControlHandle := AWinControl.Parent.Handle;
314
PageIndex := TCustomPage(AWinControl).PageIndex;
315
RealIndex := TWin32WSCustomNotebook.GetPageRealIndex(TCustomNotebook(AWinControl.Parent), PageIndex);
316
if RealIndex <> -1 then
318
Windows.SendMessage(PageControlHandle, TCM_DELETEITEM, Windows.WPARAM(RealIndex), 0);
319
AWinControl.Parent.InvalidateClientRectCache(False);
322
TWSWinControlClass(ClassParent).DestroyHandle(AWinControl);
325
class procedure TWin32WSCustomPage.ThemeChange(Wnd: HWnd);
327
WindowInfo: PWin32WindowInfo;
329
WindowInfo := GetWin32WindowInfo(Wnd);
330
if WindowInfo <> nil then
334
needParentPaint := ThemeServices.ThemesEnabled;
335
isTabPage := ThemeServices.ThemesEnabled;
340
class procedure TWin32WSCustomPage.SetText(const AWinControl: TWinControl; const AText: string);
343
PageIndex, RealIndex: integer;
344
NotebookHandle: HWND;
346
PageIndex := TCustomPage(AWinControl).PageIndex;
347
RealIndex := TWin32WSCustomNotebook.GetPageRealIndex(TCustomNotebook(AWinControl.Parent), PageIndex);
348
NotebookHandle := AWinControl.Parent.Handle;
349
// We can't set label of a page not yet added,
350
// Check for valid page index
351
if (RealIndex >= 0) and (RealIndex < Windows.SendMessage(NotebookHandle, TCM_GETITEMCOUNT, 0, 0)) then
353
// retrieve page handle from tab as extra check (in case page isn't added yet).
354
TCI.mask := TCIF_PARAM;
355
Windows.SendMessage(NotebookHandle, TCM_GETITEM, RealIndex, LPARAM(@TCI));
356
if PtrUInt(TCI.lParam) = PtrUInt(AWinControl) then
358
Assert(False, Format('Trace:TWin32WSCustomPage.SetText --> %S', [AText]));
359
TCI.mask := TCIF_TEXT;
360
{$ifdef WindowsUnicodeSupport}
361
if UnicodeEnabledOS then
363
TCI.pszText := PChar(PWideChar(UTF8ToUTF16(AText)));
364
Windows.SendMessage(NotebookHandle, TCM_SETITEMW, RealIndex, LPARAM(@TCI));
368
TCI.pszText := PChar(UTF8ToAnsi(AText));
369
Windows.SendMessage(NotebookHandle, TCM_SETITEM, RealIndex, LPARAM(@TCI));
372
TCI.pszText := PChar(AText);
373
Windows.SendMessage(NotebookHandle, TCM_SETITEM, RealIndex, LPARAM(@TCI));
379
class procedure TWin32WSCustomPage.UpdateProperties(const ACustomPage: TCustomPage);
382
PageIndex, RealIndex: integer;
383
NotebookHandle: HWND;
385
PageIndex := ACustomPage.PageIndex;
386
RealIndex := TWin32WSCustomNotebook.GetPageRealIndex(TCustomNotebook(ACustomPage.Parent), PageIndex);
387
NotebookHandle := ACustomPage.Parent.Handle;
388
// Check for valid page index
389
if (RealIndex >= 0) and (RealIndex < Windows.SendMessage(NotebookHandle, TCM_GETITEMCOUNT,0,0)) then
391
// retrieve page handle from tab as extra check (in case page isn't added yet).
392
TCI.mask := TCIF_PARAM;
393
Windows.SendMessage(NotebookHandle, TCM_GETITEM, RealIndex, LPARAM(@TCI));
394
if PtrUInt(TCI.lParam) = PtrUInt(ACustomPage) then
396
TCI.mask := TCIF_IMAGE;
397
TCI.iImage := TCustomNotebook(ACustomPage.Parent).GetImageIndex(PageIndex);
399
Windows.SendMessage(NotebookHandle, TCM_SETITEM, RealIndex, LPARAM(@TCI));
404
{ TWin32WSCustomNotebook }
406
class function TWin32WSCustomNotebook.CreateHandle(const AWinControl: TWinControl;
407
const AParams: TCreateParams): HWND;
409
TabPositionFlags: array[TTabPosition] of DWord = (
411
{ tpBottom } TCS_BOTTOM,
412
{ tpLeft } TCS_VERTICAL or TCS_MULTILINE,
413
{ tpRight } TCS_VERTICAL or TCS_RIGHT or TCS_MULTILINE
416
Params: TCreateWindowExParams;
418
// general initialization of Params
419
PrepareCreateWindow(AWinControl, AParams, Params);
420
// customization of Params
423
Flags := Flags or TabPositionFlags[TCustomNoteBook(AWinControl).TabPosition];
424
if nboMultiLine in TCustomNotebook(AWinControl).Options then
425
Flags := Flags or TCS_MULTILINE;
426
pClassName := WC_TABCONTROL;
429
FinishCreateWindow(AWinControl, Params, false);
430
Result := Params.Window;
432
if TCustomNoteBook(AWinControl).Images <> nil then
433
SendMessage(Result, TCM_SETIMAGELIST, 0, TCustomNoteBook(AWinControl).Images.Reference._Handle);
435
// although we may be child of tabpage, cut the paint chain
436
// to improve speed and possible paint anomalities
437
Params.WindowInfo^.needParentPaint := false;
440
class procedure TWin32WSCustomNotebook.AddPage(const ANotebook: TCustomNotebook;
441
const AChild: TCustomPage; const AIndex: integer);
447
// other widgetsets allocates handles because they really need this
448
// but on windows page handle is differ from tab and thus allocation can be
449
// postponed, but this cause problems with event handling like bug #0012434
450
// so to overcome such problems we need to allocate this handle
454
TCI.Mask := TCIF_TEXT or TCIF_PARAM or TCIF_IMAGE;
455
// store object as extra, so we can verify we got the right page later
456
TCI.lParam := PtrUInt(AChild);
457
TCI.iImage := ANotebook.GetImageIndex(NotebookPageRealToLCLIndex(ANotebook, AIndex));
458
{$ifdef WindowsUnicodeSupport}
459
if UnicodeEnabledOS then
461
TCI.pszText := PChar(PWideChar(UTF8ToUTF16(AChild.Caption)));
462
Windows.SendMessage(Handle, TCM_INSERTITEMW, AIndex, LPARAM(@TCI));
466
TCI.pszText := PChar(Utf8ToAnsi(AChild.Caption));
467
Windows.SendMessage(Handle, TCM_INSERTITEM, AIndex, LPARAM(@TCI));
470
TCI.pszText := PChar(AChild.Caption);
471
Windows.SendMessage(Handle, TCM_INSERTITEM, AIndex, LPARAM(@TCI));
474
// clientrect possible changed, adding first tab, or deleting last
475
// windows should send a WM_SIZE message because of this, but it doesn't
477
if LCLControlSizeNeedsUpdate(ANotebook, True) then
478
AdjustSizeNotebookPages(ANotebook);
482
class procedure TWin32WSCustomNotebook.MovePage(const ANotebook: TCustomNotebook;
483
const AChild: TCustomPage; const NewIndex: integer);
485
RemovePage(ANotebook, AChild.PageIndex);
486
AddPage(ANotebook,AChild,NewIndex);
489
class procedure TWin32WSCustomNotebook.RemovePage(const ANotebook: TCustomNotebook;
490
const AIndex: integer);
492
Windows.SendMessage(ANotebook.Handle, TCM_DELETEITEM, Windows.WPARAM(AIndex), 0);
493
if LCLControlSizeNeedsUpdate(ANotebook, True) then
494
AdjustSizeNotebookPages(ANotebook);
497
{ -----------------------------------------------------------------------------
498
Method: AddAllNBPages
499
Params: Notebook - A notebook control
502
Adds all pages to notebook (showtabs becomes true)
503
------------------------------------------------------------------------------}
504
class procedure TWin32WSCustomNotebook.AddAllNBPages(const ANotebook: TCustomNotebook);
507
I, Res, RealIndex: Integer;
511
WinHandle := ANotebook.Handle;
513
for I := 0 to ANotebook.PageCount - 1 do
515
APage := ANotebook.Page[I];
516
if not APage.TabVisible and not (csDesigning in APage.ComponentState) then
518
// check if already shown
519
TCI.Mask := TCIF_PARAM;
520
Res := Windows.SendMessage(ANotebook.Handle, TCM_GETITEM, RealIndex, LPARAM(@TCI));
521
if (Res = 0) or (PtrUInt(TCI.lParam) <> PtrUInt(APage)) then
523
TCI.Mask := TCIF_TEXT or TCIF_PARAM or TCIF_IMAGE;
524
TCI.lParam := PtrUInt(APage);
525
TCI.iImage := ANotebook.GetImageIndex(I);
526
{$ifdef WindowsUnicodeSupport}
527
if UnicodeEnabledOS then
529
TCI.pszText := PChar(PWideChar(UTF8ToUTF16(APage.Caption)));
530
Windows.SendMessage(WinHandle, TCM_INSERTITEMW, RealIndex, LPARAM(@TCI));
534
TCI.pszText := PChar(Utf8ToAnsi(APage.Caption));
535
Windows.SendMessage(WinHandle, TCM_INSERTITEM, RealIndex, LPARAM(@TCI));
538
TCI.pszText := PChar(APage.Caption);
539
Windows.SendMessage(WinHandle, TCM_INSERTITEM, RealIndex, LPARAM(@TCI));
544
AdjustSizeNotebookPages(ANotebook);
547
class procedure TWin32WSCustomNotebook.AdjustSizeNotebookPages(const ANotebook: TCustomNotebook);
554
WinHandle := ANotebook.Handle;
555
// Adjust page size to fit in tabcontrol, need bounds of notebook in client of parent
556
TWin32WidgetSet(WidgetSet).GetClientRect(WinHandle, R);
557
for I := 0 to ANotebook.PageCount - 1 do
559
lPage := ANotebook.Page[I];
560
// we don't need to resize non-existing pages yet, they will be sized when created
561
if lPage.HandleAllocated then
562
SetBounds(lPage, R.Left, R.Top, R.Right, R.Bottom);
566
{------------------------------------------------------------------------------
567
Method: RemoveAllNBPages
568
Params: Notebook - The notebook control
571
Removes all pages from a notebook control (showtabs becomes false)
572
------------------------------------------------------------------------------}
573
class procedure TWin32WSCustomNotebook.RemoveAllNBPages(const ANotebook: TCustomNotebook);
578
WinHandle := ANotebook.Handle;
579
for I := ANotebook.PageCount - 1 downto 0 do
580
Windows.SendMessage(WinHandle, TCM_DELETEITEM, Windows.WPARAM(I), 0);
581
AdjustSizeNotebookPages(ANotebook);
584
class function TWin32WSCustomNotebook.GetPageRealIndex(const ANotebook: TCustomNotebook; AIndex: Integer): Integer;
589
if csDesigning in ANotebook.ComponentState then exit;
590
for X := 0 to AIndex - 1 do
591
if ANotebook.Page[X].TabVisible = False then Dec(Result);
594
procedure SendSelChangeMessage(const ANotebook: TCustomNotebook; const AHandle: HWND;
595
const APageIndex: integer);
600
FillChar(Mess,SizeOf(Mess),0);
601
Mess.Msg := LM_NOTIFY;
602
FillChar(NMHdr,SizeOf(NMHdr),0);
603
NMHdr.code := TCN_SELCHANGE;
604
NMHdr.hwndfrom := AHandle;
605
NMHdr.idfrom := APageIndex; //use this to set pageindex to the correct page.
606
Mess.NMHdr := @NMHdr;
607
DeliverMessage(ANotebook, TLMessage(Mess));
610
class function TWin32WSCustomNotebook.GetTabIndexAtPos(const ANotebook: TCustomNotebook;
611
const AClientPos: TPoint): integer;
613
hittestInfo: TC_HITTESTINFO;
616
GetLCLClientBoundsOffset(ANotebook, ORect);
617
hittestInfo.pt.x := AClientPos.x + ORect.Left;
618
hittestInfo.pt.y := AClientPos.y + ORect.Top;
619
Result := Windows.SendMessage(ANotebook.Handle, TCM_HITTEST, 0, LPARAM(@hittestInfo));
622
class function TWin32WSCustomNotebook.GetTabRect(const ANotebook: TCustomNotebook;
623
const AIndex: Integer): TRect;
627
GetLCLClientBoundsOffset(ANotebook, ORect);
628
if Windows.SendMessage(ANotebook.Handle, TCM_GETITEMRECT, WPARAM(AIndex), LPARAM(@Result)) <> 0
630
Result.Top := Result.Top - Orect.Top;
631
Result.Bottom := Result.Bottom - Orect.Top;
632
Result.Left := Result.Left - Orect.Left;
633
Result.Right := Result.Right - Orect.Left;
636
Result := inherited GetTabRect(ANotebook, AIndex);
639
class function TWin32WSCustomNotebook.GetCapabilities: TNoteBookCapabilities;
641
Result:=[nbcMultiLine];
644
class function TWin32WSCustomNotebook.GetDesignInteractive(
645
const AWinControl: TWinControl; AClientPos: TPoint): Boolean;
647
hittestInfo: TC_HITTESTINFO;
648
AIndex, ACurIndex: Integer;
650
hittestInfo.pt.x := AClientPos.x;
651
hittestInfo.pt.y := AClientPos.y;
652
AIndex := Windows.SendMessage(AWinControl.Handle, TCM_HITTEST, 0, LPARAM(@hittestInfo));
653
ACurIndex := SendMessage(AWinControl.Handle, TCM_GETCURSEL, 0, 0);
654
Result := (AIndex <> -1) and (AIndex <> ACurIndex);
657
class procedure TWin32WSCustomNotebook.SetImageList(
658
const ANotebook: TCustomNotebook; const AImageList: TCustomImageList);
660
if not WSCheckHandleAllocated(ANotebook, 'SetImageList') then
663
if AImageList <> nil then
664
SendMessage(ANoteBook.Handle, TCM_SETIMAGELIST, 0, AImageList.Reference._Handle)
666
SendMessage(ANoteBook.Handle, TCM_SETIMAGELIST, 0, 0);
667
// if you set big images like 32x32 then tabs will be big too => you need to
668
// readjust the size of pages
669
AdjustSizeNotebookPages(ANotebook);
672
class procedure TWin32WSCustomNotebook.SetPageIndex(const ANotebook: TCustomNotebook; const AIndex: integer);
674
NotebookHandle, OldPageHandle, NewPageHandle: HWND;
675
NewRealIndex: Integer;
677
NotebookHandle := ANotebook.Handle;
678
// get the current top window
679
OldPageHandle := GetTopWindow(NotebookHandle);
681
NewRealIndex := GetPageRealIndex(ANotebook, AIndex);
683
SendMessage(NotebookHandle, TCM_SETCURSEL, Windows.WParam(NewRealIndex), 0);
684
if not (csDestroying in ANotebook.ComponentState) then
686
// create handle if not already done, need to show!
687
if (AIndex >= 0) and (AIndex < ANotebook.PageCount) then
689
NewPageHandle := ANotebook.Page[AIndex].Handle;
690
Windows.SetWindowPos(NewPageHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW or SWP_NOACTIVATE);
691
SendSelChangeMessage(ANotebook, NotebookHandle, AIndex);
692
NotebookFocusNewControl(ANotebook, AIndex);
694
// traverse children and hide them if needed
695
while OldPageHandle <> 0 do
697
// don't touch non-lcl windows
698
if (OldPageHandle <> NewPageHandle) and IsWindowVisible(OldPageHandle) and Assigned(GetProp(OldPageHandle, 'WinControl')) then
699
Windows.SetWindowPos(OldPageHandle, 0, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER or SWP_HIDEWINDOW or SWP_NOACTIVATE);
700
OldPageHandle := GetNextWindow(OldPageHandle, GW_HWNDNEXT);
705
class procedure TWin32WSCustomNotebook.SetTabPosition(const ANotebook: TCustomNotebook; const ATabPosition: TTabPosition);
707
if ANoteBook.HandleAllocated then
708
RecreateWnd(ANoteBook);
711
class procedure TWin32WSCustomNotebook.ShowTabs(const ANotebook: TCustomNotebook; AShowTabs: boolean);
714
AddAllNBPages(ANotebook)
716
RemoveAllNBPages(ANotebook);
719
class procedure TWin32WSCustomNotebook.UpdateProperties(const ANotebook: TCustomNotebook);
721
CurrentStyle, NewStyle: cardinal;
723
CurrentStyle := GetWindowLong(ANotebook.Handle, GWL_STYLE);
724
if (nboMultiLine in ANotebook.Options) or (ANotebook.TabPosition in [tpLeft, tpRight]) then
725
NewStyle := CurrentStyle or TCS_MULTILINE
727
NewStyle := CurrentStyle and not TCS_MULTILINE;
728
if NewStyle <> CurrentStyle then
730
SetWindowLong(ANotebook.Handle, GWL_STYLE, NewStyle);
731
SetWindowPos(ANoteBook.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_DRAWFRAME);
732
if LCLControlSizeNeedsUpdate(ANotebook, True) then
733
AdjustSizeNotebookPages(ANotebook);
737
165
{$include win32trayicon.inc}