OWLNext    7.0
Borland's Object Windows Library for the modern age
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 preceding 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.