#include "CtrlLib.h" NAMESPACE_UPP CH_STYLE(TabCtrl, Style, StyleDefault) { font = StdFont(); tabheight = font.Info().GetHeight() + 8; margin = 2; sel = Rect(2, 2, 2, 2); edge = Rect(6, 6, 6, 6); extendleft = 0; CtrlsImageLook(normal, CtrlsImg::I_TAB, 4); CtrlsImageLook(first, CtrlsImg::I_FTAB, 4); CtrlsImageLook(last, CtrlsImg::I_LTAB, 4); CtrlsImageLook(both, CtrlsImg::I_BTAB, 4); body = CtrlsImg::TABB(); for(int i = 0; i < 4; i++) text_color[i] = SColorText(); } TabCtrl::Item& TabCtrl::Item::Text(const String& _text) { text = _text; owner->Layout(); return *this; } TabCtrl::Item& TabCtrl::Item::Picture(PaintRect d) { pict = d; owner->Layout(); return *this; } TabCtrl::Item& TabCtrl::Item::SetCtrl(Ctrl *_ctrl) { if(ctrl) ctrl->Remove(); ctrl = _ctrl; owner->Layout(); return *this; } TabCtrl::Item& TabCtrl::Item::Slave(Ctrl *_slave) { if(slave) slave->Remove(); slave = _slave; if(slave) owner->pane.Add(*slave); int q = owner->sel; owner->sel = -1; owner->Set(q); return *this; } TabCtrl::Item& TabCtrl::Item::Enable(bool _en) { enabled = _en; owner->Refresh(); return *this; } TabCtrl::Item::Item() { ctrl = slave = NULL; enabled = true; key = 0; } void TabCtrl::Item::Layout(int xp, int y, int cy) { Font fnt = owner->style->font; Size chsz = GetTextSize("M", fnt); x = xp; Size sz = pict.GetStdSize(); if(sz.cx) { xp += chsz.cx / 2; pictpos.x = xp; pictpos.y = y + (cy - sz.cy) / 2; xp += sz.cx + chsz.cx / 2; } else xp += chsz.cx; sz = GetTextSize(text, fnt); if(sz.cx) { textpos.x = xp; textpos.y = y + (cy - sz.cy) / 2; xp += sz.cx; } if(ctrl) { xp += chsz.cx / 2; sz = ctrl->GetRect().GetSize(); ctrl->SetRect(xp, y + (cy - sz.cy) / 2, sz.cx, sz.cy); xp += sz.cx + chsz.cx / 2; } else xp += chsz.cx; cx = xp - x; } void TabCtrl::Item::Paint(Draw& w, int state) { Size sz = pict.GetStdSize(); pict.Paint(w, pictpos.x, pictpos.y, sz.cx, sz.cy, owner->style->text_color[state], Null); w.DrawText(textpos.x, textpos.y, text, owner->style->font, owner->style->text_color[state]); } void TabCtrl::SyncTabs() { int x = style->margin - x0; for(int i = 0; i < tab.GetCount(); i++) { Item& t = tab[i]; t.Layout(x, style->sel.top * (i != sel), style->tabheight + style->sel.top * (i == sel)); x += t.cx; } left.Show(x0 > 0); right.Show(tab.GetCount() && tab.Top().Right() > tabs.GetSize().cx); } void TabCtrl::Layout() { for(int i = 0; i < tab.GetCount(); i++) if(tab[i].ctrl) tab[i].ctrl->Remove(); for(int i = 0; i < tab.GetCount(); i++) if(tab[i].ctrl) Ctrl::Add(*tab[i].ctrl); Size sz = GetSize(); int th = style->tabheight + style->sel.top; tabs.TopPos(0, th + style->sel.bottom) .HSizePos(0, style->sel.left + style->sel.right); SyncTabs(); if(tab.GetCount() && tab.Top().Right() < TabsRight()) x0 = 0; SyncHot(); if(sel < tab.GetCount()) ScrollInto(sel); pane.VSizePos(style->tabheight + style->edge.top, style->edge.bottom) .HSizePos(style->edge.left, style->edge.right); left.LeftPos(0, 16).TopPos(th - 16, 16); right.RightPos(0, 16).TopPos(th - 16, 16); SyncTabs(); Refresh(); } Size TabCtrl::ComputeSize(Size pane) { return Size(pane.cx + style->edge.left + style->edge.right, pane.cy + style->tabheight + style->edge.top + style->edge.bottom); } int TabCtrl::TabsRight() { return tabs.GetSize().cx - style->sel.left - style->sel.right; } void TabCtrl::Tabs::Paint(Draw& w) { static_cast(GetParent())->PaintTabs(w); } Rect TabCtrl::GetOpaqueRect() { return pane.GetRect(); } void TabCtrl::PaintTabs(Draw& w) { int tt = style->sel.top; int th = style->tabheight + tt; Size sz = GetSize(); ChPaint(w, 0, th, sz.cx, sz.cy - th, style->body); Size chsz = GetTextSize("M", style->font); for(int phase = 0; phase < 2; phase++) { for(int i = tab.GetCount() - 1; i >= 0; i--) if((sel == i) == phase) { Item& t = tab[i]; Rect r = RectC(t.x, tt, t.cx, th - tt); if(i) r.left -= style->extendleft; if(phase) { r.left -= style->sel.left; r.right += style->sel.right; r.top -= tt; r.bottom += style->sel.bottom; } int ndx = !IsEnabled() || !t.enabled ? CTRL_DISABLED : phase ? CTRL_PRESSED : i == hot ? CTRL_HOT : CTRL_NORMAL; ChPaint(w, r, (tab.GetCount() == 1 ? style->both : i == 0 ? style->first : i == tab.GetCount() - 1 ? style->last : style->normal) [ndx] ); t.Paint(w, ndx); } } } void TabCtrl::Paint(Draw& w) { int th = style->tabheight + style->sel.top; Size sz = GetSize(); ChPaint(w, 0, th, sz.cx, sz.cy - th, style->body); } int TabCtrl::GetTab(Point p) const { if(p.y >= 0 && p.y < style->tabheight) for(int i = 0; i < tab.GetCount(); i++) if(p.x < tab[i].Right()) return i; return -1; } void TabCtrl::CancelMode() { hot = -1; } void TabCtrl::SyncHot() { Point p = GetMousePos() - GetScreenRect().TopLeft(); int h = GetTab(p); if(h != hot) { hot = h; tabs.Refresh(); } } void TabCtrl::MouseMove(Point p, dword keyflags) { SyncHot(); } void TabCtrl::LeftDown(Point p, dword keyflags) { if(!IsEditable()) return; int h = GetTab(p); if(h >= 0 && tab[h].IsEnabled()) { Set(h); Action(); } } void TabCtrl::MouseLeave() { SyncHot(); } void TabCtrl::ScrollInto(int i) { if(i < 0) return; Item& t = tab[i]; int tr = TabsRight(); if(t.Right() > tr) { x0 += t.Right() - tr; tabs.Refresh(); SyncTabs(); } if(t.x < style->margin) { x0 += t.x - style->margin; tabs.Refresh(); SyncTabs(); } } void TabCtrl::Left() { if(x0 <= 0) return; for(int i = tab.GetCount() - 1; i >= 0; i--) if(tab[i].x < style->margin) { ScrollInto(i); break; } } void TabCtrl::Right() { for(int i = 0; i < tab.GetCount(); i++) if(tab[i].Right() > tabs.GetRect().GetWidth() - style->sel.left - style->sel.right) { ScrollInto(i); break; } } void TabCtrl::Set(int i) { if(i != sel) { bool refocus = HasFocusDeep(); sel = i; tabs.Refresh(); SyncTabs(); for(int i = 0; i < tab.GetCount(); i++) if(tab[i].slave) tab[i].slave->Show(sel == i); if(sel >= 0 && refocus) IterateFocusForward(tab[sel].slave, GetTopCtrl(), false, true); WhenSet(); } ScrollInto(sel); } void TabCtrl::Set(Ctrl& slave) { for(int i = 0; i < tab.GetCount(); i++) if(tab[i].slave == &slave) { Set(i); return; } } void TabCtrl::SetData(const Value& data) { Set(data); } Value TabCtrl::GetData() const { return Get(); } TabCtrl::Item& TabCtrl::Add() { CancelMode(); Item& t = tab.Add(); t.owner = this; if(sel < 0) Set(0); Layout(); return t; } TabCtrl::Item& TabCtrl::Add(const char *text) { return Add().Text(text); } TabCtrl::Item& TabCtrl::Add(const Image& m, const char *text) { return Add().Text(text).SetImage(m); } TabCtrl::Item& TabCtrl::Add(Ctrl& slave, const char *text) { return Add(text).Slave(&slave); } TabCtrl::Item& TabCtrl::Add(Ctrl& slave, const Image& m, const char *text) { return Add(slave, text).SetImage(m); } TabCtrl::Item& TabCtrl::Insert(int i) { CancelMode(); int c = i < sel ? sel + 1 : sel; TabCtrl::Item& m = tab.Insert(i); m.owner = this; Layout(); sel = -1; Set(c); return m; } TabCtrl::Item& TabCtrl::Insert(int i, const char *text) { return Insert(i).Text(text); } TabCtrl::Item& TabCtrl::Insert(int i, const Image& m, const char *text) { return Insert(i).Text(text).SetImage(m); } TabCtrl::Item& TabCtrl::Insert(int i, Ctrl& slave, const char *text) { return Insert(i, text).Slave(&slave); } TabCtrl::Item& TabCtrl::Insert(int i, Ctrl& slave, const Image& m, const char *text) { return Insert(i, slave, text).SetImage(m); } void TabCtrl::Remove(int i) { CancelMode(); if(tab[i].ctrl) tab[i].ctrl->Remove(); if(tab[i].slave) tab[i].slave->Remove(); int c = i < sel ? sel - 1 : sel; tab.Remove(i); Layout(); sel = -1; if(tab.GetCount()) Set(minmax(c, 0, tab.GetCount() - 1)); else { x0 = 0; sel = -1; accept_current = false; WhenSet(); } } void TabCtrl::Go(int d) { if(IsEditable() && tab.GetCount()) { int i = sel + d; while(i != sel) { if(i < 0) i = tab.GetCount() - 1; if(i >= tab.GetCount()) i = 0; if(tab[i].IsEnabled()) { Set(i); break; } i += d; } } } bool TabCtrl::Key(dword key, int repcnt) { switch(key) { case K_CTRL_TAB: GoNext(); Action(); return true; case K_SHIFT_CTRL_TAB: GoPrev(); Action(); return true; } return Ctrl::Key(key, repcnt); } bool TabCtrl::HotKey(dword key) { switch(key) { case K_CTRL_TAB: GoNext(); Action(); return true; case K_SHIFT_CTRL_TAB: GoPrev(); Action(); return true; } return Ctrl::HotKey(key); } bool TabCtrl::Accept() { if(tab.GetCount() == 0) return true; int ii = Get(); if(accept_current) return !tab[ii].slave || tab[ii].slave -> Accept(); for(int i = 0; i < tab.GetCount(); i++) if(tab[i].slave) { Set(i); if(!tab[i].slave->Accept()) return false; } Set(ii); return true; } void TabCtrl::Reset() { for(int i = 0; i < tab.GetCount(); i++) { if(tab[i].ctrl) tab[i].ctrl->Remove(); if(tab[i].slave) tab[i].slave->Remove(); } tab.Clear(); x0 = 0; CancelMode(); sel = -1; Refresh(); accept_current = false; WhenSet(); } TabCtrl::TabCtrl() { hot = -1; sel = -1; x0 = 0; accept_current = false; Ctrl::Add(tabs); Ctrl::Add(pane); tabs.BackPaint().IgnoreMouse(); Ctrl::Add(left.SetImage(CtrlsImg::SLA()).ScrollStyle().NoWantFocus()); left <<= THISBACK(Left); Ctrl::Add(right.SetImage(CtrlsImg::SRA()).ScrollStyle().NoWantFocus()); right <<= THISBACK(Right); Transparent().NoWantFocus(); tabs.Transparent().NoWantFocus(); SetStyle(StyleDefault()); } // ---------------------------------------------------------------- void TabDlg::PlaceButton(Button& b, int& r) { if(b.GetParent()) { b.Remove(); AddChild(&b, &tabctrl); b.RightPosZ(r, 64).BottomPosZ(4, 24); r += 72; } } void TabDlg::Rearrange() { int r = 4; PlaceButton(apply, r); PlaceButton(cancel, r); PlaceButton(exit, r); PlaceButton(ok, r); SetRect(Rect(GetRect().TopLeft(), tabctrl.ComputeSize(sz) + Ctrl::LayoutZoom(Size(8, 40)))); } TabCtrl::Item& TabDlg::Add0(Ctrl& tab, const char *text) { Size tsz = max(tab.GetRect().GetSize(), sz); tab.SizePos(); TabCtrl::Item& m = tabctrl.Add(tab, text); if(tsz != sz) { sz = tsz; Rearrange(); } return m; } TabDlg& TabDlg::AButton(Button& b) { if(binit) { exit.Remove(); binit = false; } Ctrl::Add(b); Rearrange(); return *this; } TabDlg::TabDlg() { binit = true; Ctrl::Add(tabctrl.HSizePosZ(4, 4).VSizePosZ(4, 36)); sz = Size(0, 0); ok.Ok().SetLabel(t_("OK")); Acceptor(ok, IDOK); cancel.Cancel().SetLabel(t_("Cancel")); Rejector(cancel, IDCANCEL); apply.SetLabel(t_("Apply")); Acceptor(apply, IDYES); exit.SetLabel(t_("Close")); Acceptor(exit, IDEXIT); Ctrl::Add(exit); } END_UPP_NAMESPACE