mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 14:16:09 -06:00
509 lines
12 KiB
C++
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
|