1 
2 
3 #include "toonzqt/gutil.h"
4 #include "toonz/preferences.h"
5 
6 // TnzQt includes
7 #include "toonzqt/dvdialog.h"
8 
9 // TnzCore includes
10 #include "traster.h"
11 #include "tpixelutils.h"
12 #include "tfilepath.h"
13 #include "tfiletype.h"
14 #include "tstroke.h"
15 #include "tcurves.h"
16 #include "trop.h"
17 #include "tmsgcore.h"
18 
19 // Qt includes
20 #include <QPixmap>
21 #include <QImage>
22 #include <QPainter>
23 #include <QPainterPath>
24 #include <QIcon>
25 #include <QString>
26 #include <QApplication>
27 #include <QMouseEvent>
28 #include <QTabletEvent>
29 #include <QKeyEvent>
30 #include <QUrl>
31 #include <QFileInfo>
32 #include <QDesktopWidget>
33 #include <QSvgRenderer>
34 
35 using namespace DVGui;
36 
37 //-----------------------------------------------------------------------------
38 
fileSizeString(qint64 size,int precision)39 QString fileSizeString(qint64 size, int precision) {
40   if (size < 1024)
41     return QString::number(size) + " Bytes";
42   else if (size < 1024 * 1024)
43     return QString::number(size / (1024.0), 'f', precision) + " KB";
44   else if (size < 1024 * 1024 * 1024)
45     return QString::number(size / (1024 * 1024.0), 'f', precision) + " MB";
46   else
47     return QString::number(size / (1024 * 1024 * 1024.0), 'f', precision) +
48            " GB";
49 }
50 
51 //----------------------------------------------------------------
52 
rasterToQImage(const TRasterP & ras,bool premultiplied,bool mirrored)53 QImage rasterToQImage(const TRasterP &ras, bool premultiplied, bool mirrored) {
54   if (TRaster32P ras32 = ras) {
55     QImage image(ras->getRawData(), ras->getLx(), ras->getLy(),
56                  premultiplied ? QImage::Format_ARGB32_Premultiplied
57                                : QImage::Format_ARGB32);
58     if (mirrored) return image.mirrored();
59     return image;
60   } else if (TRasterGR8P ras8 = ras) {
61     QImage image(ras->getRawData(), ras->getLx(), ras->getLy(), ras->getWrap(),
62                  QImage::Format_Indexed8);
63     static QVector<QRgb> colorTable;
64     if (colorTable.size() == 0) {
65       int i;
66       for (i = 0; i < 256; i++) colorTable.append(QColor(i, i, i).rgb());
67     }
68     image.setColorTable(colorTable);
69     if (mirrored) return image.mirrored();
70     return image;
71   }
72   return QImage();
73 }
74 
75 //-----------------------------------------------------------------------------
76 
rasterToQPixmap(const TRaster32P & ras,bool premultiplied,bool setDevPixRatio)77 QPixmap rasterToQPixmap(const TRaster32P &ras, bool premultiplied,
78                         bool setDevPixRatio) {
79   QPixmap pixmap = QPixmap::fromImage(rasterToQImage(ras, premultiplied));
80   if (setDevPixRatio) {
81     pixmap.setDevicePixelRatio(getDevPixRatio());
82   }
83   return pixmap;
84 }
85 
86 //-----------------------------------------------------------------------------
87 
rasterFromQImage(QImage image,bool premultiply,bool mirror)88 TRaster32P rasterFromQImage(
89     QImage image, bool premultiply,
90     bool mirror)  // no need of const& - Qt uses implicit sharing...
91 {
92   QImage copyImage = mirror ? image.mirrored() : image;
93   TRaster32P ras(image.width(), image.height(), image.width(),
94                  (TPixelRGBM32 *)copyImage.bits(), false);
95   if (premultiply) TRop::premultiply(ras);
96   return ras->clone();
97 }
98 
99 //-----------------------------------------------------------------------------
100 
rasterFromQPixmap(QPixmap pixmap,bool premultiply,bool mirror)101 TRaster32P rasterFromQPixmap(
102     QPixmap pixmap, bool premultiply,
103     bool mirror)  // no need of const& - Qt uses implicit sharing...
104 {
105   QImage image = pixmap.toImage();
106   return rasterFromQImage(image, premultiply, mirror);
107 }
108 
109 //-----------------------------------------------------------------------------
110 
drawPolygon(QPainter & p,const std::vector<QPointF> & points,bool fill,const QColor colorFill,const QColor colorLine)111 void drawPolygon(QPainter &p, const std::vector<QPointF> &points, bool fill,
112                  const QColor colorFill, const QColor colorLine) {
113   if (points.size() == 0) return;
114   p.setPen(colorLine);
115   QPolygonF E0Polygon;
116   int i = 0;
117   for (i = 0; i < (int)points.size(); i++) E0Polygon << QPointF(points[i]);
118   E0Polygon << QPointF(points[0]);
119 
120   QPainterPath E0Path;
121   E0Path.addPolygon(E0Polygon);
122   if (fill) p.fillPath(E0Path, QBrush(colorFill));
123   p.drawPath(E0Path);
124 }
125 
126 //-----------------------------------------------------------------------------
127 
drawArrow(QPainter & p,const QPointF a,const QPointF b,const QPointF c,bool fill,const QColor colorFill,const QColor colorLine)128 void drawArrow(QPainter &p, const QPointF a, const QPointF b, const QPointF c,
129                bool fill, const QColor colorFill, const QColor colorLine) {
130   std::vector<QPointF> pts;
131   pts.push_back(a);
132   pts.push_back(b);
133   pts.push_back(c);
134   drawPolygon(p, pts, fill, colorFill, colorLine);
135 }
136 
137 //-----------------------------------------------------------------------------
138 
scalePixmapKeepingAspectRatio(QPixmap pixmap,QSize size,QColor color)139 QPixmap scalePixmapKeepingAspectRatio(QPixmap pixmap, QSize size,
140                                       QColor color) {
141   if (pixmap.isNull()) return pixmap;
142   if (pixmap.devicePixelRatio() > 1.0) size *= pixmap.devicePixelRatio();
143   if (pixmap.size() == size) return pixmap;
144   QPixmap scaledPixmap =
145       pixmap.scaled(size.width(), size.height(), Qt::KeepAspectRatio,
146                     Qt::SmoothTransformation);
147   QPixmap newPixmap(size);
148   newPixmap.fill(color);
149   QPainter painter(&newPixmap);
150   painter.drawPixmap(double(size.width() - scaledPixmap.width()) * 0.5,
151                      double(size.height() - scaledPixmap.height()) * 0.5,
152                      scaledPixmap);
153   newPixmap.setDevicePixelRatio(pixmap.devicePixelRatio());
154   return newPixmap;
155 }
156 
157 //-----------------------------------------------------------------------------
158 
svgToPixmap(const QString & svgFilePath,const QSize & size,Qt::AspectRatioMode aspectRatioMode,QColor bgColor)159 QPixmap svgToPixmap(const QString &svgFilePath, const QSize &size,
160                     Qt::AspectRatioMode aspectRatioMode, QColor bgColor) {
161   static int devPixRatio = getDevPixRatio();
162   QSvgRenderer svgRenderer(svgFilePath);
163   QSize pixmapSize;
164   QRectF renderRect;
165   if (size.isEmpty()) {
166     pixmapSize = svgRenderer.defaultSize() * devPixRatio;
167     renderRect = QRectF(QPointF(), QSizeF(pixmapSize));
168   } else {
169     pixmapSize = size * devPixRatio;
170     if (aspectRatioMode == Qt::KeepAspectRatio ||
171         aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
172       QSize imgSize = svgRenderer.defaultSize();
173       QPointF scaleFactor((float)pixmapSize.width() / (float)imgSize.width(),
174                           (float)pixmapSize.height() / (float)imgSize.height());
175       float factor = (aspectRatioMode == Qt::KeepAspectRatio)
176                          ? std::min(scaleFactor.x(), scaleFactor.y())
177                          : std::max(scaleFactor.x(), scaleFactor.y());
178       QSizeF renderSize(factor * (float)imgSize.width(),
179                         factor * (float)imgSize.height());
180       QPointF topLeft(
181           ((float)pixmapSize.width() - renderSize.width()) * 0.5f,
182           ((float)pixmapSize.height() - renderSize.height()) * 0.5f);
183       renderRect = QRectF(topLeft, renderSize);
184     } else {  // Qt::IgnoreAspectRatio:
185       renderRect = QRectF(QPointF(), QSizeF(pixmapSize));
186     }
187   }
188   QPixmap pixmap(pixmapSize);
189   QPainter painter;
190   pixmap.fill(bgColor);
191   painter.begin(&pixmap);
192   svgRenderer.render(&painter, renderRect);
193   painter.end();
194   pixmap.setDevicePixelRatio(devPixRatio);
195   return pixmap;
196 }
197 
198 //-----------------------------------------------------------------------------
199 
getDevPixRatio()200 int getDevPixRatio() {
201   static int devPixRatio = QApplication::desktop()->devicePixelRatio();
202   return devPixRatio;
203 }
204 
205 //-----------------------------------------------------------------------------
206 
getIconThemePath(const QString & fileSVGPath)207 QString getIconThemePath(const QString &fileSVGPath) {
208   // Use as follows:
209   // QPixmap pixmapIcon = getIconThemePath("path/to/file.svg");
210   // Is equal to:            :icons/*theme*/path/to/file.svg
211 
212   // Set themeable directory
213   static QString theme = Preferences::instance()->getIconTheme()
214                              ? ":icons/dark/"
215                              : ":icons/light/";
216 
217   // If no file in light icon theme directory, fallback to dark directory
218   if (!QFile::exists(QString(theme + fileSVGPath))) theme = ":icons/dark/";
219 
220   return theme + fileSVGPath;
221 }
222 
223 //-----------------------------------------------------------------------------
224 
compositePixmap(QPixmap pixmap,const qreal & opacity,const QSize & size,const int leftAdj,const int topAdj,QColor bgColor)225 QPixmap compositePixmap(QPixmap pixmap, const qreal &opacity, const QSize &size,
226                         const int leftAdj, const int topAdj, QColor bgColor) {
227   static int devPixRatio = getDevPixRatio();
228 
229   // Sets size of destination pixmap for source to be drawn onto, if size is
230   // empty use source pixmap size, else use custom size.
231   QPixmap destination(size.isEmpty() ? pixmap.size() : size * devPixRatio);
232   destination.setDevicePixelRatio(devPixRatio);
233   destination.fill(bgColor);
234 
235   if (!pixmap.isNull()) {
236     QPainter p(&destination);
237     pixmap = pixmap.scaled(pixmap.size(), Qt::KeepAspectRatio);
238     pixmap.setDevicePixelRatio(devPixRatio);
239     p.setBackgroundMode(Qt::TransparentMode);
240     p.setBackground(QBrush(Qt::transparent));
241     p.eraseRect(pixmap.rect());
242     p.setOpacity(opacity);
243     p.drawPixmap(leftAdj, topAdj, pixmap);
244   }
245   return destination;
246 }
247 
248 //-----------------------------------------------------------------------------
249 
recolorPixmap(QPixmap pixmap,QColor color)250 QPixmap recolorPixmap(QPixmap pixmap, QColor color) {
251   // Change black pixels to any chosen color
252   QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
253   for (int y = 0; y < img.height(); y++) {
254     QRgb *pixel = reinterpret_cast<QRgb *>(img.scanLine(y));
255     QRgb *end   = pixel + img.width();
256     for (; pixel != end; pixel++) {
257       // Only recolor zero value (black) pixels
258       if (QColor::fromRgba(*pixel).value() == 0)
259         *pixel =
260             QColor(color.red(), color.green(), color.blue(), qAlpha(*pixel))
261                 .rgba();
262     }
263   }
264   pixmap = QPixmap::fromImage(img);
265   return pixmap;
266 }
267 
268 //-----------------------------------------------------------------------------
269 
createQIcon(const char * iconSVGName,bool useFullOpacity,bool isForMenuItem)270 QIcon createQIcon(const char *iconSVGName, bool useFullOpacity,
271                   bool isForMenuItem) {
272   static int devPixRatio = getDevPixRatio();
273 
274   QIcon themeIcon = QIcon::fromTheme(iconSVGName);
275 
276   // Get icon dimensions
277   QSize iconSize(0, 0);
278   for (QList<QSize> sizes = themeIcon.availableSizes(); !sizes.isEmpty();
279        sizes.removeFirst())
280     if (sizes.first().width() > iconSize.width())
281       iconSize = sizes.first() * devPixRatio;
282 
283   // Control lightness of the icons
284   const qreal activeOpacity   = 1;
285   const qreal baseOpacity     = useFullOpacity ? 1 : 0.8;
286   const qreal disabledOpacity = 0.15;
287 
288   // Psuedo state name strings
289   QString overStr = QString(iconSVGName) + "_over";
290   QString onStr   = QString(iconSVGName) + "_on";
291 
292   //----------
293 
294   // Base pixmap
295   QPixmap themeIconPixmap(recolorPixmap(themeIcon.pixmap(iconSize)));
296   if (!themeIconPixmap.isNull()) {  // suppress message
297     themeIconPixmap.setDevicePixelRatio(devPixRatio);
298     themeIconPixmap = themeIconPixmap.scaled(iconSize, Qt::KeepAspectRatio,
299                                              Qt::SmoothTransformation);
300   }
301 
302   // Over pixmap
303   QPixmap overPixmap(recolorPixmap(QIcon::fromTheme(overStr).pixmap(iconSize)));
304   if (!overPixmap.isNull()) {  // suppress message
305     overPixmap.setDevicePixelRatio(devPixRatio);
306     overPixmap = overPixmap.scaled(iconSize, Qt::KeepAspectRatio,
307                                    Qt::SmoothTransformation);
308   }
309 
310   // On pixmap
311   QPixmap onPixmap(recolorPixmap(QIcon::fromTheme(onStr).pixmap(iconSize)));
312   if (!onPixmap.isNull()) {  // suppress message
313     onPixmap.setDevicePixelRatio(devPixRatio);
314     onPixmap = onPixmap.scaled(iconSize, Qt::KeepAspectRatio,
315                                Qt::SmoothTransformation);
316   }
317 
318   //----------
319 
320   QIcon icon;
321 
322 #ifdef _WIN32
323   bool showIconInMenu = Preferences::instance()->getBoolValue(showIconsInMenu);
324   // set transparent icon
325   if (isForMenuItem &&
326       themeIconPixmap.size() == QSize(16 * devPixRatio, 16 * devPixRatio) &&
327       !showIconInMenu) {
328     static QPixmap emptyPm(16 * devPixRatio, 16 * devPixRatio);
329     emptyPm.fill(Qt::transparent);
330 
331     icon.addPixmap(emptyPm, QIcon::Normal, QIcon::Off);
332     icon.addPixmap(emptyPm, QIcon::Normal, QIcon::On);
333     icon.addPixmap(emptyPm, QIcon::Disabled, QIcon::Off);
334     icon.addPixmap(emptyPm, QIcon::Disabled, QIcon::On);
335     icon.addPixmap(emptyPm, QIcon::Active);
336   } else
337 #endif
338   {
339     // Base icon
340     icon.addPixmap(compositePixmap(themeIconPixmap, baseOpacity), QIcon::Normal,
341                    QIcon::Off);
342     icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity),
343                    QIcon::Disabled, QIcon::Off);
344 
345     // Over icon
346     icon.addPixmap(!overPixmap.isNull()
347                        ? compositePixmap(overPixmap, activeOpacity)
348                        : compositePixmap(themeIconPixmap, activeOpacity),
349                    QIcon::Active);
350 
351     // On icon
352     if (!onPixmap.isNull()) {
353       icon.addPixmap(compositePixmap(onPixmap, activeOpacity), QIcon::Normal,
354                      QIcon::On);
355       icon.addPixmap(compositePixmap(onPixmap, disabledOpacity),
356                      QIcon::Disabled, QIcon::On);
357     } else {
358       icon.addPixmap(compositePixmap(themeIconPixmap, activeOpacity),
359                      QIcon::Normal, QIcon::On);
360       icon.addPixmap(compositePixmap(themeIconPixmap, disabledOpacity),
361                      QIcon::Disabled, QIcon::On);
362     }
363   }
364   //----------
365 
366   // For icons intended for menus that are 16x16 in dimensions, to repurpose
367   // them for use in toolbars that are set for 20x20 we want to draw them onto a
368   // 20x20 pixmap so they don't get resized in the GUI, they will be loaded into
369   // the icon along with the original 16x16 pixmap.
370 
371   if (themeIconPixmap.size() == QSize(16 * devPixRatio, 16 * devPixRatio)) {
372     const QSize drawOnSize(20, 20);
373     const int x = (drawOnSize.width() - 16) / 2;   // left adjust
374     const int y = (drawOnSize.height() - 16) / 2;  // top adjust
375 
376     // Base icon
377     icon.addPixmap(
378         compositePixmap(themeIconPixmap, baseOpacity, drawOnSize, x, y),
379         QIcon::Normal, QIcon::Off);
380     icon.addPixmap(
381         compositePixmap(themeIconPixmap, disabledOpacity, drawOnSize, x, y),
382         QIcon::Disabled, QIcon::Off);
383 
384     // Over icon
385     icon.addPixmap(
386         !overPixmap.isNull()
387             ? compositePixmap(overPixmap, activeOpacity, drawOnSize, x, y)
388             : compositePixmap(themeIconPixmap, activeOpacity, drawOnSize, x, y),
389         QIcon::Active);
390 
391     // On icon
392     if (!onPixmap.isNull()) {
393       icon.addPixmap(compositePixmap(onPixmap, activeOpacity, drawOnSize, x, y),
394                      QIcon::Normal, QIcon::On);
395       icon.addPixmap(
396           compositePixmap(onPixmap, disabledOpacity, drawOnSize, x, y),
397           QIcon::Disabled, QIcon::On);
398     } else {
399       icon.addPixmap(
400           compositePixmap(themeIconPixmap, activeOpacity, drawOnSize, x, y),
401           QIcon::Normal, QIcon::On);
402       icon.addPixmap(
403           compositePixmap(themeIconPixmap, disabledOpacity, drawOnSize, x, y),
404           QIcon::Disabled, QIcon::On);
405     }
406   }
407 
408   return icon;
409 }
410 
411 //-----------------------------------------------------------------------------
412 
createQIconPNG(const char * iconPNGName)413 QIcon createQIconPNG(const char *iconPNGName) {
414   QString normal = QString(":Resources/") + iconPNGName + ".png";
415   QString click  = QString(":Resources/") + iconPNGName + "_click.png";
416   QString over   = QString(":Resources/") + iconPNGName + "_over.png";
417 
418   QIcon icon;
419   icon.addFile(normal, QSize(), QIcon::Normal, QIcon::Off);
420   icon.addFile(click, QSize(), QIcon::Normal, QIcon::On);
421   icon.addFile(over, QSize(), QIcon::Active);
422 
423   return icon;
424 }
425 
426 //-----------------------------------------------------------------------------
427 
createQIconOnOffPNG(const char * iconPNGName,bool withOver)428 QIcon createQIconOnOffPNG(const char *iconPNGName, bool withOver) {
429   QString on   = QString(":Resources/") + iconPNGName + "_on.png";
430   QString off  = QString(":Resources/") + iconPNGName + "_off.png";
431   QString over = QString(":Resources/") + iconPNGName + "_over.png";
432 
433   QIcon icon;
434   icon.addFile(off, QSize(), QIcon::Normal, QIcon::Off);
435   icon.addFile(on, QSize(), QIcon::Normal, QIcon::On);
436   if (withOver)
437     icon.addFile(over, QSize(), QIcon::Active);
438   else
439     icon.addFile(on, QSize(), QIcon::Active);
440 
441   return icon;
442 }
443 
444 //-----------------------------------------------------------------------------
445 
createTemporaryIconFromName(const char * commandName)446 QIcon createTemporaryIconFromName(const char *commandName) {
447   const int visibleIconSize   = 20;
448   const int menubarIconSize   = 16;
449   const qreal activeOpacity   = 1;
450   const qreal baseOpacity     = 0.8;
451   const qreal disabledOpacity = 0.15;
452   QString name(commandName);
453   QList<QChar> iconChar;
454 
455   for (int i = 0; i < name.length(); i++) {
456     QChar c = name.at(i);
457     if (c.isUpper() && iconChar.size() < 2)
458       iconChar.append(c);
459     else if (c.isDigit()) {
460       if (iconChar.isEmpty())
461         iconChar.append(c);
462       else if (iconChar.size() <= 2) {
463         if (iconChar.size() == 2) iconChar.removeLast();
464         iconChar.append(c);
465         break;
466       }
467     }
468   }
469 
470   if (iconChar.isEmpty()) iconChar.append(name.at(0));
471 
472   QString iconStr;
473   for (auto c : iconChar) iconStr.append(c);
474 
475   QIcon icon;
476   // prepare for both normal and high dpi
477   for (int devPixelRatio = 1; devPixelRatio <= 2; devPixelRatio++) {
478     QPixmap transparentPm(menubarIconSize * devPixelRatio,
479                           menubarIconSize * devPixelRatio);
480     transparentPm.fill(Qt::transparent);
481 
482     int pxSize = visibleIconSize * devPixelRatio;
483 
484     QPixmap pixmap(pxSize, pxSize);
485     QPainter painter;
486     pixmap.fill(Qt::transparent);
487     painter.begin(&pixmap);
488 
489     painter.setPen(Preferences::instance()->getIconTheme() ? Qt::black
490                                                            : Qt::white);
491 
492     QRect rect(0, -2, pxSize, pxSize);
493     if (iconStr.size() == 2) {
494       painter.scale(0.6, 1.0);
495       rect.setRight(pxSize / 0.6);
496     }
497     QFont font = painter.font();
498     font.setPixelSize(pxSize);
499     painter.setFont(font);
500 
501     painter.drawText(rect, Qt::AlignCenter, iconStr);
502 
503     painter.end();
504 
505     // For menu only
506     icon.addPixmap(transparentPm, QIcon::Normal, QIcon::Off);
507     icon.addPixmap(transparentPm, QIcon::Active);
508     icon.addPixmap(transparentPm, QIcon::Normal, QIcon::On);
509     icon.addPixmap(transparentPm, QIcon::Disabled, QIcon::Off);
510     icon.addPixmap(transparentPm, QIcon::Disabled, QIcon::On);
511 
512     // For toolbars
513     icon.addPixmap(compositePixmap(pixmap, baseOpacity), QIcon::Normal,
514                    QIcon::Off);
515     icon.addPixmap(compositePixmap(pixmap, disabledOpacity), QIcon::Disabled,
516                    QIcon::Off);
517     icon.addPixmap(compositePixmap(pixmap, activeOpacity), QIcon::Active);
518     icon.addPixmap(compositePixmap(pixmap, activeOpacity), QIcon::Normal,
519                    QIcon::On);
520     icon.addPixmap(compositePixmap(pixmap, disabledOpacity), QIcon::Disabled,
521                    QIcon::On);
522   }
523   return icon;
524 }
525 
526 //-----------------------------------------------------------------------------
527 
toQString(const TFilePath & path)528 QString toQString(const TFilePath &path) {
529   return QString::fromStdWString(path.getWideString());
530 }
531 
532 //-----------------------------------------------------------------------------
533 
isSpaceString(const QString & str)534 bool isSpaceString(const QString &str) {
535   int i;
536   QString space(" ");
537   for (i = 0; i < str.size(); i++)
538     if (str.at(i) != space.at(0)) return false;
539   return true;
540 }
541 
542 //-----------------------------------------------------------------------------
543 
isValidFileName(const QString & fileName)544 bool isValidFileName(const QString &fileName) {
545   if (fileName.isEmpty() || fileName.contains(":") || fileName.contains("\\") ||
546       fileName.contains("/") || fileName.contains(">") ||
547       fileName.contains("<") || fileName.contains("*") ||
548       fileName.contains("|") || fileName.contains("\"") ||
549       fileName.contains("?") || fileName.trimmed().isEmpty())
550     return false;
551   return true;
552 }
553 
554 //-----------------------------------------------------------------------------
555 
isValidFileName_message(const QString & fileName)556 bool isValidFileName_message(const QString &fileName) {
557   return isValidFileName(fileName)
558              ? true
559              : (DVGui::error(
560                     QObject::tr("The file name cannot be empty or contain any "
561                                 "of the following "
562                                 "characters: (new line) \\ / : * ? \" |")),
563                 false);
564 }
565 
566 //-----------------------------------------------------------------------------
567 
isReservedFileName(const QString & fileName)568 bool isReservedFileName(const QString &fileName) {
569 #ifdef _WIN32
570   std::vector<QString> invalidNames{
571       "AUX",  "CON",  "NUL",  "PRN",  "COM1", "COM2", "COM3", "COM4",
572       "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3",
573       "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
574 
575   if (std::find(invalidNames.begin(), invalidNames.end(), fileName) !=
576       invalidNames.end())
577     return true;
578 #endif
579 
580   return false;
581 }
582 
583 //-----------------------------------------------------------------------------
584 
isReservedFileName_message(const QString & fileName)585 bool isReservedFileName_message(const QString &fileName) {
586   return isReservedFileName(fileName)
587              ? (DVGui::error(QObject::tr(
588                     "That is a reserved file name and cannot be used.")),
589                 true)
590              : false;
591 }
592 
593 //-----------------------------------------------------------------------------
594 
elideText(const QString & srcText,const QFont & font,int width)595 QString elideText(const QString &srcText, const QFont &font, int width) {
596   QFontMetrics metrix(font);
597   int srcWidth = metrix.width(srcText);
598   if (srcWidth < width) return srcText;
599   int tilde = metrix.width("~");
600   int block = (width - tilde) / 2;
601   QString text("");
602   int i;
603   for (i = 0; i < srcText.size(); i++) {
604     text += srcText.at(i);
605     if (metrix.width(text) > block) break;
606   }
607   text[i] = '~';
608   QString endText("");
609   for (i = srcText.size() - 1; i >= 0; i--) {
610     endText.push_front(srcText.at(i));
611     if (metrix.width(endText) > block) break;
612   }
613   endText.remove(0, 1);
614   text += endText;
615   return text;
616 }
617 
618 //-----------------------------------------------------------------------------
619 
elideText(const QString & srcText,const QFontMetrics & fm,int width,const QString & elideSymbol)620 QString elideText(const QString &srcText, const QFontMetrics &fm, int width,
621                   const QString &elideSymbol) {
622   QString text(srcText);
623 
624   for (int i = text.size(); i > 1 && fm.width(text) > width;)
625     text = srcText.left(--i).append(elideSymbol);
626 
627   return text;
628 }
629 
630 //-----------------------------------------------------------------------------
631 
pathToUrl(const TFilePath & path)632 QUrl pathToUrl(const TFilePath &path) {
633   return QUrl::fromLocalFile(QString::fromStdWString(path.getWideString()));
634 }
635 
636 //-----------------------------------------------------------------------------
637 
isResource(const QString & path)638 bool isResource(const QString &path) {
639   const TFilePath fp(path.toStdWString());
640   TFileType::Type type = TFileType::getInfo(fp);
641 
642   return (TFileType::isViewable(type) || type & TFileType::MESH_IMAGE ||
643           type == TFileType::AUDIO_LEVEL || type == TFileType::TABSCENE ||
644           type == TFileType::TOONZSCENE || fp.getType() == "tpl");
645 }
646 
647 //-----------------------------------------------------------------------------
648 
isResource(const QUrl & url)649 bool isResource(const QUrl &url) { return isResource(url.toLocalFile()); }
650 
651 //-----------------------------------------------------------------------------
652 
isResourceOrFolder(const QUrl & url)653 bool isResourceOrFolder(const QUrl &url) {
654   struct locals {
655     static inline bool isDir(const QString &path) {
656       return QFileInfo(path).isDir();
657     }
658   };  // locals
659 
660   const QString &path = url.toLocalFile();
661   return (isResource(path) || locals::isDir(path));
662 }
663 
664 //-----------------------------------------------------------------------------
665 
acceptResourceDrop(const QList<QUrl> & urls)666 bool acceptResourceDrop(const QList<QUrl> &urls) {
667   int count = 0;
668   for (const QUrl &url : urls) {
669     if (isResource(url))
670       ++count;
671     else
672       return false;
673   }
674 
675   return (count > 0);
676 }
677 
678 //-----------------------------------------------------------------------------
679 
acceptResourceOrFolderDrop(const QList<QUrl> & urls)680 bool acceptResourceOrFolderDrop(const QList<QUrl> &urls) {
681   int count = 0;
682   for (const QUrl &url : urls) {
683     if (isResourceOrFolder(url))
684       ++count;
685     else
686       return false;
687   }
688 
689   return (count > 0);
690 }
691 
692 //-----------------------------------------------------------------------------
693 
strokeToPainterPath(TStroke * stroke)694 QPainterPath strokeToPainterPath(TStroke *stroke) {
695   QPainterPath path;
696   int i, chunkSize = stroke->getChunkCount();
697   for (i = 0; i < chunkSize; i++) {
698     const TThickQuadratic *q = stroke->getChunk(i);
699     if (i == 0) path.moveTo(toQPointF(q->getThickP0()));
700     path.quadTo(toQPointF(q->getThickP1()), toQPointF(q->getThickP2()));
701   }
702   return path;
703 }
704 
705 //=============================================================================
706 // TabBarContainter
707 //-----------------------------------------------------------------------------
708 
TabBarContainter(QWidget * parent)709 TabBarContainter::TabBarContainter(QWidget *parent) : QFrame(parent) {
710   setObjectName("TabBarContainer");
711   setFrameStyle(QFrame::StyledPanel);
712 }
713 
714 //-----------------------------------------------------------------------------
715 
paintEvent(QPaintEvent * event)716 void TabBarContainter::paintEvent(QPaintEvent *event) {
717   QPainter p(this);
718   p.setPen(getBottomAboveLineColor());
719   p.drawLine(0, height() - 2, width(), height() - 2);
720   p.setPen(getBottomBelowLineColor());
721   p.drawLine(0, height() - 1, width(), height() - 1);
722 }
723 
724 //=============================================================================
725 // ToolBarContainer
726 //-----------------------------------------------------------------------------
727 
ToolBarContainer(QWidget * parent)728 ToolBarContainer::ToolBarContainer(QWidget *parent) : QFrame(parent) {
729   setObjectName("ToolBarContainer");
730   setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
731 }
732 
733 //-----------------------------------------------------------------------------
734 
paintEvent(QPaintEvent * event)735 void ToolBarContainer::paintEvent(QPaintEvent *event) { QPainter p(this); }
736 
737 //=============================================================================
738 
operator +(const QString & a,const TFilePath & fp)739 QString operator+(const QString &a, const TFilePath &fp) {
740   return a + QString::fromStdWString(fp.getWideString());
741 }
742