shun-iwasawa cd4694
#include "toonz/boardsettings.h"
shun-iwasawa cd4694
shun-iwasawa cd4694
// TnzLib includes
shun-iwasawa cd4694
#include "toonz/toonzscene.h"
shun-iwasawa cd4694
#include "toonz/tproject.h"
shun-iwasawa cd4694
#include "toonz/sceneproperties.h"
shun-iwasawa cd4694
#include "toonz/toonzfolders.h"
shun-iwasawa cd4694
#include "toutputproperties.h"
shun-iwasawa cd4694
#include "tsystem.h"
shun-iwasawa cd4694
shun-iwasawa cd4694
#include <qimage></qimage>
shun-iwasawa cd4694
#include <qdate></qdate>
shun-iwasawa cd4694
#include <qdatetime></qdatetime>
shun-iwasawa cd4694
#include <qfontmetricsf></qfontmetricsf>
shun-iwasawa cd4694
#include <qmap></qmap>
shun-iwasawa cd4694
shun-iwasawa cd4694
namespace {
shun-iwasawa cd4694
QMap<boarditem::type, std::wstring=""> strs = {</boarditem::type,>
shun-iwasawa cd4694
    {BoardItem::FreeText, L"FreeText"},
shun-iwasawa cd4694
    {BoardItem::ProjectName, L"ProjectName"},
shun-iwasawa cd4694
    {BoardItem::SceneName, L"SceneName"},
shun-iwasawa cd4694
    {BoardItem::Duration_Frame, L"Duration_Frame"},
shun-iwasawa cd4694
    {BoardItem::Duration_SecFrame, L"Duration_SecFrame"},
shun-iwasawa cd4694
    {BoardItem::Duration_HHMMSSFF, L"Duration_HHMMSSFF"},
shun-iwasawa cd4694
    {BoardItem::CurrentDate, L"CurrentDate"},
shun-iwasawa cd4694
    {BoardItem::CurrentDateTime, L"CurrentDateTime"},
shun-iwasawa cd4694
    {BoardItem::UserName, L"UserName"},
shun-iwasawa cd4694
    {BoardItem::ScenePath_Aliased, L"ScenePath_Aliased"},
shun-iwasawa cd4694
    {BoardItem::ScenePath_Full, L"ScenePath_Full"},
shun-iwasawa cd4694
    {BoardItem::MoviePath_Aliased, L"MoviePath_Aliased"},
shun-iwasawa cd4694
    {BoardItem::MoviePath_Full, L"MoviePath_Full"},
shun-iwasawa cd4694
    {BoardItem::Image, L"Image"}};
shun-iwasawa cd4694
shun-iwasawa cd4694
std::wstring type2String(BoardItem::Type type) { return strs.value(type, L""); }
shun-iwasawa cd4694
BoardItem::Type string2Type(std::wstring str) {
shun-iwasawa cd4694
  return strs.key(str, BoardItem::TypeCount);
shun-iwasawa cd4694
}
shun-iwasawa cd4694
};
shun-iwasawa cd4694
shun-iwasawa cd4694
BoardItem::BoardItem() {
shun-iwasawa cd4694
  m_name            = "Item";
shun-iwasawa cd4694
  m_type            = ProjectName;
shun-iwasawa cd4694
  m_rect            = QRectF(0.1, 0.1, 0.8, 0.8);
shun-iwasawa cd4694
  m_maximumFontSize = 300;
shun-iwasawa cd4694
  m_color           = Qt::black;
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
QString BoardItem::getContentText(ToonzScene *scene) {
shun-iwasawa cd4694
  switch (m_type) {
shun-iwasawa cd4694
  case FreeText:
shun-iwasawa cd4694
    return m_text;
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case ProjectName:
shun-iwasawa cd4694
    return scene->getProject()->getName().getQString();
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case SceneName:
shun-iwasawa cd4694
    return QString::fromStdWString(scene->getSceneName());
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case Duration_Frame:
shun-iwasawa cd4694
    return QString::number(scene->getFrameCount());
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case Duration_SecFrame: {
shun-iwasawa cd4694
    TOutputProperties *oprop = scene->getProperties()->getOutputProperties();
shun-iwasawa cd4694
    int fps                  = (int)oprop->getFrameRate();
shun-iwasawa cd4694
    int frame                = scene->getFrameCount();
shun-iwasawa cd4694
    return QString("%1 + %2").arg(QString::number(frame / fps),
shun-iwasawa cd4694
                                  QString::number(frame % fps));
shun-iwasawa cd4694
  } break;
shun-iwasawa cd4694
  case Duration_HHMMSSFF: {
shun-iwasawa cd4694
    TOutputProperties *oprop = scene->getProperties()->getOutputProperties();
shun-iwasawa cd4694
    int fps                  = (int)oprop->getFrameRate();
shun-iwasawa cd4694
    int frame                = scene->getFrameCount();
shun-iwasawa cd4694
    int hh                   = frame / (fps * 60 * 60);
shun-iwasawa cd4694
    frame -= hh * fps * 60 * 60;
shun-iwasawa cd4694
    int mm = frame / (fps * 60);
shun-iwasawa cd4694
    frame -= mm * fps * 60;
shun-iwasawa cd4694
    int ss = frame / fps;
shun-iwasawa cd4694
    int ff = frame % fps;
shun-iwasawa cd4694
    return QString::number(hh).rightJustified(2, '0') + ":" +
shun-iwasawa cd4694
           QString::number(mm).rightJustified(2, '0') + ":" +
shun-iwasawa cd4694
           QString::number(ss).rightJustified(2, '0') + ":" +
shun-iwasawa cd4694
           QString::number(ff).rightJustified(2, '0');
shun-iwasawa cd4694
  } break;
shun-iwasawa cd4694
  case CurrentDate:
shun-iwasawa cd4694
    return QDate::currentDate().toString(Qt::DefaultLocaleLongDate);
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case CurrentDateTime:
shun-iwasawa cd4694
    return QDateTime::currentDateTime().toString(Qt::DefaultLocaleLongDate);
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case UserName:
shun-iwasawa cd4694
    return TSystem::getUserName();
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case ScenePath_Aliased:
shun-iwasawa cd4694
    return scene->codeFilePath(scene->getScenePath()).getQString();
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case ScenePath_Full:
shun-iwasawa cd4694
    return scene->decodeFilePath(scene->getScenePath()).getQString();
shun-iwasawa cd4694
    break;
shun-iwasawa cd4694
  case MoviePath_Aliased: {
shun-iwasawa cd4694
    TOutputProperties *oprop = scene->getProperties()->getOutputProperties();
shun-iwasawa cd4694
    return scene->codeFilePath(oprop->getPath()).getQString();
shun-iwasawa cd4694
  } break;
shun-iwasawa cd4694
  case MoviePath_Full: {
shun-iwasawa cd4694
    TOutputProperties *oprop = scene->getProperties()->getOutputProperties();
shun-iwasawa cd4694
    return scene->decodeFilePath(oprop->getPath()).getQString();
shun-iwasawa cd4694
  } break;
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
  return QString();
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
QRectF BoardItem::getItemRect(QSize imgSize) {
shun-iwasawa cd4694
  QSizeF imgSizeF(imgSize);
shun-iwasawa cd4694
  return QRectF(
shun-iwasawa cd4694
      imgSizeF.width() * m_rect.left(), imgSizeF.height() * m_rect.top(),
shun-iwasawa cd4694
      imgSizeF.width() * m_rect.width(), imgSizeF.height() * m_rect.height());
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardItem::drawItem(QPainter &p, QSize imgSize, int shrink,
shun-iwasawa cd4694
                         ToonzScene *scene) {
shun-iwasawa cd4694
  QRectF itemRect = getItemRect(imgSize);
shun-iwasawa cd4694
shun-iwasawa cd4694
  if (m_type == Image) {
shun-iwasawa cd4694
    if (m_imgPath.isEmpty()) return;
shun-iwasawa cd4694
    TFilePath decodedPath = scene->decodeFilePath(m_imgPath);
shun-iwasawa cd4694
    QImage img(decodedPath.getQString());
shun-iwasawa cd4694
    if (m_imgARMode == Qt::KeepAspectRatio) {
shun-iwasawa cd4694
      float ratio = std::min((float)itemRect.width() / (float)img.width(),
shun-iwasawa cd4694
                             (float)itemRect.height() / (float)img.height());
shun-iwasawa cd4694
      QSizeF imgSize((float)img.width() * ratio, (float)img.height() * ratio);
shun-iwasawa cd4694
      QPointF imgTopLeft =
shun-iwasawa cd4694
          itemRect.topLeft() +
shun-iwasawa cd4694
          QPointF((itemRect.width() - imgSize.width()) * 0.5f,
shun-iwasawa cd4694
                  (itemRect.height() - imgSize.height()) * 0.5f);
shun-iwasawa cd4694
shun-iwasawa cd4694
      p.drawImage(QRectF(imgTopLeft, imgSize), img);
shun-iwasawa cd4694
    } else if (m_imgARMode == Qt::IgnoreAspectRatio)
shun-iwasawa cd4694
      p.drawImage(itemRect, img);
shun-iwasawa cd4694
    return;
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
shun-iwasawa cd4694
  QString contentText = getContentText(scene);
shun-iwasawa cd4694
shun-iwasawa cd4694
  QFont tmpFont(m_font);
shun-iwasawa cd4694
  tmpFont.setPixelSize(100);
shun-iwasawa cd4694
  QFontMetricsF tmpFm(tmpFont);
shun-iwasawa cd4694
  QRectF tmpBounding =
shun-iwasawa cd4694
      tmpFm.boundingRect(itemRect, Qt::AlignLeft | Qt::AlignTop, contentText);
shun-iwasawa cd4694
shun-iwasawa cd4694
  float ratio = std::min(itemRect.width() / tmpBounding.width(),
shun-iwasawa cd4694
                         itemRect.height() / tmpBounding.height());
shun-iwasawa cd4694
shun-iwasawa cd4694
  // compute the font size which will just fit the item region
shun-iwasawa cd4694
  int fontSize = (int)(100.0f * ratio);
shun-iwasawa cd4694
  tmpFont.setPixelSize(fontSize);
shun-iwasawa cd4694
  tmpFm = QFontMetricsF(tmpFont);
shun-iwasawa cd4694
  tmpBounding =
shun-iwasawa cd4694
      tmpFm.boundingRect(itemRect, Qt::AlignLeft | Qt::AlignTop, contentText);
shun-iwasawa cd4694
  bool isInRect;
shun-iwasawa cd4694
  if (itemRect.width() >= tmpBounding.width() &&
shun-iwasawa cd4694
      itemRect.height() >= tmpBounding.height())
shun-iwasawa cd4694
    isInRect = true;
shun-iwasawa cd4694
  else
shun-iwasawa cd4694
    isInRect = false;
shun-iwasawa cd4694
  while (1) {
shun-iwasawa cd4694
    fontSize += (isInRect) ? 1 : -1;
shun-iwasawa cd4694
    if (fontSize <= 0)  // cannot draw
shun-iwasawa cd4694
      return;
shun-iwasawa cd4694
    tmpFont.setPixelSize(fontSize);
shun-iwasawa cd4694
    tmpFm = QFontMetricsF(tmpFont);
shun-iwasawa cd4694
    tmpBounding =
shun-iwasawa cd4694
        tmpFm.boundingRect(itemRect, Qt::AlignLeft | Qt::AlignTop, contentText);
shun-iwasawa cd4694
shun-iwasawa cd4694
    bool newIsInRect = (itemRect.width() >= tmpBounding.width() &&
shun-iwasawa cd4694
                        itemRect.height() >= tmpBounding.height());
shun-iwasawa cd4694
    if (isInRect != newIsInRect) {
shun-iwasawa cd4694
      if (isInRect) fontSize--;
shun-iwasawa cd4694
      break;
shun-iwasawa cd4694
    }
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
shun-iwasawa cd4694
  //----
shun-iwasawa cd4694
  fontSize = std::min(fontSize, m_maximumFontSize / shrink);
shun-iwasawa cd4694
shun-iwasawa cd4694
  QFont font(m_font);
shun-iwasawa cd4694
  font.setPixelSize(fontSize);
shun-iwasawa cd4694
shun-iwasawa cd4694
  p.setFont(font);
shun-iwasawa cd4694
  p.setPen(m_color);
shun-iwasawa cd4694
shun-iwasawa cd4694
  if (m_type == FreeText)
shun-iwasawa cd4694
    p.drawText(itemRect, Qt::AlignLeft | Qt::AlignTop, contentText);
shun-iwasawa cd4694
  else
shun-iwasawa cd4694
    p.drawText(itemRect, Qt::AlignCenter, contentText);
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardItem::saveData(TOStream &os) {
shun-iwasawa cd4694
  os.child("type") << type2String(m_type);
shun-iwasawa cd4694
  os.child("name") << m_name;
shun-iwasawa cd4694
  os.child("rect") << m_rect.x() << m_rect.y() << m_rect.width()
shun-iwasawa cd4694
                   << m_rect.height();
shun-iwasawa cd4694
shun-iwasawa cd4694
  if (m_type == Image) {
luzpaz 27707d
    // if the path is in library folder, then save the relative path
shun-iwasawa cd4694
    TFilePath libFp = ToonzFolder::getLibraryFolder();
shun-iwasawa cd4694
    if (libFp.isAncestorOf(m_imgPath))
shun-iwasawa cd4694
      os.child("imgPath") << 1 << m_imgPath - libFp;
shun-iwasawa cd4694
    else
shun-iwasawa cd4694
      os.child("imgPath") << 0 << m_imgPath;
shun-iwasawa cd4694
    os.child("imgARMode") << (int)m_imgARMode;
shun-iwasawa cd4694
  } else {
shun-iwasawa cd4694
    if (m_type == FreeText) os.child("text") << m_text;
shun-iwasawa cd4694
shun-iwasawa cd4694
    os.child("maximumFontSize") << m_maximumFontSize;
shun-iwasawa cd4694
    os.child("color") << m_color.red() << m_color.green() << m_color.blue()
shun-iwasawa cd4694
                      << m_color.alpha();
shun-iwasawa cd4694
    os.child("font") << m_font.family() << (int)(m_font.bold() ? 1 : 0)
shun-iwasawa cd4694
                     << (int)(m_font.italic() ? 1 : 0);
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardItem::loadData(TIStream &is) {
shun-iwasawa cd4694
  std::string tagName;
shun-iwasawa cd4694
  while (is.matchTag(tagName)) {
shun-iwasawa cd4694
    if (tagName == "type") {
shun-iwasawa cd4694
      std::wstring typeStr;
shun-iwasawa cd4694
      is >> typeStr;
shun-iwasawa cd4694
      m_type = string2Type(typeStr);
shun-iwasawa cd4694
    } else if (tagName == "name") {
shun-iwasawa cd4694
      std::wstring str;
shun-iwasawa cd4694
      is >> str;
shun-iwasawa cd4694
      m_name = QString::fromStdWString(str);
shun-iwasawa cd4694
    } else if (tagName == "rect") {
shun-iwasawa cd4694
      double x, y, width, height;
shun-iwasawa cd4694
      is >> x >> y >> width >> height;
shun-iwasawa cd4694
      m_rect = QRectF(x, y, width, height);
shun-iwasawa cd4694
    } else if (tagName == "imgPath") {
shun-iwasawa cd4694
      int isInLibrary;
shun-iwasawa cd4694
      TFilePath fp;
shun-iwasawa cd4694
      is >> isInLibrary >> fp;
shun-iwasawa cd4694
      if (isInLibrary == 1)
shun-iwasawa cd4694
        m_imgPath = ToonzFolder::getLibraryFolder() + fp;
shun-iwasawa cd4694
      else
shun-iwasawa cd4694
        m_imgPath = fp;
shun-iwasawa cd4694
    } else if (tagName == "imgARMode") {
shun-iwasawa cd4694
      int mode;
shun-iwasawa cd4694
      is >> mode;
shun-iwasawa cd4694
      m_imgARMode = (Qt::AspectRatioMode)mode;
shun-iwasawa cd4694
    } else if (tagName == "text") {
shun-iwasawa cd4694
      std::wstring str;
shun-iwasawa cd4694
      is >> str;
shun-iwasawa cd4694
      m_text = QString::fromStdWString(str);
shun-iwasawa cd4694
    } else if (tagName == "maximumFontSize") {
shun-iwasawa cd4694
      is >> m_maximumFontSize;
shun-iwasawa cd4694
    } else if (tagName == "color") {
shun-iwasawa cd4694
      int r, g, b, a;
shun-iwasawa cd4694
      is >> r >> g >> b >> a;
shun-iwasawa cd4694
      m_color = QColor(r, g, b, a);
shun-iwasawa cd4694
    } else if (tagName == "font") {
shun-iwasawa cd4694
      QString family;
shun-iwasawa cd4694
      int isBold, isItalic;
shun-iwasawa cd4694
      is >> family >> isBold >> isItalic;
shun-iwasawa cd4694
      m_font.setFamily(family);
shun-iwasawa cd4694
      m_font.setBold(isBold == 1);
shun-iwasawa cd4694
      m_font.setItalic(isItalic == 1);
shun-iwasawa cd4694
    } else
shun-iwasawa cd4694
      throw TException("unexpected tag: " + tagName);
shun-iwasawa cd4694
    is.closeChild();
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
//======================================================================================
shun-iwasawa cd4694
shun-iwasawa cd4694
BoardSettings::BoardSettings() {
shun-iwasawa cd4694
  // add one item as an example
shun-iwasawa cd4694
  m_items.push_back(BoardItem());
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
QImage BoardSettings::getBoardImage(TDimension &dim, int shrink,
shun-iwasawa cd4694
                                    ToonzScene *scene) {
shun-iwasawa cd4694
  QImage img(dim.lx, dim.ly, QImage::Format_ARGB32);
shun-iwasawa cd4694
shun-iwasawa cd4694
  QPainter painter(&img);
shun-iwasawa cd4694
shun-iwasawa cd4694
  painter.fillRect(img.rect(), Qt::white);
shun-iwasawa cd4694
shun-iwasawa cd4694
  // draw each item
shun-iwasawa cd4694
  for (int i = m_items.size() - 1; i >= 0; i--)
shun-iwasawa cd4694
    m_items[i].drawItem(painter, img.rect().size(), shrink, scene);
shun-iwasawa cd4694
shun-iwasawa cd4694
  painter.end();
shun-iwasawa cd4694
shun-iwasawa cd4694
  return img;
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
TRaster32P BoardSettings::getBoardRaster(TDimension &dim, int shrink,
shun-iwasawa cd4694
                                         ToonzScene *scene) {
shun-iwasawa cd4694
  QImage img = getBoardImage(dim, shrink, scene);
shun-iwasawa cd4694
shun-iwasawa cd4694
  // convert QImage to TRaster
shun-iwasawa cd4694
  TRaster32P boardRas(dim);
shun-iwasawa cd4694
  int img_y = img.height() - 1;
shun-iwasawa cd4694
  for (int j = 0; j < dim.ly; j++, img_y--) {
shun-iwasawa cd4694
    TPixel32 *pix = boardRas->pixels(j);
shun-iwasawa cd4694
    QRgb *img_p   = (QRgb *)img.scanLine(img_y);
shun-iwasawa cd4694
    for (int i = 0; i < dim.lx; i++, pix++, img_p++) {
shun-iwasawa cd4694
      (*pix).r = (typename TPixel32::Channel)(qRed(*img_p));
shun-iwasawa cd4694
      (*pix).g = (typename TPixel32::Channel)(qGreen(*img_p));
shun-iwasawa cd4694
      (*pix).b = (typename TPixel32::Channel)(qBlue(*img_p));
shun-iwasawa cd4694
      (*pix).m = (typename TPixel32::Channel)(qAlpha(*img_p));
shun-iwasawa cd4694
    }
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
  return boardRas;
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardSettings::addNewItem(int insertAt) {
shun-iwasawa cd4694
  m_items.insert(insertAt, BoardItem());
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardSettings::removeItem(int index) {
shun-iwasawa cd4694
  if (index < 0 || index >= m_items.size()) return;
shun-iwasawa cd4694
  m_items.removeAt(index);
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardSettings::swapItems(int i, int j) { m_items.swap(i, j); }
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardSettings::saveData(TOStream &os, bool forPreset) {
shun-iwasawa cd4694
  if (!forPreset) os.child("active") << (int)((m_active) ? 1 : 0);
shun-iwasawa cd4694
  os.child("duration") << m_duration;
shun-iwasawa cd4694
  if (!m_items.isEmpty()) {
shun-iwasawa cd4694
    os.openChild("boardItems");
shun-iwasawa cd4694
    for (int i = 0; i < getItemCount(); i++) {
shun-iwasawa cd4694
      os.openChild("item");
shun-iwasawa cd4694
      m_items[i].saveData(os);
shun-iwasawa cd4694
      os.closeChild();
shun-iwasawa cd4694
    }
shun-iwasawa cd4694
    os.closeChild();
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
}
shun-iwasawa cd4694
shun-iwasawa cd4694
void BoardSettings::loadData(TIStream &is) {
shun-iwasawa cd4694
  std::string tagName;
shun-iwasawa cd4694
  while (is.matchTag(tagName)) {
shun-iwasawa cd4694
    if (tagName == "active") {
shun-iwasawa cd4694
      int val;
shun-iwasawa cd4694
      is >> val;
shun-iwasawa cd4694
      setActive(val == 1);
shun-iwasawa cd4694
    } else if (tagName == "duration") {
shun-iwasawa cd4694
      is >> m_duration;
shun-iwasawa cd4694
    } else if (tagName == "boardItems") {
shun-iwasawa cd4694
      m_items.clear();
shun-iwasawa cd4694
      while (is.matchTag(tagName)) {
shun-iwasawa cd4694
        if (tagName == "item") {
shun-iwasawa cd4694
          BoardItem item;
shun-iwasawa cd4694
          item.loadData(is);
shun-iwasawa cd4694
          m_items.append(item);
shun-iwasawa cd4694
        } else
shun-iwasawa cd4694
          throw TException("unexpected tag: " + tagName);
shun-iwasawa cd4694
        is.closeChild();
shun-iwasawa cd4694
      }
shun-iwasawa cd4694
    } else
shun-iwasawa cd4694
      throw TException("unexpected tag: " + tagName);
shun-iwasawa cd4694
    is.closeChild();
shun-iwasawa cd4694
  }
shun-iwasawa cd4694
}