From 8a3520a6769ca55fd077604be39a6018474c8f87 Mon Sep 17 00:00:00 2001 From: mrjt Date: Thu, 4 Jun 2009 10:59:32 +0000 Subject: [PATCH] Major improvement to TabBar package FileTabsExample added MultiList package removed. Reason: Promoted to uppsrc. QuickTabsTest removed. Reason: Redundant git-svn-id: svn://ultimatepp.org/upp/trunk@1271 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- bazaar/FileTabsExample/FileTabsExample.h | 41 + bazaar/FileTabsExample/FileTabsExample.lay | 20 + bazaar/FileTabsExample/FileTabsExample.upp | 12 + bazaar/FileTabsExample/init | 5 + bazaar/FileTabsExample/main.cpp | 180 + bazaar/MultiList/MultiList.cpp | 1052 ------ bazaar/MultiList/MultiList.h | 219 -- bazaar/MultiList/MultiList.upp | 6 - bazaar/MultiList/init | 3 - bazaar/QuickTabs/QuickTabs.cpp | 1073 ------ bazaar/QuickTabs/QuickTabs.h | 221 -- bazaar/QuickTabs/QuickTabs.iml | 101 - bazaar/QuickTabs/QuickTabs.upp | 8 - bazaar/QuickTabs/init | 4 - bazaar/TabBar/TabBar.cpp | 3508 +++++++++++--------- bazaar/TabBar/TabBar.h | 194 +- bazaar/TabBar/TabBar.upp | 2 + 17 files changed, 2286 insertions(+), 4363 deletions(-) create mode 100644 bazaar/FileTabsExample/FileTabsExample.h create mode 100644 bazaar/FileTabsExample/FileTabsExample.lay create mode 100644 bazaar/FileTabsExample/FileTabsExample.upp create mode 100644 bazaar/FileTabsExample/init create mode 100644 bazaar/FileTabsExample/main.cpp delete mode 100644 bazaar/MultiList/MultiList.cpp delete mode 100644 bazaar/MultiList/MultiList.h delete mode 100644 bazaar/MultiList/MultiList.upp delete mode 100644 bazaar/MultiList/init delete mode 100644 bazaar/QuickTabs/QuickTabs.cpp delete mode 100644 bazaar/QuickTabs/QuickTabs.h delete mode 100644 bazaar/QuickTabs/QuickTabs.iml delete mode 100644 bazaar/QuickTabs/QuickTabs.upp delete mode 100644 bazaar/QuickTabs/init diff --git a/bazaar/FileTabsExample/FileTabsExample.h b/bazaar/FileTabsExample/FileTabsExample.h new file mode 100644 index 000000000..cb2257205 --- /dev/null +++ b/bazaar/FileTabsExample/FileTabsExample.h @@ -0,0 +1,41 @@ +#ifndef _FileTabsExample_FileTabsExample_h +#define _FileTabsExample_FileTabsExample_h + +#include +#include +using namespace Upp; + +#define LAYOUTFILE +#include + +class FileTabsExample : public WithFileTabsExampleLayout { +private: + FileTabs bar[4]; + String barbackup; +public: + typedef FileTabsExample CLASSNAME; + FileTabsExample(); + + // TabBar events + void OnCursor(); + bool OnCloseConfirm(Value v); + bool OnCloseAllConfirm(); + // Buttons + void OnAdd(); + void OnInsert(); + // Options + void OnGrouping(); + void OnGroupSort(); + void OnSeparators(); + void OnStacking(); + void OnIcons(); + void OnPrompt(); + void OnAllAlign(); + void OnInactive(); + // Ctrl overloads + virtual bool Key(dword key, int count); + virtual void DragAndDrop(Point p, PasteClip& d); +}; + +#endif + diff --git a/bazaar/FileTabsExample/FileTabsExample.lay b/bazaar/FileTabsExample/FileTabsExample.lay new file mode 100644 index 000000000..d1b87cca8 --- /dev/null +++ b/bazaar/FileTabsExample/FileTabsExample.lay @@ -0,0 +1,20 @@ +LAYOUT(FileTabsExampleLayout, 660, 348) + ITEM(EditString, fileinput, HSizePosZ(8, 72).TopPosZ(44, 20)) + ITEM(Button, addfile, SetLabel(t_("Add")).RightPosZ(4, 64).TopPosZ(44, 20)) + ITEM(Option, grouping, SetLabel(t_("Group tabs")).LeftPosZ(8, 132).TopPosZ(84, 16)) + ITEM(Option, groupsort, SetLabel(t_("Sort tabs by group")).LeftPosZ(8, 132).TopPosZ(104, 16)) + ITEM(Option, separators, SetLabel(t_("Visually seperate groups")).LeftPosZ(8, 132).TopPosZ(124, 16)) + ITEM(Option, stacking, SetLabel(t_("Stack tabs")).LeftPosZ(144, 132).TopPosZ(84, 16)) + ITEM(Option, normalicons, SetLabel(t_("Icons for normal tabs")).LeftPosZ(144, 132).TopPosZ(104, 16)) + ITEM(Option, stackedicons, SetLabel(t_("Icons for stacked tabs")).LeftPosZ(144, 132).TopPosZ(124, 16)) + ITEM(Option, prompt, SetLabel(t_("Prompt before tab close")).LeftPosZ(280, 132).TopPosZ(84, 16)) + ITEM(Option, inactive, SetLabel(t_("Show inactive tabs")).LeftPosZ(280, 132).TopPosZ(124, 16)) + ITEM(Option, allalign, SetLabel(t_("Show all alignments")).LeftPosZ(280, 132).TopPosZ(104, 16)) + ITEM(LabelBox, dv___11, SetLabel(t_("Options")).HSizePosZ(4, 0).TopPosZ(68, 76)) + ITEM(Label, selection, HSizePosZ(4, 4).TopPosZ(184, 19)) + ITEM(Label, dv___13, SetLabel(t_("Selected file (form top bar only):")).HSizePosZ(4, 4).TopPosZ(164, 19)) + ITEM(LabelBox, dv___14, SetLabel(t_("Add Files")).HSizePosZ(4, 0).TopPosZ(0, 68)) + ITEM(Label, dv___15, SetLabel(t_("- Drag files onto this window\n- Enter full paths below (files do not need to exist)")).HSizePosZ(8, 4).TopPosZ(12, 32)) + ITEM(Button, insert, SetLabel(t_("Insert")).LeftPosZ(4, 64).BottomPosZ(5, 24)) +END_LAYOUT + diff --git a/bazaar/FileTabsExample/FileTabsExample.upp b/bazaar/FileTabsExample/FileTabsExample.upp new file mode 100644 index 000000000..41a8ab773 --- /dev/null +++ b/bazaar/FileTabsExample/FileTabsExample.upp @@ -0,0 +1,12 @@ +uses + CtrlLib, + TabBar; + +file + FileTabsExample.h, + main.cpp, + FileTabsExample.lay; + +mainconfig + "" = "GUI"; + diff --git a/bazaar/FileTabsExample/init b/bazaar/FileTabsExample/init new file mode 100644 index 000000000..42b40afd6 --- /dev/null +++ b/bazaar/FileTabsExample/init @@ -0,0 +1,5 @@ +#ifndef _FileTabsExample_icpp_init_stub +#define _FileTabsExample_icpp_init_stub +#include "CtrlLib/init" +#include "TabBar/init" +#endif diff --git a/bazaar/FileTabsExample/main.cpp b/bazaar/FileTabsExample/main.cpp new file mode 100644 index 000000000..3f2a2a6e8 --- /dev/null +++ b/bazaar/FileTabsExample/main.cpp @@ -0,0 +1,180 @@ +#include "FileTabsExample.h" + +#define FILE_LIMIT 5 +#define PACKAGE_LIMIT 5 + +FileTabsExample::FileTabsExample() +{ + CtrlLayout(*this, "FileTabs Example"); + Sizeable(); + + for (int i = 0; i < 4; i++) + bar[i].SetAlign((i+1) % 4); + AddFrame(bar[0]); + + bar[0] <<= THISBACK(OnCursor); + + addfile <<= THISBACK(OnAdd); + insert <<= THISBACK(OnInsert); + + grouping <<= THISBACK(OnGrouping); + groupsort <<= THISBACK(OnGroupSort); + separators <<= THISBACK(OnSeparators); + stacking <<= THISBACK(OnStacking); + normalicons <<= THISBACK(OnIcons); + stackedicons <<= THISBACK(OnIcons); + prompt <<= THISBACK(OnPrompt); + allalign <<= THISBACK(OnAllAlign); + + grouping <<= true; + inactive <<= true; + normalicons <<= true; + + OnInsert(); + OnCursor(); +} + +void FileTabsExample::OnCursor() +{ + if (bar[0].HasCursor()) + selection = (String)~bar[0]; + else + selection = "No tab selected"; +} + +void FileTabsExample::OnInsert() +{ + Vector files; + files.Add("C:\\uppsvn\\bazaar\\TabBar\\FileTabs.h"); + files.Add("C:\\uppsvn\\bazaar\\TabBar\\TabBar.cpp"); + files.Add("C:\\uppsvn\\bazaar\\TabBar\\TabBar.h"); + files.Add("C:\\uppsvn\\bazaar\\TabBar\\TabBar.iml"); + files.Add("C:\\uppsvn\\bazaar\\TabBar\\TabBar.upp"); + files.Add("C:\\uppsvn\\bazaar\\TabBar\\FileTabs.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\Docking.lay"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\Docking.t"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockTabBar.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockTabBar.h"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockMenu.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockMenu.h"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockPane.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockWindow.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\Docking.h"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\Docking.upp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockPane.h"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockableCtrl.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockableCtrl.h"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockConfig.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockCont.cpp"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\DockCont.h"); + files.Add("C:\\uppsvn\\bazaar\\UppDocking\\Docking.iml"); + files.Add("C:\\uppsvn\\bazaar\\FileTabsExample\\FileTabsExample.h"); + files.Add("C:\\uppsvn\\bazaar\\FileTabsExample\\FileTabsExample.lay"); + files.Add("C:\\uppsvn\\bazaar\\FileTabsExample\\FileTabsExample.upp"); + files.Add("C:\\uppsvn\\bazaar\\FileTabsExample\\main.cpp"); + for (int i = 0; i < 4; i++) + bar[i].AddFiles(files, false); +} + +bool FileTabsExample::OnCloseConfirm(Value v) +{ + return PromptOKCancel(Format("Close '%s'?", DeQtf((String)v))) == 0; +} + +bool FileTabsExample::OnCloseAllConfirm() +{ + return PromptOKCancel("Close all tabs?") == 0; +} + +void FileTabsExample::OnAdd() +{ + if (!fileinput.GetLength()) return; + for (int i = 0; i < 4; i++) + bar[i].AddFile(~fileinput); +} + +void FileTabsExample::OnGrouping() +{ + for (int i = 0; i < 4; i++) + bar[i].Grouping(~grouping); +} + +void FileTabsExample::OnGroupSort() +{ + for (int i = 0; i < 4; i++) + bar[i].GroupSort(~groupsort); +} + +void FileTabsExample::OnSeparators() +{ + for (int i = 0; i < 4; i++) + bar[i].GroupSeparators(~separators); +} + +void FileTabsExample::OnStacking() +{ + for (int i = 0; i < 4; i++) + bar[i].Stacking(~stacking); +} + +void FileTabsExample::OnIcons() +{ + for (int i = 0; i < 4; i++) + bar[i].FileIcons(~normalicons, ~stackedicons); +} + +void FileTabsExample::OnPrompt() +{ + if (prompt) { + bar[0].CancelClose = THISBACK(OnCloseConfirm); + bar[0].CancelCloseAll = THISBACK(OnCloseAllConfirm); + } + else { + bar[0].CancelClose.Clear(); + bar[0].CancelCloseAll.Clear(); + } +} + +void FileTabsExample::OnAllAlign() +{ + if (allalign) { + for (int i = 1; i < 4; i++) + AddFrame(bar[i]); + } + else { + for (int i = 0; i < 4; i++) + bar[i].Remove(); + ClearFrames(); + AddFrame(bar[0]); + } +} + +void FileTabsExample::OnInactive() +{ + for (int i = 1; i < 4; i++) + bar[i].InactiveDisabled(~inactive); +} + +bool FileTabsExample::Key(dword key, int count) +{ + if (key == K_RETURN && fileinput.HasFocus()) { + addfile.PseudoPush(); + return true; + } + return false; +} + +void FileTabsExample::DragAndDrop(Point p, PasteClip& d) +{ + if (AcceptFiles(d)) + for (int i = 0; i < 4; i++) + bar[i].AddFiles(GetFiles(d)); +} + + + +GUI_APP_MAIN +{ + FileTabsExample().Run(); +} + diff --git a/bazaar/MultiList/MultiList.cpp b/bazaar/MultiList/MultiList.cpp deleted file mode 100644 index 79c75e62b..000000000 --- a/bazaar/MultiList/MultiList.cpp +++ /dev/null @@ -1,1052 +0,0 @@ -#include "MultiList.h" - -void MultiList::MouseWheel(Point p, int zdelta, dword keyflags) { - sb.Wheel(zdelta); -} - -int MultiList::GetColumnCx(int i) const { - if (mode == MODE_ROWS) - return cx; - int szcx = GetSize().cx; - int cx = max(szcx / max(ncl, 1), Draw::GetStdFontCy()); - return i == ncl - 1 ? szcx - i * cx : cx; -} - -int MultiList::GetColumnItems() const { - if(cy == 0) return 0; - return GetSize().cy / cy; -} - -int MultiList::GetDragColumn(int x) const { - if (mode == MODE_ROWS) - return -1; - int cx = GetColumnCx(); - int i = 0; - if(cx == 0) return -1; - for(;;) { - x -= GetColumnCx(i); - if(x >= -3 && x < 4) - return i; - if(x < 0) return -1; - i++; - } -} - -void MultiList::ShiftSelect() { - if(anchor < 0) - anchor = cursor; - int l = min(anchor, cursor); - int h = max(anchor, cursor); - for(int i = 0; i < GetCount(); i++) { - bool sel = i >= l && i <= h; - if(item[i].canselect && item[i].sel != sel) { - item[i].sel = sel; - RefreshItem(i); - } - } - UpdateSelect(); -} - -Image MultiList::CursorImage(Point p, dword) -{ - return HasCapture() || GetDragColumn(p.x) >= 0 ? Image::SizeHorz() : Image::Arrow(); -} - -int MultiList::GetItem(Point p) -{ - int i; - int max = GetPageItems(); - if (mode == MODE_ROWS) { - i = ((p.y + sb % cy) / cy) * ncl + (p.x / cx); - max += ncl*2; - } - else - i = p.y / cy + GetColumnItems() * (p.x / GetColumnCx(0)); - if(i < 0 || i >= max) - return -1; - i += GetSbPos(); - return i >= 0 && i < GetCount() ? i : -1; -} - -void MultiList::PointDown(Point p) { - int i = GetItem(p); - if(i >= 0 && i < GetCount()) - SetCursor0(i, false); - else - if(clickkill) - KillCursor(); -} - -void MultiList::DoClick(Point p, dword flags) -{ - SetWantFocus(); - PointDown(p); - p.y %= cy; - p.x %= GetColumnCx(0); - if(multi && cursor >= 0) { - if(flags & K_SHIFT) - ShiftSelect(); - else - if(flags & K_CTRL) - SelectOne(cursor, !IsSelected(cursor)); - else { - ClearSelection(); - SelectOne(cursor, true); - anchor = cursor; - } - } - WhenLeftClick(); - WhenLeftClickPos(p); -} - -void MultiList::LeftDown(Point p, dword flags) { - selclick = false; - int i = GetDragColumn(p.x); - if(i >= 0) { - ci = i; - dx = p.x - GetColumnCx(0) * (i + 1); - mpos = p.x; - SetCapture(); - Refresh(mpos - dx, 0, 1, GetSize().cy); - SyncInfo(); - } - else { - int i = GetItem(p); - if(i >= 0 && i < GetCount() && multi && IsSel(i)) - selclick = true; - else - DoClick(p, flags); - } -} - -void MultiList::LeftUp(Point p, dword flags) -{ - if(selclick) - DoClick(p, flags); - selclick = false; - if(HasCapture()) { - Refresh(); - SyncInfo(); - } -} - -void MultiList::LeftDrag(Point p, dword keyflags) -{ - if(!HasCapture()) - WhenDrag(); -} - -void MultiList::RightDown(Point p, dword flags) { - int i = GetItem(p); - if(!(i >= 0 && i < GetCount() && multi && IsSel(i))) - PointDown(p); - MenuBar::Execute(WhenBar); -} - -void MultiList::LeftDouble(Point p, dword flags) { - LeftDown(p, flags); - WhenLeftDouble(); -} - -void MultiList::SyncInfo() -{ - if((HasMouse() || info.HasMouse()) && !HasCapture() && popupex) { - Point p = GetMouseViewPos(); - int i = GetItem(p); - if(i >= 0) { - Rect r = GetItemRect(i); - if(p.x > r.left + 3 && p.x < r.right - 2) { - Color ink, paper; - dword style; - GetItemStyle(i, ink, paper, style); - Item& m = item[i]; - info.Set(this, r, m.value, m.display ? m.display : display, ink, paper, style); - return; - } - } - } - info.Cancel(); -} - -void MultiList::MouseMove(Point p, dword) -{ - if(HasCapture()) { - int cx = sb.GetViewSize().cx; - Refresh(mpos - dx, 0, 1, GetSize().cy); - mpos = p.x; - Refresh(mpos - dx, 0, 1, GetSize().cy); - int ocl = ncl; - ncl = max(1, cx * (ci + 1) / max(p.x, Draw::GetStdFontCy())); - if(ncl != ocl) - Refresh(); - SetSb(); - } - SyncInfo(); -} - -void MultiList::CancelMode() -{ - info.Cancel(); - dropitem = -1; - anchor = -1; - selclick = false; -} - -void MultiList::MouseLeave() -{ - if(!info.IsOpen()) - info.Cancel(); -} - -Rect MultiList::GetItemRect(int i) const { - if (mode == MODE_ROWS) - return (i >= 0) ? RectC( (i % ncl) * cx, (i / ncl) * cy - sb, cx, cy) : Rect(0, 0, 0, 0); - i -= GetSbPos(); - int n = GetColumnItems(); - if(i < 0 || n == 0) - return Rect(0, 0, 0, 0); - int cl = i / n; - int x = 0; - for(int q = 0; q < cl; q++) - x += GetColumnCx(q); - return RectC(x, i % n * cy, GetColumnCx(cl), cy); -} - -void MultiList::Page(bool down) { - int q = GetSbPos(); - if(down) - sb.NextPage(); - else - sb.PrevPage(); - if(q == sb) - SetCursor(down ? GetCount() - 1 : 0); - else - SetCursor(cursor - q + GetSbPos()); -} - -dword MultiList::SwapKey(dword key) -{ - if (mode == MODE_ROWS) { - switch(key) { - case K_UP: - return K_LEFT; - case K_DOWN: - return K_RIGHT; - case K_LEFT: - return K_UP; - case K_RIGHT: - return K_DOWN; - } - } - return key; -} - -bool MultiList::Key(dword _key, int count) { - int c = cursor; - bool sel = _key & K_SHIFT; - int key = _key & ~K_SHIFT; - key = SwapKey(key); - switch(key) { - case K_UP: - if(c < 0) - c = GetCount() - 1; - else - if(c > 0) - c--; - break; - case K_DOWN: - if(c < 0) - c = 0; - else - if(c < GetCount() - 1) - c++; - break; - case K_LEFT: - c = max(c - ((mode == MODE_ROWS) ? ncl : GetColumnItems()), 0); - break; - case K_RIGHT: - c = min(c + ((mode == MODE_ROWS) ? ncl : GetColumnItems()), GetCount() - 1); - break; - case K_PAGEUP: - Page(false); - return true; - case K_PAGEDOWN: - Page(true); - return true; - case K_HOME: - c = 0; - break; - case K_END: - c = GetCount() - 1; - break; - default: - return MenuBar::Scan(WhenBar, _key); - } - if(sel) { - SetCursor0(c, false); - ShiftSelect(); - } - else { - SetCursor(c); - anchor = c; - } - return true; -} - -void MultiList::RefreshSel() -{ - for(int i = 0; i < item.GetCount(); i++) - if(item[i].sel) - RefreshItem(i); -} - -void MultiList::ClearSelection() { - bool upd = false; - for(int i = 0; i < item.GetCount(); i++) - if(item[i].sel) { - item[i].sel = false; - upd = true; - RefreshItem(i); - } - if(upd) - UpdateSelect(); -} - -void MultiList::SelectOne(int i, bool sel) { - if(!multi) return; - if(item[i].canselect) - item[i].sel = sel; - UpdateSelect(); - RefreshItem(i); -} - -bool MultiList::IsSelected(int i) const { - return item[i].sel; -} - -bool MultiList::IsSel(int i) const -{ - return IsMultiSelect() ? IsSelected(i) : GetCursor() == i; -} - -void MultiList::UpdateSelect() { - selcount = 0; - for(int i = 0; i < item.GetCount(); i++) - if(item[i].sel) - selcount++; - SyncInfo(); - Action(); - WhenSelection(); - WhenSel(); -} - -void MultiList::GetItemStyle(int i, Color& fg, Color& bg, dword& st) -{ - st = 0; - bool hasfocus = HasFocusDeep() && !IsDragAndDropTarget(); - bool drop = i == dropitem && !insert; - if(IsReadOnly()) - st |= Display::READONLY; - if(IsSelected(i)) - st |= Display::SELECT; - if(i == cursor) - st |= Display::CURSOR; - if(drop) { - hasfocus = true; - st |= Display::CURSOR; - } - if(hasfocus) - st |= Display::FOCUS; - fg = SColorText; - bg = SColorPaper; - if(nobg) - bg = Null; - if((st & Display::SELECT) || - (!multi || !item[i].canselect && selcount == 0) && (st & Display::CURSOR) || - drop) { - fg = hasfocus ? SColorHighlightText : SColorText; - bg = hasfocus ? SColorHighlight : Blend(SColorDisabled, SColorPaper); - } -} - -dword MultiList::PaintItem(Draw& w, int i, const Rect& r) -{ - Color ink, paper; - dword style; - GetItemStyle(i, ink, paper, style); - const Item& m = item[i]; - w.Clip(r); - (m.display ? m.display : display)->Paint(w, r, m.value, ink, paper, style); - w.End(); - return style; -} - -void MultiList::Paint(Draw& w) { - Size sz = GetSize(); - if(!GetColumnCx(0) || !cy) return; - if (mode == MODE_ROWS) - return PaintRows(w, sz); - else { - int x = 0; - int i = GetSbPos(sz); - int coli = 0; - while(x < sz.cx) { - int cx = GetColumnCx(coli++); - int y = 0; - while(y + cy <= sz.cy) { - Rect rect = RectC(x, y, cx, cy); - if(i < GetCount()) { - if(w.IsPainting(rect)) { - Rect r = rect; - r.right--; - dword style = PaintItem(w, i, r); - w.DrawRect(rect.right - 1, rect.top, 1, rect.Height(), - x + cx < sz.cx ? SColorDisabled : SColorPaper); - if(i == cursor && selcount != 1 && multi && item[i].canselect) - DrawFocus(w, r, style & Display::SELECT ? SColorPaper() : SColorText()); - } - } - else - w.DrawRect(rect, SColorPaper); - if(i == dropitem && insert) - DrawHorzDrop(w, x, y, cx); - if(i + 1 == dropitem && insert && y + 2 * cy > sz.cy) - DrawHorzDrop(w, x, y + cy - 2, cx); - y += cy; - i++; - } - w.DrawRect(x, y, cx, sz.cy - y, SColorPaper); - x += cx; - } - } - if(HasCapture()) - w.DrawRect(mpos - dx, 0, 1, sz.cy, Blend(SColorHighlight, SColorFace)); - (mode == MODE_COLUMNS) ? - scroller.Set(Point(sb, 0)) : - scroller.Set(sb); -} - -void MultiList::PaintRows(Draw &w, Size &sz) -{ - int pos = sb % cy; - int y = -pos; - int i = GetSbPos(sz); - int coli = 0; - while(y < sz.cy-pos+cy) { - int x = 0; - while (x + cx <= sz.cx) { - Rect rect = RectC(x, y, cx, cy); - if(i < GetCount()) { - if(w.IsPainting(rect)) { - Rect r = rect; - dword style = PaintItem(w, i, r); -// w.DrawRect(rect.right - 1, rect.top, 1, rect.Height(), -// x + cx < sz.cx ? SColorDisabled : SColorPaper); - if(i == cursor && selcount != 1 && multi && item[i].canselect) - DrawFocus(w, r, style & Display::SELECT ? SColorPaper() : SColorText()); - } - } - else - w.DrawRect(rect, SColorPaper); - if(i == dropitem && insert) - DrawHorzDrop(w, x, y, cx); - if(i + 1 == dropitem && insert && y + 2 * cy > sz.cy) - DrawHorzDrop(w, x, y + cy - 2, cx); - x += cx; - i++; - } - w.DrawRect(x, y, cx, sz.cy - y, SColorPaper); - y += cy; - } -} - -Image MultiList::GetDragSample() -{ - Size sz = StdSampleSize(); - ImageDraw iw(sz); - int y = 0; - for(int i = 0; i < GetCount() && y < sz.cy; i++) - if(IsSel(i)) { - PaintItem(iw, i, RectC(0, y, sz.cx, cy)); - y += cy; - } - return Crop(iw, 0, 0, sz.cx, y);; -} - -int MultiList::GetPageItems() const -{ - return ncl * GetColumnItems(); -} - -void MultiList::SetSb() -{ - switch (mode) { - case MODE_LIST: - sb.SetTotal(GetCount()); - sb.SetPage(GetPageItems()); - sb.SetLine(1); - break; - case MODE_COLUMNS: { - int icnt = max(1, GetColumnItems()); - int ccnt = GetCount()/icnt; - ccnt += (GetCount() % icnt) ? 1 : 0; - sb.SetTotal(ccnt); - sb.SetPage(ncl); - sb.SetLine(1); - break; - } - case MODE_ROWS: { - int rcnt = GetCount()/ncl; - rcnt += (GetCount() % ncl) ? 1 : 0; - sb.SetTotal(rcnt*cy); - sb.SetPage((GetSize().cy/cy)*cy); - sb.SetLine(cy); - break; - } - } -} - -void MultiList::ScrollInto(int pos) -{ - switch (mode) { - case MODE_ROWS: - sb.ScrollInto((pos / ncl) * cy, max(0, sb.GetLine() - (GetSize().cy - sb.GetPage()))); - return; - case MODE_COLUMNS: - sb.ScrollInto(pos / max(1, GetColumnItems())); - return; - case MODE_LIST: - sb.ScrollInto(pos); - return; - } -} - -void MultiList::Layout() -{ - if (mode == MODE_ROWS) - ncl = max(GetSize().cx / cx, 1); - SetSb(); -} - -void MultiList::Scroll() -{ - Size sz = GetSize(); - switch (mode) { - case MODE_LIST: - sz.cy = sz.cy / cy * cy; - scroller.Scroll(*this, sz, sb, cy); - break; - case MODE_COLUMNS: - sz.cy = sz.cy / cy * cy; - scroller.Scroll(*this, sz, Point(sb, 0), Size(GetColumnCx(0), 0)); - break; - case MODE_ROWS: - scroller.Scroll(*this, sz, sb, 1); - break; - } - info.Cancel(); -} - -void MultiList::RefreshItem(int i, int ex) -{ - if(i >= 0) { - Refresh(GetItemRect(i).InflatedVert(ex)); - SyncInfo(); - } -} - -void MultiList::SetCursor0(int c, bool sel) -{ - int c0 = cursor; - c = minmax(c, 0, GetCount() - 1); - if(c < 0 || cursor < 0) - Refresh(); - else - RefreshCursor(); - cursor = c; - int q = sb; - ScrollInto(cursor); - if(q != sb) - Refresh(); - else - RefreshCursor(); - if(sel && multi) { - ClearSelection(); - if(cursor >= 0) { - SelectOne(cursor, true); - anchor = cursor; - } - } - if(c0 != cursor) { - if(cursor >= 0) - WhenEnterItem(); - else - WhenKillCursor(); - WhenSel(); - } - SyncInfo(); - Action(); -} - -void MultiList::SetCursor(int c) -{ - SetCursor0(c, true); -} - -int MultiList::GetSbPos(const Size &sz) const -{ - switch (mode) { - case MODE_ROWS: - return (sb / cy)*ncl; - case MODE_COLUMNS: - return (cy ? sb * (sz.cy / cy) : 0); - case MODE_LIST: - return sb; - } - return sb; -} - -void MultiList::SetSbPos(int y) -{ - SetSb(); - sb = minmax(y, 0, GetCount() - GetPageItems()); -} - -void MultiList::KillCursor() -{ - if(cursor < 0) return; - Refresh(); - SyncInfo(); - cursor = -1; - sb.Begin(); - WhenKillCursor(); - WhenSel(); - Action(); -} - -void MultiList::GotFocus() -{ - if(cursor < 0 && GetCount()) - SetCursor(GetSbPos()); - Refresh(); - SyncInfo(); -} - -void MultiList::LostFocus() -{ - Refresh(); - SyncInfo(); -} - -int MultiList::RoundedCy() -{ - if (mode != MODE_LIST) - return GetRect().GetHeight(); - Rect r = GetRect(); - Rect rr = r; - frame->FrameLayout(r); - return r.Height() / cy * cy + rr.Height() - r.Height(); -} - -void MultiList::FrameLayout(Rect& r) -{ - r.bottom = r.top + RoundedCy(); - frame->FrameLayout(r); -} - -void MultiList::FrameAddSize(Size& sz) -{ - frame->FrameAddSize(sz); -} - -void MultiList::FramePaint(Draw& draw, const Rect& r) -{ - int ry = RoundedCy(); - Rect rr = r; - rr.bottom = ry; - frame->FramePaint(draw, rr); - rr = r; - rr.top = ry; - draw.DrawRect(rr, SColorFace); -} - -MultiList& MultiList::RoundSize(bool b) -{ - if(b) - Ctrl::SetFrame(0, *this); - else - Ctrl::SetFrame(0, *frame); - RefreshLayout(); - Refresh(); - SyncInfo(); - return *this; -} - -void MultiList::SetFrame(CtrlFrame& _frame) -{ - frame = &_frame; - RefreshLayout(); - Refresh(); - SyncInfo(); -} - -struct MultiList::ItemOrder { - const ValueOrder *order; - bool operator()(const Item& a, const Item& b) const { - return (*order)(a.value, b.value); - } -}; - -void MultiList::Sort(const ValueOrder& order) -{ - ItemOrder itemorder; - itemorder.order = ℴ - KillCursor(); - UPP::Sort(item, itemorder); - sb.Begin(); - SyncInfo(); -} - -Value MultiList::GetData() const -{ - if (!multi) - return (cursor >= 0) ? Get(cursor) : Value(); - for (int i = 0; i < item.GetCount(); i++) - if (item[i].sel) - return item[i].key; - return Value(); -} - -void MultiList::SetData(const Value& key) -{ - int ii = Find(key); - if (ii >= 0) { - SelectOne(ii, true); - SetCursor(ii); - } -} - -void MultiList::Clear() { - CancelMode(); - KillCursor(); - item.Clear(); - selcount = 0; - Update(); - Refresh(); - SyncInfo(); - SetSb(); -} - -void MultiList::Insert(int ii, const Value& val, bool canselect) -{ - Insert(ii, val, val, canselect); -} - -void MultiList::Insert(int ii, const Value& val, const Display& display, bool canselect) -{ - Insert(ii, val, val, display, canselect); -} - -void MultiList::Insert(int ii, const Value& key, const Value& val, bool canselect) -{ - int c = -1; - if(cursor >= ii) { - c = cursor + 1; - KillCursor(); - } - Item& m = item.Insert(ii); - m.key = key; - m.value = val; - m.sel = false; - m.canselect = canselect; - m.display = NULL; - Refresh(); - SyncInfo(); - SetSb(); - if(c >= 0) - SetCursor(c); -} - -void MultiList::Insert(int ii, const Value& key, const Value& val, const Display& display, bool canselect) -{ - Insert(ii, key, val, canselect); - item[ii].display = &display; - SyncInfo(); -} - -void MultiList::Set(int ii, const Value& val, bool canselect) -{ - Set(ii, val, val, canselect); -} - -void MultiList::Set(int ii, const Value& val, const Display& display, bool canselect) -{ - Set(ii, val, val, display, canselect); -} - -void MultiList::Set(int ii, const Value& key, const Value& val, bool canselect) -{ - Item& m = item[ii]; - m.value = val; - m.key = key; - m.sel = false; - m.canselect = canselect; - m.display = NULL; - RefreshItem(ii); - SyncInfo(); - SetSb(); -} - -void MultiList::Set(int ii, const Value& key, const Value& val, const Display& display, bool canselect) -{ - Set(ii, key, val, canselect); - item[ii].display = &display; - SyncInfo(); -} - -void MultiList::Set(const Value &key, const Value& val, const Display& display, bool canselect) -{ - int ii = Find(key); - if (ii >= 0) - Set(ii, key, val, display, canselect); -} - -void MultiList::Set(const Value &key, const Value& val, bool canselect) -{ - int ii = Find(key); - if (ii >= 0) - Set(ii, key, val, canselect); -} - -void MultiList::Remove(int ii) -{ - int c = -1; - if(cursor >= ii) { - c = max(ii, cursor - 1); - KillCursor(); - } - item.Remove(ii); - Refresh(); - SyncInfo(); - SetSb(); - if(c >= 0) - SetCursor(c); -} - -void MultiList::Add(const Value& val, bool canselect) -{ - Insert(item.GetCount(), val, val, canselect); -} - -void MultiList::Add(const Value& val, const Display& display, bool canselect) -{ - Add(val, val, display, canselect); -} - -void MultiList::Add(const Value& key, const Value& val, bool canselect) -{ - Insert(item.GetCount(), key, val, canselect); -} - -void MultiList::Add(const Value& key, const Value& val, const Display& display, bool canselect) -{ - Add(key, val, canselect); - item.Top().display = &display; -} - -void MultiList::DnD(int _drop, bool _insert) -{ - if(dropitem != _drop || insert != _insert) { - RefreshItem(dropitem - 1); - RefreshItem(dropitem); - dropitem = _drop; - insert = _insert; - RefreshItem(dropitem - 1); - RefreshItem(dropitem); - } -} - -bool MultiList::DnDInsert(int i, int py, PasteClip& d, int q) -{ - Rect r = GetItemRect(i); - int cy = r.GetHeight(); - if(py < r.top + cy / q) { - WhenDropInsert(i, d); - if(d.IsAccepted()) { - DnD(i, true); - return true; - } - } - if(py >= r.top + (q - 1) * cy / q && i < GetCount()) { - WhenDropInsert(i + 1, d); - if(d.IsAccepted()) { - DnD(i + 1, true); - return true; - } - } - return false; -} - -void MultiList::DragAndDrop(Point p, PasteClip& d) -{ - int i = GetItem(p); - if(i >= 0) { - if(DnDInsert(i, p.y, d, 4)) - return; - WhenDropItem(i, d); - if(d.IsAccepted()) { - DnD(i, false); - return; - } - if(DnDInsert(i, p.y, d, 2)) - return; - } - if(GetCount() == 0 && p.y < 4 || !WhenDrop) { - WhenDropInsert(GetCount(), d); - if(d.IsAccepted()) { - DnD(GetCount(), true); - return; - } - } - WhenDrop(d); - DnD(-1, false); -} - -void MultiList::DragRepeat(Point p) -{ - sb = sb + ((mode == MODE_COLUMNS) ? GetDragScroll(this, p, 1).x : GetDragScroll(this, p, 1).y); -} - -void MultiList::DragEnter() -{ - RefreshSel(); -} - -void MultiList::DragLeave() -{ - DnD(-1, false); - RefreshSel(); -} - -void MultiList::RemoveSelection() -{ - for(int i = GetCount() - 1; i >= 0; i--) - if(IsSel(i)) - Remove(i); // Optimize! -} - -int MultiList::Find(const Value &key) const -{ - for (int i = 0; i < item.GetCount(); i++) - if (item[i].key == key) - return i; - return -1; -} - -void MultiList::InsertDrop(int ii, const Vector& keys, const Vector& data, PasteClip& d, bool self) -{ - if(data.GetCount() == 0) - return; - if(d.GetAction() == DND_MOVE && self) { - for(int i = GetCount() - 1; i >= 0; i--) { - if(IsSel(i)) { - Remove(i); // Optimize! - if(i < ii) - ii--; - } - } - KillCursor(); - d.SetAction(DND_COPY); - } - item.InsertN(ii, data.GetCount()); - for(int i = 0; i < data.GetCount(); i++) { - Item& m = item[ii + i]; - m.value = data[i]; - m.key = keys[i]; - m.sel = false; - m.canselect = true; - m.display = NULL; - } - Refresh(); - SyncInfo(); - SetSb(); - ClearSelection(); - SetCursor(ii + data.GetCount() - 1); - if(IsMultiSelect()) - for(int i = 0; i < data.GetCount(); i++) - SelectOne(ii + i, true); -} - -void MultiList::InsertDrop(int ii, const Vector& data, PasteClip& d, bool self) -{ - InsertDrop(ii, data, data, d, self); -} - -void MultiList::InsertDrop(int ii, const ColumnList& src, PasteClip& d) -{ - Vector data; - for(int i = 0; i < src.GetCount(); i++) - if(src.IsSel(i)) - data.Add(src[i]); - InsertDrop(ii, data, d, false); -} - -void MultiList::InsertDrop(int ii, const MultiList& src, PasteClip& d) -{ - Vector keys; - Vector data; - for(int i = 0; i < src.GetCount(); i++) - if(src.IsSel(i)) { - data.Add(src.GetValue(i)); - keys.Add(src[i]); - } - InsertDrop(ii, data, d, &src == this); -} - -void MultiList::InsertDrop(int ii, PasteClip& d) -{ - InsertDrop(ii, GetInternal(d), d); -} - -void MultiList::Serialize(Stream& s) { - int version = 0; - int cnt; - s.Magic(); - s / version / ncl / cnt; - if (s.IsLoading()) - item.SetCount(cnt); - for (int i = 0; i < item.GetCount(); i++) { - Item &q = item[i]; - s % q.key % q.value % q.canselect; - if (s.IsLoading()) { - q.display = NULL; - q.sel = false; - } - } - s.Magic(); - - Refresh(); - SyncInfo(); -} - -MultiList::MultiList() { - clickkill = false; - ncl = 1; - cx = 50; - cy = Draw::GetStdFontCy(); - cursor = -1; - ColumnMode(); - AddFrame(sb); - sb.WhenScroll = THISBACK(Scroll); - sb.AutoHide(); - Ctrl::SetFrame(ViewFrame()); - frame = &ViewFrame(); - RoundSize(); - display = &StdDisplay(); - multi = false; - selcount = 0; - nobg = false; - popupex = true; -} - -MultiList::~MultiList() {} diff --git a/bazaar/MultiList/MultiList.h b/bazaar/MultiList/MultiList.h deleted file mode 100644 index 1528c4702..000000000 --- a/bazaar/MultiList/MultiList.h +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef _RowList_MultiList_h_ -#define _RowList_MultiList_h_ - -#include -using namespace Upp; - -class MultiList : public Ctrl, private CtrlFrame { -public: - virtual void Serialize(Stream& s); - virtual void Paint(Draw& w); - virtual void Layout(); - virtual Image CursorImage(Point p, dword); - virtual void LeftDown(Point p, dword); - virtual void LeftUp(Point p, dword); - virtual void LeftDouble(Point p, dword); - virtual void RightDown(Point p, dword); - virtual void LeftDrag(Point p, dword keyflags); - virtual void MouseMove(Point p, dword); - virtual void MouseLeave(); - virtual void MouseWheel(Point p, int zdelta, dword keyflags); - virtual bool Key(dword key, int count); - virtual void GotFocus(); - virtual void LostFocus(); - virtual void CancelMode(); - virtual void DragEnter(); - virtual void DragAndDrop(Point p, PasteClip& d); - virtual void DragRepeat(Point p); - virtual void DragLeave(); - -private: - virtual void FrameLayout(Rect& r); - virtual void FrameAddSize(Size& sz); - virtual void FramePaint(Draw& draw, const Rect& r); - -private: - int ncl; - int cx; - int cy; - int cursor, anchor; - int dx; - int ci; - int mpos; - ScrollBar sb; - Scroller scroller; - CtrlFrame *frame; - int dropitem; - bool insert; - bool clickkill; - bool nobg; - bool popupex; - bool selclick; - int mode; - - enum { - MODE_COLUMNS, - MODE_LIST, - MODE_ROWS - }; - - DisplayPopup info; - - const Display *display; - - struct Item { - bool sel; - bool canselect; - Value key; - Value value; - const Display *display; - }; - - Array item; - int selcount; - bool multi; - - struct ItemOrder; - friend struct ItemOrder; - - void SetSb(); - void Scroll(); - int GetSbPos() const { return GetSbPos(GetSize()); } - int GetSbPos(const Size &sz) const; - void ScrollInto(int item); - - dword SwapKey(dword key); - int GetDragColumn(int x) const; - int RoundedCy(); - void Page(bool down); - void PointDown(Point p); - void DoClick(Point p, dword flags); - void ShiftSelect(); - void RefreshItem(int i, int ex = 0); - void RefreshCursor() { RefreshItem(cursor); } - void GetItemStyle(int i, Color& ink, Color& paper, dword& style); - dword PaintItem(Draw& w, int i, const Rect& r); - void SyncInfo(); - void SetCursor0(int c, bool sel); - void UpdateSelect(); - void RefreshSel(); - - bool DnDInsert(int i, int py, PasteClip& d, int q); - void DnD(int _drop, bool _insert); - - void PaintRows(Draw &w, Size &sz); -public: - Callback WhenLeftClick; - Callback1 WhenLeftClickPos; - Callback WhenLeftDouble; - Callback1 WhenBar; - Callback WhenSel; - - Callback WhenDrag; - Callback2 WhenDropItem; - Callback2 WhenDropInsert; - Callback1 WhenDrop; - - // depracated - use WhenSel - Callback WhenSelection; - Callback WhenEnterItem; - Callback WhenKillCursor; - - int GetColumnItems() const; - int GetColumnCx(int i = 0) const; - int GetPageItems() const; - - int GetItem(Point p); - Rect GetItemRect(int i) const; - - int GetCursor() const { return cursor; } - void SetCursor(int c); - void KillCursor(); - bool IsCursor() const { return cursor >= 0; } - - void SetSbPos(int y); - - void SetFrame(CtrlFrame& frame); - - MultiList &ListMode() { mode = MODE_LIST; scroller.Clear(); sb.Vert(); return *this; } - MultiList &RowMode() { mode = MODE_ROWS; scroller.Clear(); sb.Vert(); return *this; } - MultiList &ColumnMode() { mode = MODE_COLUMNS; scroller.Clear(); sb.Horz(); return *this; } - - void Clear(); - void Add(const Value& val, bool canselect = true); - void Add(const Value& val, const Display& display, bool canselect = true); - void Add(const Value& key, const Value& val, bool canselect = true); - void Add(const Value& key, const Value& val, const Display& display, bool canselect = true); - - int GetCount() const { return item.GetCount(); } - const Value& Get(int i) const { return item[i].key; } - const Value& GetValue(int i) const { return item[i].value; } - const Value& operator[](int i) const { return item[i].key; } - - void Set(int ii, const Value& val, bool canselect = true); - void Set(int ii, const Value& val, const Display& display, bool canselect = true); - void Set(int ii, const Value& key, const Value& val, bool canselect = true); - void Set(int ii, const Value& key, const Value& val, const Display& display, bool canselect = true); - void Set(const Value &key, const Value& val, const Display& display, bool canselect = true); - void Set(const Value &key, const Value& val, bool canselect = true); - - void Insert(int ii, const Value& val, bool canselect = true); - void Insert(int ii, const Value& val, const Display& display, bool canselect = true); - void Insert(int ii, const Value& key, const Value& val, bool canselect = true); - void Insert(int ii, const Value& key, const Value& val, const Display& display, bool canselect = true); - void Remove(int ii); - void Remove(const Value & key) { int ii = Find(key); if (ii >= 0) Remove(ii); } - - void RemoveSelection(); - - int Find(const Value &key) const; - - bool IsSelection() const { return selcount > 0; } - void ClearSelection(); - void SelectOne(int i, bool sel); - bool IsSelected(int i) const; - bool IsSelected(const Value &key) const { int ii = Find(key); return (ii >= 0 && IsSelected(ii)); } - bool IsSel(int i) const; - - void Sort(const ValueOrder& order); - - virtual Value GetData() const; - virtual void SetData(const Value& key); - - Image GetDragSample(); - - void InsertDrop(int ii, const Vector& data, PasteClip& d, bool self); - void InsertDrop(int ii, const Vector& keys, const Vector& data, PasteClip& d, bool self); - void InsertDrop(int ii, const MultiList& src, PasteClip& d); - void InsertDrop(int ii, const ColumnList& src, PasteClip& d); - void InsertDrop(int ii, PasteClip& d); - - MultiList& Columns(int _n) { ncl = max(_n, 1); Refresh(); return *this; } - int GetColumns() const { return ncl; } - MultiList& ItemHeight(int _cy) { cy = max(_cy, 1); RefreshLayout(); Refresh(); return *this; } - int GetItemHeight() const { return cy; } - MultiList& ItemWidth(int _cx) { cx = max(1, _cx); RefreshLayout(); Refresh(); return *this; } - int GetItemWidth() const { return cx; } - MultiList& RoundSize(bool b = true); - MultiList& NoRoundSize() { return RoundSize(false); } - MultiList& ClickKill(bool b = true) { clickkill = b; return *this; } - MultiList& NoClickKill() { return ClickKill(false); } - MultiList& SetDisplay(const Display& d) { display = &d; return *this; } - MultiList& NoBackground(bool b = true) { nobg = b; Transparent(); Refresh(); return *this; } - MultiList& Multi(bool b = true) { multi = b; return *this; } - bool IsMulti() const { return multi; } - MultiList& MultiSelect(bool b = true) { multi = b; return *this; } - bool IsMultiSelect() const { return multi; } - MultiList& PopUpEx(bool b = true) { popupex = b; return *this; } - MultiList& NoPopUpEx() { return PopUpEx(false); } - - MultiList& SetScrollBarStyle(const ScrollBar::Style& s) { sb.SetStyle(s); return *this; } - - typedef MultiList CLASSNAME; - - MultiList(); - virtual ~MultiList(); -}; - - -#endif diff --git a/bazaar/MultiList/MultiList.upp b/bazaar/MultiList/MultiList.upp deleted file mode 100644 index 77523dd52..000000000 --- a/bazaar/MultiList/MultiList.upp +++ /dev/null @@ -1,6 +0,0 @@ -description "Bazaar: A list ctrl featuring 3 display modes and key/value support. Author: James Thomas (mrjt)"; - -file - MultiList.h, - MultiList.cpp; - diff --git a/bazaar/MultiList/init b/bazaar/MultiList/init deleted file mode 100644 index 7155ea682..000000000 --- a/bazaar/MultiList/init +++ /dev/null @@ -1,3 +0,0 @@ -#ifndef _MultiList_icpp_init_stub -#define _MultiList_icpp_init_stub -#endif diff --git a/bazaar/QuickTabs/QuickTabs.cpp b/bazaar/QuickTabs/QuickTabs.cpp deleted file mode 100644 index a4548d030..000000000 --- a/bazaar/QuickTabs/QuickTabs.cpp +++ /dev/null @@ -1,1073 +0,0 @@ -#include -//#include - -#define IMAGECLASS Img -#define IMAGEFILE -#include - -static String ParseGroup(const String &s) -{ - if(!s.IsEmpty()) - { - if(s[0] == '/' || s[0] == '\\') - return s.Mid(1); - else if(s[1] == ':') - return s.Mid(3); - } - return Null; -} - -void FloatFrame::FrameLayout(Rect &r) -{ - switch(layout) - { - case LAYOUT_LEFT: - LayoutFrameLeft(r, this, size); - break; - case LAYOUT_TOP: - LayoutFrameTop(r, this, size); - break; - case LAYOUT_RIGHT: - LayoutFrameRight(r, this, size); - break; - case LAYOUT_BOTTOM: - LayoutFrameBottom(r, this, size); - break; - } - r.top += border; - r.left += border; - r.right -= border; - r.bottom -= border; -} - -void FloatFrame::FrameAddSize(Size& sz) -{ - sz += border * 2; - switch(layout) - { - case LAYOUT_LEFT: - sz.cx += size; - break; - case LAYOUT_TOP: - sz.cy += size; - break; - case LAYOUT_RIGHT: - sz.cx -= size; - break; - case LAYOUT_BOTTOM: - sz.cy -= size; - break; - } -} - - -void FloatFrame::FramePaint(Draw& w, const Rect& r) -{ - if(border > 0) - { - Rect n = r; - switch(layout) - { - case LAYOUT_LEFT: - n.left += size; - break; - case LAYOUT_TOP: - n.top += size; - break; - case LAYOUT_RIGHT: - n.right -= size; - break; - case LAYOUT_BOTTOM: - n.bottom -= size; - break; - } - FieldFrame().FramePaint(w, n); - } - else - FrameCtrl::FramePaint(w, r); -} - - -void FloatFrame::Fix(Size& sz) -{ - if(!horizontal) - Swap(sz.cx, sz.cy); -} - -void FloatFrame::Fix(Point& p) -{ - if(!horizontal) - Swap(p.x, p.y); -} - -TabScrollBar::TabScrollBar() -{ - FloatFrame::layout = FloatFrame::TOP; - FloatFrame::size = QT_SBHEIGHT; - FloatFrame::border = 0; - - total = 0; - pos = 0; - ps = 0; - start_pos = 0; - new_pos = 0; - old_pos = 0; - 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; - WhenScroll(); -} - -void TabScrollBar::Paint(Draw &w) -{ - if(!ready) - { - UpdatePos(); - ready = true; - } - Size sz = GetSize(); - - w.DrawRect(sz, /*Yellow*/White); - - if(horizontal) - { - if(total > sz.cx) - w.DrawRect(ffloor(pos), 1, fceil(size), 2, Blue); - else - w.DrawRect(0, 1, sz.cx, 2, Blue); - } - else - { - if(total > sz.cy) - w.DrawRect(1, ffloor(pos), 2, fceil(size), Blue); - else - w.DrawRect(1, 0, 2, sz.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(); - Refresh(); -} - -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(); - Refresh(); -} - -void TabScrollBar::MouseWheel(Point p, int zdelta, dword keyflags) -{ - AddPos(-zdelta / 4, true); -} - -int TabScrollBar::GetPos() const -{ - return ffloor(ps); -} - -void TabScrollBar::SetPos(int p, bool dontscale) -{ - Fix(sz); - pos = total > 0 ? dontscale ? p : iscale(p, sz.cx, total) : 0; - UpdatePos(false); - Refresh(); -} - -void TabScrollBar::AddPos(int p, bool dontscale) -{ - Fix(sz); - 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(); -} - -QuickTabs::QuickTabs() -{ - sc.WhenScroll = THISBACK(Scroll); - highlight = -1; - active = -1; - cross = -1; - target = -1; - crosses = true; - file_icons = false; - grouping = true; - isctrl = false; - isdrag = false; - id = -1; - - Group &g = groups.Add(); - g.name = "All"; - group = 0; - - SetStyle(TabCtrl::StyleDefault()); - BackPaint(); - - FloatFrame::layout = FloatFrame::TOP; - FloatFrame::border = 0; - FloatFrame::size = GetHeight(); - - AddFrame(sc); -} - -void QuickTabs::CloseAll() -{ - for(int i = tabs.GetCount() - 1; i >= 0; i--) - if(i != active) - tabs.Remove(i); - - sc.SetTotal(tabs[0].cx); - MakeGroups(); - Repos(); - SetCursor(0); -} - -int QuickTabs::GetNextId() -{ - return ++id; -} - -void QuickTabs::Menu(Bar& bar) -{ - 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(Img::CHK); - if(i == 0 && cnt > 1) - bar.Separator(); - } - bar.Separator(); - - bar.Add("Close all tabs except current", THISBACK(CloseAll)); - bar.Add("Close non-project tabs", WhenCloseRest); -} - -void QuickTabs::GroupMenu(Bar &bar, int n) -{ - bar.Add("Set active", THISBACK1(DoGrouping, n)); - bar.Add("Close", THISBACK1(DoCloseGroup, n)); -} - -bool Tab::HasMouse(const Point& p) -{ - return visible && p.x >= x && p.x < x + cx; -} - -bool Tab::HasMouseCross(const Point& p, int w, int h) -{ - if(!visible) - return false; - - Size isz = Img::CR0().GetSize(); - int iy = (h - isz.cy) / 2; - int ix = x + cx - isz.cx - w - QT_MARGIN; - - return p.x >= ix && p.x < ix + isz.cx && - p.y >= iy && p.y < iy + isz.cy; -} - - -int QuickTabs::FindGroup(const String& g) -{ - for(int i = 0; i < groups.GetCount(); i++) - if(groups[i].path == g) - return i; - return -1; -} - -void QuickTabs::MakeGroups() -{ - groups[0].count = tabs.GetCount(); - groups[0].first = 0; - groups[0].last = tabs.GetCount() - 1; - - for(int i = 1; i < groups.GetCount(); i++) - { - groups[i].count = 0; - groups[i].first = 1000000; - groups[i].last = 0; - } - - for(int i = 0; i < tabs.GetCount(); i++) - { - Tab &tab = tabs[i]; - String s = ParseGroup(tab.group); - if(IsNull(s)) - continue; - int n = FindGroup(tab.group); - if(n < 0) - { - Group &g = groups.Add(); - g.count = 1; - g.first = 1000000; - g.last = 0; - g.name = s; - g.path = tab.group; - g.active = tab.id; - n = groups.GetCount() - 1; - } - else - { - 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 QuickTabs::DoGrouping(int n) -{ - group = n; - Repos(); - SetCursor(-1); -} - -void QuickTabs::DoCloseGroup(int n) -{ - int cnt = groups.GetCount(); - if(cnt <= 0) - return; - - if(cnt == n) - --group; - - String group = groups[n].path; - - for(int i = tabs.GetCount() - 1; i >= 0; i--) - { - String s = ParseGroup(tabs[i].group); - if(IsNull(s)) - continue; - if(group == tabs[i].group && tabs.GetCount() > 1) - tabs.Remove(i); - } - if(cnt > 1) - groups.Remove(n); - MakeGroups(); - Repos(); - SetCursor(-1); -} - -void QuickTabs::DrawLabel(Draw& w, int x, int y, Tab& t) -{ - String fn = GetFileName(t.name); - - if(horizontal) - DrawFileName(w, x + QT_MARGIN + (QT_FILEICON + QT_SPACEICON) * int(file_icons), (y - t.tsz.cy) / 2, - t.tsz.cx, t.tsz.cy, fn.ToWString(), - false, StdFont(), Black, LtBlue, - Null, Null, false); - else - w.DrawText((y + t.tsz.cy) / 2 + 1, - x + QT_MARGIN + (QT_FILEICON + QT_SPACEICON) * int(file_icons), - 2700, fn.ToWString(), - style->font); -} - -void QuickTabs::DrawTab(Draw& w, Size& sz, int i) -{ - Size isz = Img::CR0().GetSize(); - int cnt = tabs.GetCount(); - Tab &t = tabs[i]; - - bool ac = i == active; - bool hl = i == highlight; - - int lx = i > 0 ? style->extendleft : 0; - int x = t.x - sc.GetPos() + style->margin - lx; - - int ndx = !IsEnabled() ? CTRL_DISABLED : - ac ? CTRL_PRESSED : - hl ? CTRL_HOT : CTRL_NORMAL; - - Image nimg; - - int cx = t.cx + lx + (ac ? style->sel.right + style->sel.left : 0); - int cy = ac ? t.cy - style->sel.top + style->sel.bottom : t.cy - style->sel.top; - - int h = style->sel.top + style->sel.bottom; - int hs = ac ? 0 : h; - if(layout == LAYOUT_RIGHT || layout == LAYOUT_BOTTOM) - hs = -hs; - - ImageDraw img(cx, cy); - - img.DrawRect(0, 0, cx, cy, SColorFace); - - const Value& sv = (cnt == 1 ? style->both : i == 0 ? style->first : i == cnt - 1 ? style->last : style->normal)[ndx]; - - ChPaint(img, 0, 0, cx, cy, sv); - - if(crosses && tabs.GetCount() > 1) - img.DrawImage(t.cx - isz.cx - QT_MARGIN, (cy + h - isz.cy) / 2, - (ac || hl) ? (cross == i ? Img::CR2 : ac ? Img::CR1 : Img::CR0) : - Img::CR0); - - if(file_icons) - { - Image icon = Img::ARH; - //Image icon = IdeFileImage(t.name); - img.DrawImage(QT_MARGIN, (cy + hs - icon.GetSize().cx) / 2, icon); - } - - int shift = 0; - switch(layout) - { - case LAYOUT_LEFT: - nimg = MirrorVert(RotateAntiClockwise(img)); - break; - case LAYOUT_TOP: - nimg = img; - break; - case LAYOUT_RIGHT: - nimg = RotateClockwise(img); - shift = QT_SBSEPARATOR; - break; - case LAYOUT_BOTTOM: - nimg = MirrorVert(img); - shift = QT_SBSEPARATOR; - break; - } - - if(ac) - w.DrawImage(horizontal ? x - style->sel.left : shift, - horizontal ? shift : x - style->sel.left, - nimg); - else - w.DrawImage(horizontal ? x : style->sel.left - shift, - horizontal ? style->sel.top - shift : x, - nimg); - - DrawLabel(w, x, cy + hs, t); -} - -void QuickTabs::Paint(Draw &w) -{ - Size sz = GetSize(); - w.DrawRect(sz, SColorFace/*LtRed*/); - - if(!horizontal) - w.DrawRect(layout == LAYOUT_LEFT ? sz.cx - 1 : 0, 0, - 1, sz.cy, Color(128, 128, 128)); - else - w.DrawRect(0, layout == LAYOUT_TOP ? sz.cy - 1 : 0, - sz.cx, 1, Color(128, 128, 128)); - - Fix(sz); - - for(int i = 0; i < tabs.GetCount(); i++) - if(tabs[i].visible && i != active) - DrawTab(w, sz, i); - - if(active >= 0) - DrawTab(w, sz, active); - - if(target >= 0) - { - int last = GetLast(); - int first = GetFirst(); - - if(target != active && target != active + 1) - { - - int x = (target == last + 1 ? tabs[last].Right() : tabs[target].x) - - sc.GetPos() - (target <= first ? 1 : 2) - + style->margin - (target > 0 ? style->extendleft : 0); - - int y = style->sel.top; - - int cy = sz.cy - y; - - Color c(255, 0, 0); - if(horizontal) - { - w.DrawRect(x + 1, y, 2, cy, c); - w.DrawRect(x, y, 4, 1, c); - w.DrawRect(x, y + cy - 1, 4, 1, c); - } - else - { - Swap(x, y); - w.DrawRect(x, y + 1, cy, 2, c); - w.DrawRect(x, y, 1, 4, c); - w.DrawRect(x + cy - 1, y, 1, 4, c); - } - } - } -} - -void QuickTabs::Scroll() -{ - Refresh(); -} - -int QuickTabs::GetWidth(int n) -{ - Tab &t = tabs[n]; - t.tsz = GetTextSize(GetFileName(t.name), StdFont()); - return QT_MARGIN * 2 + t.tsz.cx + (QT_SPACE + Img::CR0().GetSize().cx) * crosses - + (QT_FILEICON + QT_SPACEICON) * file_icons; -} - -void QuickTabs::Add(const char *name, bool make_active) -{ - Tab &t = tabs.Add(); - - int cnt = tabs.GetCount() - 1; - t.name = name; - t.group = GetFileFolder(name); - t.id = GetNextId(); - MakeGroups(); - Repos(); - SetCursor(tabs.GetCount() - 1); -} - -int QuickTabs::GetWidth() -{ - int j = GetLast(); - return tabs[GetLast()].Right() + style->margin * 2; -} - -int QuickTabs::GetHeight() -{ - return style->tabheight + style->sel.top + QT_SBHEIGHT + QT_SBSEPARATOR; -} - -void QuickTabs::Repos() -{ - if(!tabs.GetCount()) - return; - - String g = GetGroupName(); - - int j = 0; - bool first = true; - for(int i = 0; i < tabs.GetCount(); i++) - { - bool v = IsNull(g) ? true : g == tabs[i].group; - if(v) - { - tabs[i].x = first ? 0 : tabs[j].Right(); - j = i; - first = false; - } - else - tabs[i].x = 0; - - tabs[i].visible = v; - tabs[i].y = 0; - tabs[i].cx = GetWidth(i); - tabs[i].cy = style->tabheight + style->sel.top; - } - sc.SetTotal(GetWidth()); -} - -int QuickTabs::Find(int id) -{ - for(int i = 0; i < tabs.GetCount(); i++) - if(tabs[i].id == id) - return i; - return -1; -} - -int QuickTabs::GetNext(int n) -{ - for(int i = n + 1; i < tabs.GetCount(); i++) - if(tabs[i].visible) - return i; - return -1; -} - -int QuickTabs::GetPrev(int n) -{ - for(int i = n - 1; i >= 0; i--) - if(tabs[i].visible) - return i; - return -1; -} - -void QuickTabs::Clear() -{ - tabs.Clear(); - Refresh(); -} - -QuickTabs& QuickTabs::FileIcons(bool b) -{ - file_icons = b; - Repos(); - return *this; -} - -QuickTabs& QuickTabs::Crosses(bool b) -{ - crosses = b; - Repos(); - return *this; -} - -QuickTabs& QuickTabs::Grouping(bool b) -{ - grouping = b; - return *this; -} - -void QuickTabs::LeftDown(Point p, dword keyflags) -{ - if(keyflags & K_SHIFT) - { - highlight = -1; - Refresh(); - SetCapture(); - oldp = p; - return; - } - - isctrl = keyflags & K_CTRL; - if(isctrl) - return; - - if(cross != -1) - Close(cross); - else if(highlight >= 0) - SetCursor(highlight); -} - -void QuickTabs::LeftUp(Point p, dword keyflags) -{ - ReleaseCapture(); -} - -void QuickTabs::RightDown(Point p, dword keyflags) -{ - MenuBar::Execute(THISBACK(Menu), GetMousePos()); -} - -void QuickTabs::MiddleDown(Point p, dword keyflags) -{ - Close(highlight); -} - -void QuickTabs::MiddleUp(Point p, dword keyflags) -{ -} - -int QuickTabs::GetTargetTab(Point p) -{ - Fix(p); - p.x += sc.GetPos(); - - - int f = GetFirst(); - int l = GetLast(); - - if(tabs[f].visible && p.x < tabs[f].x + tabs[f].cx / 2) - return f; - - for(int i = l; i >= f; i--) - if(tabs[i].visible && p.x >= tabs[i].x + tabs[i].cx / 2) - return i == l ? i + 1 : GetNext(i); - return -1; -} - -void QuickTabs::MouseWheel(Point p, int zdelta, dword keyflags) -{ - sc.AddPos(-zdelta / 4, true); - MouseMove(p, 0); -} - -void QuickTabs::MouseMove(Point p, dword keyflags) -{ - Fix(p); - if(HasCapture()) - { - sc.AddPos(p.x - oldp.x, true); - oldp = p; - return; - } - - p.x += sc.GetPos() - style->margin; - Size sz = GetSize(); - Fix(sz); - int h = highlight; - bool iscross = false; - bool istab = false; - for(int i = 0; i < tabs.GetCount(); i++) - { - Point np(p.x + (i > 0 ? style->extendleft : 0), p.y); - if(tabs[i].HasMouse(np)) - { - istab = true; - //int h = sz.cy + (active == i ? 0 : style->sel.top); - int h = style->sel.top + style->sel.bottom; - int hs = active == i ? style->sel.top : h; - if(layout == LAYOUT_RIGHT || layout == LAYOUT_BOTTOM) - hs = -hs; - hs += sz.cy; - int ws = active == i ? style->sel.left : 0; - - iscross = crosses ? tabs[i].HasMouseCross(np, ws, hs) : false; - if(highlight != i || (iscross && cross != i)) - { - cross = iscross ? i : -1; - highlight = i; - Refresh(); - return; - } - } - } - - if(!istab && h >= 0) - { - highlight = -1; - Refresh(); - } - - if(!iscross && cross >= 0) - { - cross = -1; - Refresh(); - } -} - -void QuickTabs::MouseLeave() -{ - if(isdrag) - return; - - highlight = -1; - cross = -1; - Refresh(); -} - -void QuickTabs::DragAndDrop(Point p, PasteClip& d) -{ - int c = GetTargetTab(p); - int tab = isctrl ? highlight : active; - - 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]; - tabs.Insert(c, t); - tabs.Remove(tab + int(c < tab)); - active = Find(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 - } - - if(c != target) - { - target = c; - Refresh(); - } -} - -void QuickTabs::CancelMode() -{ - isdrag = false; - target = -1; - Refresh(); -} - -void QuickTabs::LeftDrag(Point p, dword keyflags) -{ - if(keyflags & K_SHIFT) - return; - if(highlight < 0) - return; - - isdrag = true; - DoDragAndDrop(InternalClip(*this, "tabs")); -} - -void QuickTabs::DragEnter() -{ -} - -void QuickTabs::DragLeave() -{ - target = -1; - Refresh(); -} - -void QuickTabs::DragRepeat(Point p) -{ - if(target >= 0) - { - int dx = GetDragScroll(this, p, 16).x; - if(dx != 0) - sc.AddPos(dx); - } -} - -void QuickTabs::SetCursor(int n) -{ - if(tabs.GetCount() == 0) - return; - - if(n < 0) - { - n = max(0, Find(GetActiveGroup())); - 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(); - } - - SetActiveGroup(tabs[n].id); - - int cx = tabs[n].x - sc.GetPos(); - if(cx < 0) - sc.AddPos(cx - 10); - else - { - cx = tabs[n].x + tabs[n].cx - GetSize().cx - sc.GetPos(); - if(cx > 0) - sc.AddPos(cx + 10); - } - if(HasMouse()) - MouseMove(GetMouseViewPos(), 0); - - UpdateActionRefresh(); -} - -void QuickTabs::Close(int n) -{ - if(tabs.GetCount() <= 1) - return; - - if(n == active) - { - int c = Find(tabs[n].id); - int nc = GetNext(c); - if(nc < 0) - nc = max(0, GetPrev(c)); - - SetActiveGroup(tabs[nc].id); - } - sc.AddTotal(-tabs[n].cx); - tabs.Remove(n); - MakeGroups(); - Repos(); - SetCursor(-1); -} - -bool QuickTabs::FindSetFile(const String& fn) -{ - for(int i = 0; i < tabs.GetCount(); i++) - if(tabs[i].name == fn) { - SetCursor(i); - return true; - } - return false; -} - -void QuickTabs::SetAddFile(const String& fn) -{ - if(IsNull(fn)) - return; - if(FindSetFile(fn)) - return; - Add(fn, true); - Refresh(); -} - -void QuickTabs::RenameFile(const String& fn, const String& nn) -{ - for(int i = 0; i < tabs.GetCount(); i++) - if(tabs[i].name == fn) - { - tabs[i].name = nn; - tabs[i].group = GetFileFolder(nn); - } - Repos(); -} - -void QuickTabs::Set(const QuickTabs& t) -{ - active = t.active; - file_icons = t.file_icons; - crosses = t.crosses; - grouping = t.grouping; - - cross = -1; - highlight = -1; - target = -1; - - tabs.SetCount(t.GetCount()); - for(int i = 0; i < t.GetCount(); i++) - { - tabs[i].name = t.tabs[i].name; - tabs[i].group = t.tabs[i].group; - } - MakeGroups(); - SetGroup(t.GetGroup()); - Repos(); - sc.Set(t.sc); -} - -QuickTabs& QuickTabs::SetLayout(int l) -{ - layout = l; - switch(l) - { - case LAYOUT_LEFT: - horizontal = sc.horizontal = false; - sc.layout = LAYOUT_RIGHT; - break; - case LAYOUT_TOP: - horizontal = sc.horizontal = true; - sc.layout = LAYOUT_BOTTOM; - break; - case LAYOUT_RIGHT: - horizontal = sc.horizontal = false; - sc.layout = LAYOUT_LEFT; - break; - case LAYOUT_BOTTOM: - horizontal = sc.horizontal = true; - sc.layout = LAYOUT_TOP; - break; - } - RefreshLayout(); - return *this; -} - diff --git a/bazaar/QuickTabs/QuickTabs.h b/bazaar/QuickTabs/QuickTabs.h deleted file mode 100644 index ea8bf611a..000000000 --- a/bazaar/QuickTabs/QuickTabs.h +++ /dev/null @@ -1,221 +0,0 @@ -#ifndef _QuickTabs_QuickTabs_h -#define _QuickTabs_QuickTabs_h - -#include - -using namespace Upp; - -#define IMAGECLASS Img -#define IMAGEFILE -#include - -enum -{ - QT_MARGIN = 6, - QT_SPACE = 10, - QT_SBHEIGHT = 4, - QT_SBSEPARATOR = 1, - QT_FILEICON = 16, - QT_SPACEICON = 5 -}; - -struct FloatFrame : FrameCtrl -{ - enum - { - LAYOUT_LEFT = 0, - LAYOUT_TOP = 1, - LAYOUT_RIGHT = 2, - LAYOUT_BOTTOM = 3 - }; - - int layout; - int size; - int border; - - bool horizontal; - - FloatFrame() : border(0), size(0), layout(LAYOUT_TOP), horizontal(true) {} - virtual void FrameLayout(Rect &r); - virtual void FrameAddSize(Size& sz); - virtual void FramePaint(Draw& w, const Rect& r); - void Fix(Size& sz); - void Fix(Point& p); -}; - -class TabScrollBar : public FloatFrame -{ - private: - int total; - double pos, ps; - int new_pos; - int old_pos; - double start_pos; - double size; - double cs, ics; - void UpdatePos(bool update = true); - 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 Set(const TabScrollBar& t); - Callback WhenScroll; -}; - -struct Tab : Moveable -{ - String name; - String group; - bool visible; - int x, cx; - int y, cy; - int id; - Size tsz; - Tab() : visible(true), id(-1) - {} - int Right() { return x + cx; } - bool HasMouse(const Point& p); - bool HasMouseCross(const Point& p, int w, int h); -}; - -struct Group : Moveable -{ - Group() {} - String name; - String path; - int active; - int count; - int first; - int last; -}; - -class QuickTabs : public FloatFrame -{ - public: - - private: - - int id; - TabScrollBar sc; - void Scroll(); - - Vector groups; - Vector tabs; - int highlight; - int active; - int target; - int cross; - bool crosses; - bool file_icons; - bool isctrl; - bool isdrag; - bool grouping; - Point mouse, oldp; - int group; - - const TabCtrl::Style *style; - - virtual void Paint(Draw &w); - virtual void LeftDown(Point p, dword keysflags); - virtual void LeftUp(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); - - void DrawTab(Draw& w, Size &sz, int i); - void DrawLabel(Draw& w, int x, int y, Tab& t); - void Repos(); - int Find(int id); - int GetNext(int n); - int GetPrev(int n); - - int GetWidth(int n); - int GetTargetTab(Point p); - - int GetWidth(); - int GetHeight(); - - void Menu(Bar& bar); - void GroupMenu(Bar &bar, int n); - - void CloseAll(); - - void MakeGroups(); - int FindGroup(const String& g); - - void DoGrouping(int n); - void DoCloseGroup(int n); - - String GetGroupName() const { return group == 0 ? Null : groups[group].path; } - int SetGroup(const String &s) { group = max(0, FindGroup(s)); return group; } - int SetGroup(int c) { int t = group; group = c; return group; } - int GetGroup() const { return group; } - void SetActiveGroup(int id) { groups[group].active = id; } - int GetActiveGroup() 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; } - - public: - Callback WhenCloseRest; - - QuickTabs(); - - void Add(const char *name, bool make_active = false); - void Close(int n); - void Clear(); - - QuickTabs& FileIcons(bool b = true); - QuickTabs& Crosses(bool b = true); - QuickTabs& Grouping(bool b = true); - - typedef QuickTabs CLASSNAME; - - int GetCount() const { return tabs.GetCount(); } - int GetCursor() const { return active; } - String GetFile(int n) const { return tabs[n].name; } - bool FindSetFile(const String& fn); - void SetAddFile(const String& fn); - void RenameFile(const String& fn, const String& nn); - void Set(const QuickTabs& t); - - QuickTabs& SetLayout(int l); - - QuickTabs& SetStyle(const TabCtrl::Style& s) { style = &s; Refresh(); return *this; } - static const TabCtrl::Style& StyleDefault(); - - int GetNextId(); - - const Vector& GetTabs() { return tabs; } - int GetPos() { return sc.GetPos(); } - - void SetCursor(int n); -}; - -#endif diff --git a/bazaar/QuickTabs/QuickTabs.iml b/bazaar/QuickTabs/QuickTabs.iml deleted file mode 100644 index b858ca254..000000000 --- a/bazaar/QuickTabs/QuickTabs.iml +++ /dev/null @@ -1,101 +0,0 @@ -PREMULTIPLIED -IMAGE_ID(BA) -IMAGE_ID(BH) -IMAGE_ID(BN) -IMAGE_ID(LA) -IMAGE_ID(LH) -IMAGE_ID(RA) -IMAGE_ID(RH) -IMAGE_ID(RN) -IMAGE_ID(DND) -IMAGE_ID(LN) -IMAGE_ID(CR0) -IMAGE_ID(CR1) -IMAGE_ID(CR2) -IMAGE_ID(UD) -IMAGE_ID(UD2) -IMAGE_ID(CHK) -IMAGE_ID(AD) -IMAGE_ID(AR) -IMAGE_ID(ARH) - -IMAGE_BEGIN_DATA -IMAGE_DATA(120,156,237,154,9,108,84,215,21,134,71,74,147,32,148,86,81,33,138,186,168,161,85,81,165,86,170,26,85,170,18,213) -IMAGE_DATA(144,218,98,80,12,178,193,1,146,154,136,69,74,28,182,0,45,78,41,78,33,114,98,21,146,180,180,13,9,105,138,205) -IMAGE_DATA(226,221,216,120,55,54,222,247,109,12,6,19,140,61,227,241,224,89,188,239,118,241,70,212,191,231,92,124,135,251,134,177) -IMAGE_DATA(141,52,173,70,145,252,208,167,119,255,119,207,121,239,190,247,223,227,123,109,161,123,90,247,93,157,60,190,159,92,7,79) -IMAGE_DATA(24,27,27,243,136,153,153,25,143,152,158,158,254,90,51,53,53,229,17,147,147,147,94,101,98,98,194,171,12,15,15,123) -IMAGE_DATA(68,79,79,143,87,233,237,237,245,42,222,30,127,127,127,191,87,25,24,24,240,136,193,193,65,143,24,26,26,242,8,79) -IMAGE_DATA(231,191,183,209,169,139,81,84,84,20,60,97,113,49,90,92,140,22,23,163,197,197,104,113,49,90,92,140,60,94,140,202) -IMAGE_DATA(202,202,224,9,163,163,163,30,97,183,219,61,194,102,179,121,21,171,213,250,181,198,219,223,207,83,44,22,139,71,24,141) -IMAGE_DATA(70,143,48,153,76,30,209,214,214,230,17,102,179,217,35,218,219,219,189,202,157,59,119,60,194,219,243,223,225,112,120,68) -IMAGE_DATA(103,103,167,71,120,123,49,9,15,15,247,8,221,55,148,197,200,245,207,117,178,221,210,210,34,86,110,110,183,82,123,124) -IMAGE_DATA(124,92,236,228,89,115,155,119,229,188,51,149,127,170,187,123,247,174,56,75,205,49,140,140,231,133,71,246,75,205,72,61) -IMAGE_DATA(50,50,34,144,154,95,212,85,51,82,247,245,245,9,164,230,137,193,139,147,170,153,185,250,229,98,166,106,158,28,82,115) -IMAGE_DATA(91,237,151,19,71,106,110,119,117,117,57,53,183,93,117,119,119,183,83,203,157,164,170,121,103,200,90,53,215,85,187,53) -IMAGE_DATA(75,254,90,202,237,164,164,36,167,89,201,201,201,26,179,162,163,163,53,102,197,198,196,104,204,138,139,139,213,152,21,31) -IMAGE_DATA(31,167,49,43,41,49,81,99,22,223,95,53,235,82,74,138,198,172,212,75,151,52,102,165,165,165,106,204,74,79,79,215) -IMAGE_DATA(152,145,153,145,161,49,43,39,59,91,211,159,147,147,163,49,43,247,114,174,198,172,188,188,60,141,89,249,249,249,26,179) -IMAGE_DATA(164,150,102,21,20,20,104,204,42,44,44,212,152,85,82,82,162,49,171,112,54,94,154,197,90,53,199,85,107,204,82,43) -IMAGE_DATA(138,15,54,136,141,146,215,216,32,190,121,235,236,53,54,136,141,146,85,227,90,85,210,36,181,202,216,20,25,47,77,146) -IMAGE_DATA(90,154,164,106,30,164,212,114,208,82,75,147,164,150,91,61,169,165,73,115,245,75,147,164,150,166,168,253,124,77,106,54) -IMAGE_DATA(69,213,108,2,95,83,53,35,53,27,164,106,105,146,212,242,247,60,215,247,115,87,85,194,3,213,172,200,200,72,49,219) -IMAGE_DATA(93,205,226,234,114,53,139,171,64,53,139,171,76,53,139,171,76,53,75,86,153,52,135,171,76,53,139,159,171,154,197,247) -IMAGE_DATA(87,205,226,42,83,205,226,42,83,205,226,42,83,205,224,42,83,205,226,42,83,251,185,202,84,179,184,202,84,179,184,202) -IMAGE_DATA(84,179,184,202,84,179,184,170,84,179,164,150,230,112,149,169,102,113,149,169,102,113,149,169,102,45,84,85,172,53,102,149) -IMAGE_DATA(150,150,162,170,170,202,105,22,255,134,200,27,203,242,242,114,113,173,163,163,67,124,112,190,86,83,83,227,252,24,124,173) -IMAGE_DATA(130,98,84,93,89,89,233,220,152,184,211,85,85,90,93,77,207,85,243,107,170,171,181,186,198,85,215,56,55,190,172,107) -IMAGE_DATA(73,203,141,172,208,181,181,206,141,41,235,58,210,114,163,201,186,190,190,222,185,113,148,90,110,228,220,105,131,193,224,220) -IMAGE_DATA(168,177,110,104,104,208,140,191,193,208,160,25,31,107,185,49,146,241,143,162,165,57,172,231,221,96,212,252,84,7,21,245) -IMAGE_DATA(154,107,204,162,254,255,235,135,252,112,183,193,224,234,226,42,227,54,87,21,207,94,174,50,57,155,121,38,112,149,113,53) -IMAGE_DATA(113,91,206,40,174,30,119,90,206,64,174,38,85,115,53,169,154,171,73,205,231,106,210,234,26,141,174,157,213,178,194,184) -IMAGE_DATA(154,88,203,10,171,155,213,178,194,184,90,88,203,10,147,90,86,152,212,178,162,184,154,84,205,179,157,181,172,48,174,30) -IMAGE_DATA(117,252,82,203,241,201,120,89,65,143,162,101,101,177,126,168,178,190,69,255,228,113,96,255,190,240,211,159,158,202,46,43) -IMAGE_DATA(45,70,81,97,254,188,148,22,23,130,99,101,78,69,121,41,140,173,183,97,105,111,67,187,217,228,22,238,107,51,181,130) -IMAGE_DATA(99,239,63,167,8,55,174,95,197,205,166,70,52,221,184,54,47,50,166,184,40,95,192,121,215,27,27,4,215,174,214,139) -IMAGE_DATA(190,198,107,6,231,53,21,142,173,40,47,209,228,113,108,199,29,51,186,187,236,206,220,78,135,85,192,49,146,242,178,98) -IMAGE_DATA(228,230,102,227,26,245,95,165,231,52,54,242,143,43,43,173,69,118,113,182,90,45,162,205,24,12,181,180,100,148,208,71) -IMAGE_DATA(175,67,17,61,43,61,53,5,13,245,181,168,175,173,70,93,77,149,56,219,58,44,112,216,58,156,240,119,204,201,202,64) -IMAGE_DATA(222,229,108,65,86,70,26,82,146,19,81,95,87,77,147,177,82,80,83,93,65,223,207,8,27,61,139,225,113,23,22,228) -IMAGE_DATA(33,255,202,101,113,46,42,188,130,244,180,20,36,196,199,136,248,234,170,114,145,211,102,106,161,111,110,18,200,54,223,71) -IMAGE_DATA(126,139,210,146,66,90,251,47,210,254,226,188,136,175,170,44,19,125,95,222,188,46,226,249,190,57,217,25,228,107,179,128) -IMAGE_DATA(253,226,28,62,243,24,99,163,207,163,170,162,12,149,228,103,97,126,158,120,95,62,243,123,240,57,55,39,11,217,153,233) -IMAGE_DATA(40,42,184,130,178,146,34,148,211,188,186,148,156,68,251,147,56,241,252,146,226,2,228,209,183,189,156,147,73,123,132,44) -IMAGE_DATA(241,62,252,76,190,206,253,242,121,236,65,124,92,180,152,51,23,147,226,133,86,199,194,154,199,93,89,81,170,33,51,35) -IMAGE_DATA(85,51,71,147,18,226,196,251,186,35,45,53,89,144,152,16,235,204,209,20,7,31,135,223,124,35,220,248,198,46,52,7) -IMAGE_DATA(4,205,75,203,235,59,192,177,50,199,180,119,63,134,170,232,39,65,51,173,193,183,140,238,161,190,17,195,117,152,246,188) -IMAGE_DATA(45,114,91,67,118,163,43,54,21,221,201,57,232,74,202,186,79,66,230,131,118,226,44,212,238,190,152,77,231,108,220,222) -IMAGE_DATA(178,21,183,54,110,65,103,108,6,28,103,47,10,108,255,140,163,184,76,216,35,19,97,143,74,130,227,92,178,64,180,57) -IMAGE_DATA(38,58,21,173,187,247,163,121,227,102,202,75,167,62,202,249,34,14,255,182,88,113,111,106,146,238,155,73,58,22,83,35) -IMAGE_DATA(163,2,199,5,202,191,144,2,71,76,26,140,33,251,80,19,184,65,104,123,100,60,28,241,105,152,158,156,192,189,123,51) -IMAGE_DATA(152,161,243,228,192,128,104,51,150,127,197,192,188,255,61,56,62,143,70,227,91,123,144,229,191,14,157,103,226,97,59,125) -IMAGE_DATA(30,29,167,206,162,57,58,14,83,180,225,157,161,141,177,164,226,248,95,209,232,19,0,211,170,87,97,246,217,140,226,117) -IMAGE_DATA(65,136,209,175,69,215,39,95,192,118,242,83,226,20,172,39,78,98,136,54,142,147,19,147,130,49,250,73,119,123,107,8) -IMAGE_DATA(236,171,233,125,244,193,232,37,178,253,3,113,202,207,15,221,20,107,139,248,16,182,63,127,132,62,171,13,125,253,131,24) -IMAGE_DATA(24,28,70,119,103,23,250,169,221,223,221,139,129,144,80,140,232,183,96,204,63,24,201,47,175,67,196,106,31,116,135,29) -IMAGE_DATA(131,237,112,24,44,161,71,208,220,216,4,27,197,23,28,141,64,238,107,219,97,233,176,194,76,88,66,14,98,84,255,42) -IMAGE_DATA(198,41,239,220,26,61,194,95,242,65,239,190,3,176,147,159,183,131,118,34,89,31,136,156,176,247,112,211,103,131,24,91) -IMAGE_DATA(238,142,93,72,217,246,22,28,126,65,24,245,255,237,253,60,189,30,31,109,8,128,37,104,27,108,65,59,112,99,85,48) -IMAGE_DATA(12,47,6,163,241,215,91,232,27,4,163,211,55,24,131,126,175,162,151,24,165,247,26,33,198,253,183,226,184,175,175,152) -IMAGE_DATA(51,159,173,245,69,255,230,32,244,236,13,68,231,129,64,244,254,46,16,131,135,2,49,26,26,136,187,127,8,192,132,228) -IMAGE_DATA(157,13,72,219,164,215,204,209,15,252,245,136,90,175,199,153,245,107,112,38,96,13,34,233,124,54,208,15,231,2,238,115) -IMAGE_DATA(129,218,199,95,242,117,230,60,84,28,159,135,30,74,168,255,225,10,148,235,116,243,82,253,204,51,224,88,153,99,120,106) -IMAGE_DATA(57,122,18,50,48,84,209,128,161,82,131,123,168,175,63,35,31,134,165,203,68,110,221,138,21,48,135,70,160,253,216,223) -IMAGE_DATA(208,254,238,95,238,115,228,227,7,237,176,89,184,125,244,36,157,79,162,114,233,82,84,208,243,205,161,39,96,220,115,84) -IMAGE_DATA(208,178,227,29,138,251,24,173,33,97,84,4,127,130,113,239,49,129,104,83,191,233,247,17,168,91,178,28,149,50,143,250) -IMAGE_DATA(90,118,254,17,227,77,45,248,207,244,140,184,127,203,206,195,152,25,26,22,152,14,132,195,116,240,125,152,14,29,135,225) -IMAGE_DATA(177,101,72,165,188,118,186,135,113,87,24,204,71,78,224,43,154,212,124,112,238,116,79,31,228,113,243,205,195,184,241,236) -IMAGE_DATA(11,104,223,17,138,252,199,159,198,223,41,207,178,231,93,24,119,30,66,203,182,253,168,166,201,39,115,229,145,244,242,70) -IMAGE_DATA(20,80,220,117,162,137,56,79,28,38,58,94,15,129,113,211,118,24,95,217,134,86,255,77,24,180,118,80,1,126,37,24) -IMAGE_DATA(31,30,69,173,110,9,218,249,254,68,39,241,15,98,43,97,243,127,5,70,191,117,48,174,13,64,151,137,86,198,190,65) -IMAGE_DATA(244,209,59,217,172,118,244,80,187,199,209,133,222,37,43,49,76,177,227,196,251,132,47,97,127,254,5,152,126,246,60,190) -IMAGE_DATA(92,249,115,84,23,151,195,68,241,81,191,242,195,103,212,119,171,213,132,38,162,121,233,115,24,35,125,151,56,72,248,240) -IMAGE_DATA(179,159,253,1,204,203,190,131,58,106,127,64,124,242,139,23,197,252,224,177,157,214,125,19,17,186,167,68,91,205,91,191) -IMAGE_DATA(124,25,110,209,217,68,148,16,185,132,252,6,252,62,253,179,239,196,57,195,179,121,107,9,158,51,219,233,220,67,56,190) -IMAGE_DATA(77,177,223,163,184,231,40,254,71,20,251,99,29,166,126,162,195,180,100,165,14,31,206,230,200,57,186,154,230,206,94,186) -IMAGE_DATA(182,139,216,77,236,33,222,38,14,204,142,235,16,161,87,114,104,15,252,152,179,48,104,196,112,199,170,95,234,86,51,178) -IMAGE_DATA(29,240,27,93,160,72,120,156,210,23,74,86,81,227,212,138,116,213,226,120,146,254,61,194,241,112,226,131,235,112,211,15) -IMAGE_DATA(55,184,139,159,43,110,161,251,207,61,174,39,117,79,204,17,59,239,224,23,26,236,255,102,112,115,29,79,60,236,194,66) -IMAGE_DATA(95,124,174,235,11,57,241,168,241,11,143,199,117,208,234,31,35,93,175,187,235,83,255,55,238,92,215,213,190,133,226,221) -IMAGE_DATA(221,223,245,218,127,1,218,41,220,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) -IMAGE_END_DATA(2496, 19) diff --git a/bazaar/QuickTabs/QuickTabs.upp b/bazaar/QuickTabs/QuickTabs.upp deleted file mode 100644 index 389dbeadc..000000000 --- a/bazaar/QuickTabs/QuickTabs.upp +++ /dev/null @@ -1,8 +0,0 @@ -uses - CtrlLib; - -file - QuickTabs.h, - QuickTabs.cpp, - QuickTabs.iml; - diff --git a/bazaar/QuickTabs/init b/bazaar/QuickTabs/init deleted file mode 100644 index 4d46d361e..000000000 --- a/bazaar/QuickTabs/init +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _QuickTabs_icpp_init_stub -#define _QuickTabs_icpp_init_stub -#include "CtrlLib/init" -#endif diff --git a/bazaar/TabBar/TabBar.cpp b/bazaar/TabBar/TabBar.cpp index a58d013df..3ce1fff4f 100644 --- a/bazaar/TabBar/TabBar.cpp +++ b/bazaar/TabBar/TabBar.cpp @@ -1,1597 +1,1911 @@ -#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(false)); - BackPaint(); -} - -void TabBar::CloseAll() -{ - for(int i = tabs.GetCount() - 1; i >= 0; i--) - if(i != highlight) - tabs.Remove(i); - - SyncScrollBar(); - MakeGroups(); - Repos(); - SetCursor(0); - WhenCloseAll(); - Refresh(); -} - -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 >= tab_pos.x && p.x < tab_pos.x + tab_size.cx && - p.y >= tab_pos.y && p.y < tab_pos.y + tab_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(10, 10)); - 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 + 1; - p.y = side == LEFT ? r.bottom - space - cx : r.top + space; - } - else if (align == RIGHT) - { - p.x = r.right - (r.GetWidth() + cy) / 2 - 1; - 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 + 1; - } - else if (align == BOTTOM) - { - p.x = side == LEFT ? r.left + space : r.right - cx - space; - p.y = r.bottom - (r.GetHeight() + cy) / 2 - 1; - } - 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 align = GetAlign(); - int cnt = dragsample ? 1 : tabs.GetCount(); - int sep = TB_SBSEPARATOR * sc.IsVisible(); - - 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() - lx + s.margin; - - Point pa = Point(x - s.sel.left, 0); - Size sa = Size(t.size.cx + lx + s.sel.right + s.sel.left, t.size.cy + s.sel.bottom); - - Point pn = Point(x, s.sel.top); - Size sn = Size(t.size.cx + lx, t.size.cy - s.sel.top); - - int dy = -s.sel.top * ac; - int sel = s.sel.top; - - if (align == BOTTOM || align == RIGHT) - { - pa.y -= s.sel.bottom - sep; - pn.y -= s.sel.top - sep; - dy = -dy; - sel = s.sel.bottom; - } - - Rect ra(Fixed(pa), Fixed(sa)); - Rect rn(Fixed(pn), Fixed(sn)); - - t.tab_pos = (ac ? ra : rn).TopLeft(); - t.tab_size = (ac ? ra : rn).GetSize(); - - if(dragsample) - { - ChPaint(w, Rect(Point(0, 0), t.tab_size), sv); - rn = Rect(Fixed(Point(s.sel.left * ac, sel * ac + dy)), Fixed(sn)); - } - else - { - ChPaint(w, Rect(t.tab_pos, t.tab_size), sv); - rn = Rect(Fixed(Point(pn.x, pn.y + dy)), Fixed(sn)); - } - - #ifdef TABBAR_DEBUG - DrawFrame(w, rn, Green); - #endif - - if(crosses && (cnt > neverempty || t.stack.GetCount()) || dragsample) { - t.cross_size = TabBarImg::CR0().GetSize(); - t.cross_pos = GetImagePosition(rn, t.cross_size.cx, t.cross_size.cy, TB_MARGIN, RIGHT); - w.DrawImage(t.cross_pos.x, t.cross_pos.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 tab_size for non-visible tabs to prevent mouse handling bugs - for (int i = 0; i < first; i++) - tabs[i].tab_size = Size(0, 0); - for (int i = last+1; i < tabs.GetCount(); i++) - tabs[i].tab_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); - - if (IsHorz()) - DrawVertDrop(w, x + 1, 0, sz.cy); - else - DrawHorzDrop(w, 0, x + 1, sz.cx); - } - // Draw transparent drag image - Point mouse = GetMousePos() - GetScreenRect().TopLeft(); - Size isz = dragtab.GetSize(); - int p = 0; - int sep = TB_SBSEPARATOR * sc.IsVisible(); - - int top = drag == active ? st.sel.bottom : st.sel.top; - if (align == BOTTOM || align == RIGHT) - p = int(drag == active) * -top + sep; - else - p = int(drag != active) * top; - - if (IsHorz()) - w.DrawImage(mouse.x - isz.cx / 2, p, isz.cx, isz.cy, dragtab); - else - w.DrawImage(p, 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 &t = tabs[n]; - - Size tsz(t.tab_size); - ImageDraw iw(tsz); - iw.DrawRect(tsz, SColorFace()); //this need to be fixed - if inactive tab is dragged gray edges are visible - - PaintTab(iw, *style[GetAlign()], tsz, n, true, true); - - 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); - } - } - - Tab& t = tabs[i]; - - t.visible = v; - t.pos.y = 0; - t.size.cx = GetWidth(i); - t.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), 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 && internal && d.IsAccepted()) - { - int id = active >= 0 ? tabs[active].id : -1; - Tab t = tabs[tab]; - Tab &n = tabs.Insert(c); - n = t; - tabs.Remove(tab + int(c < tab)); - active = id >= 0 ? FindId(id) : -1; - isdrag = false; - target = -1; - MakeGroups(); - Repos(); - Refresh(); - Sync(); - MouseMove(p, 0); - } - else if(isdrag) - { - if(internal) - { - target = -1; - isdrag = false; - } - else - 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) +{ + sz = GetSize(); + Fix(sz); + total += t; + if(total <= 0 || sz.cx <= 0) + cs = ics = 0; + else + cs = sz.cx / ((double) total + 0.5); + size = sz.cx * cs; + ps = min(ps, (double)(total-sz.cx)); + pos = (int)(ps * cs); + old_pos = new_pos = (int)(pos - start_pos); + + 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 = false; + groupsort = false; + groupseps = false; + allownullcursor = false; + icons = true; + mintabcount = 1; + + style[0] = style[1] = style[2] = style[3] = NULL; + SetAlign(TOP); + SetFrameSize(GetHeight(false)); + BackPaint(); +} + +void TabBar::CloseAll(int exception) +{ + if (CancelCloseAll()) return; + WhenCloseAll(); + for(int i = tabs.GetCount() - 1; i >= 0; i--) + if(i != exception) + tabs.Remove(i); + + MakeGroups(); + Repos(); + SetCursor(0); + Refresh(); +} + +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", THISBACK1(CloseAll, highlight)); +} + +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 >= tab_pos.x && p.x < tab_pos.x + tab_size.cx && + p.y >= tab_pos.y && p.y < tab_pos.y + tab_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(); + + // Reset stack info + for (int i = 0; i < tabs.GetCount(); i++) { + Tab &t = tabs[i]; + t.stack = -1; + t.stackid = GetStackId(t); + t.sort_order = GetStackSortOrder(t); + } + // Create stacks + Vector > tstack; + for (int i = 0; i < tabs.GetCount(); i++) { + Tab &ti = tabs[i]; + if (ti.stack < 0) { + ti.stack = tstack.GetCount(); + Vector &ttabs = tstack.Add(); + ttabs.Add(ti); + for (int j = i+1; j < tabs.GetCount(); j++) { + Tab &tj = tabs[j]; + if (tj.stack < 0 && tj.stackid == ti.stackid && (!grouping || tj.group == ti.group)) { + tj.stack = ti.stack; + ttabs.Add(tj); + } + } + } + } + stackcount = tstack.GetCount(); + // Recombine + tabs.SetCount(0); + for (int i = 0; i < tstack.GetCount(); i++) { + Sort(tstack[i], TabStackSort()); + tabs.AppendPick(tstack[i]); + } + highlight = -1; + SetData(v); + MakeGroups(); + Repos(); +} + +void TabBar::DoUnstacking() +{ + stackcount = 0; + for (int i = 0; i < tabs.GetCount(); i++) + tabs[i].stack = -1; + highlight = -1; + MakeGroups(); + Repos(); + if (HasCursor()) + SetCursor(-1); + else + Refresh(); +} + +void TabBar::MakeGroups() +{ + groups[0].count = tabs.GetCount(); + groups[0].first = 0; + groups[0].last = tabs.GetCount() - 1; + + if (groupsort) + StableSort(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].value; + if (!CancelClose(v)) { + WhenClose(v); + tabs.Remove(i); + } + } + } + if(cnt > 1) + groups.Remove(n); + MakeGroups(); + Repos(); + SetCursor(-1); +} + +void TabBar::NewGroup(const String &name) +{ + Group &g = groups.Add(); + g.name = name; + 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(10, 10)); + 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; +} + +void TabBar::PaintStackedTab(Draw& w, const Rect &r, const Tab& tab, const Font &font, Color ink, dword style) +{ + if (!IsNull(tab.img)) + w.DrawImage(r.left, r.top, tab.img); + else + w.DrawText(r.left, r.top, "...", font, ink); +} + +void TabBar::PaintTab(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.value; + + 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; + int text_offset = 0; + if (PaintIcons() && !tab.HasIcon()) { + Size isz = min(tab.img.GetSize(), Size(TB_ICON, TB_ICON)); + p = GetImagePosition(r, isz.cx, isz.cy, 2, LEFT); + w.DrawImage(p.x, p.y, isz.cx, isz.cy, tab.img); + text_offset = TB_ICON + 4; + } + p = GetTextPosition(r, GetTextSize(txt, font).cy, text_offset); + w.DrawText(p.x, p.y, GetTextAngle(), 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 + 2; + } + else if(align == RIGHT) + { + p.y = r.top + space; + p.x = r.right - (r.GetWidth() - cy) / 2 - 2; + } + else + { + p.x = r.left + space; + p.y = r.top + (r.GetHeight() - cy) / 2 + (align == TOP ? 2 : -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 + 2; + p.y = side == LEFT ? r.bottom - space - cx : r.top + space; + } + else if (align == RIGHT) + { + p.x = r.right - (r.GetWidth() + cy) / 2 - 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 + 2; + } + else if (align == BOTTOM) + { + p.x = side == LEFT ? r.left + space : r.right - cx - space; + p.y = r.bottom - (r.GetHeight() + cy) / 2 - 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 align = GetAlign(); + int cnt = dragsample ? 1 : tabs.GetCount(); + int sep = TB_SBSEPARATOR * sc.IsVisible(); + + bool ac = n == active; + bool hl = n == highlight || (stacking && highlight >= 0 && tabs[highlight].stack == t.stack); + + 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() - lx + s.margin; + + Point pa = Point(x - s.sel.left, 0); + Size sa = Size(t.size.cx + lx + s.sel.right + s.sel.left, t.size.cy + s.sel.bottom); + + Point pn = Point(x, s.sel.top); + Size sn = Size(t.size.cx + lx, t.size.cy - s.sel.top); + + int dy = (-s.sel.top) * ac; + int sel = s.sel.top; + + if (align == BOTTOM || align == RIGHT) + { + pa.y -= s.sel.bottom - sep; + pn.y -= s.sel.top - sep; + dy = -dy; + sel = s.sel.bottom; + } + + Rect ra(Fixed(pa), Fixed(sa)); + Rect rn(Fixed(pn), Fixed(sn)); + + t.tab_pos = (ac ? ra : rn).TopLeft(); + t.tab_size = (ac ? ra : rn).GetSize(); + + if(dragsample) + { + ChPaint(w, Rect(Point(0, 0), t.tab_size), sv); + rn = Rect(Fixed(Point(s.sel.left * ac, sel * ac + dy)), Fixed(sn)); + } + else + { + ChPaint(w, Rect(t.tab_pos, t.tab_size), sv); + rn = Rect(Fixed(Point(pn.x, pn.y + dy)), Fixed(sn)); + } + + #ifdef TABBAR_DEBUG + DrawFrame(w, rn, Green); + #endif + + if(crosses && cnt > mintabcount && !dragsample) { + t.cross_size = TabBarImg::CR0().GetSize(); + t.cross_pos = GetImagePosition(rn, t.cross_size.cx, t.cross_size.cy, TB_MARGIN, RIGHT); + w.DrawImage(t.cross_pos.x, t.cross_pos.y, (ac || hl) + ? (cross == n ? TabBarImg::CR2 : ac ? TabBarImg::CR1 : TabBarImg::CR0) + : TabBarImg::CR0); + } + + if (display) + display->Paint(w, rn, t.value, s.text_color[ndx], SColorDisabled(), ndx); + else { + PaintTab(w, rn, t, s.font, s.text_color[ndx], ndx); + if (stacking) { + int ix = n+1; + int lastcx = t.stdcx + TB_MARGIN; + while (ix < tabs.GetCount() && tabs[ix].stack == t.stack) { + Tab &q = tabs[ix]; + + int ndx = !enable ? CTRL_DISABLED : + highlight == ix ? CTRL_HOT : CTRL_NORMAL; + + rn = (align == LEFT) ? Rect(rn.BottomLeft() - Point(0, lastcx + q.size.cx), Size(sn.cy, q.size.cx)) : + (align == RIGHT) ? Rect(rn.TopLeft() + Point(0, lastcx), Size(sn.cy, q.size.cx)) + : Rect(rn.TopLeft() + Point(lastcx, 0), Size(q.size.cx, sn.cy)); + + PaintStackedTab(w, rn, q, s.font, s.text_color[ndx], ndx); + + q.tab_pos = rn.TopLeft(); + q.tab_size = rn.GetSize(); + + lastcx = q.size.cx; + ix++; + } + } + } +} +/* + if (stacking) { + int ix = n+1; + if (align == LEFT) { + rn.bottom += t.stdcx + TB_MARGIN; + rn.top = rn.bottom; + } + else if (align == RIGHT) { + rn.top += t.stdcx + TB_MARGIN; + rn.bottom = rn.top; + } + else { + rn.left += t.stdcx + TB_MARGIN; + rn.right = rn.left; + } + while (ix < tabs.GetCount() && tabs[ix].stack == t.stack) { + Tab &q = tabs[ix]; + if (align == LEFT) { + rn.top = rn.bottom + q.size.cx; + else if (align == RIGHT) + rn.bottom = rn.top + q.size.cx; + else + rn.right = rn.left + q.size.cx; + + int ndx = !enable ? CTRL_DISABLED : + highlight == ix ? CTRL_HOT : CTRL_NORMAL; + + PaintStackedTab(w, rn, q, s.font, s.text_color[ndx], ndx); + + q.tab_pos = rn.TopLeft(); + q.tab_size = rn.GetSize(); + + rn.left = rn.right; + ix++; + } + } + } +*/ +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 tab_size for non-visible tabs to prevent mouse handling bugs + for (int i = 0; i < first; i++) + tabs[i].tab_size = Size(0, 0); + for (int i = last+1; i < tabs.GetCount(); i++) + tabs[i].tab_size = Size(0, 0); + // Draw inactive groups + if (inactivedisabled) + for (int i = first; i <= last; i++) { + if(!tabs[i].visible && i != active && (!stacking || IsStackHead(i))) + PaintTab(w, st, sz, i, !IsEnabled()); + } + + // Draw selected tab + if(active >= first && active <= last) + PaintTab(w, st, sz, active, true); + + // Separators + if (groupseps) { + Size tsz = GetTextSize("|", GetStyle().font); + for (int i = 0; i < separators.GetCount(); i++) { + int x = separators[i]; + if (x > sc.GetPos() && x < limt) { + Point p(x - sc.GetPos() + TB_SPACE/2 - tsz.cx / 2, ((IsVert() ? sz.cx : sz.cy) - tsz.cy) / 2); + Fix(p); + w.DrawText(p.x, p.y, GetTextAngle(), "|", GetStyle().font, GetStyle().text_color[0], 1); + } + } + } + + // 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); + + if (IsHorz()) + DrawVertDrop(w, x + 1, 0, sz.cy); + else + DrawHorzDrop(w, 0, x + 1, sz.cx); + } + // Draw transparent drag image + Point mouse = GetMousePos() - GetScreenRect().TopLeft(); + Size isz = dragtab.GetSize(); + int p = 0; + int sep = TB_SBSEPARATOR * sc.IsVisible(); + + int top = drag == active ? st.sel.bottom : st.sel.top; + if (align == BOTTOM || align == RIGHT) + p = int(drag == active) * -top + sep; + else + p = int(drag != active) * top; + + if (IsHorz()) + w.DrawImage(mouse.x - isz.cx / 2, p, isz.cx, isz.cy, dragtab); + else + w.DrawImage(p, 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 &t = tabs[n]; + + Size tsz(t.tab_size); + ImageDraw iw(tsz); + iw.DrawRect(tsz, SColorFace()); //this need to be fixed - if inactive tab is dragged gray edges are visible + + PaintTab(iw, *style[GetAlign()], tsz, n, true, true); + + 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) +{ + return GetStdSize(tabs[n]).cx + GetExtraWidth(); +} + +int TabBar::GetExtraWidth() +{ + return TB_MARGIN * 2 + (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(WString(q), GetStyle().font); + else + return GetTextSize("A Tab", GetStyle().font); +} + +Size TabBar::GetStackedSize(const Tab &t) +{ + if (!IsNull(t.img)) + return t.img.GetSize(); + return GetTextSize("...", GetStyle().font, 3); +} + +Size TabBar::GetStdSize(const Tab &t) +{ + return (PaintIcons() && t.HasIcon()) ? (GetStdSize(t.value) + Size(TB_ICON+2, 0)) : GetStdSize(t.value); +} + +TabBar& TabBar::Add(const Value &value, Image icon, String group, bool make_active) +{ + return InsertKey(tabs.GetCount(), value, value, icon, group, make_active); +} + +TabBar& TabBar::Insert(int ix, const Value &value, Image icon, String group, bool make_active) +{ + return InsertKey(tabs.GetCount(), value, value, icon, group, make_active); +} + +TabBar& TabBar::AddKey(const Value &key, const Value &value, Image icon, String group, bool make_active) +{ + return InsertKey(tabs.GetCount(), key, value, icon, group, make_active); +} + +TabBar& TabBar::InsertKey(int ix, const Value &key, const Value &value, Image icon, String group, bool make_active) +{ + InsertKey0(ix, key, value, icon, group); + + MakeGroups(); + Repos(); + active = -1; + if (make_active || (!allownullcursor && active < 0)) + SetCursor(minmax(ix, 0, tabs.GetCount() - 1)); + return *this; +} + +void TabBar::InsertKey0(int ix, const Value &key, const Value &value, Image icon, String group) +{ + 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; + Tab t; + t.value = value; + t.key = key; + t.img = icon; + t.id = GetNextId(); + t.group = group; + if (stacking) { + t.stackid = GetStackId(t); + t.sort_order = GetStackSortOrder(t); + + // Override index + int tail = -1; + for (int i = 0; i < tabs.GetCount(); i++) + if (tabs[i].stackid == t.stackid && (!grouping || tabs[i].group == t.group)) + tail = FindStackTail(tabs[i].stack); + if (tail >= 0) { + ix = tail+1; + t.stack = tabs[tail].stack; + tail++; + } + else if (ix < tabs.GetCount()) { + ix = FindStackHead(tabs[ix].stack); + t.stack = stackcount++; + } + tabs.Insert(ix, t); + if (tail >= 0) { + int head = FindStackHead(t.stack); + int headid = tabs[head].id; + Sort(tabs.GetIter(head), tabs.GetIter(tail+1), TabStackSort()); + for (int i = head; i <= tail; i++) + if (tabs[i].id == headid) { + SetStackHead(tabs[i]); + break; + } + } + } + else + tabs.Insert(ix, t); +} + + + +int TabBar::GetWidth() const +{ + if (!tabs.GetCount()) return 0; + int ix = GetLast(); + if (IsStackHead(ix)) + return tabs[ix].Right() + style[GetAlign()]->margin * 2; + int stack = tabs[ix].stack; + ix--; + while (ix >= 0 && tabs[ix].stack == stack) + ix--; + return tabs[ix+1].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; + separators.Clear(); + 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 ishead = IsStackHead(i); + bool v = IsNull(g) ? true : g == tabs[i].group; + Tab& t = tabs[i]; + + if(ishead && (v || inactive)) + { + t.visible = v; + t.pos.y = 0; + t.size.cy = GetStyleHeight(*style[1]); + + // Normal visible or inactive but greyed out tabs + t.pos.x = first ? 0 : tabs[j].Right(); + // Separators + if (groupseps && !first && t.group != tabs[j].group) { + separators.Add(t.pos.x); + t.pos.x += TB_SPACE; + } + + + int cx = GetStdSize(t).cx; + t.stdcx = cx; + // Stacked/shortened tabs + if (stacking) { + int n = i+1; + while (n < tabs.GetCount() && tabs[n].stack == t.stack) { + Tab &q = tabs[n]; + q.visible = false; + q.pos.x = t.pos.x + cx; + q.pos.y = 0; + q.size.cx = GetStackedSize(q).cx; + q.size.cy = t.size.cy; + cx += q.size.cx; + n++; + } + + } + t.size.cx = cx + GetExtraWidth(); + + j = i; + first = false; + } + else if (!(v || inactive)) { + t.visible = false; + t.pos.x = sc.GetTotal() + GetSize().cx; + } + 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; + cross = -1; + id = -1; + stackcount = 0; + tabs.Clear(); + groups.Clear(); + NewGroup("All"); + group = 0; + Refresh(); +} + +TabBar& TabBar::Crosses(bool b) +{ + crosses = b; + Repos(); + Refresh(); + return *this; +} + +TabBar& TabBar::Grouping(bool b) +{ + grouping = b; + return *this; +} + +TabBar& TabBar::GroupSort(bool b) +{ + Value v; + if (b && HasCursor()) + v = GetData(); + groupsort = b; + MakeGroups(); + Repos(); + if (b && HasCursor()) + SetData(v); + Refresh(); + return *this; +} + +TabBar& TabBar::GroupSeparators(bool b) +{ + groupseps = b; + Repos(); + Refresh(); + return *this; +} + +TabBar& TabBar::AutoScrollHide(bool b) +{ + autoscrollhide = b; + sc.Hide(); + SetFrameSize(GetHeight(false), false); + SyncScrollBar(GetWidth()); + return *this; +} + +TabBar& TabBar::InactiveDisabled(bool b) +{ + inactivedisabled = b; + Repos(); + Refresh(); + return *this; +} + +TabBar& TabBar::AllowNullCursor(bool b) +{ + allownullcursor = b; + return *this; +} + +TabBar& TabBar::Icons(bool v) +{ + icons = v; + Repos(); + Refresh(); + return *this; +} + +TabBar& TabBar::Stacking(bool b) +{ + stacking = b; + if (b) + DoStacking(); + else + DoUnstacking(); + Refresh(); + 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::FindValue(const Value &v) const +{ + for (int i = 0; i < tabs.GetCount(); i++) + if (tabs[i].value == v) + return i; + return -1; +} + +int TabBar::FindKey(const Value &v) const +{ + for (int i = 0; i < tabs.GetCount(); i++) + if (tabs[i].key == v) + return i; + return -1; +} + +bool TabBar::IsStackHead(int n) const +{ + return tabs[n].stack < 0 || n == 0 || (n > 0 && tabs[n-1].stack != tabs[n].stack); +} + +bool TabBar::IsStackTail(int n) const +{ + return tabs[n].stack < 0 || n >= tabs.GetCount()-1 || (n < tabs.GetCount() && tabs[n+1].stack != tabs[n].stack); +} + +int TabBar::FindStackHead(int stackix) const +{ + int i = 0; + while (tabs[i].stack != stackix) + i++; + return i; +} + +int TabBar::FindStackTail(int stackix) const +{ + int i = tabs.GetCount()-1; + while (tabs[i].stack != stackix) + i--; + return i; +} + +int TabBar::SetStackHead(Tab &t) +// Returns index of stack head +{ + ASSERT(stacking); + int id = t.id; + int stack = t.stack; + int head = FindStackHead(stack); + while (tabs[head].id != id) + CycleTabStack(head, stack); + return head; +} + +int TabBar::CycleTabStack(int n) +// Returns index of stack head +{ + int head = FindStackHead(n); + CycleTabStack(head, n); + return head; +} + +void TabBar::CycleTabStack(int head, int n) +{ + // Swap tab to end of stack + int ix = head; + while (!IsStackTail(ix)) { + tabs.Swap(ix, ix+1); + ++ix; + } +} + +void TabBar::SetData(const Value &key) +{ + int n = FindKey(key); + if (n >= 0) { + if (stacking && tabs[n].stack >= 0) + n = SetStackHead(tabs[n]); + SetCursor(n); + } +} + +void TabBar::Set(int n, const Value &newkey, const Value &newvalue) +{ + ASSERT(n >= 0 && n < tabs.GetCount()); + tabs[n].key = newkey; + tabs[n].value = newkey; + DoStacking(); + Repos(); +} + +void TabBar::Set(const Value &key, const Value &newvalue) +{ + Set(FindKey(key), key, newvalue); +} + +void TabBar::Set(int n, const Value &newvalue) +{ + ASSERT(n >= 0 && n < tabs.GetCount()); + Set(n, tabs[n].key, newvalue); +} + +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].key; + int ix = cross; + if (!CancelClose(v)) { + WhenClose(v); + Close(ix); + } + } + else if(highlight >= 0) { + if (stacking && highlight == active) { + CycleTabStack(tabs[active].stack); + 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) +{ + if (highlight >= 0) + 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)) + { + if (stacking && ProcessStackMouse(i, p)) + return true; + bool iscross = crosses ? tabs[i].HasMouseCross(p) : false; + if(highlight != i || (iscross && cross != i || !iscross && cross == i)) + { + cross = iscross ? i : -1; + SetHighlight(i); + } + return true; + } + return false; +} + +bool TabBar::ProcessStackMouse(int i, const Point& p) +{ + int j = i+1; + while (j < tabs.GetCount() && tabs[j].stack == tabs[i].stack) { + if (Rect(tabs[j].tab_pos, tabs[j].tab_size).Contains(p)) { + cross = -1; + if (highlight != j) + SetHighlight(j); + return true; + } + j++; + } + return false; +} + +void TabBar::SetHighlight(int n) +{ + highlight = n; + WhenHighlight(); + Refresh(); +} + +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; + + if (stacking) { + tab = FindStackHead(tabs[tab].stack); + c = FindStackHead(tabs[c].stack); + } + + bool sametab = c == tab || c == tab + 1; + bool internal = AcceptInternal(d, "tabs"); + + if(!sametab && internal && d.IsAccepted()) + { + int id = active >= 0 ? tabs[active].id : -1; + + // Count stack + int count = 1; + if (stacking) { + int ix = tab+1; + int stack = tabs[tab].stack; + while (ix < tabs.GetCount() && tabs[ix].stack == stack) + ix++; + count = ix - tab; + } + // Copy tabs + Vector stacktemp; + stacktemp.SetCount(count); + Copy(&stacktemp[0], &tabs[tab], count); + // Remove + tabs.Remove(tab, count); + if (tab < c) + c -= count; + // Re-insert + tabs.InsertPick(c, stacktemp); + + active = id >= 0 ? FindId(id) : -1; + isdrag = false; + target = -1; + MakeGroups(); + Repos(); + Refresh(); + Sync(); + MouseMove(p, 0); + } + else if(isdrag) + { + if(internal) + { + target = -1; + isdrag = false; + } + else + 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; + if (allownullcursor) + return; + } + + bool is_all = IsGroupAll(); + bool same_group = tabs[n].group == GetGroupName(); + + if((same_group || is_all) && active == n) + return; + + + bool repos = false; + if (!IsStackHead(n)) + { + n = SetStackHead(tabs[n]); + repos = true; + } + active = n; + if(!is_all && !same_group) + { + SetGroup(tabs[n].group); + repos = true; + } + if (repos) + 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(); +} + +void TabBar::Close(int n) +{ + if(tabs.GetCount() <= mintabcount) + 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(); + + highlight = min(highlight, tabs.GetCount()-1); + if(n == active) + SetCursor(-1); + else { + if (n < active) + active--; + Refresh(); + if (n == highlight && Ctrl::HasMouse()) { + Sync(); + MouseMove(GetMouseViewPos(), 0); + } + } +} + +void TabBar::CloseData(const Value &key) +{ + int tabix = FindKey(key); + if (tabix < 0) return; + Close(tabix); +} + +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); +} + +Vector TabBar::GetKeys() const +{ + Vector keys; + keys.SetCount(tabs.GetCount()); + for (int i = 0; i < tabs.GetCount(); i++) + keys[i] = tabs[i].key; + return keys; +} + +Vector TabBar::GetIcons() const +{ + Vector img; + img.SetCount(tabs.GetCount()); + for (int i = 0; i < tabs.GetCount(); i++) + img[i] = tabs[i].img; + return img; +} + +TabBar& TabBar::CopySettings(const TabBar &src) +{ + crosses = src.crosses; + grouping = src.grouping; + autoscrollhide = src.autoscrollhide; + nosel = src.nosel; + nohl = src.nohl; + inactivedisabled = src.inactivedisabled; + stacking = src.stacking; + groupsort = src.groupsort; + groupseps = src.groupseps; + allownullcursor = src.allownullcursor; + icons = src.icons; + mintabcount = src.mintabcount; + + if (stacking != src.stacking) + Stacking(src.stacking); + else { + MakeGroups(); + Repos(); + Refresh(); + } + return *this; +} + +/* +void TabBar::Serialize(Stream& s) +{ + int version = 0x01; + int cnt; + if (s.IsLoading()) Clear(); + + s / version / group / highlight / active; + + ASSERT(version >= 0x01); // Incompatible with previous version, sorry + + if (s.IsStoring()) { + cnt = groups.GetCount(); + s / cnt; + for (int i = 1; i < groups.GetCount(); i++) { + Group &g = groups[i]; + s % 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.key % t.value / t.id / g; + } + } + else { + s / cnt; + groups.SetCount(cnt); + for (int i = 1; i < cnt; i++) { + Group &g = groups[i]; + s % g.active; + } + s / cnt; + tabs.SetCount(cnt); + for (int i = 0; i < tabs.GetCount(); i++) { + int g; + Tab &t = tabs[i]; + s % t.key % t.value / t.id / g; + t.group = groups[g].name; + } + MakeGroups(); + Repos(); + } +} +*/ \ No newline at end of file diff --git a/bazaar/TabBar/TabBar.h b/bazaar/TabBar/TabBar.h index 2fa75339f..9cae98912 100644 --- a/bazaar/TabBar/TabBar.h +++ b/bazaar/TabBar/TabBar.h @@ -101,59 +101,67 @@ public: struct Style : public TabCtrl::Style { }; protected: - enum - { + enum { TB_MARGIN = 6, TB_SPACE = 10, TB_SBHEIGHT = 4, TB_SBSEPARATOR = 1, - TB_FILEICON = 16, + TB_ICON = 16, TB_SPACEICON = 5 }; - struct Tab : Moveable - { + struct Tab : Moveable { int id; - - Value data; - String group; - BiVector stack; + + Image img; + Value key; + Value value; + String group; + + String stackid; + unsigned sort_order; + int stack; bool visible; Point pos; Size size; - + int stdcx; + Point cross_pos; Size cross_size; Point tab_pos; Size tab_size; - Tab() : visible(true), id(-1) + Tab() : visible(true), id(-1), stack(-1), sort_order(0) {} - int Right() const { return pos.x + size.cx; } bool HasMouse(const Point& p) const; bool HasMouseCross(const Point& p) const; + bool HasIcon() const { return !img.IsEmpty(); } + int Right() const { return pos.x + size.cx; } }; - - struct Group : Moveable - { + struct Group : Moveable { Group() {} String name; - Value data; int active; int count; int first; int last; + }; + struct TabGroupSort { + bool operator()(const Tab &a, const Tab &b) const { return a.group < b.group; } }; + struct TabStackSort { + bool operator()(const Tab &a, const Tab &b) const { return a.sort_order < b.sort_order || (a.stackid == b.stackid && a.sort_order < b.sort_order); } + }; protected: - - TabScrollBar sc; - - Vector groups; - Vector tabs; - int active; + TabScrollBar sc; + + Vector groups; + Vector tabs; + Vector separators; + int active; private: int id; @@ -170,17 +178,20 @@ private: bool inactivedisabled:1; bool stacking:1; bool groupsort:1; - Gate2 stackfunc; - int neverempty; + bool groupseps:1; + bool allownullcursor:1; + bool icons:1; + int mintabcount; Point mouse, oldp; int group; const Display *display; Image dragtab; + int stackcount; 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); + 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); @@ -191,14 +202,20 @@ private: int GetPrev(int n) const; int GetWidth(int n); + int GetExtraWidth(); 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); + void InsertIntoStack(Tab &t, int ix); + int FindStackHead(int stackix) const; + int FindStackTail(int stackix) const; + bool IsStackHead(int n) const; + bool IsStackTail(int n) const; + int SetStackHead(Tab &t); + void CycleTabStack(int head, int n); + int CycleTabStack(int n); static int GetStyleHeight(const Style& s); @@ -227,77 +244,100 @@ protected: virtual void FrameLayout(Rect& r); virtual void Layout(); + // Mouse handling/tab positioning bool ProcessMouse(int i, const Point& p); - + bool ProcessStackMouse(int i, const Point& p); + void SetHighlight(int n); + int GetTargetTab(Point p); void Repos(); + + // Grouping void MakeGroups(); int FindGroup(const String& g) const; - void CloseAll(); + void CloseAll(int exception); 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); + void NewGroup(const String &name); + + // Insertion without repos/refresh - for batch actions + void InsertKey0(int ix, const Value &key, const Value &value, Image icon = Null, String group = Null); + + // Sub-class Paint override + virtual void PaintTab(Draw& w, const Rect &r, const Tab& tab, const Font &font, + Color ink, dword style); + virtual void PaintStackedTab(Draw& w, const Rect &r, const Tab& tab, const Font &font, + Color ink, dword style); virtual Size GetStdSize(const Tab &t); + virtual Size GetStackedSize(const Tab &t); Size GetStdSize(const Value &v); - + + // Paint helpers 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); + bool PaintIcons() { return icons; } 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; } - }; + // Sorting/Stacking overriddes + virtual String GetStackId(const Tab &a) { NEVER(); return false; } + virtual unsigned GetStackSortOrder(const Tab &a) { return 0; } public: typedef TabBar CLASSNAME; - Callback WhenHighlight; - Callback1 WhenClose; - Callback WhenCloseAll; - Callback WhenLeftDouble; + Callback WhenHighlight; // Executed on tab mouse-over + Callback WhenLeftDouble; // Executed on left-button double-click (clicked tab will be the active tab) + Gate1 CancelClose; // Return true to cancel action. Parameter: Key of closed tab + Callback1 WhenClose; // Executed before tab closing. Parameter: Key of closed tab + Gate CancelCloseAll; // Return true to cancel action; + Callback WhenCloseAll; // Executed before 'Close All' action 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); + TabBar& Add(const Value &value, Image icon = Null, String group = Null, bool make_active = false); + TabBar& Insert(int ix, const Value &value, Image icon = Null, String group = Null, bool make_active = false); + + TabBar& AddKey(const Value &key, const Value &value, Image icon = Null, String group = Null, bool make_active = false); + TabBar& InsertKey(int ix, const Value &key, const Value &value, Image icon = Null, String group = Null, bool make_active = false); + void Close(int n); - void CloseData(const Value &data); + void CloseData(const Value &key); void Clear(); TabBar& Crosses(bool b = true); TabBar& Grouping(bool b = true); - TabBar& GroupSort(bool b = true); + TabBar& GroupSort(bool b = true); + TabBar& GroupSeparators(bool b = true); TabBar& AutoScrollHide(bool b = true); TabBar& InactiveDisabled(bool b = true); + TabBar& AllowNullCursor(bool b = true); + TabBar& Icons(bool v = true); + + TabBar& Stacking(bool b = true); + bool IsStacking() { return stacking; } + + TabBar& NeverEmpty() { MinTabCount(1); } + TabBar& MinTabCount(int cnt) { mintabcount = max(cnt, 0); Refresh(); return *this; } TabBar& SetDisplay(const Display &d) { display = &d; Refresh(); } TabBar& SetBorder(int border) { AlignedFrame::SetBorder(border); return *this; } - int Find(const Value &v) const; + int FindKey(const Value &v) const; + int FindValue(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 GetKey(int n) const { ASSERT(n >= 0 && n < tabs.GetCount()); return tabs[n].key;} + Value GetValue(int n) const { ASSERT(n >= 0 && n < tabs.GetCount()); return tabs[n].value;} + Value Get(const Value &key) const { return GetValue(FindKey(key)); } + void Set(int n, const Value &newkey, const Value &newvalue); + void Set(const Value &key, const Value &newvalue); + void Set(int n, const Value &newvalue); + void SetTabGroup(int n, const String &group); + + virtual Value GetData() const { return (HasCursor() && active < GetCount()) ? GetKey(active) : Value(); } + virtual void SetData(const Value &key); - 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; } @@ -309,36 +349,32 @@ public: 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; } + int GetHighlight() const { return highlight; } bool HasHighlight() const { return highlight >= 0; } + int GetCount() const { return tabs.GetCount(); } - 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; } + void SetCursor(int n); + void KillCursor() { SetCursor(-1); } Image GetDragSample(); Image GetDragSample(int n); + Vector GetKeys() const; + Vector GetIcons() const; + TabBar& CopySettings(const TabBar &src); + 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); + static void ResetStyles(); }; +#include "FileTabs.h" #endif diff --git a/bazaar/TabBar/TabBar.upp b/bazaar/TabBar/TabBar.upp index f495247b5..e856e58e0 100644 --- a/bazaar/TabBar/TabBar.upp +++ b/bazaar/TabBar/TabBar.upp @@ -6,6 +6,8 @@ uses file TabBar.h, TabBar.cpp, + FileTabs.h, + FileTabs.cpp, TabBar.iml; mainconfig