mirror of
https://codeberg.org/comaps/comaps
synced 2026-01-08 05:17:56 +00:00
Organic Maps sources as of 02.04.2025 (fad26bbf22ac3da75e01e62aa01e5c8e11861005)
To expand with full Organic Maps and Maps.ME commits history run: git remote add om-historic [om-historic.git repo url] git fetch --tags om-historic git replace squashed-history historic-commits
This commit is contained in:
313
drape_frontend/gui/skin.cpp
Normal file
313
drape_frontend/gui/skin.cpp
Normal file
@@ -0,0 +1,313 @@
|
||||
#include "drape_frontend/gui/skin.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "coding/parse_xml.hpp"
|
||||
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#ifdef DEBUG
|
||||
bool IsSimple(dp::Anchor anchor)
|
||||
{
|
||||
return anchor >= 0 && anchor <= 8;
|
||||
}
|
||||
|
||||
bool IsAnchor(dp::Anchor anchor)
|
||||
{
|
||||
return anchor >= 0 && anchor <= 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
dp::Anchor ParseValueAnchor(std::string_view value)
|
||||
{
|
||||
if (value == "center")
|
||||
return dp::Center;
|
||||
if (value == "left")
|
||||
return dp::Left;
|
||||
if (value == "right")
|
||||
return dp::Right;
|
||||
if (value == "top")
|
||||
return dp::Top;
|
||||
if (value == "bottom")
|
||||
return dp::Bottom;
|
||||
else
|
||||
{
|
||||
ASSERT(false, ());
|
||||
}
|
||||
|
||||
return dp::Center;
|
||||
}
|
||||
|
||||
dp::Anchor MergeAnchors(dp::Anchor src, dp::Anchor dst)
|
||||
{
|
||||
ASSERT(IsSimple(dst), ());
|
||||
ASSERT(IsSimple(src), ());
|
||||
dp::Anchor result = static_cast<dp::Anchor>(src | dst);
|
||||
ASSERT(IsAnchor(result), ());
|
||||
return result;
|
||||
}
|
||||
|
||||
float ParseFloat(char const * v)
|
||||
{
|
||||
float f = 0.0f;
|
||||
VERIFY(strings::to_float(v, f), ());
|
||||
return f;
|
||||
}
|
||||
|
||||
class ResolverParser
|
||||
{
|
||||
public:
|
||||
enum class Element
|
||||
{
|
||||
Empty,
|
||||
Anchor,
|
||||
Relative,
|
||||
Offset
|
||||
};
|
||||
|
||||
ResolverParser()
|
||||
: m_element(Element::Empty)
|
||||
{}
|
||||
|
||||
void Parse(std::string_view attr, char const * value)
|
||||
{
|
||||
ASSERT(m_element != Element::Empty, ());
|
||||
|
||||
if (attr == "x")
|
||||
{
|
||||
ASSERT(m_element == Element::Offset, ());
|
||||
m_resolver.SetOffsetX(ParseFloat(value));
|
||||
}
|
||||
else if (attr == "y")
|
||||
{
|
||||
ASSERT(m_element == Element::Offset, ());
|
||||
m_resolver.SetOffsetY(ParseFloat(value));
|
||||
}
|
||||
else if (attr == "vertical" || attr == "horizontal")
|
||||
{
|
||||
if (m_element == Element::Anchor)
|
||||
m_resolver.AddAnchor(ParseValueAnchor(value));
|
||||
else if (m_element == Element::Relative)
|
||||
m_resolver.AddRelative(ParseValueAnchor(value));
|
||||
else
|
||||
{
|
||||
ASSERT(false, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_resolver = PositionResolver();
|
||||
}
|
||||
|
||||
PositionResolver const & GetResolver() const
|
||||
{
|
||||
return m_resolver;
|
||||
}
|
||||
|
||||
void SetElement(Element e)
|
||||
{
|
||||
m_element = e;
|
||||
}
|
||||
|
||||
private:
|
||||
Element m_element;
|
||||
PositionResolver m_resolver;
|
||||
};
|
||||
|
||||
class SkinLoader
|
||||
{
|
||||
public:
|
||||
explicit SkinLoader(std::map<EWidget, std::pair<PositionResolver, PositionResolver>> & skin)
|
||||
: m_skin(skin)
|
||||
{}
|
||||
|
||||
bool Push(std::string_view element)
|
||||
{
|
||||
if (!m_inElement)
|
||||
{
|
||||
if (element == "root")
|
||||
return true;
|
||||
|
||||
m_inElement = true;
|
||||
if (element == "ruler")
|
||||
m_currentElement = WIDGET_RULER;
|
||||
else if (element == "compass")
|
||||
m_currentElement = WIDGET_COMPASS;
|
||||
else if (element == "copyright")
|
||||
m_currentElement = WIDGET_COPYRIGHT;
|
||||
else
|
||||
{
|
||||
ASSERT(false, ());
|
||||
}
|
||||
}
|
||||
else if (!m_inConfiguration)
|
||||
{
|
||||
if (element == "portrait" || element == "landscape")
|
||||
m_inConfiguration = true;
|
||||
else
|
||||
{
|
||||
ASSERT(false, ());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (element == "anchor")
|
||||
m_parser.SetElement(ResolverParser::Element::Anchor);
|
||||
else if (element == "relative")
|
||||
m_parser.SetElement(ResolverParser::Element::Relative);
|
||||
else if (element == "offset")
|
||||
m_parser.SetElement(ResolverParser::Element::Offset);
|
||||
else
|
||||
{
|
||||
ASSERT(false, ());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Pop(std::string_view element)
|
||||
{
|
||||
if (element == "anchor" || element == "relative" || element == "offset")
|
||||
m_parser.SetElement(ResolverParser::Element::Empty);
|
||||
else if (element == "portrait")
|
||||
{
|
||||
m_skin[m_currentElement].first = m_parser.GetResolver();
|
||||
m_parser.Reset();
|
||||
m_inConfiguration = false;
|
||||
}
|
||||
else if (element == "landscape")
|
||||
{
|
||||
m_skin[m_currentElement].second = m_parser.GetResolver();
|
||||
m_parser.Reset();
|
||||
m_inConfiguration = false;
|
||||
}
|
||||
else if (element == "ruler" || element == "compass" || element == "copyright" ||
|
||||
element == "country_status")
|
||||
{
|
||||
m_inElement = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AddAttr(std::string_view attribute, char const * value)
|
||||
{
|
||||
m_parser.Parse(attribute, value);
|
||||
}
|
||||
|
||||
void CharData(std::string const &) {}
|
||||
|
||||
private:
|
||||
bool m_inConfiguration = false;
|
||||
bool m_inElement = false;
|
||||
|
||||
EWidget m_currentElement = WIDGET_RULER;
|
||||
ResolverParser m_parser;
|
||||
|
||||
std::map<EWidget, std::pair<PositionResolver, PositionResolver>> & m_skin;
|
||||
};
|
||||
}
|
||||
|
||||
Position PositionResolver::Resolve(int w, int h, double vs) const
|
||||
{
|
||||
float resultX = w / 2.0f;
|
||||
float resultY = h / 2.0f;
|
||||
m2::PointF offset = m_offset * vs;
|
||||
|
||||
if (m_resolveAnchor & dp::Left)
|
||||
resultX = offset.x;
|
||||
else if (m_resolveAnchor & dp::Right)
|
||||
resultX = w - offset.x;
|
||||
else
|
||||
resultX += offset.x;
|
||||
|
||||
if (m_resolveAnchor & dp::Top)
|
||||
resultY = offset.y;
|
||||
else if (m_resolveAnchor & dp::Bottom)
|
||||
resultY = h - offset.y;
|
||||
else
|
||||
resultY += offset.y;
|
||||
|
||||
return Position(m2::PointF(resultX, resultY), m_elementAnchor);
|
||||
}
|
||||
|
||||
void PositionResolver::AddAnchor(dp::Anchor anchor)
|
||||
{
|
||||
m_elementAnchor = MergeAnchors(m_elementAnchor, anchor);
|
||||
}
|
||||
|
||||
void PositionResolver::AddRelative(dp::Anchor anchor)
|
||||
{
|
||||
m_resolveAnchor = MergeAnchors(m_resolveAnchor, anchor);
|
||||
}
|
||||
|
||||
void PositionResolver::SetOffsetX(float x)
|
||||
{
|
||||
m_offset.x = x;
|
||||
}
|
||||
|
||||
void PositionResolver::SetOffsetY(float y)
|
||||
{
|
||||
m_offset.y = y;
|
||||
}
|
||||
|
||||
Skin::Skin(ReaderPtr<Reader> const & reader, float visualScale)
|
||||
: m_visualScale(visualScale)
|
||||
{
|
||||
SkinLoader loader(m_resolvers);
|
||||
ReaderSource<ReaderPtr<Reader> > source(reader);
|
||||
if (!ParseXML(source, loader))
|
||||
LOG(LERROR, ("Error parsing gui skin"));
|
||||
}
|
||||
|
||||
Position Skin::ResolvePosition(EWidget name)
|
||||
{
|
||||
// check that name have only one bit
|
||||
ASSERT((static_cast<int>(name) & (static_cast<int>(name) - 1)) == 0, ());
|
||||
TResolversPair const & resolvers = m_resolvers[name];
|
||||
PositionResolver const & resolver = (m_displayWidth < m_displayHeight) ? resolvers.first : resolvers.second;
|
||||
return resolver.Resolve(m_displayWidth, m_displayHeight, m_visualScale);
|
||||
}
|
||||
|
||||
void Skin::Resize(int w, int h)
|
||||
{
|
||||
m_displayWidth = w;
|
||||
m_displayHeight = h;
|
||||
}
|
||||
|
||||
ReaderPtr<Reader> ResolveGuiSkinFile(std::string const & deviceType)
|
||||
{
|
||||
Platform & pl = GetPlatform();
|
||||
std::unique_ptr<Reader> reader;
|
||||
try
|
||||
{
|
||||
reader = pl.GetReader("resources-default/" + deviceType + ".ui");
|
||||
}
|
||||
catch(FileAbsentException & e)
|
||||
{
|
||||
LOG(LINFO, ("Gui skin for : ", deviceType ,"not found"));
|
||||
}
|
||||
|
||||
if (!reader)
|
||||
{
|
||||
try
|
||||
{
|
||||
reader = pl.GetReader("resources-default/default.ui");
|
||||
}
|
||||
catch(FileAbsentException & e)
|
||||
{
|
||||
LOG(LINFO, ("Default gui skin not found"));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return ReaderPtr<Reader>(std::move(reader));
|
||||
}
|
||||
} // namespace gui
|
||||
Reference in New Issue
Block a user