Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/gutil.h"
Kite 521c84
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/dvdialog.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "traster.h"
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
#include "tfilepath.h"
Toshihiro Shimizu 890ddd
#include "tfiletype.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tcurves.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "tmsgcore.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
konero 7bed16
#include <qdiriterator></qdiriterator>
Toshihiro Shimizu 890ddd
#include <qpixmap></qpixmap>
Toshihiro Shimizu 890ddd
#include <qimage></qimage>
Toshihiro Shimizu 890ddd
#include <qpainter></qpainter>
Toshihiro Shimizu 890ddd
#include <qpainterpath></qpainterpath>
Toshihiro Shimizu 890ddd
#include <qicon></qicon>
Toshihiro Shimizu 890ddd
#include <qstring></qstring>
Toshihiro Shimizu 890ddd
#include <qapplication></qapplication>
Toshihiro Shimizu 890ddd
#include <qmouseevent></qmouseevent>
Toshihiro Shimizu 890ddd
#include <qtabletevent></qtabletevent>
Toshihiro Shimizu 890ddd
#include <qkeyevent></qkeyevent>
Toshihiro Shimizu 890ddd
#include <qurl></qurl>
Toshihiro Shimizu 890ddd
#include <qfileinfo></qfileinfo>
shun_iwasawa 3cc41f
#include <qdesktopwidget></qdesktopwidget>
shun_iwasawa 3cc41f
#include <qsvgrenderer></qsvgrenderer>
shun-iwasawa f2e168
#include <qscreen></qscreen>
shun-iwasawa f2e168
#include <qwindow></qwindow>
konero 7bed16
#include <qdebug></qdebug>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace DVGui;
Toshihiro Shimizu 890ddd
shun-iwasawa f2e168
namespace {
shun-iwasawa f2e168
inline bool hasScreensWithDifferentDevPixRatio() {
shun-iwasawa f2e168
  static bool ret     = false;
shun-iwasawa f2e168
  static bool checked = false;
shun-iwasawa f2e168
  if (!checked) {  // check once
shun-iwasawa f2e168
    int dpr = QApplication::desktop()->devicePixelRatio();
shun-iwasawa f2e168
    for (auto screen : QGuiApplication::screens()) {
shun-iwasawa f2e168
      if ((int)screen->devicePixelRatio() != dpr) {
shun-iwasawa f2e168
        ret = true;
shun-iwasawa f2e168
        break;
shun-iwasawa f2e168
      }
shun-iwasawa f2e168
    }
shun-iwasawa f2e168
    checked = true;
shun-iwasawa f2e168
  }
shun-iwasawa f2e168
  return ret;
shun-iwasawa f2e168
}
shun-iwasawa f2e168
shun-iwasawa f2e168
int getHighestDevicePixelRatio() {
shun-iwasawa f2e168
  static int highestDevPixRatio = 0;
shun-iwasawa f2e168
  if (highestDevPixRatio == 0) {
shun-iwasawa f2e168
    for (auto screen : QGuiApplication::screens())
shun-iwasawa f2e168
      highestDevPixRatio =
shun-iwasawa f2e168
          std::max(highestDevPixRatio, (int)screen->devicePixelRatio());
shun-iwasawa f2e168
  }
shun-iwasawa f2e168
  return highestDevPixRatio;
shun-iwasawa f2e168
}
shun-iwasawa f2e168
}  // namespace
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString fileSizeString(qint64 size, int precision) {
Shinya Kitaoka 120a6e
  if (size < 1024)
Shinya Kitaoka 120a6e
    return QString::number(size) + " Bytes";
Shinya Kitaoka 120a6e
  else if (size < 1024 * 1024)
Shinya Kitaoka 120a6e
    return QString::number(size / (1024.0), 'f', precision) + " KB";
Shinya Kitaoka 120a6e
  else if (size < 1024 * 1024 * 1024)
Shinya Kitaoka 120a6e
    return QString::number(size / (1024 * 1024.0), 'f', precision) + " MB";
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return QString::number(size / (1024 * 1024 * 1024.0), 'f', precision) +
Shinya Kitaoka 120a6e
           " GB";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QImage rasterToQImage(const TRasterP &ras, bool premultiplied, bool mirrored) {
Shinya Kitaoka 120a6e
  if (TRaster32P ras32 = ras) {
Shinya Kitaoka 120a6e
    QImage image(ras->getRawData(), ras->getLx(), ras->getLy(),
Shinya Kitaoka 120a6e
                 premultiplied ? QImage::Format_ARGB32_Premultiplied
Shinya Kitaoka 120a6e
                               : QImage::Format_ARGB32);
Shinya Kitaoka 120a6e
    if (mirrored) return image.mirrored();
Shinya Kitaoka 120a6e
    return image;
Shinya Kitaoka 120a6e
  } else if (TRasterGR8P ras8 = ras) {
Shinya Kitaoka 120a6e
    QImage image(ras->getRawData(), ras->getLx(), ras->getLy(), ras->getWrap(),
Shinya Kitaoka 120a6e
                 QImage::Format_Indexed8);
Shinya Kitaoka 120a6e
    static QVector<qrgb> colorTable;</qrgb>
Shinya Kitaoka 120a6e
    if (colorTable.size() == 0) {
Shinya Kitaoka 120a6e
      int i;
Shinya Kitaoka 120a6e
      for (i = 0; i < 256; i++) colorTable.append(QColor(i, i, i).rgb());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    image.setColorTable(colorTable);
Shinya Kitaoka 120a6e
    if (mirrored) return image.mirrored();
Shinya Kitaoka 120a6e
    return image;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return QImage();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun_iwasawa 3cc41f
QPixmap rasterToQPixmap(const TRaster32P &ras, bool premultiplied,
shun_iwasawa 3cc41f
                        bool setDevPixRatio) {
shun_iwasawa 3cc41f
  QPixmap pixmap = QPixmap::fromImage(rasterToQImage(ras, premultiplied));
shun_iwasawa 3cc41f
  if (setDevPixRatio) {
shun-iwasawa f2e168
    pixmap.setDevicePixelRatio(getDevicePixelRatio());
shun_iwasawa 3cc41f
  }
shun_iwasawa 3cc41f
  return pixmap;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRaster32P rasterFromQImage(
Shinya Kitaoka 120a6e
    QImage image, bool premultiply,
Shinya Kitaoka 120a6e
    bool mirror)  // no need of const& - Qt uses implicit sharing...
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  QImage copyImage = mirror ? image.mirrored() : image;
Shinya Kitaoka 120a6e
  TRaster32P ras(image.width(), image.height(), image.width(),
Shinya Kitaoka 120a6e
                 (TPixelRGBM32 *)copyImage.bits(), false);
Shinya Kitaoka 120a6e
  if (premultiply) TRop::premultiply(ras);
Shinya Kitaoka 120a6e
  return ras->clone();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRaster32P rasterFromQPixmap(
Shinya Kitaoka 120a6e
    QPixmap pixmap, bool premultiply,
Shinya Kitaoka 120a6e
    bool mirror)  // no need of const& - Qt uses implicit sharing...
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  QImage image = pixmap.toImage();
Shinya Kitaoka 120a6e
  return rasterFromQImage(image, premultiply, mirror);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void drawPolygon(QPainter &p, const std::vector<qpointf> &points, bool fill,</qpointf>
Shinya Kitaoka 120a6e
                 const QColor colorFill, const QColor colorLine) {
Shinya Kitaoka 120a6e
  if (points.size() == 0) return;
Shinya Kitaoka 120a6e
  p.setPen(colorLine);
Shinya Kitaoka 120a6e
  QPolygonF E0Polygon;
Shinya Kitaoka 120a6e
  int i = 0;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)points.size(); i++) E0Polygon << QPointF(points[i]);
Shinya Kitaoka 120a6e
  E0Polygon << QPointF(points[0]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QPainterPath E0Path;
Shinya Kitaoka 120a6e
  E0Path.addPolygon(E0Polygon);
Shinya Kitaoka 120a6e
  if (fill) p.fillPath(E0Path, QBrush(colorFill));
Shinya Kitaoka 120a6e
  p.drawPath(E0Path);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void drawArrow(QPainter &p, const QPointF a, const QPointF b, const QPointF c,
Shinya Kitaoka 120a6e
               bool fill, const QColor colorFill, const QColor colorLine) {
Shinya Kitaoka 120a6e
  std::vector<qpointf> pts;</qpointf>
Shinya Kitaoka 120a6e
  pts.push_back(a);
Shinya Kitaoka 120a6e
  pts.push_back(b);
Shinya Kitaoka 120a6e
  pts.push_back(c);
Shinya Kitaoka 120a6e
  drawPolygon(p, pts, fill, colorFill, colorLine);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QPixmap scalePixmapKeepingAspectRatio(QPixmap pixmap, QSize size,
Shinya Kitaoka 120a6e
                                      QColor color) {
shun_iwasawa 3cc41f
  if (pixmap.isNull()) return pixmap;
shun_iwasawa 3cc41f
  if (pixmap.devicePixelRatio() > 1.0) size *= pixmap.devicePixelRatio();
shun_iwasawa 3cc41f
  if (pixmap.size() == size) return pixmap;
Shinya Kitaoka 120a6e
  QPixmap scaledPixmap =
Shinya Kitaoka 120a6e
      pixmap.scaled(size.width(), size.height(), Qt::KeepAspectRatio,
Shinya Kitaoka 120a6e
                    Qt::SmoothTransformation);
Shinya Kitaoka 120a6e
  QPixmap newPixmap(size);
Shinya Kitaoka 120a6e
  newPixmap.fill(color);
Shinya Kitaoka 120a6e
  QPainter painter(&newPixmap);
Shinya Kitaoka 120a6e
  painter.drawPixmap(double(size.width() - scaledPixmap.width()) * 0.5,
Shinya Kitaoka 120a6e
                     double(size.height() - scaledPixmap.height()) * 0.5,
Shinya Kitaoka 120a6e
                     scaledPixmap);
shun_iwasawa 3cc41f
  newPixmap.setDevicePixelRatio(pixmap.devicePixelRatio());
Shinya Kitaoka 120a6e
  return newPixmap;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
konero 7bed16
int getDevicePixelRatio(const QWidget *widget) {
konero 7bed16
  if (hasScreensWithDifferentDevPixRatio() && widget) {
konero 7bed16
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
konero 7bed16
    return widget->screen()->devicePixelRatio();
konero 7bed16
#else
konero 7bed16
    if (!widget->windowHandle()) widget->winId();
konero 7bed16
    if (widget->windowHandle())
konero 7bed16
      return widget->windowHandle()->devicePixelRatio();
konero 7bed16
#endif
konero 7bed16
  }
konero 7bed16
  static int devPixRatio = QApplication::desktop()->devicePixelRatio();
konero 7bed16
  return devPixRatio;
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// Calculate render params for use by svgToImage() and svgToPixmap()
konero 7bed16
SvgRenderParams calculateSvgRenderParams(const QSize &desiredSize,
konero 7bed16
                                         QSize &imageSize,
konero 7bed16
                                         Qt::AspectRatioMode aspectRatioMode) {
konero 7bed16
  SvgRenderParams params;
konero 7bed16
  if (desiredSize.isEmpty()) {
konero 7bed16
    params.size = imageSize;
konero 7bed16
    params.rect = QRectF(QPointF(), QSizeF(params.size));
shun_iwasawa 3cc41f
  } else {
konero 7bed16
    params.size = desiredSize;
shun_iwasawa 3cc41f
    if (aspectRatioMode == Qt::KeepAspectRatio ||
shun_iwasawa 3cc41f
        aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
konero 7bed16
      QPointF scaleFactor(
konero 7bed16
          (float)params.size.width() / (float)imageSize.width(),
konero 7bed16
          (float)params.size.height() / (float)imageSize.height());
shun_iwasawa 3cc41f
      float factor = (aspectRatioMode == Qt::KeepAspectRatio)
shun_iwasawa 3cc41f
                         ? std::min(scaleFactor.x(), scaleFactor.y())
shun_iwasawa 3cc41f
                         : std::max(scaleFactor.x(), scaleFactor.y());
konero 7bed16
      QSizeF renderSize(factor * (float)imageSize.width(),
konero 7bed16
                        factor * (float)imageSize.height());
shun_iwasawa 3cc41f
      QPointF topLeft(
konero 7bed16
          ((float)params.size.width() - renderSize.width()) * 0.5f,
konero 7bed16
          ((float)params.size.height() - renderSize.height()) * 0.5f);
konero 7bed16
      params.rect = QRectF(topLeft, renderSize);
shun_iwasawa 3cc41f
    } else {  // Qt::IgnoreAspectRatio:
konero 7bed16
      params.rect = QRectF(QPointF(), QSizeF(params.size));
shun_iwasawa 3cc41f
    }
shun_iwasawa 3cc41f
  }
konero 7bed16
  return params;
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
QPixmap svgToPixmap(const QString &svgFilePath, QSize size,
konero 7bed16
                    Qt::AspectRatioMode aspectRatioMode, QColor bgColor) {
konero 7bed16
  if (svgFilePath.isEmpty()) return QPixmap();
konero 7bed16
konero 7bed16
  QSvgRenderer svgRenderer(svgFilePath);
konero 7bed16
konero 7bed16
  // Check if SVG file was loaded correctly
konero 7bed16
  if (!svgRenderer.isValid()) {
konero 7bed16
    qDebug() << "Invalid SVG file:" << svgFilePath;
konero 7bed16
    return QPixmap();
konero 7bed16
  }
konero 7bed16
konero 7bed16
  static int devPixRatio = getHighestDevicePixelRatio();
konero 7bed16
  if (!size.isEmpty()) size *= devPixRatio;
konero 7bed16
konero 7bed16
  QSize imageSize = svgRenderer.defaultSize() * devPixRatio;
konero 7bed16
  SvgRenderParams params =
konero 7bed16
      calculateSvgRenderParams(size, imageSize, aspectRatioMode);
konero 7bed16
  QPixmap pixmap(params.size);
shun_iwasawa 3cc41f
  QPainter painter;
shun_iwasawa 3cc41f
  pixmap.fill(bgColor);
konero 7bed16
konero 7bed16
  if (!painter.begin(&pixmap)) {
konero 7bed16
    qDebug() << "Failed to begin QPainter on pixmap";
konero 7bed16
    return QPixmap();
konero 7bed16
  }
konero 7bed16
konero 7bed16
  svgRenderer.render(&painter, params.rect);
shun_iwasawa 3cc41f
  painter.end();
shun_iwasawa 3cc41f
  pixmap.setDevicePixelRatio(devPixRatio);
shun_iwasawa 3cc41f
  return pixmap;
shun_iwasawa 3cc41f
}
shun_iwasawa 3cc41f
shun_iwasawa 3cc41f
//-----------------------------------------------------------------------------
shun_iwasawa 3cc41f
konero 7bed16
QImage svgToImage(const QString &svgFilePath, QSize size,
konero 7bed16
                  Qt::AspectRatioMode aspectRatioMode, QColor bgColor) {
konero 7bed16
  if (svgFilePath.isEmpty()) return QImage();
konero 7bed16
konero 7bed16
  QSvgRenderer svgRenderer(svgFilePath);
konero 7bed16
konero 7bed16
  // Check if SVG file was loaded correctly
konero 7bed16
  if (!svgRenderer.isValid()) {
konero 7bed16
    qDebug() << "Invalid SVG file:" << svgFilePath;
konero 7bed16
    return QImage();
shun-iwasawa f2e168
  }
konero 7bed16
konero 7bed16
  static int devPixRatio = getHighestDevicePixelRatio();
konero 7bed16
konero 7bed16
  QSize imageSize = svgRenderer.defaultSize() * devPixRatio;
konero 7bed16
  SvgRenderParams params =
konero 7bed16
      calculateSvgRenderParams(size, imageSize, aspectRatioMode);
konero 7bed16
  QImage image(params.size, QImage::Format_ARGB32_Premultiplied);
konero 7bed16
  QPainter painter;
konero 7bed16
  image.fill(bgColor);
konero 7bed16
konero 7bed16
  if (!painter.begin(&image)) {
konero 7bed16
    qDebug() << "Failed to begin QPainter on image";
konero 7bed16
    return QImage();
konero 7bed16
  }
konero 7bed16
konero 7bed16
  svgRenderer.render(&painter, params.rect);
konero 7bed16
  painter.end();
konero 7bed16
  return image;
shun_iwasawa 3cc41f
}
shun_iwasawa 3cc41f
shun_iwasawa 3cc41f
//-----------------------------------------------------------------------------
shun_iwasawa 3cc41f
konero 7bed16
// Change the opacity of a QImage (0.0 - 1.0)
konero 7bed16
QImage adjustImageOpacity(const QImage &input, qreal opacity) {
konero 7bed16
  if (input.isNull()) return QImage();
konero 7bed16
konero 7bed16
  QImage result(input.size(), QImage::Format_ARGB32_Premultiplied);
Toshihiro Shimizu 890ddd
konero 7bed16
  QPainter painter(&result);
konero 7bed16
  if (!painter.isActive()) return QImage();
Kite 521c84
konero 7bed16
  painter.setCompositionMode(QPainter::CompositionMode_Source);
konero 7bed16
  painter.fillRect(result.rect(), Qt::transparent);
konero 7bed16
  painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
konero 7bed16
  painter.drawImage(0, 0, input);
konero 7bed16
  painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
konero 7bed16
  painter.fillRect(
konero 7bed16
      result.rect(),
konero 7bed16
      QColor(0, 0, 0, qBound(0, static_cast<int>(opacity * 255), 255)));</int>
konero 7bed16
  painter.end();
Kite 521c84
konero 7bed16
  return result;
Kite 521c84
}
Kite 521c84
Kite 521c84
//-----------------------------------------------------------------------------
Kite 521c84
konero 7bed16
// Resizes a QImage, if scaleInput is true then input image will scale according
konero 7bed16
// to newSize otherwise the input image will be centered and not scaled
konero 7bed16
QImage compositeImage(const QImage &input, QSize newSize, bool scaleInput,
konero 7bed16
                      QColor bgColor) {
konero 7bed16
  if (input.isNull()) return QImage();
konero 7bed16
konero 7bed16
  int devPixRatio = getHighestDevicePixelRatio();
konero 7bed16
konero 7bed16
  int w, h, x = 0, y = 0;
konero 7bed16
  if (newSize.isEmpty()) {
konero 7bed16
    w = input.width();
konero 7bed16
    h = input.height();
konero 7bed16
  } else {
konero 7bed16
    w = newSize.width() * devPixRatio;
konero 7bed16
    h = newSize.height() * devPixRatio;
konero 7bed16
    if (!scaleInput) {
konero 7bed16
      x = (w - input.width()) / 2;
konero 7bed16
      y = (h - input.height()) / 2;
konero 7bed16
    }
konero 7bed16
  }
konero 7bed16
konero 7bed16
  QImage newImage(w, h, QImage::Format_ARGB32_Premultiplied);
konero 7bed16
  newImage.fill(bgColor);
konero 7bed16
konero 7bed16
  if (scaleInput) {
konero 7bed16
    return input.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
konero 7bed16
  } else {
konero 7bed16
    QPainter painter(&newImage);
konero 7bed16
    if (!painter.isActive()) return QImage();
konero 7bed16
    painter.drawImage(QPoint(x, y), input);
konero 7bed16
    painter.end();
Kite 521c84
konero 7bed16
    return newImage;
Kite 521c84
  }
Kite 521c84
}
Kite 521c84
Kite 521c84
//-----------------------------------------------------------------------------
Kite 521c84
konero 7bed16
// Convert QImage to QPixmap and set device pixel ratio
konero 7bed16
QPixmap convertImageToPixmap(const QImage &image) {
konero 7bed16
  if (image.isNull()) return QPixmap();
konero 7bed16
konero 7bed16
  QPixmap pixmap(QPixmap::fromImage(image));
konero 7bed16
  int devPixRatio = getHighestDevicePixelRatio();
konero 7bed16
  pixmap.setDevicePixelRatio(devPixRatio);
konero 7bed16
Kite 52018c
  return pixmap;
Kite 52018c
}
Kite 52018c
Kite 52018c
//-----------------------------------------------------------------------------
Kite 52018c
konero 7bed16
// Load, theme colorize and change opacity of an icon image
konero 7bed16
QImage generateIconImage(const QString &iconSVGName, qreal opacity,
konero 7bed16
                         QSize newSize, Qt::AspectRatioMode aspectRatioMode) {
konero 7bed16
  static ThemeManager &themeManager = ThemeManager::getInstance();
Kite 521c84
konero 7bed16
  if (iconSVGName.isEmpty() || !themeManager.hasIcon(iconSVGName)) {
konero 7bed16
    return QImage();
konero 7bed16
  }
Kite c50ec4
konero 7bed16
  int devPixRatio = getHighestDevicePixelRatio();
konero 7bed16
  newSize *= devPixRatio;
Kite c50ec4
konero 7bed16
  // Path to icon image
konero 7bed16
  const QString imgPath = themeManager.getIconPath(iconSVGName);
Kite c50ec4
konero 7bed16
  // Convert SVG to QImage
konero 7bed16
  QImage image(svgToImage(imgPath, newSize, aspectRatioMode));
Kite c50ec4
konero 7bed16
  // Colorize QImage
konero 7bed16
  image = themeManager.recolorBlackPixels(image);
Kite c50ec4
konero 7bed16
  // Change opacity if required
konero 7bed16
  if (opacity != qreal(1.0)) image = adjustImageOpacity(image, opacity);
Kite c50ec4
konero 7bed16
  return image;
konero 7bed16
}
Kite c50ec4
konero 7bed16
//-----------------------------------------------------------------------------
Kite c50ec4
konero 7bed16
// Load, theme colorize and change opacity of an icon image file
konero 7bed16
QPixmap generateIconPixmap(const QString &iconSVGName, qreal opacity,
konero 7bed16
                           QSize newSize, Qt::AspectRatioMode aspectRatioMode) {
konero 7bed16
  QImage image =
konero 7bed16
      generateIconImage(iconSVGName, opacity, newSize, aspectRatioMode);
konero 7bed16
  return convertImageToPixmap(image);
konero 7bed16
}
Kite c50ec4
konero 7bed16
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
konero 7bed16
// Process and populate all modes and states of a QIcon
konero 7bed16
void addImagesToIcon(QIcon &icon, const QImage &baseImg, const QImage &overImg,
konero 7bed16
                     const QImage &onImg, bool useFullOpacity) {
konero 7bed16
  if (baseImg.isNull()) return;
shun-iwasawa bb8132
konero 7bed16
  ThemeManager &themeManager = ThemeManager::getInstance();
konero 7bed16
  const qreal offOpacity = useFullOpacity ? 1.0 : themeManager.getOffOpacity();
konero 7bed16
  const qreal onOpacity  = themeManager.getOnOpacity();
konero 7bed16
  const qreal disabledOpacity = themeManager.getDisabledOpacity();
Kite c50ec4
konero 7bed16
  // Generate more images using input images for other modes and states
konero 7bed16
  QImage offImg      = adjustImageOpacity(baseImg, offOpacity);
konero 7bed16
  QImage disabledImg = adjustImageOpacity(baseImg, disabledOpacity);
konero 7bed16
  QImage onDisabledImg =
konero 7bed16
      !onImg.isNull() ? adjustImageOpacity(onImg, disabledOpacity) : QImage();
konero 7bed16
konero 7bed16
  // Convert images to pixmaps and set device pixel ratio
konero 7bed16
  QPixmap basePm(convertImageToPixmap(baseImg));
konero 7bed16
  QPixmap offPm(convertImageToPixmap(offImg));
konero 7bed16
  QPixmap disabledPm(convertImageToPixmap(disabledImg));
konero 7bed16
  QPixmap overPm(convertImageToPixmap(overImg));
konero 7bed16
  QPixmap onPm(convertImageToPixmap(onImg));
konero 7bed16
  QPixmap onDisabledPm(convertImageToPixmap(onDisabledImg));
konero 7bed16
konero 7bed16
  // Add pixmaps to icon and fallback to basePm if 'over' and 'on' are null
konero 7bed16
  icon.addPixmap(offPm, QIcon::Normal, QIcon::Off);
konero 7bed16
  icon.addPixmap(disabledPm, QIcon::Disabled, QIcon::Off);
konero 7bed16
  icon.addPixmap(!overPm.isNull() ? overPm : basePm, QIcon::Active);
konero 7bed16
  icon.addPixmap(!onPm.isNull() ? onPm : basePm, QIcon::Normal, QIcon::On);
konero 7bed16
  icon.addPixmap(!onPm.isNull() ? onDisabledPm : disabledPm, QIcon::Disabled,
konero 7bed16
                 QIcon::On);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
konero d3dd18
void addSpecifiedSizedImageToIcon(QIcon &icon, const char *iconSVGName,
konero d3dd18
                                  QSize newSize) {
konero d3dd18
  static int devPixRatio = getHighestDevicePixelRatio();
konero d3dd18
  newSize *= devPixRatio;
konero d3dd18
konero d3dd18
  // Construct icon filenames
konero d3dd18
  QString iconName     = QString::fromUtf8(iconSVGName);
konero d3dd18
  QString overIconName = iconName + "_over";
konero d3dd18
  QString onIconName   = iconName + "_on";
konero d3dd18
konero d3dd18
  // Generate icon images
konero d3dd18
  QImage baseImg = generateIconImage(iconName, 1.0, newSize);
konero d3dd18
  QImage overImg = generateIconImage(overIconName, 1.0, newSize);
konero d3dd18
  QImage onImg   = generateIconImage(onIconName, 1.0, newSize);
konero d3dd18
konero d3dd18
  // Add newly sized images to the icon
konero d3dd18
  addImagesToIcon(icon, baseImg, overImg, onImg);
konero d3dd18
}
konero d3dd18
konero d3dd18
//-----------------------------------------------------------------------------
konero d3dd18
konero 7bed16
// Add the same pixmap to all modes and states of a QIcon
konero 7bed16
void addPixmapToAllModesAndStates(QIcon &icon, const QPixmap &pixmap) {
konero 4823ff
  QIcon::Mode modes[]   = {QIcon::Normal, QIcon::Disabled, QIcon::Selected};
konero 7bed16
  QIcon::State states[] = {QIcon::On, QIcon::Off};
konero 7bed16
konero 7bed16
  for (const auto &mode : modes) {
konero 7bed16
    for (const auto &state : states) {
konero 7bed16
      icon.addPixmap(pixmap, mode, state);
konero 7bed16
    }
shun-iwasawa 9b2afe
  }
konero 4823ff
  icon.addPixmap(pixmap, QIcon::Active, QIcon::Off);
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
shun-iwasawa 9b2afe
konero 7bed16
/// @brief Return a themed icon
konero 7bed16
/// @param iconSVGName Name of the icon (SVG file base name)
konero 7bed16
/// @param useFullOpacity If true the icon will be max brightness
konero 7bed16
/// @param isForMenuItem For special handling of menu icons
konero 7bed16
/// @param newSize Render the SVG images of the icon at the specified size
konero 7bed16
/// @return QIcon
konero 7bed16
QIcon createQIcon(const QString &iconSVGName, bool useFullOpacity,
konero 7bed16
                  bool isForMenuItem, QSize newSize) {
konero 7bed16
  static ThemeManager &themeManager = ThemeManager::getInstance();
konero 7bed16
  if (iconSVGName.isEmpty() || !themeManager.hasIcon(iconSVGName)) {
konero 7bed16
    // Use debug to check if something calls for an icon that doesn't exist
konero 7bed16
    //qDebug () << "File not found:" << iconSVGName;
konero 7bed16
    return QIcon();
shun-iwasawa 9b2afe
  }
shun-iwasawa 9b2afe
konero 7bed16
  static int devPixRatio = getHighestDevicePixelRatio();
konero 7bed16
konero 7bed16
  QImage baseImg(generateIconImage(iconSVGName, qreal(1.0), newSize));
konero 7bed16
  QImage overImg(generateIconImage(iconSVGName + "_over", qreal(1.0), newSize));
konero 7bed16
  QImage onImg(generateIconImage(iconSVGName + "_on", qreal(1.0), newSize));
konero 7bed16
konero 7bed16
  QIcon icon;
konero 543cca
  
konero 7bed16
  // START_BUG_WORKAROUND: #20230627
konero 7bed16
  // Set an empty pixmap for menu icons when hiding icons from menus is true,
konero 7bed16
  // search bug ID for more info.
konero 7bed16
#ifdef _WIN32
konero 7bed16
  bool showIconInMenu = Preferences::instance()->getBoolValue(showIconsInMenu);
konero 7bed16
  if (isForMenuItem && baseImg.width() == (16 * devPixRatio) &&
konero 7bed16
      baseImg.height() == (16 * devPixRatio) && !showIconInMenu) {
konero 7bed16
    static QPixmap emptyPm(16 * devPixRatio, 16 * devPixRatio);
konero 7bed16
    emptyPm.fill(Qt::transparent);
konero 7bed16
    addPixmapToAllModesAndStates(icon, emptyPm);
konero 7bed16
  } else
konero 7bed16
#endif  // END_BUG_WORKAROUND
konero 7bed16
  {
konero 7bed16
    addImagesToIcon(icon, baseImg, overImg, onImg, useFullOpacity);
shun-iwasawa 9b2afe
  }
shun-iwasawa 9b2afe
konero 7bed16
  // For tool bars we draw menu sized icons onto tool bar sized images otherwise
konero 7bed16
  // there can be scaling artifacts with high dpi and load these in addition
konero 7bed16
  if (baseImg.width() == (16 * devPixRatio) &&
konero 7bed16
      baseImg.height() == (16 * devPixRatio)) {
konero 3a5304
    for (auto screen : QApplication::screens()) {
konero 3a5304
      QSize expandSize(20, 20);
konero 3a5304
      int otherDevPixRatio = screen->devicePixelRatio();
konero 3a5304
      if (otherDevPixRatio != devPixRatio) {
konero 3a5304
        expandSize.setWidth(16 * otherDevPixRatio);
konero 3a5304
        expandSize.setHeight(16 * otherDevPixRatio);
konero 3a5304
      }
konero 3a5304
      QImage toolBaseImg(compositeImage(baseImg, expandSize));
konero 3a5304
      QImage toolOverImg(compositeImage(overImg, expandSize));
konero 3a5304
      QImage toolOnImg(compositeImage(onImg, expandSize));
konero 3a5304
      addImagesToIcon(icon, toolBaseImg, toolOverImg, toolOnImg,
konero 3a5304
                      useFullOpacity);
konero 3a5304
    }
shun-iwasawa 9b2afe
  }
konero 7bed16
konero 7bed16
  return icon;
shun-iwasawa 9b2afe
}
shun-iwasawa 9b2afe
shun-iwasawa 9b2afe
//-----------------------------------------------------------------------------
shun-iwasawa 9b2afe
Shinya Kitaoka 120a6e
QIcon createQIconPNG(const char *iconPNGName) {
Shinya Kitaoka 120a6e
  QString normal = QString(":Resources/") + iconPNGName + ".png";
Shinya Kitaoka 120a6e
  QString click  = QString(":Resources/") + iconPNGName + "_click.png";
Shinya Kitaoka 120a6e
  QString over   = QString(":Resources/") + iconPNGName + "_over.png";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QIcon icon;
Shinya Kitaoka 120a6e
  icon.addFile(normal, QSize(), QIcon::Normal, QIcon::Off);
Shinya Kitaoka 120a6e
  icon.addFile(click, QSize(), QIcon::Normal, QIcon::On);
Shinya Kitaoka 120a6e
  icon.addFile(over, QSize(), QIcon::Active);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return icon;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QIcon createQIconOnOffPNG(const char *iconPNGName, bool withOver) {
Shinya Kitaoka 120a6e
  QString on   = QString(":Resources/") + iconPNGName + "_on.png";
Shinya Kitaoka 120a6e
  QString off  = QString(":Resources/") + iconPNGName + "_off.png";
Shinya Kitaoka 120a6e
  QString over = QString(":Resources/") + iconPNGName + "_over.png";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QIcon icon;
Shinya Kitaoka 120a6e
  icon.addFile(off, QSize(), QIcon::Normal, QIcon::Off);
Shinya Kitaoka 120a6e
  icon.addFile(on, QSize(), QIcon::Normal, QIcon::On);
Shinya Kitaoka 120a6e
  if (withOver)
Shinya Kitaoka 120a6e
    icon.addFile(over, QSize(), QIcon::Active);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    icon.addFile(on, QSize(), QIcon::Active);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return icon;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 75b9b0
QIcon createTemporaryIconFromName(const char *commandName) {
konero 7bed16
  const int visibleIconSize = 20;
konero 7bed16
  const int menubarIconSize = 16;
shun-iwasawa 75b9b0
  QString name(commandName);
shun-iwasawa 75b9b0
  QList<qchar> iconChar;</qchar>
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
  for (int i = 0; i < name.length(); i++) {
shun-iwasawa 75b9b0
    QChar c = name.at(i);
shun-iwasawa 75b9b0
    if (c.isUpper() && iconChar.size() < 2)
shun-iwasawa 75b9b0
      iconChar.append(c);
shun-iwasawa 75b9b0
    else if (c.isDigit()) {
shun-iwasawa 75b9b0
      if (iconChar.isEmpty())
shun-iwasawa 75b9b0
        iconChar.append(c);
shun-iwasawa 75b9b0
      else if (iconChar.size() <= 2) {
shun-iwasawa 75b9b0
        if (iconChar.size() == 2) iconChar.removeLast();
shun-iwasawa 75b9b0
        iconChar.append(c);
shun-iwasawa 75b9b0
        break;
shun-iwasawa 75b9b0
      }
shun-iwasawa 75b9b0
    }
shun-iwasawa 75b9b0
  }
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
  if (iconChar.isEmpty()) iconChar.append(name.at(0));
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
  QString iconStr;
shun-iwasawa 75b9b0
  for (auto c : iconChar) iconStr.append(c);
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
  QIcon icon;
konero 7bed16
  // Prepare for both normal and high dpi
shun-iwasawa 75b9b0
  for (int devPixelRatio = 1; devPixelRatio <= 2; devPixelRatio++) {
konero 7bed16
    QImage transparentImg(menubarIconSize * devPixelRatio,
konero 7bed16
                          menubarIconSize * devPixelRatio,
konero 7bed16
                          QImage::Format_ARGB32);
konero 7bed16
    transparentImg.fill(Qt::transparent);
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
    int pxSize = visibleIconSize * devPixelRatio;
shun-iwasawa 75b9b0
konero 7bed16
    QImage charImg(pxSize, pxSize, QImage::Format_ARGB32_Premultiplied);
shun-iwasawa 75b9b0
    QPainter painter;
konero 7bed16
    charImg.fill(Qt::transparent);
konero 7bed16
    painter.begin(&charImg);
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
    painter.setPen(Preferences::instance()->getIconTheme() ? Qt::black
shun-iwasawa 75b9b0
                                                           : Qt::white);
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
    QRect rect(0, -2, pxSize, pxSize);
shun-iwasawa 75b9b0
    if (iconStr.size() == 2) {
shun-iwasawa 75b9b0
      painter.scale(0.6, 1.0);
shun-iwasawa 75b9b0
      rect.setRight(pxSize / 0.6);
shun-iwasawa 75b9b0
    }
shun-iwasawa 75b9b0
    QFont font = painter.font();
shun-iwasawa 75b9b0
    font.setPixelSize(pxSize);
shun-iwasawa 75b9b0
    painter.setFont(font);
shun-iwasawa 75b9b0
    painter.drawText(rect, Qt::AlignCenter, iconStr);
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
    painter.end();
shun-iwasawa 75b9b0
Kite c50ec4
    // For menu only
konero 7bed16
    addPixmapToAllModesAndStates(icon, QPixmap::fromImage(transparentImg));
Kite c50ec4
Kite c50ec4
    // For toolbars
konero 7bed16
    addImagesToIcon(icon, charImg);
shun-iwasawa 75b9b0
  }
konero 7bed16
shun-iwasawa 75b9b0
  return icon;
shun-iwasawa 75b9b0
}
shun-iwasawa 75b9b0
shun-iwasawa 75b9b0
//-----------------------------------------------------------------------------
shun-iwasawa 75b9b0
Shinya Kitaoka 120a6e
QString toQString(const TFilePath &path) {
Shinya Kitaoka 120a6e
  return QString::fromStdWString(path.getWideString());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isSpaceString(const QString &str) {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  QString space(" ");
Shinya Kitaoka 120a6e
  for (i = 0; i < str.size(); i++)
Shinya Kitaoka 120a6e
    if (str.at(i) != space.at(0)) return false;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isValidFileName(const QString &fileName) {
Shinya Kitaoka 120a6e
  if (fileName.isEmpty() || fileName.contains(":") || fileName.contains("\\") ||
Shinya Kitaoka 120a6e
      fileName.contains("/") || fileName.contains(">") ||
Shinya Kitaoka 120a6e
      fileName.contains("<") || fileName.contains("*") ||
Shinya Kitaoka 120a6e
      fileName.contains("|") || fileName.contains("\"") ||
Shinya Kitaoka 120a6e
      fileName.contains("?") || fileName.trimmed().isEmpty())
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isValidFileName_message(const QString &fileName) {
Shinya Kitaoka 120a6e
  return isValidFileName(fileName)
Shinya Kitaoka 120a6e
             ? true
Shinya Kitaoka 120a6e
             : (DVGui::error(
Shinya Kitaoka 120a6e
                    QObject::tr("The file name cannot be empty or contain any "
Shinya Kitaoka 120a6e
                                "of the following "
Shinya Kitaoka 120a6e
                                "characters: (new line) \\ / : * ? \" |")),
Shinya Kitaoka 120a6e
                false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
manongjohn 7f3150
bool isReservedFileName(const QString &fileName) {
manongjohn 7f3150
#ifdef _WIN32
manongjohn 7f3150
  std::vector<qstring> invalidNames{</qstring>
manongjohn 7f3150
      "AUX",  "CON",  "NUL",  "PRN",  "COM1", "COM2", "COM3", "COM4",
manongjohn 7f3150
      "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3",
manongjohn 7f3150
      "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
manongjohn 7f3150
manongjohn 7f3150
  if (std::find(invalidNames.begin(), invalidNames.end(), fileName) !=
manongjohn 7f3150
      invalidNames.end())
manongjohn 7f3150
    return true;
manongjohn 7f3150
#endif
manongjohn 7f3150
manongjohn 7f3150
  return false;
manongjohn 7f3150
}
manongjohn 7f3150
manongjohn 7f3150
//-----------------------------------------------------------------------------
manongjohn 7f3150
manongjohn 7f3150
bool isReservedFileName_message(const QString &fileName) {
manongjohn 7f3150
  return isReservedFileName(fileName)
manongjohn 7f3150
             ? (DVGui::error(QObject::tr(
manongjohn 7f3150
                    "That is a reserved file name and cannot be used.")),
manongjohn 7f3150
                true)
manongjohn 7f3150
             : false;
manongjohn 7f3150
}
manongjohn 7f3150
manongjohn 7f3150
//-----------------------------------------------------------------------------
manongjohn 7f3150
Shinya Kitaoka 120a6e
QString elideText(const QString &srcText, const QFont &font, int width) {
Shinya Kitaoka 120a6e
  QFontMetrics metrix(font);
shun-iwasawa 443318
  int srcWidth = metrix.horizontalAdvance(srcText);
Shinya Kitaoka 120a6e
  if (srcWidth < width) return srcText;
shun-iwasawa 443318
  int tilde = metrix.horizontalAdvance("~");
Shinya Kitaoka 120a6e
  int block = (width - tilde) / 2;
Shinya Kitaoka 120a6e
  QString text("");
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < srcText.size(); i++) {
Shinya Kitaoka 120a6e
    text += srcText.at(i);
shun-iwasawa 443318
    if (metrix.horizontalAdvance(text) > block) break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  text[i] = '~';
Shinya Kitaoka 120a6e
  QString endText("");
Shinya Kitaoka 120a6e
  for (i = srcText.size() - 1; i >= 0; i--) {
Shinya Kitaoka 120a6e
    endText.push_front(srcText.at(i));
shun-iwasawa 443318
    if (metrix.horizontalAdvance(endText) > block) break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  endText.remove(0, 1);
Shinya Kitaoka 120a6e
  text += endText;
Shinya Kitaoka 120a6e
  return text;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString elideText(const QString &srcText, const QFontMetrics &fm, int width,
Shinya Kitaoka 120a6e
                  const QString &elideSymbol) {
Shinya Kitaoka 120a6e
  QString text(srcText);
Toshihiro Shimizu 890ddd
shun-iwasawa 443318
  for (int i = text.size(); i > 1 && fm.horizontalAdvance(text) > width;)
Shinya Kitaoka 120a6e
    text = srcText.left(--i).append(elideSymbol);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return text;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QUrl pathToUrl(const TFilePath &path) {
Shinya Kitaoka 120a6e
  return QUrl::fromLocalFile(QString::fromStdWString(path.getWideString()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isResource(const QString &path) {
Shinya Kitaoka 120a6e
  const TFilePath fp(path.toStdWString());
Shinya Kitaoka 120a6e
  TFileType::Type type = TFileType::getInfo(fp);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return (TFileType::isViewable(type) || type & TFileType::MESH_IMAGE ||
Shinya Kitaoka 120a6e
          type == TFileType::AUDIO_LEVEL || type == TFileType::TABSCENE ||
Shinya Kitaoka 120a6e
          type == TFileType::TOONZSCENE || fp.getType() == "tpl");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isResource(const QUrl &url) { return isResource(url.toLocalFile()); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isResourceOrFolder(const QUrl &url) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static inline bool isDir(const QString &path) {
Shinya Kitaoka 120a6e
      return QFileInfo(path).isDir();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };  // locals
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const QString &path = url.toLocalFile();
Shinya Kitaoka 120a6e
  return (isResource(path) || locals::isDir(path));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool acceptResourceDrop(const QList<qurl> &urls) {</qurl>
Shinya Kitaoka 120a6e
  int count = 0;
otakuto dfe1cf
  for (const QUrl &url : urls) {
Shinya Kitaoka 120a6e
    if (isResource(url))
Shinya Kitaoka 120a6e
      ++count;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return (count > 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool acceptResourceOrFolderDrop(const QList<qurl> &urls) {</qurl>
Shinya Kitaoka 120a6e
  int count = 0;
otakuto dfe1cf
  for (const QUrl &url : urls) {
Shinya Kitaoka 120a6e
    if (isResourceOrFolder(url))
Shinya Kitaoka 120a6e
      ++count;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return (count > 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QPainterPath strokeToPainterPath(TStroke *stroke) {
Shinya Kitaoka 120a6e
  QPainterPath path;
Shinya Kitaoka 120a6e
  int i, chunkSize = stroke->getChunkCount();
Shinya Kitaoka 120a6e
  for (i = 0; i < chunkSize; i++) {
Shinya Kitaoka 120a6e
    const TThickQuadratic *q = stroke->getChunk(i);
Shinya Kitaoka 120a6e
    if (i == 0) path.moveTo(toQPointF(q->getThickP0()));
Shinya Kitaoka 120a6e
    path.quadTo(toQPointF(q->getThickP1()), toQPointF(q->getThickP2()));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return path;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// TabBarContainter
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TabBarContainter::TabBarContainter(QWidget *parent) : QFrame(parent) {
Shinya Kitaoka 120a6e
  setObjectName("TabBarContainer");
Shinya Kitaoka 120a6e
  setFrameStyle(QFrame::StyledPanel);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TabBarContainter::paintEvent(QPaintEvent *event) {
Shinya Kitaoka 120a6e
  QPainter p(this);
Jeremy Bullock 0f89c5
  p.setPen(getBottomAboveLineColor());
Shinya Kitaoka 120a6e
  p.drawLine(0, height() - 2, width(), height() - 2);
Jeremy Bullock 0f89c5
  p.setPen(getBottomBelowLineColor());
Shinya Kitaoka 120a6e
  p.drawLine(0, height() - 1, width(), height() - 1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// ToolBarContainer
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToolBarContainer::ToolBarContainer(QWidget *parent) : QFrame(parent) {
Shinya Kitaoka 120a6e
  setObjectName("ToolBarContainer");
Shinya Kitaoka 120a6e
  setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Kite 521c84
void ToolBarContainer::paintEvent(QPaintEvent *event) { QPainter p(this); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QString operator+(const QString &a, const TFilePath &fp) {
Shinya Kitaoka 120a6e
  return a + QString::fromStdWString(fp.getWideString());
Toshihiro Shimizu 890ddd
}
konero 7bed16
konero 7bed16
//=============================================================================
konero 7bed16
// Theme Manager
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
class ThemeManager::ThemeManagerImpl {
konero 7bed16
public:
konero 7bed16
  QMap<qstring, qstring=""> m_iconPaths;</qstring,>
konero 7bed16
  qreal m_onOpacity       = 1.0;
konero 7bed16
  qreal m_offOpacity      = 0.8;
konero 7bed16
  qreal m_disabledOpacity = 0.3;
konero 7bed16
};
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
ThemeManager::ThemeManager() : impl(new ThemeManagerImpl) {}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
ThemeManager::~ThemeManager() {}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
ThemeManager &ThemeManager::getInstance() {
konero 7bed16
  static ThemeManager instance;
konero 7bed16
  return instance;
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// Populate a QMap with icon filepaths and assign their basename as the key
konero 7bed16
void ThemeManager::buildIconPathsMap(const QString &path) {
konero 7bed16
  QDir dir(path);
konero 7bed16
  if (!dir.exists(path)) {
konero 7bed16
    qDebug() << "Resource path does not exist:" << path;
konero 7bed16
    return;
konero 7bed16
  }
konero 7bed16
konero 7bed16
  QDirIterator it(path,
konero 7bed16
                  QStringList() << "*.svg"
konero 7bed16
                                << "*.png",
konero 7bed16
                  QDir::Files, QDirIterator::Subdirectories);
konero 7bed16
konero 7bed16
  while (it.hasNext()) {
konero 7bed16
    it.next();
konero 7bed16
konero 7bed16
    const QString iconPath = it.fileInfo().filePath();
konero 7bed16
    const QString iconName = it.fileInfo().baseName();
konero 7bed16
konero 7bed16
    if (!impl->m_iconPaths.contains(iconName)) {
konero 7bed16
      impl->m_iconPaths.insert(iconName, iconPath);
konero 7bed16
    } else {
konero 7bed16
      qDebug() << "Icon with file name already exists in iconPaths, ensure "
konero 7bed16
                  "icons have unique file names:"
konero 7bed16
               << "\nCurrently added:" << getIconPath(iconName)
konero 7bed16
               << "\nTried to add:" << iconPath;
konero 7bed16
    }
konero 7bed16
  }
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// Get the full filepath of an icon image by basename
konero 7bed16
QString ThemeManager::getIconPath(const QString &iconName) const {
konero 7bed16
  return impl->m_iconPaths.value(iconName);
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// Boolean to check if iconName is contained within the iconPaths QMap
konero 7bed16
bool ThemeManager::hasIcon(const QString &iconName) const {
konero 7bed16
  return impl->m_iconPaths.contains(iconName);
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
qreal ThemeManager::getOnOpacity() const { return impl->m_onOpacity; }
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
qreal ThemeManager::getOffOpacity() const { return impl->m_offOpacity; }
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
qreal ThemeManager::getDisabledOpacity() const {
konero 7bed16
  return impl->m_disabledOpacity;
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// Colorize black pixels in a QImage while retaining other colors, however be
konero 7bed16
// mindful that if black pixels overlap color pixels it can cause artifacting
konero 7bed16
QImage ThemeManager::recolorBlackPixels(const QImage &input, QColor color) {
konero 7bed16
  if (input.isNull() || color == Qt::black) return QImage();
konero 7bed16
konero 7bed16
  // Default is icon theme color
konero 7bed16
  if (!color.isValid())
konero 7bed16
    color = Preferences::instance()->getIconTheme() ? Qt::black : Qt::white;
konero 7bed16
konero 7bed16
  QImage image     = input.convertToFormat(QImage::Format_ARGB32);
konero 7bed16
  QRgb targetColor = color.rgb();
konero 7bed16
  int height       = image.height();
konero 7bed16
  int width        = image.width();
konero 7bed16
  for (int y = 0; y < height; ++y) {
konero 7bed16
    QRgb *pixel = reinterpret_cast<qrgb *="">(image.scanLine(y));</qrgb>
konero 7bed16
    QRgb *end   = pixel + width;
konero 7bed16
    for (; pixel != end; ++pixel) {
konero 7bed16
      if (qGray(*pixel) == 0) {
konero 7bed16
        *pixel = (targetColor & 0x00FFFFFF) | (qAlpha(*pixel) << 24);
konero 7bed16
      }
konero 7bed16
    }
konero 7bed16
  }
konero 7bed16
konero 7bed16
  return image;
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// Colorize black pixels in a QPixmap while retaining other colors, however be
konero 7bed16
// mindful that if black pixels overlap color pixels if can cause artifacting
konero 7bed16
QPixmap ThemeManager::recolorBlackPixels(const QPixmap &input, QColor color) {
konero 7bed16
  if (input.isNull() || color == Qt::black) return QPixmap();
konero 7bed16
konero 7bed16
  QImage image          = input.toImage();
konero 7bed16
  QImage recoloredImage = recolorBlackPixels(image, color);
konero 7bed16
  QPixmap pixmap        = convertImageToPixmap(recoloredImage);
konero 7bed16
konero 7bed16
  return pixmap;
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// For debugging contents
konero 7bed16
void ThemeManager::printiconPathsMap() {
konero 7bed16
  const QMap<qstring, qstring=""> map = impl->m_iconPaths;</qstring,>
konero 7bed16
  qDebug() << "Contents of QMap:";
konero 7bed16
  for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
konero 7bed16
    qDebug() << it.key() << ":" << it.value();
konero 7bed16
  }
konero 7bed16
}
konero 7bed16
konero 7bed16
//-----------------------------------------------------------------------------
konero 7bed16
konero 7bed16
// Public version of ThemeManager::getIconPath()
konero 7bed16
QString getIconPath(const QString &path) {
konero 7bed16
  return ThemeManager::getInstance().getIconPath(path);
konero 7bed16
}