metaforce/specter/lib/Space.cpp

319 lines
12 KiB
C++

#include "specter/Space.hpp"
#include "specter/IViewManager.hpp"
#include "specter/RootView.hpp"
#include "specter/ViewResources.hpp"
#include <boo/graphicsdev/IGraphicsCommandQueue.hpp>
namespace specter {
#define TRIANGLE_DIM 12
#define TRIANGLE_DIM1 10
#define TRIANGLE_DIM2 8
#define TRIANGLE_DIM3 6
#define TRIANGLE_DIM4 4
#define TRIANGLE_DIM5 2
#define CORNER_DRAG_THRESHOLD 20
static const zeus::CColor TriColor = {0.75, 0.75, 0.75, 1.0};
struct Space::CornerView : View {
Space& m_space;
VertexBufferBindingSolid m_vertexBinding;
bool m_flip;
CornerView(ViewResources& res, Space& space, const zeus::CColor& triColor);
void mouseEnter(const boo::SWindowCoord&) override;
void mouseLeave(const boo::SWindowCoord&) override;
void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) override;
void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) override;
using View::resized;
void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub, bool flip);
void draw(boo::IGraphicsCommandQueue* gfxQ) override;
};
Space::Space(ViewResources& res, View& parentView, ISpaceController& controller, Toolbar::Position tbPos,
unsigned tbUnits)
: View(res, parentView), m_controller(controller), m_tbPos(tbPos) {
commitResources(res, [&](boo::IGraphicsDataFactory::Context& ctx) -> bool {
buildResources(ctx, res);
return true;
});
setBackground(res.themeData().spaceBackground());
if (controller.spaceSplitAllowed()) {
m_cornerView.m_view = std::make_unique<CornerView>(res, *this, TriColor);
}
if (tbPos != Toolbar::Position::None) {
m_toolbar.m_view = std::make_unique<Toolbar>(res, *this, tbPos, tbUnits);
}
}
Space::~Space() = default;
Space::CornerView::CornerView(ViewResources& res, Space& space, const zeus::CColor& triColor)
: View(res, space), m_space(space) {
commitResources(res, [&](boo::IGraphicsDataFactory::Context& ctx) -> bool {
buildResources(ctx, res);
m_vertexBinding.init(ctx, res, 34, m_viewVertBlockBuf);
return true;
});
float pf = res.pixelFactor();
zeus::CColor edgeColor1 = triColor * res.themeData().spaceTriangleShading1();
zeus::CColor edgeColor2 = triColor * res.themeData().spaceTriangleShading2();
View::SolidShaderVert verts[34];
verts[0].m_pos.assign(0, TRIANGLE_DIM * pf, 0);
verts[0].m_color = edgeColor1;
verts[1].m_pos.assign(TRIANGLE_DIM * pf, 0, 0);
verts[1].m_color = edgeColor1;
verts[2].m_pos.assign(0, (TRIANGLE_DIM + 1) * pf, 0);
verts[2].m_color = edgeColor1;
verts[3].m_pos.assign((TRIANGLE_DIM + 1) * pf, 0, 0);
verts[3].m_color = edgeColor1;
verts[4] = verts[3];
verts[5].m_pos.assign(0, TRIANGLE_DIM1 * pf, 0);
verts[5].m_color = edgeColor2;
verts[6] = verts[5];
verts[7].m_pos.assign(TRIANGLE_DIM1 * pf, 0, 0);
verts[7].m_color = edgeColor2;
verts[8].m_pos.assign(0, (TRIANGLE_DIM1 + 1) * pf, 0);
verts[8].m_color = edgeColor2;
verts[9].m_pos.assign((TRIANGLE_DIM1 + 1) * pf, 0, 0);
verts[9].m_color = edgeColor2;
verts[10] = verts[9];
verts[11].m_pos.assign(0, TRIANGLE_DIM2 * pf, 0);
verts[11].m_color = edgeColor2;
verts[12] = verts[11];
verts[13].m_pos.assign(TRIANGLE_DIM2 * pf, 0, 0);
verts[13].m_color = edgeColor2;
verts[14].m_pos.assign(0, (TRIANGLE_DIM2 + 1) * pf, 0);
verts[14].m_color = edgeColor2;
verts[15].m_pos.assign((TRIANGLE_DIM2 + 1) * pf, 0, 0);
verts[15].m_color = edgeColor2;
verts[16] = verts[15];
verts[17].m_pos.assign(0, TRIANGLE_DIM3 * pf, 0);
verts[17].m_color = edgeColor2;
verts[18] = verts[17];
verts[19].m_pos.assign(TRIANGLE_DIM3 * pf, 0, 0);
verts[19].m_color = edgeColor2;
verts[20].m_pos.assign(0, (TRIANGLE_DIM3 + 1) * pf, 0);
verts[20].m_color = edgeColor2;
verts[21].m_pos.assign((TRIANGLE_DIM3 + 1) * pf, 0, 0);
verts[21].m_color = edgeColor2;
verts[22] = verts[21];
verts[23].m_pos.assign(0, TRIANGLE_DIM4 * pf, 0);
verts[23].m_color = edgeColor2;
verts[24] = verts[23];
verts[25].m_pos.assign(TRIANGLE_DIM4 * pf, 0, 0);
verts[25].m_color = edgeColor2;
verts[26].m_pos.assign(0, (TRIANGLE_DIM4 + 1) * pf, 0);
verts[26].m_color = edgeColor2;
verts[27].m_pos.assign((TRIANGLE_DIM4 + 1) * pf, 0, 0);
verts[27].m_color = edgeColor2;
verts[28] = verts[27];
verts[29].m_pos.assign(0, TRIANGLE_DIM5 * pf, 0);
verts[29].m_color = edgeColor2;
verts[30] = verts[29];
verts[31].m_pos.assign(TRIANGLE_DIM5 * pf, 0, 0);
verts[31].m_color = edgeColor2;
verts[32].m_pos.assign(0, (TRIANGLE_DIM5 + 1) * pf, 0);
verts[32].m_color = edgeColor2;
verts[33].m_pos.assign((TRIANGLE_DIM5 + 1) * pf, 0, 0);
verts[33].m_color = edgeColor2;
m_vertexBinding.load<decltype(verts)>(verts);
}
View* Space::setContentView(View* view) {
View* ret = m_contentView.m_view;
m_contentView.m_view = view;
updateSize();
return ret;
}
void Space::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) {
if (m_cornerView.mouseDown(coord, button, mod))
return;
m_contentView.mouseDown(coord, button, mod);
m_toolbar.mouseDown(coord, button, mod);
}
void Space::CornerView::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) {
if (button == boo::EMouseButton::Primary) {
m_space.m_cornerDrag = true;
m_space.m_cornerDragPoint[0] = coord.pixel[0];
m_space.m_cornerDragPoint[1] = coord.pixel[1];
rootView().setActiveDragView(&m_space);
}
}
void Space::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) {
m_cornerView.mouseUp(coord, button, mod);
m_contentView.mouseUp(coord, button, mod);
m_toolbar.mouseUp(coord, button, mod);
}
void Space::CornerView::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) {
if (button == boo::EMouseButton::Primary) {
m_space.m_cornerDrag = false;
rootView().unsetActiveDragView(&m_space);
}
}
void Space::mouseMove(const boo::SWindowCoord& coord) {
if (m_cornerDrag) {
float pf = rootView().viewRes().pixelFactor();
if (coord.pixel[0] < m_cornerDragPoint[0] - CORNER_DRAG_THRESHOLD * pf) {
if (m_cornerView.m_view->m_flip) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Vertical, 1, coord);
} else {
SplitView* sv = findSplitViewOnSide(SplitView::Axis::Vertical, 0);
if (sv) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().beginInteractiveJoin(sv, coord);
}
}
} else if (coord.pixel[1] < m_cornerDragPoint[1] - CORNER_DRAG_THRESHOLD * pf) {
if (m_cornerView.m_view->m_flip) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Horizontal, 1, coord);
} else {
SplitView* sv = findSplitViewOnSide(SplitView::Axis::Horizontal, 0);
if (sv) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().beginInteractiveJoin(sv, coord);
}
}
} else if (coord.pixel[0] > m_cornerDragPoint[0] + CORNER_DRAG_THRESHOLD * pf) {
if (!m_cornerView.m_view->m_flip) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Vertical, 0, coord);
} else {
SplitView* sv = findSplitViewOnSide(SplitView::Axis::Vertical, 1);
if (sv) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().beginInteractiveJoin(sv, coord);
}
}
} else if (coord.pixel[1] > m_cornerDragPoint[1] + CORNER_DRAG_THRESHOLD * pf) {
if (!m_cornerView.m_view->m_flip) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().viewManager().deferSpaceSplit(&m_controller, SplitView::Axis::Horizontal, 0, coord);
} else {
SplitView* sv = findSplitViewOnSide(SplitView::Axis::Horizontal, 1);
if (sv) {
rootView().mouseUp(coord, boo::EMouseButton::Primary, boo::EModifierKey::None);
rootView().beginInteractiveJoin(sv, coord);
}
}
}
} else {
m_cornerView.mouseMove(coord);
m_contentView.mouseMove(coord);
m_toolbar.mouseMove(coord);
}
}
void Space::mouseEnter(const boo::SWindowCoord& coord) {
m_cornerView.mouseEnter(coord);
m_contentView.mouseEnter(coord);
m_toolbar.mouseEnter(coord);
}
void Space::CornerView::mouseEnter(const boo::SWindowCoord& coord) { rootView().setSpaceCornerHover(true); }
void Space::mouseLeave(const boo::SWindowCoord& coord) {
m_cornerView.mouseLeave(coord);
m_contentView.mouseLeave(coord);
m_toolbar.mouseLeave(coord);
}
void Space::CornerView::mouseLeave(const boo::SWindowCoord& coord) { rootView().setSpaceCornerHover(false); }
SplitView* Space::findSplitViewOnSide(SplitView::Axis axis, int side) {
SplitView* ret = parentView().castToSplitView();
View* test = this;
while (ret) {
if (ret->axis() != axis)
return nullptr;
if (ret->m_views[side ^ 1].m_view == test)
return ret;
else if (ret->m_views[side].m_view == test)
test = ret;
ret = ret->parentView().castToSplitView();
}
return nullptr;
}
void Space::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) {
View::resized(root, sub);
float pf = rootView().viewRes().pixelFactor();
if (m_cornerView.m_view) {
boo::SWindowRect cornerRect = sub;
int triDim = TRIANGLE_DIM * pf;
cornerRect.size[0] = cornerRect.size[1] = triDim;
if (cornerRect.location[0] < triDim && cornerRect.location[1] < triDim) {
cornerRect.location[0] += sub.size[0] - triDim;
cornerRect.location[1] += sub.size[1] - triDim;
m_cornerView.m_view->resized(root, cornerRect, true);
} else
m_cornerView.m_view->resized(root, cornerRect, false);
}
boo::SWindowRect tbRect = sub;
if (m_toolbar.m_view) {
tbRect.size[1] = m_toolbar.m_view->nominalHeight();
if (m_tbPos == Toolbar::Position::Top)
tbRect.location[1] += sub.size[1] - tbRect.size[1];
m_toolbar.m_view->resized(root, tbRect);
} else
tbRect.size[1] = 0;
if (m_contentView.m_view) {
boo::SWindowRect contentRect = sub;
if (m_tbPos == Toolbar::Position::Bottom)
contentRect.location[1] += tbRect.size[1];
contentRect.size[1] = sub.size[1] - tbRect.size[1];
contentRect.size[1] = std::max(contentRect.size[1], 0);
m_contentView.m_view->resized(root, contentRect);
}
}
void Space::CornerView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub, bool flip) {
m_flip = flip;
if (flip) {
m_viewVertBlock.m_mv[0][0] = -2.0f / root.size[0];
m_viewVertBlock.m_mv[1][1] = -2.0f / root.size[1];
m_viewVertBlock.m_mv[3][0] = (sub.location[0] + sub.size[0]) * -m_viewVertBlock.m_mv[0][0] - 1.0f;
m_viewVertBlock.m_mv[3][1] = (sub.location[1] + sub.size[1]) * -m_viewVertBlock.m_mv[1][1] - 1.0f;
View::resized(m_viewVertBlock, sub);
} else
View::resized(root, sub);
}
void Space::draw(boo::IGraphicsCommandQueue* gfxQ) {
View::draw(gfxQ);
if (m_contentView.m_view)
m_contentView.m_view->draw(gfxQ);
if (m_toolbar.m_view)
m_toolbar.m_view->draw(gfxQ);
if (m_cornerView.m_view)
m_cornerView.m_view->draw(gfxQ);
}
void Space::CornerView::draw(boo::IGraphicsCommandQueue* gfxQ) {
gfxQ->setShaderDataBinding(m_vertexBinding);
gfxQ->draw(0, 34);
}
} // namespace specter