2015-12-11 02:37:54 +00:00
|
|
|
#include "Space.hpp"
|
2015-12-12 00:37:32 +00:00
|
|
|
#include "ViewManager.hpp"
|
2016-01-07 00:40:27 +00:00
|
|
|
#include "ResourceBrowser.hpp"
|
2016-02-02 04:29:58 +00:00
|
|
|
#include "ParticleEditor.hpp"
|
2016-02-02 08:31:05 +00:00
|
|
|
#include "ModelViewer.hpp"
|
|
|
|
#include "InformationCenter.hpp"
|
2016-12-13 02:56:43 +00:00
|
|
|
#include "GameMode.hpp"
|
2016-01-18 23:33:23 +00:00
|
|
|
#include "icons/icons.hpp"
|
2017-12-29 08:08:12 +00:00
|
|
|
#include "specter/Menu.hpp"
|
2015-12-11 02:37:54 +00:00
|
|
|
|
2021-04-10 08:42:06 +00:00
|
|
|
namespace metaforce {
|
2016-03-04 23:04:53 +00:00
|
|
|
static logvisor::Module Log("URDE::Space");
|
2015-12-11 02:37:54 +00:00
|
|
|
|
2016-01-17 04:14:13 +00:00
|
|
|
Space::Space(ViewManager& vm, Class cls, Space* parent)
|
2018-12-08 05:30:43 +00:00
|
|
|
: m_spaceMenuNode(*this), m_spaceSelectBind(*this), m_vm(vm), m_class(cls), m_parent(parent) {}
|
|
|
|
|
|
|
|
specter::View* Space::buildSpaceView(specter::ViewResources& res) {
|
|
|
|
if (usesToolbar()) {
|
|
|
|
m_spaceView.reset(
|
|
|
|
new specter::Space(res, *m_parent->basisView(), *this, specter::Toolbar::Position::Bottom, toolbarUnits()));
|
|
|
|
specter::View* sview = buildContentView(res);
|
|
|
|
m_spaceView->setContentView(sview);
|
|
|
|
specter::Toolbar& tb = *m_spaceView->toolbar();
|
|
|
|
specter::Icon* classIcon = SpaceMenuNode::LookupClassIcon(m_class);
|
|
|
|
const zeus::CColor* classColor = SpaceMenuNode::LookupClassColor(m_class);
|
|
|
|
m_spaceSelectButton.reset(new specter::Button(res, tb, &m_spaceSelectBind, "", classIcon,
|
|
|
|
specter::Button::Style::Block,
|
2019-02-24 07:15:54 +00:00
|
|
|
classColor ? *classColor : zeus::skWhite));
|
2018-12-08 05:30:43 +00:00
|
|
|
tb.push_back(m_spaceSelectButton.get(), 0);
|
|
|
|
buildToolbarView(res, tb);
|
|
|
|
return m_spaceView.get();
|
|
|
|
} else {
|
|
|
|
m_spaceView.reset(new specter::Space(res, *m_parent->basisView(), *this, specter::Toolbar::Position::None, 0));
|
|
|
|
specter::View* sview = buildContentView(res);
|
|
|
|
m_spaceView->setContentView(sview);
|
|
|
|
return m_spaceView.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Space::SpaceMenuNode::SubNodeData> Space::SpaceMenuNode::s_subNodeDats = {
|
|
|
|
{Class::ResourceBrowser,
|
|
|
|
"Resource Browser",
|
|
|
|
GetIcon(SpaceIcon::ResourceBrowser),
|
|
|
|
{0.0f, 1.0f, 0.0f, 1.0f}},
|
|
|
|
{Class::EffectEditor,
|
|
|
|
"Effect Editor",
|
|
|
|
GetIcon(SpaceIcon::ParticleEditor),
|
|
|
|
{1.0f, 0.5f, 0.0f, 1.0f}},
|
2019-07-20 04:27:21 +00:00
|
|
|
{Class::ModelViewer, "Model Viewer", GetIcon(SpaceIcon::ModelViewer), {0.95f, 0.95f, 0.95f, 1.0f}},
|
2018-12-08 05:30:43 +00:00
|
|
|
{Class::InformationCenter,
|
|
|
|
"Information Center",
|
|
|
|
GetIcon(SpaceIcon::InformationCenter),
|
|
|
|
{0.0f, 1.0f, 1.0f, 1.0f}},
|
2019-07-20 04:27:21 +00:00
|
|
|
{Class::GameMode, "Game Mode", GetIcon(SpaceIcon::GameMode), {}}};
|
2016-01-17 04:14:13 +00:00
|
|
|
std::string Space::SpaceMenuNode::s_text = "Space Types";
|
|
|
|
|
2019-07-20 04:27:21 +00:00
|
|
|
template <typename Key>
|
|
|
|
static void RecurseTranslations(ViewManager& vm, std::vector<Space::SpaceMenuNode::SubNodeData>::iterator it) {
|
|
|
|
it->m_text = vm.translate<Key>();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Key, typename Key2, typename... RemKeys>
|
|
|
|
static void RecurseTranslations(ViewManager& vm, std::vector<Space::SpaceMenuNode::SubNodeData>::iterator it) {
|
|
|
|
RecurseTranslations<Key>(vm, it);
|
|
|
|
RecurseTranslations<Key2, RemKeys...>(vm, ++it);
|
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void Space::SpaceMenuNode::InitializeStrings(ViewManager& vm) {
|
2019-07-20 04:27:21 +00:00
|
|
|
s_text = vm.translate<locale::space_types>();
|
|
|
|
RecurseTranslations<locale::resource_browser,
|
|
|
|
locale::effect_editor,
|
|
|
|
locale::model_viewer,
|
|
|
|
locale::information_center,
|
|
|
|
locale::game_mode>(vm, s_subNodeDats.begin());
|
2016-01-17 04:14:13 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
std::unique_ptr<specter::View> Space::SpaceSelectBind::buildMenu(const specter::Button* button) {
|
|
|
|
return std::unique_ptr<specter::View>(
|
|
|
|
new specter::Menu(m_space.m_vm.rootView().viewRes(), *m_space.m_spaceView, &m_space.m_spaceMenuNode));
|
2016-01-17 04:14:13 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
specter::View* RootSpace::buildSpaceView(specter::ViewResources& res) {
|
|
|
|
specter::View* newRoot = buildContentView(res);
|
|
|
|
m_vm.RootSpaceViewBuilt(newRoot);
|
|
|
|
return newRoot;
|
2016-01-11 02:17:08 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
specter::View* RootSpace::basisView() { return &m_vm.rootView(); }
|
2016-02-01 01:13:45 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
specter::View* SplitSpace::buildContentView(specter::ViewResources& res) {
|
|
|
|
int clearance = res.pixelFactor() * SPECTER_TOOLBAR_GAUGE;
|
|
|
|
m_splitView.reset(
|
|
|
|
new specter::SplitView(res, *m_parent->basisView(), this, m_state.axis, m_state.split, clearance, clearance));
|
|
|
|
if (m_slots[0])
|
|
|
|
m_splitView->setContentView(0, m_slots[0]->buildSpaceView(res));
|
|
|
|
if (m_slots[1])
|
|
|
|
m_splitView->setContentView(1, m_slots[1]->buildSpaceView(res));
|
|
|
|
return m_splitView.get();
|
2015-12-12 00:37:32 +00:00
|
|
|
}
|
2015-12-11 02:37:54 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void SplitSpace::setChildSlot(unsigned slot, std::unique_ptr<Space>&& space) {
|
|
|
|
if (slot > 1)
|
2020-04-11 22:51:39 +00:00
|
|
|
Log.report(logvisor::Fatal, FMT_STRING("invalid slot {} for SplitView"), slot);
|
2018-12-08 05:30:43 +00:00
|
|
|
m_slots[slot] = std::move(space);
|
|
|
|
m_slots[slot]->m_parent = this;
|
2016-01-10 06:42:58 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void SplitSpace::joinViews(specter::SplitView* thisSplit, int thisSlot, specter::SplitView* otherSplit, int otherSlot) {
|
|
|
|
if (thisSplit == otherSplit) {
|
|
|
|
SplitSpace* thisSS = m_slots[thisSlot]->castToSplitSpace();
|
|
|
|
if (thisSS) {
|
|
|
|
int ax = thisSS->m_state.axis == specter::SplitView::Axis::Horizontal ? 1 : 0;
|
|
|
|
const boo::SWindowRect& thisRect = m_splitView->subRect();
|
|
|
|
const boo::SWindowRect& subRect = thisSS->m_splitView->subRect();
|
|
|
|
int splitPx = subRect.location[ax] + subRect.size[ax] * thisSS->m_state.split - thisRect.location[ax];
|
|
|
|
thisSS->m_state.split = splitPx / float(thisRect.size[ax]);
|
2016-02-01 01:13:45 +00:00
|
|
|
}
|
2018-12-08 05:30:43 +00:00
|
|
|
m_parent->exchangeSpaceSplitJoin(this, std::move(m_slots[thisSlot]));
|
|
|
|
m_vm.BuildSpaceViews();
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
SplitSpace* otherSS = m_slots[i]->castToSplitSpace();
|
|
|
|
if (otherSS && otherSS->m_splitView.get() == otherSplit) {
|
|
|
|
int ax = m_state.axis == specter::SplitView::Axis::Horizontal ? 1 : 0;
|
|
|
|
const boo::SWindowRect& thisRect = m_splitView->subRect();
|
|
|
|
const boo::SWindowRect& subRect = otherSS->m_splitView->subRect();
|
|
|
|
int splitPx = subRect.location[ax] + subRect.size[ax] * otherSS->m_state.split - thisRect.location[ax];
|
|
|
|
m_state.split = splitPx / float(thisRect.size[ax]);
|
|
|
|
exchangeSpaceSplitJoin(otherSS, std::move(otherSS->m_slots[otherSlot ^ 1]));
|
2016-01-11 02:17:08 +00:00
|
|
|
m_vm.BuildSpaceViews();
|
2018-12-08 05:30:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-01-10 06:42:58 +00:00
|
|
|
}
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2016-01-10 06:42:58 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
specter::ISplitSpaceController* Space::spaceSplit(specter::SplitView::Axis axis, int thisSlot) {
|
|
|
|
if (m_parent) {
|
|
|
|
/* Reject split operations with insufficient clearance */
|
|
|
|
int clearance = m_vm.m_viewResources.pixelFactor() * SPECTER_TOOLBAR_GAUGE;
|
|
|
|
if (axis == specter::SplitView::Axis::Horizontal) {
|
|
|
|
if (m_spaceView->subRect().size[1] <= clearance)
|
|
|
|
return nullptr;
|
|
|
|
} else {
|
|
|
|
if (m_spaceView->subRect().size[0] <= clearance)
|
|
|
|
return nullptr;
|
2016-01-10 06:42:58 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
SplitSpace* ss = new SplitSpace(m_vm, m_parent, axis);
|
|
|
|
ss->setChildSlot(thisSlot, m_parent->exchangeSpaceSplitJoin(this, std::unique_ptr<Space>(ss)));
|
|
|
|
ss->setChildSlot(thisSlot ^ 1, std::unique_ptr<Space>(copy(ss)));
|
|
|
|
m_vm.BuildSpaceViews();
|
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
return nullptr;
|
2016-01-05 00:01:02 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
std::unique_ptr<Space> RootSpace::exchangeSpaceSplitJoin(Space* removeSpace, std::unique_ptr<Space>&& keepSpace) {
|
|
|
|
std::unique_ptr<Space> ret = std::move(keepSpace);
|
2016-01-04 05:31:02 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if (removeSpace == m_spaceTree.get()) {
|
|
|
|
m_spaceTree.swap(ret);
|
|
|
|
m_spaceTree->m_parent = this;
|
|
|
|
} else
|
2020-04-11 22:51:39 +00:00
|
|
|
Log.report(logvisor::Fatal, FMT_STRING("RootSpace::exchangeSpaceSplitJoin() failure"));
|
2016-01-07 00:40:27 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
return ret;
|
2016-01-07 00:40:27 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
std::unique_ptr<Space> SplitSpace::exchangeSpaceSplitJoin(Space* removeSpace, std::unique_ptr<Space>&& keepSpace) {
|
|
|
|
std::unique_ptr<Space> ret = std::move(keepSpace);
|
2016-01-10 06:42:58 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if (removeSpace == m_slots[0].get()) {
|
|
|
|
m_slots[0].swap(ret);
|
|
|
|
m_slots[0]->m_parent = this;
|
|
|
|
} else if (removeSpace == m_slots[1].get()) {
|
|
|
|
m_slots[1].swap(ret);
|
|
|
|
m_slots[1]->m_parent = this;
|
|
|
|
} else
|
2020-04-11 22:51:39 +00:00
|
|
|
Log.report(logvisor::Fatal, FMT_STRING("SplitSpace::exchangeSpaceSplitJoin() failure"));
|
2016-01-05 00:01:02 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
return ret;
|
2016-07-09 01:23:34 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
template <class Reader>
|
|
|
|
static Space* BuildNewSpace(ViewManager& vm, Space::Class cls, Space* parent, Reader& r) {
|
|
|
|
using Class = Space::Class;
|
|
|
|
switch (cls) {
|
|
|
|
case Class::SplitSpace:
|
|
|
|
return new SplitSpace(vm, parent, r);
|
|
|
|
case Class::ResourceBrowser:
|
|
|
|
return new ResourceBrowser(vm, parent, r);
|
|
|
|
case Class::EffectEditor:
|
|
|
|
return new EffectEditor(vm, parent, r);
|
|
|
|
case Class::ModelViewer:
|
|
|
|
return new ModelViewer(vm, parent, r);
|
|
|
|
case Class::InformationCenter:
|
|
|
|
return new InformationCenter(vm, parent, r);
|
|
|
|
case Class::GameMode:
|
|
|
|
return new GameMode(vm, parent, r);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Space::saveState(athena::io::IStreamWriter& w) const {
|
|
|
|
w.writeUint32Big(atUint32(m_class));
|
|
|
|
spaceState().write(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Space::saveState(athena::io::YAMLDocWriter& w) const {
|
|
|
|
w.writeUint32("class", atUint32(m_class));
|
|
|
|
spaceState().write(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
Space* Space::NewSpaceFromConfigStream(ViewManager& vm, Space* parent, ConfigReader& r) {
|
|
|
|
Class cls = Class(r.readUint32("class"));
|
|
|
|
return BuildNewSpace(vm, cls, parent, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
RootSpace* Space::NewRootSpaceFromConfigStream(ViewManager& vm, ConfigReader& r) {
|
|
|
|
Class cls = Class(r.readUint32("class"));
|
|
|
|
if (cls != Class::RootSpace)
|
|
|
|
return nullptr;
|
|
|
|
return new RootSpace(vm, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Space::SpaceMenuNode::SubNode::activated(const boo::SWindowCoord& coord) {
|
|
|
|
std::unique_ptr<Space> newSpace;
|
|
|
|
switch (m_data.m_cls) {
|
|
|
|
case Class::InformationCenter:
|
|
|
|
if (m_space.cls() == Class::InformationCenter)
|
|
|
|
newSpace.reset(new InformationCenter(m_space.m_parent->m_vm, m_space.m_parent));
|
|
|
|
break;
|
|
|
|
case Class::EffectEditor:
|
|
|
|
if (m_space.cls() == Class::EffectEditor)
|
|
|
|
newSpace.reset(new EffectEditor(m_space.m_parent->m_vm, m_space.m_parent));
|
|
|
|
break;
|
|
|
|
case Class::ResourceBrowser:
|
|
|
|
if (m_space.cls() == Class::ResourceBrowser)
|
|
|
|
newSpace.reset(new ResourceBrowser(m_space.m_parent->m_vm, m_space.m_parent));
|
|
|
|
break;
|
|
|
|
case Class::ModelViewer:
|
|
|
|
if (m_space.cls() == Class::ModelViewer)
|
|
|
|
newSpace.reset(new ModelViewer(m_space.m_parent->m_vm, m_space.m_parent));
|
|
|
|
break;
|
|
|
|
case Class::GameMode:
|
|
|
|
if (m_space.cls() == Class::GameMode)
|
|
|
|
newSpace.reset(new GameMode(m_space.m_parent->m_vm, m_space.m_parent));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (newSpace) {
|
|
|
|
Space* parent = m_space.m_parent;
|
|
|
|
m_space.m_parent->exchangeSpaceSplitJoin(&m_space, std::move(newSpace));
|
|
|
|
parent->m_vm.BuildSpaceViews();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-10 08:42:06 +00:00
|
|
|
} // namespace metaforce
|