ultimatepp/bazaar/XMLMenu/XMLToolBarFrame.cpp
micio 31599d99f3 sandbox/XMLMenu moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@4070 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2011-10-20 10:38:46 +00:00

509 lines
12 KiB
C++

#include "XMLToolBarFrame.h"
#include "WithXMLMenu.h"
NAMESPACE_UPP
// recalculates relative toolbar's positions
// needed after adding or removing a toolbar
void XMLToolBarFrame::Reposition(void)
{
// clears position mapper
posMapper.Clear();
// setup a dummy frame size, just in case frame is empty
frameSize = 3;
// if no toolbars inside, just do nothing else
if(!toolBars.GetCount())
return;
// fixup 'vertical' positions, i.e. rows on which toolbars belong
Array<int>vPos;
for(int iPos = 0; iPos < relativePositions.GetCount(); iPos++)
{
Size const &sz = relativePositions[iPos];
vPos.Add(sz.cy);
}
Sort(vPos);
VectorMap<int, int>vMap;
int v = 0;
for(int iPos = 0; iPos < vPos.GetCount(); iPos++)
{
if(vMap.Find(vPos[iPos]) < 0)
{
vMap.Add(vPos[iPos], v);
v ++;
}
}
for(int iPos = 0; iPos < relativePositions.GetCount(); iPos++)
{
Size &sz = relativePositions[iPos];
sz.cy = vMap.Get(sz.cy);
}
// now, scans each row, fixing up positions inside it and
// building true toolbars positions
int curVPos = 0;
for(int iRow = 0; iRow < vMap.GetCount(); iRow++)
{
Vector<int>ps, idx;
int rowHeight = 0;
for(int iPos = 0; iPos < relativePositions.GetCount(); iPos++)
{
Size &sz = relativePositions[iPos];
if(sz.cy == iRow)
{
ps.Add(sz.cx);
idx.Add(iPos);
}
}
IndexSort(ps, idx);
int minNextPos = 0;
for(int i = 0; i < ps.GetCount(); i++)
{
if(ps[i] < minNextPos)
ps[i] = minNextPos;
XMLToolBarCtrl &tb = *toolBars[idx[i]];
Size sz;
switch(toolBarState)
{
case TOOLBAR_LEFT :
case TOOLBAR_RIGHT :
sz = tb.GetVertSize();
rowHeight = max(rowHeight, sz.cx);
minNextPos = ps[i] + sz.cy + 2; // 2 pixels gap between columns
break;
case TOOLBAR_TOP :
case TOOLBAR_BOTTOM :
sz = tb.GetHorzSize();
rowHeight = max(rowHeight, sz.cy);
minNextPos = ps[i] + sz.cx + 2; // 2 pixels gap between columns
break;
default:
NEVER();
}
}
VectorMap<int, int> &rowMap = posMapper.Add(curVPos);
for(int i = 0; i < ps.GetCount(); i++)
rowMap.Add(ps[i], idx[i]);
curVPos += rowHeight;
}
// store total frame size
frameSize = curVPos;
// if reversed direction, fixup cols
if(toolBarState == TOOLBAR_RIGHT || toolBarState == TOOLBAR_BOTTOM)
{
int lastPos = posMapper.GetKey(posMapper.GetCount()-1);
for(int iRow = 0; iRow < posMapper.GetCount(); iRow++)
posMapper.SetKey(iRow, lastPos - posMapper.GetKey(iRow));
}
}
void XMLToolBarFrame::FrameLayout(Rect& r)
{
// stores frame rectangle -- it's needed to layout toolbars
frameRect = r;
Reposition();
switch(toolBarState)
{
case TOOLBAR_LEFT:
r.left += frameSize + 4;
frameRect.right = r.left;
frameP11 = Point(frameRect.left, frameRect.top);
frameP12 = Point(frameRect.left, frameRect.bottom);
frameP21 = Point(frameRect.right-1, frameRect.top);
frameP22 = Point(frameRect.right-1, frameRect.bottom);
frameRect.left += 2;
frameRect.right -= 2;
break;
case TOOLBAR_RIGHT:
r.right -= frameSize + 4;
frameRect.left = r.right;
frameP11 = Point(frameRect.left, frameRect.top);
frameP12 = Point(frameRect.left, frameRect.bottom);
frameP21 = Point(frameRect.right-1, frameRect.top);
frameP22 = Point(frameRect.right-1, frameRect.bottom);
frameRect.left += 2;
frameRect.right -= 2;
break;
case TOOLBAR_TOP:
r.top += frameSize + 4;
frameRect.bottom = r.top;
frameP11 = Point(frameRect.left, frameRect.top);
frameP12 = Point(frameRect.right, frameRect.top);
frameP21 = Point(frameRect.left, frameRect.bottom-1);
frameP22 = Point(frameRect.right, frameRect.bottom-1);
frameRect.top += 2;
frameRect.bottom -= 2;
break;
case TOOLBAR_BOTTOM:
r.bottom -= frameSize + 4;
frameRect.top = r.bottom;
frameP11 = Point(frameRect.left, frameRect.top);
frameP12 = Point(frameRect.right, frameRect.top);
frameP21 = Point(frameRect.left, frameRect.bottom-1);
frameP22 = Point(frameRect.right, frameRect.bottom-1);
frameRect.top += 2;
frameRect.bottom -= 2;
break;
default:
NEVER();
}
// fixup control inside frame
toolBarContainer.SetFrameRect(
frameRect.left,
frameRect.top,
frameRect.GetSize().cx,
frameRect.GetSize().cy
);
// layouts toolbars inside frame
Layout();
}
void XMLToolBarFrame::FrameAddSize(Size& sz)
{
Reposition();
switch(toolBarState)
{
case TOOLBAR_LEFT:
case TOOLBAR_RIGHT:
sz.cx += frameSize + 4;
break;
case TOOLBAR_TOP:
case TOOLBAR_BOTTOM:
sz.cy += frameSize + 4;
break;
default:
NEVER();
break;
}
}
// frame painting
void XMLToolBarFrame::FramePaint(Draw& w, const Rect& r)
{
// w.DrawRect(r, Red());
w.DrawRect(r, SColorLtFace());
// w.DrawLine(frameP11, frameP12, 0, SColorLight());
// w.DrawLine(frameP21, frameP22, 0, SColorLtFace());
// if predocking, paint the docking toolBar placeholder
/*
if(preDocking)
w.DrawRect(preDockRect, Yellow());
*/
}
// lays toolbars inside frame
void XMLToolBarFrame::Layout(void)
{
// don't layout if still no parent
if(!parent)
return;
for(int iRow = 0; iRow < posMapper.GetCount(); iRow++)
{
int rowPos = posMapper.GetKey(iRow);
VectorMap<int, int> &rowMapper = posMapper[iRow];
for(int iCol = 0; iCol < rowMapper.GetCount(); iCol++)
{
int colPos = rowMapper.GetKey(iCol);
int idx = rowMapper[iCol];
XMLToolBarCtrl &tb = *toolBars[idx];
Ctrl::LogPos pos;
Size sz;
int x1, y1, x2, y2;
switch(toolBarState)
{
case TOOLBAR_LEFT :
case TOOLBAR_RIGHT :
sz = tb.GetVertSize();
x1 = rowPos;
y1 = colPos;
break;
case TOOLBAR_TOP :
case TOOLBAR_BOTTOM :
sz = tb.GetHorzSize();
x1 = colPos;
y1 = rowPos;
break;
default :
NEVER();
break;
}
x2 = x1 + sz.cx;
y2 = y1 + sz.cy;
// don't add last toolbar as a child if predocking
if(!preDocking || &tb != toolBars.Top())
{
pos = Ctrl::LogPos(
Ctrl::PosLeft(x1, x2 - x1),
Ctrl::PosTop(y1, y2 - y1)
);
tb.SetPos(pos);
}
if(preDocking && &tb == toolBars.Top())
preDockRect = Rect(x1, y1, x2, y2);
}
}
}
// frame insertion/removing handlers
void XMLToolBarFrame::FrameAdd(Ctrl &_parent)
{
parent = &_parent;
parent->AddChild(&toolBarContainer);
Layout();
}
void XMLToolBarFrame::FrameRemove(void)
{
toolBars.Clear();
relativePositions.Clear();
parent->RemoveChild(&toolBarContainer);
posMapper.Clear();
parent = NULL;
}
XMLToolBarFrame::XMLToolBarFrame(XMLToolBarState _toolBarState)
{
parent = NULL;
toolBarState = _toolBarState;
preDocking = false;
}
XMLToolBarFrame::~XMLToolBarFrame()
{
}
// find index of a docked XMLToolBarFrame; -1 if not found
int XMLToolBarFrame::FindIndex(XMLToolBarCtrl &tb)
{
int n = toolBars.GetCount();
// skip last toolbar if predocking, it's there
// just as a placeholder
if(preDocking)
n--;
for(int i = 0; i < n; i++)
if(&tb == toolBars[i])
return i;
return -1;
}
// docks a toolbar into this frame
// internal function -- called by XMLToolBar one
XMLToolBarFrame &XMLToolBarFrame::Dock(XMLToolBarCtrl &tb, Point p)
{
// if already docked here, just do nothing
if(FindIndex(tb) >= 0)
return *this;
// undocks/unfloats from previous position asking owning frame, if any, to do it
if(tb.toolBarFrame)
tb.toolBarFrame->Undock(tb);
// dock here the frame
toolBars.Add(&tb);
toolBarContainer.AddChild(&tb);
relativePositions.Add(p);
Reposition();
Layout();
tb.toolBarPos = Point(relativePositions.Top().cx, relativePositions.Top().cy);
return *this;
}
bool XMLToolBarFrame::GetDockTarget(XMLToolBarCtrl &tb, Point p, int &dockLine, bool &insert, int &col)
{
// nothing if point outside frame
if(!toolBarContainer.GetScreenRect().Contains(p))
return false;
p -= toolBarContainer.GetScreenRect().TopLeft();
Size sz = toolBarContainer.GetRect().GetSize();
// ok, it's inside the frame, we must now search for
// row, column and if we must dock on existing row or
// inserting a new one
int framePos;
switch(toolBarState)
{
case TOOLBAR_LEFT :
framePos = p.x;
col = p.y;
break;
case TOOLBAR_RIGHT :
framePos = sz.cx - p.x;
col = p.y;
break;
case TOOLBAR_TOP :
framePos = p.y;
col = p.x;
break;
case TOOLBAR_BOTTOM :
framePos = sz.cy - p.y;
col = p.x;
break;
default :
NEVER();
return false;
}
int numLines = posMapper.GetCount();
if(!numLines)
{
dockLine = 0;
insert = false;
return true;
}
ASSERT(numLines);
int lineHeight = frameSize / numLines;
ASSERT(lineHeight);
dockLine = framePos / lineHeight;
int rem = framePos - dockLine * lineHeight;
if(rem <= lineHeight / 4)
insert = true;
else if(rem >= 3 * lineHeight / 4)
{
dockLine++;
insert = true;
}
else
insert = false;
return true;
}
XMLToolBarFrame &XMLToolBarFrame::DockAt(XMLToolBarCtrl &tb, Point p)
{
// should not happen, but....
if(FindIndex(tb) >= 0)
return *this;
// get dock position
int dockLine, col;
bool insert;
if(!GetDockTarget(tb, p, dockLine, insert, col))
return *this;
// if needed, shift all positions to make place for this toolbar line
if(insert)
{
for(int i = 0; i < relativePositions.GetCount(); i++)
if(relativePositions[i].cy >= dockLine)
relativePositions[i].cy++;
}
// docks the toolbar there
relativePositions.Add(Size(col, dockLine));
toolBars.Add(&tb);
toolBarContainer.AddChild(&tb);
Reposition();
Layout();
tb.toolBarPos = Point(relativePositions.Top().cx, relativePositions.Top().cy);
return *this;
}
// closes (undocking it) an XMLToolBar from this frame
XMLToolBarFrame &XMLToolBarFrame::Undock(XMLToolBarCtrl &tb)
{
// if already docked here, just do nothing
int i = FindIndex(tb);
if(i < 0)
return *this;
// store inside toolbar last docked position
Size &sz = relativePositions[i];
toolBars[i]->toolBarPos= Point(sz.cx, sz.cy);
// remove from toolbars and positions list
toolBars.Remove(i);
toolBarContainer.RemoveChild(&tb);
relativePositions.Remove(i);
// signals closed toolbar
tb.toolBarState = TOOLBAR_CLOSED;
tb.toolBarFrame = NULL;
// reposition the frame
Reposition();
Layout();
// frees toolbar from pointing here
return *this;
}
// pre-docking handling -- Point p in SCREEN COORDINATES
XMLToolBarFrame &XMLToolBarFrame::PreDock(XMLToolBarCtrl &tb, Point p)
{
if(preDocking)
return *this;
// get dock position
int dockLine, col;
bool insert;
if(!GetDockTarget(tb, p, dockLine, insert, col))
return *this;
preDocking = true;
// if needed, shift all positions to make place for this toolbar line
if(insert)
{
for(int i = 0; i < relativePositions.GetCount(); i++)
if(relativePositions[i].cy >= dockLine)
relativePositions[i].cy++;
}
// docks the toolbar there
relativePositions.Add(Size(col, dockLine));
toolBars.Add(&tb);
Reposition();
Layout();
return *this;
}
XMLToolBarFrame &XMLToolBarFrame::UnPreDock(XMLToolBarCtrl &tb)
{
if(!preDocking)
return *this;
relativePositions.Trim(relativePositions.GetCount() - 1);
toolBars.Trim(toolBars.GetCount() - 1);
Reposition();
// parent->Refresh(preDockRect);
Layout();
preDocking = false;
return *this;
}
// check whether a point (in SCREEN coordinates) is inside the frame
bool XMLToolBarFrame::Contains(Point ps)
{
if(!this->parent)
return false;
ps -= parent->GetScreenRect().TopLeft();
return frameRect.Contains(ps);
}
END_UPP_NAMESPACE