From ef448a592f7650f3db49863a2a46d68a65b974ba Mon Sep 17 00:00:00 2001 From: unodgs Date: Fri, 8 May 2009 10:43:26 +0000 Subject: [PATCH] Painting fixes and clean up's git-svn-id: svn://ultimatepp.org/upp/trunk@1148 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- bazaar/Docking/DockTabBar.cpp | 632 +++--- bazaar/Docking/DockTabBar.h | 180 +- bazaar/TabBar/TabBar.cpp | 3225 +++++++++++++++--------------- bazaar/TabBar/TabBar.h | 687 +++---- bazaar/TabBar/TabBar.upp | 26 +- bazaar/TabBarTest/TabBarTest.cpp | 19 +- 6 files changed, 2368 insertions(+), 2401 deletions(-) diff --git a/bazaar/Docking/DockTabBar.cpp b/bazaar/Docking/DockTabBar.cpp index 42ca917f4..d04986660 100644 --- a/bazaar/Docking/DockTabBar.cpp +++ b/bazaar/Docking/DockTabBar.cpp @@ -1,324 +1,308 @@ -#include "DockTabBar.h" - -#include "DockCont.h" -#define ANIM_SPEED 10 -#define ANIM_FRAMES 10 - -// DockTabBar -int AutoHideBar::autohide_timeout = 1000; - -void DockTabBar::FrameLayout(Rect& r) -{ - if (IsAutoHide()) return Hide(); - Show(); - TabBar::FrameLayout(r); -} - -void DockTabBar::FrameAddSize(Size& sz) -{ - if (!IsAutoHide()) - TabBar::FrameAddSize(sz); -} - -void DockTabBar::PaintTabData(Draw& w, const Rect &r, const Tab& tab, const Font &font, Color ink, dword style, int bl) -{ - DockableCtrl *d; - WString txt; - const Value &q = tab.data; - - ink = (style == CTRL_DISABLED) ? SColorDisabled : ink; - - if (IsTypeRaw(q)) { - DockCont *c = ValueTo(q); - d = &c->GetCurrent(); - txt = c->GetTitle(); - } - else { - ASSERT(IsTypeRaw(q)); - d = ValueTo(q); - txt = d->GetTitle(); - } - - Point p = GetTextPosition(r, GetTextSize(txt, font).cy, bl); - if(icons) - { - const Image& icon = (style == CTRL_DISABLED) ? DisabledImage(d->GetIcon()) : d->GetIcon(); - if (!icon.IsEmpty()) { - int al = GetAlign(); - Size isz = icon.GetSize(); - Point ip; - switch (al) { - case LEFT: - ip = Point(r.left + (r.Width() - isz.cy) / 2, p.y - isz.cy); - p.y -= isz.cy + TB_SPACEICON; - break; - case TOP: - ip = Point(p.x, r.top + (r.Height() - isz.cy) / 2); - p.x += isz.cx + TB_SPACEICON; - break; - case RIGHT: - ip = Point(r.left + (r.Width() - isz.cy) / 2, p.y); - p.y += isz.cy + TB_SPACEICON; - break; - case BOTTOM: - ip = Point(p.x, r.top + (r.Height() - isz.cy) / 2); - p.x += isz.cx + TB_SPACEICON; - break; - }; - w.DrawImage(ip.x, ip.y, icon); - } - } - if (showtext) - w.DrawText(p.x, p.y, GetTextAngle(), txt, font, ink); -} - -Size DockTabBar::GetStdSize(const Tab& t) -{ - DockableCtrl *d; - const Value &q = t.data; - Value v; - if (IsTypeRaw(q)) { - DockCont *c = ValueTo(q); - d = &c->GetCurrent(); - v = c->GetTitle(); - } - else { - ASSERT(IsTypeRaw(q)); - d = ValueTo(q); - v = d->GetTitle(); - } - int isz = (IsVert() ? d->GetIcon().GetHeight() : d->GetIcon().GetWidth()); - return showtext ? TabBar::GetStdSize(v) + Size(isz + TB_SPACEICON, 0) : Size(isz, isz); -} - -void DockTabBar::RightDown(Point p, dword keyflags) -{ - if (GetHighlight() >= 0) - WhenContext(GetHighlight()); - else - TabBar::RightDown(p, keyflags); -} - -void DockTabBar::LeftDrag(Point p, dword keyflags) -{ - if (keyflags & K_CTRL || keyflags & K_SHIFT) - return TabBar::LeftDrag(p, keyflags &= ~K_SHIFT); - if (GetHighlight() >= 0) - WhenDrag(GetHighlight()); -} - -DockTabBar::DockTabBar() -{ - autohide = -1; - icons = true; - showtext = true; - AutoScrollHide().InactiveDisabled(); -} - -// AutoHide bar -void AutoHideBar::MouseEnter(Point p, dword keyflags) -{ - if (ctrl && ctrl->IsOpen()) - KillTimeCallback(TIMEID_HIDE_TIMEOUT); - DockTabBar::MouseEnter(p, keyflags); -} - -void AutoHideBar::MouseLeave() -{ - if (ctrl && ctrl->IsOpen()) - KillSetTimeCallback(autohide_timeout, THISBACK1(HideAnimate, ctrl), TIMEID_HIDE_TIMEOUT); - DockTabBar::MouseLeave(); -} - -void AutoHideBar::AddCtrl(DockCont& c, const String& group) -{ - TabBar::Add(RawToValue(&c), group); - if (GetCount() == autohide+1) - RefreshParentLayout(); - else - Refresh(); -} - -void AutoHideBar::RemoveCtrl(DockCont& c, int ix) -{ - if (c.IsOpen()) c.Close(); - - if (ctrl == &c) { - if (popup.IsOpen()) - popup.Close(); - ctrl->Remove(); - //KillTimeCallback(TIMEID_ANIMATE); - KillTimeCallback(TIMEID_HIDE_TIMEOUT); - ctrl = NULL; - } - if (ix >= 0) DockTabBar::Close(ix); - if (GetCount() == autohide) - RefreshParentLayout(); -} - -void AutoHideBar::RemoveCtrl(int ix) -{ - if (ix >= 0) { - DockCont *c = GetCtrl(ix); - ASSERT(c); - RemoveCtrl(*c, ix); - } -} - -void AutoHideBar::TabHighlight() -{ - Ctrl *c = NULL; - int ix = TabBar::GetHighlight(); - if (ix >= 0) - c = GetCtrl(ix); - if (!c || ctrl == c) - return; - else if (ctrl) { - if (c) { - if (popup.IsPopUp()) - popup.Close(); - ctrl->Remove(); - ctrl = NULL; - } - else - HideAnimate(ctrl); - } - if (c) { - ASSERT(ix >= 0 && ix < GetCount()); - // Clear WhenHighlight ot prevent stack overflow. Perhaps a better solution should be found... - Callback cb = WhenHighlight; - WhenHighlight = Callback(); - SetCursor(ix); - ShowAnimate(c); - WhenHighlight = cb; - } -} - -void AutoHideBar::TabClose(Value v) -{ - DockCont &dc = *(ValueTo(v)); - RemoveCtrl(dc, -1); - dc.StateNotDocked(); - dc.SignalStateChange(); - if (GetCount() == autohide-1) - RefreshParentLayout(); -} - -void AutoHideBar::ShowAnimate(Ctrl *c) -{ - if (c == ctrl) return; - if (popup.IsPopUp()) popup.Close(); - - Rect target = Ctrl::GetScreenRect(); - Size sz = c->GetStdSize(); - switch (GetAlign()) { - case DockTabBar::LEFT: - sz.cy = target.Height(); - target.left = target.right; - break; - case DockTabBar::TOP: - sz.cx = target.Width(); - target.top = target.bottom; - break; - case DockTabBar::RIGHT: - sz.cy = target.Height(); - target.right = target.left; - break; - case DockTabBar::BOTTOM: - sz.cx = target.Width(); - target.bottom = target.top; - break; - }; - if (IsVert()) - sz.cx = min(sz.cx, GetParent()->GetSize().cx / 2); - else - sz.cy = min(sz.cy, GetParent()->GetSize().cy / 2); - - Rect init = target; - AdjustSize(init, Size(5, 5)); - AdjustSize(target, sz); - - c->SetRect(sz); - c->SizePos(); - popup << *(ctrl = c); - c->Show(); - - popup.SetRect(target); - popup.PopUp(GetParent(), false, true, false, false); - Animate(popup, target, GUIEFFECT_SLIDE); -} - -void AutoHideBar::HideAnimate(Ctrl *c) -{ - ASSERT(ctrl); - // If the popup has a child popup active then reset timer and keep the popup visible - Vector wins = Ctrl::GetTopCtrls(); - for(int i = 0; i < wins.GetCount(); i++) { - if (wins[i]->IsPopUp() && wins[i]->GetOwner() == &popup) { - KillSetTimeCallback(autohide_timeout, THISBACK1(HideAnimate, ctrl), TIMEID_HIDE_TIMEOUT); - return; - } - } - DockTabBar::KillCursor(); -#ifdef PLATFORM_WIN32 - Rect r = popup.GetRect(); - AdjustSize(r, -r.GetSize()); - Animate(popup, r, GUIEFFECT_SLIDE); -#endif - popup.Close(); - ctrl->Remove(); - ctrl = NULL; -} - -void AutoHideBar::AdjustSize(Rect& r, const Size& sz) -{ - switch (DockTabBar::GetAlign()) { - case DockTabBar::LEFT: - r.right += sz.cx; - break; - case DockTabBar::TOP: - r.bottom += sz.cy; - break; - case DockTabBar::RIGHT: - r.left -= sz.cx; - break; - case DockTabBar::BOTTOM: - r.top -= sz.cy; - break; - }; -} - -int AutoHideBar::FindCtrl(const DockCont& c) const -{ - if (&c == ctrl) return GetCursor(); - for (int i = 0; i < GetCount(); i++) { - DockCont *v = ValueTo(Get(i)); - if (v == &c) return i; - } - return -1; -} - -void AutoHideBar::TabDrag(int ix) -{ - GetCtrl(ix)->MoveBegin(); -} - -AutoHideBar::AutoHideBar() -{ - ctrl = NULL; - AutoHideMin(0).InactiveDisabled().CanEmpty(); - popup.WhenEnter = THISBACK2(MouseEnter, Point(0, 0), 0); - popup.WhenLeave = THISBACK(MouseLeave); - DockTabBar::WhenHighlight = THISBACK(TabHighlight); - WhenClose = THISBACK(TabClose); - WhenDrag = THISBACK(TabDrag); -} - -void AutoHideBar::HidePopup::ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags) -{ - if (event == MOUSELEAVE) - WhenLeave(); - else if (event != MOUSEMOVE) - WhenEnter(); -} - +#include "DockTabBar.h" + +#include "DockCont.h" +#define ANIM_SPEED 10 +#define ANIM_FRAMES 10 + +// DockTabBar +int AutoHideBar::autohide_timeout = 1000; + +void DockTabBar::FrameLayout(Rect& r) +{ + if (IsAutoHide()) return Hide(); + Show(); + TabBar::FrameLayout(r); +} + +void DockTabBar::FrameAddSize(Size& sz) +{ + if (!IsAutoHide()) + TabBar::FrameAddSize(sz); +} + +void DockTabBar::PaintTabData(Draw& w, const Rect &r, const Tab& tab, const Font &font, Color ink, dword style) +{ + DockableCtrl *d; + WString txt; + const Value &q = tab.data; + + ink = (style == CTRL_DISABLED) ? SColorDisabled : ink; + + if (IsTypeRaw(q)) { + DockCont *c = ValueTo(q); + d = &c->GetCurrent(); + txt = c->GetTitle(); + } + else { + ASSERT(IsTypeRaw(q)); + d = ValueTo(q); + txt = d->GetTitle(); + } + + Size isz; + if(icons) + { + const Image& icon = (style == CTRL_DISABLED) ? DisabledImage(d->GetIcon()) : d->GetIcon(); + if (!icon.IsEmpty()) { + isz = icon.GetSize(); + Point ip = GetImagePosition(r, isz.cx, isz.cy, TB_SPACEICON, LEFT); + w.DrawImage(ip.x, ip.y, icon); + } + } + if (showtext) + { + Point p = GetTextPosition(r, GetTextSize(txt, font).cy, isz.cx + TB_SPACEICON + TB_MARGIN); + w.DrawText(p.x, p.y, GetTextAngle(), txt, font, ink); + } +} + +Size DockTabBar::GetStdSize(const Tab& t) +{ + DockableCtrl *d; + const Value &q = t.data; + Value v; + if (IsTypeRaw(q)) { + DockCont *c = ValueTo(q); + d = &c->GetCurrent(); + v = c->GetTitle(); + } + else { + ASSERT(IsTypeRaw(q)); + d = ValueTo(q); + v = d->GetTitle(); + } + int isz = (IsVert() ? d->GetIcon().GetHeight() : d->GetIcon().GetWidth()); + return showtext ? TabBar::GetStdSize(v) + Size(isz + TB_SPACEICON, 0) : Size(isz, isz); +} + +void DockTabBar::RightDown(Point p, dword keyflags) +{ + if (GetHighlight() >= 0) + WhenContext(GetHighlight()); + else + TabBar::RightDown(p, keyflags); +} + +void DockTabBar::LeftDrag(Point p, dword keyflags) +{ + if (keyflags & K_CTRL || keyflags & K_SHIFT) + return TabBar::LeftDrag(p, keyflags &= ~K_SHIFT); + if (GetHighlight() >= 0) + WhenDrag(GetHighlight()); +} + +DockTabBar::DockTabBar() +{ + autohide = -1; + icons = true; + showtext = true; + AutoScrollHide().InactiveDisabled(); +} + +// AutoHide bar +void AutoHideBar::MouseEnter(Point p, dword keyflags) +{ + if (ctrl && ctrl->IsOpen()) + KillTimeCallback(TIMEID_HIDE_TIMEOUT); + DockTabBar::MouseEnter(p, keyflags); +} + +void AutoHideBar::MouseLeave() +{ + if (ctrl && ctrl->IsOpen()) + KillSetTimeCallback(autohide_timeout, THISBACK1(HideAnimate, ctrl), TIMEID_HIDE_TIMEOUT); + DockTabBar::MouseLeave(); +} + +void AutoHideBar::AddCtrl(DockCont& c, const String& group) +{ + TabBar::Add(RawToValue(&c), group); + if (GetCount() == autohide+1) + RefreshParentLayout(); + else + Refresh(); +} + +void AutoHideBar::RemoveCtrl(DockCont& c, int ix) +{ + if (c.IsOpen()) c.Close(); + + if (ctrl == &c) { + if (popup.IsOpen()) + popup.Close(); + ctrl->Remove(); + //KillTimeCallback(TIMEID_ANIMATE); + KillTimeCallback(TIMEID_HIDE_TIMEOUT); + ctrl = NULL; + } + if (ix >= 0) DockTabBar::Close(ix); + if (GetCount() == autohide) + RefreshParentLayout(); +} + +void AutoHideBar::RemoveCtrl(int ix) +{ + if (ix >= 0) { + DockCont *c = GetCtrl(ix); + ASSERT(c); + RemoveCtrl(*c, ix); + } +} + +void AutoHideBar::TabHighlight() +{ + Ctrl *c = NULL; + int ix = TabBar::GetHighlight(); + if (ix >= 0) + c = GetCtrl(ix); + if (!c || ctrl == c) + return; + else if (ctrl) { + if (c) { + if (popup.IsPopUp()) + popup.Close(); + ctrl->Remove(); + ctrl = NULL; + } + else + HideAnimate(ctrl); + } + if (c) { + ASSERT(ix >= 0 && ix < GetCount()); + // Clear WhenHighlight ot prevent stack overflow. Perhaps a better solution should be found... + Callback cb = WhenHighlight; + WhenHighlight = Callback(); + SetCursor(ix); + ShowAnimate(c); + WhenHighlight = cb; + } +} + +void AutoHideBar::TabClose(Value v) +{ + DockCont &dc = *(ValueTo(v)); + RemoveCtrl(dc, -1); + dc.StateNotDocked(); + dc.SignalStateChange(); + if (GetCount() == autohide-1) + RefreshParentLayout(); +} + +void AutoHideBar::ShowAnimate(Ctrl *c) +{ + if (c == ctrl) return; + if (popup.IsPopUp()) popup.Close(); + + Rect target = Ctrl::GetScreenRect(); + Size sz = c->GetStdSize(); + switch (GetAlign()) { + case DockTabBar::LEFT: + sz.cy = target.Height(); + target.left = target.right; + break; + case DockTabBar::TOP: + sz.cx = target.Width(); + target.top = target.bottom; + break; + case DockTabBar::RIGHT: + sz.cy = target.Height(); + target.right = target.left; + break; + case DockTabBar::BOTTOM: + sz.cx = target.Width(); + target.bottom = target.top; + break; + }; + if (IsVert()) + sz.cx = min(sz.cx, GetParent()->GetSize().cx / 2); + else + sz.cy = min(sz.cy, GetParent()->GetSize().cy / 2); + + Rect init = target; + AdjustSize(init, Size(5, 5)); + AdjustSize(target, sz); + + c->SetRect(sz); + c->SizePos(); + popup << *(ctrl = c); + c->Show(); + + popup.SetRect(target); + popup.PopUp(GetParent(), false, true, false, false); + Animate(popup, target, GUIEFFECT_SLIDE); +} + +void AutoHideBar::HideAnimate(Ctrl *c) +{ + ASSERT(ctrl); + // If the popup has a child popup active then reset timer and keep the popup visible + Vector wins = Ctrl::GetTopCtrls(); + for(int i = 0; i < wins.GetCount(); i++) { + if (wins[i]->IsPopUp() && wins[i]->GetOwner() == &popup) { + KillSetTimeCallback(autohide_timeout, THISBACK1(HideAnimate, ctrl), TIMEID_HIDE_TIMEOUT); + return; + } + } + DockTabBar::KillCursor(); +#ifdef PLATFORM_WIN32 + Rect r = popup.GetRect(); + AdjustSize(r, -r.GetSize()); + Animate(popup, r, GUIEFFECT_SLIDE); +#endif + popup.Close(); + ctrl->Remove(); + ctrl = NULL; +} + +void AutoHideBar::AdjustSize(Rect& r, const Size& sz) +{ + switch (DockTabBar::GetAlign()) { + case DockTabBar::LEFT: + r.right += sz.cx; + break; + case DockTabBar::TOP: + r.bottom += sz.cy; + break; + case DockTabBar::RIGHT: + r.left -= sz.cx; + break; + case DockTabBar::BOTTOM: + r.top -= sz.cy; + break; + }; +} + +int AutoHideBar::FindCtrl(const DockCont& c) const +{ + if (&c == ctrl) return GetCursor(); + for (int i = 0; i < GetCount(); i++) { + DockCont *v = ValueTo(Get(i)); + if (v == &c) return i; + } + return -1; +} + +void AutoHideBar::TabDrag(int ix) +{ + GetCtrl(ix)->MoveBegin(); +} + +AutoHideBar::AutoHideBar() +{ + ctrl = NULL; + AutoHideMin(0).InactiveDisabled().CanEmpty(); + popup.WhenEnter = THISBACK2(MouseEnter, Point(0, 0), 0); + popup.WhenLeave = THISBACK(MouseLeave); + DockTabBar::WhenHighlight = THISBACK(TabHighlight); + WhenClose = THISBACK(TabClose); + WhenDrag = THISBACK(TabDrag); +} + +void AutoHideBar::HidePopup::ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags) +{ + if (event == MOUSELEAVE) + WhenLeave(); + else if (event != MOUSEMOVE) + WhenEnter(); +} + diff --git a/bazaar/Docking/DockTabBar.h b/bazaar/Docking/DockTabBar.h index 29c4329d3..cf919fae8 100644 --- a/bazaar/Docking/DockTabBar.h +++ b/bazaar/Docking/DockTabBar.h @@ -1,90 +1,90 @@ -#ifndef _Docking_DockTabBar_h_ -#define _Docking_DockTabBar_h_ - -#include -using namespace Upp; - -#include - -class DockTabBar : public TabBar { -public: - typedef DockTabBar CLASSNAME; - - Callback1 WhenContext; - Callback1 WhenDrag; - - virtual void ContextMenu(Bar& bar) { TabBar::ContextMenu(bar); } - - virtual void FrameAddSize(Size& sz); - virtual void FrameLayout(Rect& r); - bool IsAutoHide() const { return GetCount() <= autohide; } - - DockTabBar& AutoHideMin(int hidemin = 1) { autohide = hidemin; return *this; } - DockTabBar& Icons(bool b = true) { icons = b; return *this; } - - void SyncRepos() { Repos(); } - void ShowText(bool show) { showtext = show; } - - DockTabBar(); -protected: - int autohide; - bool icons:1; - bool showtext:1; - - virtual void PaintTabData(Draw& w, const Rect &t, const Tab& tab, const Font &font, - Color ink, dword style, int bl); - virtual Size GetStdSize(const Tab &q); - - virtual void RightDown(Point p, dword keyflags); - virtual void LeftDown(Point p, dword keyflags) { TabBar::LeftDown(p, keyflags &= ~K_SHIFT); } - virtual void LeftUp(Point p, dword keyflags) { TabBar::LeftUp(p, keyflags &= ~K_SHIFT); } - virtual void LeftDrag(Point p, dword keyflags); -}; - -class DockCont; - -class AutoHideBar : public DockTabBar { -public: - typedef AutoHideBar CLASSNAME; - - virtual void MouseEnter(Point p, dword keyflags); - virtual void MouseLeave(); - - void AddCtrl(DockCont& c, const String& group = Null); - int FindCtrl(const DockCont& c) const; - DockCont *GetCtrl(int ix) const { return ValueTo(Get(ix)); } - void RemoveCtrl(int ix); - void RemoveCtrl(DockCont& c) { return RemoveCtrl(c, FindCtrl(c)); } - void RemoveCtrl(DockCont& c, int ix); - bool HasCtrl(const DockCont& c) const { return (FindCtrl(c) >= 0); } - - void ShowAnimate(Ctrl *c); - - static void SetTimeout(int delay_ms) { ASSERT(delay_ms > 0); autohide_timeout = delay_ms; } - - AutoHideBar(); - -private: - static int autohide_timeout; - - struct HidePopup : public Ctrl { - HidePopup() { BackPaint(); } - Callback WhenEnter; - Callback WhenLeave; - virtual void ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags); - }; - - enum { TIMEID_ACTION_CHECK = Ctrl::TIMEID_COUNT, - TIMEID_HIDE_TIMEOUT, - TIMEID_COUNT }; - Ctrl *ctrl; - HidePopup popup; - - void TabDrag(int ix); - void TabHighlight(); - void TabClose(Value v); - void HideAnimate(Ctrl *c); - void AdjustSize(Rect& r, const Size& sz); -}; - -#endif +#ifndef _Docking_DockTabBar_h_ +#define _Docking_DockTabBar_h_ + +#include +using namespace Upp; + +#include + +class DockTabBar : public TabBar { +public: + typedef DockTabBar CLASSNAME; + + Callback1 WhenContext; + Callback1 WhenDrag; + + virtual void ContextMenu(Bar& bar) { TabBar::ContextMenu(bar); } + + virtual void FrameAddSize(Size& sz); + virtual void FrameLayout(Rect& r); + bool IsAutoHide() const { return GetCount() <= autohide; } + + DockTabBar& AutoHideMin(int hidemin = 1) { autohide = hidemin; return *this; } + DockTabBar& Icons(bool b = true) { icons = b; return *this; } + + void SyncRepos() { Repos(); } + void ShowText(bool show) { showtext = show; } + + DockTabBar(); +protected: + int autohide; + bool icons:1; + bool showtext:1; + + virtual void PaintTabData(Draw& w, const Rect &t, const Tab& tab, const Font &font, + Color ink, dword style); + virtual Size GetStdSize(const Tab &q); + + virtual void RightDown(Point p, dword keyflags); + virtual void LeftDown(Point p, dword keyflags) { TabBar::LeftDown(p, keyflags &= ~K_SHIFT); } + virtual void LeftUp(Point p, dword keyflags) { TabBar::LeftUp(p, keyflags &= ~K_SHIFT); } + virtual void LeftDrag(Point p, dword keyflags); +}; + +class DockCont; + +class AutoHideBar : public DockTabBar { +public: + typedef AutoHideBar CLASSNAME; + + virtual void MouseEnter(Point p, dword keyflags); + virtual void MouseLeave(); + + void AddCtrl(DockCont& c, const String& group = Null); + int FindCtrl(const DockCont& c) const; + DockCont *GetCtrl(int ix) const { return ValueTo(Get(ix)); } + void RemoveCtrl(int ix); + void RemoveCtrl(DockCont& c) { return RemoveCtrl(c, FindCtrl(c)); } + void RemoveCtrl(DockCont& c, int ix); + bool HasCtrl(const DockCont& c) const { return (FindCtrl(c) >= 0); } + + void ShowAnimate(Ctrl *c); + + static void SetTimeout(int delay_ms) { ASSERT(delay_ms > 0); autohide_timeout = delay_ms; } + + AutoHideBar(); + +private: + static int autohide_timeout; + + struct HidePopup : public Ctrl { + HidePopup() { BackPaint(); } + Callback WhenEnter; + Callback WhenLeave; + virtual void ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags); + }; + + enum { TIMEID_ACTION_CHECK = Ctrl::TIMEID_COUNT, + TIMEID_HIDE_TIMEOUT, + TIMEID_COUNT }; + Ctrl *ctrl; + HidePopup popup; + + void TabDrag(int ix); + void TabHighlight(); + void TabClose(Value v); + void HideAnimate(Ctrl *c); + void AdjustSize(Rect& r, const Size& sz); +}; + +#endif diff --git a/bazaar/TabBar/TabBar.cpp b/bazaar/TabBar/TabBar.cpp index f825cf6dd..9934cdc7c 100644 --- a/bazaar/TabBar/TabBar.cpp +++ b/bazaar/TabBar/TabBar.cpp @@ -1,1628 +1,1597 @@ -#include "TabBar.h" - -#define IMAGECLASS TabBarImg -#define IMAGEFILE -#include - -// AlignedFrame -void AlignedFrame::FrameLayout(Rect &r) -{ - switch(layout) - { - case LEFT: - LayoutFrameLeft(r, this, framesize); - break; - case TOP: - LayoutFrameTop(r, this, framesize); - break; - case RIGHT: - LayoutFrameRight(r, this, framesize); - break; - case BOTTOM: - LayoutFrameBottom(r, this, framesize); - break; - } - r.top += border; - r.left += border; - r.right -= border; - r.bottom -= border; -} - -void AlignedFrame::FrameAddSize(Size& sz) -{ - sz += border * 2; - IsVert() ? sz.cx += framesize : sz.cy += framesize; -} - -void AlignedFrame::FramePaint(Draw& w, const Rect& r) -{ - if(border > 0) - { - Rect n = r; - switch(layout) - { - case LEFT: - n.left += framesize; - break; - case TOP: - n.top += framesize; - break; - case RIGHT: - n.right -= framesize; - break; - case BOTTOM: - n.bottom -= framesize; - break; - } - ViewFrame().FramePaint(w, n); - } - else - FrameCtrl::FramePaint(w, r); -} - -AlignedFrame& AlignedFrame::SetFrameSize(int sz, bool refresh) -{ - framesize = sz; - if (refresh) RefreshParentLayout(); - return *this; -} - -void AlignedFrame::Fix(Size& sz) -{ - if(IsVert()) - Swap(sz.cx, sz.cy); -} - -void AlignedFrame::Fix(Point& p) -{ - if(IsVert()) - Swap(p.x, p.y); -} - -Size AlignedFrame::Fixed(const Size& sz) -{ - return IsVert() ? Size(sz.cy, sz.cx) : Size(sz.cx, sz.cy); -} - -Point AlignedFrame::Fixed(const Point& p) -{ - return IsVert() ? Point(p.y, p.x) : Point(p.x, p.y); -} - -// TabScrollBar -TabScrollBar::TabScrollBar() -{ - Clear(); -} - -void TabScrollBar::Clear() -{ - total = 0; - pos = 0; - ps = 0; - start_pos = 0; - new_pos = 0; - old_pos = 0; - sz.Clear(); - ready = false; -} - -void TabScrollBar::UpdatePos(bool update) -{ - sz = GetSize(); - Fix(sz); - if(total <= 0 || sz.cx <= 0) - cs = ics = 0; - else - { - cs = sz.cx / ((double) total + 0.5); - ics = total / ((double) sz.cx); - } - size = sz.cx * cs; - if(update) - pos = new_pos - start_pos; - if(pos < 0) - pos = 0; - else if(pos + size > sz.cx) - pos = sz.cx - size; - - ps = total > sz.cx ? pos * ics : 0; -} - -void TabScrollBar::Paint(Draw &w) -{ - if(!ready) - { - UpdatePos(); - ready = true; - } - Size rsz = GetSize(); - #ifdef TABBAR_DEBUG - w.DrawRect(rsz, Red); - #else - w.DrawRect(rsz, White); - #endif - Point p; - - if(total > sz.cx) { - p = Point(ffloor(pos), 1); - rsz = Size(fceil(size), 2); - } - else { - p = Point(0, 1); - rsz = Size(sz.cx, 2); - } - Fix(p); - Fix(rsz); - w.DrawRect(p.x, p.y, rsz.cx, rsz.cy, Blue); -} - -void TabScrollBar::Layout() -{ - UpdatePos(false); -} - -void TabScrollBar::LeftDown(Point p, dword keyflags) -{ - SetCapture(); - Fix(p); - old_pos = new_pos = p.x; - if(p.x < pos || p.x > pos + size) - start_pos = size / 2; - else - start_pos = tabs(p.x - pos); - UpdatePos(); - UpdateActionRefresh(); -} - -void TabScrollBar::LeftUp(Point p, dword keyflags) -{ - ReleaseCapture(); - Fix(p); - old_pos = p.x; -} - -void TabScrollBar::MouseMove(Point p, dword keyflags) -{ - if(!HasCapture()) - return; - - Fix(p); - new_pos = p.x; - UpdatePos(); - UpdateActionRefresh(); -} - -void TabScrollBar::MouseWheel(Point p, int zdelta, dword keyflags) -{ - AddPos(-zdelta / 4, true); - UpdateActionRefresh(); -} - -int TabScrollBar::GetPos() const -{ - return ffloor(ps); -} - -void TabScrollBar::SetPos(int p, bool dontscale) -{ - pos = total > 0 ? dontscale ? p : iscale(p, sz.cx, total) : 0; - UpdatePos(false); - Refresh(); -} - -void TabScrollBar::AddPos(int p, bool dontscale) -{ - pos += total > 0 ? dontscale ? p : iscale(p, sz.cx, total) : 0; - UpdatePos(false); - Refresh(); -} - -int TabScrollBar::GetTotal() const -{ - return total; -} - -void TabScrollBar::SetTotal(int t) -{ - bool upd = total < t; - total = t; - UpdatePos(upd); - Refresh(); -} - -void TabScrollBar::AddTotal(int t) -{ - total += t; - UpdatePos(); - Refresh(); -} - -void TabScrollBar::GoEnd() -{ - pos = total; - UpdatePos(false); - Refresh(); -} - -void TabScrollBar::GoBegin() -{ - pos = 0; - UpdatePos(false); - Refresh(); -} - -void TabScrollBar::Set(const TabScrollBar& t) -{ - total = t.total; - pos = t.pos; - ps = t.ps; - Refresh(); -} - -bool TabScrollBar::IsScrollable() const -{ - // Note: sz already 'fixed' - return total > sz.cx && sz.cx > 0; -} - -// TabBar -TabBar::Style TabBar::leftstyle; -TabBar::Style TabBar::rightstyle; -TabBar::Style TabBar::bottomstyle; - -TabBar::TabBar() -{ - Clear(); - display = NULL; - crosses = true; - grouping = true; - isctrl = false; - isdrag = false; - inactivedisabled = false; - autoscrollhide = true; - stacking = true; - groupsort = true; - neverempty = 1; - - style[0] = style[1] = style[2] = style[3] = NULL; - SetAlign(TOP); - SetFrameSize(GetHeight()); - BackPaint(); -} - -void TabBar::CloseAll() -{ - for(int i = tabs.GetCount() - 1; i >= 0; i--) - if(i != active) - tabs.Remove(i); - - SyncScrollBar(); - MakeGroups(); - Repos(); - SetCursor(0); - WhenCloseAll(); -} - -int TabBar::GetNextId() -{ - return ++id; -} - -void TabBar::ContextMenu(Bar& bar) -{ - if (highlight >= 0) { - bar.Add(tabs.GetCount() > 1, "Close", THISBACK1(Close, highlight)); - bar.Separator(); - } - int cnt = groups.GetCount(); - for(int i = 0; i < cnt; i++) - { - String name = Format("%s (%d)", groups[i].name, groups[i].count); - Bar::Item &it = i > 0 ? bar.Add(name, THISBACK1(GroupMenu, i)) - : bar.Add(name, THISBACK1(DoGrouping, i)); - if(i == group) - it.Image(TabBarImg::CHK); - if(i == 0 && cnt > 1) - bar.Separator(); - } - bar.Separator(); - - bar.Add("Close others", THISBACK(CloseAll)); -} - -void TabBar::GroupMenu(Bar &bar, int n) -{ - bar.Add("Set active", THISBACK1(DoGrouping, n)); - bar.Add("Close", THISBACK1(DoCloseGroup, n)); -} - -bool TabBar::Tab::HasMouse(const Point& p) const -{ - return visible && p.x >= real_pos.x && p.x < real_pos.x + real_size.cx && - p.y >= real_pos.y && p.y < real_pos.y + real_size.cy; -} - -bool TabBar::Tab::HasMouseCross(const Point& p) const -{ - if(!visible) - return false; - - return p.x >= cross_pos.x && p.x < cross_pos.x + cross_size.cx && - p.y >= cross_pos.y && p.y < cross_pos.y + cross_size.cy; -} - -int TabBar::FindGroup(const String& g) const -{ - for(int i = 0; i < groups.GetCount(); i++) - if(groups[i].name == g) - return i; - return -1; -} - -void TabBar::DoStacking() -{ - Value v = GetData(); - for (int i = 0; i < tabs.GetCount(); i++) { - Tab &base = tabs[i]; - for (int j = i+1; j < tabs.GetCount(); j++) { - Tab &t = tabs[j]; - if ((!grouping || base.group == t.group) && stackfunc(base.data, t.data)) { - base.stack.AddTail(t.data); - tabs.Remove(j); - j--; - } - } - } - highlight = -1; - MakeGroups(); - Repos(); - int c = active; - SetData(v); - if (active < 0 || c != active) - Refresh(); -} - -void TabBar::DoUnstacking() -{ - for (int i = 0; i < tabs.GetCount(); i++) { - for (int j = tabs[i].stack.GetCount()-1; j >= 0; j--) { - Tab &t = tabs.Insert(i+1); - t.id = GetNextId(); - t.data = tabs[i].stack[j]; - t.group = tabs[i].group; - } - tabs[i].stack.Clear(); - } - highlight = -1; - MakeGroups(); - Repos(); - if (HasCursor()) - SetCursor(-1); - else - Refresh(); -} - -void TabBar::StackRemove(BiVector &stack, int ix) -{ - int cnt = stack.GetCount() >> 1; - if (ix <= cnt) { - int i = ix-1; - while (i >= 0) { - Swap(stack[i], stack[ix]); - ix = i; - i--; - } - stack.DropHead(); - } - else { - int i = ix+1; - while (i < stack.GetCount()) { - Swap(stack[i], stack[ix]); - ix = i; - i++; - } - stack.DropTail(); - } -} - -void TabBar::MakeGroups() -{ - groups[0].count = tabs.GetCount(); - groups[0].first = 0; - groups[0].last = tabs.GetCount() - 1; - - if (groupsort) - Sort(tabs, TabGroupSort()); - - for(int i = 1; i < groups.GetCount(); i++) - { - groups[i].count = 0; - groups[i].first = 10000000; - groups[i].last = 0; - } - - for(int i = 0; i < tabs.GetCount(); i++) - { - Tab &tab = tabs[i]; - int n = FindGroup(tab.group); - ASSERT(n >= 0); - if (n > 0) { - if(groups[n].active < 0) - groups[n].active = tab.id; - groups[n].count++; - groups[n].last = i; - - if(i < groups[n].first) - groups[n].first = i; - if(i > groups[n].last) - groups[n].last = i; - } - } - - int removed = 0; - for(int i = 1; i < groups.GetCount(); i++) - if(groups[i].count == 0) - { - groups.Remove(i - removed); - removed++; - } - if(group > groups.GetCount() - 1 && group > 0) - group--; -} - -void TabBar::DoGrouping(int n) -{ - group = n; - Repos(); - SyncScrollBar(); - SetCursor(-1); -} - -void TabBar::DoCloseGroup(int n) -{ - int cnt = groups.GetCount(); - if(cnt <= 0) - return; - if (cnt == n) - --group; - - String group = groups[n].name; - - for(int i = tabs.GetCount() - 1; i >= 0; i--) - { - if(group == tabs[i].group && tabs.GetCount() > 1) { - Value v = tabs[i].data; - tabs.Remove(i); - WhenClose(v); - } - } - if(cnt > 1) - groups.Remove(n); - MakeGroups(); - Repos(); - SetCursor(-1); -} - -void TabBar::NewGroup(const String &name, const Value &data) -{ - Group &g = groups.Add(); - g.name = name; - g.data = data; - g.count = 0; - g.first = 10000000; - g.last = 0; - g.active = -1; -} - -Value TabBar::AlignValue(int align, const Value &v, const Size &isz) -{ - if (align == TOP) return v; - if (IsTypeRaw(v)) { - switch(align) { - case AlignedFrame::LEFT: return RotateAntiClockwise((Image)v); - case AlignedFrame::RIGHT: return RotateClockwise((Image)v); - case AlignedFrame::BOTTOM: return MirrorVert((Image)v); - } - } - else if (!IsTypeRaw(v)) { - ImageDraw w(isz.cx, isz.cy); - w.DrawRect(isz, SColorFace()); - ChPaint(w, isz, v); - ImageBuffer img; - Image temp = (Image)w; - switch(align) { - case AlignedFrame::LEFT: - temp = RotateAntiClockwise(temp); - img = temp; // GCC - img.SetHotSpot(Point(1, 5)); - img.Set2ndSpot(Point(isz.cy / 2, isz.cx / 2)); - break; - case AlignedFrame::RIGHT: - temp = RotateClockwise(temp); - img = temp; - img.SetHotSpot(Point(isz.cy - 10, isz.cx - 10)); - img.Set2ndSpot(Point(isz.cy / 2, isz.cx / 2)); - break; - case AlignedFrame::BOTTOM: - temp = MirrorVert(temp); - img = temp; - img.SetHotSpot(Point(10, 10)); - img.Set2ndSpot(Point(isz.cx / 2, isz.cy / 2)); - break; - - } - return (Image)img; - } - return v; -} - -WString TabBar::ParseLabel(const WString& s) -{ - return s; -} - -void TabBar::PaintTabData(Draw& w, const Rect& r, const Tab& tab, const Font &font, Color ink, dword style, int bl) -{ - WString txt; - Font f = font; - Color i = ink; - const Value &q = tab.data; - - if(IsType(q)) { - const AttrText& t = ValueTo(q); - txt = t.text; - if(!IsNull(t.font)) - f = t.font; - i = IsNull(t.ink) ? ink : t.ink; - } - else - txt = IsString(q) ? q : StdConvert().Format(q); - - Point p = GetTextPosition(r, GetTextSize(txt, font).cy, bl); - w.DrawText(p.x, p.y, GetTextAngle(), ParseLabel(txt), f, i); -} - -Point TabBar::GetTextPosition(const Rect& r, int fy, int bl) const -{ - Point p; - int align = GetAlign(); - - fy /= 2; - if(align == LEFT) - { - p = r.BottomLeft(); - p.x = bl - fy; - } - else if(align == RIGHT) - { - p = r.TopRight(); - p.x = bl + fy + 1; - } - else - { - p = r.TopLeft(); - p.y = bl - fy; - } - return p; -} - -void TabBar::PaintTab(Draw &w, const Style &s, const Size &sz, int n, bool enable, bool dragsample) -{ - TabBar::Tab &t = tabs[n]; - int cnt = dragsample ? 1 : tabs.GetCount(); - Size tsz, fsz(sz.cx, sz.cy + TB_SBSEPARATOR * !sc.IsShown()), isz(0, 0); - Fix(fsz); - - Point p; - - int align = GetAlign(); - bool ac = n == active; - bool hl = n == highlight; - - int ndx = !enable ? CTRL_DISABLED : - ac ? CTRL_PRESSED : - hl ? CTRL_HOT : CTRL_NORMAL; - - int c = align == LEFT ? cnt - n : n; - const Value& sv = (cnt == 1 ? s.both : c == 0 ? s.first : c == cnt - 1 ? s.last : s.normal)[ndx]; - - int lx = n > 0 ? s.extendleft : 0; - int x = t.pos.x - sc.GetPos() + s.margin - lx; - - if (ac) { - p = Point(x - s.sel.left, 0); - tsz = Size(t.size.cx + lx + s.sel.right + s.sel.left, t.size.cy + s.sel.bottom); - } - else { - p = Point(x, s.sel.top); - tsz = Size(t.size.cx + lx, t.size.cy - s.sel.top); - } - - if (align == BOTTOM || align == RIGHT) - p.y -= s.sel.top - TB_SBSEPARATOR * sc.IsVisible(); - - t.real_pos = Fixed(p); - t.real_size = Fixed(tsz); - - ChPaint(w, t.real_pos.x, t.real_pos.y, t.real_size.cx, t.real_size.cy, sv); - - #ifdef TABBAR_DEBUG - DrawFrame(w, Rect(t.real_pos, t.real_size), Blue); - #endif - - Point cp; - - Size bsz(t.size.cx + lx, t.size.cy - s.sel.top); - - int cly = (fsz.cy - s.sel.top - s.sel.bottom * ac) / 2 + s.sel.top; - - if(crosses && (cnt > neverempty || t.stack.GetCount())) { - - const Image &cimg = TabBarImg::CR0(); - isz = cimg.GetSize(); - - if (align == LEFT) - { - cp.x = cly - isz.cy / 2; - cp.y = x + TB_MARGIN; - } - else if (align == RIGHT) - { - cp.x = fsz.cy - (cly - isz.cy / 2 + isz.cy); - cp.y = x + bsz.cx - isz.cx - TB_MARGIN; - } - else if (align == TOP) - { - cp.x = x + bsz.cx - isz.cx - TB_MARGIN; - cp.y = cly - isz.cy / 2; - } - else if (align == BOTTOM) - { - cp.x = x + bsz.cx - isz.cx - TB_MARGIN; - cp.y = fsz.cy - (cly - isz.cy / 2 + isz.cy); - } - - t.cross_pos = cp; - t.cross_size = isz; - w.DrawImage(cp.x, cp.y, (ac || hl) ? (cross == n ? TabBarImg::CR2 : ac ? TabBarImg::CR1 : TabBarImg::CR0) : TabBarImg::CR0); - isz.cx += 2; - } - - bsz.cx -= TB_MARGIN * 2 + isz.cx; - - if (align == LEFT) - { - cp.x = cly - bsz.cy / 2; - cp.y = x + TB_MARGIN + isz.cx; - } - else if (align == RIGHT) - { - cp.x = fsz.cy - (cly - bsz.cy / 2 + bsz.cy); - cp.y = x + TB_MARGIN; - } - else if (align == TOP) - { - cp.x = x + TB_MARGIN; - cp.y = cly - bsz.cy / 2; - } - else if (align == BOTTOM) - { - cp.x = x + TB_MARGIN; - cp.y = fsz.cy - (cly - bsz.cy / 2 + bsz.cy); - } - - Fix(bsz); - - Rect r(cp, bsz); - - #ifdef TABBAR_DEBUG - w.DrawRect(r, Green); - //w.DrawText(p.x, p.y, AsString(s.sel.bottom) + ", " + AsString(s.sel.top) + ", st:" + AsString(GetHeight()) + ", sz:" + AsString(sz.cy) + ", rs:" + AsString(t.real_size.cy), StdFont().Bold()); - #endif - - if(align == RIGHT || align == BOTTOM) - cly = fsz.cy - cly - 1; - - if (display) - display->Paint(w, r, t.data, s.text_color[ndx], SColorDisabled(), ndx); - else - PaintTabData(w, r, t, s.font, s.text_color[ndx], ndx, cly); - - #ifdef TABBAR_DEBUG - Point pp(p.x, cly); - Fix(pp); - w.DrawRect(pp.x, pp.y, IsVert() ? 1 : bsz.cx, IsVert() ? bsz.cy : 1, LtBlue); - #endif -} - -void TabBar::Paint(Draw &w) -{ - int align = GetAlign(); - const Style &st = *style[align]; - Size sz = GetSize(); - - #ifdef TABBAR_DEBUG - w.DrawRect(sz, Yellow); - #else - w.DrawRect(sz, SColorFace()); - #endif - - if(sc.IsShown()) - { - IsVert() ? - w.DrawRect(align == LEFT ? sz.cx - 1 : 0, 0, 1, sz.cy, Color(128, 128, 128)): - w.DrawRect(0, align == TOP ? sz.cy - 1 : 0, sz.cx, 1, Color(128, 128, 128)); - } - - if (!tabs.GetCount()) return; - - int limt = sc.GetPos() + (IsVert() ? sz.cy : sz.cx); - - int first = 0; - int last = tabs.GetCount()-1; - // Find first visible tab - for(int i = 0; i < tabs.GetCount(); i++) { - Tab &tab = tabs[i]; - if (tab.pos.x + tab.size.cx > sc.GetPos()) { - first = i; - break; - } - } - // Find last visible tab - for(int i = first + 1; i < tabs.GetCount(); i++) { - if (tabs[i].visible && tabs[i].pos.x > limt) { - last = i; - break; - } - } - // Draw active group - for (int i = first; i <= last; i++) { - if(tabs[i].visible && i != active) - PaintTab(w, st, sz, i, IsEnabled()); - } - // Clear real_size for non-visible tabs to prevent mouse handling bugs - for (int i = 0; i < first; i++) - tabs[i].real_size = Size(0, 0); - for (int i = last+1; i < tabs.GetCount(); i++) - tabs[i].real_size = Size(0, 0); - // Draw inactive groups - if (inactivedisabled) - for (int i = first; i <= last; i++) { - if(!tabs[i].visible && i != active) - PaintTab(w, st, sz, i, !IsEnabled()); - } - - // Draw selected tab - if(active >= first && active <= last) - PaintTab(w, st, sz, active, true); - // Draw drag highlights - if(target >= 0) - { - // Draw target marker - int drag = isctrl ? highlight : active; - if(target != drag && target != drag + 1) - { - last = GetLast(); - first = GetFirst(); - int x = (target == last + 1 ? tabs[last].Right() : tabs[target].pos.x) - - sc.GetPos() - (target <= first ? 1 : 2) - + st.margin - (target > 0 ? st.extendleft : 0); - int y = st.sel.top; - int cy = sz.cy - y; - if (IsHorz()) { - w.DrawRect(x + 1, y, 2, cy, SRed()); - w.DrawRect(x, y, 4, 1, SRed()); - w.DrawRect(x, y + cy - 1, 4, 1, SRed()); - } - else{ - w.DrawRect(y, x + 1, cy, 2, SRed()); - w.DrawRect(y, x, 1, 4, SRed()); - w.DrawRect(y + cy - 1, x, 1, 4, SRed()); - } - } - // Draw transparent drag image - Point mouse = GetMousePos() - GetScreenRect().TopLeft(); - Size isz = dragtab.GetSize(); - if (IsHorz()) - w.DrawImage(mouse.x - isz.cx/2, 0, isz.cx, isz.cy, dragtab); - else - w.DrawImage(0, mouse.y - isz.cy/2, isz.cx, isz.cy, dragtab); - } -} - -Image TabBar::GetDragSample() -{ - return GetDragSample(highlight); -} - -Image TabBar::GetDragSample(int n) -{ - if (n < 0) return Image(); - Tab &tab = tabs[n]; - const Style& st = *style[GetAlign()]; - - Size tsz(tab.real_size); - ImageDraw iw(tsz); - iw.DrawRect(tsz, SColorFace()); //this need to be fixed - if inactive tab is dragged gray edges are visible - - Point temp = tab.pos; - tab.pos.x = sc.GetPos(); - tab.pos.y = 0; - PaintTab(iw, st, GetSize(), n, true, true); - tab.pos.x = temp.x; - tab.pos.y = temp.y; - - Image img = iw; - ImageBuffer ib(img); - Unmultiply(ib); - RGBA *s = ~ib; - RGBA *e = s + ib.GetLength(); - while(s < e) { - s->a = 180; - s++; - } - Premultiply(ib); - return ib; -} - -void TabBar::Scroll() -{ - Refresh(); -} - -int TabBar::GetWidth(int n) -{ - Tab &t = tabs[n]; - Size tsz = GetStdSize(t); - return TB_MARGIN * 2 + tsz.cx + (TB_SPACE + TabBarImg::CR0().GetSize().cx) * crosses; -} - -Size TabBar::GetStdSize(const Value &q) -{ - if (display) - return display->GetStdSize(q); - else if (q.GetType() == STRING_V || q.GetType() == WSTRING_V) - return GetTextSize(ParseLabel(WString(q)), StdFont()); - else - return GetTextSize("A Tab", StdFont()); -} - -Size TabBar::GetStdSize(const Tab &t) -{ - return GetStdSize(t.data); -} - -TabBar& TabBar::Add(const Value &data, String group, bool make_active) -{ - return Insert(tabs.GetCount(), data, group, make_active); -} - -TabBar& TabBar::Insert(int ix, const Value &data, String group, bool make_active) -{ - ASSERT(ix >= 0); - int g = 0; - if (!group.IsEmpty()) { - g = FindGroup(group); - if (g < 0) { - NewGroup(group); - g = groups.GetCount() - 1; - } - } - group = groups[g].name; - bool stacked = false; - if (stacking) { - for (int i = 0; i < tabs.GetCount(); i++) { - Tab &t = tabs[i]; - if (t.group == group && stackfunc(t.data, data)) { - if (make_active) { - t.stack.AddHead(t.data); - t.data = data; - } - else - t.stack.AddTail(data); - stacked = true; - } - } - } - if (!stacked) { - Tab &t = tabs.Insert(ix); - t.data = data; - t.id = GetNextId(); - t.group = group; - - MakeGroups(); - } - Repos(); - active = -1; - if (make_active) - SetCursor(minmax(ix, 0, tabs.GetCount() - 1)); - return *this; -} -int TabBar::GetWidth() const -{ - if (!tabs.GetCount()) return 0; - return tabs[GetLast()].Right() + style[GetAlign()]->margin * 2; -} - -int TabBar::GetHeight(bool scrollbar) const -{ - return TabBar::GetStyleHeight(*style[GetAlign()]) + TB_SBSEPARATOR * int(scrollbar); -} - -int TabBar::GetStyleHeight(const Style &s) -{ - return s.tabheight + s.sel.top; -} - -void TabBar::Repos() -{ - if(!tabs.GetCount()) - return; - - String g = GetGroupName(); - - int j; - bool first = true; - j = 0; - for(int i = 0; i < tabs.GetCount(); i++) - j = TabPos(g, first, i, j, false); - if (inactivedisabled) - for(int i = 0; i < tabs.GetCount(); i++) - if (!tabs[i].visible) - j = TabPos(g, first, i, j, true); - SyncScrollBar(); -} - -int TabBar::TabPos(const String &g, bool &first, int i, int j, bool inactive) -{ - bool v = IsNull(g) ? true : g == tabs[i].group; - if(v) - { - tabs[i].pos.x = first ? 0 : tabs[j].Right(); - /* Separators - if (showseps && !first && tabs[i].group != tabs[j].group) { - seperators.Add(tabs[i].pos.x); - tabs[i].pos.x += TB_SEPARATOR; - } */ - j = i; - first = false; - } - else { - tabs[i].pos.x = 0; - if (inactive) { - tabs[i].pos.x = tabs[j].Right(); - return (j = i); - } - } - - tabs[i].visible = v; - tabs[i].pos.y = 0; - tabs[i].size.cx = GetWidth(i); - tabs[i].size.cy = GetStyleHeight(*style[1]); - - return j; -} - -void TabBar::SyncScrollBar(bool synctotal) -{ - if (synctotal) - sc.SetTotal(GetWidth()); - if (autoscrollhide) { - bool v = sc.IsScrollable(); - if (sc.IsShown() != v) { - SetFrameSize((v ? sc.GetFrameSize() : 0) + GetHeight(v), false); - sc.Show(v); - PostCallback(THISBACK(RefreshParentLayout)); - } - } - else { - SetFrameSize(sc.GetFrameSize() + GetHeight(true), false); - sc.Show(); - } -} - -int TabBar::FindId(int id) const -{ - for(int i = 0; i < tabs.GetCount(); i++) - if(tabs[i].id == id) - return i; - return -1; -} - -int TabBar::GetNext(int n) const -{ - for(int i = n + 1; i < tabs.GetCount(); i++) - if(tabs[i].visible) - return i; - return -1; -} - -int TabBar::GetPrev(int n) const -{ - for(int i = n - 1; i >= 0; i--) - if(tabs[i].visible) - return i; - return -1; -} - -void TabBar::Clear() -{ - highlight = -1; - active = -1; - target = -1; - id = -1; - tabs.Clear(); - groups.Clear(); - NewGroup("All"); - group = 0; - Refresh(); -} - -TabBar& TabBar::Crosses(bool b) -{ - crosses = b; - Repos(); - return *this; -} - -TabBar& TabBar::Grouping(bool b) -{ - grouping = b; - return *this; -} - -TabBar& TabBar::GroupSort(bool b) -{ - groupsort = b; - if (b) - MakeGroups(); - return *this; -} -/* Separators -TabBar& TabBar::Seperators(bool b) -{ - showseps = b; - Repos(); - return *this; -} -*/ -TabBar& TabBar::AutoScrollHide(bool b) -{ - autoscrollhide = b; - sc.Hide(); - SetFrameSize(GetHeight(), false); - SyncScrollBar(GetWidth()); - return *this; -} - -TabBar& TabBar::InactiveDisabled(bool b) -{ - inactivedisabled = b; - if (b) Repos(); - return *this; -} - -void TabBar::FrameSet() -{ - int al = GetAlign(); - Ctrl::ClearFrames(); - sc.Clear(); - sc.SetFrameSize(TB_SBHEIGHT).SetAlign((al >= 2) ? al - 2 : al + 2); - sc <<= THISBACK(Scroll); - sc.Hide(); - if (!sc.IsChild()) - AddFrame(sc); - - style[0] = &StyleLeft(); - style[1] = &StyleDefault(); - style[2] = &StyleRight(); - style[3] = &StyleBottom(); - - SyncScrollBar(GetWidth()); -} - -void TabBar::ResetStyles() -{ - StyleLeft(); - StyleRight(); - StyleBottom(); -} - -void TabBar::FrameLayout(Rect& r) -{ - AlignedFrame::FrameLayout(r); -} - -void TabBar::Layout() -{ - if (autoscrollhide && tabs.GetCount()) - SyncScrollBar(false); -} - -int TabBar::Find(const Value &v) const -{ - for (int i = 0; i < tabs.GetCount(); i++) - if (tabs[i].data == v) - return i; - return -1; -} - -int TabBar::FindInStack(const Value &v, int &stackix) const -{ - stackix = -1; - for (int i = 0; i < tabs.GetCount(); i++) { - if (tabs[i].data == v) - return i; - for (int j = 0; j < tabs[i].stack.GetCount(); j++) - if (tabs[i].stack[j] == v) { - stackix = j; - return i; - } - } - return -1; -} - -void TabBar::CycleTabStack(int n) -{ - if (tabs[n].stack.GetCount()) { - Tab &t = tabs[n]; - Value v = t.data; - t.data = t.stack.Head(); - t.stack.DropHead(); - t.stack.AddTail(v); - } -} - -void TabBar::SetData(const Value &data) -{ - int stackix = -1; - int n = FindInStack(data, stackix); - if (n >= 0) { - if (stackix >= 0) { - Tab &t = tabs[n]; - Value v = t.stack[stackix]; - StackRemove(t.stack, stackix); - t.stack.AddTail(t.data); - t.data = v; - } - SetCursor(n); - } -} - -void TabBar::Set(int n, const Value &data, const String &group) -{ - ASSERT(n >= 0 && n < tabs.GetCount()); - tabs[n].data = data; - if (!IsNull(data)) - SetTabGroup(n, group); - else - Repos(); -} - -void TabBar::LeftDown(Point p, dword keyflags) -{ - if(keyflags & K_SHIFT) - { - highlight = -1; - Refresh(); - SetCapture(); - Fix(p); - oldp = p; - return; - } - - isctrl = keyflags & K_CTRL; - if(isctrl) - return; - - if(cross != -1) { - Value v = tabs[cross].data; - Close(cross); - WhenClose(v); - } - else if(highlight >= 0) { - if (highlight == active) { - CycleTabStack(active); - Repos(); - UpdateActionRefresh(); - } - else - SetCursor(highlight); - } -} - -void TabBar::LeftUp(Point p, dword keyflags) -{ - ReleaseCapture(); -} - -void TabBar::LeftDouble(Point p, dword keysflags) -{ - WhenLeftDouble(); -} - -void TabBar::RightDown(Point p, dword keyflags) -{ - MenuBar::Execute(THISBACK(ContextMenu), GetMousePos()); -} - -void TabBar::MiddleDown(Point p, dword keyflags) -{ - Close(highlight); -} - -void TabBar::MiddleUp(Point p, dword keyflags) -{ -} - -int TabBar::GetTargetTab(Point p) -{ - p.x += sc.GetPos(); - - int f = GetFirst(); - int l = GetLast(); - - if(tabs[f].visible && p.x < tabs[f].pos.x + tabs[f].size.cx / 2) - return f; - - for(int i = l; i >= f; i--) - if(tabs[i].visible && p.x >= tabs[i].pos.x + tabs[i].size.cx / 2) - return i == l ? i + 1 : GetNext(i); -// if(tabs[i].visible && p.x >= tabs[i].x && p.x <= tabs[i].x + tabs[i].cx) -// return i; - return -1; -} - -void TabBar::MouseWheel(Point p, int zdelta, dword keyflags) -{ - sc.AddPos(-zdelta / 4, true); - Scroll(); - MouseMove(p, 0); -} - -bool TabBar::ProcessMouse(int i, const Point& p) -{ - if(i >= 0 && tabs[i].HasMouse(p)) - { - bool iscross = crosses ? tabs[i].HasMouseCross(p) : false; - if(highlight != i || (iscross && cross != i || !iscross && cross == i)) - { - cross = iscross ? i : -1; - highlight = i; - WhenHighlight(); - Refresh(); - } - return true; - } - - return false; -} - -void TabBar::MouseMove(Point p, dword keyflags) -{ - if(HasCapture()) - { - Fix(p); - sc.AddPos(p.x - oldp.x, true); - oldp = p; - Refresh(); - return; - } - - if(ProcessMouse(active, p)) - return; - - for(int i = 0; i < tabs.GetCount(); i++) - { - if(i == active) - continue; - - if(ProcessMouse(i, p)) - return; - } - - if(highlight >= 0 || cross >= 0) - { - highlight = cross = -1; - WhenHighlight(); - Refresh(); - } -} - -void TabBar::MouseLeave() -{ - if(isdrag) - return; - highlight = cross = -1; - WhenHighlight(); - Refresh(); -} - -void TabBar::DragAndDrop(Point p, PasteClip& d) -{ - Fix(p); - int c = GetTargetTab(p); - int tab = isctrl ? highlight : active; - - if (&GetInternal(d) != this) return; - - bool sametab = c == tab || c == tab + 1; - bool internal = AcceptInternal(d, "tabs"); - - if(!sametab && d.IsAccepted()) - { - if(internal) - { - int id = tabs[active].id; - Tab t = tabs[tab]; - Tab &n = tabs.Insert(c); - n = t; - tabs.Remove(tab + int(c < tab)); - active = FindId(id); - isdrag = false; - MakeGroups(); - Repos(); - return; - } - else if(d.IsPaste()) - { - CancelMode(); - return; - } - } - else - { - //d.Reject(); - //unfortunately after Reject DragLeave stops working until d is accepted - } - target = c; - Refresh(); -} - -void TabBar::CancelMode() -{ - isdrag = false; - target = -1; - Refresh(); -} - -void TabBar::LeftDrag(Point p, dword keyflags) -{ - if(keyflags & K_SHIFT) - return; - if(highlight < 0) - return; - - isdrag = true; - dragtab = GetDragSample(); - DoDragAndDrop(InternalClip(*this, "tabs")); -} - -void TabBar::DragEnter() -{ -} - -void TabBar::DragLeave() -{ - target = -1; - Refresh(); -} - -void TabBar::DragRepeat(Point p) -{ - if(target >= 0) - { - Point dx = GetDragScroll(this, p, 16); - Fix(dx); - if(dx.x != 0) - sc.AddPos(dx.x); - } -} - -void TabBar::SetCursor(int n) -{ - if(tabs.GetCount() == 0) - return; - - if(n < 0) - { - n = max(0, FindId(GetGroupActive())); - active = -1; - } - - bool is_all = IsGroupAll(); - bool same_group = tabs[n].group == GetGroupName(); - - if((same_group || is_all) && active == n) - return; - - active = n; - - if(!is_all && !same_group) - { - SetGroup(tabs[n].group); - Repos(); - } - - SetGroupActive(tabs[n].id); - - int cx = tabs[n].pos.x - sc.GetPos(); - if(cx < 0) - sc.AddPos(cx - 10); - else - { - Size sz = Ctrl::GetSize(); - Fix(sz); - cx = tabs[n].pos.x + tabs[n].size.cx - sz.cx - sc.GetPos(); - if(cx > 0) - sc.AddPos(cx + 10); - } - - Refresh(); - - if(Ctrl::HasMouse()) - { - Sync(); - MouseMove(GetMouseViewPos(), 0); - } - - UpdateAction(); -} - -void TabBar::SetTabGroup(int n, const String &group) -{ - ASSERT(n >= 0 && n < tabs.GetCount()); - int g = FindGroup(group); - if (g <= 0) - NewGroup(group); - else if (groups[g].active == tabs[n].id) - SetGroupActive(tabs[n].id); - tabs[n].group = group; - MakeGroups(); - Repos(); -} - -TabBar & TabBar::StackingFunc(Gate2 func) -{ - if (stacking) - DoUnstacking(); - - stackfunc = func; - DoStacking(); - stacking = true; - return *this; -} - -TabBar & TabBar::NoStacking() -{ - if (stacking) { - stacking = false; - DoUnstacking(); - } - return *this; -} - -void TabBar::Close(int n) -{ - if (stacking && tabs[n].stack.GetCount()) { - CycleTabStack(n); - tabs[n].stack.DropTail(); - Repos(); - SetCursor(-1); - return; - } - - if(tabs.GetCount() <= neverempty) - return; - - if(n == active) - { - int c = FindId(tabs[n].id); - int nc = GetNext(c); - if(nc < 0) - nc = max(0, GetPrev(c)); - SetGroupActive(tabs[nc].id); - } - sc.AddTotal(-tabs[n].size.cx); - tabs.Remove(n); - MakeGroups(); - Repos(); - SetCursor(-1); -} - -void TabBar::CloseData(const Value &data) -{ - int stackix = -1; - int tabix = FindInStack(data, stackix); - if (tabix < 0) return; - - Tab &t = tabs[tabix]; - if (!stacking || t.stack.GetCount() == 0) return Close(tabix); - - if (stackix) - StackRemove(t.stack, stackix); - else { - CycleTabStack(tabix); - t.stack.DropTail(); - } - Repos(); -} - -const TabBar::Style& TabBar::AlignStyle(int align, Style &s) -{ - Size sz(30, GetStyleHeight(s)); - for (int i = 0; i < 4; i++) s.first[i] = AlignValue(align, s.first[i], sz); - for (int i = 0; i < 4; i++) s.last[i] = AlignValue(align, s.last[i], sz); - for (int i = 0; i < 4; i++) s.normal[i] = AlignValue(align, s.normal[i], sz); - for (int i = 0; i < 4; i++) s.both[i] = AlignValue(align, s.both[i], sz); - return s; -} - -CH_STYLE(TabBar, Style, StyleDefault) -{ - Assign(TabCtrl::StyleDefault()); - TabBar::ResetStyles(); -} - -const TabBar::Style& TabBar::StyleLeft() -{ - leftstyle = StyleDefault(); - return AlignStyle(AlignedFrame::LEFT, leftstyle); -} - -const TabBar::Style& TabBar::StyleRight() -{ - rightstyle = StyleDefault(); - return AlignStyle(AlignedFrame::RIGHT, rightstyle); -} - -const TabBar::Style& TabBar::StyleBottom() -{ - bottomstyle = StyleDefault(); - return AlignStyle(AlignedFrame::BOTTOM, bottomstyle); -} - -void TabBar::Serialize(Stream& s) -{ - // Note: doens't work with stacking - int version = 0x00; - int cnt; - if (s.IsLoading()) Clear(); - - s / version / group / highlight / active; - - if (s.IsLoading()) { - cnt = groups.GetCount(); - s / cnt; - for (int i = 1; i < groups.GetCount(); i++) { - Group &g = groups[i]; - s % g.data / g.active; - } - cnt = tabs.GetCount(); - s / cnt; - for (int i = 0; i < tabs.GetCount(); i++) { - Tab &t = tabs[i]; - int g = FindGroup(t.group); - s % t.data / t.id / g; - } - } - else { - s / cnt; - groups.SetCount(cnt); - for (int i = 1; i < cnt; i++) { - Group &g = groups[i]; - s % g.data / g.active; - } - s / cnt; - tabs.SetCount(cnt); - for (int i = 0; i < tabs.GetCount(); i++) { - int g; - Tab &t = tabs[i]; - s % t.data / t.id / g; - t.group = groups[g].name; - } - MakeGroups(); - Repos(); - } -} +#include "TabBar.h" + +#define IMAGECLASS TabBarImg +#define IMAGEFILE +#include + +// AlignedFrame +void AlignedFrame::FrameLayout(Rect &r) +{ + switch(layout) + { + case LEFT: + LayoutFrameLeft(r, this, framesize); + break; + case TOP: + LayoutFrameTop(r, this, framesize); + break; + case RIGHT: + LayoutFrameRight(r, this, framesize); + break; + case BOTTOM: + LayoutFrameBottom(r, this, framesize); + break; + } + r.top += border; + r.left += border; + r.right -= border; + r.bottom -= border; +} + +void AlignedFrame::FrameAddSize(Size& sz) +{ + sz += border * 2; + IsVert() ? sz.cx += framesize : sz.cy += framesize; +} + +void AlignedFrame::FramePaint(Draw& w, const Rect& r) +{ + if(border > 0) + { + Rect n = r; + switch(layout) + { + case LEFT: + n.left += framesize; + break; + case TOP: + n.top += framesize; + break; + case RIGHT: + n.right -= framesize; + break; + case BOTTOM: + n.bottom -= framesize; + break; + } + ViewFrame().FramePaint(w, n); + } + else + FrameCtrl::FramePaint(w, r); +} + +AlignedFrame& AlignedFrame::SetFrameSize(int sz, bool refresh) +{ + framesize = sz; + if (refresh) RefreshParentLayout(); + return *this; +} + +void AlignedFrame::Fix(Size& sz) +{ + if(IsVert()) + Swap(sz.cx, sz.cy); +} + +void AlignedFrame::Fix(Point& p) +{ + if(IsVert()) + Swap(p.x, p.y); +} + +Size AlignedFrame::Fixed(const Size& sz) +{ + return IsVert() ? Size(sz.cy, sz.cx) : Size(sz.cx, sz.cy); +} + +Point AlignedFrame::Fixed(const Point& p) +{ + return IsVert() ? Point(p.y, p.x) : Point(p.x, p.y); +} + +// TabScrollBar +TabScrollBar::TabScrollBar() +{ + Clear(); +} + +void TabScrollBar::Clear() +{ + total = 0; + pos = 0; + ps = 0; + start_pos = 0; + new_pos = 0; + old_pos = 0; + sz.Clear(); + ready = false; +} + +void TabScrollBar::UpdatePos(bool update) +{ + sz = GetSize(); + Fix(sz); + if(total <= 0 || sz.cx <= 0) + cs = ics = 0; + else + { + cs = sz.cx / ((double) total + 0.5); + ics = total / ((double) sz.cx); + } + size = sz.cx * cs; + if(update) + pos = new_pos - start_pos; + if(pos < 0) + pos = 0; + else if(pos + size > sz.cx) + pos = sz.cx - size; + + ps = total > sz.cx ? pos * ics : 0; +} + +void TabScrollBar::Paint(Draw &w) +{ + if(!ready) + { + UpdatePos(); + ready = true; + } + Size rsz = GetSize(); + #ifdef TABBAR_DEBUG + w.DrawRect(rsz, Red); + #else + w.DrawRect(rsz, White); + #endif + Point p; + + if(total > sz.cx) { + p = Point(ffloor(pos), 1); + rsz = Size(fceil(size), 2); + } + else { + p = Point(0, 1); + rsz = Size(sz.cx, 2); + } + Fix(p); + Fix(rsz); + w.DrawRect(p.x, p.y, rsz.cx, rsz.cy, Blue); +} + +void TabScrollBar::Layout() +{ + UpdatePos(false); +} + +void TabScrollBar::LeftDown(Point p, dword keyflags) +{ + SetCapture(); + Fix(p); + old_pos = new_pos = p.x; + if(p.x < pos || p.x > pos + size) + start_pos = size / 2; + else + start_pos = tabs(p.x - pos); + UpdatePos(); + UpdateActionRefresh(); +} + +void TabScrollBar::LeftUp(Point p, dword keyflags) +{ + ReleaseCapture(); + Fix(p); + old_pos = p.x; +} + +void TabScrollBar::MouseMove(Point p, dword keyflags) +{ + if(!HasCapture()) + return; + + Fix(p); + new_pos = p.x; + UpdatePos(); + UpdateActionRefresh(); +} + +void TabScrollBar::MouseWheel(Point p, int zdelta, dword keyflags) +{ + AddPos(-zdelta / 4, true); + UpdateActionRefresh(); +} + +int TabScrollBar::GetPos() const +{ + return ffloor(ps); +} + +void TabScrollBar::SetPos(int p, bool dontscale) +{ + pos = total > 0 ? dontscale ? p : iscale(p, sz.cx, total) : 0; + UpdatePos(false); + Refresh(); +} + +void TabScrollBar::AddPos(int p, bool dontscale) +{ + pos += total > 0 ? dontscale ? p : iscale(p, sz.cx, total) : 0; + UpdatePos(false); + Refresh(); +} + +int TabScrollBar::GetTotal() const +{ + return total; +} + +void TabScrollBar::SetTotal(int t) +{ + bool upd = total < t; + total = t; + UpdatePos(upd); + Refresh(); +} + +void TabScrollBar::AddTotal(int t) +{ + total += t; + UpdatePos(); + Refresh(); +} + +void TabScrollBar::GoEnd() +{ + pos = total; + UpdatePos(false); + Refresh(); +} + +void TabScrollBar::GoBegin() +{ + pos = 0; + UpdatePos(false); + Refresh(); +} + +void TabScrollBar::Set(const TabScrollBar& t) +{ + total = t.total; + pos = t.pos; + ps = t.ps; + Refresh(); +} + +bool TabScrollBar::IsScrollable() const +{ + // Note: sz already 'fixed' + return total > sz.cx && sz.cx > 0; +} + +// TabBar +TabBar::Style TabBar::leftstyle; +TabBar::Style TabBar::rightstyle; +TabBar::Style TabBar::bottomstyle; + +TabBar::TabBar() +{ + Clear(); + display = NULL; + crosses = true; + grouping = true; + isctrl = false; + isdrag = false; + inactivedisabled = false; + autoscrollhide = true; + stacking = true; + groupsort = true; + neverempty = 1; + + style[0] = style[1] = style[2] = style[3] = NULL; + SetAlign(TOP); + SetFrameSize(GetHeight()); + BackPaint(); +} + +void TabBar::CloseAll() +{ + for(int i = tabs.GetCount() - 1; i >= 0; i--) + if(i != active) + tabs.Remove(i); + + SyncScrollBar(); + MakeGroups(); + Repos(); + SetCursor(0); + WhenCloseAll(); +} + +int TabBar::GetNextId() +{ + return ++id; +} + +void TabBar::ContextMenu(Bar& bar) +{ + if (highlight >= 0) { + bar.Add(tabs.GetCount() > 1, "Close", THISBACK1(Close, highlight)); + bar.Separator(); + } + int cnt = groups.GetCount(); + for(int i = 0; i < cnt; i++) + { + String name = Format("%s (%d)", groups[i].name, groups[i].count); + Bar::Item &it = i > 0 ? bar.Add(name, THISBACK1(GroupMenu, i)) + : bar.Add(name, THISBACK1(DoGrouping, i)); + if(i == group) + it.Image(TabBarImg::CHK); + if(i == 0 && cnt > 1) + bar.Separator(); + } + bar.Separator(); + + bar.Add("Close others", THISBACK(CloseAll)); +} + +void TabBar::GroupMenu(Bar &bar, int n) +{ + bar.Add("Set active", THISBACK1(DoGrouping, n)); + bar.Add("Close", THISBACK1(DoCloseGroup, n)); +} + +bool TabBar::Tab::HasMouse(const Point& p) const +{ + return visible && p.x >= real_pos.x && p.x < real_pos.x + real_size.cx && + p.y >= real_pos.y && p.y < real_pos.y + real_size.cy; +} + +bool TabBar::Tab::HasMouseCross(const Point& p) const +{ + if(!visible) + return false; + + return p.x >= cross_pos.x && p.x < cross_pos.x + cross_size.cx && + p.y >= cross_pos.y && p.y < cross_pos.y + cross_size.cy; +} + +int TabBar::FindGroup(const String& g) const +{ + for(int i = 0; i < groups.GetCount(); i++) + if(groups[i].name == g) + return i; + return -1; +} + +void TabBar::DoStacking() +{ + Value v = GetData(); + for (int i = 0; i < tabs.GetCount(); i++) { + Tab &base = tabs[i]; + for (int j = i+1; j < tabs.GetCount(); j++) { + Tab &t = tabs[j]; + if ((!grouping || base.group == t.group) && stackfunc(base.data, t.data)) { + base.stack.AddTail(t.data); + tabs.Remove(j); + j--; + } + } + } + highlight = -1; + MakeGroups(); + Repos(); + int c = active; + SetData(v); + if (active < 0 || c != active) + Refresh(); +} + +void TabBar::DoUnstacking() +{ + for (int i = 0; i < tabs.GetCount(); i++) { + for (int j = tabs[i].stack.GetCount()-1; j >= 0; j--) { + Tab &t = tabs.Insert(i+1); + t.id = GetNextId(); + t.data = tabs[i].stack[j]; + t.group = tabs[i].group; + } + tabs[i].stack.Clear(); + } + highlight = -1; + MakeGroups(); + Repos(); + if (HasCursor()) + SetCursor(-1); + else + Refresh(); +} + +void TabBar::StackRemove(BiVector &stack, int ix) +{ + int cnt = stack.GetCount() >> 1; + if (ix <= cnt) { + int i = ix-1; + while (i >= 0) { + Swap(stack[i], stack[ix]); + ix = i; + i--; + } + stack.DropHead(); + } + else { + int i = ix+1; + while (i < stack.GetCount()) { + Swap(stack[i], stack[ix]); + ix = i; + i++; + } + stack.DropTail(); + } +} + +void TabBar::MakeGroups() +{ + groups[0].count = tabs.GetCount(); + groups[0].first = 0; + groups[0].last = tabs.GetCount() - 1; + + if (groupsort) + Sort(tabs, TabGroupSort()); + + for(int i = 1; i < groups.GetCount(); i++) + { + groups[i].count = 0; + groups[i].first = 10000000; + groups[i].last = 0; + } + + for(int i = 0; i < tabs.GetCount(); i++) + { + Tab &tab = tabs[i]; + int n = FindGroup(tab.group); + ASSERT(n >= 0); + if (n > 0) { + if(groups[n].active < 0) + groups[n].active = tab.id; + groups[n].count++; + groups[n].last = i; + + if(i < groups[n].first) + groups[n].first = i; + if(i > groups[n].last) + groups[n].last = i; + } + } + + int removed = 0; + for(int i = 1; i < groups.GetCount(); i++) + if(groups[i].count == 0) + { + groups.Remove(i - removed); + removed++; + } + if(group > groups.GetCount() - 1 && group > 0) + group--; +} + +void TabBar::DoGrouping(int n) +{ + group = n; + Repos(); + SyncScrollBar(); + SetCursor(-1); +} + +void TabBar::DoCloseGroup(int n) +{ + int cnt = groups.GetCount(); + if(cnt <= 0) + return; + if (cnt == n) + --group; + + String group = groups[n].name; + + for(int i = tabs.GetCount() - 1; i >= 0; i--) + { + if(group == tabs[i].group && tabs.GetCount() > 1) { + Value v = tabs[i].data; + tabs.Remove(i); + WhenClose(v); + } + } + if(cnt > 1) + groups.Remove(n); + MakeGroups(); + Repos(); + SetCursor(-1); +} + +void TabBar::NewGroup(const String &name, const Value &data) +{ + Group &g = groups.Add(); + g.name = name; + g.data = data; + g.count = 0; + g.first = 10000000; + g.last = 0; + g.active = -1; +} + +Value TabBar::AlignValue(int align, const Value &v, const Size &isz) +{ + if (align == TOP) return v; + if (IsTypeRaw(v)) { + switch(align) { + case AlignedFrame::LEFT: return RotateAntiClockwise((Image)v); + case AlignedFrame::RIGHT: return RotateClockwise((Image)v); + case AlignedFrame::BOTTOM: return MirrorVert((Image)v); + } + } + else if (!IsTypeRaw(v)) { + ImageDraw w(isz.cx, isz.cy); + w.DrawRect(isz, SColorFace()); + ChPaint(w, isz, v); + ImageBuffer img; + Image temp = (Image)w; + switch(align) { + case AlignedFrame::LEFT: + temp = RotateAntiClockwise(temp); + img = temp; // GCC + img.SetHotSpot(Point(1, 5)); + img.Set2ndSpot(Point(isz.cy / 2, isz.cx / 2)); + break; + case AlignedFrame::RIGHT: + temp = RotateClockwise(temp); + img = temp; + img.SetHotSpot(Point(isz.cy - 10, isz.cx - 10)); + img.Set2ndSpot(Point(isz.cy / 2, isz.cx / 2)); + break; + case AlignedFrame::BOTTOM: + temp = MirrorVert(temp); + img = temp; + img.SetHotSpot(Point(10, 10)); + img.Set2ndSpot(Point(isz.cx / 2, isz.cy / 2)); + break; + + } + return (Image)img; + } + return v; +} + +WString TabBar::ParseLabel(const WString& s) +{ + return s; +} + +void TabBar::PaintTabData(Draw& w, const Rect& r, const Tab& tab, const Font &font, Color ink, dword style) +{ + WString txt; + Font f = font; + Color i = ink; + const Value &q = tab.data; + + if(IsType(q)) { + const AttrText& t = ValueTo(q); + txt = t.text; + if(!IsNull(t.font)) + f = t.font; + i = IsNull(t.ink) ? ink : t.ink; + } + else + txt = IsString(q) ? q : StdConvert().Format(q); + + Point p = GetTextPosition(r, GetTextSize(txt, font).cy, TB_MARGIN); + w.DrawText(p.x, p.y, GetTextAngle(), ParseLabel(txt), f, i); +} + +Point TabBar::GetTextPosition(const Rect& r, int cy, int space) const +{ + Point p; + int align = GetAlign(); + + if(align == LEFT) + { + p.y = r.bottom - space; + p.x = r.left + (r.GetWidth() - cy) / 2; + } + else if(align == RIGHT) + { + p.y = r.top + space; + p.x = r.right - (r.GetWidth() - cy) / 2; + } + else + { + p.x = r.left + space; + p.y = r.top + (r.GetHeight() - cy) / 2; + } + return p; +} + +Point TabBar::GetImagePosition(const Rect& r, int cx, int cy, int space, int side) const +{ + Point p; + int align = GetAlign(); + + if (align == LEFT) + { + p.x = r.left + (r.GetWidth() - cy) / 2; + p.y = side == LEFT ? r.bottom - space - cx : r.top + space; + } + else if (align == RIGHT) + { + p.x = r.right - (r.GetWidth() + cy) / 2; + p.y = side == LEFT ? r.top + space : r.bottom - space - cx; + } + else if (align == TOP) + { + p.x = side == LEFT ? r.left + space : r.right - cx - space; + p.y = r.top + (r.GetHeight() - cy) / 2; + } + else if (align == BOTTOM) + { + p.x = side == LEFT ? r.left + space : r.right - cx - space; + p.y = r.bottom - (r.GetHeight() + cy) / 2; + } + return p; +} + +void TabBar::PaintTab(Draw &w, const Style &s, const Size &sz, int n, bool enable, bool dragsample) +{ + TabBar::Tab &t = tabs[n]; + int cnt = dragsample ? 1 : tabs.GetCount(); + int sep = TB_SBSEPARATOR * sc.IsVisible(); + + Size tsz; + Point p; + + int align = GetAlign(); + bool ac = n == active; + bool hl = n == highlight; + + int ndx = !enable ? CTRL_DISABLED : + ac ? CTRL_PRESSED : + hl ? CTRL_HOT : CTRL_NORMAL; + + int c = align == LEFT ? cnt - n : n; + const Value& sv = (cnt == 1 ? s.both : c == 0 ? s.first : c == cnt - 1 ? s.last : s.normal)[ndx]; + + int lx = n > 0 ? s.extendleft : 0; + int x = t.pos.x - sc.GetPos() + s.margin - lx; + + p = Point(x - s.sel.left, 0); + tsz = Size(t.size.cx + lx + s.sel.right + s.sel.left, t.size.cy + s.sel.bottom); + + if (align == BOTTOM || align == RIGHT) + p.y -= s.sel.bottom - sep; + + Rect ra(Fixed(p), Fixed(tsz)); + + p = Point(x, s.sel.top); + tsz = Size(t.size.cx + lx, t.size.cy - s.sel.top); + + int dy = -s.sel.top * ac; + + if (align == BOTTOM || align == RIGHT) + { + p.y -= s.sel.top - sep; + dy = -dy; + } + + Rect rn(Fixed(p), Fixed(tsz)); + + t.real_pos = (ac ? ra : rn).TopLeft(); + t.real_size = (ac ? ra : rn).GetSize(); + + ChPaint(w, Rect(t.real_pos, t.real_size), sv); + + rn = Rect(Fixed(Point(p.x, p.y + dy)), Fixed(tsz)); + + #ifdef TABBAR_DEBUG + DrawFrame(w, rn, Green); + #endif + + if(crosses && (cnt > neverempty || t.stack.GetCount())) { + + Size isz = TabBarImg::CR0().GetSize(); + Point p = GetImagePosition(rn, isz.cx, isz.cy, TB_MARGIN, RIGHT); + + t.cross_pos = p; + t.cross_size = isz; + w.DrawImage(p.x, p.y, (ac || hl) ? (cross == n ? TabBarImg::CR2 : ac ? TabBarImg::CR1 : TabBarImg::CR0) : TabBarImg::CR0); + } + + if (display) + display->Paint(w, rn, t.data, s.text_color[ndx], SColorDisabled(), ndx); + else + PaintTabData(w, rn, t, s.font, s.text_color[ndx], ndx); +} + +void TabBar::Paint(Draw &w) +{ + int align = GetAlign(); + const Style &st = *style[align]; + Size sz = GetSize(); + + #ifdef TABBAR_DEBUG + w.DrawRect(sz, Yellow); + #else + w.DrawRect(sz, SColorFace()); + #endif + + if(sc.IsShown()) + { + IsVert() ? + w.DrawRect(align == LEFT ? sz.cx - 1 : 0, 0, 1, sz.cy, Color(128, 128, 128)): + w.DrawRect(0, align == TOP ? sz.cy - 1 : 0, sz.cx, 1, Color(128, 128, 128)); + } + + if (!tabs.GetCount()) return; + + int limt = sc.GetPos() + (IsVert() ? sz.cy : sz.cx); + + int first = 0; + int last = tabs.GetCount()-1; + // Find first visible tab + for(int i = 0; i < tabs.GetCount(); i++) { + Tab &tab = tabs[i]; + if (tab.pos.x + tab.size.cx > sc.GetPos()) { + first = i; + break; + } + } + // Find last visible tab + for(int i = first + 1; i < tabs.GetCount(); i++) { + if (tabs[i].visible && tabs[i].pos.x > limt) { + last = i; + break; + } + } + // Draw active group + for (int i = first; i <= last; i++) { + if(tabs[i].visible && i != active) + PaintTab(w, st, sz, i, IsEnabled()); + } + // Clear real_size for non-visible tabs to prevent mouse handling bugs + for (int i = 0; i < first; i++) + tabs[i].real_size = Size(0, 0); + for (int i = last+1; i < tabs.GetCount(); i++) + tabs[i].real_size = Size(0, 0); + // Draw inactive groups + if (inactivedisabled) + for (int i = first; i <= last; i++) { + if(!tabs[i].visible && i != active) + PaintTab(w, st, sz, i, !IsEnabled()); + } + + // Draw selected tab + if(active >= first && active <= last) + PaintTab(w, st, sz, active, true); + // Draw drag highlights + if(target >= 0) + { + // Draw target marker + int drag = isctrl ? highlight : active; + if(target != drag && target != drag + 1) + { + last = GetLast(); + first = GetFirst(); + int x = (target == last + 1 ? tabs[last].Right() : tabs[target].pos.x) + - sc.GetPos() - (target <= first ? 1 : 2) + + st.margin - (target > 0 ? st.extendleft : 0); + int y = st.sel.top; + int cy = sz.cy - y; + if (IsHorz()) { + w.DrawRect(x + 1, y, 2, cy, SRed()); + w.DrawRect(x, y, 4, 1, SRed()); + w.DrawRect(x, y + cy - 1, 4, 1, SRed()); + } + else{ + w.DrawRect(y, x + 1, cy, 2, SRed()); + w.DrawRect(y, x, 1, 4, SRed()); + w.DrawRect(y + cy - 1, x, 1, 4, SRed()); + } + } + // Draw transparent drag image + Point mouse = GetMousePos() - GetScreenRect().TopLeft(); + Size isz = dragtab.GetSize(); + if (IsHorz()) + w.DrawImage(mouse.x - isz.cx/2, 0, isz.cx, isz.cy, dragtab); + else + w.DrawImage(0, mouse.y - isz.cy/2, isz.cx, isz.cy, dragtab); + } +} + +Image TabBar::GetDragSample() +{ + return GetDragSample(highlight); +} + +Image TabBar::GetDragSample(int n) +{ + if (n < 0) return Image(); + Tab &tab = tabs[n]; + const Style& st = *style[GetAlign()]; + + Size tsz(tab.real_size); + ImageDraw iw(tsz); + iw.DrawRect(tsz, SColorFace()); //this need to be fixed - if inactive tab is dragged gray edges are visible + + Point temp = tab.pos; + tab.pos.x = sc.GetPos(); + tab.pos.y = 0; + PaintTab(iw, st, GetSize(), n, true, true); + tab.pos.x = temp.x; + tab.pos.y = temp.y; + + Image img = iw; + ImageBuffer ib(img); + Unmultiply(ib); + RGBA *s = ~ib; + RGBA *e = s + ib.GetLength(); + while(s < e) { + s->a = 180; + s++; + } + Premultiply(ib); + return ib; +} + +void TabBar::Scroll() +{ + Refresh(); +} + +int TabBar::GetWidth(int n) +{ + Tab &t = tabs[n]; + Size tsz = GetStdSize(t); + return TB_MARGIN * 2 + tsz.cx + (TB_SPACE + TabBarImg::CR0().GetSize().cx) * crosses; +} + +Size TabBar::GetStdSize(const Value &q) +{ + if (display) + return display->GetStdSize(q); + else if (q.GetType() == STRING_V || q.GetType() == WSTRING_V) + return GetTextSize(ParseLabel(WString(q)), StdFont()); + else + return GetTextSize("A Tab", StdFont()); +} + +Size TabBar::GetStdSize(const Tab &t) +{ + return GetStdSize(t.data); +} + +TabBar& TabBar::Add(const Value &data, String group, bool make_active) +{ + return Insert(tabs.GetCount(), data, group, make_active); +} + +TabBar& TabBar::Insert(int ix, const Value &data, String group, bool make_active) +{ + ASSERT(ix >= 0); + int g = 0; + if (!group.IsEmpty()) { + g = FindGroup(group); + if (g < 0) { + NewGroup(group); + g = groups.GetCount() - 1; + } + } + group = groups[g].name; + bool stacked = false; + if (stacking) { + for (int i = 0; i < tabs.GetCount(); i++) { + Tab &t = tabs[i]; + if (t.group == group && stackfunc(t.data, data)) { + if (make_active) { + t.stack.AddHead(t.data); + t.data = data; + } + else + t.stack.AddTail(data); + stacked = true; + } + } + } + if (!stacked) { + Tab &t = tabs.Insert(ix); + t.data = data; + t.id = GetNextId(); + t.group = group; + + MakeGroups(); + } + Repos(); + active = -1; + if (make_active) + SetCursor(minmax(ix, 0, tabs.GetCount() - 1)); + return *this; +} +int TabBar::GetWidth() const +{ + if (!tabs.GetCount()) return 0; + return tabs[GetLast()].Right() + style[GetAlign()]->margin * 2; +} + +int TabBar::GetHeight(bool scrollbar) const +{ + return TabBar::GetStyleHeight(*style[GetAlign()]) + TB_SBSEPARATOR * int(scrollbar); +} + +int TabBar::GetStyleHeight(const Style &s) +{ + return s.tabheight + s.sel.top; +} + +void TabBar::Repos() +{ + if(!tabs.GetCount()) + return; + + String g = GetGroupName(); + + int j; + bool first = true; + j = 0; + for(int i = 0; i < tabs.GetCount(); i++) + j = TabPos(g, first, i, j, false); + if (inactivedisabled) + for(int i = 0; i < tabs.GetCount(); i++) + if (!tabs[i].visible) + j = TabPos(g, first, i, j, true); + SyncScrollBar(); +} + +int TabBar::TabPos(const String &g, bool &first, int i, int j, bool inactive) +{ + bool v = IsNull(g) ? true : g == tabs[i].group; + if(v) + { + tabs[i].pos.x = first ? 0 : tabs[j].Right(); + /* Separators + if (showseps && !first && tabs[i].group != tabs[j].group) { + seperators.Add(tabs[i].pos.x); + tabs[i].pos.x += TB_SEPARATOR; + } */ + j = i; + first = false; + } + else { + tabs[i].pos.x = 0; + if (inactive) { + tabs[i].pos.x = tabs[j].Right(); + return (j = i); + } + } + + tabs[i].visible = v; + tabs[i].pos.y = 0; + tabs[i].size.cx = GetWidth(i); + tabs[i].size.cy = GetStyleHeight(*style[1]); + + return j; +} + +void TabBar::SyncScrollBar(bool synctotal) +{ + if (synctotal) + sc.SetTotal(GetWidth()); + if (autoscrollhide) { + bool v = sc.IsScrollable(); + if (sc.IsShown() != v) { + SetFrameSize((v ? sc.GetFrameSize() : 0) + GetHeight(v), false); + sc.Show(v); + PostCallback(THISBACK(RefreshParentLayout)); + } + } + else { + SetFrameSize(sc.GetFrameSize() + GetHeight(true), false); + sc.Show(); + } +} + +int TabBar::FindId(int id) const +{ + for(int i = 0; i < tabs.GetCount(); i++) + if(tabs[i].id == id) + return i; + return -1; +} + +int TabBar::GetNext(int n) const +{ + for(int i = n + 1; i < tabs.GetCount(); i++) + if(tabs[i].visible) + return i; + return -1; +} + +int TabBar::GetPrev(int n) const +{ + for(int i = n - 1; i >= 0; i--) + if(tabs[i].visible) + return i; + return -1; +} + +void TabBar::Clear() +{ + highlight = -1; + active = -1; + target = -1; + id = -1; + tabs.Clear(); + groups.Clear(); + NewGroup("All"); + group = 0; + Refresh(); +} + +TabBar& TabBar::Crosses(bool b) +{ + crosses = b; + Repos(); + return *this; +} + +TabBar& TabBar::Grouping(bool b) +{ + grouping = b; + return *this; +} + +TabBar& TabBar::GroupSort(bool b) +{ + groupsort = b; + if (b) + MakeGroups(); + return *this; +} +/* Separators +TabBar& TabBar::Seperators(bool b) +{ + showseps = b; + Repos(); + return *this; +} +*/ +TabBar& TabBar::AutoScrollHide(bool b) +{ + autoscrollhide = b; + sc.Hide(); + SetFrameSize(GetHeight(), false); + SyncScrollBar(GetWidth()); + return *this; +} + +TabBar& TabBar::InactiveDisabled(bool b) +{ + inactivedisabled = b; + if (b) Repos(); + return *this; +} + +void TabBar::FrameSet() +{ + int al = GetAlign(); + Ctrl::ClearFrames(); + sc.Clear(); + sc.SetFrameSize(TB_SBHEIGHT).SetAlign((al >= 2) ? al - 2 : al + 2); + sc <<= THISBACK(Scroll); + sc.Hide(); + if (!sc.IsChild()) + AddFrame(sc); + + style[0] = &StyleLeft(); + style[1] = &StyleDefault(); + style[2] = &StyleRight(); + style[3] = &StyleBottom(); + + SyncScrollBar(GetWidth()); +} + +void TabBar::ResetStyles() +{ + StyleLeft(); + StyleRight(); + StyleBottom(); +} + +void TabBar::FrameLayout(Rect& r) +{ + AlignedFrame::FrameLayout(r); +} + +void TabBar::Layout() +{ + if (autoscrollhide && tabs.GetCount()) + SyncScrollBar(false); +} + +int TabBar::Find(const Value &v) const +{ + for (int i = 0; i < tabs.GetCount(); i++) + if (tabs[i].data == v) + return i; + return -1; +} + +int TabBar::FindInStack(const Value &v, int &stackix) const +{ + stackix = -1; + for (int i = 0; i < tabs.GetCount(); i++) { + if (tabs[i].data == v) + return i; + for (int j = 0; j < tabs[i].stack.GetCount(); j++) + if (tabs[i].stack[j] == v) { + stackix = j; + return i; + } + } + return -1; +} + +void TabBar::CycleTabStack(int n) +{ + if (tabs[n].stack.GetCount()) { + Tab &t = tabs[n]; + Value v = t.data; + t.data = t.stack.Head(); + t.stack.DropHead(); + t.stack.AddTail(v); + } +} + +void TabBar::SetData(const Value &data) +{ + int stackix = -1; + int n = FindInStack(data, stackix); + if (n >= 0) { + if (stackix >= 0) { + Tab &t = tabs[n]; + Value v = t.stack[stackix]; + StackRemove(t.stack, stackix); + t.stack.AddTail(t.data); + t.data = v; + } + SetCursor(n); + } +} + +void TabBar::Set(int n, const Value &data, const String &group) +{ + ASSERT(n >= 0 && n < tabs.GetCount()); + tabs[n].data = data; + if (!IsNull(data)) + SetTabGroup(n, group); + else + Repos(); +} + +void TabBar::LeftDown(Point p, dword keyflags) +{ + if(keyflags & K_SHIFT) + { + highlight = -1; + Refresh(); + SetCapture(); + Fix(p); + oldp = p; + return; + } + + isctrl = keyflags & K_CTRL; + if(isctrl) + return; + + if(cross != -1) { + Value v = tabs[cross].data; + Close(cross); + WhenClose(v); + } + else if(highlight >= 0) { + if (highlight == active) { + CycleTabStack(active); + Repos(); + UpdateActionRefresh(); + } + else + SetCursor(highlight); + } +} + +void TabBar::LeftUp(Point p, dword keyflags) +{ + ReleaseCapture(); +} + +void TabBar::LeftDouble(Point p, dword keysflags) +{ + WhenLeftDouble(); +} + +void TabBar::RightDown(Point p, dword keyflags) +{ + MenuBar::Execute(THISBACK(ContextMenu), GetMousePos()); +} + +void TabBar::MiddleDown(Point p, dword keyflags) +{ + Close(highlight); +} + +void TabBar::MiddleUp(Point p, dword keyflags) +{ +} + +int TabBar::GetTargetTab(Point p) +{ + p.x += sc.GetPos(); + + int f = GetFirst(); + int l = GetLast(); + + if(tabs[f].visible && p.x < tabs[f].pos.x + tabs[f].size.cx / 2) + return f; + + for(int i = l; i >= f; i--) + if(tabs[i].visible && p.x >= tabs[i].pos.x + tabs[i].size.cx / 2) + return i == l ? i + 1 : GetNext(i); +// if(tabs[i].visible && p.x >= tabs[i].x && p.x <= tabs[i].x + tabs[i].cx) +// return i; + return -1; +} + +void TabBar::MouseWheel(Point p, int zdelta, dword keyflags) +{ + sc.AddPos(-zdelta / 4, true); + Scroll(); + MouseMove(p, 0); +} + +bool TabBar::ProcessMouse(int i, const Point& p) +{ + if(i >= 0 && tabs[i].HasMouse(p)) + { + bool iscross = crosses ? tabs[i].HasMouseCross(p) : false; + if(highlight != i || (iscross && cross != i || !iscross && cross == i)) + { + cross = iscross ? i : -1; + highlight = i; + WhenHighlight(); + Refresh(); + } + return true; + } + + return false; +} + +void TabBar::MouseMove(Point p, dword keyflags) +{ + if(HasCapture()) + { + Fix(p); + sc.AddPos(p.x - oldp.x, true); + oldp = p; + Refresh(); + return; + } + + if(ProcessMouse(active, p)) + return; + + for(int i = 0; i < tabs.GetCount(); i++) + { + if(i == active) + continue; + + if(ProcessMouse(i, p)) + return; + } + + if(highlight >= 0 || cross >= 0) + { + highlight = cross = -1; + WhenHighlight(); + Refresh(); + } +} + +void TabBar::MouseLeave() +{ + if(isdrag) + return; + highlight = cross = -1; + WhenHighlight(); + Refresh(); +} + +void TabBar::DragAndDrop(Point p, PasteClip& d) +{ + Fix(p); + int c = GetTargetTab(p); + int tab = isctrl ? highlight : active; + + if (&GetInternal(d) != this) return; + + bool sametab = c == tab || c == tab + 1; + bool internal = AcceptInternal(d, "tabs"); + + if(!sametab && d.IsAccepted()) + { + if(internal) + { + int id = tabs[active].id; + Tab t = tabs[tab]; + Tab &n = tabs.Insert(c); + n = t; + tabs.Remove(tab + int(c < tab)); + active = FindId(id); + isdrag = false; + MakeGroups(); + Repos(); + return; + } + else if(d.IsPaste()) + { + CancelMode(); + return; + } + } + else + { + //d.Reject(); + //unfortunately after Reject DragLeave stops working until d is accepted + } + target = c; + Refresh(); +} + +void TabBar::CancelMode() +{ + isdrag = false; + target = -1; + Refresh(); +} + +void TabBar::LeftDrag(Point p, dword keyflags) +{ + if(keyflags & K_SHIFT) + return; + if(highlight < 0) + return; + + isdrag = true; + dragtab = GetDragSample(); + DoDragAndDrop(InternalClip(*this, "tabs")); +} + +void TabBar::DragEnter() +{ +} + +void TabBar::DragLeave() +{ + target = -1; + Refresh(); +} + +void TabBar::DragRepeat(Point p) +{ + if(target >= 0) + { + Point dx = GetDragScroll(this, p, 16); + Fix(dx); + if(dx.x != 0) + sc.AddPos(dx.x); + } +} + +void TabBar::SetCursor(int n) +{ + if(tabs.GetCount() == 0) + return; + + if(n < 0) + { + n = max(0, FindId(GetGroupActive())); + active = -1; + } + + bool is_all = IsGroupAll(); + bool same_group = tabs[n].group == GetGroupName(); + + if((same_group || is_all) && active == n) + return; + + active = n; + + if(!is_all && !same_group) + { + SetGroup(tabs[n].group); + Repos(); + } + + SetGroupActive(tabs[n].id); + + int cx = tabs[n].pos.x - sc.GetPos(); + if(cx < 0) + sc.AddPos(cx - 10); + else + { + Size sz = Ctrl::GetSize(); + Fix(sz); + cx = tabs[n].pos.x + tabs[n].size.cx - sz.cx - sc.GetPos(); + if(cx > 0) + sc.AddPos(cx + 10); + } + + Refresh(); + + if(Ctrl::HasMouse()) + { + Sync(); + MouseMove(GetMouseViewPos(), 0); + } + + UpdateAction(); +} + +void TabBar::SetTabGroup(int n, const String &group) +{ + ASSERT(n >= 0 && n < tabs.GetCount()); + int g = FindGroup(group); + if (g <= 0) + NewGroup(group); + else if (groups[g].active == tabs[n].id) + SetGroupActive(tabs[n].id); + tabs[n].group = group; + MakeGroups(); + Repos(); +} + +TabBar & TabBar::StackingFunc(Gate2 func) +{ + if (stacking) + DoUnstacking(); + + stackfunc = func; + DoStacking(); + stacking = true; + return *this; +} + +TabBar & TabBar::NoStacking() +{ + if (stacking) { + stacking = false; + DoUnstacking(); + } + return *this; +} + +void TabBar::Close(int n) +{ + if (stacking && tabs[n].stack.GetCount()) { + CycleTabStack(n); + tabs[n].stack.DropTail(); + Repos(); + SetCursor(-1); + return; + } + + if(tabs.GetCount() <= neverempty) + return; + + if(n == active) + { + int c = FindId(tabs[n].id); + int nc = GetNext(c); + if(nc < 0) + nc = max(0, GetPrev(c)); + SetGroupActive(tabs[nc].id); + } + sc.AddTotal(-tabs[n].size.cx); + tabs.Remove(n); + MakeGroups(); + Repos(); + SetCursor(-1); +} + +void TabBar::CloseData(const Value &data) +{ + int stackix = -1; + int tabix = FindInStack(data, stackix); + if (tabix < 0) return; + + Tab &t = tabs[tabix]; + if (!stacking || t.stack.GetCount() == 0) return Close(tabix); + + if (stackix) + StackRemove(t.stack, stackix); + else { + CycleTabStack(tabix); + t.stack.DropTail(); + } + Repos(); +} + +const TabBar::Style& TabBar::AlignStyle(int align, Style &s) +{ + Size sz(30, GetStyleHeight(s)); + for (int i = 0; i < 4; i++) s.first[i] = AlignValue(align, s.first[i], sz); + for (int i = 0; i < 4; i++) s.last[i] = AlignValue(align, s.last[i], sz); + for (int i = 0; i < 4; i++) s.normal[i] = AlignValue(align, s.normal[i], sz); + for (int i = 0; i < 4; i++) s.both[i] = AlignValue(align, s.both[i], sz); + return s; +} + +CH_STYLE(TabBar, Style, StyleDefault) +{ + Assign(TabCtrl::StyleDefault()); + TabBar::ResetStyles(); +} + +const TabBar::Style& TabBar::StyleLeft() +{ + leftstyle = StyleDefault(); + return AlignStyle(AlignedFrame::LEFT, leftstyle); +} + +const TabBar::Style& TabBar::StyleRight() +{ + rightstyle = StyleDefault(); + return AlignStyle(AlignedFrame::RIGHT, rightstyle); +} + +const TabBar::Style& TabBar::StyleBottom() +{ + bottomstyle = StyleDefault(); + return AlignStyle(AlignedFrame::BOTTOM, bottomstyle); +} + +void TabBar::Serialize(Stream& s) +{ + // Note: doens't work with stacking + int version = 0x00; + int cnt; + if (s.IsLoading()) Clear(); + + s / version / group / highlight / active; + + if (s.IsLoading()) { + cnt = groups.GetCount(); + s / cnt; + for (int i = 1; i < groups.GetCount(); i++) { + Group &g = groups[i]; + s % g.data / g.active; + } + cnt = tabs.GetCount(); + s / cnt; + for (int i = 0; i < tabs.GetCount(); i++) { + Tab &t = tabs[i]; + int g = FindGroup(t.group); + s % t.data / t.id / g; + } + } + else { + s / cnt; + groups.SetCount(cnt); + for (int i = 1; i < cnt; i++) { + Group &g = groups[i]; + s % g.data / g.active; + } + s / cnt; + tabs.SetCount(cnt); + for (int i = 0; i < tabs.GetCount(); i++) { + int g; + Tab &t = tabs[i]; + s % t.data / t.id / g; + t.group = groups[g].name; + } + MakeGroups(); + Repos(); + } +} diff --git a/bazaar/TabBar/TabBar.h b/bazaar/TabBar/TabBar.h index 794d822e3..7934cc358 100644 --- a/bazaar/TabBar/TabBar.h +++ b/bazaar/TabBar/TabBar.h @@ -1,343 +1,344 @@ -#ifndef _TabBar_TabBar_h_ -#define _TabBar_TabBar_h_ - -#include -using namespace Upp; - -#define IMAGECLASS TabBarImg -#define IMAGEFILE -#include - -//#define TABBAR_DEBUG - -struct AlignedFrame : FrameCtrl -{ - int layout; - int framesize; - int border; -public: - enum - { - LEFT = 0, - TOP = 1, - RIGHT = 2, - BOTTOM = 3 - }; - - AlignedFrame() : border(0), framesize(0), layout(TOP) {} - - virtual void FrameLayout(Rect &r); - virtual void FrameAddSize(Size& sz); - virtual void FramePaint(Draw& w, const Rect& r); - - bool IsVert() const { return (layout & 1) == 0; } - bool IsHorz() const { return layout & 1; } - bool IsTL() const { return layout < 2; } - bool IsBR() const { return layout >= 2; } - - AlignedFrame& SetAlign(int align) { layout = align; FrameSet(); RefreshParentLayout(); return *this; } - AlignedFrame& SetLeft() { return SetAlign(LEFT); } - AlignedFrame& SetTop() { return SetAlign(TOP); } - AlignedFrame& SetRight() { return SetAlign(RIGHT); } - AlignedFrame& SetBottom() { return SetAlign(BOTTOM); } - AlignedFrame& SetFrameSize(int sz, bool refresh = true); - - int GetAlign() const { return layout; } - int GetFrameSize() const { return framesize; } - int GetBorder() const { return border; } -protected: - void Fix(Size& sz); - void Fix(Point& p); - Size Fixed(const Size& sz); - Point Fixed(const Point& p); - - bool HasBorder() { return border >= 0; } - AlignedFrame& SetBorder(int _border) { border = _border; return *this; } - - virtual void FrameSet() { } -}; - -class TabScrollBar : public AlignedFrame -{ - private: - int total; - double pos, ps; - int new_pos; - int old_pos; - double start_pos; - double size; - double cs, ics; - virtual void UpdatePos(bool update = true); - void RefreshScroll(); - bool ready; - Size sz; - public: - TabScrollBar(); - - virtual void Paint(Draw &w); - virtual void LeftDown(Point p, dword keyflags); - virtual void LeftUp(Point p, dword keyflags); - virtual void MouseMove(Point p, dword keyflags); - virtual void MouseWheel(Point p, int zdelta, dword keyflags); - virtual void Layout(); - - int GetPos() const; - void SetPos(int p, bool dontscale = false); - void AddPos(int p, bool dontscale = false); - int GetTotal() const; - void AddTotal(int t); - void SetTotal(int t); - void GoEnd(); - void GoBegin(); - void Clear(); - void Set(const TabScrollBar& t); - bool IsScrollable() const; - Callback WhenScroll; -}; - -class TabBar : public AlignedFrame -{ -public: - struct Style : public TabCtrl::Style { }; - -protected: - enum - { - TB_MARGIN = 6, - TB_SPACE = 10, - TB_SBHEIGHT = 4, - TB_SBSEPARATOR = 1, - TB_FILEICON = 16, - TB_SPACEICON = 5 - }; - - struct Tab : Moveable - { - int id; - - Value data; - String group; - BiVector stack; - - bool visible; - - Point pos; - Size size; - - Point cross_pos; - Size cross_size; - - Point real_pos; - Size real_size; - - Tab() : visible(true), id(-1) - {} - int Right() const { return pos.x + size.cx; } - bool HasMouse(const Point& p) const; - bool HasMouseCross(const Point& p) const; - }; - - struct Group : Moveable - { - Group() {} - String name; - Value data; - int active; - int count; - int first; - int last; - }; -protected: - - TabScrollBar sc; - - Vector groups; - Vector tabs; - int active; - -private: - int id; - int highlight; - int target; - int cross; - bool crosses:1; - bool isctrl:1; - bool isdrag:1; - bool grouping:1; - bool autoscrollhide:1; - bool nosel:1; - bool nohl:1; - bool inactivedisabled:1; - bool stacking:1; - bool groupsort:1; - Gate2 stackfunc; - int neverempty; - Point mouse, oldp; - int group; - const Display *display; - Image dragtab; - - static Style leftstyle, rightstyle, bottomstyle; - const Style *style[4]; - - void PaintTab(Draw &w, const Style &s, const Size &sz, int i, bool enable, bool dragsample = false); - - int TabPos(const String &g, bool &first, int i, int j, bool inactive); - void SyncScrollBar(bool synctotal = true); - void Scroll(); - - int FindId(int id) const; - int GetNext(int n) const; - int GetPrev(int n) const; - - int GetWidth(int n); - int GetWidth() const; - int GetHeight(bool scrollbar = true) const; - - void DoStacking(); - void DoUnstacking(); - void StackRemove(BiVector &stack, int ix); - int FindInStack(const Value &data, int &stackix) const; - void CycleTabStack(int n); - - static int GetStyleHeight(const Style& s); - - int GetNextId(); - int GetScrollPos() { return sc.GetPos(); } - - static Value AlignValue(int align, const Value &v, const Size &isz); -protected: - virtual void Paint(Draw &w); - virtual void LeftDown(Point p, dword keysflags); - virtual void LeftUp(Point p, dword keysflags); - virtual void LeftDouble(Point p, dword keysflags); - virtual void RightDown(Point p, dword keyflags); - virtual void MiddleDown(Point p, dword keyflags); - virtual void MiddleUp(Point p, dword keyflags); - virtual void MouseMove(Point p, dword keysflags); - virtual void MouseLeave(); - virtual void DragAndDrop(Point p, PasteClip& d); - virtual void LeftDrag(Point p, dword keyflags); - virtual void DragEnter(); - virtual void DragLeave(); - virtual void DragRepeat(Point p); - virtual void CancelMode(); - virtual void MouseWheel(Point p, int zdelta, dword keyflags); - virtual void FrameSet(); - virtual void FrameLayout(Rect& r); - virtual void Layout(); - - bool ProcessMouse(int i, const Point& p); - - void Repos(); - void MakeGroups(); - int FindGroup(const String& g) const; - void CloseAll(); - void DoGrouping(int n); - void DoCloseGroup(int n); - void NewGroup(const String &name, const Value &data = Value()); - - virtual WString ParseLabel(const WString& s); - // Sub-class display overide & helpers - virtual void PaintTabData(Draw& w, const Rect &t, const Tab& tab, const Font &font, - Color ink, dword style, int bl); - virtual Size GetStdSize(const Tab &t); - Size GetStdSize(const Value &v); - - int GetTextAngle() { return AlignedFrame::IsVert() ? (GetAlign() == LEFT ? 900 : 2700) : 0; } - Point GetTextPosition(const Rect& r, int cy, int bl) const; - int GetTargetTab(Point p); - - const Style &GetStyle() { return *style[GetAlign()]; } - - // Sub-class menu overrides - virtual void ContextMenu(Bar& bar); - virtual void GroupMenu(Bar &bar, int n); - - struct TabGroupSort { - bool operator () (const Tab& a, const Tab& b) const { return a.group < b.group; } - }; -public: - typedef TabBar CLASSNAME; - - Callback WhenHighlight; - Callback1 WhenClose; - Callback WhenCloseAll; - Callback WhenLeftDouble; - - TabBar(); - - TabBar& Add(const Value &data) { return Add(data, Null, false); } - TabBar& Add(const Value &data, bool make_active) { return Add(data, Null, make_active); } - TabBar& Add(const Value &data, const char *group, bool make_active = false) { return Add(data, String(group), make_active); } - TabBar& Add(const Value &data, String group, bool make_active = false); - TabBar& Insert(int ix, const Value &data, bool make_active = false) { return Insert(ix, data, Null, make_active); } - TabBar& Insert(int ix, const Value &data, String group = Null, bool make_active = false); - void Close(int n); - void CloseData(const Value &data); - void Clear(); - - TabBar& Crosses(bool b = true); - TabBar& Grouping(bool b = true); - TabBar& GroupSort(bool b = true); - TabBar& AutoScrollHide(bool b = true); - TabBar& InactiveDisabled(bool b = true); - - TabBar& SetDisplay(const Display &d) { display = &d; Refresh(); } - TabBar& SetBorder(int border) { AlignedFrame::SetBorder(border); return *this; } - int Find(const Value &v) const; - - Value Get(int n) const { ASSERT(n >= 0 && n < tabs.GetCount()); return tabs[n].data;} - void Set(int n, const Value &data, const String &group = Null); - virtual Value GetData() const { return HasCursor() ? Get(active) : Value(); } - virtual void SetData(const Value &data); - - Value GetGroupData(const String &s) const { return GetGroupData(FindGroup(s)); } - void SetGroupData(const String &s, const Value &data) { SetGroupData(FindGroup(s), data); } - Value GetGroupData(int n) const { ASSERT(n >= 0 && n < groups.GetCount()); return groups[n].data; } - void SetGroupData(int n, const Value &data) { ASSERT(n >= 0 && n < groups.GetCount()); groups[n].data = data;} - - String GetGroupName() const { return (group == 0) ? Null : groups[group].name; } - String GetGroupName(int i) const { return groups[i].name; } - int SetGroup(const String &s) { DoGrouping(max(0, FindGroup(s))); return group; } - int SetGroup(int c) { DoGrouping(c); return group; } - int GetGroup() const { return group; } - int GetGroupCount() const { return groups.GetCount(); } - void SetGroupActive(int id) { groups[group].active = id; } - int GetGroupActive() const { return groups[group].active; } - int GetFirst() const { return groups[group].first; } - int GetLast() const { return groups[group].last; } - bool IsGroupAll() const { return group == 0; } - int GetCount() const { return tabs.GetCount(); } - int GetCursor() const { return active; } - int GetHighlight() const { return highlight; } - void SetCursor(int n); - void KillCursor() { active = -1; Refresh(); } - void SetTabGroup(int n, const String &group); - - bool HasCursor() const { return active >= 0; } - bool HasHighlight() const { return highlight >= 0; } - - TabBar& StackingFunc(Gate2 func); - TabBar& NoStacking(); - bool IsStacking() { return stacking; } - - TabBar& NeverEmpty(int limit = 1) { neverempty = max(limit, 1); Refresh(); return *this; } - TabBar& CanEmpty() { neverempty = 0; Refresh(); return *this; } - - Image GetDragSample(); - Image GetDragSample(int n); - - TabBar& SetStyle(int align, const Style& s) { ASSERT(align >= 0 && align < 4); style[align] = &s; Refresh(); return *this; } - static const Style& StyleDefault(); - static const Style& StyleLeft(); - static const Style& StyleRight(); - static const Style& StyleBottom(); - static const Style& AlignStyle(int align, Style &s); - static void ResetStyles(); - - virtual void Serialize(Stream& s); -}; - - -#endif +#ifndef _TabBar_TabBar_h_ +#define _TabBar_TabBar_h_ + +#include +using namespace Upp; + +#define IMAGECLASS TabBarImg +#define IMAGEFILE +#include + +//#define TABBAR_DEBUG + +struct AlignedFrame : FrameCtrl +{ + int layout; + int framesize; + int border; +public: + enum + { + LEFT = 0, + TOP = 1, + RIGHT = 2, + BOTTOM = 3 + }; + + AlignedFrame() : border(0), framesize(0), layout(TOP) {} + + virtual void FrameLayout(Rect &r); + virtual void FrameAddSize(Size& sz); + virtual void FramePaint(Draw& w, const Rect& r); + + bool IsVert() const { return (layout & 1) == 0; } + bool IsHorz() const { return layout & 1; } + bool IsTL() const { return layout < 2; } + bool IsBR() const { return layout >= 2; } + + AlignedFrame& SetAlign(int align) { layout = align; FrameSet(); RefreshParentLayout(); return *this; } + AlignedFrame& SetLeft() { return SetAlign(LEFT); } + AlignedFrame& SetTop() { return SetAlign(TOP); } + AlignedFrame& SetRight() { return SetAlign(RIGHT); } + AlignedFrame& SetBottom() { return SetAlign(BOTTOM); } + AlignedFrame& SetFrameSize(int sz, bool refresh = true); + + int GetAlign() const { return layout; } + int GetFrameSize() const { return framesize; } + int GetBorder() const { return border; } +protected: + void Fix(Size& sz); + void Fix(Point& p); + Size Fixed(const Size& sz); + Point Fixed(const Point& p); + + bool HasBorder() { return border >= 0; } + AlignedFrame& SetBorder(int _border) { border = _border; return *this; } + + virtual void FrameSet() { } +}; + +class TabScrollBar : public AlignedFrame +{ + private: + int total; + double pos, ps; + int new_pos; + int old_pos; + double start_pos; + double size; + double cs, ics; + virtual void UpdatePos(bool update = true); + void RefreshScroll(); + bool ready; + Size sz; + public: + TabScrollBar(); + + virtual void Paint(Draw &w); + virtual void LeftDown(Point p, dword keyflags); + virtual void LeftUp(Point p, dword keyflags); + virtual void MouseMove(Point p, dword keyflags); + virtual void MouseWheel(Point p, int zdelta, dword keyflags); + virtual void Layout(); + + int GetPos() const; + void SetPos(int p, bool dontscale = false); + void AddPos(int p, bool dontscale = false); + int GetTotal() const; + void AddTotal(int t); + void SetTotal(int t); + void GoEnd(); + void GoBegin(); + void Clear(); + void Set(const TabScrollBar& t); + bool IsScrollable() const; + Callback WhenScroll; +}; + +class TabBar : public AlignedFrame +{ +public: + struct Style : public TabCtrl::Style { }; + +protected: + enum + { + TB_MARGIN = 6, + TB_SPACE = 10, + TB_SBHEIGHT = 4, + TB_SBSEPARATOR = 1, + TB_FILEICON = 16, + TB_SPACEICON = 5 + }; + + struct Tab : Moveable + { + int id; + + Value data; + String group; + BiVector stack; + + bool visible; + + Point pos; + Size size; + + Point cross_pos; + Size cross_size; + + Point real_pos; + Size real_size; + + Tab() : visible(true), id(-1) + {} + int Right() const { return pos.x + size.cx; } + bool HasMouse(const Point& p) const; + bool HasMouseCross(const Point& p) const; + }; + + struct Group : Moveable + { + Group() {} + String name; + Value data; + int active; + int count; + int first; + int last; + }; +protected: + + TabScrollBar sc; + + Vector groups; + Vector tabs; + int active; + +private: + int id; + int highlight; + int target; + int cross; + bool crosses:1; + bool isctrl:1; + bool isdrag:1; + bool grouping:1; + bool autoscrollhide:1; + bool nosel:1; + bool nohl:1; + bool inactivedisabled:1; + bool stacking:1; + bool groupsort:1; + Gate2 stackfunc; + int neverempty; + Point mouse, oldp; + int group; + const Display *display; + Image dragtab; + + static Style leftstyle, rightstyle, bottomstyle; + const Style *style[4]; + + void PaintTab(Draw &w, const Style &s, const Size &sz, int i, bool enable, bool dragsample = false); + + int TabPos(const String &g, bool &first, int i, int j, bool inactive); + void SyncScrollBar(bool synctotal = true); + void Scroll(); + + int FindId(int id) const; + int GetNext(int n) const; + int GetPrev(int n) const; + + int GetWidth(int n); + int GetWidth() const; + int GetHeight(bool scrollbar = true) const; + + void DoStacking(); + void DoUnstacking(); + void StackRemove(BiVector &stack, int ix); + int FindInStack(const Value &data, int &stackix) const; + void CycleTabStack(int n); + + static int GetStyleHeight(const Style& s); + + int GetNextId(); + int GetScrollPos() { return sc.GetPos(); } + + static Value AlignValue(int align, const Value &v, const Size &isz); +protected: + virtual void Paint(Draw &w); + virtual void LeftDown(Point p, dword keysflags); + virtual void LeftUp(Point p, dword keysflags); + virtual void LeftDouble(Point p, dword keysflags); + virtual void RightDown(Point p, dword keyflags); + virtual void MiddleDown(Point p, dword keyflags); + virtual void MiddleUp(Point p, dword keyflags); + virtual void MouseMove(Point p, dword keysflags); + virtual void MouseLeave(); + virtual void DragAndDrop(Point p, PasteClip& d); + virtual void LeftDrag(Point p, dword keyflags); + virtual void DragEnter(); + virtual void DragLeave(); + virtual void DragRepeat(Point p); + virtual void CancelMode(); + virtual void MouseWheel(Point p, int zdelta, dword keyflags); + virtual void FrameSet(); + virtual void FrameLayout(Rect& r); + virtual void Layout(); + + bool ProcessMouse(int i, const Point& p); + + void Repos(); + void MakeGroups(); + int FindGroup(const String& g) const; + void CloseAll(); + void DoGrouping(int n); + void DoCloseGroup(int n); + void NewGroup(const String &name, const Value &data = Value()); + + virtual WString ParseLabel(const WString& s); + // Sub-class display overide & helpers + virtual void PaintTabData(Draw& w, const Rect &t, const Tab& tab, const Font &font, + Color ink, dword style); + virtual Size GetStdSize(const Tab &t); + Size GetStdSize(const Value &v); + + int GetTextAngle() { return AlignedFrame::IsVert() ? (GetAlign() == LEFT ? 900 : 2700) : 0; } + Point GetTextPosition(const Rect& r, int cy, int space) const; + Point GetImagePosition(const Rect& r, int cx, int cy, int space, int side) const; + int GetTargetTab(Point p); + + const Style &GetStyle() { return *style[GetAlign()]; } + + // Sub-class menu overrides + virtual void ContextMenu(Bar& bar); + virtual void GroupMenu(Bar &bar, int n); + + struct TabGroupSort { + bool operator () (const Tab& a, const Tab& b) const { return a.group < b.group; } + }; +public: + typedef TabBar CLASSNAME; + + Callback WhenHighlight; + Callback1 WhenClose; + Callback WhenCloseAll; + Callback WhenLeftDouble; + + TabBar(); + + TabBar& Add(const Value &data) { return Add(data, Null, false); } + TabBar& Add(const Value &data, bool make_active) { return Add(data, Null, make_active); } + TabBar& Add(const Value &data, const char *group, bool make_active = false) { return Add(data, String(group), make_active); } + TabBar& Add(const Value &data, String group, bool make_active = false); + TabBar& Insert(int ix, const Value &data, bool make_active = false) { return Insert(ix, data, Null, make_active); } + TabBar& Insert(int ix, const Value &data, String group = Null, bool make_active = false); + void Close(int n); + void CloseData(const Value &data); + void Clear(); + + TabBar& Crosses(bool b = true); + TabBar& Grouping(bool b = true); + TabBar& GroupSort(bool b = true); + TabBar& AutoScrollHide(bool b = true); + TabBar& InactiveDisabled(bool b = true); + + TabBar& SetDisplay(const Display &d) { display = &d; Refresh(); } + TabBar& SetBorder(int border) { AlignedFrame::SetBorder(border); return *this; } + int Find(const Value &v) const; + + Value Get(int n) const { ASSERT(n >= 0 && n < tabs.GetCount()); return tabs[n].data;} + void Set(int n, const Value &data, const String &group = Null); + virtual Value GetData() const { return HasCursor() ? Get(active) : Value(); } + virtual void SetData(const Value &data); + + Value GetGroupData(const String &s) const { return GetGroupData(FindGroup(s)); } + void SetGroupData(const String &s, const Value &data) { SetGroupData(FindGroup(s), data); } + Value GetGroupData(int n) const { ASSERT(n >= 0 && n < groups.GetCount()); return groups[n].data; } + void SetGroupData(int n, const Value &data) { ASSERT(n >= 0 && n < groups.GetCount()); groups[n].data = data;} + + String GetGroupName() const { return (group == 0) ? Null : groups[group].name; } + String GetGroupName(int i) const { return groups[i].name; } + int SetGroup(const String &s) { DoGrouping(max(0, FindGroup(s))); return group; } + int SetGroup(int c) { DoGrouping(c); return group; } + int GetGroup() const { return group; } + int GetGroupCount() const { return groups.GetCount(); } + void SetGroupActive(int id) { groups[group].active = id; } + int GetGroupActive() const { return groups[group].active; } + int GetFirst() const { return groups[group].first; } + int GetLast() const { return groups[group].last; } + bool IsGroupAll() const { return group == 0; } + int GetCount() const { return tabs.GetCount(); } + int GetCursor() const { return active; } + int GetHighlight() const { return highlight; } + void SetCursor(int n); + void KillCursor() { active = -1; Refresh(); } + void SetTabGroup(int n, const String &group); + + bool HasCursor() const { return active >= 0; } + bool HasHighlight() const { return highlight >= 0; } + + TabBar& StackingFunc(Gate2 func); + TabBar& NoStacking(); + bool IsStacking() { return stacking; } + + TabBar& NeverEmpty(int limit = 1) { neverempty = max(limit, 1); Refresh(); return *this; } + TabBar& CanEmpty() { neverempty = 0; Refresh(); return *this; } + + Image GetDragSample(); + Image GetDragSample(int n); + + TabBar& SetStyle(int align, const Style& s) { ASSERT(align >= 0 && align < 4); style[align] = &s; Refresh(); return *this; } + static const Style& StyleDefault(); + static const Style& StyleLeft(); + static const Style& StyleRight(); + static const Style& StyleBottom(); + static const Style& AlignStyle(int align, Style &s); + static void ResetStyles(); + + virtual void Serialize(Stream& s); +}; + + +#endif diff --git a/bazaar/TabBar/TabBar.upp b/bazaar/TabBar/TabBar.upp index 0e8494832..f495247b5 100644 --- a/bazaar/TabBar/TabBar.upp +++ b/bazaar/TabBar/TabBar.upp @@ -1,13 +1,13 @@ -description "Bazaar: Generic tab frame. Authors: Daniel Kos (unodgs), James Thomas (mrtj)"; - -uses - CtrlLib; - -file - TabBar.h, - TabBar.iml, - TabBar.cpp; - -mainconfig - "" = "GUI"; - +description "Bazaar: Generic tab frame. Authors: Daniel Kos (unodgs), James Thomas (mrtj)\377"; + +uses + CtrlLib; + +file + TabBar.h, + TabBar.cpp, + TabBar.iml; + +mainconfig + "" = "GUI"; + diff --git a/bazaar/TabBarTest/TabBarTest.cpp b/bazaar/TabBarTest/TabBarTest.cpp index d7f1f6808..16315a0f2 100644 --- a/bazaar/TabBarTest/TabBarTest.cpp +++ b/bazaar/TabBarTest/TabBarTest.cpp @@ -10,6 +10,17 @@ struct TabBarTest : TopWindow TabBar t_tabs; TabBar b_tabs; + typedef TabBarTest CLASSNAME; + + bool Stack(Value a, Value b) + { + String as = a; + String bs = b; + as = as.Left(as.Find('.')); + bs = bs.Left(bs.Find('.')); + return as == bs; + } + TabBarTest() { l_tabs.Crosses(true); @@ -35,15 +46,17 @@ struct TabBarTest : TopWindow r_tabs.Grouping(true); t_tabs.Crosses(true); - t_tabs.Add("/ala/Test.cpp"); - t_tabs.Add("/ala/Test.h"); + t_tabs.Add("Test.cpp"); + t_tabs.Add("Test.h"); t_tabs.Add("/ala/SuperProgram.cpp", true); t_tabs.Add("/kasia/SuperProgram.h"); t_tabs.Add("/kasia/Synchronize.cpp"); t_tabs.Add("/kasia/Synchronize.h"); t_tabs.Add("/test/Test.cpp"); t_tabs.Add("/test/Test.h"); - t_tabs.Grouping(true); + t_tabs.StackingFunc(THISBACK(Stack)); + //t_tabs.Grouping(true); + //t_tabs.Stacking(true); b_tabs.Crosses(true); b_tabs.Add("/ala/Test.cpp");