aseprite/src/app/ui/layout.cpp

194 lines
4.7 KiB
C++

// Aseprite
// Copyright (C) 2022-2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/layout.h"
#include "app/app.h"
#include "app/ui/color_bar.h"
#include "app/ui/context_bar.h"
#include "app/ui/dock.h"
#include "app/ui/main_window.h"
#include "app/ui/status_bar.h"
#include "app/ui/timeline/timeline.h"
#include "app/ui/toolbar.h"
#include "app/ui/workspace.h"
#include "app/xml_document.h"
#include "app/xml_exception.h"
#include "base/convert_to.h"
#include "ui/widget.h"
#include <cstring>
#include <sstream>
namespace app {
using namespace tinyxml2;
static void save_dock_layout(XMLElement* elem, const Dock* dock)
{
for (const auto child : dock->children()) {
const int side = dock->whichSideChildIsDocked(child);
const gfx::Size size = dock->getUserDefinedSizeAtSide(side);
std::string sideStr;
switch (side) {
case ui::LEFT: sideStr = "left"; break;
case ui::RIGHT: sideStr = "right"; break;
case ui::TOP: sideStr = "top"; break;
case ui::BOTTOM: sideStr = "bottom"; break;
case ui::CENTER:
// Empty side attribute
break;
}
XMLElement* childElem = elem->InsertNewChildElement("");
if (auto subdock = dynamic_cast<const Dock*>(child)) {
childElem->SetValue("dock");
if (!sideStr.empty())
childElem->SetAttribute("side", sideStr.c_str());
save_dock_layout(childElem, subdock);
}
else {
// Set the widget ID as the element name, e.g. <timeline />,
// <colorbar />, etc.
childElem->SetValue(child->id().c_str());
if (!sideStr.empty())
childElem->SetAttribute("side", sideStr.c_str());
if (size.w)
childElem->SetAttribute("width", size.w);
if (size.h)
childElem->SetAttribute("height", size.h);
}
}
}
static void load_dock_layout(const XMLElement* elem, Dock* dock)
{
const char* elemNameStr = elem->Value();
if (!elemNameStr) {
ASSERT(false); // Impossible?
return;
}
const std::string elemName = elemNameStr;
MainWindow* win = App::instance()->mainWindow();
ASSERT(win);
ui::Widget* widget = nullptr;
Dock* subdock = nullptr;
int side = ui::CENTER;
if (auto sideStr = elem->Attribute("side")) {
if (std::strcmp(sideStr, "left") == 0)
side = ui::LEFT;
if (std::strcmp(sideStr, "right") == 0)
side = ui::RIGHT;
if (std::strcmp(sideStr, "top") == 0)
side = ui::TOP;
if (std::strcmp(sideStr, "bottom") == 0)
side = ui::BOTTOM;
}
const char* widthStr = elem->Attribute("width");
const char* heightStr = elem->Attribute("height");
gfx::Size size;
if (widthStr)
size.w = base::convert_to<int>(std::string(widthStr));
if (heightStr)
size.h = base::convert_to<int>(std::string(heightStr));
if (elemName == "colorbar") {
widget = win->colorBar();
}
else if (elemName == "contextbar") {
widget = win->getContextBar();
}
else if (elemName == "timeline") {
widget = win->getTimeline();
}
else if (elemName == "toolbar") {
widget = win->toolBar();
}
else if (elemName == "workspace") {
widget = win->getWorkspace();
}
else if (elemName == "statusbar") {
widget = win->statusBar();
}
else if (elemName == "dock") {
subdock = dock->subdock(side);
}
if (subdock) {
auto childElem = elem->FirstChildElement();
while (childElem) {
load_dock_layout(childElem, subdock);
childElem = childElem->NextSiblingElement();
}
}
else {
dock->dock(side, widget, size);
}
}
// static
LayoutPtr Layout::MakeFromXmlElement(const XMLElement* layoutElem)
{
auto layout = std::make_shared<Layout>();
if (auto name = layoutElem->Attribute("name")) {
layout->m_id = name;
layout->m_name = name;
}
layout->m_elem = layoutElem->DeepClone(&layout->m_dummyDoc)->ToElement();
return layout;
}
// static
LayoutPtr Layout::MakeFromDock(const std::string& id, const std::string& name, const Dock* dock)
{
auto layout = std::make_shared<Layout>();
layout->m_id = id;
layout->m_name = name;
layout->m_elem = layout->m_dummyDoc.NewElement("layout");
layout->m_elem->SetAttribute("name", name.c_str());
save_dock_layout(layout->m_elem, dock);
return layout;
}
bool Layout::matchId(const std::string& id) const
{
if (m_id == id)
return true;
else if ((m_id.empty() && id == kDefault) || (m_id == kDefault && id.empty()))
return true;
else
return false;
}
bool Layout::loadLayout(Dock* dock) const
{
if (!m_elem)
return false;
XMLElement* elem = m_elem->FirstChildElement();
while (elem) {
load_dock_layout(elem, dock);
elem = elem->NextSiblingElement();
}
return true;
}
} // namespace app