mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-10 13:47:46 +00:00
FileBrowser column resizing and navigation
This commit is contained in:
@@ -8,14 +8,17 @@ static LogVisor::LogModule Log("Specter::Table");
|
||||
#define ROW_HEIGHT 18
|
||||
#define CELL_MARGIN 1
|
||||
|
||||
Table::Table(ViewResources& res, View& parentView, ITableDataBinding* data, ITableStateBinding* state, size_t maxColumns)
|
||||
Table::Table(ViewResources& res, View& parentView, ITableDataBinding* data,
|
||||
ITableStateBinding* state, size_t maxColumns)
|
||||
: View(res, parentView), m_data(data), m_state(state), m_maxColumns(maxColumns),
|
||||
m_hVerts(new SolidShaderVert[maxColumns * 6]), m_rowsView(*this, res)
|
||||
{
|
||||
if (!maxColumns)
|
||||
Log.report(LogVisor::FatalError, "0-column tables not supported");
|
||||
|
||||
m_hVertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SolidShaderVert), maxColumns * 6);
|
||||
m_hVertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex,
|
||||
sizeof(SolidShaderVert),
|
||||
maxColumns * 6);
|
||||
|
||||
if (!res.m_viewRes.m_texVtxFmt)
|
||||
{
|
||||
@@ -86,7 +89,6 @@ void Table::_setHeaderVerts(const boo::SWindowRect& sub)
|
||||
const ThemeData& theme = rootView().themeData();
|
||||
|
||||
float pf = rootView().viewRes().pixelFactor();
|
||||
int div = sub.size[0] / m_headerViews.size();
|
||||
int margin = CELL_MARGIN * pf;
|
||||
int rowHeight = ROW_HEIGHT * pf;
|
||||
int xOff = 0;
|
||||
@@ -99,6 +101,12 @@ void Table::_setHeaderVerts(const boo::SWindowRect& sub)
|
||||
if (m_state)
|
||||
sDir = m_state->getSort(sCol);
|
||||
|
||||
boo::SWindowRect headRowRect = sub;
|
||||
headRowRect.size[1] = rowHeight;
|
||||
headRowRect.location[1] = sub.size[1] - rowHeight;
|
||||
m_hCellRects = getCellRects(headRowRect);
|
||||
auto cellRectsIt = m_hCellRects.begin();
|
||||
|
||||
for (c=0 ; c<std::min(m_maxColumns, m_columns) ; ++c)
|
||||
{
|
||||
const ViewChild<std::unique_ptr<CellView>>& hv = *it;
|
||||
@@ -131,6 +139,7 @@ void Table::_setHeaderVerts(const boo::SWindowRect& sub)
|
||||
}
|
||||
}
|
||||
|
||||
int div = cellRectsIt->size[0];
|
||||
v[0].m_pos.assign(xOff + margin, yOff - margin, 0);
|
||||
v[0].m_color = cm1;
|
||||
v[1] = v[0];
|
||||
@@ -144,6 +153,7 @@ void Table::_setHeaderVerts(const boo::SWindowRect& sub)
|
||||
v += 6;
|
||||
xOff += div;
|
||||
++it;
|
||||
++cellRectsIt;
|
||||
}
|
||||
|
||||
if (c)
|
||||
@@ -161,7 +171,6 @@ void Table::RowsView::_setRowVerts(const boo::SWindowRect& sub, const boo::SWind
|
||||
return;
|
||||
|
||||
float pf = rootView().viewRes().pixelFactor();
|
||||
int div = sub.size[0] / m_t.m_cellViews.size();
|
||||
int spacing = (ROW_HEIGHT + CELL_MARGIN * 2) * pf;
|
||||
int margin = CELL_MARGIN * pf;
|
||||
int rowHeight = ROW_HEIGHT * pf;
|
||||
@@ -173,15 +182,22 @@ void Table::RowsView::_setRowVerts(const boo::SWindowRect& sub, const boo::SWind
|
||||
++idx;
|
||||
}
|
||||
int startIdx = int(m_t.m_rows) - idx;
|
||||
if (!m_t.m_header)
|
||||
startIdx -= 1;
|
||||
|
||||
std::vector<boo::SWindowRect> cellRects = m_t.getCellRects(sub);
|
||||
|
||||
size_t r, c;
|
||||
for (r=0, c=0 ; r<SPECTER_TABLE_MAX_ROWS && (sub.location[1] + yOff + spacing) >= scissor.location[1] ; ++r)
|
||||
for (r=0, c=0 ; r<SPECTER_TABLE_MAX_ROWS &&
|
||||
(sub.location[1] + yOff + spacing) >= scissor.location[1] ; ++r)
|
||||
{
|
||||
const Zeus::CColor& color = (startIdx+r==m_t.m_selectedRow) ? theme.tableCellBgSelected() :
|
||||
((r&1) ? theme.tableCellBg1() : theme.tableCellBg2());
|
||||
int xOff = 0;
|
||||
auto cellRectsIt = cellRects.begin();
|
||||
for (c=0 ; c<std::min(m_t.m_maxColumns, m_t.m_columns) ; ++c)
|
||||
{
|
||||
int div = cellRectsIt->size[0];
|
||||
v[0].m_pos.assign(xOff + margin, yOff - margin, 0);
|
||||
v[0].m_color = color;
|
||||
v[1] = v[0];
|
||||
@@ -194,6 +210,7 @@ void Table::RowsView::_setRowVerts(const boo::SWindowRect& sub, const boo::SWind
|
||||
v[5] = v[4];
|
||||
v += 6;
|
||||
xOff += div;
|
||||
++cellRectsIt;
|
||||
}
|
||||
yOff -= spacing;
|
||||
}
|
||||
@@ -276,15 +293,38 @@ void Table::CellView::deselect()
|
||||
m_text->colorGlyphs(rootView().themeData().uiText());
|
||||
}
|
||||
|
||||
void Table::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||
void Table::mouseDown(const boo::SWindowCoord& coord,
|
||||
boo::EMouseButton button, boo::EModifierKey mod)
|
||||
{
|
||||
if (m_state && m_state->columnSplitResizeAllowed())
|
||||
{
|
||||
size_t cIdx = 0;
|
||||
for (const boo::SWindowRect& rect : m_hCellRects)
|
||||
{
|
||||
if (cIdx == 0)
|
||||
{
|
||||
++cIdx;
|
||||
continue;
|
||||
}
|
||||
if (abs(coord.pixel[0] - rect.location[0]) < 4 &&
|
||||
unsigned(coord.pixel[1] - subRect().location[1] -
|
||||
subRect().size[1] + rect.size[1]) < rect.size[1])
|
||||
{
|
||||
m_hDraggingIdx = cIdx;
|
||||
rootView().setActiveDragView(this);
|
||||
return;
|
||||
}
|
||||
++cIdx;
|
||||
}
|
||||
}
|
||||
|
||||
m_scroll.mouseDown(coord, button, mod);
|
||||
if (m_headerNeedsUpdate)
|
||||
_setHeaderVerts(subRect());
|
||||
}
|
||||
|
||||
|
||||
void Table::RowsView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||
void Table::RowsView::mouseDown(const boo::SWindowCoord& coord,
|
||||
boo::EMouseButton button, boo::EModifierKey mod)
|
||||
{
|
||||
for (ViewChild<std::unique_ptr<CellView>>& hv : m_t.m_headerViews)
|
||||
if (hv.mouseDown(coord, button, mod))
|
||||
@@ -294,7 +334,8 @@ void Table::RowsView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButto
|
||||
cv.mouseDown(coord, button, mod);
|
||||
}
|
||||
|
||||
void Table::CellView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||
void Table::CellView::mouseDown(const boo::SWindowCoord& coord,
|
||||
boo::EMouseButton button, boo::EModifierKey mod)
|
||||
{
|
||||
if (m_r != -1)
|
||||
{
|
||||
@@ -308,14 +349,21 @@ void Table::CellView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButto
|
||||
m_t.m_headerNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void Table::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||
void Table::mouseUp(const boo::SWindowCoord& coord,
|
||||
boo::EMouseButton button, boo::EModifierKey mod)
|
||||
{
|
||||
m_scroll.mouseUp(coord, button, mod);
|
||||
if (m_headerNeedsUpdate)
|
||||
_setHeaderVerts(subRect());
|
||||
if (m_hDraggingIdx)
|
||||
{
|
||||
rootView().setActiveDragView(nullptr);
|
||||
m_hDraggingIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Table::RowsView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||
void Table::RowsView::mouseUp(const boo::SWindowCoord& coord,
|
||||
boo::EMouseButton button, boo::EModifierKey mod)
|
||||
{
|
||||
size_t idx = 0;
|
||||
for (ViewChild<std::unique_ptr<CellView>>& hv : m_t.m_headerViews)
|
||||
@@ -330,7 +378,8 @@ void Table::RowsView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton
|
||||
cv.mouseUp(coord, button, mod);
|
||||
}
|
||||
|
||||
void Table::CellView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||
void Table::CellView::mouseUp(const boo::SWindowCoord& coord,
|
||||
boo::EMouseButton button, boo::EModifierKey mod)
|
||||
{
|
||||
if (m_r == -1)
|
||||
m_t.m_headerNeedsUpdate = true;
|
||||
@@ -338,6 +387,43 @@ void Table::CellView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton
|
||||
|
||||
void Table::mouseMove(const boo::SWindowCoord& coord)
|
||||
{
|
||||
if (m_state && m_state->columnSplitResizeAllowed())
|
||||
{
|
||||
if (m_hDraggingIdx)
|
||||
{
|
||||
float split = (coord.pixel[0] - subRect().location[0]) / float(subRect().size[0]);
|
||||
|
||||
if (m_hDraggingIdx <= 1)
|
||||
split = std::max(0.03f, split);
|
||||
else
|
||||
split = std::max(m_state->getColumnSplit(m_hDraggingIdx-1)+0.03f, split);
|
||||
|
||||
if (m_hDraggingIdx >= m_columns - 1)
|
||||
split = std::min(0.97f, split);
|
||||
else
|
||||
split = std::min(m_state->getColumnSplit(m_hDraggingIdx+1)-0.03f, split);
|
||||
|
||||
m_state->setColumnSplit(m_hDraggingIdx, split);
|
||||
updateSize();
|
||||
return;
|
||||
}
|
||||
size_t cIdx = 0;
|
||||
bool hovering = false;
|
||||
for (const boo::SWindowRect& rect : m_hCellRects)
|
||||
{
|
||||
if (cIdx++ == 0)
|
||||
continue;
|
||||
if (abs(coord.pixel[0] - rect.location[0]) < 4 &&
|
||||
unsigned(coord.pixel[1] - subRect().location[1] -
|
||||
subRect().size[1] + rect.size[1]) < rect.size[1])
|
||||
{
|
||||
hovering = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rootView().setVerticalSplitHover(hovering);
|
||||
}
|
||||
|
||||
m_scroll.mouseMove(coord);
|
||||
if (m_headerNeedsUpdate)
|
||||
_setHeaderVerts(subRect());
|
||||
@@ -460,25 +546,77 @@ void Table::updateData()
|
||||
updateSize();
|
||||
}
|
||||
|
||||
std::vector<boo::SWindowRect> Table::getCellRects(const boo::SWindowRect& sub) const
|
||||
{
|
||||
if (!m_columns)
|
||||
return {};
|
||||
float pf = rootView().viewRes().pixelFactor();
|
||||
|
||||
/* Validate column split values */
|
||||
bool valid = false;
|
||||
std::vector<float> splits;
|
||||
splits.reserve(m_columns);
|
||||
if (m_state)
|
||||
{
|
||||
float lastSplit = 0.0;
|
||||
size_t i;
|
||||
for (i=0 ; i<m_columns ; ++i)
|
||||
{
|
||||
float split = m_state->getColumnSplit(i);
|
||||
if (split < lastSplit || split < 0.0 || split > 1.0)
|
||||
break;
|
||||
splits.push_back(split);
|
||||
lastSplit = split;
|
||||
}
|
||||
if (i == m_columns)
|
||||
valid = true;
|
||||
}
|
||||
|
||||
/* Uniform split otherwise */
|
||||
if (!valid)
|
||||
{
|
||||
float split = 0.0;
|
||||
for (size_t i=0 ; i<m_columns ; ++i)
|
||||
{
|
||||
splits.push_back(split);
|
||||
split += 1.0 / float(m_columns);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<boo::SWindowRect> ret;
|
||||
ret.reserve(m_columns);
|
||||
|
||||
int lastX = 0;
|
||||
for (size_t i=0 ; i<m_columns ; ++i)
|
||||
{
|
||||
float nextSplit = (i==m_columns-1) ? 1.0 : splits[i+1];
|
||||
int x = nextSplit * sub.size[0];
|
||||
ret.push_back({{sub.location[0] + lastX, sub.location[1]},
|
||||
{x - lastX, int(ROW_HEIGHT * pf)}});
|
||||
lastX = x;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Table::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
||||
{
|
||||
View::resized(root, sub);
|
||||
if (m_scroll.m_view)
|
||||
m_scroll.m_view->resized(root, sub);
|
||||
|
||||
boo::SWindowRect headRow = sub;
|
||||
float pf = rootView().viewRes().pixelFactor();
|
||||
boo::SWindowRect cell = sub;
|
||||
cell.size[1] = ROW_HEIGHT * pf;
|
||||
cell.location[1] += sub.size[1] - cell.size[1];
|
||||
int div = sub.size[0] / m_cellViews.size();
|
||||
cell.size[0] = div;
|
||||
|
||||
headRow.location[1] += sub.size[1] - ROW_HEIGHT * pf;
|
||||
std::vector<boo::SWindowRect> cellRects = getCellRects(headRow);
|
||||
_setHeaderVerts(sub);
|
||||
size_t cIdx = 0;
|
||||
for (ViewChild<std::unique_ptr<CellView>>& hv : m_headerViews)
|
||||
{
|
||||
if (hv.m_view)
|
||||
hv.m_view->resized(root, cell);
|
||||
cell.location[0] += div;
|
||||
hv.m_view->resized(root, cellRects[cIdx], sub);
|
||||
++cIdx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,34 +635,32 @@ void Table::RowsView::resized(const boo::SWindowRect& root, const boo::SWindowRe
|
||||
View::resized(root, sub);
|
||||
_setRowVerts(sub, scissor);
|
||||
|
||||
if (m_t.m_cellViews.empty())
|
||||
if (!m_t.m_columns)
|
||||
return;
|
||||
|
||||
float pf = rootView().viewRes().pixelFactor();
|
||||
int div = sub.size[0] / m_t.m_cellViews.size();
|
||||
boo::SWindowRect cell = sub;
|
||||
cell.size[0] = div;
|
||||
cell.size[1] = ROW_HEIGHT * pf;
|
||||
cell.location[1] += sub.size[1] - cell.size[1];
|
||||
boo::SWindowRect rowRect = sub;
|
||||
rowRect.location[1] += sub.size[1] - ROW_HEIGHT * pf;
|
||||
int spacing = (ROW_HEIGHT + CELL_MARGIN * 2) * pf;
|
||||
int hStart = cell.location[1];
|
||||
std::vector<boo::SWindowRect> cellRects = m_t.getCellRects(rowRect);
|
||||
auto cellRectIt = cellRects.begin();
|
||||
for (auto& col : m_t.m_cellViews)
|
||||
{
|
||||
cell.location[1] = hStart;
|
||||
for (ViewChild<std::unique_ptr<CellView>>& cv : col)
|
||||
{
|
||||
cell.location[1] -= spacing;
|
||||
cellRectIt->location[1] -= spacing;
|
||||
if (cv.m_view)
|
||||
cv.m_view->resized(root, cell);
|
||||
cv.m_view->resized(root, *cellRectIt, scissor);
|
||||
}
|
||||
cell.location[0] += div;
|
||||
++cellRectIt;
|
||||
}
|
||||
|
||||
m_scissorRect = scissor;
|
||||
m_scissorRect.size[1] -= spacing;
|
||||
}
|
||||
|
||||
void Table::CellView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
||||
void Table::CellView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub,
|
||||
const boo::SWindowRect& scissor)
|
||||
{
|
||||
View::resized(root, sub);
|
||||
boo::SWindowRect textRect = sub;
|
||||
@@ -532,6 +668,7 @@ void Table::CellView::resized(const boo::SWindowRect& root, const boo::SWindowRe
|
||||
textRect.location[0] += 5 * pf;
|
||||
textRect.location[1] += 5 * pf;
|
||||
m_text->resized(root, textRect);
|
||||
m_scissorRect = sub.intersect(scissor);
|
||||
}
|
||||
|
||||
void Table::draw(boo::IGraphicsCommandQueue* gfxQ)
|
||||
@@ -557,22 +694,28 @@ void Table::RowsView::draw(boo::IGraphicsCommandQueue* gfxQ)
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
gfxQ->setScissor(rootView().subRect());
|
||||
|
||||
if (m_t.m_header)
|
||||
{
|
||||
gfxQ->setShaderDataBinding(m_t.m_hShaderBinding);
|
||||
gfxQ->setDrawPrimitive(boo::Primitive::TriStrips);
|
||||
gfxQ->setScissor(rootView().subRect());
|
||||
gfxQ->draw(1, m_t.m_columns * 6 - 2);
|
||||
for (ViewChild<std::unique_ptr<CellView>>& hv : m_t.m_headerViews)
|
||||
if (hv.m_view)
|
||||
hv.m_view->draw(gfxQ);
|
||||
}
|
||||
|
||||
gfxQ->setScissor(rootView().subRect());
|
||||
}
|
||||
|
||||
void Table::CellView::draw(boo::IGraphicsCommandQueue* gfxQ)
|
||||
{
|
||||
m_text->draw(gfxQ);
|
||||
if (m_scissorRect.size[0] && m_scissorRect.size[1])
|
||||
{
|
||||
gfxQ->setScissor(m_scissorRect);
|
||||
m_text->draw(gfxQ);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user