2779 lines
No EOL
97 KiB
C++
2779 lines
No EOL
97 KiB
C++
|
|
#include "exportxsheetpdf.h"
|
|
|
|
// Tnz6 includes
|
|
#include "menubarcommandids.h"
|
|
#include "tapp.h"
|
|
#include "toutputproperties.h"
|
|
#include "orientation.h"
|
|
|
|
// TnzQt includes
|
|
#include "toonzqt/menubarcommand.h"
|
|
#include "toonzqt/gutil.h"
|
|
#include "toonzqt/filefield.h"
|
|
#include "toonzqt/colorfield.h"
|
|
|
|
// TnzLib includes
|
|
#include "toonz/tscenehandle.h"
|
|
#include "toonz/txsheethandle.h"
|
|
#include "toonz/toonzscene.h"
|
|
#include "toonz/sceneproperties.h"
|
|
#include "toonz/txshlevelcolumn.h"
|
|
#include "toonz/txshsoundcolumn.h"
|
|
#include "toonz/tstageobject.h"
|
|
#include "toonz/preferences.h"
|
|
#include "toonz/toonzfolders.h"
|
|
#include "toonz/txshsoundtextcolumn.h"
|
|
#include "toonz/txshsoundtextlevel.h"
|
|
|
|
// TnzCore includes
|
|
#include "tsystem.h"
|
|
#include "tlevel_io.h"
|
|
#include "tenv.h"
|
|
|
|
#include <iostream>
|
|
#include <QMainWindow>
|
|
#include <QPdfWriter>
|
|
#include <QPainter>
|
|
#include <QFile>
|
|
#include <QApplication>
|
|
#include <QFontMetrics>
|
|
#include <QComboBox>
|
|
#include <QCheckBox>
|
|
#include <QScrollArea>
|
|
#include <QPushButton>
|
|
#include <QHBoxLayout>
|
|
#include <QGridLayout>
|
|
#include <QLabel>
|
|
#include <QPixmap>
|
|
#include <QMouseEvent>
|
|
#include <QScrollBar>
|
|
#include <QPainterPath>
|
|
#include <QFontComboBox>
|
|
#include <QTextEdit>
|
|
#include <QRadioButton>
|
|
#include <QImageReader>
|
|
#include <QLineEdit>
|
|
#include <QIntValidator>
|
|
#include <QDesktopServices>
|
|
#include <QGroupBox>
|
|
#include <QSettings>
|
|
|
|
// Template
|
|
TEnv::StringVar XShPdfExportTemplate("XShPdfExportTemplate", "B4_6sec");
|
|
// output area
|
|
TEnv::IntVar XShPdfExportOutputArea("XShPdfExportOutputArea", Area_Cells);
|
|
// line color
|
|
TEnv::StringVar XShPdfExportLineColor(
|
|
"XShPdfExportLineColor", QColor(128, 196, 128).name().toStdString());
|
|
// print datetime
|
|
TEnv::IntVar XShPdfExportPrintDateTime("XShPdfExportPrintDateTime", 0);
|
|
// print scene path
|
|
TEnv::IntVar XShPdfExportPrintScenePath("XShPdfExportPrintScenePath", 0);
|
|
// print soundtrack
|
|
TEnv::IntVar XShPdfExportPrintSoundtrack("XShPdfExportPrintSoundtrack", 0);
|
|
// serial frame number
|
|
TEnv::IntVar XShPdfExportSerialFrameNumber("XShPdfExportSerialFrameNumber", 0);
|
|
// print level name on the bottom
|
|
TEnv::IntVar XShPdfExportLevelNameOnBottom("XShPdfExportLevelNameOnBottom", 0);
|
|
// print dialogue
|
|
TEnv::IntVar XShPdfExportPrintDialogue("XShPdfExportPrintDialogue", 0);
|
|
// print scene name
|
|
TEnv::IntVar XShPdfExportPrintSceneName("XShPdfExportPrintSceneName", 0);
|
|
// template font
|
|
TEnv::StringVar XShPdfExportTemplateFont("XShPdfExportTemplateFont", "");
|
|
// output font
|
|
TEnv::StringVar XShPdfExportOutputFont("XShPdfExportOutputFont", "");
|
|
// logo preferene (0 = text, 1 = image)
|
|
TEnv::IntVar XShPdfExportLogoPreference("XShPdfExportLogoPreference", 0);
|
|
// logo text
|
|
TEnv::StringVar XShPdfExportLogoText("XShPdfExportLogoText", "");
|
|
// logo image path
|
|
TEnv::StringVar XShPdfExportImgPath("XShPdfExportImgPath", "");
|
|
// continuous line threshold
|
|
TEnv::IntVar XShPdfExportContinuousLineThres("XShPdfExportContinuousLineThres",
|
|
0);
|
|
|
|
TEnv::IntVar XShPdfExportTick1Id("XShPdfExportTick1Id", -1);
|
|
TEnv::IntVar XShPdfExportTick2Id("XShPdfExportTick2Id", -1);
|
|
TEnv::IntVar XShPdfExportKeyId("XShPdfExportKeyId", -1);
|
|
TEnv::IntVar XShPdfExportTick1Type("XShPdfExportTick1Type", TickMark_Dot);
|
|
TEnv::IntVar XShPdfExportTick2Type("XShPdfExportTick2Type", TickMark_Dot);
|
|
|
|
using namespace XSheetPDFTemplateParamIDs;
|
|
|
|
namespace {
|
|
const int PDF_Resolution = 400;
|
|
int mm2px(double mm) {
|
|
return (int)std::round(mm * (double)PDF_Resolution / 25.4);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*! convert the last one digit of the frame number to alphabet
|
|
Ex. 12 -> 1B 21 -> 2A 30 -> 3
|
|
*/
|
|
QString getFrameNumberWithLetters(int frame) {
|
|
int letterNum = frame % 10;
|
|
QChar letter;
|
|
|
|
switch (letterNum) {
|
|
case 0:
|
|
letter = QChar();
|
|
break;
|
|
case 1:
|
|
letter = 'A';
|
|
break;
|
|
case 2:
|
|
letter = 'B';
|
|
break;
|
|
case 3:
|
|
letter = 'C';
|
|
break;
|
|
case 4:
|
|
letter = 'D';
|
|
break;
|
|
case 5:
|
|
letter = 'E';
|
|
break;
|
|
case 6:
|
|
letter = 'F';
|
|
break;
|
|
case 7:
|
|
letter = 'G';
|
|
break;
|
|
case 8:
|
|
letter = 'H';
|
|
break;
|
|
case 9:
|
|
letter = 'I';
|
|
break;
|
|
default:
|
|
letter = QChar();
|
|
break;
|
|
}
|
|
|
|
QString number;
|
|
if (frame >= 10) {
|
|
number = QString::number(frame);
|
|
number.chop(1);
|
|
} else
|
|
number = "0";
|
|
|
|
return (QChar(letter).isNull()) ? number : number.append(letter);
|
|
}
|
|
|
|
void decoSceneInfo(QPainter& painter, QRect rect,
|
|
QMap<XSheetPDFDataType, QRect>& dataRects, bool) {
|
|
dataRects[Data_SceneName] = painter.transform().mapRect(rect);
|
|
}
|
|
|
|
void decoTimeInfo(QPainter& painter, QRect rect,
|
|
QMap<XSheetPDFDataType, QRect>& dataRects, bool doTranslate) {
|
|
QString plusStr, secStr, frmStr;
|
|
if (doTranslate) {
|
|
plusStr = QObject::tr("+", "XSheetPDF");
|
|
secStr = QObject::tr("'", "XSheetPDF:second");
|
|
frmStr = QObject::tr("\"", "XSheetPDF:frame");
|
|
} else {
|
|
plusStr = "+";
|
|
secStr = "'";
|
|
frmStr = "\"";
|
|
}
|
|
|
|
painter.save();
|
|
{
|
|
QFont font = painter.font();
|
|
font.setPixelSize(rect.height() / 2 - mm2px(1));
|
|
font.setLetterSpacing(QFont::PercentageSpacing, 100);
|
|
while (font.pixelSize() > mm2px(2)) {
|
|
if (QFontMetrics(font).boundingRect(plusStr).width() < rect.width() / 12)
|
|
break;
|
|
font.setPixelSize(font.pixelSize() - mm2px(0.2));
|
|
}
|
|
painter.setFont(font);
|
|
|
|
QRect labelRect(0, 0, rect.width() / 2, rect.height() / 2);
|
|
QRect dataRect(0, 0, rect.width() / 2, rect.height());
|
|
painter.drawText(labelRect, Qt::AlignRight | Qt::AlignVCenter, secStr);
|
|
dataRects[Data_Second] = painter.transform().mapRect(dataRect);
|
|
painter.translate(labelRect.width(), 0);
|
|
painter.drawText(labelRect.adjusted(0, 0, 0, -mm2px(0.5)),
|
|
Qt::AlignRight | Qt::AlignVCenter, frmStr);
|
|
dataRects[Data_Frame] = painter.transform().mapRect(dataRect);
|
|
painter.translate(0, labelRect.height());
|
|
painter.drawText(labelRect, Qt::AlignLeft | Qt::AlignVCenter, plusStr);
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
// Display the total pages over the current page.
|
|
// This format is odd in terms of fraction, but can be seen in many Japanese
|
|
// studios.
|
|
|
|
void doDecoSheetInfo(QPainter& painter, QRect rect,
|
|
QMap<XSheetPDFDataType, QRect>& dataRects,
|
|
bool doTranslate, bool inv) {
|
|
QString totStr, thStr;
|
|
if (doTranslate) {
|
|
totStr = QObject::tr("TOT", "XSheetPDF");
|
|
thStr = QObject::tr("th", "XSheetPDF");
|
|
} else {
|
|
totStr = "TOT";
|
|
thStr = "th";
|
|
}
|
|
QString upperStr = (inv) ? totStr : thStr;
|
|
QString bottomStr = (inv) ? thStr : totStr;
|
|
XSheetPDFDataType upperType = (inv) ? Data_TotalPages : Data_CurrentPage;
|
|
XSheetPDFDataType bottomType = (inv) ? Data_CurrentPage : Data_TotalPages;
|
|
|
|
painter.save();
|
|
{
|
|
QFont font = painter.font();
|
|
font.setPixelSize(rect.height() / 2 - mm2px(1));
|
|
font.setLetterSpacing(QFont::PercentageSpacing, 100);
|
|
while (font.pixelSize() > mm2px(2)) {
|
|
if (QFontMetrics(font).boundingRect(totStr).width() < rect.width() / 6)
|
|
break;
|
|
font.setPixelSize(font.pixelSize() - mm2px(0.2));
|
|
}
|
|
painter.setFont(font);
|
|
|
|
painter.drawLine(rect.topRight(), rect.bottomLeft());
|
|
QRect labelRect(0, 0, rect.width() / 2, rect.height() / 2);
|
|
painter.drawText(labelRect, Qt::AlignRight | Qt::AlignVCenter, upperStr);
|
|
dataRects[upperType] = painter.transform().mapRect(
|
|
labelRect.adjusted(0, 0, -labelRect.width() / 4, mm2px(1)));
|
|
painter.translate(labelRect.width(), labelRect.height());
|
|
painter.drawText(labelRect.adjusted(0, 0, -mm2px(0.5), 0),
|
|
Qt::AlignRight | Qt::AlignVCenter, bottomStr);
|
|
dataRects[bottomType] = painter.transform().mapRect(
|
|
labelRect.adjusted(0, -mm2px(1), -labelRect.width() / 4, 0));
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void decoSheetInfoInv(QPainter& painter, QRect rect,
|
|
QMap<XSheetPDFDataType, QRect>& dataRects,
|
|
bool doTranslate) {
|
|
doDecoSheetInfo(painter, rect, dataRects, doTranslate, true);
|
|
}
|
|
|
|
void decoSheetInfo(QPainter& painter, QRect rect,
|
|
QMap<XSheetPDFDataType, QRect>& dataRects,
|
|
bool doTranslate) {
|
|
doDecoSheetInfo(painter, rect, dataRects, doTranslate, false);
|
|
}
|
|
|
|
QPageSize::PageSizeId str2PageSizeId(const QString& str) {
|
|
const QMap<QString, QPageSize::PageSizeId> map = {
|
|
{"JisB4", QPageSize::JisB4},
|
|
{"B4", QPageSize::JisB4}, // return Jis B4 instead of ISO B4
|
|
{"A3", QPageSize::A3},
|
|
{"A4", QPageSize::A4}};
|
|
|
|
return map.value(str, QPageSize::JisB4);
|
|
}
|
|
|
|
DecoFunc infoType2DecoFunc(const QString& str) {
|
|
const QMap<QString, DecoFunc> map = {{"Scene", decoSceneInfo},
|
|
{"Time", decoTimeInfo},
|
|
{"Sheet", decoSheetInfo},
|
|
{"SheetInv", decoSheetInfoInv}};
|
|
|
|
return map.value(str, nullptr);
|
|
}
|
|
|
|
XSheetPDFDataType dataStr2Type(const QString& str) {
|
|
const QMap<QString, XSheetPDFDataType> map = {
|
|
{"Memo", Data_Memo},
|
|
{"Second", Data_Second},
|
|
{"Frame", Data_Frame},
|
|
{"TotalPages", Data_TotalPages},
|
|
{"CurrentPage", Data_CurrentPage},
|
|
{"DateTimeAndScenePath", Data_DateTimeAndScenePath},
|
|
{"SceneName", Data_SceneName},
|
|
{"Logo", Data_Logo}};
|
|
|
|
return map.value(str, Data_Invalid);
|
|
}
|
|
|
|
QIcon getColorChipIcon(TPixel32 color) {
|
|
QPixmap pm(15, 15);
|
|
pm.fill(QColor(color.r, color.g, color.b));
|
|
return QIcon(pm);
|
|
}
|
|
|
|
void refreshCellMarkComboItems(QComboBox* combo) {
|
|
int current = -1;
|
|
if (combo->count()) current = combo->currentData().toInt();
|
|
|
|
combo->clear();
|
|
QList<TSceneProperties::CellMark> marks = TApp::instance()
|
|
->getCurrentScene()
|
|
->getScene()
|
|
->getProperties()
|
|
->getCellMarks();
|
|
combo->addItem(QObject::tr("None", "XSheetPDF CellMark"), -1);
|
|
int curId = 0;
|
|
for (auto mark : marks) {
|
|
QString label = QString("%1: %2").arg(curId).arg(mark.name);
|
|
combo->addItem(getColorChipIcon(mark.color), label, curId);
|
|
curId++;
|
|
}
|
|
|
|
if (current >= 0) combo->setCurrentIndex(combo->findData(current));
|
|
}
|
|
|
|
QPixmap tickMarkPm(TickMarkType type, int size, bool withBG = false) {
|
|
QPixmap pm(size, size);
|
|
QPointF center(double(size) * 0.5, double(size) * 0.5);
|
|
|
|
pm.fill((withBG) ? Qt::white : Qt::transparent);
|
|
QPainter p(&pm);
|
|
QPen pen(Qt::black);
|
|
pen.setWidthF(double(size) / 15.0);
|
|
p.setPen(pen);
|
|
switch (type) {
|
|
case TickMark_Dot: {
|
|
p.setBrush(Qt::black);
|
|
double dotR = double(size) * 0.1;
|
|
p.drawEllipse(center, dotR, dotR);
|
|
break;
|
|
}
|
|
case TickMark_Circle: {
|
|
double circleR = double(size) * 0.4;
|
|
p.drawEllipse(center, circleR, circleR);
|
|
break;
|
|
}
|
|
case TickMark_Filled: {
|
|
p.setBrush(Qt::black);
|
|
double circleR = double(size) * 0.4;
|
|
p.drawEllipse(center, circleR, circleR);
|
|
break;
|
|
}
|
|
case TickMark_Asterisk: {
|
|
QFont font = p.font();
|
|
font.setPixelSize(size);
|
|
p.setFont(font);
|
|
p.drawText(0, 0, size, size, Qt::AlignCenter, "*");
|
|
break;
|
|
}
|
|
}
|
|
return pm;
|
|
}
|
|
|
|
QComboBox* createTickMarkCombo(QWidget* parent) {
|
|
QComboBox* combo = new QComboBox(parent);
|
|
combo->addItem(QIcon(tickMarkPm(TickMark_Dot, 15, true)),
|
|
QObject::tr("Dot", "XSheetPDF CellMark"), TickMark_Dot);
|
|
combo->addItem(QIcon(tickMarkPm(TickMark_Circle, 15, true)),
|
|
QObject::tr("Circle", "XSheetPDF CellMark"), TickMark_Circle);
|
|
combo->addItem(QIcon(tickMarkPm(TickMark_Filled, 15, true)),
|
|
QObject::tr("Filled circle", "XSheetPDF CellMark"),
|
|
TickMark_Filled);
|
|
combo->addItem(QIcon(tickMarkPm(TickMark_Asterisk, 15, true)),
|
|
QObject::tr("Asterisk", "XSheetPDF CellMark"),
|
|
TickMark_Asterisk);
|
|
return combo;
|
|
}
|
|
|
|
void doDrawText(QPainter& p, const QString& str, const QRect rect) {
|
|
QFontMetrics fm(p.font());
|
|
int spaceWidth = fm.boundingRect('A').width();
|
|
// check if spaces can be iserted between letters
|
|
int textWidth = fm.boundingRect(str).width() + spaceWidth * (str.count() - 1);
|
|
if (rect.width() - spaceWidth * 2 <= textWidth) {
|
|
p.drawText(rect, Qt::AlignCenter, str);
|
|
return;
|
|
}
|
|
// check if spaces can be doubled
|
|
int textWidth_s2 =
|
|
fm.boundingRect(str).width() + spaceWidth * 2 * (str.count() - 1);
|
|
if (rect.width() - spaceWidth * 4 > textWidth_s2) textWidth = textWidth_s2;
|
|
QRect textRect(rect.center().x() - textWidth / 2, rect.y(), textWidth,
|
|
rect.height());
|
|
p.drawText(textRect,
|
|
Qt::TextJustificationForced | Qt::AlignJustify | Qt::AlignVCenter,
|
|
str);
|
|
}
|
|
|
|
void setFontFittingRectWidth(QPainter& p, const QString& str, const QRect rect,
|
|
double vmargin = 0.5, double hmargin = 1.0) {
|
|
QFont font = p.font();
|
|
int pixelSize = rect.height() - mm2px(vmargin);
|
|
while (1) {
|
|
font.setPixelSize(pixelSize);
|
|
if (pixelSize <= mm2px(2) || QFontMetrics(font).boundingRect(str).width() <=
|
|
rect.width() - mm2px(hmargin))
|
|
break;
|
|
pixelSize -= mm2px(0.1);
|
|
}
|
|
p.setFont(font);
|
|
}
|
|
|
|
} // namespace
|
|
//---------------------------------------------------------
|
|
|
|
void XSheetPDFTemplate::drawGrid(QPainter& painter, int colAmount, int colWidth,
|
|
int blockWidth) {
|
|
// horiontal lines
|
|
painter.save();
|
|
{
|
|
// loop 3 seconds
|
|
for (int sec = 0; sec < 3; sec++) {
|
|
painter.save();
|
|
{
|
|
for (int f = 1; f <= 24; f++) {
|
|
if (f % 6 == 0)
|
|
painter.setPen(thickPen);
|
|
else
|
|
painter.setPen(thinPen);
|
|
painter.translate(0, param(RowHeight));
|
|
painter.drawLine(0, 0, blockWidth, 0);
|
|
}
|
|
}
|
|
painter.restore();
|
|
|
|
painter.translate(0, param(OneSecHeight));
|
|
painter.setPen(thickPen);
|
|
painter.drawLine(0, 0, blockWidth, 0);
|
|
}
|
|
}
|
|
painter.restore();
|
|
// vertical lines
|
|
painter.save();
|
|
{
|
|
painter.setPen(thinPen);
|
|
for (int kc = 0; kc < colAmount; kc++) {
|
|
painter.translate(colWidth, 0);
|
|
painter.drawLine(0, 0, 0, param(OneSecHeight) * 3);
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawHeaderGrid(QPainter& painter, int colAmount,
|
|
int colWidth, int blockWidth) {
|
|
// Cells Block header
|
|
painter.save();
|
|
{
|
|
// horizontal lines
|
|
painter.setPen(thinPen);
|
|
painter.drawLine(0, param(HeaderHeight) / 2, blockWidth,
|
|
param(HeaderHeight) / 2);
|
|
painter.setPen(thickPen);
|
|
painter.drawLine(0, param(HeaderHeight), blockWidth, param(HeaderHeight));
|
|
// vertical lines
|
|
painter.setPen(thinPen);
|
|
painter.save();
|
|
{
|
|
for (int col = 1; col < colAmount; col++) {
|
|
painter.translate(colWidth, 0);
|
|
painter.drawLine(0, param(HeaderHeight) / 2, 0, param(HeaderHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::registerColLabelRects(QPainter& painter, int colAmount,
|
|
int colWidth, int bodyId) {
|
|
painter.save();
|
|
{
|
|
for (int kc = 0; kc < colAmount; kc++) {
|
|
QRect labelRect(0, 0, colWidth, param(HeaderHeight) / 2);
|
|
labelRect = painter.transform().mapRect(labelRect);
|
|
|
|
if (bodyId == 0) {
|
|
QList<QRect> labelRects = {labelRect};
|
|
m_colLabelRects.append(labelRects);
|
|
} else
|
|
m_colLabelRects[kc].append(labelRect);
|
|
|
|
painter.translate(colWidth, 0);
|
|
}
|
|
}
|
|
painter.restore();
|
|
|
|
if (!m_info.drawLevelNameOnBottom) return;
|
|
|
|
// register bottom rects
|
|
painter.save();
|
|
{
|
|
painter.translate(0, param(BodyHeight) - param(HeaderHeight) / 2);
|
|
|
|
for (int kc = 0; kc < colAmount; kc++) {
|
|
QRect labelRect(0, 0, colWidth, param(HeaderHeight) / 2);
|
|
labelRect = painter.transform().mapRect(labelRect);
|
|
|
|
if (bodyId == 0) {
|
|
QList<QRect> labelRects = {labelRect};
|
|
m_colLabelRects_bottom.append(labelRects);
|
|
} else
|
|
m_colLabelRects_bottom[kc].append(labelRect);
|
|
|
|
painter.translate(colWidth, 0);
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::registerCellRects(QPainter& painter, int colAmount,
|
|
int colWidth, int bodyId) {
|
|
int heightAdj = (param(OneSecHeight) - param(RowHeight) * 24) / 2;
|
|
painter.save();
|
|
{
|
|
for (int kc = 0; kc < colAmount; kc++) {
|
|
QList<QRect> colCellRects;
|
|
|
|
painter.save();
|
|
{
|
|
for (int sec = 0; sec < 3; sec++) {
|
|
painter.save();
|
|
{
|
|
for (int f = 1; f <= 24; f++) {
|
|
QRect cellRect(0, 0, colWidth, param(RowHeight));
|
|
// fill gap between the doubled lines between seconds
|
|
if (sec != 0 && f == 1)
|
|
cellRect.adjust(0, -heightAdj, 0, 0);
|
|
else if (sec != 2 && f == 24)
|
|
cellRect.adjust(0, 0, 0, heightAdj);
|
|
|
|
colCellRects.append(painter.transform().mapRect(cellRect));
|
|
painter.translate(0, param(RowHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
painter.translate(0, param(OneSecHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
|
|
if (bodyId == 0)
|
|
m_cellRects.append(colCellRects);
|
|
else
|
|
m_cellRects[kc].append(colCellRects);
|
|
|
|
painter.translate(colWidth, 0);
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::registerSoundRects(QPainter& painter, int colWidth,
|
|
int bodyId) {
|
|
int heightAdj = (param(OneSecHeight) - param(RowHeight) * 24) / 2;
|
|
painter.save();
|
|
{
|
|
painter.save();
|
|
{
|
|
for (int sec = 0; sec < 3; sec++) {
|
|
painter.save();
|
|
{
|
|
for (int f = 1; f <= 24; f++) {
|
|
QRect cellRect(0, 0, colWidth, param(RowHeight));
|
|
// fill gap between the doubled lines between seconds
|
|
if (sec != 0 && f == 1)
|
|
cellRect.adjust(0, -heightAdj, 0, 0);
|
|
else if (sec != 2 && f == 24)
|
|
cellRect.adjust(0, 0, 0, heightAdj);
|
|
|
|
m_soundCellRects.append(painter.transform().mapRect(cellRect));
|
|
painter.translate(0, param(RowHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
painter.translate(0, param(OneSecHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
painter.translate(colWidth, 0);
|
|
}
|
|
painter.restore();
|
|
}
|
|
// Key Block
|
|
void XSheetPDFTemplate::drawKeyBlock(QPainter& painter, int framePage,
|
|
const int bodyId) {
|
|
QFont font = painter.font();
|
|
font.setPixelSize(m_p.bodylabelTextSize_Small);
|
|
painter.setFont(font);
|
|
|
|
painter.save();
|
|
{
|
|
drawHeaderGrid(painter, param(KeyColAmount), param(KeyColWidth),
|
|
m_p.keyBlockWidth);
|
|
|
|
if (m_info.exportArea == Area_Actions) {
|
|
painter.save();
|
|
{
|
|
painter.translate(0, param(HeaderHeight) / 2);
|
|
// register actions rects.
|
|
registerColLabelRects(painter, columnsInPage(), param(KeyColWidth),
|
|
bodyId);
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
QRect labelRect(0, 0, m_p.keyBlockWidth, param(HeaderHeight) / 2);
|
|
QString actionLabel = (param(TranslateBodyLabel, 1) == 1)
|
|
? QObject::tr("ACTION", "XSheetPDF")
|
|
: "ACTION";
|
|
doDrawText(painter, actionLabel, labelRect);
|
|
|
|
painter.save();
|
|
{
|
|
painter.translate(0, param(HeaderHeight));
|
|
|
|
// Key Animation Block
|
|
drawGrid(painter, param(KeyColAmount), param(KeyColWidth),
|
|
m_p.keyBlockWidth);
|
|
|
|
if (m_info.exportArea == Area_Actions)
|
|
// register cell rects.
|
|
registerCellRects(painter, columnsInPage(), param(KeyColWidth), bodyId);
|
|
|
|
// frame numbers
|
|
painter.save();
|
|
{
|
|
font.setPixelSize(param(RowHeight) - mm2px(2));
|
|
font.setLetterSpacing(QFont::PercentageSpacing, 100);
|
|
painter.setFont(font);
|
|
|
|
if (param(LastKeyColWidth) > 0) {
|
|
painter.translate(param(KeyColAmount) * param(KeyColWidth), 0);
|
|
for (int sec = 0; sec < 3; sec++) {
|
|
painter.save();
|
|
{
|
|
for (int f = 1; f <= 24; f++) {
|
|
if (f % 2 == 0) {
|
|
int frame = bodyId * 72 + sec * 24 + f;
|
|
if (m_info.serialFrameNumber)
|
|
frame += param(FrameLength) * framePage;
|
|
QRect frameLabelRect(0, 0,
|
|
param(LastKeyColWidth) - mm2px(0.5),
|
|
param(RowHeight));
|
|
painter.drawText(frameLabelRect,
|
|
Qt::AlignRight | Qt::AlignVCenter,
|
|
QString::number(frame));
|
|
}
|
|
painter.translate(0, param(RowHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
painter.translate(0, param(OneSecHeight));
|
|
}
|
|
}
|
|
// draw frame numbers on the left side of the block
|
|
else {
|
|
painter.translate(-param(KeyColWidth) * 2, 0);
|
|
for (int sec = 0; sec < 3; sec++) {
|
|
painter.save();
|
|
{
|
|
for (int f = 1; f <= 24; f++) {
|
|
if (f % 2 == 0) {
|
|
int frame = bodyId * 72 + sec * 24 + f;
|
|
if (m_info.serialFrameNumber)
|
|
frame += param(FrameLength) * framePage;
|
|
QRect frameLabelRect(0, 0,
|
|
param(KeyColWidth) * 2 - mm2px(0.5),
|
|
param(RowHeight));
|
|
painter.drawText(frameLabelRect,
|
|
Qt::AlignRight | Qt::AlignVCenter,
|
|
QString::number(frame));
|
|
}
|
|
painter.translate(0, param(RowHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
painter.translate(0, param(OneSecHeight));
|
|
}
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
painter.restore();
|
|
|
|
painter.translate(m_p.keyBlockWidth, 0);
|
|
painter.setPen(blockBorderPen);
|
|
painter.drawLine(0, 0, 0, param(BodyHeight));
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawDialogBlock(QPainter& painter, const int framePage,
|
|
const int bodyId) {
|
|
QFont font = painter.font();
|
|
font.setPixelSize(m_p.bodylabelTextSize_Large);
|
|
font.setLetterSpacing(QFont::PercentageSpacing, 100);
|
|
|
|
QRect labelRect(0, 0, param(DialogColWidth), param(HeaderHeight));
|
|
QString serifLabel =
|
|
(param(TranslateBodyLabel, 1) == 1) ? QObject::tr("S", "XSheetPDF") : "S";
|
|
while (font.pixelSize() > mm2px(1)) {
|
|
if (QFontMetrics(font).boundingRect(serifLabel).width() <
|
|
labelRect.width() - mm2px(1))
|
|
break;
|
|
font.setPixelSize(font.pixelSize() - mm2px(0.5));
|
|
}
|
|
painter.setFont(font);
|
|
painter.drawText(labelRect, Qt::AlignCenter, serifLabel);
|
|
|
|
// triangle shapes at every half seconds
|
|
static const QPointF points[3] = {
|
|
QPointF(mm2px(-0.8), 0.0),
|
|
QPointF(mm2px(-2.8), mm2px(1.25)),
|
|
QPointF(mm2px(-2.8), mm2px(-1.25)),
|
|
};
|
|
QRect secLabelRect(0, 0, param(DialogColWidth) - mm2px(1.0),
|
|
param(RowHeight));
|
|
|
|
painter.save();
|
|
{
|
|
font.setPixelSize(param(RowHeight) - mm2px(1.5));
|
|
painter.setFont(font);
|
|
|
|
painter.translate(0, param(HeaderHeight));
|
|
painter.save();
|
|
{
|
|
for (int sec = 1; sec <= 3; sec++) {
|
|
painter.save();
|
|
{
|
|
painter.setBrush(painter.pen().color());
|
|
painter.setPen(Qt::NoPen);
|
|
painter.translate(param(DialogColWidth), param(RowHeight) * 12);
|
|
painter.drawPolygon(points, 3);
|
|
}
|
|
painter.restore();
|
|
painter.save();
|
|
{
|
|
int second = bodyId * 3 + sec;
|
|
if (m_info.serialFrameNumber)
|
|
second += framePage * param(FrameLength) / 24;
|
|
painter.translate(0, param(RowHeight) * ((sec == 3) ? 23 : 23.5));
|
|
painter.drawText(secLabelRect, Qt::AlignRight | Qt::AlignVCenter,
|
|
QString::number(second));
|
|
}
|
|
painter.restore();
|
|
painter.translate(0, param(OneSecHeight));
|
|
}
|
|
}
|
|
painter.restore();
|
|
|
|
// register sound cells
|
|
if (m_info.drawSound || m_noteColumn)
|
|
registerSoundRects(painter, param(DialogColWidth), bodyId);
|
|
}
|
|
painter.restore();
|
|
|
|
painter.save();
|
|
{
|
|
painter.setPen(blockBorderPen);
|
|
painter.translate(param(DialogColWidth), 0);
|
|
painter.drawLine(0, 0, 0, param(BodyHeight));
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawCellsBlock(QPainter& painter, int bodyId) {
|
|
QFont font = painter.font();
|
|
font.setPixelSize(m_p.bodylabelTextSize_Small);
|
|
painter.setFont(font);
|
|
|
|
painter.save();
|
|
{
|
|
drawHeaderGrid(painter, param(CellsColAmount), param(CellsColWidth),
|
|
m_p.cellsBlockWidth);
|
|
|
|
if (m_info.exportArea == Area_Cells) {
|
|
painter.save();
|
|
{
|
|
painter.translate(0, param(HeaderHeight) / 2);
|
|
// register cell rects
|
|
registerColLabelRects(painter, columnsInPage(), param(CellsColWidth),
|
|
bodyId);
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
if (param(DrawCellsHeaderLabel, 1) == 1) {
|
|
QRect labelRect(0, 0, m_p.cellsBlockWidth, param(HeaderHeight) / 2);
|
|
QString cellsLabel = (param(TranslateBodyLabel, 1) == 1)
|
|
? QObject::tr("CELL", "XSheetPDF")
|
|
: "CELL";
|
|
doDrawText(painter, cellsLabel, labelRect);
|
|
}
|
|
|
|
painter.save();
|
|
{
|
|
painter.translate(0, param(HeaderHeight));
|
|
// Cells Block
|
|
drawGrid(painter, param(CellsColAmount) - 1, param(CellsColWidth),
|
|
m_p.cellsBlockWidth);
|
|
|
|
if (m_info.exportArea == Area_Cells)
|
|
// register cell rects.
|
|
registerCellRects(painter, columnsInPage(), param(CellsColWidth),
|
|
bodyId);
|
|
}
|
|
painter.restore();
|
|
|
|
painter.setPen(blockBorderPen);
|
|
painter.translate(m_p.cellsBlockWidth, 0);
|
|
painter.drawLine(0, 0, 0, param(BodyHeight));
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawCameraBlock(QPainter& painter) {
|
|
QFont font = painter.font();
|
|
font.setPixelSize(m_p.bodylabelTextSize_Large);
|
|
painter.setFont(font);
|
|
|
|
painter.save();
|
|
{
|
|
// Camera Block header
|
|
painter.save();
|
|
{
|
|
QString cameraLabel = (param(TranslateBodyLabel, 1) == 1)
|
|
? QObject::tr("CAMERA", "XSheetPDF")
|
|
: "CAMERA";
|
|
if (param(DrawCameraHeaderGrid, 0) == 1) {
|
|
drawHeaderGrid(painter, param(CameraColAmount), param(CameraColWidth),
|
|
m_p.cameraBlockWidth);
|
|
if (param(DrawCameraHeaderLabel, 1) == 1) {
|
|
font.setPixelSize(m_p.bodylabelTextSize_Small);
|
|
painter.setFont(font);
|
|
QRect labelRect(0, 0, m_p.cameraBlockWidth, param(HeaderHeight) / 2);
|
|
doDrawText(painter, cameraLabel, labelRect);
|
|
}
|
|
} else {
|
|
// horizontal lines
|
|
painter.setPen(thickPen);
|
|
painter.drawLine(0, param(HeaderHeight), m_p.cameraBlockWidth,
|
|
param(HeaderHeight));
|
|
|
|
if (param(DrawCameraHeaderLabel, 1) == 1) {
|
|
font.setPixelSize(m_p.bodylabelTextSize_Large);
|
|
painter.setFont(font);
|
|
QRect labelRect(0, 0, m_p.cameraBlockWidth, param(HeaderHeight));
|
|
doDrawText(painter, cameraLabel, labelRect);
|
|
}
|
|
}
|
|
}
|
|
painter.restore();
|
|
|
|
if (param(DrawCameraGrid, 1) != 0 || m_useExtraColumns) {
|
|
painter.save();
|
|
{
|
|
painter.translate(0, param(HeaderHeight));
|
|
// Cells Block
|
|
drawGrid(painter, param(CameraColAmount) - 1, param(CameraColWidth),
|
|
m_p.cameraBlockWidth);
|
|
}
|
|
painter.restore();
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawXsheetBody(QPainter& painter, int framePage,
|
|
int bodyId) {
|
|
// Body
|
|
painter.save();
|
|
{
|
|
painter.setPen(bodyOutlinePen);
|
|
painter.drawRect(QRect(0, 0, param(BodyWidth), param(BodyHeight)));
|
|
|
|
drawKeyBlock(painter, framePage, bodyId);
|
|
painter.translate(m_p.keyBlockWidth, 0);
|
|
drawDialogBlock(painter, framePage, bodyId);
|
|
painter.translate(param(DialogColWidth), 0);
|
|
drawCellsBlock(painter, bodyId);
|
|
painter.translate(m_p.cellsBlockWidth, 0);
|
|
drawCameraBlock(painter);
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawInfoHeader(QPainter& painter) {
|
|
painter.save();
|
|
{
|
|
painter.translate(param(InfoOriginLeft), param(InfoOriginTop));
|
|
QFont font = painter.font();
|
|
font.setPixelSize(param(InfoTitleHeight) - mm2px(2));
|
|
painter.setFont(font);
|
|
bool isLeftMost = true;
|
|
// draw each info
|
|
for (auto info : m_p.array_Infos) {
|
|
painter.setPen((isLeftMost) ? bodyOutlinePen : thinPen);
|
|
isLeftMost = false;
|
|
// vertical line
|
|
painter.drawLine(0, 0, 0, m_p.infoHeaderHeight);
|
|
// 3 horizontal lines
|
|
painter.setPen(thinPen);
|
|
painter.drawLine(0, param(InfoTitleHeight), info.width,
|
|
param(InfoTitleHeight));
|
|
painter.setPen(bodyOutlinePen);
|
|
painter.drawLine(0, 0, info.width, 0);
|
|
painter.drawLine(0, m_p.infoHeaderHeight, info.width,
|
|
m_p.infoHeaderHeight);
|
|
|
|
painter.setPen(thinPen);
|
|
// label
|
|
QRect labelRect(0, 0, info.width, param(InfoTitleHeight));
|
|
doDrawText(painter, info.label, labelRect);
|
|
|
|
if (info.decoFunc) {
|
|
painter.save();
|
|
{
|
|
painter.translate(0, param(InfoTitleHeight));
|
|
(*info.decoFunc)(painter,
|
|
QRect(0, 0, info.width, param(InfoBodyHeight)),
|
|
m_dataRects, param(TranslateInfoLabel, 1));
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
// translate
|
|
painter.translate(info.width, 0);
|
|
}
|
|
// vertical line at the rightmost edge
|
|
painter.setPen(bodyOutlinePen);
|
|
painter.drawLine(0, 0, 0, m_p.infoHeaderHeight);
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::addInfo(int w, QString lbl, DecoFunc f) {
|
|
XSheetPDF_InfoFormat info;
|
|
info.width = w;
|
|
info.label = lbl;
|
|
info.decoFunc = f;
|
|
m_p.array_Infos.append(info);
|
|
};
|
|
|
|
void XSheetPDFTemplate::drawContinuousLine(QPainter& painter, QRect rect,
|
|
bool isEmpty) {
|
|
if (isEmpty) {
|
|
int offset = rect.height() / 4;
|
|
QPoint p0(rect.center().x(), rect.top());
|
|
QPoint p3(rect.center().x(), rect.bottom());
|
|
QPoint p1 = p0 + QPoint(-offset, offset);
|
|
QPoint p2 = p3 + QPoint(offset, -offset);
|
|
QPainterPath path(p0);
|
|
path.cubicTo(p1, p2, p3);
|
|
painter.drawPath(path);
|
|
} else
|
|
painter.drawLine(rect.center().x(), rect.top(), rect.center().x(),
|
|
rect.bottom());
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawCellNumber(QPainter& painter, QRect rect,
|
|
TXshCell& cell, bool isKey) {
|
|
QFont font = painter.font();
|
|
font.setPixelSize(param(RowHeight) - mm2px(1));
|
|
font.setLetterSpacing(QFont::PercentageSpacing, 100);
|
|
painter.setFont(font);
|
|
|
|
if (cell.isEmpty()) {
|
|
painter.drawLine(rect.topLeft(), rect.bottomRight());
|
|
painter.drawLine(rect.topRight(), rect.bottomLeft());
|
|
} else {
|
|
QString str;
|
|
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) {
|
|
str = getFrameNumberWithLetters(cell.m_frameId.getNumber());
|
|
} else {
|
|
str = QString::number(cell.m_frameId.getNumber());
|
|
if (!cell.m_frameId.getLetter().isEmpty())
|
|
str += cell.m_frameId.getLetter();
|
|
}
|
|
painter.drawText(rect, Qt::AlignCenter, str);
|
|
if (isKey) {
|
|
QPen keep(painter.pen());
|
|
QPen circlePen(keep);
|
|
circlePen.setWidth(mm2px(0.3));
|
|
painter.setPen(circlePen);
|
|
QFontMetrics fm(font);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
|
|
int keyR_width =
|
|
std::max(param(RowHeight), fm.horizontalAdvance(str) + mm2px(1));
|
|
#else
|
|
int keyR_width =
|
|
std::max(param(RowHeight), fm.boundingRect(str).width() + mm2px(1));
|
|
#endif
|
|
QRect keyR(0, 0, keyR_width, param(RowHeight));
|
|
keyR.moveCenter(rect.center());
|
|
painter.drawEllipse(keyR);
|
|
painter.setPen(keep);
|
|
}
|
|
}
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawTickMark(QPainter& painter, QRect rect,
|
|
TickMarkType type) {
|
|
QRect tickR(0, 0, rect.height(), rect.height());
|
|
tickR.moveCenter(rect.center());
|
|
painter.drawPixmap(tickR, tickMarkPm(type, rect.height()));
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawEndMark(QPainter& painter, QRect upperRect) {
|
|
QRect rect = upperRect.translated(0, upperRect.height());
|
|
|
|
painter.drawLine(rect.topLeft(), rect.topRight());
|
|
|
|
painter.drawLine(rect.center().x(), rect.top(), rect.left(),
|
|
rect.center().y());
|
|
painter.drawLine(rect.topRight(), rect.bottomLeft());
|
|
painter.drawLine(rect.right(), rect.center().y(), rect.center().x(),
|
|
rect.bottom());
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawLevelName(QPainter& painter, QRect rect,
|
|
QString name, bool isBottom) {
|
|
QFont font = painter.font();
|
|
font.setPixelSize(rect.height());
|
|
font.setLetterSpacing(QFont::PercentageSpacing, 100);
|
|
painter.setFont(font);
|
|
|
|
// if it can fit in the rect, then just draw it
|
|
if (QFontMetrics(font).boundingRect(name).width() < rect.width()) {
|
|
painter.drawText(rect, Qt::AlignCenter, name);
|
|
return;
|
|
}
|
|
|
|
// if it can fit with 90% sized font
|
|
QFont altFont(font);
|
|
altFont.setPixelSize(font.pixelSize() * 0.9);
|
|
if (QFontMetrics(altFont).boundingRect(name).width() < rect.width()) {
|
|
painter.setFont(altFont);
|
|
painter.drawText(rect, Qt::AlignCenter, name);
|
|
return;
|
|
}
|
|
|
|
// or, draw level name vertically
|
|
// insert line breaks to every characters
|
|
for (int i = 1; i < name.size(); i += 2) name.insert(i, '\n');
|
|
// QFontMetrics::boundingRect(const QString &text) does NOT process newline
|
|
// characters as linebreaks.
|
|
QRect boundingRect = QFontMetrics(font).boundingRect(
|
|
QRect(0, 0, mm2px(100), mm2px(100)), Qt::AlignTop | Qt::AlignLeft, name);
|
|
if (!isBottom) {
|
|
boundingRect.moveCenter(
|
|
QPoint(rect.center().x(), rect.bottom() - boundingRect.height() / 2));
|
|
} else {
|
|
boundingRect.moveCenter(
|
|
QPoint(rect.center().x(), rect.top() + boundingRect.height() / 2));
|
|
}
|
|
|
|
// fill background of the label
|
|
painter.fillRect(boundingRect, Qt::white);
|
|
painter.drawText(boundingRect, Qt::AlignCenter, name);
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawLogo(QPainter& painter) {
|
|
if (!m_dataRects.contains(Data_Logo)) return;
|
|
if (m_info.logoText.isEmpty() && m_info.logoPixmap.isNull()) return;
|
|
QRect logoRect = m_dataRects.value(Data_Logo);
|
|
|
|
if (!m_info.logoText.isEmpty()) {
|
|
QFont font = painter.font();
|
|
font.setPixelSize(logoRect.height() - mm2px(2));
|
|
while (1) {
|
|
if (QFontMetrics(font).boundingRect(m_info.logoText).width() <
|
|
logoRect.width() &&
|
|
QFontMetrics(font).boundingRect(m_info.logoText).height() <
|
|
logoRect.height())
|
|
break;
|
|
if (font.pixelSize() <= mm2px(1)) break;
|
|
font.setPixelSize(font.pixelSize() - mm2px(1));
|
|
}
|
|
painter.setFont(font);
|
|
painter.drawText(logoRect, Qt::AlignTop | Qt::AlignLeft, m_info.logoText);
|
|
}
|
|
|
|
else if (!m_info.logoPixmap.isNull()) {
|
|
painter.drawPixmap(logoRect.topLeft(), m_info.logoPixmap);
|
|
}
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawSound(QPainter& painter, int framePage) {
|
|
if (!m_info.drawSound || m_soundColumns.isEmpty() ||
|
|
m_soundCellRects.isEmpty())
|
|
return;
|
|
|
|
// obtain united range of the sound columns
|
|
int r0 = INT_MAX, r1 = -1;
|
|
for (auto soundCol : m_soundColumns) {
|
|
int tmpR0, tmpR1;
|
|
soundCol->getRange(tmpR0, tmpR1);
|
|
r0 = std::min(r0, tmpR0);
|
|
r1 = std::max(r1, tmpR1);
|
|
}
|
|
|
|
// obtain frame range to be printed in the current page
|
|
int printFrameR0 = framePage * param(FrameLength);
|
|
int printFrameR1 = printFrameR0 + param(FrameLength) - 1;
|
|
|
|
// return if the current page is out of range
|
|
if (r1 < printFrameR0 || printFrameR1 < r0) return;
|
|
|
|
const Orientation* o = Orientations::instance().topToBottom();
|
|
int oneFrameHeight = o->dimension(PredefinedDimension::FRAME);
|
|
int trackWidth = o->layerSide(o->rect(PredefinedRect::SOUND_TRACK)).length();
|
|
|
|
painter.setRenderHints(QPainter::Antialiasing |
|
|
QPainter::SmoothPixmapTransform);
|
|
|
|
// frame range to be printed
|
|
for (int f = std::max(r0, printFrameR0); f <= std::min(r1, printFrameR1);
|
|
f++) {
|
|
int rectId = f - printFrameR0;
|
|
|
|
QPixmap img(trackWidth, oneFrameHeight);
|
|
img.fill(Qt::transparent);
|
|
QPainter p(&img);
|
|
p.setPen(QPen(m_info.lineColor, 1, Qt::SolidLine, Qt::FlatCap));
|
|
p.translate(trackWidth / 2, 0);
|
|
for (auto soundCol : m_soundColumns) {
|
|
TXshCell cell = soundCol->getSoundCell(f);
|
|
if (soundCol->isCellEmpty(f) || cell.isEmpty() ||
|
|
f > soundCol->getMaxFrame() + 1 || f < soundCol->getFirstRow())
|
|
continue;
|
|
|
|
TXshSoundLevelP soundLevel = cell.getSoundLevel();
|
|
|
|
int soundPixel = cell.getFrameId().getNumber() *
|
|
oneFrameHeight; // pixels since start of clip
|
|
|
|
for (int i = 0; i < oneFrameHeight; i++) {
|
|
DoublePair minmax;
|
|
soundLevel->getValueAtPixel(o, soundPixel, minmax);
|
|
p.drawLine(minmax.first, i, minmax.second, i);
|
|
soundPixel++;
|
|
}
|
|
}
|
|
p.end();
|
|
|
|
QRect rect = m_soundCellRects.at(rectId);
|
|
|
|
painter.drawPixmap(rect, img.scaled(rect.size()));
|
|
}
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawDialogue(QPainter& painter, int framePage) {
|
|
if (!m_noteColumn || m_soundCellRects.isEmpty()) return;
|
|
|
|
QFont font = painter.font();
|
|
font.setPixelSize(m_soundCellRects[0].height());
|
|
painter.setFont(font);
|
|
|
|
QFont smallFont(font);
|
|
smallFont.setPixelSize(font.pixelSize() * 2 / 3);
|
|
|
|
QFont largeFont(font);
|
|
largeFont.setPixelSize(font.pixelSize() * 13 / 10);
|
|
int heightThres = QFontMetrics(largeFont).height();
|
|
|
|
int r0, r1;
|
|
m_noteColumn->getRange(r0, r1);
|
|
|
|
// obtain frame range to be printed in the current page
|
|
int printFrameR0 = framePage * param(FrameLength);
|
|
int printFrameR1 = printFrameR0 + param(FrameLength) - 1;
|
|
|
|
// compute for each body
|
|
int framesPerBody = 72;
|
|
int bodyFrameR0 = printFrameR0;
|
|
int bodyFrameR1 = bodyFrameR0 + framesPerBody - 1;
|
|
while (bodyFrameR1 <= printFrameR1) {
|
|
// move to next body if the current body is out of range
|
|
if (r1 < bodyFrameR0 || bodyFrameR1 < r0) {
|
|
// to next body
|
|
bodyFrameR0 = bodyFrameR1 + 1;
|
|
bodyFrameR1 = bodyFrameR0 + framesPerBody - 1;
|
|
continue;
|
|
}
|
|
|
|
// frame range to be printed
|
|
int drawStart = std::max(r0, bodyFrameR0);
|
|
int drawEnd = std::min(r1, std::min(bodyFrameR1, printFrameR1));
|
|
|
|
int rStart = drawStart;
|
|
int rEnd = drawEnd;
|
|
// obtain top row of the fist note block
|
|
if (!m_noteColumn->getCell(drawStart).isEmpty()) {
|
|
while (rStart > 0 && m_noteColumn->getCell(rStart - 1) ==
|
|
m_noteColumn->getCell(drawStart)) {
|
|
rStart--;
|
|
}
|
|
}
|
|
// obtain bottom row of the last note block
|
|
if (!m_noteColumn->getCell(drawEnd).isEmpty()) {
|
|
while (m_noteColumn->getCell(rEnd + 1) ==
|
|
m_noteColumn->getCell(drawEnd)) {
|
|
rEnd++;
|
|
}
|
|
}
|
|
|
|
for (int row = rStart; row <= drawEnd; row++) {
|
|
TXshCell cell = m_noteColumn->getCell(row);
|
|
if (cell.isEmpty()) continue;
|
|
|
|
// check how long the same content continues
|
|
int rowTo = row;
|
|
while (m_noteColumn->getCell(rowTo + 1) == cell) {
|
|
rowTo++;
|
|
}
|
|
int blockLength = rowTo - row + 1;
|
|
|
|
QString text = cell.getSoundTextLevel()->getFrameText(
|
|
cell.m_frameId.getNumber() - 1);
|
|
int textCount = text.count();
|
|
// separate text if it overflows the body
|
|
if (row < drawStart) {
|
|
int partialBlockLength = rowTo - drawStart + 1;
|
|
int partialTextCount = (int)std::round(
|
|
(double)(textCount * partialBlockLength) / (double)blockLength);
|
|
text = text.mid(textCount - partialTextCount);
|
|
textCount = partialTextCount;
|
|
row = drawStart;
|
|
blockLength = partialBlockLength;
|
|
}
|
|
// draw start mark
|
|
else {
|
|
int topRectId = row - printFrameR0;
|
|
QRect rect = m_soundCellRects.at(topRectId);
|
|
painter.drawLine(rect.topLeft(), rect.topRight());
|
|
}
|
|
|
|
if (rowTo > drawEnd) {
|
|
int partialBlockLength = drawEnd - row + 1;
|
|
int partialTextCount = (int)std::round(
|
|
(double)(textCount * partialBlockLength) / (double)blockLength);
|
|
text = text.mid(0, partialTextCount);
|
|
textCount = partialTextCount;
|
|
rowTo = drawEnd;
|
|
}
|
|
// draw end mark
|
|
else if (m_noteColumn->getCell(rowTo + 1).isEmpty()) {
|
|
int bottomRectId = rowTo - printFrameR0;
|
|
QRect rect = m_soundCellRects.at(bottomRectId);
|
|
drawEndMark(painter, rect);
|
|
}
|
|
if (text.isEmpty()) {
|
|
row = rowTo;
|
|
continue;
|
|
}
|
|
|
|
int normalLettersPerChunk = textCount * m_soundCellRects[0].width() /
|
|
QFontMetrics(font).boundingRect(text).width();
|
|
int maxLettersPerChunk =
|
|
textCount * m_soundCellRects[0].width() /
|
|
QFontMetrics(smallFont).boundingRect(text).width();
|
|
|
|
int lettersPerChunk =
|
|
(int)std::ceil((double)textCount / ((double)blockLength));
|
|
lettersPerChunk = std::min(lettersPerChunk, maxLettersPerChunk);
|
|
int chunkCount =
|
|
(int)std::ceil((double)textCount / (double)(lettersPerChunk));
|
|
chunkCount = std::min(chunkCount, (int)((double)(blockLength)*1.5));
|
|
|
|
int topRectId = row - printFrameR0;
|
|
int bottomRectId = rowTo - printFrameR0;
|
|
// unite the cell rects and divide by the amount of chunks
|
|
QRect unitedRect = m_soundCellRects.at(topRectId).united(
|
|
m_soundCellRects.at(bottomRectId));
|
|
// check if the large font is available
|
|
if (lettersPerChunk == 1 && unitedRect.height() / textCount > heightThres)
|
|
painter.setFont(largeFont);
|
|
else if (lettersPerChunk > normalLettersPerChunk)
|
|
painter.setFont(smallFont);
|
|
else
|
|
painter.setFont(font);
|
|
// draw text
|
|
for (int c = 0; c < chunkCount; c++) {
|
|
int y0 = unitedRect.top() + unitedRect.height() * c / chunkCount;
|
|
int y1 = unitedRect.top() + unitedRect.height() * (c + 1) / chunkCount;
|
|
QRect tmpRect(unitedRect.left(), y0, unitedRect.width(), y1 - y0 + 1);
|
|
painter.drawText(tmpRect, Qt::AlignCenter,
|
|
text.mid(c * lettersPerChunk, lettersPerChunk));
|
|
}
|
|
|
|
row = rowTo;
|
|
}
|
|
// to next body
|
|
bodyFrameR0 = bodyFrameR1 + 1;
|
|
bodyFrameR1 = bodyFrameR0 + framesPerBody - 1;
|
|
}
|
|
}
|
|
|
|
XSheetPDFTemplate::XSheetPDFTemplate(
|
|
const QList<QPair<TXshLevelColumn*, QString>>& columns, const int duration)
|
|
: m_columns(columns), m_duration(duration), m_useExtraColumns(false) {}
|
|
|
|
void XSheetPDFTemplate::setInfo(const XSheetPDFFormatInfo& info) {
|
|
m_info = info;
|
|
thinPen = QPen(info.lineColor, param(ThinLineWidth, mm2px(0.25)),
|
|
Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
|
|
thickPen = QPen(info.lineColor, param(ThickLineWidth, mm2px(0.5)),
|
|
Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
|
|
bodyOutlinePen = QPen(info.lineColor, param(BodyOutlineWidth, mm2px(0.5)),
|
|
Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
|
|
blockBorderPen = (param(IsBlockBorderThick, 0) > 0) ? thickPen : thinPen;
|
|
// check if it should use extra columns
|
|
if (info.exportArea == Area_Cells && param(ExtraCellsColAmount, 0) > 0) {
|
|
int colsInScene = m_columns.size();
|
|
int colsInPage = param(CellsColAmount);
|
|
int colsInPage_Ex = param(CellsColAmount) + param(ExtraCellsColAmount);
|
|
auto getPageNum = [&](int cip) {
|
|
int ret = colsInScene / cip;
|
|
if (colsInScene % cip != 0 || colsInScene == 0) ret += 1;
|
|
return ret;
|
|
};
|
|
if (getPageNum(colsInPage) > getPageNum(colsInPage_Ex))
|
|
m_useExtraColumns = true;
|
|
}
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawXsheetTemplate(QPainter& painter, int framePage,
|
|
bool isPreview) {
|
|
// clear rects
|
|
m_colLabelRects.clear();
|
|
m_colLabelRects_bottom.clear();
|
|
m_cellRects.clear();
|
|
m_soundCellRects.clear();
|
|
|
|
// painter.setFont(QFont("Times New Roman"));
|
|
painter.setFont(m_info.templateFontFamily);
|
|
painter.setPen(thinPen);
|
|
|
|
painter.save();
|
|
{
|
|
if (isPreview)
|
|
painter.translate(mm2px(m_p.documentMargin.left()),
|
|
mm2px(m_p.documentMargin.top()));
|
|
|
|
drawLogo(painter);
|
|
|
|
// draw Info header
|
|
drawInfoHeader(painter);
|
|
|
|
painter.translate(0, param(BodyTop));
|
|
for (int bId = 0; bId < param(BodyAmount); bId++) {
|
|
drawXsheetBody(painter, framePage, bId);
|
|
painter.translate(param(BodyWidth) + param(BodyHMargin), 0);
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void XSheetPDFTemplate::drawXsheetContents(QPainter& painter, int framePage,
|
|
int parallelPage, bool isPreview) {
|
|
auto checkContinuous = [&](const TXshLevelColumn* column, int f, int r) {
|
|
if (m_info.continuousLineMode == Line_Always)
|
|
return true;
|
|
else if (m_info.continuousLineMode == Line_None)
|
|
return false;
|
|
TXshCell cell = column->getCell(f);
|
|
// check subsequent cells and see if more than 3 cells continue.
|
|
int tmp_r = r + 1;
|
|
for (int tmp_f = f + 1; tmp_f <= f + 3; tmp_f++, tmp_r++) {
|
|
if (tmp_f == m_duration) return false;
|
|
if (tmp_r % 72 == 0) return false; // step over to the next body
|
|
if (column->getCell(tmp_f) != cell) return false;
|
|
// tickmark breaks continuous line
|
|
int markId = column->getCellMark(tmp_f);
|
|
if (markId >= 0 &&
|
|
(m_info.tick1MarkId == markId || m_info.tick2MarkId == markId))
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// draw soundtrack
|
|
drawSound(painter, framePage);
|
|
|
|
painter.setPen(
|
|
QPen(Qt::black, mm2px(0.5), Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
|
|
painter.setFont(m_info.contentsFontFamily);
|
|
|
|
// draw dialogue
|
|
drawDialogue(painter, framePage);
|
|
|
|
int colsInPage = columnsInPage();
|
|
int startColId = colsInPage * parallelPage;
|
|
int startFrame = param(FrameLength) * framePage;
|
|
int c = 0, r;
|
|
for (int colId = startColId; c < colsInPage; c++, colId++) {
|
|
if (colId == m_columns.size()) break;
|
|
|
|
TXshLevelColumn* column = m_columns.at(colId).first;
|
|
// obtain level in this column
|
|
int r0, r1;
|
|
column->getRange(r0, r1);
|
|
TXshLevelP level = column->getCell(r0).m_level;
|
|
|
|
QString columnName = m_columns.at(colId).second;
|
|
if (columnName.isEmpty())
|
|
columnName = QString::fromStdWString(level->getName());
|
|
|
|
TXshCell prevCell;
|
|
bool drawCLFlag;
|
|
|
|
r = 0;
|
|
for (int f = startFrame; r < param(FrameLength); r++, f++) {
|
|
// draw level name
|
|
if (r % 72 == 0)
|
|
drawLevelName(painter, m_colLabelRects[c][r / 72], columnName);
|
|
// draw level name on bottom
|
|
if (m_info.drawLevelNameOnBottom && r % 72 == 37 &&
|
|
startFrame + 72 != m_duration)
|
|
drawLevelName(painter, m_colLabelRects_bottom[c][r / 72], columnName,
|
|
true);
|
|
|
|
TXshCell cell = column->getCell(f);
|
|
if (cell.m_level != level) cell.m_level = nullptr;
|
|
|
|
int markId = column->getCellMark(f);
|
|
|
|
// draw tick mark
|
|
if ((prevCell == cell || cell.isEmpty()) && markId >= 0 &&
|
|
(m_info.tick1MarkId == markId || m_info.tick2MarkId == markId)) {
|
|
if (m_info.tick1MarkId == markId)
|
|
drawTickMark(painter, m_cellRects[c][r], m_info.tick1MarkType);
|
|
else
|
|
drawTickMark(painter, m_cellRects[c][r], m_info.tick2MarkType);
|
|
drawCLFlag = checkContinuous(column, f, r);
|
|
}
|
|
// cotinuous line
|
|
else if (r != 0 && r != 72 && prevCell == cell) {
|
|
if (drawCLFlag)
|
|
drawContinuousLine(painter, m_cellRects[c][r], cell.isEmpty());
|
|
}
|
|
// draw cell
|
|
else {
|
|
bool drawKeyMark = (markId >= 0 && m_info.keyMarkId == markId);
|
|
drawCellNumber(painter, m_cellRects[c][r], cell, drawKeyMark);
|
|
drawCLFlag = checkContinuous(column, f, r);
|
|
}
|
|
prevCell = cell;
|
|
|
|
if (f == m_duration - 1) {
|
|
// break after drawing the end mark
|
|
drawEndMark(painter, m_cellRects[c][r]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
painter.setFont(m_info.templateFontFamily);
|
|
QFont font = painter.font();
|
|
font.setLetterSpacing(QFont::PercentageSpacing, 100);
|
|
|
|
// draw data
|
|
painter.save();
|
|
{
|
|
if (isPreview)
|
|
painter.translate(mm2px(m_p.documentMargin.left()),
|
|
mm2px(m_p.documentMargin.top()));
|
|
|
|
if (m_dataRects.contains(Data_Memo) && !m_info.memoText.isEmpty() &&
|
|
framePage == 0) {
|
|
// define the preferable font size
|
|
int lines =
|
|
std::max(m_info.memoText.count("\n") + 1, param(MemoLinesAmount));
|
|
int lineSpacing = m_dataRects.value(Data_Memo).height() / lines;
|
|
int pixelSize = lineSpacing;
|
|
while (1) {
|
|
font.setPixelSize(pixelSize);
|
|
if (pixelSize <= mm2px(2) ||
|
|
QFontMetrics(font).lineSpacing() <= lineSpacing)
|
|
break;
|
|
pixelSize -= mm2px(0.2);
|
|
}
|
|
painter.setFont(font);
|
|
painter.drawText(m_dataRects.value(Data_Memo),
|
|
Qt::AlignLeft | Qt::AlignTop, m_info.memoText);
|
|
}
|
|
|
|
QString dateTime_scenePath = m_info.dateTimeText;
|
|
if (!m_info.scenePathText.isEmpty()) {
|
|
if (!dateTime_scenePath.isEmpty()) dateTime_scenePath += "\n";
|
|
dateTime_scenePath += m_info.scenePathText;
|
|
}
|
|
if (m_dataRects.contains(Data_DateTimeAndScenePath) &&
|
|
!dateTime_scenePath.isEmpty()) {
|
|
font.setPixelSize(m_p.bodylabelTextSize_Small);
|
|
painter.setFont(font);
|
|
painter.drawText(m_dataRects.value(Data_DateTimeAndScenePath),
|
|
Qt::AlignRight | Qt::AlignTop, dateTime_scenePath);
|
|
}
|
|
}
|
|
painter.restore();
|
|
|
|
if (m_dataRects.contains(Data_Second) && m_duration >= 24) {
|
|
QString str = QString::number(m_duration / 24);
|
|
setFontFittingRectWidth(painter, str, m_dataRects.value(Data_Second));
|
|
painter.drawText(m_dataRects.value(Data_Second), Qt::AlignCenter, str);
|
|
}
|
|
if (m_dataRects.contains(Data_Frame) && m_duration > 0) {
|
|
QString str = QString::number(m_duration % 24);
|
|
setFontFittingRectWidth(painter, str, m_dataRects.value(Data_Frame));
|
|
painter.drawText(m_dataRects.value(Data_Frame), Qt::AlignCenter, str);
|
|
}
|
|
|
|
if (m_dataRects.contains(Data_TotalPages)) {
|
|
QString totStr = QString::number(framePageCount());
|
|
if (parallelPageCount() > 1)
|
|
totStr += "x" + QString::number(parallelPageCount());
|
|
|
|
setFontFittingRectWidth(painter, totStr,
|
|
m_dataRects.value(Data_TotalPages));
|
|
painter.drawText(m_dataRects.value(Data_TotalPages), Qt::AlignCenter,
|
|
totStr);
|
|
}
|
|
if (m_dataRects.contains(Data_CurrentPage)) {
|
|
QString curStr = QString::number(framePage + 1);
|
|
if (parallelPageCount() > 1) curStr += QChar('A' + parallelPage);
|
|
|
|
setFontFittingRectWidth(painter, curStr,
|
|
m_dataRects.value(Data_CurrentPage));
|
|
painter.drawText(m_dataRects.value(Data_CurrentPage),
|
|
Qt::AlignLeft | Qt::AlignVCenter, curStr);
|
|
}
|
|
if (m_dataRects.contains(Data_SceneName) && !m_info.sceneNameText.isEmpty()) {
|
|
QRect rect = m_dataRects.value(Data_SceneName);
|
|
setFontFittingRectWidth(painter, m_info.sceneNameText, rect);
|
|
painter.drawText(rect, Qt::AlignCenter, m_info.sceneNameText);
|
|
}
|
|
}
|
|
|
|
void XSheetPDFTemplate::initializePage(QPdfWriter& writer) {
|
|
QPageLayout pageLayout;
|
|
pageLayout.setUnits(QPageLayout::Millimeter);
|
|
pageLayout.setPageSize(
|
|
QPageSize(m_p.documentPageSize)); // 普通のB4はISO B4(250x353mm)
|
|
// 日本のB4はJIS B4(257x364mm)
|
|
pageLayout.setOrientation(QPageLayout::Portrait);
|
|
pageLayout.setMargins(m_p.documentMargin);
|
|
writer.setPageLayout(pageLayout);
|
|
writer.setResolution(PDF_Resolution);
|
|
}
|
|
|
|
QPixmap XSheetPDFTemplate::initializePreview() {
|
|
QSizeF size = QPageSize::definitionSize(m_p.documentPageSize);
|
|
QSize pxSize;
|
|
// convert to px
|
|
switch (QPageSize::definitionUnits(m_p.documentPageSize)) {
|
|
case QPageSize::Millimeter:
|
|
pxSize = QSize(mm2px(size.width()), mm2px(size.height()));
|
|
break;
|
|
case QPageSize::Inch:
|
|
pxSize =
|
|
QSize(size.width() * PDF_Resolution, size.height() * PDF_Resolution);
|
|
break;
|
|
default:
|
|
std::cout << "unsupported unit" << std::endl;
|
|
return QPixmap();
|
|
}
|
|
QPixmap retPm(pxSize);
|
|
retPm.fill(Qt::white);
|
|
|
|
return retPm;
|
|
}
|
|
|
|
int XSheetPDFTemplate::framePageCount() {
|
|
int ret = m_duration / param(FrameLength);
|
|
if (m_duration % param(FrameLength) != 0 || m_duration == 0) ret += 1;
|
|
return ret;
|
|
}
|
|
|
|
int XSheetPDFTemplate::parallelPageCount() {
|
|
int colsInPage = columnsInPage();
|
|
int colsInScene = m_columns.size();
|
|
|
|
int ret = colsInScene / colsInPage;
|
|
if (colsInScene % colsInPage != 0 || colsInScene == 0) ret += 1;
|
|
return ret;
|
|
}
|
|
|
|
int XSheetPDFTemplate::columnsInPage() {
|
|
if (m_info.exportArea == Area_Actions) {
|
|
int colsInPage = param(KeyColAmount);
|
|
if (param(LastKeyColWidth) > 0) colsInPage++;
|
|
return colsInPage;
|
|
}
|
|
|
|
// CELLS
|
|
if (m_useExtraColumns)
|
|
return param(CellsColAmount) + param(ExtraCellsColAmount, 0);
|
|
return param(CellsColAmount);
|
|
}
|
|
|
|
QSize XSheetPDFTemplate::logoPixelSize() {
|
|
if (!m_dataRects.contains(Data_Logo)) return QSize();
|
|
return m_dataRects.value(Data_Logo).size();
|
|
}
|
|
|
|
void XSheetPDFTemplate::setLogoPixmap(QPixmap pm) { m_info.logoPixmap = pm; }
|
|
|
|
//---------------------------------------------------------
|
|
XSheetPDFTemplate_B4_6sec::XSheetPDFTemplate_B4_6sec(
|
|
const QList<QPair<TXshLevelColumn*, QString>>& columns, const int duration)
|
|
: XSheetPDFTemplate(columns, duration) {
|
|
m_p.documentPageSize = QPageSize::JisB4; // 257 * 364 mm
|
|
m_p.documentMargin = QMarginsF(9.5, 6.0, 8.5, 6.0); // millimeters
|
|
|
|
m_params.insert("BodyWidth", mm2px(117));
|
|
m_params.insert("BodyHeight", mm2px(315.5));
|
|
m_params.insert("BodyAmount", 2);
|
|
m_params.insert("BodyHMargin", mm2px(5.0));
|
|
m_params.insert("BodyTop", mm2px(36.5));
|
|
m_params.insert("HeaderHeight", mm2px(6.5));
|
|
m_params.insert("KeyColWidth", mm2px(5.0));
|
|
m_params.insert("KeyColAmount", 4);
|
|
m_params.insert("LastKeyColWidth", mm2px(7));
|
|
m_params.insert("DialogColWidth", mm2px(10));
|
|
m_params.insert("CellsColWidth", mm2px(10));
|
|
m_params.insert("CellsColAmount", 5);
|
|
m_params.insert("CameraColWidth", mm2px(10));
|
|
m_params.insert("CameraColAmount", 3);
|
|
m_params.insert("RowHeight", mm2px(102.0 / 24.0));
|
|
m_params.insert("1SecHeight", mm2px(103.0));
|
|
m_params.insert("FrameLength", 144);
|
|
m_params.insert("InfoOriginLeft", mm2px(84));
|
|
m_params.insert("InfoOriginTop", mm2px(0));
|
|
m_params.insert("InfoTitleHeight", mm2px(4.5));
|
|
m_params.insert("InfoBodyHeight", mm2px(8.5));
|
|
m_params.insert("MemoLinesAmount", 3);
|
|
m_params.insert("ExtraCellsColAmount", 3);
|
|
|
|
addInfo(mm2px(26), QObject::tr("EPISODE", "XSheetPDF"));
|
|
addInfo(mm2px(18.5), QObject::tr("SEQ.", "XSheetPDF"));
|
|
addInfo(mm2px(18.5), QObject::tr("SCENE", "XSheetPDF"), decoSceneInfo);
|
|
addInfo(mm2px(40), QObject::tr("TIME", "XSheetPDF"), decoTimeInfo);
|
|
addInfo(mm2px(26), QObject::tr("NAME", "XSheetPDF"));
|
|
addInfo(mm2px(26), QObject::tr("SHEET", "XSheetPDF"), decoSheetInfo);
|
|
|
|
m_p.keyBlockWidth =
|
|
param(KeyColWidth) * param(KeyColAmount) + param(LastKeyColWidth);
|
|
m_p.cellsBlockWidth = param(CellsColWidth) * param(CellsColAmount);
|
|
m_p.cameraBlockWidth = param(CameraColWidth) * param(CameraColAmount);
|
|
m_p.infoHeaderHeight = param(InfoTitleHeight) + param(InfoBodyHeight);
|
|
m_p.bodylabelTextSize_Large = param(HeaderHeight) - mm2px(3);
|
|
m_p.bodylabelTextSize_Small = param(HeaderHeight) / 2 - mm2px(1);
|
|
|
|
// data rects
|
|
int infoBottom =
|
|
param(InfoOriginTop) + param(InfoTitleHeight) + param(InfoBodyHeight);
|
|
m_dataRects[Data_Memo] = QRect(mm2px(0), infoBottom + mm2px(1), mm2px(239),
|
|
param(BodyTop) - infoBottom - mm2px(3));
|
|
m_dataRects[Data_DateTimeAndScenePath] = m_dataRects[Data_Memo];
|
|
m_dataRects[Data_Logo] =
|
|
QRect(mm2px(0), mm2px(0), param(InfoOriginLeft), infoBottom);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read from the settings file
|
|
XSheetPDFTemplate_Custom::XSheetPDFTemplate_Custom(
|
|
const QString& fp, const QList<QPair<TXshLevelColumn*, QString>>& columns,
|
|
const int duration)
|
|
: XSheetPDFTemplate(columns, duration), m_valid(false) {
|
|
QSettings s(fp, QSettings::IniFormat);
|
|
if (!s.childGroups().contains("XSheetPDFTemplate")) return;
|
|
|
|
s.beginGroup("XSheetPDFTemplate");
|
|
{
|
|
QString pageStr = s.value("PageSize").toString();
|
|
m_p.documentPageSize = str2PageSizeId(pageStr);
|
|
|
|
QString marginStr = s.value("Margin").toString();
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
QStringList m = marginStr.split(QLatin1Char(','), Qt::SkipEmptyParts);
|
|
#else
|
|
QStringList m = marginStr.split(QLatin1Char(','), QString::SkipEmptyParts);
|
|
#endif
|
|
assert(m.size() == 4);
|
|
if (m.size() == 4)
|
|
m_p.documentMargin = QMarginsF(m[0].toDouble(), m[1].toDouble(),
|
|
m[2].toDouble(), m[3].toDouble());
|
|
|
|
s.beginGroup("Number");
|
|
{
|
|
for (auto key : s.childKeys())
|
|
m_params.insert(key.toStdString(), s.value(key).toInt());
|
|
}
|
|
s.endGroup();
|
|
|
|
s.beginGroup("Length");
|
|
{
|
|
for (auto key : s.childKeys())
|
|
m_params.insert(key.toStdString(), mm2px(s.value(key).toDouble()));
|
|
}
|
|
s.endGroup();
|
|
|
|
bool translateInfo = param(TranslateInfoLabel, 1) == 1;
|
|
int size = s.beginReadArray("InfoFormats");
|
|
for (int i = 0; i < size; ++i) {
|
|
s.setArrayIndex(i);
|
|
XSheetPDF_InfoFormat infoFormat;
|
|
infoFormat.width = mm2px(s.value("width").toDouble());
|
|
if (translateInfo)
|
|
infoFormat.label =
|
|
QObject::tr(s.value("label").toString().toLocal8Bit(), "XSheetPDF");
|
|
else
|
|
infoFormat.label = s.value("label").toString();
|
|
|
|
infoFormat.decoFunc =
|
|
infoType2DecoFunc(s.value("infoType", "").toString());
|
|
m_p.array_Infos.append(infoFormat);
|
|
}
|
|
s.endArray();
|
|
|
|
s.beginGroup("DataFields");
|
|
{
|
|
for (auto key : s.childKeys()) {
|
|
QString rectStr = s.value(key).toString();
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
QStringList r = rectStr.split(QLatin1Char(','), Qt::SkipEmptyParts);
|
|
#else
|
|
QStringList r =
|
|
rectStr.split(QLatin1Char(','), QString::SkipEmptyParts);
|
|
#endif
|
|
assert(r.size() == 4);
|
|
if (r.size() == 4)
|
|
m_dataRects[dataStr2Type(key)] =
|
|
QRect(mm2px(r[0].toDouble()), mm2px(r[1].toDouble()),
|
|
mm2px(r[2].toDouble()), mm2px(r[3].toDouble()));
|
|
}
|
|
}
|
|
s.endGroup();
|
|
}
|
|
s.endGroup();
|
|
|
|
m_p.keyBlockWidth =
|
|
param(KeyColWidth) * param(KeyColAmount) + param(LastKeyColWidth);
|
|
m_p.cellsBlockWidth = param(CellsColWidth) * param(CellsColAmount);
|
|
m_p.cameraBlockWidth = param(CameraColWidth) * param(CameraColAmount);
|
|
m_p.infoHeaderHeight = param(InfoTitleHeight) + param(InfoBodyHeight);
|
|
m_p.bodylabelTextSize_Large = param(HeaderHeight) - mm2px(3);
|
|
m_p.bodylabelTextSize_Small = param(HeaderHeight) / 2 - mm2px(1);
|
|
|
|
m_valid = true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
XsheetPdfPreviewPane::XsheetPdfPreviewPane(QWidget* parent)
|
|
: QWidget(parent), m_scaleFactor(1.0) {}
|
|
|
|
void XsheetPdfPreviewPane::paintEvent(QPaintEvent* event) {
|
|
QPainter painter(this);
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
|
QSize pmSize((double)m_pixmap.width() * m_scaleFactor,
|
|
(double)m_pixmap.height() * m_scaleFactor);
|
|
painter.drawPixmap(
|
|
0, 0,
|
|
m_pixmap.scaled(pmSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
|
}
|
|
|
|
void XsheetPdfPreviewPane::setPixmap(QPixmap pm) {
|
|
m_pixmap = pm;
|
|
resize(pm.size() * m_scaleFactor);
|
|
update();
|
|
}
|
|
|
|
void XsheetPdfPreviewPane::doZoom(double d_scale) {
|
|
m_scaleFactor += d_scale;
|
|
if (m_scaleFactor > 1.0)
|
|
m_scaleFactor = 1.0;
|
|
else if (m_scaleFactor < 0.1)
|
|
m_scaleFactor = 0.1;
|
|
|
|
resize(m_pixmap.size() * m_scaleFactor);
|
|
update();
|
|
}
|
|
|
|
void XsheetPdfPreviewPane::fitScaleTo(QSize size) {
|
|
double tmp_scaleFactor =
|
|
std::min((double)size.width() / (double)m_pixmap.width(),
|
|
(double)size.height() / (double)m_pixmap.height());
|
|
|
|
m_scaleFactor = tmp_scaleFactor;
|
|
if (m_scaleFactor > 1.0)
|
|
m_scaleFactor = 1.0;
|
|
else if (m_scaleFactor < 0.1)
|
|
m_scaleFactor = 0.1;
|
|
|
|
resize(m_pixmap.size() * m_scaleFactor);
|
|
update();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void XsheetPdfPreviewArea::mousePressEvent(QMouseEvent* e) {
|
|
m_mousePos = e->pos();
|
|
}
|
|
|
|
void XsheetPdfPreviewArea::mouseMoveEvent(QMouseEvent* e) {
|
|
QPoint d = m_mousePos - e->pos();
|
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + d.x());
|
|
verticalScrollBar()->setValue(verticalScrollBar()->value() + d.y());
|
|
m_mousePos = e->pos();
|
|
}
|
|
|
|
void XsheetPdfPreviewArea::contextMenuEvent(QContextMenuEvent* event) {
|
|
QMenu* menu = new QMenu(this);
|
|
QAction* fitAction = menu->addAction(tr("Fit To Window"));
|
|
connect(fitAction, SIGNAL(triggered()), this, SLOT(fitToWindow()));
|
|
menu->exec(event->globalPos());
|
|
}
|
|
|
|
void XsheetPdfPreviewArea::fitToWindow() {
|
|
dynamic_cast<XsheetPdfPreviewPane*>(widget())->fitScaleTo(rect().size());
|
|
}
|
|
|
|
void XsheetPdfPreviewArea::wheelEvent(QWheelEvent* event) {
|
|
int delta = 0;
|
|
switch (event->source()) {
|
|
case Qt::MouseEventNotSynthesized: {
|
|
delta = event->angleDelta().y();
|
|
}
|
|
case Qt::MouseEventSynthesizedBySystem: {
|
|
QPoint numPixels = event->pixelDelta();
|
|
QPoint numDegrees = event->angleDelta() / 8;
|
|
if (!numPixels.isNull()) {
|
|
delta = event->pixelDelta().y();
|
|
} else if (!numDegrees.isNull()) {
|
|
QPoint numSteps = numDegrees / 15;
|
|
delta = numSteps.y();
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: // Qt::MouseEventSynthesizedByQt,
|
|
// Qt::MouseEventSynthesizedByApplication
|
|
{
|
|
std::cout << "not supported event: Qt::MouseEventSynthesizedByQt, "
|
|
"Qt::MouseEventSynthesizedByApplication"
|
|
<< std::endl;
|
|
break;
|
|
}
|
|
|
|
} // end switch
|
|
|
|
if (delta == 0) {
|
|
event->accept();
|
|
return;
|
|
}
|
|
|
|
dynamic_cast<XsheetPdfPreviewPane*>(widget())->doZoom((delta > 0) ? 0.1
|
|
: -0.1);
|
|
|
|
event->accept();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
ExportXsheetPdfPopup::ExportXsheetPdfPopup()
|
|
: DVGui::Dialog(TApp::instance()->getMainWindow(), false, false,
|
|
"ExportXsheetPdf")
|
|
, m_currentTmpl(nullptr) {
|
|
setWindowTitle(tr("Export Xsheet PDF"));
|
|
|
|
m_previewPane = new XsheetPdfPreviewPane(this);
|
|
m_pathFld = new DVGui::FileField();
|
|
m_fileNameFld = new QLineEdit(this);
|
|
m_templateCombo = new QComboBox(this);
|
|
m_exportAreaCombo = new QComboBox(this);
|
|
m_continuousLineCombo = new QComboBox(this);
|
|
|
|
m_pageInfoLbl = new QLabel(this);
|
|
m_lineColorFld = new DVGui::ColorField(this, false, TPixel32(128, 128, 128));
|
|
m_templateFontCB = new QFontComboBox(this);
|
|
m_contentsFontCB = new QFontComboBox(this);
|
|
m_addDateTimeCB = new QCheckBox(tr("Print Export DateTime"), this);
|
|
m_addScenePathCB = new QCheckBox(tr("Print Scene Path"), this);
|
|
m_drawSoundCB = new QCheckBox(tr("Print Soundtrack"), this);
|
|
m_addSceneNameCB = new QCheckBox(tr("Print Scene Name"), this);
|
|
m_serialFrameNumberCB =
|
|
new QCheckBox(tr("Put Serial Frame Numbers Over Pages"), this);
|
|
m_levelNameOnBottomCB =
|
|
new QCheckBox(tr("Print Level Names On The Bottom"), this);
|
|
m_drawDialogueCB = new QCheckBox(tr("Print Dialogue"), this);
|
|
m_dialogueColCombo = new QComboBox();
|
|
m_sceneNameEdit = new QLineEdit(this);
|
|
m_memoEdit = new QTextEdit(this);
|
|
|
|
m_logoTxtRB = new QRadioButton(tr("Text"), this);
|
|
m_logoImgRB = new QRadioButton(tr("Image"), this);
|
|
m_logoTextEdit = new QLineEdit(this);
|
|
m_logoImgPathField = new DVGui::FileField(this);
|
|
|
|
m_previewArea = new XsheetPdfPreviewArea(this);
|
|
m_currentPageEdit = new QLineEdit(this);
|
|
m_totalPageCount = 1;
|
|
m_prev = new QPushButton(tr("< Prev"), this);
|
|
m_next = new QPushButton(tr("Next >"), this);
|
|
|
|
QPushButton* exportBtn = new QPushButton(tr("Export PDF"), this);
|
|
QPushButton* exportPngBtn = new QPushButton(tr("Export PNG"), this);
|
|
QPushButton* cancelBtn = new QPushButton(tr("Cancel"), this);
|
|
|
|
m_tick1IdCombo = new QComboBox(this);
|
|
m_tick2IdCombo = new QComboBox(this);
|
|
m_keyIdCombo = new QComboBox(this);
|
|
refreshCellMarkComboItems(m_tick1IdCombo);
|
|
refreshCellMarkComboItems(m_tick2IdCombo);
|
|
refreshCellMarkComboItems(m_keyIdCombo);
|
|
m_tick1MarkCombo = createTickMarkCombo(this);
|
|
m_tick2MarkCombo = createTickMarkCombo(this);
|
|
|
|
//------
|
|
QStringList pdfFileTypes = {"pdf"};
|
|
m_pathFld->setFilters(pdfFileTypes);
|
|
m_pathFld->setFileMode(QFileDialog::DirectoryOnly);
|
|
m_fileNameFld->setFixedWidth(100);
|
|
m_previewArea->setWidget(m_previewPane);
|
|
m_previewArea->setAlignment(Qt::AlignCenter);
|
|
m_previewArea->setBackgroundRole(QPalette::Dark);
|
|
m_previewArea->setStyleSheet("background-color:black;");
|
|
m_exportAreaCombo->addItem(tr("ACTIONS"), Area_Actions);
|
|
m_exportAreaCombo->addItem(tr("CELLS"), Area_Cells);
|
|
// m_exportAreaCombo->setCurrentIndex(1);
|
|
m_memoEdit->setAcceptRichText(false);
|
|
m_memoEdit->setStyleSheet(
|
|
"background:white;\ncolor:black;\nborder:1 solid black;");
|
|
m_memoEdit->setFixedHeight(150);
|
|
m_dialogueColCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
|
m_sceneNameEdit->setFixedWidth(100);
|
|
|
|
m_continuousLineCombo->addItem(tr("Always"), Line_Always);
|
|
m_continuousLineCombo->addItem(tr("More Than 3 Continuous Cells"),
|
|
Line_MoreThan3s);
|
|
m_continuousLineCombo->addItem(tr("None"), Line_None);
|
|
|
|
QStringList filters;
|
|
for (QByteArray& format : QImageReader::supportedImageFormats())
|
|
filters += format;
|
|
m_logoImgPathField->setFilters(filters);
|
|
m_logoImgPathField->setFileMode(QFileDialog::ExistingFile);
|
|
|
|
m_currentPageEdit->setValidator(new QIntValidator(1, m_totalPageCount, this));
|
|
m_currentPageEdit->setText("1");
|
|
m_currentPageEdit->setObjectName("LargeSizedText");
|
|
m_currentPageEdit->setFixedWidth(100);
|
|
m_prev->setDisabled(true);
|
|
m_next->setDisabled(true);
|
|
exportBtn->setObjectName("LargeSizedText");
|
|
|
|
QHBoxLayout* mainLay = new QHBoxLayout();
|
|
mainLay->setMargin(0);
|
|
mainLay->setSpacing(5);
|
|
{
|
|
QVBoxLayout* previewLay = new QVBoxLayout();
|
|
previewLay->setMargin(0);
|
|
previewLay->setSpacing(0);
|
|
{
|
|
previewLay->addWidget(m_previewArea, 1);
|
|
QHBoxLayout* prevBtnLay = new QHBoxLayout();
|
|
prevBtnLay->setMargin(15);
|
|
prevBtnLay->setSpacing(10);
|
|
{
|
|
prevBtnLay->addStretch(1);
|
|
prevBtnLay->addWidget(m_prev, 0);
|
|
prevBtnLay->addWidget(m_currentPageEdit, 0);
|
|
prevBtnLay->addWidget(m_next, 0);
|
|
prevBtnLay->addStretch(1);
|
|
}
|
|
previewLay->addLayout(prevBtnLay, 0);
|
|
}
|
|
mainLay->addLayout(previewLay, 1);
|
|
|
|
QVBoxLayout* rightLay = new QVBoxLayout();
|
|
rightLay->setMargin(0);
|
|
rightLay->setSpacing(10);
|
|
{
|
|
QScrollArea* scrollArea = new QScrollArea(this);
|
|
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
QWidget* scrollPanel = new QWidget(this);
|
|
QVBoxLayout* controlLay = new QVBoxLayout();
|
|
controlLay->setMargin(20);
|
|
controlLay->setSpacing(10);
|
|
{
|
|
QGroupBox* tmplGBox = new QGroupBox(tr("Template Settings"), this);
|
|
|
|
QGridLayout* tmplLay = new QGridLayout();
|
|
tmplLay->setMargin(10);
|
|
tmplLay->setHorizontalSpacing(5);
|
|
tmplLay->setVerticalSpacing(10);
|
|
{
|
|
tmplLay->addWidget(new QLabel(tr("Template:"), this), 0, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
tmplLay->addWidget(m_templateCombo, 0, 1, 1, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
tmplLay->addWidget(new QLabel(tr("Line color:"), this), 1, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
tmplLay->addWidget(m_lineColorFld, 1, 1, 1, 2);
|
|
|
|
tmplLay->addWidget(new QLabel(tr("Template font:"), this), 2, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
tmplLay->addWidget(m_templateFontCB, 2, 1, 1, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
tmplLay->addWidget(new QLabel(tr("Logo:"), this), 3, 0,
|
|
Qt::AlignRight | Qt::AlignTop);
|
|
tmplLay->addWidget(m_logoTxtRB, 3, 1);
|
|
tmplLay->addWidget(m_logoTextEdit, 3, 2);
|
|
tmplLay->addWidget(m_logoImgRB, 4, 1);
|
|
tmplLay->addWidget(m_logoImgPathField, 4, 2);
|
|
|
|
tmplLay->addWidget(m_serialFrameNumberCB, 5, 0, 1, 3);
|
|
}
|
|
tmplLay->setColumnStretch(2, 1);
|
|
tmplGBox->setLayout(tmplLay);
|
|
controlLay->addWidget(tmplGBox, 0);
|
|
|
|
QGroupBox* exportGBox = new QGroupBox(tr("Export Settings"), this);
|
|
|
|
QGridLayout* exportLay = new QGridLayout();
|
|
exportLay->setMargin(10);
|
|
exportLay->setHorizontalSpacing(5);
|
|
exportLay->setVerticalSpacing(10);
|
|
{
|
|
exportLay->addWidget(new QLabel(tr("Output area:"), this), 0, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
exportLay->addWidget(m_exportAreaCombo, 0, 1);
|
|
exportLay->addWidget(m_pageInfoLbl, 0, 2);
|
|
|
|
exportLay->addWidget(new QLabel(tr("Output font:"), this), 1, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
exportLay->addWidget(m_contentsFontCB, 1, 1, 1, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
exportLay->addWidget(new QLabel(tr("Continuous line:"), this), 2, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
exportLay->addWidget(m_continuousLineCombo, 2, 1, 1, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
QGridLayout* checksLay = new QGridLayout();
|
|
checksLay->setMargin(0);
|
|
checksLay->setHorizontalSpacing(10);
|
|
checksLay->setVerticalSpacing(10);
|
|
{
|
|
checksLay->addWidget(m_addDateTimeCB, 0, 0);
|
|
checksLay->addWidget(m_addScenePathCB, 0, 1, 1, 2);
|
|
checksLay->addWidget(m_drawSoundCB, 1, 0);
|
|
checksLay->addWidget(m_addSceneNameCB, 1, 1);
|
|
checksLay->addWidget(m_sceneNameEdit, 1, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
checksLay->addWidget(m_levelNameOnBottomCB, 2, 0);
|
|
checksLay->addWidget(m_drawDialogueCB, 2, 1);
|
|
checksLay->addWidget(m_dialogueColCombo, 2, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
}
|
|
checksLay->setColumnStretch(0, 2);
|
|
checksLay->setColumnStretch(1, 1);
|
|
checksLay->setColumnStretch(2, 1);
|
|
exportLay->addLayout(checksLay, 3, 0, 1, 3);
|
|
|
|
exportLay->addWidget(new QLabel(tr("Inbetween mark 1:"), this), 4, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
exportLay->addWidget(m_tick1IdCombo, 4, 1);
|
|
exportLay->addWidget(m_tick1MarkCombo, 4, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
exportLay->addWidget(new QLabel(tr("Inbetween mark 2:"), this), 5, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
exportLay->addWidget(m_tick2IdCombo, 5, 1);
|
|
exportLay->addWidget(m_tick2MarkCombo, 5, 2,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
exportLay->addWidget(new QLabel(tr("Keyframe mark:"), this), 6, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
exportLay->addWidget(m_keyIdCombo, 6, 1);
|
|
|
|
exportLay->addWidget(new QLabel(tr("Memo:"), this), 7, 0,
|
|
Qt::AlignRight | Qt::AlignTop);
|
|
exportLay->addWidget(m_memoEdit, 7, 1, 1, 2);
|
|
}
|
|
exportLay->setColumnStretch(2, 1);
|
|
exportGBox->setLayout(exportLay);
|
|
controlLay->addWidget(exportGBox, 0);
|
|
|
|
controlLay->addStretch(1);
|
|
}
|
|
scrollPanel->setLayout(controlLay);
|
|
scrollArea->setWidget(scrollPanel);
|
|
rightLay->addWidget(scrollArea, 1);
|
|
|
|
QGridLayout* saveLay = new QGridLayout();
|
|
saveLay->setMargin(15);
|
|
saveLay->setHorizontalSpacing(5);
|
|
saveLay->setVerticalSpacing(10);
|
|
{
|
|
saveLay->addWidget(new QLabel(tr("Save in:"), this), 0, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
saveLay->addWidget(m_pathFld, 0, 1);
|
|
|
|
saveLay->addWidget(new QLabel(tr("Name:"), this), 1, 0,
|
|
Qt::AlignRight | Qt::AlignVCenter);
|
|
saveLay->addWidget(m_fileNameFld, 1, 1,
|
|
Qt::AlignLeft | Qt::AlignVCenter);
|
|
}
|
|
rightLay->addLayout(saveLay, 0);
|
|
|
|
QHBoxLayout* btnLay = new QHBoxLayout();
|
|
btnLay->setMargin(10);
|
|
btnLay->setSpacing(10);
|
|
{
|
|
btnLay->addStretch(1);
|
|
btnLay->addWidget(exportBtn, 0);
|
|
btnLay->addWidget(exportPngBtn, 0);
|
|
btnLay->addWidget(cancelBtn, 0);
|
|
}
|
|
rightLay->addLayout(btnLay, 0);
|
|
}
|
|
mainLay->addLayout(rightLay, 0);
|
|
}
|
|
m_topLayout->addLayout(mainLay, 1);
|
|
|
|
loadPresetItems();
|
|
loadSettings();
|
|
|
|
connect(exportBtn, SIGNAL(clicked()), this, SLOT(onExport()));
|
|
connect(exportPngBtn, SIGNAL(clicked()), this, SLOT(onExportPNG()));
|
|
connect(cancelBtn, SIGNAL(clicked()), this, SLOT(close()));
|
|
|
|
connect(m_templateCombo, SIGNAL(activated(int)), this, SLOT(initTemplate()));
|
|
|
|
connect(m_exportAreaCombo, SIGNAL(activated(int)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_continuousLineCombo, SIGNAL(activated(int)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_lineColorFld, SIGNAL(colorChanged(const TPixel32&, bool)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_templateFontCB, SIGNAL(currentFontChanged(const QFont&)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_contentsFontCB, SIGNAL(currentFontChanged(const QFont&)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_addDateTimeCB, SIGNAL(clicked(bool)), this, SLOT(updatePreview()));
|
|
connect(m_addScenePathCB, SIGNAL(clicked(bool)), this, SLOT(updatePreview()));
|
|
connect(m_drawSoundCB, SIGNAL(clicked(bool)), this, SLOT(updatePreview()));
|
|
connect(m_serialFrameNumberCB, SIGNAL(clicked(bool)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_levelNameOnBottomCB, SIGNAL(clicked(bool)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_drawDialogueCB, SIGNAL(clicked(bool)), this, SLOT(updatePreview()));
|
|
connect(m_drawDialogueCB, SIGNAL(clicked(bool)), m_dialogueColCombo,
|
|
SLOT(setEnabled(bool)));
|
|
connect(m_dialogueColCombo, SIGNAL(activated(int)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_addSceneNameCB, SIGNAL(clicked(bool)), this, SLOT(updatePreview()));
|
|
connect(m_addSceneNameCB, SIGNAL(clicked(bool)), m_sceneNameEdit,
|
|
SLOT(setEnabled(bool)));
|
|
connect(m_sceneNameEdit, SIGNAL(editingFinished()), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_memoEdit, SIGNAL(textChanged()), this, SLOT(updatePreview()));
|
|
|
|
connect(m_logoTxtRB, SIGNAL(toggled(bool)), this, SLOT(onLogoModeToggled()));
|
|
connect(m_logoImgRB, SIGNAL(toggled(bool)), this, SLOT(onLogoModeToggled()));
|
|
connect(m_logoTextEdit, SIGNAL(editingFinished()), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_logoImgPathField, SIGNAL(pathChanged()), this,
|
|
SLOT(onLogoImgPathChanged()));
|
|
connect(m_currentPageEdit, SIGNAL(editingFinished()), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_prev, SIGNAL(clicked(bool)), this, SLOT(onPrev()));
|
|
connect(m_next, SIGNAL(clicked(bool)), this, SLOT(onNext()));
|
|
|
|
connect(m_tick1IdCombo, SIGNAL(activated(int)), this,
|
|
SLOT(onTickIdComboActivated()));
|
|
connect(m_tick2IdCombo, SIGNAL(activated(int)), this,
|
|
SLOT(onTickIdComboActivated()));
|
|
connect(m_keyIdCombo, SIGNAL(activated(int)), this, SLOT(updatePreview()));
|
|
connect(m_tick1MarkCombo, SIGNAL(activated(int)), this,
|
|
SLOT(updatePreview()));
|
|
connect(m_tick2MarkCombo, SIGNAL(activated(int)), this,
|
|
SLOT(updatePreview()));
|
|
|
|
// The following lines are "translation word book" listing the words which may
|
|
// appear in the template
|
|
|
|
// info item labels
|
|
QObject::tr("EPISODE", "XSheetPDF");
|
|
QObject::tr("SEQ.", "XSheetPDF");
|
|
QObject::tr("SCENE", "XSheetPDF");
|
|
QObject::tr("TIME", "XSheetPDF");
|
|
QObject::tr("NAME", "XSheetPDF");
|
|
QObject::tr("SHEET", "XSheetPDF");
|
|
QObject::tr("TITLE", "XSheetPDF");
|
|
QObject::tr("CAMERAMAN", "XSheetPDF");
|
|
// template name
|
|
tr("B4 size, 3 seconds sheet");
|
|
tr("B4 size, 6 seconds sheet");
|
|
tr("A3 size, 3 seconds sheet");
|
|
tr("A3 size, 6 seconds sheet");
|
|
}
|
|
|
|
ExportXsheetPdfPopup::~ExportXsheetPdfPopup() {
|
|
if (m_currentTmpl) delete m_currentTmpl;
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::loadPresetItems() {
|
|
// check in the preset folder
|
|
TFilePath presetFolderPath =
|
|
ToonzFolder::getLibraryFolder() + "xsheetpdfpresets";
|
|
QDir presetFolder(presetFolderPath.getQString());
|
|
QStringList filters;
|
|
filters << "*.ini";
|
|
presetFolder.setNameFilters(filters);
|
|
presetFolder.setFilter(QDir::Files);
|
|
TFilePathSet pathSet;
|
|
try {
|
|
TSystem::readDirectory(pathSet, presetFolder, false);
|
|
} catch (...) {
|
|
return;
|
|
}
|
|
|
|
for (auto fp : pathSet) {
|
|
QSettings s(fp.getQString(), QSettings::IniFormat);
|
|
if (!(s.childGroups().contains("XSheetPDFTemplate"))) continue;
|
|
s.beginGroup("XSheetPDFTemplate");
|
|
QString labelStr =
|
|
s.value("Label", QString::fromStdString(fp.getName())).toString();
|
|
m_templateCombo->addItem(tr(labelStr.toLocal8Bit()), fp.getQString());
|
|
}
|
|
|
|
if (m_templateCombo->count() == 0)
|
|
m_templateCombo->addItem(tr("B4 size, 6 seconds sheet"), "");
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::initialize() {
|
|
ToonzScene* scene = TApp::instance()->getCurrentScene()->getScene();
|
|
|
|
// default save destination
|
|
QString initialPath, initialFileName;
|
|
if (scene->isUntitled()) {
|
|
initialPath = "+scenes";
|
|
initialFileName = "untitled";
|
|
} else {
|
|
initialPath = scene->getScenePath().getParentDir().getQString();
|
|
initialFileName = QString::fromStdWString(scene->getSceneName());
|
|
}
|
|
m_pathFld->setPath(initialPath);
|
|
m_fileNameFld->setText(initialFileName);
|
|
|
|
// gather columns to be exported
|
|
// TODO: consider if the top xsheet should be choosable when the current
|
|
// xsheet is sub xsheet
|
|
TXsheet* xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
|
|
// if the current xsheet is top xsheet in the scene and the output
|
|
// frame range is specified, set the "to" frame value as duration
|
|
|
|
TOutputProperties* oprop = scene->getProperties()->getOutputProperties();
|
|
int from, to, step;
|
|
if (scene->getTopXsheet() == xsheet && oprop->getRange(from, to, step))
|
|
m_duration = to + 1;
|
|
else
|
|
m_duration = xsheet->getFrameCount();
|
|
|
|
m_columns.clear();
|
|
m_soundColumns.clear();
|
|
m_noteColumns.clear();
|
|
for (int col = 0; col < xsheet->getColumnCount(); col++) {
|
|
if (xsheet->isColumnEmpty(col)) continue;
|
|
|
|
TXshSoundColumn* soundColumn = xsheet->getColumn(col)->getSoundColumn();
|
|
if (soundColumn) {
|
|
if (soundColumn->isPreviewVisible()) m_soundColumns.append(soundColumn);
|
|
continue;
|
|
}
|
|
|
|
TXshSoundTextColumn* noteColumn =
|
|
xsheet->getColumn(col)->getSoundTextColumn();
|
|
if (noteColumn) {
|
|
m_noteColumns.insert(col, noteColumn);
|
|
continue;
|
|
}
|
|
|
|
TXshLevelColumn* column = xsheet->getColumn(col)->getLevelColumn();
|
|
if (!column) continue;
|
|
// do not export if the "eye" (render) button is off
|
|
if (!column->isPreviewVisible()) continue;
|
|
// skip column containing single-framed level
|
|
TFrameId firstFid = column->getCell(column->getFirstRow()).getFrameId();
|
|
if (firstFid.getNumber() == TFrameId::EMPTY_FRAME ||
|
|
firstFid.getNumber() == TFrameId::NO_FRAME)
|
|
continue;
|
|
|
|
TStageObject* columnObject =
|
|
xsheet->getStageObject(TStageObjectId::ColumnId(col));
|
|
QString colName = (columnObject->hasSpecifiedName())
|
|
? QString::fromStdString(columnObject->getName())
|
|
: QString();
|
|
m_columns.append(QPair<TXshLevelColumn*, QString>(column, colName));
|
|
}
|
|
|
|
m_addScenePathCB->setDisabled(scene->isUntitled());
|
|
m_drawSoundCB->setDisabled(m_soundColumns.isEmpty());
|
|
m_sceneNameEdit->setText(
|
|
(scene->isUntitled()) ? ""
|
|
: QString::fromStdWString(scene->getSceneName()));
|
|
m_drawDialogueCB->setDisabled(m_noteColumns.isEmpty());
|
|
m_dialogueColCombo->setEnabled(!m_noteColumns.isEmpty() &&
|
|
m_drawDialogueCB->isChecked());
|
|
m_dialogueColCombo->clear();
|
|
for (auto colId : m_noteColumns.keys())
|
|
m_dialogueColCombo->addItem(tr("Col%1").arg(colId + 1), colId);
|
|
|
|
initTemplate();
|
|
|
|
m_previewPane->fitScaleTo(m_previewArea->size());
|
|
|
|
refreshCellMarkComboItems(m_tick1IdCombo);
|
|
refreshCellMarkComboItems(m_tick2IdCombo);
|
|
refreshCellMarkComboItems(m_keyIdCombo);
|
|
}
|
|
|
|
// register settings to the user env file on close
|
|
void ExportXsheetPdfPopup::saveSettings() {
|
|
XShPdfExportTemplate =
|
|
m_templateCombo->currentData().toString().toStdString();
|
|
XShPdfExportOutputArea = m_exportAreaCombo->currentData().toInt();
|
|
TPixel32 col = m_lineColorFld->getColor();
|
|
XShPdfExportLineColor = QColor(col.r, col.g, col.b).name().toStdString();
|
|
XShPdfExportPrintDateTime = (m_addDateTimeCB->isChecked()) ? 1 : 0;
|
|
XShPdfExportPrintScenePath = (m_addScenePathCB->isChecked()) ? 1 : 0;
|
|
XShPdfExportPrintSoundtrack = (m_drawSoundCB->isChecked()) ? 1 : 0;
|
|
XShPdfExportPrintSceneName = (m_addSceneNameCB->isChecked()) ? 1 : 0;
|
|
XShPdfExportSerialFrameNumber = (m_serialFrameNumberCB->isChecked()) ? 1 : 0;
|
|
XShPdfExportLevelNameOnBottom = (m_levelNameOnBottomCB->isChecked()) ? 1 : 0;
|
|
XShPdfExportPrintDialogue = (m_drawDialogueCB->isChecked()) ? 1 : 0;
|
|
XShPdfExportTemplateFont =
|
|
m_templateFontCB->currentFont().family().toStdString();
|
|
XShPdfExportOutputFont =
|
|
m_contentsFontCB->currentFont().family().toStdString();
|
|
XShPdfExportLogoPreference = (m_logoTxtRB->isChecked()) ? 0 : 1;
|
|
XShPdfExportLogoText = m_logoTextEdit->text().toStdString();
|
|
XShPdfExportImgPath = m_logoImgPathField->getPath().toStdString();
|
|
|
|
ContinuousLineMode clMode =
|
|
(ContinuousLineMode)(m_continuousLineCombo->currentData().toInt());
|
|
XShPdfExportContinuousLineThres = (clMode == Line_Always) ? 0
|
|
: (clMode == Line_None) ? -1
|
|
: 3;
|
|
|
|
XShPdfExportTick1Id = m_tick1IdCombo->currentData().toInt();
|
|
XShPdfExportTick2Id = m_tick2IdCombo->currentData().toInt();
|
|
XShPdfExportKeyId = m_keyIdCombo->currentData().toInt();
|
|
XShPdfExportTick1Type = m_tick1MarkCombo->currentData().toInt();
|
|
XShPdfExportTick2Type = m_tick2MarkCombo->currentData().toInt();
|
|
}
|
|
|
|
// load settings from the user env file on ctor
|
|
void ExportXsheetPdfPopup::loadSettings() {
|
|
int tmplId =
|
|
m_templateCombo->findData(QString::fromStdString(XShPdfExportTemplate));
|
|
m_templateCombo->setCurrentIndex((tmplId >= 0) ? tmplId : 0);
|
|
int areaId = XShPdfExportOutputArea;
|
|
m_exportAreaCombo->setCurrentIndex(m_exportAreaCombo->findData(areaId));
|
|
QColor lineColor(QString::fromStdString(XShPdfExportLineColor));
|
|
m_lineColorFld->setColor(
|
|
TPixel32(lineColor.red(), lineColor.green(), lineColor.blue()));
|
|
m_addDateTimeCB->setChecked(XShPdfExportPrintDateTime != 0);
|
|
m_addScenePathCB->setChecked(XShPdfExportPrintScenePath != 0);
|
|
m_drawSoundCB->setChecked(XShPdfExportPrintSoundtrack != 0);
|
|
m_addSceneNameCB->setChecked(XShPdfExportPrintSceneName != 0);
|
|
m_serialFrameNumberCB->setChecked(XShPdfExportSerialFrameNumber != 0);
|
|
m_levelNameOnBottomCB->setChecked(XShPdfExportLevelNameOnBottom != 0);
|
|
m_drawDialogueCB->setChecked(XShPdfExportPrintDialogue != 0);
|
|
|
|
QString tmplFont = QString::fromStdString(XShPdfExportTemplateFont);
|
|
if (!tmplFont.isEmpty()) m_templateFontCB->setCurrentFont(QFont(tmplFont));
|
|
QString outFont = QString::fromStdString(XShPdfExportOutputFont);
|
|
if (!outFont.isEmpty()) m_contentsFontCB->setCurrentFont(QFont(outFont));
|
|
|
|
m_logoTxtRB->setChecked(XShPdfExportLogoPreference == 0);
|
|
m_logoImgRB->setChecked(XShPdfExportLogoPreference == 1);
|
|
m_logoTextEdit->setText(QString::fromStdString(XShPdfExportLogoText));
|
|
m_logoImgPathField->setPath(QString::fromStdString(XShPdfExportImgPath));
|
|
|
|
ContinuousLineMode clMode =
|
|
(XShPdfExportContinuousLineThres == 0) ? Line_Always
|
|
: (XShPdfExportContinuousLineThres == -1) ? Line_None
|
|
: Line_MoreThan3s;
|
|
m_continuousLineCombo->setCurrentIndex(
|
|
m_continuousLineCombo->findData(clMode));
|
|
|
|
m_logoTextEdit->setEnabled(m_logoTxtRB->isChecked());
|
|
m_logoImgPathField->setEnabled(m_logoImgRB->isChecked());
|
|
m_sceneNameEdit->setEnabled(m_addSceneNameCB->isChecked());
|
|
m_dialogueColCombo->setEnabled(m_drawDialogueCB->isChecked() &&
|
|
m_drawDialogueCB->isEnabled());
|
|
|
|
int id = XShPdfExportTick1Id;
|
|
m_tick1IdCombo->setCurrentIndex(m_tick1IdCombo->findData(id));
|
|
m_tick1MarkCombo->setEnabled(id != -1);
|
|
id = XShPdfExportTick2Id;
|
|
m_tick2IdCombo->setCurrentIndex(m_tick2IdCombo->findData(id));
|
|
m_tick2MarkCombo->setEnabled(id != -1);
|
|
id = XShPdfExportKeyId;
|
|
m_keyIdCombo->setCurrentIndex(m_keyIdCombo->findData(id));
|
|
int type = XShPdfExportTick1Type;
|
|
m_tick1MarkCombo->setCurrentIndex(m_tick1MarkCombo->findData(type));
|
|
type = XShPdfExportTick2Type;
|
|
m_tick2MarkCombo->setCurrentIndex(m_tick2MarkCombo->findData(type));
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::initTemplate() {
|
|
if (m_currentTmpl) {
|
|
delete m_currentTmpl;
|
|
m_currentTmpl = nullptr;
|
|
}
|
|
|
|
QString tmplPath = m_templateCombo->currentData().toString();
|
|
if (tmplPath.isEmpty()) {
|
|
m_currentTmpl = new XSheetPDFTemplate_B4_6sec(m_columns, m_duration);
|
|
} else {
|
|
XSheetPDFTemplate_Custom* ret =
|
|
new XSheetPDFTemplate_Custom(tmplPath, m_columns, m_duration);
|
|
|
|
if (ret->isValid())
|
|
m_currentTmpl = ret;
|
|
else {
|
|
DVGui::MsgBoxInPopup(
|
|
DVGui::CRITICAL,
|
|
tr("The preset file %1 is not valid.").arg(tmplPath));
|
|
delete ret;
|
|
m_currentTmpl = new XSheetPDFTemplate_B4_6sec(m_columns, m_duration);
|
|
}
|
|
}
|
|
|
|
if (!m_soundColumns.isEmpty()) m_currentTmpl->setSoundColumns(m_soundColumns);
|
|
|
|
updatePreview();
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::setInfo() {
|
|
XSheetPDFFormatInfo info;
|
|
|
|
TPixel32 col = m_lineColorFld->getColor();
|
|
info.lineColor = QColor(col.r, col.g, col.b);
|
|
info.dateTimeText =
|
|
(m_addDateTimeCB->isChecked())
|
|
? QDateTime::currentDateTime().toString(Qt::DefaultLocaleLongDate)
|
|
: "";
|
|
ToonzScene* scene = TApp::instance()->getCurrentScene()->getScene();
|
|
info.scenePathText =
|
|
(m_addScenePathCB->isEnabled() && m_addScenePathCB->isChecked())
|
|
? scene->getScenePath().getQString()
|
|
: "";
|
|
info.sceneNameText =
|
|
(m_addSceneNameCB->isChecked()) ? m_sceneNameEdit->text() : "";
|
|
|
|
info.exportArea = (ExportArea)(m_exportAreaCombo->currentData().toInt());
|
|
info.continuousLineMode =
|
|
(ContinuousLineMode)(m_continuousLineCombo->currentData().toInt());
|
|
info.templateFontFamily = m_templateFontCB->currentFont().family();
|
|
info.contentsFontFamily = m_contentsFontCB->currentFont().family();
|
|
info.memoText = m_memoEdit->toPlainText();
|
|
|
|
info.logoText = (m_logoTxtRB->isChecked()) ? m_logoTextEdit->text() : "";
|
|
info.drawSound = m_drawSoundCB->isEnabled() && m_drawSoundCB->isChecked();
|
|
info.serialFrameNumber = m_serialFrameNumberCB->isChecked();
|
|
info.drawLevelNameOnBottom = m_levelNameOnBottomCB->isChecked();
|
|
|
|
info.tick1MarkId = m_tick1IdCombo->currentData().toInt();
|
|
info.tick2MarkId = m_tick2IdCombo->currentData().toInt();
|
|
info.keyMarkId = m_keyIdCombo->currentData().toInt();
|
|
info.tick1MarkType = (TickMarkType)(m_tick1MarkCombo->currentData().toInt());
|
|
info.tick2MarkType = (TickMarkType)(m_tick2MarkCombo->currentData().toInt());
|
|
|
|
m_currentTmpl->setInfo(info);
|
|
|
|
if (m_drawDialogueCB->isChecked() && m_drawDialogueCB->isEnabled())
|
|
m_currentTmpl->setNoteColumn(m_noteColumns.value(
|
|
m_dialogueColCombo->currentData().toInt(), nullptr));
|
|
else
|
|
m_currentTmpl->setNoteColumn(nullptr);
|
|
|
|
if (!m_logoImgRB->isChecked()) return;
|
|
|
|
// prepare logo image
|
|
QSize logoPixSize = m_currentTmpl->logoPixelSize();
|
|
if (logoPixSize.isEmpty()) return;
|
|
|
|
TFilePath decodedPath =
|
|
scene->decodeFilePath(TFilePath(m_logoImgPathField->getPath()));
|
|
QImage img(decodedPath.getQString());
|
|
img = img.scaled(logoPixSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
QImage alphaImg = img;
|
|
alphaImg.invertPixels();
|
|
img.setAlphaChannel(alphaImg);
|
|
QImage logoImg(img.size(), QImage::Format_ARGB32_Premultiplied);
|
|
logoImg.fill(info.lineColor);
|
|
QPainter p(&logoImg);
|
|
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
|
p.drawImage(QPoint(0, 0), img);
|
|
p.end();
|
|
|
|
m_currentTmpl->setLogoPixmap(QPixmap::fromImage(logoImg));
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::updatePreview() {
|
|
setInfo();
|
|
|
|
int framePageCount = m_currentTmpl->framePageCount();
|
|
int parallelPageCount = m_currentTmpl->parallelPageCount();
|
|
int totalPage = framePageCount * parallelPageCount;
|
|
|
|
int currentPage = m_currentPageEdit->text().toInt();
|
|
// if the page count is changed
|
|
if (m_totalPageCount != totalPage) {
|
|
m_currentPageEdit->setValidator(new QIntValidator(1, totalPage, this));
|
|
if (m_totalPageCount > totalPage) {
|
|
m_currentPageEdit->setText(QString::number(totalPage));
|
|
currentPage = totalPage;
|
|
}
|
|
m_totalPageCount = totalPage;
|
|
|
|
m_prev->setDisabled(currentPage == 1);
|
|
m_next->setDisabled(currentPage == totalPage);
|
|
}
|
|
m_serialFrameNumberCB->setDisabled(framePageCount == 1);
|
|
m_levelNameOnBottomCB->setEnabled(m_duration > 36);
|
|
|
|
int fPage = (currentPage - 1) / parallelPageCount;
|
|
int pPage = (currentPage - 1) % parallelPageCount;
|
|
|
|
QPixmap pm = m_currentTmpl->initializePreview();
|
|
QPainter painter(&pm);
|
|
m_currentTmpl->drawXsheetTemplate(painter, fPage, true);
|
|
m_currentTmpl->drawXsheetContents(painter, fPage, pPage, true);
|
|
m_previewPane->setPixmap(pm);
|
|
|
|
QColor infoColor;
|
|
if (parallelPageCount == 1) {
|
|
m_pageInfoLbl->setText(tr("%n page(s)", "", framePageCount));
|
|
infoColor = QColor(Qt::green);
|
|
} else {
|
|
m_pageInfoLbl->setText(
|
|
tr("%1 x %2 pages").arg(framePageCount).arg(parallelPageCount));
|
|
infoColor = QColor(Qt::yellow);
|
|
}
|
|
m_pageInfoLbl->setStyleSheet(QString("QLabel{color: %1;}\
|
|
QLabel QWidget{ color: black;}")
|
|
.arg(infoColor.name()));
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onExport() {
|
|
ToonzScene* scene = TApp::instance()->getCurrentScene()->getScene();
|
|
|
|
if (m_fileNameFld->text().isEmpty()) {
|
|
DVGui::MsgBoxInPopup(DVGui::WARNING, tr("Please specify the file name."));
|
|
return;
|
|
}
|
|
|
|
TFilePath fp(m_pathFld->getPath());
|
|
fp += m_fileNameFld->text().toStdString() + ".pdf";
|
|
fp = scene->decodeFilePath(fp);
|
|
|
|
if (TSystem::doesExistFileOrLevel(fp)) {
|
|
QString question =
|
|
tr("The file %1 already exists.\nDo you want to overwrite it?")
|
|
.arg(fp.getQString());
|
|
int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
|
|
QObject::tr("Cancel"));
|
|
if (ret == 0 || ret == 2) {
|
|
return;
|
|
}
|
|
}
|
|
if (!TFileStatus(fp.getParentDir()).doesExist()) {
|
|
QString question =
|
|
tr("A folder %1 does not exist.\nDo you want to create it?")
|
|
.arg(fp.getParentDir().getQString());
|
|
int ret = DVGui::MsgBox(question, QObject::tr("Create folder"),
|
|
QObject::tr("Cancel"));
|
|
if (ret == 0 || ret == 2) {
|
|
return;
|
|
}
|
|
|
|
if (!TSystem::touchParentDir(fp)) {
|
|
DVGui::MsgBoxInPopup(DVGui::CRITICAL,
|
|
tr("Failed to create folder %1.")
|
|
.arg(fp.getParentDir().getQString()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
QFile pdfFile(fp.getQString());
|
|
|
|
pdfFile.open(QIODevice::WriteOnly);
|
|
QPdfWriter writer(&pdfFile);
|
|
|
|
initTemplate();
|
|
setInfo();
|
|
|
|
m_currentTmpl->initializePage(writer);
|
|
QPainter painter(&writer);
|
|
|
|
int framePageCount = m_currentTmpl->framePageCount();
|
|
int parallelPageCount = m_currentTmpl->parallelPageCount();
|
|
for (int framePage = 0; framePage < framePageCount; framePage++) {
|
|
for (int parallelPage = 0; parallelPage < parallelPageCount;
|
|
parallelPage++) {
|
|
m_currentTmpl->drawXsheetTemplate(painter, framePage);
|
|
m_currentTmpl->drawXsheetContents(painter, framePage, parallelPage);
|
|
if (framePage != framePageCount - 1 ||
|
|
parallelPage != parallelPageCount - 1)
|
|
writer.newPage();
|
|
}
|
|
}
|
|
painter.end();
|
|
|
|
pdfFile.close();
|
|
|
|
onExportFinished(fp);
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onExportPNG() {
|
|
ToonzScene* scene = TApp::instance()->getCurrentScene()->getScene();
|
|
|
|
if (m_fileNameFld->text().isEmpty()) {
|
|
DVGui::MsgBoxInPopup(DVGui::WARNING, tr("Please specify the file name."));
|
|
return;
|
|
}
|
|
|
|
TFilePath fp(m_pathFld->getPath());
|
|
fp += m_fileNameFld->text().toStdString() + "..png";
|
|
fp = scene->decodeFilePath(fp);
|
|
|
|
if (TSystem::doesExistFileOrLevel(fp)) {
|
|
QString question =
|
|
tr("The file %1 already exists.\nDo you want to overwrite it?")
|
|
.arg(fp.getQString());
|
|
int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
|
|
QObject::tr("Cancel"));
|
|
if (ret == 0 || ret == 2) {
|
|
return;
|
|
}
|
|
}
|
|
if (!TFileStatus(fp.getParentDir()).doesExist()) {
|
|
QString question =
|
|
tr("A folder %1 does not exist.\nDo you want to create it?")
|
|
.arg(fp.getParentDir().getQString());
|
|
int ret = DVGui::MsgBox(question, QObject::tr("Create folder"),
|
|
QObject::tr("Cancel"));
|
|
if (ret == 0 || ret == 2) {
|
|
return;
|
|
}
|
|
|
|
if (!TSystem::touchParentDir(fp)) {
|
|
DVGui::MsgBoxInPopup(DVGui::CRITICAL,
|
|
tr("Failed to create folder %1.")
|
|
.arg(fp.getParentDir().getQString()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
initTemplate();
|
|
setInfo();
|
|
QPixmap tmplPm = m_currentTmpl->initializePreview();
|
|
|
|
int framePageCount = m_currentTmpl->framePageCount();
|
|
int parallelPageCount = m_currentTmpl->parallelPageCount();
|
|
for (int framePage = 0; framePage < framePageCount; framePage++) {
|
|
for (int parallelPage = 0; parallelPage < parallelPageCount;
|
|
parallelPage++) {
|
|
QPixmap pm(tmplPm);
|
|
QPainter painter(&pm);
|
|
m_currentTmpl->drawXsheetTemplate(painter, framePage, true);
|
|
m_currentTmpl->drawXsheetContents(painter, framePage, parallelPage, true);
|
|
painter.end();
|
|
|
|
if (parallelPageCount == 1) {
|
|
pm.save(fp.withFrame(framePage + 1).getQString());
|
|
} else {
|
|
pm.save(fp.withFrame(framePage + 1, 'a' + parallelPage).getQString());
|
|
}
|
|
}
|
|
}
|
|
|
|
onExportFinished(fp);
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onExportFinished(const TFilePath& fp) {
|
|
close();
|
|
QString str = QObject::tr("The file %1 has been exported successfully.")
|
|
.arg(QString::fromStdString(fp.getLevelName()));
|
|
|
|
std::vector<QString> buttons = {QObject::tr("OK"),
|
|
QObject::tr("Open containing folder")};
|
|
int ret = DVGui::MsgBox(DVGui::INFORMATION, str, buttons);
|
|
|
|
if (ret == 2) {
|
|
TFilePath folderPath = fp.getParentDir();
|
|
if (TSystem::isUNC(folderPath))
|
|
QDesktopServices::openUrl(QUrl(folderPath.getQString()));
|
|
else
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath.getQString()));
|
|
}
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onLogoModeToggled() {
|
|
m_logoTextEdit->setEnabled(m_logoTxtRB->isChecked());
|
|
m_logoImgPathField->setEnabled(m_logoImgRB->isChecked());
|
|
updatePreview();
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onLogoImgPathChanged() {
|
|
TFilePath fp(m_logoImgPathField->getPath());
|
|
if (fp.isLevelName()) {
|
|
ToonzScene* scene = TApp::instance()->getCurrentScene()->getScene();
|
|
TLevelReaderP lr(scene->decodeFilePath(fp));
|
|
TLevelP level;
|
|
if (lr) level = lr->loadInfo();
|
|
if (level.getPointer() && level->getTable()->size() > 0) {
|
|
TFrameId firstFrame = level->begin()->first;
|
|
fp = fp.withFrame(firstFrame);
|
|
m_logoImgPathField->setPath(fp.getQString());
|
|
}
|
|
}
|
|
updatePreview();
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onPrev() {
|
|
int current = m_currentPageEdit->text().toInt();
|
|
assert(current > 1);
|
|
current -= 1;
|
|
m_currentPageEdit->setText(QString::number(current));
|
|
|
|
m_prev->setDisabled(current == 1);
|
|
m_next->setDisabled(current == m_totalPageCount);
|
|
updatePreview();
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onNext() {
|
|
int current = m_currentPageEdit->text().toInt();
|
|
assert(current < m_totalPageCount);
|
|
current += 1;
|
|
m_currentPageEdit->setText(QString::number(current));
|
|
|
|
m_prev->setDisabled(current == 1);
|
|
m_next->setDisabled(current == m_totalPageCount);
|
|
updatePreview();
|
|
}
|
|
|
|
void ExportXsheetPdfPopup::onTickIdComboActivated() {
|
|
QComboBox* combo = qobject_cast<QComboBox*>(sender());
|
|
if (combo == m_tick1IdCombo)
|
|
m_tick1MarkCombo->setEnabled(m_tick1IdCombo->currentData().toInt() != -1);
|
|
else if (combo == m_tick2IdCombo)
|
|
m_tick2MarkCombo->setEnabled(m_tick2IdCombo->currentData().toInt() != -1);
|
|
updatePreview();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
OpenPopupCommandHandler<ExportXsheetPdfPopup> openExportXsheetPdfPopup(
|
|
MI_ExportXsheetPDF); |