//------------------------------------------------------------------------------
// ObjectWindows
// Copyright � 1998 by Bidus Yura. All Rights Reserved.
//
/// \file
/// Source file for implementation of TTabbedBase.
/// Added dynamic Add/DeletePage. Contributed by David Linch.
//------------------------------------------------------------------------------
//@doc TTabbedBase
#include <owl/pch.h>
#include <owl/defs.h>
#include <owl/docmanag.h>
#include <owl/layoutwi.h>
#include <owl/tabbed.h>
OWL_DIAGINFO;
namespace owl {
static void setWindowLayoutMetrics(TLayoutMetrics& lm, TNoteTab* tab,
TTabbedBase::TTabPosition pos)
{
if(pos == TTabbedBase::tpLeft){
lm.X.LeftOf(tab, 0);
lm.Y.SameAs(lmParent, lmTop);
lm.Width.SameAs(lmParent, lmWidth);
lm.Height.SameAs(lmParent, lmHeight);
}
else if(pos == TTabbedBase::tpRight){
lm.X.SameAs(lmParent, lmLeft);
lm.Y.SameAs(lmParent, lmTop);
lm.Width.RightOf(tab);
lm.Height.SameAs(lmParent, lmHeight);
}
else if(pos == TTabbedBase::tpTop){
lm.X.Below(tab);
lm.Y.SameAs(lmParent, lmTop);
lm.Width.SameAs(lmParent, lmWidth);
lm.Height.SameAs(lmParent, lmHeight);
}
else if(pos == TTabbedBase::tpBottom){
lm.X.SameAs(lmParent, lmLeft);
lm.Y.SameAs(lmParent, lmTop);
lm.Width.SameAs(lmParent, lmRight);
lm.Height.Above(tab);
}
}
////////////////////////////////////////////////////////////////////////////////
// TTabbedBase
// ~~~~~~~~~~~
DEFINE_RESPONSE_TABLE1(TTabbedBase, TEventHandler)
EV_TCN_SELCHANGE(IDC_TABCONTROL, EvTabControlSelChange),
EV_TCN_SELCHANGING(IDC_TABCONTROL, EvTabControlSelChanging),
END_RESPONSE_TABLE;
// -----------------------------------------------------------------------------
TTabbedBase::TTabbedBase(TWindow* self, int x, int y, int w, int h, TTabPosition pos, TNoteTab* tab)
:
Position(pos)
{
NoteTab = tab;
if(!NoteTab)
NoteTab = new TNoteTab(self, IDC_TABCONTROL, x,y,w,h);
}
// -----------------------------------------------------------------------------
TTabbedBase::TTabbedBase(TWindow* self, TTabPosition pos, TNoteTab* tab)
:
Position(pos)
{
NoteTab = tab;
if(!NoteTab)
NoteTab = new TNoteTab(self, IDC_TABCONTROL);
}
// -----------------------------------------------------------------------------
/// Add a new tab page.
/// \note Use before the Tab window is created!
int TTabbedBase::Add(TWindow& wnd, LPCTSTR titles)
{
LPCTSTR text = titles ? titles : wnd.GetCaption();
if (!text)
text = _T("");
int index = NoteTab->Add(text, INT_PTR((TWindow*)&wnd));
#if 0 // this code now in AddPage()
// if already constructed
if(NoteTab->GetHandle() && index >=0 ){
TLayoutWindow* layoutWnd = TYPESAFE_DOWNCAST(this, TLayoutWindow);
if(layoutWnd){
TLayoutMetrics lmWindow;
setWindowLayoutMetrics(lmWindow, NoteTab, Position);
if(!wnd.GetHandle())
wnd.Create();
layoutWnd->SetChildLayoutMetrics(wnd, lmWindow);
layoutWnd->Layout();
}
else{
if(!wnd.GetHandle())
wnd.Create();
AdjustPage(wnd);
}
wnd.ShowWindow(SW_SHOWNORMAL);
}
#endif
return index;
}
// -----------------------------------------------------------------------------
void TTabbedBase::AdjustPage(TWindow& page)
{
// assumes that note tab positioning
TWindow* parent = NoteTab->GetParentO();
// Retrieve area of tab (in terms of tabbed window)
TRect tRect;
NoteTab->GetWindowRect(tRect);
::MapWindowPoints(HWND_DESKTOP, *parent, LPPOINT(&tRect), 2);
TRect pgRect;
page.GetWindowRect(pgRect);
::MapWindowPoints(HWND_DESKTOP, *parent, LPPOINT(&pgRect), 2);
pgRect.left = pgRect.top = 0;
switch(Position){
case tpLeft:
pgRect += TPoint(tRect.Width(), 0);
break;
case tpRight:
if(pgRect.right > tRect.left)
pgRect.right = tRect.left;
break;
case tpTop:
pgRect += TPoint(0, tRect.Height());
break;
case tpBottom:
if(pgRect.bottom > tRect.top)
pgRect.bottom = tRect.top;
break;
}
page.SetWindowPos(HWND_TOP, pgRect, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER);
}
// -----------------------------------------------------------------------------
void TTabbedBase::SetupPages()
{
// first set all titles
TWindow* wnd;
TNoteTabItem Item;
int count = NoteTab->GetCount();
for(int i = 0; i< count; i++){
NoteTab->GetItem(i, Item);
wnd = ((TWindow*)Item.ClientData);
if (!wnd->IsWindow())
{
wnd->Create();
//Bug#1456799 Jogy (24.3.2006)
wnd->ShowWindow(SW_HIDE);
}
// it will be here only for dialog ????
if(Item.Label.empty()){
tchar title[MAX_PATH];
wnd->GetWindowText(title, MAX_PATH);
Item.Label = title;
NoteTab->SetItem(i, Item);
}
// Adjust child position
AdjustPage(*wnd);
}
if(count){
int Selected = NoteTab->GetSel();
NoteTab->GetItem(Selected, Item);
wnd = (TWindow*)Item.ClientData;
// Show the newly selected tab, if any.
if(wnd)
wnd->ShowWindow(SW_SHOWNORMAL);
}
}
// -----------------------------------------------------------------------------
TWindow* TTabbedBase::GetPage(int index)
{
if(index == -1)
index = NoteTab->GetSel();
TNoteTabItem Item;
NoteTab->GetItem(index, Item);
return (TWindow*)Item.ClientData;
}
//
/// Hides the current page and shows the page at the given index.
/// Does nothing if the page at the given index is already selected.
/// Note that this function does not send any notifications.
//
void TTabbedBase::SelectPage(int index, bool shouldFocusPage)
{
PRECONDITION(index >= 0 && index < NoteTab->GetCount());
if (index == NoteTab->GetSel()) return;
if (const auto currentPage = GetPage())
currentPage->ShowWindow(SW_HIDE);
NoteTab->SetSel(index);
const auto newPage = GetPage();
newPage->ShowWindow(SW_SHOWNORMAL);
if (shouldFocusPage)
newPage->SetFocus();
}
void TTabbedBase::EvTabControlSelChange(TNotify&)
{
if (const auto w = GetPage())
w->ShowWindow(SW_SHOWNORMAL);
}
bool TTabbedBase::EvTabControlSelChanging(TNotify &)
{
if (const auto w = GetPage())
w->ShowWindow(SW_HIDE);
return false; // Don't veto the change.
}
//////////////////////////////////////////////////////////////
//
//
DEFINE_RESPONSE_TABLE2(TTabbedWindow, TLayoutWindow, TTabbedBase)
END_RESPONSE_TABLE;
TTabbedWindow::TTabbedWindow(TWindow* parent, LPCTSTR title, TModule* module)
:
TLayoutWindow(parent, title, module),
TTabbedBase(this,0,0,0,0)
{
Init();
}
TTabbedWindow::TTabbedWindow(TWindow* parent, const tstring& title, TModule* module)
: TLayoutWindow(parent, title, module),
TTabbedBase(this,0,0,0,0)
{
Init();
}
void TTabbedWindow::Init()
{
SetBkgndColor(TColor::Transparent); // No erase; see TWindow::EvEraseBkgnd.
ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS); // Clipping reduces resize flicker.
}
//
bool TTabbedWindow::Create()
{
uint count = GetTabControl()->GetCount();
uint i;
for(i = 0; i < count; i++){
TWindow* wnd = GetPage(i);
wnd->ModifyStyle(WS_VISIBLE, 0);
}
// Calculate tab control height and layout.
//
uint height = GetTabControl()->GetMinimalHeight() + 1;
TLayoutMetrics lmWindow;
TLayoutMetrics lmNoteTab;
setWindowLayoutMetrics(lmWindow, GetTabControl(), Position);
switch(Position){
case tpLeft:
lmNoteTab.X.SameAs(lmParent, lmLeft);
lmNoteTab.Y.SameAs(lmParent, lmTop);
lmNoteTab.Width.Absolute(lmRight, height);
lmNoteTab.Width.Units = lmPixels;
lmNoteTab.Height.SameAs(lmParent, lmHeight);
break;
case tpRight:
lmNoteTab.X.SameAs(lmParent, lmRight);
lmNoteTab.Y.SameAs(lmParent, lmTop);
lmNoteTab.Height.SameAs(lmParent, lmHeight);
lmNoteTab.Width.Absolute(lmLeft, height);
lmNoteTab.Width.Units = lmPixels;
break;
case tpTop:
lmNoteTab.X.SameAs(lmParent, lmLeft);
lmNoteTab.Y.SameAs(lmParent, lmTop);
lmNoteTab.Width.SameAs(lmParent, lmWidth);
lmNoteTab.Height.Absolute(lmBottom, height);
lmNoteTab.Height.Units = lmPixels;
break;
case tpBottom:
lmNoteTab.X.SameAs(lmParent, lmLeft);
// Needed an adjustment of -1 here, otherwise there is a 1 pixel gap
// below the tab control.
//
// TODO: Determine if this is a bug in TLayoutWindow, or whether this
// bottom pixel exclusion is indeed correct.
//
lmNoteTab.Y.Set(lmBottom, lmAbove, lmParent, lmBottom, -1);
lmNoteTab.Height.Absolute(height);
lmNoteTab.Height.Units = lmPixels;
lmNoteTab.Width.SameAs(lmParent, lmRight);
break;
}
SetChildLayoutMetrics(*GetTabControl(), lmNoteTab);
for(i = 0; i < count; i++)
SetChildLayoutMetrics(*GetPage(i), lmWindow);
TLayoutWindow::Create();
SetupPages();
return true;
}
//
/// Add a new tab page.
///\note Need at least one page in order to add a page. The initial page must be added before creating the window.
int TTabbedWindow::AddPage(TWindow& wnd, LPCTSTR titles)
{
TWindow* wnd1 = (TWindow*)&wnd;
// If the layout window hasn't been created, just Add the tab
if(!GetHandle())
return Add(*wnd1, titles);
// Need at least one page in order to add a page
if(GetTabControl()->GetSel() < 0)
return -1;
// Tell the currently selected Tab we're about to change
TNotify dummy;
EvTabControlSelChanging(dummy);
int index = Add(*wnd1, titles);
wnd1->ModifyStyle(WS_VISIBLE, 0);
TLayoutMetrics lmWindow;
GetChildLayoutMetrics(*GetPage(0), lmWindow);
if(!wnd1->IsWindow())
wnd1->Create();
SetChildLayoutMetrics(*wnd1, lmWindow);
Layout();
// Tell the new Tab we've changed to it
EvTabControlSelChange(dummy);
return index;
}
//
bool TTabbedWindow::DeletePage(TWindow& wnd)
{
TWindow* wnd1 = (TWindow*)&wnd;
uint count = GetTabControl()->GetCount();
for(uint i = 0; i < count; i++){
if(wnd1 == GetPage(i)) {
// Tell the currently selected Tab we're about to change
TNotify dummy;
EvTabControlSelChanging(dummy);
GetTabControl()->Delete(i);
EvTabControlSelChange(dummy);
return true;
}
}
return false;
}
void TTabbedWindow::ResizeTabControl(int newHeight)
{
TNoteTab* t = GetTabControl(); CHECK(t);
TLayoutMetrics m;
GetChildLayoutMetrics(*t, m);
m.Height.Absolute(newHeight);
m.SetMeasurementUnits(lmPixels);
SetChildLayoutMetrics(*t, m);
Layout();
t->Invalidate();
}
//------------------------------------------------------------------------------
// TTabbedView Implementation
//
DEFINE_RESPONSE_TABLE1(TTabbedView, TTabbedWindow)
EV_VN_ISWINDOW,
END_RESPONSE_TABLE;
//
//
//
TTabbedView::TTabbedView(TDocument& doc, TWindow* parent)
:
TTabbedWindow(parent, 0, doc.GetDocManager().GetApplication()),
TView(doc)
{
}
//
// Does a given HWND belong to this view? Yes if it is us, or a child of us
//
bool
TTabbedView::VnIsWindow(HWND hWnd)
{
return hWnd == GetHandle() || IsChild(hWnd);
}
//----------------------------------------------------------------------------
/*
IMPLEMENT_STREAMABLE2(TTabbedWindow, TLayoutWindow, TTabbed);
IMPLEMENT_STREAMABLE2(TTabbedView, TTabbedWindow, TView);
#if OWL_PERSISTENT_STREAMS
//
//
//
void*
*/
//TTabbedView::Streamer::Read(ipstream& is, uint32 /*version*/) const
/*
{
ReadBaseObject((TTabbedWindow*)GetObject(), is);
ReadBaseObject((TView*)GetObject(), is);
return GetObject();
}
//
//
//
void
TTabbedView::Streamer::Write(opstream& os) const
{
WriteBaseObject((TTabbedWindow*)GetObject(), os);
WriteBaseObject((TView*)GetObject(), os);
}
#endif
*/
} // OWL namespace
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
↑ V1004 The 't' pointer was used unsafely after it was verified against nullptr. Check lines: 368, 370.