OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
notetab.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectWindows
3// Copyright (c) 1995, 1996 by Borland International, All Rights Reserved
4//
5/// \file
6/// Implementation of class TNoteTab
7/// Added Scroll handling. Contributed by Jogy.
8/// Added support for set font and set image. Contributed by Jogy.
9//----------------------------------------------------------------------------
10#include <owl/pch.h>
11
12#include <owl/contain.h>
13#include <owl/control.h>
14#include <owl/notetab.h>
15#include <owl/uihelper.h>
16#include <owl/commctrl.h>
17#include <owl/uimetric.h>
18#include <owl/updown.h>
19#include <owl/uimetric.h>
20#include <owl/celarray.h>
21#include <owl/theme.h>
22#include <owl/gdiplus.h>
23#include <algorithm>
24
25using namespace std;
26
27namespace owl {
28
30
31#define OWL_CLIP_TAB_BOUNDING_RECT_ 0 // debugging
32#define OWL_DRAW_TAB_BOUNDING_RECT_ 0 // debugging
33
34#if OWL_CLIP_TAB_BOUNDING_RECT_
35
37
38#endif
39
40#if OWL_DRAW_TAB_BOUNDING_RECT_
41
43
44#endif
45
46//----------------------------------------------------------------------------
47
48DEFINE_RESPONSE_TABLE1(TNoteTab, TControl)
59
60//
61/// Constructor of NoteTab object. Use this constructor when creating a notetab
62/// control from scratch.
63//
65 int id,
66 int x, int y, int w, int h,
68 bool dialogBuddy,
69 TModule* module)
70:
71 TControl(parent, id, nullptr, x, y, w, h, module),
72 WindowFace(!dialogBuddy),
73 Buddy(buddy)
74{
75 InitCtrl();
76}
77
78//
79/// Constructor of NoteTab object. Use this constructor when aliasing a control
80/// defined within a dialog template.
81//
83 int resourceId,
85 bool dialogBuddy,
86 TModule* module)
87:
88 TControl(parent, resourceId, module),
89 WindowFace(!dialogBuddy),
90 Buddy(buddy)
91{
92 InitCtrl();
93}
94
95//
96/// Returns "OWL_Notetab" - the Window class name of the notetab control object
97//
102
103//
104/// Overriden virtual of TWindow - Initializes font used by control and resize
105/// accordingly.
106//
107void
109{
111
112 // Initialize BuddyHandle if we have a Buddy.
113 //
114 if (Buddy)
115 BuddyHandle = Buddy->GetHandle();
116}
117
118//
119/// Adds a new tabitem to the notetab control
120//
121int
131
132//
133/// Inserts a new TTabItem at the specified index.
134//
135int
138 int index,
140 int imageIdx,
142 bool shouldSelect)
143{
144 PRECONDITION(index >= 0 && index <= GetCount());
145
146 TabList.insert(TabList.begin() + index,
148
149 SetTabSize(index);
150 SetTabRects(FirstVisibleTab);
151 if (shouldSelect)
152 SetSel(index);
153
154 return index;
155}
156
157//
158/// Remove the tabitem at the specified 'index'. Returns true on success; false
159/// otherwise.
160//
161bool
163{
164 if (index < 0 || index >= GetCount()) return false; // invalid index
165
166 // Mark rectangles that need to be redrawn.
167 //
168 if (IsVisible(index))
169 {
170 for (int i = index; i < GetCount(); i++)
172 }
173
174 // Remove the tab.
175 //
176 TabList.erase(TabList.begin() + index);
177
178 // Adjust SelectedTab and FirstVisibleTab.
179 // If a tab before SelectedTab is deleted, then correct the index so that it
180 // points to the same item. If the SelectedTab was deleted, then do nothing,
181 // thus moving the selection to the following tab, unless it was the last
182 // tab, in which case we need to move the selection left. Then do the same
183 // for FirstVisibleTab.
184 //
185 int n = GetCount(); // new count
186 if (index < SelectedTab || SelectedTab == n)
187 --SelectedTab;
188 CHECK(SelectedTab >= -1 && SelectedTab < n);
189 if (index < FirstVisibleTab || FirstVisibleTab == n)
190 --FirstVisibleTab;
191 CHECK(FirstVisibleTab >= -1 && FirstVisibleTab < n);
192
193 // Force SelectedTab to have focus.
194 //
195 if ((SelectedTab >= 0) && (SelectedTab < n))
196 InvalidateTab(SelectedTab);
197
198 // Calculate new tab rectangles, if any left.
199 //
200 if (n > 0)
201 SetTabRects(FirstVisibleTab);
202 return true;
203}
204
205//
206/// Removes all tab items in the notetab control. Always returns true.
207//
208bool
210{
211 TabList.clear();
212 FirstVisibleTab = 0;
213 SelectedTab = -1;
214
215 return true;
216}
217
218//
219/// Return the number of tab items in the notetab control.
220//
221int
223{
224 PRECONDITION(TabList.size() <= INT_MAX);
225 return static_cast<int>(TabList.size());
226}
227
228//
229/// Returns the index of the selected tabitem.
230///
231/// \note Returns a zero-based index or -1 if there are no tab items in the notetab
232/// control.
233int
235{
236 return SelectedTab;
237}
238
239//
240/// Selects the tabitem at the specified index.
241/// \note SetSel does not send any
242/// notifications to the parent and/or buddy. Returns the 0 based index of the tab
243/// item selected or -1 on failure.
244//
245int
247{
248 if (index < 0 || index >= GetCount()) return -1;
249 if (index == SelectedTab) return index;
250
251 // Change the selection.
252 // First, invalidate area occupied by previously selected item.
253 //
254 if (SelectedTab >= 0 && SelectedTab < GetCount())
255 InvalidateTab(SelectedTab);
256
257 // Update selected index and tab rectangles (selected tab may differ from the rest).
258 //
259 SelectedTab = index;
260 SetTabRects(FirstVisibleTab);
261
262 // Invalidate area occupied by new selection.
263 //
264 if (SelectedTab >= 0 && SelectedTab < GetCount())
265 InvalidateTab(SelectedTab);
266
267 return index;
268}
269
270int
272{
273 int labelHeight = 0;
274 for (int i = 0; i != GetCount(); ++i)
275 {
276 SetTabSize(i);
277 labelHeight = std::max(labelHeight, static_cast<int>(TabList[i].LabelSize.cy));
278 }
279 return Margin.cy +
280 LabelMargin.cy +
282 LabelMargin.cy +
283 (Style3d ? TUIMetric::CyEdge.Get() : 0);
284}
285
286//
287/// Sets the amount of space to the left of the tabs and above the tabs.
288/// Note that the horizontal margin is additional to the space required for scroll buttons, if the
289/// latter are aligned to the left and visible. In this case, the horizontal margin is the space
290/// between the scroll buttons and the first visible tab. Otherwise, the horizontal margin is the
291/// space between the left edge of the control and the first visible tab.
292//
293void
295{
296 Margin = v;
297 Update();
298}
299
300//
301/// Sets the amount of padding around the tab label.
302//
303void
305{
306 LabelMargin = v;
307 Update();
308}
309
310//
311/// Sets the horizontal spacing between image and text in the label.
312//
313void
315{
316 LabelImageMargin = v;
317 Update();
318}
319
320//
321/// Sets the margin around the focus rectangle for the selected tab.
322//
323void
325{
326 FocusMargin = v;
327 Update();
328}
329
330//
331/// Sets the horizontal distance between two tabs.
332//
333void
335{
336 TabSpacing = v;
337 Update();
338}
339
340//
341/// Sets the amount of narrowing on each side of the tab towards the bottom.
342//
343void
345{
346 TabTapering = v;
347 Update();
348}
349
350//
351/// Sets the amount of extra height of the selected tab.
352//
353void
355{
356 SelectedTabProtrusion = v;
357 Update();
358}
359
360//
361/// Returns the font used to render the text part of the tab labels.
362//
363const TFont&
365{
366 PRECONDITION(TabFont);
367 return *TabFont;
368}
369
370//
371/// Sets the font used to render the text part of the tab labels.
372//
373void
375{
376 TabFont.reset(new TFont(font.GetObject()));
377 Update();
378}
379
380//
381/// Returns the font used to render the text part of the selected tab label.
382//
383const TFont&
385{
386 PRECONDITION(TabFont);
387 return SelectedTabFont ? *SelectedTabFont : *TabFont;
388}
389
390//
391/// Sets the font used to render the text part of the selected tab label.
392//
393void
395{
396 SelectedTabFont.reset(new TFont(font.GetObject()));
397 Update();
398}
399
400//
401/// Sets the fill color used to paint the tabs.
402//
403void
405{
406 TabColor = v;
407 Update();
408}
409
410//
411/// Sets the fill color used to paint the selected tab.
412/// This color is only used when WindowFace mode is selected.
413//
414void
416{
417 SelectedTabColor = v;
418 Update();
419}
420
421//
422/// Sets the pen color used to draw the edges of the tabs.
423//
424void
426{
427 EdgeColor = v;
428 Update();
429}
430
431//
432/// Retrieve information about the tab item at the specified index. Always returns
433/// true.
434//
435bool
437{
438 PRECONDITION(index >= 0);
439 PRECONDITION(index < GetCount());
440
441 tabItem = TabList[index];
442 return true;
443}
444
445//
446/// Functional style overload
447//
449TNoteTab::GetItem(int index) const
450{
452 bool r = GetItem(index, n); CHECK(r); InUse(r);
453 return n;
454}
455
456//
457/// Updates information about the tab item at the specified index.
458//
459bool
461{
462 if (index < GetCount() && index >= 0) {
463
464 TabList[index] = tabItem;
465
466 // !BB Need to recalc/invalidate etc...
467 SetTabSize(index);
468 SetTabRects(FirstVisibleTab);
469 InvalidateTab(index);
470 return true;
471 }
472 return false;
473}
474
475//
476/// Return handle of buddy window associated with the notetab control.
477//
478HWND
480{
481 return BuddyHandle;
482}
483
484//
485/// Sets handle of the buddy window associated with this notetab control.
486//
487void
489{
490 BuddyHandle = hwnd;
491 Buddy = GetWindowPtr( BuddyHandle );
492 if( !Buddy )
493 Buddy = new TWindow( hwnd );
494}
495
496//
497/// Overrides TWindow virtual member function to handle transfers. There are no
498/// transfers for NoteTab controls.
499//
500uint
501TNoteTab::Transfer(void* /*buffer*/, TTransferDirection /*direction*/)
502{
503 return 0;
504}
505
506//----------------------------------------------------------------------------
507
508//
509/// Initialize internal variables used by NoteTab.
510//
511void
513{
514 Style3d = true;
515 ShouldUseThemes = false;
516 Margin = TSize(5, TUIMetric::CySizeFrame);
517 LabelMargin = TSize(5, 3);
518 SelectedTabProtrusion = 0;
519 LabelImageMargin = 3;
520 FocusMargin = TSize(2, 2);
521 TabSpacing = 4;
522 TabTapering = 4;
523 TabColor = TColor::Sys3dFace;
524 SelectedTabColor = TColor::SysWindow;
525 EdgeColor = TColor::SysWindowFrame;
527
528 TabList.clear();
530 SelectedTabFont.reset(); // Causes TabFont to be used for selected tabs.
531 SelectedTab = -1;
532 FirstVisibleTab = 0;
533 CelArray = nullptr;
534 OwnedCelArray.reset();
535 TransparentColor = TColor::Sys3dFace;
536 ScrollLoc = alRight;
537
538 ModifyStyle(0, WS_CLIPCHILDREN); // Clipping eliminates scrollbar flicker.
539 ScrollButtons = new TUpDown{this, -1, 0, 0, 0, 0};
540 ScrollButtons->ModifyStyle(WS_TABSTOP, UDS_HORZ); // No focus, please.
541}
542
543//
544/// Returns the bounding rectangle of a tab given its hit rectangle.
545/// The bounding rectangle is the smallest rectangle that encapsulates the
546/// whole tab, and outside which the tab will not draw.
547/// The bounding rectangle may be larger than the tab's hit rectangle.
548//
549TRect
550TNoteTab::GetBoundingRect(const TRect& tabRect) const
551{
552 // Adjust for the widening of the tab towards the page edge (top).
553 //
554 return tabRect.IsEmpty() ? TRect() : tabRect.InflatedBy(TabTapering, 0);
555}
556
557//
558/// Invalidates the rectangle occupied by the tab at the specified index.
559//
560void
562{
563 PRECONDITION(index >= 0 && index < GetCount());
564 if (!GetHandle()) return;
565
566 const TNoteTabItem& tab = TabList[index];
567 InvalidateRect(GetBoundingRect(tab.Rect));
568}
569
570namespace
571{
572
573 //
574 // Returns `true` if themes are enabled for this application and
575 // themed Common Controls (version 6 or later) are in use.
576 //
577 // Important: This function must be called after the creation of the main
578 // window, otherwise it may always return `false`.
579 //
580 // Note that IsAppThemed will return `false` if either (a) themes have been
581 // disabled for the application by selecting "Disable visual themes" in the
582 // Compatibility tab in the Properties dialog for the executable, or (b)
583 // themes have been deactivated by selecting the Windows Classic style in
584 // the Windows XP/7/Vista Control Panel (not available in Windows 8).
585 // Note that (b) may change at run-time.
586 //
587 // Note we do not have to use IsThemeActive here. This function only reports
588 // the state of the Control Panel setting (Classic vs themed).
589 //
590 bool IsThemed_()
591 {
592 static const auto v = GetCommCtrlVersion();
593 return TThemeModule::GetInstance().IsAppThemed() && v >= 0x60000;
594 }
595
596 //
597 // Defines a base class with common implementation and utilities for derived
598 // UI part renderers.
599 //
600 struct TRenderer_
601 {
602 TWindow& Window;
603 TDC& Dc;
604 const TFont& TabFont;
605 const TFont& SelectedTabFont;
606 TColor TabTextColor;
607
608 TRenderer_(
609 TWindow& w,
610 TDC& dc,
611 const TRect& paintRect,
612 const TFont& tabFont,
613 const TFont& selectedTabFont,
614 TColor tabTextColor,
615 TColor tabColor,
616 TColor selectedTabColor,
617 TColor edgeColor
618 )
619 : Window(w), Dc(dc), TabFont(tabFont), SelectedTabFont(selectedTabFont), TabTextColor(tabTextColor)
621
622 void PaintPageEdge(const TSize& margin)
623 {CHECKX(false, _T("Not implemented")); InUse(margin);}
624
625 void PaintTabFace(const TRect& tabBoundingRect, TPoint (&pt)[4], bool isSelectedTab)
626 {CHECKX(false, _T("Not implemented")); InUse(tabBoundingRect); InUse(pt); InUse(isSelectedTab);}
627
628 void DrawTabContour(const TPoint (&pt)[4], bool isSelectedTab)
629 {CHECKX(false, _T("Not implemented")); InUse(pt); InUse(isSelectedTab);}
630
631 void PaintTabIcon(const TNoteTabItem& tab, const TCelArray& celArray, TColor transparentColor, const TSize& labelMargin, bool isSelectedTab, int selectedTabProtrusion)
632 {
633 CHECK(!tab.Rect.IsEmpty());
635 TRect imageRect(tab.Rect.TopLeft() + TSize(0, dy), tab.Rect.BottomRight());
637 TSize size = celArray.CelSize();
638 TRect srcRect(celArray.CelRect(tab.ImageIdx));
639 TPoint dstPt(
640 (tab.ImageLoc == alRight) ? imageRect.Width() - (size.cx + labelMargin.cx) : labelMargin.cx,
641 (imageRect.Height() - size.cy) / 2);
642 face.Paint(Dc, srcRect, dstPt, TUIFace::Normal, false, false);
643 }
644
645 void DrawTabText(const TNoteTabItem& tab, const TCelArray* celArray, const TSize& labelMargin, int labelImageMargin, bool isSelectedTab, int selectedTabProtrusion)
646 {
647 bool hasImage = celArray && tab.ImageIdx >= 0;
648 int leftMargin = tab.Rect.left + labelMargin.cx;
649 int rightMargin = tab.Rect.right - labelMargin.cx;
651 TRect labelRect(
652 (hasImage && tab.ImageLoc == alLeft) ? (leftMargin + celArray->CelSize().cx + labelImageMargin) : leftMargin,
653 tab.Rect.top + topMargin,
654 (hasImage && tab.ImageLoc == alRight) ? (rightMargin - celArray->CelSize().cx - labelImageMargin) : rightMargin,
655 tab.Rect.bottom - labelMargin.cy);
656 uint16 labelAlign = static_cast<uint16>(!hasImage ? DT_CENTER : (tab.ImageLoc == alRight ? DT_RIGHT : DT_LEFT));
658 int oldBkMode = Dc.SetBkMode(TRANSPARENT);
659 Dc.SetTextColor(TabTextColor);
660 Dc.SelectObject(isSelectedTab ? SelectedTabFont : TabFont);
661 Dc.DrawText(tab.Label, -1, labelRect, labelFormat);
662 Dc.SetBkMode(oldBkMode);
663 }
664
665 void DrawTabFocusRect(const TNoteTabItem& tab, const TSize& focusMargin, int selectedTabProtrusion)
666 {
668 }
669
670 static void DrawTabFocusRect(TDC& dc, const TNoteTabItem& tab, const TSize& focusMargin, int selectedTabProtrusion)
671 {
672 int oldBkMode = dc.SetBkMode(TRANSPARENT);
673 TRect selectedRect = TRect(
674 tab.Rect.TopLeft().OffsetBy(0, selectedTabProtrusion),
675 tab.Rect.BottomRight())
676 .InflatedBy(-focusMargin);
677 dc.DrawFocusRect(selectedRect);
678 dc.SetBkMode(oldBkMode);
679 }
680
681 protected:
682
683 //
684 // Utilities for concrete renderers.
685 //
686
687 void FillPageEdge(const TSize& margin, const TBrush& brush)
688 {
689 TRect r = Window.GetClientRect();
690 TRect m(r.TopLeft(), TSize(r.Width(), margin.cy));
691 Dc.FillRect(m, brush);
692 }
693
694 void DrawPageEdge(const TSize& margin, const TPen& pen)
695 {
696 TRect r = Window.GetClientRect();
697 TRect m(r.TopLeft(), TSize(r.Width(), margin.cy));
698 Dc.SelectObject(pen);
699 Dc.MoveTo(m.BottomLeft());
700 Dc.LineTo(m.BottomRight());
701 }
702
703 void FillPolygon(const TPoint (&pt)[4], const TBrush& brush)
704 {
705 Dc.SelectStockObject(NULL_PEN);
706 Dc.SelectObject(brush);
707 Dc.Polygon(pt, COUNTOF(pt));
708 }
709
710 void DrawContour(const TPoint (&pt)[4], const TPen& pen)
711 {
712
713#if defined(OWL_GDIPLUS_H)
714
715 // Draw anti-aliased lines using GDI+.
716 //
717 Gdiplus::Graphics g(Dc);
718 Gdiplus::Pen gdiPlusPen(gdiplus_cast<Gdiplus::Color>(TColor(pen.GetObject().lopnColor)));
719 Gdiplus::Point points[COUNTOF(pt)];
721 g.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
722 g.DrawLines(&gdiPlusPen, points, COUNTOF(points));
723
724#else
725
726 Dc.SelectObject(pen);
727 Dc.Polyline(pt, COUNTOF(pt));
728 Dc.SetPixel(pt[3], pen.GetObject().lopnColor); // We want that last pixel as well!
729
730#endif
731
732 }
733
734 };
735
736 struct TFlatRenderer_
737 : TRenderer_
738 {
739 TBrush TabBrush;
740 TPen EdgePen;
741
742 TFlatRenderer_(
743 TWindow& w,
744 TDC& dc,
745 const TRect& paintRect,
746 const TFont& tabFont,
747 const TFont& selectedTabFont,
748 TColor tabTextColor,
749 TColor tabColor,
750 TColor selectedTabColor,
751 TColor edgeColor
752 )
754 TabBrush(tabColor),
755 EdgePen(edgeColor)
756 {}
757
758 void PaintPageEdge(const TSize& margin) // non-virtual override
759 {
760 FillPageEdge(margin, TabBrush);
761 DrawPageEdge(margin, EdgePen);
762 }
763
764 void PaintTabFace(const TRect& tabBoundingRect, TPoint (&pt)[4], bool isSelectedTab)
765 {
766 InUse(tabBoundingRect); InUse(isSelectedTab); // non-virtual override
767 FillPolygon(pt, TabBrush);
768 }
769
770 void DrawTabContour(const TPoint (&pt)[4], bool isSelectedTab) // non-virtual override
771 {
773 DrawContour(pt, EdgePen);
774 }
775
776 };
777
778 struct TWindowFaceRenderer_
779 : TFlatRenderer_
780 {
781 TBrush SelectedTabBrush;
782
783 TWindowFaceRenderer_(
784 TWindow& w,
785 TDC& dc,
786 const TRect& paintRect,
787 const TFont& tabFont,
788 const TFont& selectedTabFont,
789 TColor tabTextColor,
790 TColor tabColor,
791 TColor selectedTabColor,
792 TColor edgeColor
793 )
795 SelectedTabBrush(selectedTabColor)
796 {}
797
798 void PaintPageEdge(const TSize& margin) // non-virtual override
799 {
800 FillPageEdge(margin, SelectedTabBrush);
801 DrawPageEdge(margin, EdgePen);
802 }
803
804 void PaintTabFace(const TRect& tabBoundingRect, TPoint (&pt)[4], bool isSelectedTab) // non-virtual override
805 {
807 FillPolygon(pt, isSelectedTab ? SelectedTabBrush : TabBrush);
808 }
809
810 };
811
812 struct TStyle3dRenderer_
813 : TRenderer_
814 {
815 TBrush FaceBrush;
816 TPen LightPen;
817 TPen HilightPen;
818 TPen ShadowPen;
819 TPen DkShadowPen;
820
821 TStyle3dRenderer_(
822 TWindow& w,
823 TDC& dc,
824 const TRect& paintRect,
825 const TFont& tabFont,
826 const TFont& selectedTabFont,
827 TColor tabTextColor,
828 TColor tabColor,
829 TColor selectedTabColor,
830 TColor edgeColor
831 )
833 FaceBrush(tabColor),
834 LightPen(TColor::Sys3dLight),
835 HilightPen(TColor::Sys3dHilight),
836 ShadowPen(TColor::Sys3dShadow),
837 DkShadowPen(TColor::Sys3dDkShadow)
838 {}
839
840 void PaintPageEdge(const TSize& margin) // non-virtual override
841 {
842 FillPageEdge(margin, FaceBrush);
843
844 // Draw a recessed frame around the tabs.
845 //
846 TRect r = Window.GetClientRect();
847 TRect f(
848 r.TopLeft().OffsetBy(0, margin.cy),
849 r.BottomRight());
850 TUIBorder(f, TUIBorder::WndRecessed).Paint(Dc);
851 }
852
853 void PaintTabFace(const TRect& tabBoundingRect, TPoint (&pt)[4], bool isSelectedTab) // non-virtual override
854 {
856 FillPolygon(pt, FaceBrush);
857 }
858
859 void DrawTabContour(const TPoint (&pt)[4], bool isSelectedTab) // non-virtual override
860 {
862
863 Dc.SelectObject(LightPen); // inside left
864 Dc.MoveTo(pt[0].x + 1, pt[0].y);
865 Dc.LineTo(pt[1].x + 1, pt[1].y - 1);
866
867 Dc.SelectObject(HilightPen); // outside left
868 Dc.MoveTo(pt[0].x, pt[0].y);
869 Dc.LineTo(pt[1].x, pt[1].y);
870
871 Dc.SelectObject(ShadowPen); // inside bottom & right
872 Dc.MoveTo(pt[1].x + 1, pt[1].y - 1);
873 Dc.LineTo(pt[2].x - 1, pt[2].y - 1);
874 Dc.MoveTo(pt[2].x - 1, pt[2].y);
875 Dc.LineTo(pt[3].x - 1, pt[3].y);
876
877 Dc.SelectObject(DkShadowPen); // outside bottom & right
878 Dc.MoveTo(pt[1].x + 1, pt[1].y);
879 Dc.LineTo(pt[2].x, pt[2].y);
880 Dc.LineTo(pt[3].x, pt[3].y);
881 }
882
883 };
884
885 struct TThemeRenderer_
886 : TRenderer_
887 {
888 TPen EdgePen;
889
890 TThemeRenderer_(
891 TWindow& w,
892 TDC& dc,
893 const TRect& paintRect,
894 const TFont& tabFont,
895 const TFont& selectedTabFont,
896 TColor tabTextColor,
897 TColor tabColor,
898 TColor selectedTabColor,
899 TColor edgeColor
900 )
902 EdgePen(edgeColor)
903 {}
904
905 void PaintPageEdge(const TSize& margin) // non-virtual override
906 {
907 TRect r = Window.GetClientRect();
908 TRect m(r.TopLeft(), TSize(r.Width(), margin.cy));
909 TThemePart p(Window, L"TAB", TABP_BODY, 0);
910 p.DrawBackground(Dc, m);
911 DrawPageEdge(margin, EdgePen);
912 }
913
914 void PaintTabFace(const TRect& tabBoundingRect, TPoint (&pt)[4], bool isSelectedTab) // non-virtual override
915 {
917 int state = isSelectedTab ? TIS_SELECTED : TIS_NORMAL;
918 TThemePart p(Window, L"TAB", item, state);
919 TRegion savedClipRegion;
920 int r = Dc.GetClipRgn(savedClipRegion); CHECK(r != -1);
921 TRegion clipRegion(pt, COUNTOF(pt), WINDING);
922 Dc.SelectClipRgn(clipRegion);
923 p.DrawBackground(Dc, tabBoundingRect.InflatedBy(0, 1)); // Inflate to not paint the edge.
924 Dc.SelectClipRgn(r == 1 ? savedClipRegion.GetHandle() : NULL);
925 }
926
927 void DrawTabContour(const TPoint (&pt)[4], bool isSelectedTab) // non-virtual override
928 {
930 DrawContour(pt, EdgePen);
931 }
932
933 };
934
935} // namespace
936
937//
938/// Implements the rendering of the window, using the given part renderer.
939//
940template <class TPartRenderer>
941void TNoteTab::PaintTabs(TDC& dc, const TRect& paintRect)
942{
943 if (GetCount() == 0) return;
944
946 *this,
947 dc,
948 paintRect,
949 GetTabFont(),
952 TabColor,
953 SelectedTabColor,
954 EdgeColor);
955
956 // Now, go through the tab list in reverse order and paint each tab, except for
957 // the selected one, which has its painting deferred to the end (since it overlaps
958 // both its neighbours). We iterate in reverse order so that the tabs overlap
959 // correctly from left to right.
960 //
961 for (int i = GetCount(); --i >= -1;)
962 {
963 // Skip the selected tab; it's drawn last. Otherwise get the working index.
964 //
965 if (i == GetSel()) continue;
966 const bool isSelectedTab = (i == -1);
967
968 // If this is the final item (selected tab), then draw the page edge.
969 //
970 if (isSelectedTab)
971 renderer.PaintPageEdge(Margin);
972
973 // Retrieve tab item information.
974 //
975 const TNoteTabItem& tab = TabList[isSelectedTab ? GetSel() : i];
976 TRect tabBoundingRect = GetBoundingRect(tab.Rect);
977 if (tabBoundingRect.IsNull()) continue;
978 CHECK(!tabBoundingRect.IsEmpty());
979
980 // If the tab is completely outside the painting area, then skip it.
981 // Note that we inflate the paint area by 1 here to avoid edge conditions,
982 // i.e. whether or not a shared edge constitutes touching.
983 //
984 if (!(tabBoundingRect.InflatedBy(1, 1).Touches(paintRect)))
985 continue;
986
987#if OWL_CLIP_TAB_BOUNDING_RECT_
988
990 {
991 TDC& Dc;
992 TRegion SavedClipRegion;
994
995 TTabBoundingRectClipper(TDC& d, const TRect& b)
997 {
998 if (!ShouldClipTabBoundingRect_) return;
999 int rc = Dc.GetClipRgn(SavedClipRegion);
1000 CHECK(rc != -1);
1001 DidSaveClipRegion = rc == 1;
1002 int ri = Dc.IntersectClipRect(b);
1003 CHECK(ri != ERROR);
1004 }
1005
1007 {
1008 if (!ShouldClipTabBoundingRect_) return;
1009 int r = DidSaveClipRegion ?
1010 Dc.SelectClipRgn(SavedClipRegion) :
1011 Dc.RemoveClipRgn();
1012 CHECK(r != ERROR);
1013 }
1014 }
1016
1017#endif
1018
1019 // Define the contour of the tab.
1020 //
1021 // Note that we exclude the edge on the right and bottom of our bounding
1022 // rectangle, as per Windows drawing conventions. See the documentation
1023 // for GDI, e.g. for the Rectangle function:
1024 //
1025 // "The rectangle that is drawn excludes the bottom and right edges."
1026 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd162898.aspx
1027 //
1028 // By doing so we draw only within the clipping rectangle that would be
1029 // visible if we had intersected the clipping region with the tab's
1030 // bounding rectangle. This ensures that invalidation of our bounding
1031 // rectangle covers all pixels drawn.
1032 //
1033 int dx = TabTapering; // amount of narrowing on each side
1034 TPoint pt[4] =
1035 {
1036 tabBoundingRect.TopLeft(),
1037 tabBoundingRect.BottomLeft().OffsetBy(dx, -1),
1038 tabBoundingRect.BottomRight().OffsetBy(-dx - 1, -1),
1039 tabBoundingRect.TopRight().OffsetBy(-1, 0)
1040 };
1041
1042 // Fill the face of the tab, draw the contour and paint the label.
1043 // If the note tab has input focus, also draw the focus rectangle.
1044 //
1045 renderer.PaintTabFace(tabBoundingRect, pt, isSelectedTab);
1046 renderer.DrawTabContour(pt, isSelectedTab);
1047 if (isSelectedTab && GetFocus() == GetHandle())
1048 renderer.DrawTabFocusRect(tab, FocusMargin, SelectedTabProtrusion);
1049 bool hasImage = CelArray && tab.ImageIdx >= 0;
1050 if (hasImage)
1051 renderer.PaintTabIcon(tab, *CelArray, TransparentColor, LabelMargin, isSelectedTab, SelectedTabProtrusion);
1052 renderer.DrawTabText(tab, CelArray, LabelMargin, LabelImageMargin, isSelectedTab, SelectedTabProtrusion);
1053 }
1054
1055#if OWL_DRAW_TAB_BOUNDING_RECT_
1056
1058 for (int i = 0; i != GetCount(); ++i)
1059 {
1060 const TNoteTabItem& tab = TabList[i];
1061 if (tab.Rect.IsNull()) continue;
1062
1063 // Use Polyline for accuracy; Rectangle excludes right and bottom edge.
1064 //
1066 dc.SelectObject(tabRectPen);
1067 TRect b = GetBoundingRect(tab.Rect);
1068 TPoint bp[] = {b.TopLeft(), b.BottomLeft(), b.BottomRight(), b.TopRight(), b.TopLeft()};
1069 dc.Polyline(bp, COUNTOF(bp));
1070 }
1071
1072#endif
1073
1074 dc.RestorePen();
1075 dc.RestoreBrush();
1076 dc.RestoreFont();
1077}
1078
1079//
1080/// TWindow::Paint override
1081//
1082void
1084{
1085 const auto bkgndColor = GetBkgndColor();
1087 {
1089 if (GetCount() == 0)
1091 else
1092 {
1093 // First create a region consisting of the invalidated parts of the tabs
1094 // area, i.e. excluding the top margin, which will be painted later.
1095 // Then clip this against the tabs, since these will be painted anyway.
1096 // This leaves only the invalidated parts around the tabs. Note that we
1097 // do not exclude the scroller, since we rely on WS_CLIPCHILDREN.
1098 //
1099 TRect c = GetClientRect();
1100 TRect tabsArea(c.TopLeft().OffsetBy(0, Margin.cy), c.BottomRight());
1102 for (TNoteTabItemArray::const_iterator i = TabList.begin(); i != TabList.end(); ++i)
1103 {
1104 const TNoteTabItem& t = *i;
1105 CHECK(t.Rect.IsNull() || !t.Rect.IsEmpty());
1106 r -= t.Rect;
1107 }
1108 dc.FillRgn(r, TBrush{color}); // May be NULLREGION at this point.
1109 }
1110 }
1111
1112 if (GetCount() == 0) return;
1113
1114 if (ShouldUseThemes && IsThemed_())
1116 else if (Style3d)
1118 else if (WindowFace)
1120 else
1122
1123 if (ScrollButtons->IsWindowVisible())
1124 {
1125 ScrollButtons->Invalidate(false);
1126 ScrollButtons->UpdateWindow();
1127 }
1128
1129 LastClientRectPainted = GetClientRect(); // See EvSize.
1130}
1131
1132//
1133/// WM_SIZE handler - Relay tab items
1134//
1135void
1137{
1139
1140 // Unless the layout of the tabs changes in response to the size change,
1141 // the only stale part of the old painting is possibly the right and bottom
1142 // edges, which are only drawn for 3D style. These need to be invalidated if
1143 // the width or height of the window increases.
1144 //
1145 if (Style3d)
1146 {
1147 const auto getRightEdge = [](const TRect& r) { return TRect{r.TopRight().OffsetBy(-TUIMetric::CyEdge, 0), r.BottomRight()}; };
1148 const auto getBottomEdge = [](const TRect& r) { return TRect{r.BottomLeft().OffsetBy(0, -TUIMetric::CxEdge), r.BottomRight()}; };
1149
1150 const auto n = GetClientRect();
1151 const auto& p = LastClientRectPainted;
1152 const auto hasPaintedBefore = !p.IsNull();
1153
1154 if (hasPaintedBefore && n.Width() > p.Width()) // Increasing width; invalidate old right edge.
1156 else if (!hasPaintedBefore || n.Width() < p.Width()) // New or decreasing width; invalidate new right edge.
1158
1159 if (hasPaintedBefore && n.Height() > p.Height()) // Inreasing height; invalidate old bottom edge.
1161 else if (!hasPaintedBefore || n.Height() < p.Height()) // New or decreasing height; invalidate new bottom edge.
1163 }
1164
1165 // Layout tab items.
1166 //
1167 int s = GetSel();
1168 bool hasVisibleSel = GetCount() > 0 && s >= 0 && IsVisible(s);
1169 SetTabRects(FirstVisibleTab);
1170 if (hasVisibleSel)
1171 EnsureVisible(s);
1172}
1173
1174//
1175/// WM_LBUTTONDOWN handler - Checks whether the mouse was clicked on a tab item and
1176/// selects it.
1177///
1178/// \note A notification is sent to the parent before and after selecting the tab.
1179/// The parent may choose to veto the selection after receiving the first
1180/// notification.
1181//
1182void
1184{
1185 PRECONDITION(ScrollButtons);
1186 if (ScrollButtons->IsWindowVisible() && GetScrollerArea().Contains(point)) return;
1187
1188 SetFocus();
1189
1190 const auto hitIndex = TabFromPoint(point);
1191 if (hitIndex != -1)
1193}
1194
1195//
1196/// Handle WM_SETFOCUS: Draw focus to identify selected tab.
1197//
1198void
1200{
1201 PRECONDITION(SelectedTab >= 0 && SelectedTab < GetCount());
1203 InvalidateRect(TabList[SelectedTab].Rect);
1204 UpdateWindow();
1205}
1206
1207//
1208/// Handle WM_KillFOCUS: Remove dotted focus rectangle from selected tab.
1209//
1210void
1212{
1213 PRECONDITION(SelectedTab >= 0 && SelectedTab < GetCount());
1215 InvalidateRect(TabList[SelectedTab].Rect);
1216 UpdateWindow();
1217}
1218
1219//
1220/// WM_GETDLGCODE handler - Informs dialog manager that arrow keys are to be used.
1221//
1222uint
1227
1228//
1229/// WM_KEYDOWN handler - handles arrow keys to allow user to navigate through tab
1230/// items.
1231//
1232void
1233TNoteTab::EvKeyDown(uint key, uint /*repeatCount*/, uint /*flags*/)
1234{
1235 int tab = GetSel();
1236 if (tab < 0) return;
1237 CHECK(tab < GetCount());
1238
1239 if (GetKeyState(VK_CONTROL) & 0x8000) switch (key)
1240 {
1241 case VK_RIGHT:
1242 EvHScroll(SB_LINERIGHT, 0, nullptr);
1243 break;
1244
1245 case VK_LEFT:
1246 EvHScroll(SB_LINELEFT, 0, nullptr);
1247 break;
1248 }
1249 else switch (key)
1250 {
1251 case VK_RIGHT:
1252 {
1253 int last = GetCount() - 1;
1254 if (tab < last)
1255 {
1256 if (NotifyAndSelect(++tab))
1257 {
1259 while (!IsFullyVisible(tab) && GetFirstVisibleTab() < last)
1261 }
1262 }
1263 break;
1264 }
1265 case VK_LEFT:
1266 {
1267 if (tab > 0)
1268 {
1269 if (NotifyAndSelect(--tab))
1271 }
1272 break;
1273 }
1274
1275#if OWL_CLIP_TAB_BOUNDING_RECT_
1276
1277 case VK_F2:
1279 Invalidate();
1280 break;
1281
1282#endif
1283
1284#if OWL_DRAW_TAB_BOUNDING_RECT_
1285
1286 case VK_F3:
1288 Invalidate();
1289 break;
1290
1291#endif
1292
1293 }
1294}
1295
1296//
1297/// Updates the internal information stored about the label of a particular tab
1298/// item.
1299//
1300void
1302{
1303 PRECONDITION(TabFont);
1304
1306
1307 // Compute size of label.
1308 // Accommodate the largest font in both dimensions.
1309 // Use screen DC (may be called before 'HWND').
1310 //
1311 TScreenDC dc;
1312 TNoteTabItem& tab = TabList[index];
1313 static const tchar overhangSet[] = _T("dfkmVWY"); // TODO: Add complete set, or query font.
1314 bool hasOverhang = !tab.Label.empty() &&
1315 (TabFont->GetObject().lfItalic || selectedTabFont.GetObject().lfItalic) &&
1316 find(begin(overhangSet), end(overhangSet), tab.Label.back()) != end(overhangSet);
1317 tstring s = tab.Label + (hasOverhang ? _T(" ") : _T(""));
1318 TRect regularExtent = TRect(TPoint(), TabFont->GetTextExtent(dc, s));
1319 TRect selectedExtent = TRect(TPoint(), selectedTabFont.GetTextExtent(dc, s));
1320 tab.LabelSize = (regularExtent | selectedExtent).Size();
1321
1322 // Add image dimensions to LabelSize.
1323 //
1324 if (tab.ImageIdx >= 0 && CelArray)
1325 {
1326 TSize size = CelArray->CelSize();
1327 tab.LabelSize.cx += size.cx + LabelImageMargin;
1328 tab.LabelSize.cy = std::max(tab.LabelSize.cy, size.cy);
1329 }
1330}
1331
1332//
1333/// Calculates the tab rectangle for the given tab and position.
1334//
1335TRect
1336TNoteTab::CalculateTabRect(const TNoteTabItem& tab, const TPoint& p, bool isSelected) const
1337{
1338 TSize padding(2 * LabelMargin.cx, 2 * LabelMargin.cy + (isSelected ? SelectedTabProtrusion : 0));
1339 return TRect(p.OffsetBy(TabTapering, 0), tab.LabelSize + padding);
1340};
1341
1342
1343//
1344/// Calculates and returns a list of updated tab hit rectangles based on the
1345/// given start index and the given area for the tabs.
1346//
1347TNoteTab::TRects
1348TNoteTab::CalculateTabRects(int firstTab, const TRect& area) const
1349{
1350 TRects rects;
1351 rects.reserve(GetCount());
1352
1353 // Reset all the tab rectangles preceeding the first visible tab.
1354 // Value-initialize these by calling `resize` (i.e. insert empty rectangles).
1355 //
1356 rects.resize(std::min(firstTab, GetCount()));
1357
1358 // Assign rectangles to all visible tabs.
1359 //
1360 TPoint p = area.TopLeft();
1361 for (int i = firstTab; i != GetCount(); ++i)
1362 {
1363 const TNoteTabItem& tab = TabList[i];
1364 const TRect r = CalculateTabRect(tab, p, i == SelectedTab);
1365
1366 // If the tab is completely outside the tabs area, then break. In other
1367 // words; include partially visible tabs.
1368 //
1369 const TRect b = GetBoundingRect(r);
1370 bool isVisible = (b.left < area.right);
1371 if (!isVisible)
1372 {
1373 // Reset the rectangles for the remaining tabs, then exit.
1374 //
1375 rects.resize(GetCount());
1376 break;
1377 }
1378 rects.push_back(r);
1379 p.Offset(r.Width() + TabSpacing, 0); // Move to next tab position.
1380 }
1381 return rects;
1382}
1383
1384
1385//
1386/// Assigns the given new rectangle to the given tab item.
1387/// Both old and new rectangle is invalidated in the client area.
1388//
1389void
1390TNoteTab::AssignTabRect(TNoteTabItem& tab, const TRect& newRect)
1391{
1392 TRect& r = tab.Rect;
1393 if (r == newRect) return;
1394 if (GetHandle() && !r.IsNull())
1395 InvalidateRect(GetBoundingRect(r));
1396 r = newRect;
1397 if (GetHandle() && !r.IsNull())
1398 InvalidateRect(GetBoundingRect(r));
1399}
1400
1401namespace
1402{
1403
1404 //
1405 // Returns true if the horizontal projection of the given rect `r`
1406 // lies within the horizontal projection of the given rect `area`.
1407 //
1408 bool ContainsHorizontalExtents_(const TRect& area, const TRect& r)
1409 {
1410 if (area.IsEmpty() || r.IsEmpty()) return false;
1411 return r.left >= area.left && r.right <= area.right;
1412 }
1413
1414} // namespace
1415
1416//
1417/// Lays out tab items (and scroll buttons) with the specified index at the leftmost.
1418/// Scroll buttons are enabled when needed (unless the scroll location is set to alNone).
1419//
1421{
1422 const auto tabCount = GetCount();
1423 PRECONDITION((tabCount == 0 && firstTab == 0) || (firstTab >= 0 && firstTab < tabCount));
1424 if (!GetHandle()) return;
1425
1426 // First, calculate tab layout with no scroll buttons present. If we have multiple tabs, and all
1427 // tabs did not fit, then we need to reserve space for the scroll buttons (unless ScrollLoc ==
1428 // alNone), so calculate the layout anew within the dedicated tabs area. Finally, store the
1429 // effective tabs area, and assign tab rectangles for the new layout.
1430 //
1431 const auto c = GetClientRect();
1432 const auto allArea = TRect{c.TopLeft() + Margin, c.BottomRight()};
1434 const auto scrollerArea = GetScrollerArea();
1435 auto newRects = CalculateTabRects(firstTab, allArea);
1436 const auto needScrolling = ScrollLoc != alNone && tabCount > 1 &&
1437 (
1438 firstTab != 0 || // Invisible tab to the left.
1439 newRects.back().IsNull() || // Invisible tab to the right.
1440 !ContainsHorizontalExtents_(allArea, GetBoundingRect(newRects.back())) // Tab does not fit.
1441 );
1442 if (needScrolling)
1443 newRects = CalculateTabRects(firstTab, scrollingTabsArea);
1444 EffectiveTabsArea = needScrolling ? scrollingTabsArea : allArea;
1445 CHECK(static_cast<int>(newRects.size()) == tabCount);
1446 for (auto i = 0; i != tabCount; ++i)
1447 AssignTabRect(TabList[i], newRects[i]);
1448
1449 // If we need scrolling, then calculate the upper index of the scroll range. Then update and show
1450 // the scroll buttons. Otherwise, hide the scroll buttons.
1451 //
1452 CHECK(ScrollButtons && ScrollButtons->GetHandle());
1453 if (needScrolling)
1454 {
1455 const auto countNotFullyVisibleTabs = [&]
1456 {
1459 auto n = firstTab; // Invisible tabs to the left.
1460 for (auto i = tabCount - 1; i >= firstTab && !IsFullyVisible(i); --i)
1461 ++n; // Invisible (or partially visible) tab to the right.
1462 CHECK(n >= 0 && n <= tabCount);
1463 return n;
1464 };
1465 const auto upper = min(countNotFullyVisibleTabs(), tabCount - 1);
1466 CHECK(upper > 0 && upper < tabCount);
1467 ScrollButtons->SetRange(0, upper);
1468 ScrollButtons->SetPos(firstTab);
1469 ScrollButtons->MoveWindow(scrollerArea, true);
1470 ScrollButtons->ShowWindow(SW_SHOW);
1471 ScrollButtons->UpdateWindow();
1472 }
1473 else
1474 ScrollButtons->ShowWindow(SW_HIDE);
1475}
1476
1477//
1478/// Returns the index of the tab item at the specified window coordinate. Returns -1
1479/// on failure.
1480//
1481int
1483{
1484 for (int i = 0; i < GetCount(); i++)
1485 {
1486 const TNoteTabItem& tab = TabList[i];
1487 if (tab.Rect.Contains(pt))
1488 return i;
1489 }
1490 return -1;
1491}
1492
1493//
1494/// Selects the tab at the given index and sends the appropriate notifications.
1495/// Returns false if the change was vetoed by the buddy/parent, true otherwise.
1496/// Does nothing and returns false if the tab at the given index is already selected.
1497//
1498bool
1500{
1501 PRECONDITION(index >= 0);
1502 PRECONDITION(index < GetCount());
1503
1504 if (index == SelectedTab) return false;
1505
1506 HWND receiver = Buddy ? BuddyHandle : ::GetParent(GetHandle());
1507
1508 // First notify that we're about to change selection.
1509 //
1510 TNotify nSelChanging(*this, Attr.Id, TCN_SELCHANGING);
1512 if (wasVetoed) return false;
1513
1514 // Set new selection and notify that it has changed.
1515 //
1516 SetSel(index);
1517 TNotify nSelChange(*this, Attr.Id, TCN_SELCHANGE);
1519 return true;
1520}
1521
1522//
1523// Refreshes the drawing of the control.
1524// If the control has not been created yet, does nothing.
1525//
1526void
1528{
1529 if (!GetHandle()) return;
1530 for (int i = 0; i != GetCount(); ++i)
1531 SetTabSize(i);
1533 Invalidate();
1534}
1535
1536//
1537/// Returns the desired location of the scrollers within the tab.
1538//
1539TRect
1541{
1543 rect.bottom -= TUIMetric::CyFixedFrame;
1544 rect.top = std::max(
1545 rect.top + Margin.cy + TUIMetric::CyFixedFrame,
1546 rect.bottom - TUIMetric::CyHScroll);
1547 switch (ScrollLoc)
1548 {
1549 default:
1550 case alNone:
1551 rect.left = rect.right = 0;
1552 break;
1553
1554 case alLeft:
1556 rect.right = rect.left + 2 * TUIMetric::CxHScroll;
1557 break;
1558
1559 case alRight:
1560 rect.left = rect.right - 2 * TUIMetric::CxHScroll;
1562 break;
1563 }
1564 return rect;
1565}
1566
1567//
1568/// Returns the rectangle of the area reserved for tabs when scrolling is active.
1569//
1570TRect
1572{
1573 // First retrieve left, top and right borders
1574 //
1576 rect.left += Margin.cx;
1577 rect.top += Margin.cy;
1579 switch (ScrollLoc)
1580 {
1581 default:
1582 case alRight:
1583 rect.right -= scrollArea.Width();
1584 break;
1585 case alLeft:
1586 rect.left += scrollArea.Width();
1587 break;
1588 }
1589 return rect;
1590}
1591
1592//
1593/// Returns true if the tab item at the specified index is visible.
1594/// Note that true is returned even if the tab is only partially visible.
1595/// Use IsFullyVisible to check for full visibility.
1596//
1597bool
1598TNoteTab::IsVisible(int index) const
1599{
1600 PRECONDITION(index < GetCount() && index >= 0);
1601 return TabList[index].Rect.IsNull() ? false : true;
1602}
1603
1604//
1605/// Returns true if the horizontal projection of the tab item at the specified
1606/// index is contained within the horizontal projection of the current
1607/// effective tabs area. Vertical visibility is ignored.
1608//
1609bool
1611{
1612 PRECONDITION(index < GetCount() && index >= 0);
1613 if (EffectiveTabsArea.IsEmpty()) return false;
1614 if (!IsVisible(index)) return false;
1615 TRect b = GetBoundingRect(TabList[index].Rect);
1616 CHECK(!b.IsEmpty());
1617 return ContainsHorizontalExtents_(EffectiveTabsArea, b);
1618}
1619
1620//
1621/// Sets FirstVisibleTab to index if index is valid.
1622//
1623void
1625{
1626 if (index == GetFirstVisibleTab() || index < 0 || index >= GetCount()) return;
1627 FirstVisibleTab = index;
1628 SetTabRects(FirstVisibleTab);
1629}
1630
1631//
1632/// If the tab specified by index is not visible, it is scrolled into view.
1633/// If the given index is -1, the index of the selected tab is used instead.
1634/// Returns true if successful, false on failure.
1635//
1636bool
1638{
1639 PRECONDITION(GetCount() > 0);
1640 PRECONDITION(index >= -1 && index < GetCount());
1641 int i = (index == -1) ? GetSel() : index; CHECK(i >= 0);
1642 while (i != GetFirstVisibleTab() && !IsFullyVisible(i))
1643 {
1644 int v = GetFirstVisibleTab(); CHECK(v != i);
1645 SetFirstVisibleTab(v + (i < v ? -1 : +1));
1646 }
1647 return true;
1648}
1649
1650//
1651/// Sets the first visible tab to the given thumb position.
1652//
1658
1659//
1660/// EV_WM_PAINT handler.
1661//
1662void
1667
1668//
1669/// Disables automatic background erasure by returning `false`.
1670//
1671bool
1673{
1674 return false;
1675}
1676
1677//
1678/// Set the scroller location.
1679//
1680void
1682{
1683 if (ScrollLoc == loc)
1684 return;
1685
1686 ScrollLoc = loc;
1687
1688 SetTabRects(FirstVisibleTab);
1689}
1690
1691//
1692/// Sets the bitmap array to be used for the tabs.
1693/// Use SetCelArrayTransparentColor to set the bitmap pixel color that should
1694/// not be drawn. The default color is TColor::Sys3dFace.
1695//
1696void
1698{
1699 CelArray = array;
1700 OwnedCelArray.reset(del == AutoDelete ? array : nullptr);
1701 Update();
1702}
1703
1704//
1705/// Sets the color assigned to denote transparency in the bitmaps used for the
1706/// tabs (see SetCelArray). All the bitmap pixels of this color will be fully
1707/// transparent (i.e. not drawn).
1708//
1709void
1711{
1712 TransparentColor = c;
1713 Update();
1714}
1715
1716} // OWL namespace
1717/* ========================================================================== */
Definition of a bitmap Cel array class.
#define CHECK(condition)
Definition checks.h:239
#define PRECONDITION(condition)
Definition checks.h:227
#define CHECKX(condition, message)
Definition checks.h:245
The GDI Brush class is derived from TGdiObject.
Definition gdiobjec.h:180
TCelArray is a horizontal array of cels (a unit of animation) created by slicing a portion of or an e...
Definition celarray.h:35
TSize CelSize() const
Return the size of the celarray.
Definition celarray.h:133
Class wrapper for management of color values.
Definition color.h:245
static const TColor Transparent
a non-painting color
Definition color.h:319
static const TColor None
not-a-color
Definition color.h:318
static const TColor SysWindowFrame
The symbolic system color value for the frame around each window.
Definition color.h:330
static const TColor SysWindowText
The symbolic system color value for text in every window.
Definition color.h:332
static const TColor Sys3dFace
The symbolic system color value for the face color of 3-dimensional display elements.
Definition color.h:339
static const TColor SysWindow
The symbolic system color value for the background of each window.
Definition color.h:329
static const TColor LtRed
Static TColor object with fixed Value set by RGB(255, 0, 0).
Definition color.h:308
TControl unifies its derived control classes, such as TScrollBar, TControlGadget, and TButton.
Definition control.h:38
void EvPaint()
Intercept WM_PAINT to redirect from TWindow to the underlying control if this Owl object is just a wr...
Definition control.cpp:159
TDC is the root class for GDI DC wrappers.
Definition dc.h:64
bool FillSolidRect(const TRect &r, const TColor &color)
Definition dc.h:318
bool FillRgn(const TRegion &region, const TBrush &brush)
Fills the given region on this DC using the specified brush.
Definition dc.h:1932
Encapsulates the system font used for a specific GUI element, e.g. icon, caption, menu,...
Definition gdiobjec.h:380
TFont derived from TGdiObject provides constructors for creating font objects from explicit informati...
Definition gdiobjec.h:296
ObjectWindows dynamic-link libraries (DLLs) construct an instance of TModule, which acts as an object...
Definition module.h:75
TNotify is a thin wrapper around the NMHDR structure.
Definition commctrl.h:91
TPoint is a support class, derived from tagPOINT.
Definition geometry.h:87
TPoint OffsetBy(int dx, int dy) const
Calculates an offset to this point using the given displacement arguments.
Definition geometry.h:482
TRect is a mathematical class derived from tagRect.
Definition geometry.h:308
bool IsNull() const
Returns true if left, right, top, and bottom are all 0; otherwise, returns false.
Definition geometry.h:1167
bool IsEmpty() const
Returns true if left >= right or top >= bottom; otherwise, returns false.
Definition geometry.h:1157
TRegion, derived from TGdiObject, represents GDI abstract shapes or regions.
Definition gdiobjec.h:581
Derived from TWindowDC, TScreenDC is a DC class that provides direct access to the screen bitmap.
Definition dc.h:610
The tagSIZE struct is defined as.
Definition geometry.h:234
static TThemeModule & GetInstance()
Returns the module instance.
Definition theme.cpp:91
@ WndRecessed
Input field & other window recessed.
Definition uihelper.h:306
@ Normal
Normal state.
Definition uihelper.h:373
static const TUIMetric CyEdge
Definition uimetric.h:80
static const TUIMetric CyHScroll
Definition uimetric.h:37
static const TUIMetric CyFixedFrame
Definition uimetric.h:42
static const TUIMetric CySizeFrame
Definition uimetric.h:67
static const TUIMetric CxFixedFrame
Definition uimetric.h:41
static const TUIMetric CxEdge
Definition uimetric.h:79
static const TUIMetric CxHScroll
Definition uimetric.h:55
TUpDown encapsulates an up-down control, which is a window with a pair of arrow buttons that the user...
Definition updown.h:40
void SetRange(int lower, int upper)
Sets the minimum and maximum positions of the up-down control.
Definition updown.h:174
TResult SetPos(int pos)
Sets the current position of the underlying up-down control.
Definition updown.h:165
Type-safe encapsulation of a Windows class name, a union between ATOM and LPCTSTR.
Definition module.h:47
TWindow, derived from TEventHandler and TStreamableBase, provides window-specific behavior and encaps...
Definition window.h:414
HWND SetFocus()
Sets the keyboard focus to current window and activates the window that receives the focus by sending...
Definition window.h:2151
void SetBkgndColor(TColor color, bool shouldUpdate=true)
Sets the background color for the window.
Definition window.h:1925
TWindow()
Protected constructor for use by immediate virtually derived classes.
Definition window.cpp:392
TWindow * GetParent() const
Retrieves the OWL object of the parent window. If none exists, returns 0.
Definition window.h:2013
auto GetBkgndColor() const -> TColor
Returns the overriding background color set for the window.
Definition window.h:1913
virtual void InvalidateRect(const TRect &rect, bool erase=true)
Invalidates a specified client area.
Definition window.h:2834
uint EvGetDlgCode(const MSG *msg)
The default message handler for WM_GETDLGCODE.
Definition window.h:3698
void EvKillFocus(HWND hWndGetFocus)
Handle WM_KILLFOCUS so that we can have a parent window hold onto our Handle and possibly restore foc...
Definition window.cpp:1611
bool ModifyStyle(uint32 offBits, uint32 onBits, uint swpFlags=0)
Modifies the style bits of the window.
Definition window.cpp:3591
bool MoveWindow(int x, int y, int w, int h, bool repaint=false)
Repositions the specified window.
Definition window.h:2571
TRect GetClientRect() const
Gets the coordinates of the window's client area (the area in a window you can use for drawing).
Definition window.h:2217
void UpdateWindow()
Updates the client area of the specified window by immediately sending a WM_PAINT message.
Definition window.h:2901
void EvSetFocus(HWND hWndLostFocus)
The default message handler for WM_SETFOCUS.
Definition window.h:4084
void SendNotification(int id, int notifyCode, HWND hCtl, TMsgId=WM_COMMAND)
Repacks a command message (msg) so that a child window (hCtl) can send a message to its parent regard...
Definition window.h:2055
bool IsWindowVisible() const
Returns true if the window is visible.
Definition window.h:2605
virtual bool ShowWindow(int cmdShow)
Displays this TWindow in a given state.
Definition window.cpp:3713
virtual void SetupWindow()
Performs setup following creation of an associated MS-Windows window.
Definition window.cpp:2575
static HWND GetFocus()
Gets a handle to the window that has the focus.
Definition window.h:2139
void EvSize(uint sizeType, const TSize &size)
Response method for an incoming WM_SIZE message.
Definition window.cpp:1632
HWND THandle
TWindow encapsulates an HWND.
Definition window.h:418
virtual void Invalidate(bool erase=true)
Invalidates (mark for painting) the entire client area of a window.
Definition window.h:2822
HWND GetHandle() const
Returns the handle of the window.
Definition window.h:2020
Definition of classes for CommonControl encapsulation.
Definition of container classes used and made available by OWL.
Definition of class TControl.
#define _T(x)
Definition cygwin.h:51
#define DEFINE_RESPONSE_TABLE1(cls, base)
Macro to define a response table for a class with one base.
Definition eventhan.h:492
Utilities for GDI+ interoperability.
TAutoDelete
Flag for Handle ctors to control Handle deletion in dtor.
Definition gdibase.h:70
@ AutoDelete
Definition gdibase.h:70
void EvLButtonDown(uint modKeys, const TPoint &point)
WM_LBUTTONDOWN handler - Checks whether the mouse was clicked on a tab item and selects it.
Definition notetab.cpp:1183
TRect Rect
Location of tab [client-area base coords].
Definition notetab.h:56
uint EvGetDlgCode(const MSG *msg)
WM_GETDLGCODE handler - Informs dialog manager that arrow keys are to be used.
Definition notetab.cpp:1223
int Add(LPCTSTR txt, INT_PTR clientData=0, int imageIdx=-1, TAbsLocation imageLoc=alLeft, bool shouldSelect=true)
Adds a new tabitem to the notetab control.
Definition notetab.cpp:122
void SetSelectedTabFont(const TFont &)
Sets the font used to render the text part of the selected tab label.
Definition notetab.cpp:394
void SetSelectedTabColor(const TColor &)
Sets the fill color used to paint the selected tab.
Definition notetab.cpp:415
auto GetWindowClassName() -> TWindowClassName override
Returns "OWL_Notetab" - the Window class name of the notetab control object.
Definition notetab.cpp:98
void EvKeyDown(uint key, uint repeatCount, uint flags)
WM_KEYDOWN handler - handles arrow keys to allow user to navigate through tab items.
Definition notetab.cpp:1233
int TabFromPoint(const TPoint &pt) const
Returns the index of the tab item at the specified window coordinate.
Definition notetab.cpp:1482
void SetLabelMargin(const TSize &)
Sets the amount of padding around the tab label.
Definition notetab.cpp:304
bool IsVisible(int index) const
Returns true if the tab item at the specified index is visible.
Definition notetab.cpp:1598
int GetSel() const
Returns the index of the selected tabitem.
Definition notetab.cpp:234
bool EnsureVisible(int index)
If the tab specified by index is not visible, it is scrolled into view.
Definition notetab.cpp:1637
const TFont & GetSelectedTabFont() const
Returns the font used to render the text part of the selected tab label.
Definition notetab.cpp:384
int Insert(LPCTSTR txt, int index, INT_PTR clientData=0, int imageIdx=-1, TAbsLocation imageLoc=alLeft, bool shouldSelect=true)
Inserts a new TTabItem at the specified index.
Definition notetab.cpp:136
void SetSelectedTabProtrusion(int)
Sets the amount of extra height of the selected tab.
Definition notetab.cpp:354
void EvSetFocus(THandle hWndLostFocus)
Handle WM_SETFOCUS: Draw focus to identify selected tab.
Definition notetab.cpp:1199
const TFont & GetTabFont() const
Returns the font used to render the text part of the tab labels.
Definition notetab.cpp:364
HWND GetBuddy() const
Return handle of buddy window associated with the notetab control.
Definition notetab.cpp:479
void SetFirstVisibleTab(int index)
Sets FirstVisibleTab to index if index is valid.
Definition notetab.cpp:1624
void SetTabFont(const TFont &)
Sets the font used to render the text part of the tab labels.
Definition notetab.cpp:374
bool IsFullyVisible(int index) const
Returns true if the horizontal projection of the tab item at the specified index is contained within ...
Definition notetab.cpp:1610
void SetTabTapering(int)
Sets the amount of narrowing on each side of the tab towards the bottom.
Definition notetab.cpp:344
void SetMargin(const TSize &)
Sets the amount of space to the left of the tabs and above the tabs.
Definition notetab.cpp:294
bool GetItem(int index, TNoteTabItem &item) const
Retrieve information about the tab item at the specified index.
Definition notetab.cpp:436
void SetEdgeColor(const TColor &)
Sets the pen color used to draw the edges of the tabs.
Definition notetab.cpp:425
void SetFocusMargin(const TSize &)
Sets the margin around the focus rectangle for the selected tab.
Definition notetab.cpp:324
void SetBuddy(HWND buddy)
Sets handle of the buddy window associated with this notetab control.
Definition notetab.cpp:488
int SetSel(int index)
Selects the tabitem at the specified index.
Definition notetab.cpp:246
void SetTabRects(int firstTab)
Lays out tab items (and scroll buttons) with the specified index at the leftmost.
Definition notetab.cpp:1420
void SetLabelImageMargin(int)
Sets the horizontal spacing between image and text in the label.
Definition notetab.cpp:314
TNoteTab(TWindow *parent, int id, int x, int y, int w, int h, TWindow *buddy=0, bool dialogBuddy=true, TModule *module=0)
Constructor of NoteTab object.
Definition notetab.cpp:64
TRect GetScrollerArea() const
Returns the desired location of the scrollers within the tab.
Definition notetab.cpp:1540
void EvHScroll(uint scrollCode, uint thumbPos, HWND hWndCtl)
Sets the first visible tab to the given thumb position.
Definition notetab.cpp:1653
bool Delete(int index)
Remove the tabitem at the specified 'index'.
Definition notetab.cpp:162
void EvKillFocus(THandle hwndGetFocus)
Handle WM_KillFOCUS: Remove dotted focus rectangle from selected tab.
Definition notetab.cpp:1211
bool SetItem(int index, const TNoteTabItem &item)
Updates information about the tab item at the specified index.
Definition notetab.cpp:460
void SetupWindow() override
Overriden virtual of TWindow - Initializes font used by control and resize accordingly.
Definition notetab.cpp:108
bool NotifyAndSelect(int index)
Selects the tab at the given index and sends the appropriate notifications.
Definition notetab.cpp:1499
void SetTabColor(const TColor &)
Sets the fill color used to paint the tabs.
Definition notetab.cpp:404
void EvPaint()
EV_WM_PAINT handler.
Definition notetab.cpp:1663
void SetCelArrayTransparentColor(const TColor &)
Sets the color assigned to denote transparency in the bitmaps used for the tabs (see SetCelArray).
Definition notetab.cpp:1710
int GetFirstVisibleTab() const
Returns FirstVisibleTab.
Definition notetab.h:406
void InvalidateTab(int index)
Invalidates the rectangle occupied by the tab at the specified index.
Definition notetab.cpp:561
void SetTabSize(int index)
Updates the internal information stored about the label of a particular tab item.
Definition notetab.cpp:1301
bool DeleteAll()
Removes all tab items in the notetab control. Always returns true.
Definition notetab.cpp:209
void SetCelArray(TCelArray *array, TAutoDelete=AutoDelete)
Sets the bitmap array to be used for the tabs.
Definition notetab.cpp:1697
void SetScrollLocation(TAbsLocation pos)
Set the scroller location.
Definition notetab.cpp:1681
bool EvEraseBkgnd(HDC)
Disables automatic background erasure by returning false.
Definition notetab.cpp:1672
void SetTabSpacing(int)
Sets the horizontal distance between two tabs.
Definition notetab.cpp:334
TRect GetScrollingTabsArea() const
Returns the rectangle of the area reserved for tabs when scrolling is active.
Definition notetab.cpp:1571
void EvSize(uint sizeType, const TSize &size)
WM_SIZE handler - Relay tab items.
Definition notetab.cpp:1136
void Paint(TDC &, bool erase, TRect &) override
TWindow::Paint override.
Definition notetab.cpp:1083
auto Transfer(void *buffer, TTransferDirection) -> uint override
Overrides TWindow virtual member function to handle transfers.
Definition notetab.cpp:501
void InitCtrl()
Initialize internal variables used by NoteTab.
Definition notetab.cpp:512
int GetCount() const
Return the number of tab items in the notetab control.
Definition notetab.cpp:222
int GetMinimalHeight()
Returns the minimal control height for which tabs are not clipped.
Definition notetab.cpp:271
TAbsLocation
General use absolute 2-D rectangular location enum.
Definition geometry.h:62
@ alRight
Refers to right edge of frame.
Definition geometry.h:67
@ alLeft
Refers to left edge of frame.
Definition geometry.h:66
@ alNone
No location specified.
Definition geometry.h:63
TTransferDirection
The TTransferDirection enum describes the constants that the transfer function uses to determine how ...
Definition window.h:92
Height
Definition occtrl.cpp:160
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
EV_WM_HSCROLL
Definition notetab.cpp:55
EV_WM_PAINT
Definition control.cpp:28
EV_WM_KILLFOCUS
Definition edit.cpp:85
EV_WM_KEYDOWN
Definition edit.cpp:82
TWindow * GetWindowPtr(HWND, const TApplication *)
Raw function to retrieve a TWindow pointer given an HWND from the a given app, or any app (app==0).
Definition window.cpp:1557
void InUse(const T &arg)
Handy utility to avoid compiler warnings about unused parameters.
Definition defs.h:299
auto GetCommCtrlVersion() -> DWORD
Returns the version number of the Common Control library (ComCtl32.dll).
Definition commctrl.cpp:26
OWL_DIAGINFO
Definition animctrl.cpp:14
EV_WM_SETFOCUS
Definition edit.cpp:84
END_RESPONSE_TABLE
Definition button.cpp:26
unsigned short uint16
Definition number.h:33
std::string tstring
Definition defs.h:79
EV_WM_GETDLGCODE
Definition button.cpp:24
unsigned int uint
Definition number.h:25
EV_WM_LBUTTONDOWN
Definition checklst.cpp:195
EV_WM_ERASEBKGND
Definition docking.cpp:965
EV_WM_SIZE
Definition decframe.cpp:34
Definition of class TNoteTab.
#define OWL_NOTETAB
Definition notetab.h:26
#define COUNTOF(s)
Array element count Important: Only use this with an argument of array type.
Definition defs.h:376
TNoteTabItem holds information about each tab in a notetab control.
Definition notetab.h:52
Microsoft UxTheme Library Encapsulation.
Definition of the UI Helper Classes: TUIHandle, TUIBorder, TUIFace, TUIPart.
Definition of TUIMetric, a UI metrics provider class.
Definition of class TUpDown.