#include "tabber.h" #include "stdafx.h" IMPLEMENT_DYNAMIC(Tabber, CTabCtrl) BEGIN_MESSAGE_MAP(Tabber, CTabCtrl) ON_WM_SIZE() ON_WM_ERASEBKGND() ON_NOTIFY_REFLECT(TCN_SELCHANGE, tcn_selChange) END_MESSAGE_MAP() static CRect tabsRect(CTabCtrl& t) { CRect r(0, 0, 0, 0); int n = t.GetItemCount(); for (int k = 0; k < n; ++k) { CRect c; t.GetItemRect(k, &c); if (c.left < r.left) r.left = c.left; if (c.right > r.right) r.right = c.right; if (c.top < r.top) r.top = c.top; if (c.bottom > r.bottom) r.bottom = c.bottom; } return r; } CRect Tabber::getInnerRect() { CRect r; GetClientRect(&r); int x = 2, y = 2, w = r.Width() - 4, h = r.Height() - 4; r = tabsRect(*this); h -= r.Height(); y += r.Height(); r.left = x; r.top = y; r.right = x + w; r.bottom = y + h; return r; } Tabber::Tabber() : listener(0), curr(-1) {} Tabber::~Tabber() { for (; tabs.size(); tabs.pop_back()) delete tabs.back(); } void Tabber::OnSize(UINT type, int w, int h) { CTabCtrl::OnSize(type, w, h); refresh(); } BOOL Tabber::OnEraseBkgnd(CDC* dc) { CRect c; GetClientRect(&c); HBRUSH hb = (HBRUSH)GetClassLong(m_hWnd, GCL_HBRBACKGROUND); CBrush br; br.Attach(hb); if (curr < 0) dc->FillRect(&c, &br); else { CRect i = getInnerRect(); CRect t(c.left, c.top, i.right, i.top); dc->FillRect(&t, &br); CRect r(i.right, c.top, c.right, i.bottom); dc->FillRect(&r, &br); CRect b(i.left, i.bottom, c.right, c.bottom); dc->FillRect(&b, &br); CRect l(c.left, i.top, i.left, c.bottom); dc->FillRect(&l, &br); } return true; } void Tabber::setListener(TabberListener* l) { listener = l; } void Tabber::refresh() { if (curr < 0) return; CRect r = getInnerRect(); CWnd* wnd = getTabWnd(curr); wnd->MoveWindow(r.left, r.top, r.Width(), r.Height()); wnd->ShowWindow(SW_SHOW); wnd->SetFocus(); } Tabber::Tab* Tabber::getTab(int index) const { if (index < 0 || index >= tabs.size()) return 0; Tabs::const_iterator it = tabs.begin(); while (index--) ++it; return *it; } void Tabber::tcn_selChange(NMHDR* p, LRESULT* result) { setCurrent(GetCurSel()); } void Tabber::insert(int index, CWnd* w, const string& t) { if (index < 0 || index > tabs.size()) return; Tabs::iterator it = tabs.begin(); for (int k = 0; k < index; ++k) ++it; Tab* tab = new Tab(w, t); tabs.insert(it, tab); InsertItem(index, t.c_str()); if (curr < 0) setCurrent(index); } void Tabber::remove(int index) { if (index < 0 || index >= tabs.size()) return; CWnd* w = getTabWnd(index); Tabs::iterator it = tabs.begin(); for (int k = 0; k < index; ++k) ++it; delete *it; tabs.erase(it); DeleteItem(index); if (curr >= tabs.size()) curr = tabs.size() - 1; refresh(); if (curr >= 0) SetCurSel(curr); if (w) w->ShowWindow(SW_HIDE); if (listener) listener->currentSet(this, curr); } void Tabber::setCurrent(int index) { if (index < 0 || index >= tabs.size()) return; if (index != curr) { CWnd* w = getTabWnd(curr); curr = index; refresh(); SetCurSel(curr); if (w) w->ShowWindow(SW_HIDE); } if (listener) listener->currentSet(this, curr); } void Tabber::setTabText(int index, const string& t) { if (index < 0 || index >= tabs.size()) return; string s = t + '\0'; TCITEM tc = {TCIF_TEXT}; tc.pszText = (char*)s.data(); SetItem(index, &tc); } int Tabber::size() const { return tabs.size(); } int Tabber::getCurrent() const { return curr; } CWnd* Tabber::getTabWnd(int index) const { Tab* t = getTab(index); return t ? t->wnd : 0; } string Tabber::getTabText(int index) const { Tab* t = getTab(index); return t ? t->text : ""; }