Welcome to mirror list, hosted at ThFree Co, Russian Federation.

build_skins.cpp « build_style « qt - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8f1fcad0be661f435904e62d99ca80c49c4ae5ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include "build_skins.h"
#include "build_common.h"

#include "platform/platform.hpp"

#include <array>
#include <algorithm>
#include <exception>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <fstream>

#include <QDir>

namespace
{
enum SkinType
{
  SkinMDPI,
  SkinHDPI,
  SkinXHDPI,
  SkinXXHDPI,
  Skin6Plus,

  // SkinCount MUST BE last
  SkinCount
};

using SkinInfo = std::tuple<const char*, int, bool>;
SkinInfo const g_skinInfo[SkinCount] =
{
  std::make_tuple("mdpi", 18, false),
  std::make_tuple("hdpi", 27, false),
  std::make_tuple("xhdpi", 36, false),
  std::make_tuple("xxhdpi", 54, false),
  std::make_tuple("6plus", 54, false),
};

std::array<SkinType, SkinCount> const g_skinTypes =
{{
  SkinMDPI,
  SkinHDPI,
  SkinXHDPI,
  SkinXXHDPI,
  Skin6Plus
}};

inline const char * SkinSuffix(SkinType s) { return std::get<0>(g_skinInfo[s]); }
inline int SkinSize(SkinType s) { return std::get<1>(g_skinInfo[s]); }
inline bool SkinCoorrectColor(SkinType s) { return std::get<2>(g_skinInfo[s]); }

QString GetSkinGeneratorPath()
{
  return GetExternalPath("skin_generator", "skin_generator.app/Contents/MacOS", "");
}

class RAII
{
public:
  RAII(std::function<void()> && f) : m_f(std::move(f)) {}
  ~RAII() { m_f(); }
private:
  function<void()> const m_f;
};

std::string trim(std::string && s)
{
  s.erase(std::remove_if(s.begin(), s.end(), &isspace), s.end());
  return s;
}
}  // namespace

namespace build_style
{
std::unordered_map<string, int> GetSkinSizes(QString const & file)
{
  std::unordered_map<string, int> skinSizes;

  for (SkinType s : g_skinTypes)
    skinSizes.insert(make_pair(SkinSuffix(s), SkinSize(s)));

  try
  {
    std::ifstream ifs(to_string(file));

    std::string line;
    while (std::getline(ifs, line))
    {
      size_t const pos = line.find('=');
      if (pos == std::string::npos)
        continue;

      std::string name(line.begin(), line.begin() + pos);
      std::string valueTxt(line.begin() + pos + 1, line.end());

      name = trim(std::move(name));
      int value = std::stoi(trim(std::move(valueTxt)));

      if (value <= 0)
        continue;

      skinSizes[name] = value;
    }
  }
  catch (std::exception const & e)
  {
    // reset
    for (SkinType s : g_skinTypes)
      skinSizes[SkinSuffix(s)] = SkinSize(s);
  }

  return skinSizes;
}

void BuildSkinImpl(QString const & styleDir, QString const & suffix,
                   int size, bool colorCorrection, QString const & outputDir)
{
  QString const symbolsDir = JoinFoldersToPath({styleDir, "symbols"});

  // Check symbols directory exists
  if (!QDir(symbolsDir).exists())
    throw std::runtime_error("Symbols directory does not exist");

  // Caller ensures that output directory is clear
  if (QDir(outputDir).exists())
    throw std::runtime_error("Output directory is not clear");

  // Create output skin directory
  if (!QDir().mkdir(outputDir))
    throw std::runtime_error("Cannot create output skin directory");

  // Create symbolic link for symbols/png
  QString const pngOriginDir = styleDir + suffix;
  QString const pngDir = JoinFoldersToPath({styleDir, "symbols", "png"});
  QFile::remove(pngDir);
  if (!QFile::link(pngOriginDir, pngDir))
    throw std::runtime_error("Unable to create symbols/png link");
  RAII const cleaner([=]() { QFile::remove(pngDir); });

  // Prepare command line
  QStringList params;
  params << GetSkinGeneratorPath() <<
          "--symbolWidth" << to_string(size).c_str() <<
          "--symbolHeight" << to_string(size).c_str() <<
          "--symbolsDir" << symbolsDir <<
          "--skinName" << JoinFoldersToPath({outputDir, "basic"}) <<
          "--skinSuffix=\"\"";
  if (colorCorrection)
    params << "--colorCorrection true";
  QString const cmd = params.join(' ');

  // Run the script
  auto res = ExecProcess(cmd);

  // If script returns non zero then it is error
  if (res.first != 0)
  {
    QString msg = QString("System error ") + to_string(res.first).c_str();
    if (!res.second.isEmpty())
      msg = msg + "\n" + res.second;
    throw std::runtime_error(to_string(msg));
  }

  // Check files were created
  if (QFile(JoinFoldersToPath({outputDir, "symbols.png"})).size() == 0 ||
      QFile(JoinFoldersToPath({outputDir, "symbols.sdf"})).size() == 0)
  {
    throw std::runtime_error("Skin files have not been created");
  }
}

void BuildSkins(QString const & styleDir, QString const & outputDir)
{
  QString const resolutionFilePath = JoinFoldersToPath({styleDir, "resolutions.txt"});

  auto const resolution2size = GetSkinSizes(resolutionFilePath);

  for (SkinType s : g_skinTypes)
  {
    QString const suffix = SkinSuffix(s);
    QString const outputSkinDir = JoinFoldersToPath({outputDir, "resources-" + suffix + "_design"});
    int const size = resolution2size.at(to_string(suffix)); // SkinSize(s);
    bool const colorCorrection = SkinCoorrectColor(s);

    BuildSkinImpl(styleDir, suffix, size, colorCorrection, outputSkinDir);
  }
}

void ApplySkins(QString const & outputDir)
{
  QString const resourceDir = GetPlatform().ResourcesDir().c_str();

  for (SkinType s : g_skinTypes)
  {
    QString const suffix = SkinSuffix(s);
    QString const outputSkinDir = JoinFoldersToPath({outputDir, "resources-" + suffix + "_design"});
    QString const resourceSkinDir = JoinFoldersToPath({resourceDir, "resources-" + suffix + "_design"});

    if (!QFileInfo::exists(resourceSkinDir) && !QDir().mkdir(resourceSkinDir))
      throw std::runtime_error("Cannot create resource skin directory: " + resourceSkinDir.toStdString());

    if (!CopyFile(JoinFoldersToPath({outputSkinDir, "symbols.png"}),
                  JoinFoldersToPath({resourceSkinDir, "symbols.png"})) ||
        !CopyFile(JoinFoldersToPath({outputSkinDir, "symbols.sdf"}),
                  JoinFoldersToPath({resourceSkinDir, "symbols.sdf"})))
    {
      throw std::runtime_error("Cannot copy skins files");
    }
  }
}
}  // namespace build_style