justburner 0be1bc
#include "ocaio.h"
justburner 0be1bc
justburner 0be1bc
#include "tsystem.h"
justburner 0be1bc
#include "tenv.h"
justburner 0be1bc
justburner 0be1bc
#include "toonz/tcamera.h"
justburner 0be1bc
justburner 0be1bc
#include "toonz/toonzscene.h"
justburner 0be1bc
#include "toonz/tproject.h"
justburner 0be1bc
#include "toonz/levelset.h"
justburner 0be1bc
#include "toonz/txsheet.h"
justburner 0be1bc
#include "toonz/txshcell.h"
justburner 0be1bc
#include "toonz/txshsimplelevel.h"
justburner 0be1bc
#include "toonz/txshchildlevel.h"
justburner 0be1bc
#include "toonz/txsheethandle.h"
justburner 0be1bc
#include "toonz/tscenehandle.h"
justburner 0be1bc
#include "toonz/preferences.h"
justburner 0be1bc
#include "toonz/sceneproperties.h"
justburner 0be1bc
#include "toonz/tstageobject.h"
justburner 0be1bc
#include "toutputproperties.h"
justburner 0be1bc
justburner 0be1bc
#include "toonzqt/gutil.h"
justburner 0be1bc
justburner 0be1bc
#include "tapp.h"
justburner 0be1bc
#include "menubarcommandids.h"
justburner 0be1bc
#include "filebrowserpopup.h"
justburner 0be1bc
justburner 0be1bc
#include "tiio.h"
justburner 0be1bc
#include "timage_io.h"
justburner 0be1bc
#include "tlevel_io.h"
justburner 0be1bc
#include "tvectorimage.h"
justburner 0be1bc
#include "exportlevelcommand.h"
justburner 0be1bc
justburner 0be1bc
#include <qjsonobject></qjsonobject>
justburner 0be1bc
#include <qjsonarray></qjsonarray>
justburner 0be1bc
#include <qjsondocument></qjsondocument>
justburner 0be1bc
#include <qdesktopservices></qdesktopservices>
justburner 0be1bc
#include <qcoreapplication></qcoreapplication>
justburner 0be1bc
justburner 0be1bc
#include <qwidget></qwidget>
justburner 0be1bc
#include <qlabel></qlabel>
justburner 0be1bc
#include <qspinbox></qspinbox>
justburner 0be1bc
#include <qcheckbox></qcheckbox>
justburner 0be1bc
#include <qvboxlayout></qvboxlayout>
justburner 0be1bc
justburner 0be1bc
using namespace OCAIo;
justburner 0be1bc
justburner 0be1bc
void OCAData::write(QJsonObject &json) const {
justburner 0be1bc
  // Header
justburner 0be1bc
  json["name"]       = m_name;
justburner 0be1bc
  json["frameRate"]  = m_framerate;
justburner 0be1bc
  json["width"]      = m_width;
justburner 0be1bc
  json["height"]     = m_height;
justburner 0be1bc
  json["startTime"]  = m_startTime + m_stOff;
justburner 0be1bc
  json["endTime"]    = m_endTime + m_stOff;
justburner 0be1bc
  json["colorDepth"] = m_raEXR ? "U16" : "U8";
justburner 0be1bc
justburner 0be1bc
  // Background color
justburner 0be1bc
  QJsonArray bgColorArray;
justburner 0be1bc
  bgColorArray.append(m_bgRed);
justburner 0be1bc
  bgColorArray.append(m_bgGreen);
justburner 0be1bc
  bgColorArray.append(m_bgBlue);
justburner 0be1bc
  bgColorArray.append(m_bgAlpha);
justburner 0be1bc
  json["backgroundColor"] = bgColorArray;
justburner 0be1bc
justburner 0be1bc
  // Layers
justburner 0be1bc
  json["layers"] = m_layers;
justburner 0be1bc
justburner 0be1bc
  // Versions
justburner 0be1bc
  json["originApp"] = "OpenToonz";
justburner 0be1bc
  json["originAppVersion"] =
justburner 0be1bc
      QString::fromStdString(TEnv::getApplicationVersion());
justburner 0be1bc
  json["ocaVersion"] = "1.1.0";
justburner 0be1bc
}
justburner 0be1bc
shun-iwasawa a807ce
int OCAData::frameLen(TXshCellColumn *column, const QList<int> &rows,</int>
shun-iwasawa a807ce
                      int index) {
justburner 0be1bc
  // Next cells must match same level and frame-id
shun-iwasawa a807ce
  int length          = 0;
justburner 0be1bc
  const TXshCell &stc = column->getCell(rows[index]);
justburner 0be1bc
  for (int i = index; i < rows.count(); i++) {
justburner 0be1bc
    int currentRow       = rows[i];
justburner 0be1bc
    const TXshCell &cell = column->getCell(currentRow);
justburner 0be1bc
    if (stc.m_frameId != cell.m_frameId || stc.m_level != cell.m_level) break;
justburner 0be1bc
    length++;
justburner 0be1bc
  }
justburner 0be1bc
  return length;
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
bool OCAData::isBlank(TXshCellColumn *column, int row) {
justburner 0be1bc
  TXshCell cell = column->getCell(row);
justburner 0be1bc
  return cell.isEmpty();
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
bool OCAData::getLayerName(TXshCellColumn *column, QString &out) {
justburner 0be1bc
  // Layer name will be the first cel that occur on the column
justburner 0be1bc
  TXshCell cell = column->getCell(column->getFirstRow());
justburner 0be1bc
  if (cell.isEmpty()) return false;
justburner 0be1bc
justburner 0be1bc
  out = QString::fromStdWString(cell.m_level->getName());
justburner 0be1bc
  return true;
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
bool OCAData::getCellName(TXshCellColumn *column, int row, QString &out) {
justburner 0be1bc
  TXshCell cell = column->getCell(row);
justburner 0be1bc
  if (cell.isEmpty()) return false;
justburner 0be1bc
justburner 0be1bc
  TFilePath fp(cell.m_level->getName());
shun-iwasawa a807ce
  fp  = fp.withFrame(cell.getFrameId(), TFrameId::FrameFormat::FOUR_ZEROS);
justburner 0be1bc
  out = fp.getQString();
justburner 0be1bc
  return true;
shun-iwasawa a807ce
}
justburner 0be1bc
shun-iwasawa a807ce
bool OCAData::saveCell(TXshCellColumn *column, int row, const QString &cellname,
shun-iwasawa a807ce
                       OCAAsset &out) {
shun-iwasawa a807ce
  TXshCell cell       = column->getCell(row);
justburner 0be1bc
  TXshSimpleLevel *sl = cell.getSimpleLevel();
justburner 0be1bc
justburner 0be1bc
  std::string format = m_raEXR ? "exr" : "png";
justburner 0be1bc
justburner 0be1bc
  // Rasterize cell
justburner 0be1bc
  TImageP image = IoCmd::exportedImage(format, *sl, cell.getFrameId());
justburner 0be1bc
  if (!image) return false;
justburner 0be1bc
justburner 0be1bc
  if (TRasterImageP ri = (TRasterImageP)(image)) {
justburner 0be1bc
    TRasterP raster;
shun-iwasawa a807ce
    raster     = ri->getRaster();
justburner 0be1bc
    out.width  = raster->getLx();
justburner 0be1bc
    out.height = raster->getLy();
justburner 0be1bc
    if (!raster) return false;
justburner 0be1bc
  } else {
justburner 0be1bc
    return false;
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  out.fileExt = QString::fromStdString(format);
justburner 0be1bc
justburner 0be1bc
  if (m_veSVG) {
justburner 0be1bc
    // Get vector image directly and discard rasterized image
justburner 0be1bc
    TVectorImageP vectorImg = cell.getImage(false);
justburner 0be1bc
    if (vectorImg) {
justburner 0be1bc
      image       = vectorImg;
justburner 0be1bc
      out.fileExt = "svg";
justburner 0be1bc
    }
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  QString filename = QString("/%1.%2").arg(cellname, out.fileExt);
justburner 0be1bc
  TFilePath fpr(m_path);
justburner 0be1bc
  TFilePath fpa(m_path + filename);
justburner 0be1bc
  out.fileName = QString::fromStdWString(fpr.getWideName()) + filename;
justburner 0be1bc
justburner 0be1bc
  TLevelWriterP lw(fpa);
justburner 0be1bc
  lw->setFrameRate(m_framerate);
justburner 0be1bc
  TImageWriterP iw = lw->getFrameWriter(cell.getFrameId());
shun-iwasawa a807ce
  iw->setFilePath(fpa);  // Added to aid my own sanity!
justburner 0be1bc
  iw->save(image);
justburner 0be1bc
justburner 0be1bc
  return true;
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
bool OCAData::isGroup(TXshCellColumn *column) {
justburner 0be1bc
  TXshCell firstcell = column->getCell(column->getFirstRow());
justburner 0be1bc
  TXshChildLevel *cl = firstcell.getChildLevel();
justburner 0be1bc
  return cl;
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
bool OCAData::buildGroup(QJsonObject &json, const QList<int> &rows,</int>
justburner 0be1bc
                         TXshCellColumn *column) {
justburner 0be1bc
  QString layername;
justburner 0be1bc
  if (!getLayerName(column, layername)) return false;
justburner 0be1bc
justburner 0be1bc
  // Get sub-xsheet
justburner 0be1bc
  int firstrow       = column->getFirstRow();
justburner 0be1bc
  TXshCell firstcell = column->getCell(firstrow);
justburner 0be1bc
  TXshChildLevel *cl = firstcell.getChildLevel();
shun-iwasawa a807ce
  TXsheet *xsheet    = cl->getXsheet();
justburner 0be1bc
  if (!xsheet) return false;
justburner 0be1bc
justburner 0be1bc
  // Build a list of child rows
justburner 0be1bc
  QList<int> crows;</int>
justburner 0be1bc
  for (int i = m_startTime; i <= m_endTime; i++) {
justburner 0be1bc
    TXshCell cell = column->getCell(i);
justburner 0be1bc
    if (cell.isEmpty())
justburner 0be1bc
      crows.append(-1);
justburner 0be1bc
    else
justburner 0be1bc
      crows.append(cell.getFrameId().getNumber() - 1);
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  // Build all columns from sub-xsheet
justburner 0be1bc
  int subID = ++m_subId;
justburner 0be1bc
  QJsonArray layers;
justburner 0be1bc
  for (int col = 0; col < xsheet->getFirstFreeColumnIndex(); col++) {
justburner 0be1bc
    if (xsheet->isColumnEmpty(col)) continue;
justburner 0be1bc
    TXshCellColumn *column = xsheet->getColumn(col)->getCellColumn();
justburner 0be1bc
    if (!column) continue;                      // skip non-cell column
justburner 0be1bc
    if (!column->isPreviewVisible()) continue;  // skip inactive column
justburner 0be1bc
justburner 0be1bc
    if (column->getColumnType() == column->eLevelType) {
justburner 0be1bc
      QJsonObject json;
justburner 0be1bc
      if (isGroup(column)) {
justburner 0be1bc
        if (buildGroup(json, crows, column)) layers.append(json);
justburner 0be1bc
      } else {
justburner 0be1bc
        if (buildLayer(json, crows, column)) layers.append(json);
justburner 0be1bc
      }
justburner 0be1bc
    }
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  QJsonArray jsonBlankPos;
justburner 0be1bc
  jsonBlankPos.append(m_width / 2);
justburner 0be1bc
  jsonBlankPos.append(m_height / 2);
justburner 0be1bc
  json["name"]         = layername;
justburner 0be1bc
  json["position"]     = jsonBlankPos;
justburner 0be1bc
  json["width"]        = m_width;
justburner 0be1bc
  json["height"]       = m_height;
justburner 0be1bc
  json["frames"]       = QJsonArray();
justburner 0be1bc
  json["childLayers"]  = layers;
justburner 0be1bc
  json["type"]         = "grouplayer";
justburner 0be1bc
  json["fileType"]     = "png";
justburner 0be1bc
  json["blendingMode"] = "normal";
justburner 0be1bc
  json["animated"]     = false;
justburner 0be1bc
  json["label"]        = 0;
justburner 0be1bc
  json["opacity"]      = column->getOpacity() / 255.0;
justburner 0be1bc
  json["visible"]      = column->isCamstandVisible();
justburner 0be1bc
  json["passThrough"]  = false;
justburner 0be1bc
  json["reference"]    = false;
justburner 0be1bc
  json["inheritAlpha"] = false;
justburner 0be1bc
justburner 0be1bc
  return true;
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
bool OCAData::buildLayer(QJsonObject &json, const QList<int> &rows,</int>
justburner 0be1bc
                         TXshCellColumn *column) {
justburner 0be1bc
  QJsonArray jsonFrames;
justburner 0be1bc
  bool firstcel = true;
justburner 0be1bc
justburner 0be1bc
  // Layer name will be the first cel that occur on the column
justburner 0be1bc
  int firstrow = column->getFirstRow();
justburner 0be1bc
  QString layername;
justburner 0be1bc
  QString cellname;
justburner 0be1bc
  if (!getLayerName(column, layername)) return false;
justburner 0be1bc
  if (!getCellName(column, firstrow, cellname)) return false;
justburner 0be1bc
justburner 0be1bc
  QJsonArray jsonBlankPos;
justburner 0be1bc
  jsonBlankPos.append(m_width / 2);
justburner 0be1bc
  jsonBlankPos.append(m_height / 2);
justburner 0be1bc
  json["name"]     = layername;
justburner 0be1bc
  json["position"] = jsonBlankPos;
justburner 0be1bc
  json["width"]    = 0;
justburner 0be1bc
  json["height"]   = 0;
justburner 0be1bc
justburner 0be1bc
  for (int i = 0; i < rows.count(); i++) {
justburner 0be1bc
    int row = rows[i];
justburner 0be1bc
justburner 0be1bc
    QJsonObject frame;
justburner 0be1bc
    QJsonArray jsonPosition;
justburner 0be1bc
    jsonPosition.append(m_width / 2);
justburner 0be1bc
    jsonPosition.append(m_height / 2);
justburner 0be1bc
    int len = frameLen(column, rows, i);
justburner 0be1bc
justburner 0be1bc
    frame["frameNumber"] = i + m_stOff;
justburner 0be1bc
    frame["position"]    = jsonPosition;
justburner 0be1bc
    frame["opacity"]     = 1.0;  // OT uses Transparency Fx node
justburner 0be1bc
    frame["duration"]    = len;
justburner 0be1bc
justburner 0be1bc
    if (isBlank(column, row)) {
shun-iwasawa a807ce
      frame["name"]     = "_blank";
shun-iwasawa a807ce
      frame["fileName"] = "";
shun-iwasawa a807ce
      frame["width"]    = 0;
shun-iwasawa a807ce
      frame["height"]   = 0;
justburner 0be1bc
    } else {
justburner 0be1bc
      // Cell name will be used for the frame name
justburner 0be1bc
      if (!getCellName(column, row, cellname)) continue;
justburner 0be1bc
justburner 0be1bc
      // Save cell image as an asset
justburner 0be1bc
      OCAAsset asset;
justburner 0be1bc
      if (!m_assets.contains(cellname)) {
justburner 0be1bc
        if (!saveCell(column, row, cellname, asset)) return false;
justburner 0be1bc
        m_assets.insert(cellname, asset);
justburner 0be1bc
      } else {
justburner 0be1bc
        asset = m_assets.value(cellname);
justburner 0be1bc
      }
justburner 0be1bc
justburner 0be1bc
      frame["name"]     = cellname;
justburner 0be1bc
      frame["fileName"] = asset.fileName;
justburner 0be1bc
      frame["width"]    = asset.width;
justburner 0be1bc
      frame["height"]   = asset.height;
justburner 0be1bc
justburner 0be1bc
      if (firstcel) {
justburner 0be1bc
        // Layer size and type will depend of the first cell too
justburner 0be1bc
        json["width"]    = asset.width;
justburner 0be1bc
        json["height"]   = asset.height;
justburner 0be1bc
        json["fileType"] = asset.fileExt;
justburner 0be1bc
        firstcel         = false;
justburner 0be1bc
      }
justburner 0be1bc
    }
justburner 0be1bc
    jsonFrames.append(frame);
justburner 0be1bc
justburner 0be1bc
    i += len - 1;
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  json["frames"]       = jsonFrames;
justburner 0be1bc
  json["childLayers"]  = QJsonArray();
justburner 0be1bc
  json["type"]         = "paintlayer";
justburner 0be1bc
  json["blendingMode"] = "normal";  // OT uses nodes Fx to make blending
justburner 0be1bc
                                    // possible, how to approach this?
justburner 0be1bc
  json["animated"]     = jsonFrames.count() >= 2;
justburner 0be1bc
  json["label"]        = 0;  // OT doesn't support labels
justburner 0be1bc
  json["opacity"]      = column->getOpacity() / 255.0;
justburner 0be1bc
  json["visible"]      = column->isCamstandVisible();
justburner 0be1bc
  json["passThrough"]  = false;
justburner 0be1bc
  json["reference"]    = false;
justburner 0be1bc
  json["inheritAlpha"] = false;
justburner 0be1bc
justburner 0be1bc
  return true;
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
void OCAData::setProgressDialog(DVGui::ProgressDialog *dialog) {
justburner 0be1bc
  m_progressDialog = dialog;
justburner 0be1bc
}
justburner 0be1bc
justburner 0be1bc
void OCAData::build(ToonzScene *scene, TXsheet *xsheet, QString name,
justburner 0be1bc
                    QString path, int startOffset, bool useEXR,
justburner 0be1bc
                    bool vectorAsSVG) {
justburner 0be1bc
  m_name  = name;
justburner 0be1bc
  m_path  = path;
justburner 0be1bc
  m_subId = 0;
justburner 0be1bc
  m_raEXR = useEXR;
justburner 0be1bc
  m_veSVG = vectorAsSVG;
justburner 0be1bc
  m_stOff = startOffset;
justburner 0be1bc
justburner 0be1bc
  // if the current xsheet is top xsheet in the scene and the output
justburner 0be1bc
  // frame range is specified, set the "to" frame value as duration
justburner 0be1bc
  TOutputProperties *oprop = scene->getProperties()->getOutputProperties();
justburner 0be1bc
  int from, to, step;
justburner 0be1bc
  if (scene->getTopXsheet() == xsheet && oprop->getRange(from, to, step)) {
justburner 0be1bc
    m_startTime = from - 1;
justburner 0be1bc
    m_endTime   = to - 1;
shun-iwasawa a807ce
    // m_stepTime  = step;
justburner 0be1bc
  } else {
justburner 0be1bc
    m_startTime = 0;
justburner 0be1bc
    m_endTime   = xsheet->getFrameCount() - 1;
shun-iwasawa a807ce
    // m_stepTime  = 1;
justburner 0be1bc
  }
justburner 0be1bc
  if (m_endTime < 0) m_endTime = 0;
justburner 0be1bc
justburner 0be1bc
  // Build a list of rows
justburner 0be1bc
  QList<int> rows;</int>
justburner 0be1bc
  for (int i = m_startTime; i <= m_endTime; i++) {
justburner 0be1bc
    rows.append(i);
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  m_framerate = oprop->getFrameRate();
justburner 0be1bc
  m_width     = scene->getCurrentCamera()->getRes().lx;
justburner 0be1bc
  m_height    = scene->getCurrentCamera()->getRes().ly;
justburner 0be1bc
justburner 0be1bc
  TPixel bgc = scene->getProperties()->getBgColor();
justburner 0be1bc
  m_bgRed    = bgc.r / double(TPixel::maxChannelValue);
justburner 0be1bc
  m_bgGreen  = bgc.g / double(TPixel::maxChannelValue);
justburner 0be1bc
  m_bgBlue   = bgc.b / double(TPixel::maxChannelValue);
justburner 0be1bc
  m_bgAlpha  = bgc.m / double(TPixel::maxChannelValue);
justburner 0be1bc
justburner 0be1bc
  // Build all columns from current xsheet
justburner 0be1bc
  m_layers.empty();
justburner 0be1bc
  for (int col = 0; col < xsheet->getColumnCount(); col++) {
justburner 0be1bc
    if (xsheet->isColumnEmpty(col)) continue;
justburner 0be1bc
    TXshCellColumn *column = xsheet->getColumn(col)->getCellColumn();
shun-iwasawa a807ce
    if (!column) continue;                      // skip non-cell column
justburner 0be1bc
    if (!column->isPreviewVisible()) continue;  // skip inactive column
justburner 0be1bc
justburner 0be1bc
    if (column->getColumnType() == column->eLevelType) {
justburner 0be1bc
      if (m_progressDialog) {
justburner 0be1bc
        QString layername;
justburner 0be1bc
        getLayerName(column, layername);
justburner 0be1bc
        m_progressDialog->setLabelText(QObject::tr("Layer: ") + layername);
justburner 0be1bc
        m_progressDialog->setMaximum(xsheet->getColumnCount());
justburner 0be1bc
        m_progressDialog->setValue(col);
justburner 0be1bc
        QCoreApplication::processEvents();
justburner 0be1bc
      }
justburner 0be1bc
justburner 0be1bc
      QJsonObject json;
justburner 0be1bc
      if (isGroup(column)) {
justburner 0be1bc
        if (buildGroup(json, rows, column)) m_layers.append(json);
justburner 0be1bc
      } else {
justburner 0be1bc
        if (buildLayer(json, rows, column)) m_layers.append(json);
justburner 0be1bc
      }
justburner 0be1bc
    }
justburner 0be1bc
  }
justburner 0be1bc
}
justburner 0be1bc
shun-iwasawa a807ce
ExportOCACommand::ExportOCACommand() : MenuItemHandler(MI_ExportOCA) {}
justburner 0be1bc
justburner 0be1bc
void ExportOCACommand::execute() {
justburner 0be1bc
  ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
justburner 0be1bc
  TXsheet *xsheet   = TApp::instance()->getCurrentXsheet()->getXsheet();
justburner 0be1bc
  TFilePath fp      = scene->getScenePath().withType("oca");
justburner 0be1bc
justburner 0be1bc
  static GenericSaveFilePopup *savePopup = 0;
justburner 0be1bc
  static QCheckBox *exrImageFormat       = nullptr;
justburner 0be1bc
  static QCheckBox *rasVectors           = nullptr;
justburner 0be1bc
  static QCheckBox *doKeyframing         = nullptr;
justburner 0be1bc
  static QHBoxLayout *startingOffsetLay  = nullptr;
justburner 0be1bc
  static QLabel *startingOffsetLab       = nullptr;
justburner 0be1bc
  static QSpinBox *startingOffsetSpin    = nullptr;
justburner 0be1bc
justburner 0be1bc
  static DVGui::ProgressDialog *progressDialog = nullptr;
justburner 0be1bc
justburner 0be1bc
  if (!savePopup) {
justburner 0be1bc
    QWidget *customWidget = new QWidget();
justburner 0be1bc
justburner 0be1bc
    exrImageFormat = new QCheckBox(tr("Save Images in EXR Format"));
justburner 0be1bc
    rasVectors     = new QCheckBox(tr("Rasterize Vectors"));
justburner 0be1bc
justburner 0be1bc
    startingOffsetLay  = new QHBoxLayout();
justburner 0be1bc
    startingOffsetLab  = new QLabel(tr("Frame Offset: "));
justburner 0be1bc
    startingOffsetSpin = new QSpinBox();
justburner 0be1bc
justburner 0be1bc
    exrImageFormat->setToolTip(
justburner 0be1bc
        tr("Checked: Images are saved as EXR\nUnchecked: Images are "
justburner 0be1bc
           "saved as PNG"));
justburner 0be1bc
    rasVectors->setToolTip(
justburner 0be1bc
        tr("Checked: Rasterize into EXR/PNG\nUnchecked: Vectors are "
justburner 0be1bc
           "saved as SVG"));
justburner 0be1bc
    startingOffsetLab->setToolTip(tr("Starting Frame Offset"));
justburner 0be1bc
    startingOffsetSpin->setToolTip(tr("Starting Frame Offset"));
justburner 0be1bc
    rasVectors->setChecked(true);
justburner 0be1bc
justburner 0be1bc
    startingOffsetSpin->setValue(1);
justburner 0be1bc
    startingOffsetSpin->setMinimum(0);
justburner 0be1bc
    startingOffsetSpin->setMaximum(1000000);
justburner 0be1bc
    startingOffsetLab->adjustSize();
justburner 0be1bc
    startingOffsetLay->setMargin(0);
justburner 0be1bc
    startingOffsetLay->setSpacing(0);
justburner 0be1bc
    startingOffsetLay->addWidget(startingOffsetLab, 0, Qt::AlignRight);
justburner 0be1bc
    startingOffsetLay->addWidget(startingOffsetSpin);
justburner 0be1bc
justburner 0be1bc
    QGridLayout *customLay = new QGridLayout();
justburner 0be1bc
    customLay->setMargin(5);
justburner 0be1bc
    customLay->setSpacing(5);
justburner 0be1bc
    customLay->addWidget(exrImageFormat, 0, 0);
justburner 0be1bc
    customLay->addWidget(rasVectors, 1, 0);
justburner 0be1bc
    customLay->addLayout(startingOffsetLay, 0, 1);
justburner 0be1bc
    customWidget->setLayout(customLay);
justburner 0be1bc
justburner 0be1bc
    progressDialog = new DVGui::ProgressDialog("", tr("Hide"), 0, 0);
justburner 0be1bc
    progressDialog->setWindowTitle(tr("Exporting..."));
justburner 0be1bc
    progressDialog->setWindowFlags(
justburner 0be1bc
        Qt::Dialog | Qt::WindowTitleHint);  // Don't show ? and X buttons
justburner 0be1bc
    progressDialog->setWindowModality(Qt::WindowModal);
justburner 0be1bc
justburner 0be1bc
    savePopup = new GenericSaveFilePopup(
justburner 0be1bc
        QObject::tr("Export Open Cel Animation (OCA)"), customWidget);
justburner 0be1bc
    savePopup->addFilterType("oca");
justburner 0be1bc
  }
justburner 0be1bc
  if (!scene->isUntitled())
justburner 0be1bc
    savePopup->setFolder(fp.getParentDir());
justburner 0be1bc
  else
justburner 0be1bc
    savePopup->setFolder(
justburner 0be1bc
        TProjectManager::instance()->getCurrentProject()->getScenesPath());
justburner 0be1bc
justburner 0be1bc
  savePopup->setFilename(fp.withoutParentDir());
justburner 0be1bc
  fp = savePopup->getPath();
justburner 0be1bc
  if (fp.isEmpty()) return;
justburner 0be1bc
justburner 0be1bc
  int frameOffset  = startingOffsetSpin->value();
justburner 0be1bc
  bool exrImageFmt = exrImageFormat->isChecked();
justburner 0be1bc
  bool rasterVecs  = rasVectors->isChecked();
justburner 0be1bc
justburner 0be1bc
  // Export
justburner 0be1bc
justburner 0be1bc
  progressDialog->setLabelText(tr("Starting..."));
justburner 0be1bc
  progressDialog->setValue(0);
justburner 0be1bc
  progressDialog->show();
justburner 0be1bc
  QCoreApplication::processEvents();
justburner 0be1bc
justburner 0be1bc
  QString ocafile = fp.getQString();
justburner 0be1bc
  QString ocafolder(ocafile);
justburner 0be1bc
  ocafolder.replace(".", "_");
justburner 0be1bc
justburner 0be1bc
  QFile saveFile(ocafile);
justburner 0be1bc
  QDir saveDir(ocafolder);
justburner 0be1bc
justburner 0be1bc
  if (!saveFile.open(QIODevice::WriteOnly)) {
justburner 97869c
    progressDialog->close();
justburner 97869c
    DVGui::error(QObject::tr("Unable to open OCA file for saving."));
justburner 0be1bc
    return;
justburner 0be1bc
  }
justburner 0be1bc
  if (!saveDir.exists()) {
justburner 97869c
    if (!saveDir.mkpath(".")) {
justburner 97869c
      progressDialog->close();
justburner 97869c
      DVGui::error(QObject::tr("Unable to create folder for saving layers."));
justburner 0be1bc
      return;
justburner 0be1bc
    }
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  OCAData ocaData;
justburner 0be1bc
  ocaData.setProgressDialog(progressDialog);
justburner 0be1bc
  ocaData.build(scene, xsheet, QString::fromStdString(fp.getName()), ocafolder,
justburner 0be1bc
                frameOffset, exrImageFmt, !rasterVecs);
justburner 0be1bc
  if (ocaData.isEmpty()) {
justburner 97869c
    progressDialog->close();
justburner 0be1bc
    DVGui::error(QObject::tr("No columns can be exported."));
justburner 0be1bc
    return;
justburner 0be1bc
  }
justburner 0be1bc
justburner 0be1bc
  QJsonObject ocaObject;
justburner 0be1bc
  ocaData.write(ocaObject);
justburner 0be1bc
  QJsonDocument saveDoc(ocaObject);
justburner 0be1bc
  QByteArray jsonByteArrayData = saveDoc.toJson();
justburner 0be1bc
  saveFile.write(jsonByteArrayData);
justburner 0be1bc
justburner 0be1bc
  progressDialog->close();
justburner 0be1bc
justburner 0be1bc
  // Done
justburner 0be1bc
justburner 0be1bc
  QString str = QObject::tr("%1 has been exported successfully.")
justburner 0be1bc
                    .arg(QString::fromStdString(fp.getLevelName()));
justburner 0be1bc
justburner 0be1bc
  std::vector<qstring> buttons = {QObject::tr("OK"),</qstring>
justburner 0be1bc
                                  QObject::tr("Open containing folder")};
justburner 0be1bc
  int ret = DVGui::MsgBox(DVGui::INFORMATION, str, buttons);
justburner 0be1bc
justburner 0be1bc
  if (ret == 2) {
justburner 0be1bc
    TFilePath folderPath = fp.getParentDir();
justburner 0be1bc
    if (TSystem::isUNC(folderPath))
justburner 0be1bc
      QDesktopServices::openUrl(QUrl(folderPath.getQString()));
justburner 0be1bc
    else
justburner 0be1bc
      QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath.getQString()));
justburner 0be1bc
  }
justburner 0be1bc
}
shun-iwasawa a807ce
shun-iwasawa a807ce
ExportOCACommand exportOCACommand;