Merge pull request #848 from manongjohn/ot_patches_20211222

OpenToonz patches thru 12/22
This commit is contained in:
manongjohn 2021-12-30 21:51:57 -05:00 committed by GitHub
commit 119de0256f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
97 changed files with 4021 additions and 1119 deletions

View file

@ -73,7 +73,7 @@ inline QString blanks(const QString &str, int count = 15) {
//--------------------------------------------------------------------
inline QString getStr(const TFrameId &id) {
if (id.getLetter() != 0)
if (!id.getLetter().isEmpty())
return QString::number(id.getNumber()) + id.getLetter();
else
return QString::number(id.getNumber());
@ -159,7 +159,7 @@ const QString TContentHistory::currentToString() const {
dateSorted.insert(pair<QDateTime, TFrameId>(it->second, it->first));
std::multimap<QDateTime, TFrameId>::const_iterator it1 = dateSorted.begin();
QDateTime currDate = it1->first;
QDateTime currDate = it1->first;
while (it1 != dateSorted.end()) {
set<TFrameId> frames;

View file

@ -132,6 +132,9 @@ TLevelP TLevelReader::loadInfo() {
if (!data.empty()) {
std::vector<TFilePath>::iterator it =
std::min_element(data.begin(), data.end(), myLess);
m_frameFormat = (*it).getFrame().getCurrentFormat();
/*
TFilePath fr = (*it).withoutParentDir().withName("").withType("");
wstring ws = fr.getWideString();
if (ws.length() == 5) {
@ -150,7 +153,7 @@ TLevelP TLevelReader::loadInfo() {
else
m_frameFormat = TFrameId::UNDERSCORE_NO_PAD;
}
*/
} else
m_frameFormat = TFrameId::FOUR_ZEROS;

View file

@ -27,9 +27,16 @@ const char wauxslash = '\\';
// QT
#include <QObject>
#include <QRegExp>
bool TFilePath::m_underscoreFormatAllowed = true;
// specifies file path condition for sequential image for each project.
// See filepathproperties.h
bool TFilePath::m_useStandard = true;
bool TFilePath::m_acceptNonAlphabetSuffix = false;
int TFilePath::m_letterCountForSuffix = 1;
namespace {
/*-- fromSeg位置 と
@ -102,23 +109,27 @@ std::string TFrameId::expand(FrameFormat format) const {
} else {
o_buff << m_frame;
}
if (m_letter != '\0') o_buff << m_letter;
return o_buff.str();
if (m_letter.isEmpty())
return o_buff.str();
else
return o_buff.str() + m_letter.toStdString();
}
//-------------------------------------------------------------------
const TFrameId &TFrameId::operator++() {
++m_frame;
m_letter = 0;
m_letter = "";
// m_letter = 0;
return *this;
}
//-------------------------------------------------------------------
const TFrameId &TFrameId::operator--() {
if (m_letter > 0)
m_letter = 0;
if (!m_letter.isEmpty()) m_letter = "";
// if (m_letter > 0)
// m_letter = 0;
else
--m_frame;
return *this;
@ -245,9 +256,9 @@ void TFilePath::setPath(std::wstring path) {
}
// se si tratta di un path in formato UNC e' del tipo "\\\\MachineName"
else if ((path.length() >= 3 && path[0] == L'\\' && path[1] == L'\\' &&
iswalnum(path[2])) ||
iswalnum(path[2])) ||
(path.length() >= 3 && path[0] == L'/' && path[1] == L'/' &&
iswalnum(path[2]))) {
iswalnum(path[2]))) {
isUncName = true;
m_path.append(2, L'\\');
m_path.append(1, path[2]);
@ -283,14 +294,13 @@ void TFilePath::setPath(std::wstring path) {
// oppure sia UNC (Windows only) )
if (!((m_path.length() == 1 && m_path[0] == wslash) ||
(m_path.length() == 3 && iswalpha(m_path[0]) && m_path[1] == L':' &&
m_path[2] == wslash)) &&
m_path[2] == wslash)) &&
(m_path.length() > 1 && m_path[m_path.length() - 1] == wslash))
m_path.erase(m_path.length() - 1, 1);
if (isUncName &&
!(m_path.find_last_of(L'\\') > 1 ||
m_path.find_last_of(L'/') >
1)) // e' indicato solo il nome della macchina...
if (isUncName && !(m_path.find_last_of(L'\\') > 1 ||
m_path.find_last_of(L'/') >
1)) // e' indicato solo il nome della macchina...
m_path.append(1, wslash);
}
@ -520,10 +530,10 @@ bool TFilePath::isAbsolute() const {
bool TFilePath::isRoot() const {
return ((m_path.length() == 1 && m_path[0] == slash) ||
(m_path.length() == 3 && iswalpha(m_path[0]) && m_path[1] == ':' &&
m_path[2] == slash) ||
m_path[2] == slash) ||
((m_path.length() > 2 && m_path[0] == slash && m_path[1] == slash) &&
(std::string::npos == m_path.find(slash, 2) ||
m_path.find(slash, 2) == (m_path.size() - 1))));
(std::string::npos == m_path.find(slash, 2) ||
m_path.find(slash, 2) == (m_path.size() - 1))));
}
//-----------------------------------------------------------------------------
@ -531,6 +541,15 @@ bool TFilePath::isRoot() const {
// ritorna ""(niente tipo, niente punto), "." (file con tipo) o ".." (file con
// tipo e frame)
std::string TFilePath::getDots() const {
if (!TFilePath::m_useStandard) {
TFilePathInfo info = analyzePath();
if (info.extension.isEmpty()) return "";
if (info.sepChar.isNull()) return ".";
// return ".." regardless of sepChar type (either "_" or ".")
return "..";
}
//-----
QString type = QString::fromStdString(getType()).toLower();
if (isFfmpegType()) return ".";
int i = getLastSlash(m_path);
@ -555,6 +574,12 @@ std::string TFilePath::getDots() const {
std::string TFilePath::getDottedType()
const // ritorna l'estensione con PUNTO (se c'e')
{
if (!TFilePath::m_useStandard) {
QString ext = analyzePath().extension;
if (ext.isEmpty()) return "";
return "." + ext.toLower().toStdString();
}
int i = getLastSlash(m_path);
std::wstring str = m_path.substr(i + 1);
i = str.rfind(L".");
@ -568,6 +593,15 @@ std::string TFilePath::getDottedType()
std::string TFilePath::getUndottedType()
const // ritorna l'estensione senza PUNTO
{
if (!TFilePath::m_useStandard) {
QString ext = analyzePath().extension;
if (ext.isEmpty())
return "";
else
return ext.toLower().toStdString();
}
//-----
size_t i = getLastSlash(m_path);
std::wstring str = m_path.substr(i + 1);
i = str.rfind(L".");
@ -579,6 +613,11 @@ std::string TFilePath::getUndottedType()
std::wstring TFilePath::getWideName() const // noDot! noSlash!
{
if (!TFilePath::m_useStandard) {
return analyzePath().levelName.toStdWString();
}
//-----
QString type = QString::fromStdString(getType()).toLower();
int i = getLastSlash(m_path); // cerco l'ultimo slash
std::wstring str = m_path.substr(i + 1);
@ -613,6 +652,16 @@ std::string TFilePath::getLevelName() const {
// es. TFilePath("/pippo/pluto.0001.gif").getLevelName() == "pluto..gif"
std::wstring TFilePath::getLevelNameW() const {
if (!TFilePath::m_useStandard) {
TFilePathInfo info = analyzePath();
if (info.extension.isEmpty()) return info.levelName.toStdWString();
QString name = info.levelName;
if (!info.sepChar.isNull()) name += info.sepChar;
name += "." + info.extension;
return name.toStdWString();
}
//-----
int i = getLastSlash(m_path); // cerco l'ultimo slash
std::wstring str = m_path.substr(i + 1); // str e' m_path senza directory
QString type = QString::fromStdString(getType()).toLower();
@ -627,7 +676,8 @@ std::wstring TFilePath::getLevelNameW() const {
return str;
if (!checkForSeqNum(type) || !isNumbers(str, i, j) ||
i == (int)std::wstring::npos) return str;
i == (int)std::wstring::npos)
return str;
// prova.0001.tif
return str.erase(i + 1, j - i - 1);
}
@ -638,8 +688,9 @@ TFilePath TFilePath::getParentDir() const // noSlash!
{
int i = getLastSlash(m_path); // cerco l'ultimo slash
if (i < 0) {
if (m_path.length() >= 2 && (('a' <= m_path[0] && m_path[0] <= 'z') ||
('A' <= m_path[0] && m_path[0] <= 'Z')) &&
if (m_path.length() >= 2 &&
(('a' <= m_path[0] && m_path[0] <= 'z') ||
('A' <= m_path[0] && m_path[0] <= 'Z')) &&
m_path[1] == ':')
return TFilePath(m_path.substr(0, 2));
else
@ -651,8 +702,13 @@ TFilePath TFilePath::getParentDir() const // noSlash!
}
//-----------------------------------------------------------------------------
// return true if the fID is EMPTY_FRAME
bool TFilePath::isLevelName() const {
if (!TFilePath::m_useStandard) {
return analyzePath().fId.getNumber() == TFrameId::EMPTY_FRAME;
}
//-----
QString type = QString::fromStdString(getType()).toLower();
if (isFfmpegType() || !checkForSeqNum(type)) return false;
try {
@ -665,6 +721,11 @@ bool TFilePath::isLevelName() const {
}
TFrameId TFilePath::getFrame() const {
if (!TFilePath::m_useStandard) {
return analyzePath().fId;
}
//-----
int i = getLastSlash(m_path); // cerco l'ultimo slash
std::wstring str = m_path.substr(i + 1); // str e' il path senza parentdir
QString type = QString::fromStdString(getType()).toLower();
@ -680,8 +741,7 @@ TFrameId TFilePath::getFrame() const {
if (j == (int)std::wstring::npos) return TFrameId(TFrameId::NO_FRAME);
if (i == j + 1) return TFrameId(TFrameId::EMPTY_FRAME);
/*-- 間が数字でない場合(ファイル名にまぎれた"_" や "."がある場合)を除外する
* --*/
// 間が数字でない場合(ファイル名にまぎれた"_" や "."がある場合)を除外する
if (!checkForSeqNum(type) || !isNumbers(str, j, i))
return TFrameId(TFrameId::NO_FRAME);
@ -690,14 +750,13 @@ TFrameId TFilePath::getFrame() const {
digits++;
number = number * 10 + str[k] - L'0';
}
char letter = '\0';
char letter = '\0';
if (iswalpha(str[k])) letter = str[k++] + ('a' - L'a');
/*
if (number == 0 || k < i) // || letter!='\0')
throw TMalformedFrameException(
*this,
str + L": " + QObject::tr("Malformed frame name").toStdWString());
*/
// if (number == 0 || k < i) // || letter!='\0')
// throw TMalformedFrameException(
// *this,
// str + L": " + QObject::tr("Malformed frame name").toStdWString());
int padding = 0;
if (str[j + 1] == '0') padding = digits;
@ -751,6 +810,20 @@ TFilePath TFilePath::withName(const std::string &name) const {
//-----------------------------------------------------------------------------
TFilePath TFilePath::withName(const std::wstring &name) const {
if (!TFilePath::m_useStandard) {
TFilePathInfo info = analyzePath();
QString ret = info.parentDir + QString::fromStdWString(name);
if (info.fId.getNumber() != TFrameId::NO_FRAME) {
QString sepChar = (info.sepChar.isNull()) ? "." : QString(info.sepChar);
ret += sepChar + QString::fromStdString(
info.fId.expand(info.fId.getCurrentFormat()));
}
if (!info.extension.isEmpty()) ret += "." + info.extension;
return TFilePath(ret);
}
int i = getLastSlash(m_path); // cerco l'ultimo slash
std::wstring str = m_path.substr(i + 1); // str e' il path senza parentdir
QString type = QString::fromStdString(getType()).toLower();
@ -790,6 +863,31 @@ TFilePath TFilePath::withParentDir(const TFilePath &dir) const {
TFilePath TFilePath::withFrame(const TFrameId &frame,
TFrameId::FrameFormat format) const {
if (!TFilePath::m_useStandard) {
TFilePathInfo info = analyzePath();
// Override format input because it may be wrong.
if (checkForSeqNum(info.extension)) format = frame.getCurrentFormat();
// override format if the original fid is available
else if (info.fId.getNumber() != TFrameId::NO_FRAME)
format = info.fId.getCurrentFormat();
if (info.extension.isEmpty()) {
if (frame.isEmptyFrame() || frame.isNoFrame()) return *this;
return TFilePath(m_path + L"." + ::to_wstring(frame.expand(format)));
}
if (frame.isNoFrame()) {
return TFilePath(info.parentDir + info.levelName + "." + info.extension);
}
QString sepChar = (info.sepChar.isNull()) ? "." : QString(info.sepChar);
return TFilePath(info.parentDir + info.levelName + sepChar +
QString::fromStdString(frame.expand(format)) + "." +
info.extension);
}
//-----------------
const std::wstring dot = L".", dotDot = L"..";
int i = getLastSlash(m_path); // cerco l'ultimo slash
std::wstring str = m_path.substr(i + 1); // str e' il path senza parentdir
@ -804,6 +902,8 @@ TFilePath TFilePath::withFrame(const TFrameId &frame,
format == TFrameId::UNDERSCORE_NO_PAD ||
format == TFrameId::UNDERSCORE_CUSTOM_PAD))
ch = "_";
// no extension case
if (j == (int)std::wstring::npos) {
if (frame.isEmptyFrame() || frame.isNoFrame())
return *this;
@ -842,7 +942,7 @@ TFilePath TFilePath::withFrame(const TFrameId &frame,
(k == j - 1 ||
(checkForSeqNum(type) &&
isNumbers(str, k,
j)))) /*-- "_." の並びか、"_[数字]."の並びのとき --*/
j)))) //-- "_." の並びか、"_[数字]."の並びのとき --
return TFilePath(m_path.substr(0, k + i + 1) +
((frame.isNoFrame())
? L""
@ -893,6 +993,16 @@ TFilePath TFilePath::operator-(const TFilePath &fp) const {
//-----------------------------------------------------------------------------
bool TFilePath::match(const TFilePath &fp) const {
if (!TFilePath::m_useStandard) {
if (getParentDir() != fp.getParentDir()) return false;
TFilePathInfo info = analyzePath();
TFilePathInfo info_ext = fp.analyzePath();
return (info.levelName == info_ext.levelName && info.fId == info_ext.fId &&
info.extension == info_ext.extension);
}
return getParentDir() == fp.getParentDir() && getName() == fp.getName() &&
getFrame() == fp.getFrame() && getType() == fp.getType();
}
@ -915,3 +1025,118 @@ void TFilePath::split(std::wstring &head, TFilePath &tail) const {
head = ancestor.getWideString();
tail = *this - ancestor;
}
//-----------------------------------------------------------------------------
QString TFilePath::fidRegExpStr() {
if (m_useStandard) return QString("(\\d+)([a-zA-Z]?)");
QString suffixLetter = (m_acceptNonAlphabetSuffix)
? "[^\\._ \\\\/:,;*?\"<>|0123456789]"
: "[a-zA-Z]";
QString countLetter = (m_letterCountForSuffix == 0)
? "{0,}"
: (QString("{0,%1}").arg(m_letterCountForSuffix));
return QString("(\\d+)(%1%2)").arg(suffixLetter).arg(countLetter);
// const QString fIdRegExp("(\\d+)([a-zA-Z]?)");
}
//-----------------------------------------------------------------------------
TFilePath::TFilePathInfo TFilePath::analyzePath() const {
assert(!TFilePath::m_useStandard);
TFilePath::TFilePathInfo info;
int i = getLastSlash(m_path);
std::wstring str = m_path.substr(i + 1);
if (i >= 0) info.parentDir = QString::fromStdWString(m_path.substr(0, i + 1));
QString fileName = QString::fromStdWString(str);
// Level Name : letters other than \/:,;*?"<>|
const QString levelNameRegExp("([^\\\\/:,;*?\"<>|]+)");
// Sep Char : period or underscore
const QString sepCharRegExp("([\\._])");
// Frame Number and Suffix
QString fIdRegExp = TFilePath::fidRegExpStr();
// Extensionletters other than "._" or \/:,;*?"<>| or " "(space)
const QString extensionRegExp("([^\\._ \\\\/:,;*?\"<>|]+)");
// ignore frame numbers on non-sequential (i.e. movie) extension case :
// hoge_0001.mp4
// QRegExp rx_mf("^" + levelNameRegExp + "\\." + extensionRegExp + "$");
// if (rx_mf.indexIn(levelName) != -1) {
// QString ext = rx_mf.cap(2);
// if (!checkForSeqNum(ext)) {
// info.levelName = rx_mf.cap(1);
// info.sepChar = QChar();
// info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); //NO_PADで初期化する
// info.extension = ext;
// return info;
// }
//}
// hogehoge.0001a.jpg
// empty frame case : hogehoge..jpg
QRegExp rx("^" + levelNameRegExp + sepCharRegExp + "(?:" + fIdRegExp + ")?" +
"\\." + extensionRegExp + "$");
if (rx.indexIn(fileName) != -1) {
assert(rx.captureCount() == 5);
info.levelName = rx.cap(1);
info.sepChar = rx.cap(2)[0];
info.extension = rx.cap(5);
// ignore frame numbers on non-sequential (i.e. movie) extension case :
// hoge_0001.mp4
if (!checkForSeqNum(info.extension)) {
info.levelName = rx.cap(1) + rx.cap(2);
if (!rx.cap(3).isEmpty()) info.levelName += rx.cap(3);
if (!rx.cap(4).isEmpty()) info.levelName += rx.cap(4);
info.sepChar = QChar();
info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); // initialize with NO_PAD
} else {
QString numberStr = rx.cap(3);
if (numberStr.isEmpty()) // empty frame case : hogehoge..jpg
info.fId =
TFrameId(TFrameId::EMPTY_FRAME, 0, 4, info.sepChar.toLatin1());
else {
int number = numberStr.toInt();
int padding = 0;
if (numberStr[0] == "0") // with padding
padding = numberStr.count();
QString suffix;
if (!rx.cap(4).isEmpty()) suffix = rx.cap(4);
info.fId = TFrameId(number, suffix, padding, info.sepChar.toLatin1());
}
}
return info;
}
// QRegExp rx_ef("^" + levelNameRegExp + sepCharRegExp + "\\." +
// extensionRegExp + "$"); if (rx_ef.indexIn(levelName) != -1) {
// info.levelName = rx_ef.cap(1);
// info.sepChar = rx_ef.cap(2)[0];
// info.fId = TFrameId(TFrameId::EMPTY_FRAME, 0, 4, info.sepChar.toLatin1());
// info.extension = rx_ef.cap(3);
// return info;
//}
// no frame case : hogehoge.jpg
// no level name case : .jpg
QRegExp rx_nf("^(?:" + levelNameRegExp + ")?\\." + extensionRegExp + "$");
if (rx_nf.indexIn(fileName) != -1) {
if (!rx_nf.cap(1).isEmpty()) info.levelName = rx_nf.cap(1);
info.sepChar = QChar();
info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); // initialize with NO_PAD
info.extension = rx_nf.cap(2);
return info;
}
// no periods
info.levelName = fileName;
info.sepChar = QChar();
info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); // initialize with NO_PAD
info.extension = QString();
return info;
}

View file

@ -332,7 +332,7 @@ void TLevelWriterAvi::createBitmap(int lx, int ly) {
TImageWriterP TLevelWriterAvi::getFrameWriter(TFrameId fid) {
if (IOError != 0)
throw TImageException(m_path, buildAVIExceptionString(IOError));
if (fid.getLetter() != 0) return TImageWriterP(0);
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
int index = fid.getNumber() - 1;
TImageWriterAvi *iwa = new TImageWriterAvi(m_path, index, this);
return TImageWriterP(iwa);
@ -879,7 +879,7 @@ TLevelP TLevelReaderAvi::loadInfo() {
TImageReaderP TLevelReaderAvi::getFrameReader(TFrameId fid) {
if (IOError != 0)
throw TImageException(m_path, buildAVIExceptionString(IOError));
if (fid.getLetter() != 0) return TImageReaderP(0);
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
int index = fid.getNumber() - 1;
TImageReaderAvi *ira = new TImageReaderAvi(m_path, index, this);

View file

@ -119,7 +119,7 @@ TLevelWriterGif::~TLevelWriterGif() {
TImageWriterP TLevelWriterGif::getFrameWriter(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildGifExceptionString(IOError));
if (fid.getLetter() != 0) return TImageWriterP(0);
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
int index = fid.getNumber();
TImageWriterGif *iwg = new TImageWriterGif(m_path, index, this);
return TImageWriterP(iwg);
@ -224,7 +224,7 @@ TLevelP TLevelReaderGif::loadInfo() {
TImageReaderP TLevelReaderGif::getFrameReader(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildAVIExceptionString(IOError));
if (fid.getLetter() != 0) return TImageReaderP(0);
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
int index = fid.getNumber();
TImageReaderGif *irm = new TImageReaderGif(m_path, index, this, m_info);
return TImageReaderP(irm);

View file

@ -104,7 +104,7 @@ TLevelWriterMov::~TLevelWriterMov() {
TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildMovExceptionString(IOError));
if (fid.getLetter() != 0) return TImageWriterP(0);
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
int index = fid.getNumber();
TImageWriterMov *iwg = new TImageWriterMov(m_path, index, this);
return TImageWriterP(iwg);
@ -207,7 +207,7 @@ TLevelP TLevelReaderMov::loadInfo() {
TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildAVIExceptionString(IOError));
if (fid.getLetter() != 0) return TImageReaderP(0);
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
int index = fid.getNumber();
TImageReaderMov *irm = new TImageReaderMov(m_path, index, this, m_info);

View file

@ -100,7 +100,7 @@ TLevelWriterMp4::~TLevelWriterMp4() {
TImageWriterP TLevelWriterMp4::getFrameWriter(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildMp4ExceptionString(IOError));
if (fid.getLetter() != 0) return TImageWriterP(0);
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
int index = fid.getNumber();
TImageWriterMp4 *iwg = new TImageWriterMp4(m_path, index, this);
return TImageWriterP(iwg);
@ -203,7 +203,7 @@ TLevelP TLevelReaderMp4::loadInfo() {
TImageReaderP TLevelReaderMp4::getFrameReader(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildAVIExceptionString(IOError));
if (fid.getLetter() != 0) return TImageReaderP(0);
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
int index = fid.getNumber();
TImageReaderMp4 *irm = new TImageReaderMp4(m_path, index, this, m_info);

View file

@ -101,7 +101,7 @@ TLevelWriterWebm::~TLevelWriterWebm() {
TImageWriterP TLevelWriterWebm::getFrameWriter(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildGifExceptionString(IOError));
if (fid.getLetter() != 0) return TImageWriterP(0);
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
int index = fid.getNumber();
TImageWriterWebm *iwg = new TImageWriterWebm(m_path, index, this);
return TImageWriterP(iwg);
@ -204,7 +204,7 @@ TLevelP TLevelReaderWebm::loadInfo() {
TImageReaderP TLevelReaderWebm::getFrameReader(TFrameId fid) {
// if (IOError != 0)
// throw TImageException(m_path, buildAVIExceptionString(IOError));
if (fid.getLetter() != 0) return TImageReaderP(0);
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
int index = fid.getNumber();
TImageReaderWebm *irm = new TImageReaderWebm(m_path, index, this, m_info);

View file

@ -29,7 +29,7 @@ typedef TVectorImage::IntersectionBranch IntersectionBranch;
TNZ_LITTLE_ENDIAN undefined !!
#endif
static const int c_majorVersionNumber = 120;
static const int c_majorVersionNumber = 150;
static const int c_minorVersionNumber = 0;
/*=====================================================================*/
@ -58,8 +58,8 @@ inline double doubleFromUlong1(TUINT32 hi, TUINT32 lo) {
l[1] = hi;
l[0] = lo;
#else
l[0] = hi;
l[1] = lo;
l[0] = hi;
l[1] = lo;
#endif
return *(double *)l; // - 1;
@ -84,8 +84,8 @@ public:
#if TNZ_LITTLE_ENDIAN
app = n;
#else
UCHAR *uc = (UCHAR *)&n;
app = *(uc) | (*(uc + 1)) << 8 | (*(uc + 2)) << 16 | (*(uc + 3)) << 24;
UCHAR *uc = (UCHAR *)&n;
app = *(uc) | (*(uc + 1)) << 8 | (*(uc + 2)) << 16 | (*(uc + 3)) << 24;
#endif
write((char *)&app, sizeof(TUINT32));
return *this;
@ -669,15 +669,27 @@ void ParsedPliImp::loadInfo(bool readPlt, TPalette *&palette,
USHORT frame;
m_iChan >> frame;
char letter = 0;
if (m_majorVersionNumber > 6 ||
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6))
m_iChan >> letter;
QByteArray suffix;
if (m_majorVersionNumber >= 150) {
TUINT32 suffixLength;
m_iChan >> suffixLength;
if ((int)suffixLength > 0) {
suffix.resize(suffixLength);
m_iChan.read(suffix.data(), suffixLength);
}
} else {
char letter = 0;
if (m_majorVersionNumber > 6 ||
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6))
m_iChan >> letter;
if (letter > 0) suffix = QByteArray(&letter, 1);
}
m_frameOffsInFile[TFrameId(frame, letter)] = m_iChan.tellg();
m_frameOffsInFile[TFrameId(frame, QString::fromUtf8(suffix))] =
m_iChan.tellg();
// m_iChan.seekg(m_tagLength, ios::cur);
m_iChan.seekg(m_tagLength - 2, ios::cur);
if (m_majorVersionNumber < 150) m_iChan.seekg(m_tagLength - 2, ios::cur);
} else if (type == PliTag::STYLE_NGOBJ) {
m_iChan.seekg(pos, ios::beg);
TagElem *tagElem = readTag();
@ -798,7 +810,7 @@ ImageTag *ParsedPliImp::loadFrame(const TFrameId &frameNumber) {
// PliTag *tag;
USHORT type = PliTag::IMAGE_BEGIN_GOBJ;
USHORT frame;
char letter;
QByteArray suffix;
TFrameId frameId;
// cerco il frame
@ -813,13 +825,21 @@ ImageTag *ParsedPliImp::loadFrame(const TFrameId &frameNumber) {
while ((type = readTagHeader()) != PliTag::END_CNTRL) {
if (type == PliTag::IMAGE_BEGIN_GOBJ) {
m_iChan >> frame;
if (m_majorVersionNumber > 6 ||
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6))
m_iChan >> letter;
else
letter = 0;
if (m_majorVersionNumber >= 150) {
TUINT32 suffixLength;
m_iChan >> suffixLength;
suffix.resize(suffixLength);
m_iChan.read(suffix.data(), suffixLength);
} else {
char letter = 0;
if (m_majorVersionNumber > 6 ||
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) {
m_iChan >> letter;
if (letter > 0) suffix = QByteArray(&letter, 1);
}
}
frameId = TFrameId(frame, letter);
frameId = TFrameId(frame, QString::fromUtf8(suffix));
m_frameOffsInFile[frameId] = m_iChan.tellg();
if (frameId == frameNumber) break;
} else
@ -1056,15 +1076,16 @@ inline bool ParsedPliImp::readDynamicData(TINT32 &val, TUINT32 &bufOffs) {
case 4:
if (m_isIrixEndian) {
val = (m_buf[bufOffs + 3] | (m_buf[bufOffs + 2] << 8) |
(m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24)) & 0x7fffffff;
(m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24)) &
0x7fffffff;
if (m_buf[bufOffs] & 0x80) {
val = -val;
isNegative = true;
}
} else {
val = (m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8) |
(m_buf[bufOffs + 2] << 16) |
(m_buf[bufOffs + 3] << 24)) & 0x7fffffff;
(m_buf[bufOffs + 2] << 16) | (m_buf[bufOffs + 3] << 24)) &
0x7fffffff;
if (m_buf[bufOffs + 3] & 0x80) {
val = -val;
isNegative = true;
@ -1466,7 +1487,7 @@ UINT ParsedPliImp::readRasterData(TRaster32P &r, TUINT32 &bufOffs) {
/*=====================================================================*/
inline void getLongValFromFloat(double val, TINT32 &intVal, TUINT32 &decVal) {
intVal = (TINT32)val;
intVal = (TINT32)val;
if (val < 0) decVal = (TUINT32)((double)((-val) - (-intVal)) * 65536.0);
/*if (intVal<(0x1<<7))
intVal|=(0x1<<7);
@ -1614,11 +1635,25 @@ PliTag *ParsedPliImp::readImageTag() {
bufOffs += 2;
int headerLength = 2;
char letter = 0;
if (m_majorVersionNumber > 6 ||
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) {
letter = (char)m_buf[bufOffs++];
++headerLength;
QByteArray suffix;
if (m_majorVersionNumber >= 150) {
TUINT32 suffixLength;
readTUINT32Data(suffixLength, bufOffs);
headerLength += 4;
if (suffixLength > 0) {
suffix = QByteArray((char *)m_buf.get() + bufOffs, suffixLength);
bufOffs += suffixLength;
headerLength += suffixLength;
}
} else {
char letter = 0;
if (m_majorVersionNumber > 6 ||
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) {
letter = (char)m_buf[bufOffs++];
++headerLength;
if (letter > 0) suffix = QByteArray(&letter, 1);
}
}
TUINT32 numObjects = (m_tagLength - headerLength) / m_currDynamicTypeBytesNum;
@ -1638,7 +1673,8 @@ PliTag *ParsedPliImp::readImageTag() {
assert(false);
std::unique_ptr<ImageTag[]> tag(
new ImageTag(TFrameId(frame, letter), numObjects, std::move(object)));
new ImageTag(TFrameId(frame, QString::fromUtf8(suffix)), numObjects,
std::move(object)));
return tag.release();
}
@ -1655,8 +1691,8 @@ inline double doubleFromUlong(TUINT32 q) {
l[1] = 0x3FF00000 | (q >> 12);
l[0] = (q & 0xFFE) << 20;
#else
l[0] = 0x3FF00000 | (q >> 12);
l[1] = (q & 0xFFE) << 20;
l[0] = 0x3FF00000 | (q >> 12);
l[1] = (q & 0xFFE) << 20;
#endif
return *(double *)l - 1;
@ -1700,7 +1736,7 @@ PliTag *ParsedPliImp::readIntersectionDataTag() {
readUShortData(style, bufOffs);
branchArray[i].m_style = style;
/*
*/
*/
if (m_buf[bufOffs] & 0x80) // in un numero double tra 0 e 1, il bit piu'
// significativo e' sempre 0
// sfrutto questo bit; se e' 1, vuol dire che il valore e' 0.0 o 1.0 in un
@ -1981,7 +2017,7 @@ TUINT32 ParsedPliImp::writePaletteWithAlphaTag(PaletteWithAlphaTag *tag) {
inline void ParsedPliImp::WRITE_UCHAR_FROM_DOUBLE(double dval) {
assert(m_oChan);
int ival = tround(dval);
int ival = tround(dval);
if (ival > 255) ival = 255;
assert(ival >= 0);
*m_oChan << (UCHAR)ival;
@ -2128,10 +2164,24 @@ TUINT32 ParsedPliImp::writeImageTag(ImageTag *tag) {
TUINT32 *objectOffset, offset, tagLength;
int maxval = 0, minval = 100000;
writeTagHeader((UCHAR)PliTag::IMAGE_BEGIN_GOBJ, 3);
*m_oChan << (USHORT)tag->m_numFrame.getNumber();
*m_oChan << tag->m_numFrame.getLetter();
QByteArray suffix = tag->m_numFrame.getLetter().toUtf8();
TUINT32 suffixLength = suffix.size();
UINT fIdTagLength;
if (m_majorVersionNumber >= 150) { // write the suffix length before data
fIdTagLength = 2 + 4 + suffixLength;
writeTagHeader((UCHAR)PliTag::IMAGE_BEGIN_GOBJ, fIdTagLength);
*m_oChan << (USHORT)tag->m_numFrame.getNumber();
*m_oChan << suffixLength;
if (suffixLength > 0) m_oChan->writeBuf(suffix.data(), suffixLength);
} else { // write only the first byte
fIdTagLength = 3;
writeTagHeader((UCHAR)PliTag::IMAGE_BEGIN_GOBJ, fIdTagLength);
*m_oChan << (USHORT)tag->m_numFrame.getNumber();
if (suffixLength > 0)
m_oChan->writeBuf(suffix.data(), 1);
else
*m_oChan << (UCHAR)0;
}
m_currDynamicTypeBytesNum = 3;
objectOffset = new TUINT32[tag->m_numObjects];
@ -2155,12 +2205,23 @@ TUINT32 ParsedPliImp::writeImageTag(ImageTag *tag) {
setDynamicTypeBytesNum(minval, maxval);
tagLength = tag->m_numObjects * m_currDynamicTypeBytesNum + 3;
tagLength = tag->m_numObjects * m_currDynamicTypeBytesNum + fIdTagLength;
// tagLength = tag->m_numObjects * m_currDynamicTypeBytesNum + 3;
offset = writeTagHeader((UCHAR)PliTag::IMAGE_GOBJ, tagLength);
suffix = tag->m_numFrame.getLetter().toUtf8();
*m_oChan << (USHORT)tag->m_numFrame.getNumber();
*m_oChan << tag->m_numFrame.getLetter();
if (m_majorVersionNumber >= 150) { // write the suffix length before data
*m_oChan << suffixLength;
if (suffixLength > 0) m_oChan->writeBuf(suffix.data(), suffixLength);
} else { // write only the first byte
if (suffixLength > 0)
m_oChan->writeBuf(suffix.data(), 1);
else
*m_oChan << (UCHAR)0;
}
for (i = 0; i < tag->m_numObjects; i++) writeDynamicData(objectOffset[i]);
@ -2420,29 +2481,29 @@ TUINT32 ParsedPliImp::writeGeometricTransformationTag(
if (objectOffset > (unsigned int)maxval) maxval = (int)objectOffset;
getLongValFromFloat(tag->m_affine.a11, intVal[0], decVal[0]);
if (intVal[0] < minval) minval = (int)intVal[0];
if (intVal[0] > maxval) maxval = (int)intVal[0];
if (intVal[0] < minval) minval = (int)intVal[0];
if (intVal[0] > maxval) maxval = (int)intVal[0];
if (decVal[0] > (unsigned int)maxval) maxval = (int)decVal[0];
getLongValFromFloat(tag->m_affine.a12, intVal[1], decVal[1]);
if (decVal[1] > (unsigned int)maxval) maxval = (int)decVal[1];
if (intVal[1] < minval) minval = (int)intVal[1];
if (intVal[1] > maxval) maxval = (int)intVal[1];
if (intVal[1] < minval) minval = (int)intVal[1];
if (intVal[1] > maxval) maxval = (int)intVal[1];
getLongValFromFloat(tag->m_affine.a13, intVal[2], decVal[2]);
if (decVal[2] > (unsigned int)maxval) maxval = (int)decVal[2];
if (intVal[2] < minval) minval = (int)intVal[2];
if (intVal[2] > maxval) maxval = (int)intVal[2];
if (intVal[2] < minval) minval = (int)intVal[2];
if (intVal[2] > maxval) maxval = (int)intVal[2];
getLongValFromFloat(tag->m_affine.a21, intVal[3], decVal[3]);
if (decVal[3] > (unsigned int)maxval) maxval = (int)decVal[3];
if (intVal[3] < minval) minval = (int)intVal[3];
if (intVal[3] > maxval) maxval = (int)intVal[3];
if (intVal[3] < minval) minval = (int)intVal[3];
if (intVal[3] > maxval) maxval = (int)intVal[3];
getLongValFromFloat(tag->m_affine.a22, intVal[4], decVal[4]);
if (decVal[4] > (unsigned int)maxval) maxval = (int)decVal[4];
if (intVal[4] < minval) minval = (int)intVal[4];
if (intVal[4] > maxval) maxval = (int)intVal[4];
if (intVal[4] < minval) minval = (int)intVal[4];
if (intVal[4] > maxval) maxval = (int)intVal[4];
getLongValFromFloat(tag->m_affine.a23, intVal[5], decVal[5]);
if (decVal[5] > (unsigned int)maxval) maxval = (int)decVal[5];
if (intVal[5] < minval) minval = (int)intVal[5];
if (intVal[5] > maxval) maxval = (int)intVal[5];
if (intVal[5] < minval) minval = (int)intVal[5];
if (intVal[5] > maxval) maxval = (int)intVal[5];
setDynamicTypeBytesNum(minval, maxval);
@ -2479,11 +2540,11 @@ TUINT32 ParsedPliImp::writeDoublePairTag(DoublePairTag *tag) {
getLongValFromFloat(tag->m_first, xIntVal, xDecVal);
getLongValFromFloat(tag->m_second, yIntVal, yDecVal);
if (xIntVal < minval) minval = (int)xIntVal;
if (xIntVal > maxval) maxval = (int)xIntVal;
if (xIntVal < minval) minval = (int)xIntVal;
if (xIntVal > maxval) maxval = (int)xIntVal;
if ((int)xDecVal > maxval) maxval = (int)xDecVal;
if (yIntVal < minval) minval = (int)yIntVal;
if (yIntVal > maxval) maxval = (int)yIntVal;
if (yIntVal < minval) minval = (int)yIntVal;
if (yIntVal > maxval) maxval = (int)yIntVal;
if ((int)yDecVal > maxval) maxval = (int)yDecVal;
setDynamicTypeBytesNum(minval, maxval);
@ -2635,10 +2696,16 @@ void ParsedPli::getVersion(UINT &majorVersionNumber,
/*=====================================================================*/
void ParsedPli::setVersion(UINT majorVersionNumber, UINT minorVersionNumber) {
if (imp->m_versionLocked) return;
if (imp->m_versionLocked) {
// accept only when settings higher versions
if ((imp->m_majorVersionNumber > majorVersionNumber) ||
(imp->m_majorVersionNumber == majorVersionNumber &&
imp->m_minorVersionNumber >= minorVersionNumber))
return;
}
if (majorVersionNumber >= 120) imp->m_versionLocked = true;
imp->m_majorVersionNumber = majorVersionNumber;
imp->m_minorVersionNumber = minorVersionNumber;
imp->m_majorVersionNumber = majorVersionNumber;
imp->m_minorVersionNumber = minorVersionNumber;
}
/*=====================================================================*/

View file

@ -160,7 +160,7 @@ void buildPalette(ParsedPli *pli, const TImageP img) {
assert(vPalette->getPageCount());
std::vector<TStyleParam> pageNames(vPalette->getPageCount());
for (i = 0; i < pageNames.size(); i++)
for (i = 0; i < pageNames.size(); i++)
pageNames[i] = TStyleParam(::to_string(vPalette->getPage(i)->getName()));
StyleTag *pageNamesTag =
new StyleTag(0, 0, pageNames.size(), pageNames.data());
@ -414,18 +414,18 @@ TImageP TImageReaderPli::doLoad() {
} // switch(groupTag->m_object[j]->m_type)
} // for (i=0; i<imageTag->m_numObjects; i++)
//} // try
//} // try
// catch(...) // cosi' e' inutile o raccolgo qualcosa prima di rilanciare o lo
// elimino
//{
// throw;
// }
// catch(...) // cosi' e' inutile o raccolgo qualcosa prima di rilanciare o lo
// elimino
//{
// throw;
// }
// if (regionsComputed) //WARNING !!! la seedFill mette il flag a ValidRegion a
// TRUE
// outVectImage->seedFill(); //le vecchie immagini hanno il seed
// (version<3.1)
// if (regionsComputed) //WARNING !!! la seedFill mette il flag a ValidRegion
// a TRUE
// outVectImage->seedFill(); //le vecchie immagini hanno il seed
// (version<3.1)
#ifdef _DEBUG
outVectImage->checkIntersections();
@ -564,6 +564,9 @@ solo nel costruttore)
PliTag *tag = new PrecisionScaleTag(precisionScale);
tags.push_back((PliObjectTag *)tag);
}
// update the format version if multiple suffixes is supported0
if (!TFilePath::useStandard()) pli->setVersion(150, 0);
// Store the auto close tolerance
double pliTolerance = m_lwp->m_pli->getAutocloseTolerance();
// write the tag if the frame's tolerance has been changed or
@ -744,7 +747,7 @@ TPalette *readPalette(GroupTag *paletteTag, int majorVersion,
// caricarli!
std::vector<TStyleParam> params(styleTag->m_numParams);
for (int j = 0; j < styleTag->m_numParams; j++)
for (int j = 0; j < styleTag->m_numParams; j++)
params[j] = styleTag->m_param[j];
PliInputStream chan(&params, majorVersion, minorVersion);

View file

@ -190,7 +190,7 @@ TLevelWriterSprite::~TLevelWriterSprite() {
//-----------------------------------------------------------
TImageWriterP TLevelWriterSprite::getFrameWriter(TFrameId fid) {
if (fid.getLetter() != 0) return TImageWriterP(0);
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
int index = fid.getNumber();
TImageWriterSprite *iwg = new TImageWriterSprite(m_path, index, this);
return TImageWriterP(iwg);
@ -265,9 +265,9 @@ void TLevelWriterSprite::save(const TImageP &img, int frameIndex) {
m_top = t;
m_bottom = b;
} else {
if (l < m_left) m_left = l;
if (r > m_right) m_right = r;
if (t < m_top) m_top = t;
if (l < m_left) m_left = l;
if (r > m_right) m_right = r;
if (t < m_top) m_top = t;
if (b > m_bottom) m_bottom = b;
}
QImage *newQi = new QImage(m_lx, m_ly, QImage::Format_ARGB32_Premultiplied);

View file

@ -25,8 +25,7 @@
TNZ_LITTLE_ENDIAN undefined !!
#endif
const int CURRENT_VERSION = 14;
const int CREATOR_LENGTH = 40;
const int CREATOR_LENGTH = 40;
namespace {
@ -40,6 +39,13 @@ char *reverse(char *buffer, int size) {
}
return buffer;
}
// switch the saving version according to the file path property
int currentVersion() {
if (TFilePath::useStandard()) return 14;
return 15;
}
} // namespace
static int tfwrite(const char *data, const unsigned int count, FILE *f) {
@ -138,6 +144,8 @@ bool readVersion(FILE *chan, int &version) {
version = 13;
} else if (memcmp(magic, "TLV14", 5) == 0) {
version = 14;
} else if (memcmp(magic, "TLV15", 5) == 0) {
version = 15;
} else {
return false;
}
@ -162,7 +170,7 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable,
if (!readVersion(chan, version)) return false;
// read creator
if (version == 14) {
if (version >= 14) {
char buffer[CREATOR_LENGTH + 1];
memset(buffer, 0, sizeof buffer);
fread(&buffer, sizeof(char), CREATOR_LENGTH, chan);
@ -201,9 +209,18 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable,
TFrameId oldFid(TFrameId::EMPTY_FRAME);
for (int i = 0; i < (int)frameCount; i++) {
TINT32 number, offs, length;
char letter;
QByteArray suffix;
fread(&number, sizeof(TINT32), 1, chan);
fread(&letter, sizeof(char), 1, chan);
if (version >= 15) {
TINT32 suffixLength;
fread(&suffixLength, sizeof(TINT32), 1, chan);
suffix.resize(suffixLength);
fread(suffix.data(), sizeof(char), suffixLength, chan);
} else {
char letter;
fread(&letter, sizeof(char), 1, chan);
suffix = QByteArray(&letter, 1);
}
fread(&offs, sizeof(TINT32), 1, chan);
if (version >= 12) fread(&length, sizeof(TINT32), 1, chan);
@ -215,7 +232,7 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable,
// std::cout << "#" << i << std::hex << " n 0x" << number
//<< " l 0x" << letter << " o 0x" << offs << std::dec << std::endl;
TFrameId fid(number, letter);
TFrameId fid(number, QString::fromUtf8(suffix));
// assert(i==0 || oldFid<fid);
if (version >= 12) {
@ -241,9 +258,18 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable,
for (int i = 0; i < (int)frameCount; i++) {
TINT32 number, thumbnailOffs, thumbnailLength;
char letter;
QByteArray suffix;
fread(&number, sizeof(TINT32), 1, chan);
fread(&letter, sizeof(char), 1, chan);
if (version >= 15) {
TINT32 suffixLength;
fread(&suffixLength, sizeof(TINT32), 1, chan);
suffix.resize(suffixLength);
fread(suffix.data(), sizeof(char), suffixLength, chan);
} else {
char letter;
fread(&letter, sizeof(char), 1, chan);
suffix = QByteArray(&letter, 1);
}
fread(&thumbnailOffs, sizeof(TINT32), 1, chan);
fread(&thumbnailLength, sizeof(TINT32), 1, chan);
@ -252,7 +278,7 @@ bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable,
thumbnailOffs = swapTINT32(thumbnailOffs);
thumbnailLength = swapTINT32(thumbnailLength);
#endif
TFrameId fid(number, letter);
TFrameId fid(number, QString::fromUtf8(suffix));
iconOffsTable[fid] = TzlChunk(thumbnailOffs, thumbnailLength);
}
}
@ -460,7 +486,7 @@ void TLevelWriterTzl::buildFreeChunksTable() {
// dati relativi alle immagini
if (m_version == 13)
curPos = 6 * sizeof(TINT32) + 4 * sizeof(char) + 8 * sizeof(char);
else if (m_version == 14)
else if (m_version >= 14)
curPos = 6 * sizeof(TINT32) + 4 * sizeof(char) + 8 * sizeof(char) +
CREATOR_LENGTH * sizeof(char);
else
@ -495,7 +521,7 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info)
, m_palette(0)
, m_res(0, 0)
, m_exists(false)
, m_version(CURRENT_VERSION)
, m_version(currentVersion())
, m_updatedIconsSize(false)
, m_currentIconSize(0, 0)
, m_iconSize(TDimension(80, 60))
@ -506,13 +532,14 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info)
m_path = path;
m_palettePath = path.withNoFrame().withType("tpl");
TFileStatus fs(path);
m_magic = "TLV14B1a"; // actual version
m_magic = (m_version == 14) ? "TLV14B1a" : "TLV15B1a"; // actual version
erasedFrame = false;
// version TLV10B1a: first version
// version TLV11B1a: added frameIds
// version TLV12B1a: incremental writings
// version TLV13B1a: added thumbnails
// version TLV15B1a: add creator string (fixed size = CREATOR_LENGTH char)
// version TLV14B1a: add creator string (fixed size = CREATOR_LENGTH char)
// version TLV15B1a: support multiple suffixes
if (fs.doesExist()) {
// if (!fs.isWritable())
@ -530,7 +557,7 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info)
if (m_version >= 12) buildFreeChunksTable();
m_headerWritten = true;
m_exists = true;
if (m_version == 14)
if (m_version >= 14)
m_frameCountPos = 8 + CREATOR_LENGTH + 3 * sizeof(TINT32);
else
m_frameCountPos = 8 + 3 * sizeof(TINT32);
@ -555,9 +582,9 @@ TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info)
//-------------------------------------------------------------------
TLevelWriterTzl::~TLevelWriterTzl() {
if (m_version < CURRENT_VERSION) {
if (m_version < currentVersion()) {
if (!convertToLatestVersion()) return;
assert(m_version == CURRENT_VERSION);
assert(m_version == currentVersion());
}
delete m_codec;
@ -573,13 +600,18 @@ TLevelWriterTzl::~TLevelWriterTzl() {
TzlOffsetMap::iterator it = m_frameOffsTable.begin();
for (; it != m_frameOffsTable.end(); ++it) {
TFrameId fid = it->first;
TINT32 num = fid.getNumber();
char letter = fid.getLetter();
TINT32 offs = it->second.m_offs;
TINT32 length = it->second.m_length;
TFrameId fid = it->first;
TINT32 num = fid.getNumber();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 offs = it->second.m_offs;
TINT32 length = it->second.m_length;
tfwrite(&num, 1, m_chan);
tfwrite(&letter, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 1, m_chan);
tfwrite(&offs, 1, m_chan);
tfwrite(&length, 1, m_chan);
}
@ -593,11 +625,16 @@ TLevelWriterTzl::~TLevelWriterTzl() {
for (; iconIt != m_iconOffsTable.end(); ++iconIt) {
TFrameId fid = iconIt->first;
TINT32 num = fid.getNumber();
char letter = fid.getLetter();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 thumbnailOffs = iconIt->second.m_offs;
TINT32 thumbnailLength = iconIt->second.m_length;
tfwrite(&num, 1, m_chan);
tfwrite(&letter, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 1, m_chan);
tfwrite(&thumbnailOffs, 1, m_chan);
tfwrite(&thumbnailLength, 1, m_chan);
}
@ -774,7 +811,7 @@ bool TLevelWriterTzl::convertToLatestVersion() {
if (!m_chan) return false;
if (!writeVersionAndCreator(m_chan, m_magic, m_creator)) return false;
m_creatorWritten = true;
m_version = CURRENT_VERSION;
m_version = currentVersion();
TLevelReaderP lr(tempPath);
if (!lr) return false;
TLevelP level = lr->loadInfo();
@ -798,13 +835,18 @@ bool TLevelWriterTzl::convertToLatestVersion() {
TzlOffsetMap::iterator it2 = m_frameOffsTable.begin();
for (; it2 != m_frameOffsTable.end(); ++it2) {
TFrameId fid = it2->first;
TINT32 num = fid.getNumber();
char letter = fid.getLetter();
TINT32 offs = it2->second.m_offs;
TINT32 length = it2->second.m_length;
TFrameId fid = it2->first;
TINT32 num = fid.getNumber();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 offs = it2->second.m_offs;
TINT32 length = it2->second.m_length;
tfwrite(&num, 1, m_chan);
tfwrite(&letter, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 1, m_chan);
tfwrite(&offs, 1, m_chan);
tfwrite(&length, 1, m_chan);
}
@ -816,11 +858,16 @@ bool TLevelWriterTzl::convertToLatestVersion() {
for (; iconIt != m_iconOffsTable.end(); ++iconIt) {
TFrameId fid = iconIt->first;
TINT32 num = fid.getNumber();
char letter = fid.getLetter();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 thumbnailOffs = iconIt->second.m_offs;
TINT32 thumbnailLength = iconIt->second.m_length;
tfwrite(&num, 1, m_chan);
tfwrite(&letter, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 1, m_chan);
tfwrite(&thumbnailOffs, 1, m_chan);
tfwrite(&thumbnailLength, 1, m_chan);
}
@ -856,7 +903,7 @@ bool TLevelWriterTzl::convertToLatestVersion() {
m_headerWritten = true;
m_exists = true;
m_frameCountPos = 8 + CREATOR_LENGTH + 3 * sizeof(TINT32);
assert(m_version == CURRENT_VERSION);
assert(m_version == currentVersion());
if (!m_renumberTable.empty()) renumberFids(m_renumberTable);
return true;
}
@ -867,9 +914,9 @@ void TLevelWriterTzl::saveImage(const TImageP &img, const TFrameId &_fid,
if (!m_chan) return;
// se il file è di una versione precedente allora lo converto prima
if (m_version < CURRENT_VERSION) {
if (m_version < currentVersion()) {
if (!convertToLatestVersion()) return;
assert(m_version == CURRENT_VERSION);
assert(m_version == currentVersion());
}
if (!m_updatedIconsSize && m_exists)
@ -1348,7 +1395,7 @@ float TLevelWriterTzl::getFreeSpace() {
if (m_version == 13)
totalSpace = m_offsetTablePos - 6 * sizeof(TINT32) - 4 * sizeof(char) -
8 * sizeof(char);
else if (m_version == 14)
else if (m_version >= 14)
totalSpace = m_offsetTablePos - 6 * sizeof(TINT32) - 4 * sizeof(char) -
8 * sizeof(char) - CREATOR_LENGTH * sizeof(char);
assert(totalSpace > 0);
@ -2285,6 +2332,10 @@ TImageP TImageReaderTzl::load() {
if (!m_lrp->m_frameOffsTable.empty() && !m_lrp->m_iconOffsTable.empty())
image = load14();
break;
case 15: // same as v14
if (!m_lrp->m_frameOffsTable.empty() && !m_lrp->m_iconOffsTable.empty())
image = load14();
break;
default:
image = load10();
}

View file

@ -67,6 +67,7 @@ enum class PredefinedRect {
BEGIN_EXTENDER, //! top / left extender
KEYFRAME_AREA, //! part of cell dedicated to key frames
DRAG_AREA, //! draggable side bar
CELL_MARK_AREA, //! cell mark
SOUND_TRACK, //! area dedicated to waveform display
PREVIEW_TRACK, //! sound preview area
BEGIN_SOUND_EDIT, //! top sound resize

View file

@ -5,6 +5,7 @@
// tcg includes
#include "macros.h"
#include <algorithm>
/*!
\file tcg_poly_ops.h

View file

@ -16,7 +16,7 @@
#define DVVAR DV_IMPORT_VAR
#endif
class QString;
#include <QString>
//-----------------------------------------------------------------------------
/*
@ -28,8 +28,8 @@ class QString;
//! figures and, in case, by a character (necessary for added frames)
class DVAPI TFrameId {
int m_frame;
char m_letter; // serve per i frame "aggiunti" del tipo pippo.0001a.tzp =>
// f=1 c='a'
QString m_letter; // serve per i frame "aggiunti" del tipo pippo.0001a.tzp =>
// f=1 c='a'
int m_zeroPadding;
char m_startSeqInd;
@ -50,13 +50,13 @@ public:
}; // pippo_1.tif
TFrameId(int f = EMPTY_FRAME)
: m_frame(f), m_letter(0), m_zeroPadding(4), m_startSeqInd('.') {}
TFrameId(int f, char c)
: m_frame(f), m_letter(c), m_zeroPadding(4), m_startSeqInd('.') {}
TFrameId(int f, char c, int p)
: m_frame(f), m_letter(c), m_zeroPadding(p), m_startSeqInd('.') {}
TFrameId(int f, char c, int p, char s)
: m_frame(f), m_letter(c), m_zeroPadding(p), m_startSeqInd(s) {}
: m_frame(f), m_letter(""), m_zeroPadding(4), m_startSeqInd('.') {}
TFrameId(int f, char c, int p = 4, char s = '.')
: m_frame(f), m_zeroPadding(p), m_startSeqInd(s) {
m_letter = (c == '\0') ? "" : QString(c);
}
TFrameId(int f, QString str, int p = 4, char s = '.')
: m_frame(f), m_letter(str), m_zeroPadding(p), m_startSeqInd(s) {}
inline bool operator==(const TFrameId &f) const {
return f.m_frame == m_frame && f.m_letter == m_letter;
@ -66,7 +66,8 @@ public:
}
inline bool operator<(const TFrameId &f) const {
return (m_frame < f.m_frame ||
(m_frame == f.m_frame && m_letter < f.m_letter));
(m_frame == f.m_frame &&
QString::localeAwareCompare(m_letter, f.m_letter) < 0));
}
inline bool operator>(const TFrameId &f) const { return f < *this; }
inline bool operator>=(const TFrameId &f) const { return !operator<(f); }
@ -89,7 +90,7 @@ public:
// operator string() const;
std::string expand(FrameFormat format = FOUR_ZEROS) const;
int getNumber() const { return m_frame; }
char getLetter() const { return m_letter; }
QString getLetter() const { return m_letter; }
void setZeroPadding(int p) { m_zeroPadding = p; }
int getZeroPadding() const { return m_zeroPadding; }
@ -132,7 +133,23 @@ inline std::ostream &operator<<(std::ostream &out, const TFrameId &f) {
constructor.*/
class DVAPI TFilePath {
static bool m_underscoreFormatAllowed;
// specifies file path condition for sequential image for each project.
// See filepathproperties.h
static bool m_useStandard;
static bool m_acceptNonAlphabetSuffix;
static int m_letterCountForSuffix;
std::wstring m_path;
struct TFilePathInfo {
QString parentDir; // with slash
QString levelName;
QChar sepChar; // either "." or "_"
TFrameId fId;
QString extension;
};
void setPath(std::wstring path);
public:
@ -142,6 +159,23 @@ public:
m_underscoreFormatAllowed = state;
}
// called from TProjectManager::getCurrentProject() and
// ProjectPopup::updateProjectFromFields
// returns true if something changed
static bool setFilePathProperties(bool useStandard, bool acceptNonAlphaSuffix,
int letterCountForSuffix) {
if (m_useStandard == useStandard &&
m_acceptNonAlphabetSuffix == acceptNonAlphaSuffix &&
m_letterCountForSuffix == letterCountForSuffix)
return false;
m_useStandard = useStandard;
m_acceptNonAlphabetSuffix = acceptNonAlphaSuffix;
m_letterCountForSuffix = letterCountForSuffix;
return true;
}
static bool useStandard() { return m_useStandard; }
static QString fidRegExpStr();
/*!This constructor creates a string removing redundances ('//', './',etc.)
and final slashes,
correcting (redressing) the "twisted" slashes.
@ -191,6 +225,7 @@ If the path is "<alpha>:" a slash will be added*/
std::string getType() const {
return getUndottedType();
} // ritorna l'estensione SENZA PUNTO
/*!Returns the base filename (no extension, no dots, no slash)*/
std::string getName() const; // noDot! noSlash!
std::wstring getWideName() const; // noDot! noSlash!
@ -274,6 +309,8 @@ type is a string that indicate the filename extension(ex:. bmp or .bmp)*/
// '/a/b/c.txt' => head='a' tail='b/c.txt'
void split(std::wstring &head, TFilePath &tail) const;
TFilePathInfo analyzePath() const;
};
//-----------------------------------------------------------------------------

View file

@ -160,6 +160,12 @@ public:
/*--- オフセットを軸ごとにロックする ---*/
bool m_offx_lock, m_offy_lock;
// hold brightness and contrast values for each line processing modes (grey
// and color).
double m_altBrightness, m_altContrast;
// exporting file format when Line Processing = None
std::string m_lpNoneFormat;
public:
CleanupParameters();
CleanupParameters(const CleanupParameters &p) { assign(&p); }

View file

@ -0,0 +1,49 @@
#pragma once
#ifndef FILEPATHPROPERTIES_H
#define FILEPATHPROPERTIES_H
#include "tcommon.h"
#undef DVAPI
#undef DVVAR
#ifdef TOONZLIB_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif
//=============================================================================
// forward declarations
class TIStream;
class TOStream;
//=============================================================================
// FilePathProperties
// This class defines file path condition for sequential image level
class DVAPI FilePathProperties {
bool m_useStandard;
bool m_acceptNonAlphabetSuffix;
int m_letterCountForSuffix;
public:
FilePathProperties();
bool useStandard() { return m_useStandard; }
void setUseStandard(bool on) { m_useStandard = on; }
bool acceptNonAlphabetSuffix() { return m_acceptNonAlphabetSuffix; }
void setAcceptNonAlphabetSuffix(bool on) { m_acceptNonAlphabetSuffix = on; }
int letterCountForSuffix() { return m_letterCountForSuffix; }
void setLetterCountForSuffix(int val) { m_letterCountForSuffix = val; }
void saveData(TOStream& os) const;
void loadData(TIStream& is);
bool isDefault();
};
#endif

View file

@ -49,6 +49,11 @@ class DVAPI TSceneProperties {
public:
typedef std::vector<double> Guides;
struct CellMark {
QString name;
TPixel32 color;
};
private:
Guides m_hGuides, m_vGuides;
@ -73,6 +78,9 @@ private:
//! Xsheet Note Color, color number = 7.
QList<TPixel32> m_notesColor;
// Cell Mark colors and names
QList<CellMark> m_cellMarks;
bool m_columnColorFilterOnRender;
TFilePath m_camCapSaveInPath;
@ -274,6 +282,12 @@ and height.
TPixel32 getNoteColor(int colorIndex) const;
void setNoteColor(TPixel32 color, int colorIndex);
QList<CellMark> getCellMarks() const;
CellMark getCellMark(int index) const;
void setCellMark(const CellMark &mark, int index);
bool hasDefaultCellMarks()
const; // check if the cell mark settings are modified
private:
// not implemented
TSceneProperties(const TSceneProperties &);

View file

@ -89,10 +89,11 @@ time, to unlock a possibly useful memory block.
*/
CleanupPreprocessedImage *process(TRasterImageP &image, bool first_image,
TRasterImageP &onlyResampledImage,
bool isCameraTest = false,
bool returnResampled = false,
bool onlyForSwatch = false,
TAffine *aff = 0);
bool isCameraTest = false,
bool returnResampled = false,
bool onlyForSwatch = false,
TAffine *aff = 0,
TRasterP templateForResampled = 0);
void finalize(const TRaster32P &dst, CleanupPreprocessedImage *src);
TToonzImageP finalize(CleanupPreprocessedImage *src,

View file

@ -9,6 +9,7 @@
class ToonzScene;
class TSceneProperties;
class FilePathProperties;
#undef DVAPI
#undef DVVAR
@ -28,6 +29,8 @@ class DVAPI TProject final : public TSmartObject {
bool m_useSubScenePath;
TSceneProperties *m_sprop;
FilePathProperties *m_fpProp;
public:
// default folders names
static const std::string Inputs;
@ -70,6 +73,8 @@ public:
void setSceneProperties(const TSceneProperties &sprop);
const TSceneProperties &getSceneProperties() const { return *m_sprop; }
FilePathProperties *getFilePathProperties() const { return m_fpProp; }
//?????????????????????????????????????????????
void setUseScenePath(std::string folderName, bool on);
//?????????????????????????????????????????????

View file

@ -9,6 +9,7 @@
#include <QPair>
#include <QString>
#include <QMap>
#undef DVAPI
#undef DVVAR
@ -304,6 +305,9 @@ protected:
std::vector<TXshCell> m_cells;
int m_first;
// cell marks information key:frame value:id
QMap<int, int> m_cellMarkIds;
public:
/*!
Constructs a TXshCellColumn with default value.
@ -398,6 +402,13 @@ last row with not empty cell of same level.
bool getLevelRange(int row, int &r0, int &r1) const override;
// virtual void updateIcon() = 0;
void saveCellMarks(TOStream &os);
bool loadCellMarks(std::string tagName, TIStream &is);
void setCellMark(int frame, int id);
int getCellMark(int frame) const;
QMap<int, int> getCellMarks() const;
void clearCellMarks();
};
#endif

View file

@ -442,8 +442,9 @@ frame duplication.
// cutomized exposseLevel used from LoadLevel command
int exposeLevel(int row, int col, TXshLevel *xl, std::vector<TFrameId> &fIds_,
int xFrom = -1, int xTo = -1, int step = -1, int inc = -1,
int frameCount = -1, bool doesFileActuallyExist = true);
TFrameId xFrom = TFrameId(), TFrameId xTo = TFrameId(),
int step = -1, int inc = -1, int frameCount = -1,
bool doesFileActuallyExist = true);
/*! Exposes level \b \e xl \b \e fids in xsheet starting from cell identified
* by \b \e row and \b \e col.

View file

@ -202,7 +202,8 @@ table) it returns the proper insertion index
// load icon (and image) data of all frames into cache
void loadAllIconsAndPutInCache(bool cacheImagesAsWell);
TRasterImageP getFrameToCleanup(const TFrameId &fid) const;
TRasterImageP getFrameToCleanup(const TFrameId &fid,
bool toBeLineProcessed) const;
std::string getImageId(const TFrameId &fid, int frameStatus = -1) const;
std::string getIconId(const TFrameId &fid, int frameStatus = -1) const;

View file

@ -65,7 +65,8 @@ enum CommandType {
MiscCommandType,
MenuCommandType,
VisualizationButtonCommandType,
StopMotionCommandType
StopMotionCommandType,
CellMarkCommandType
};
//-----------------------------------------------------------------------------

View file

@ -160,19 +160,24 @@ QString fidsToString(const std::vector<TFrameId> &fids,
} else {
bool beginBlock = true;
for (int f = 0; f < fids.size() - 1; f++) {
int num = fids[f].getNumber();
int next_num = fids[f + 1].getNumber();
if (num + 1 == next_num) {
int num = fids[f].getNumber();
QString letter = fids[f].getLetter();
int next_num = fids[f + 1].getNumber();
QString next_letter = fids[f + 1].getLetter();
if (num + 1 == next_num && letter.isEmpty() && next_letter.isEmpty()) {
if (beginBlock) {
retStr += QString::number(num) + " - ";
beginBlock = false;
}
} else {
retStr += QString::number(num) + ", ";
retStr += QString::number(num);
if (!letter.isEmpty()) retStr += letter;
retStr += ", ";
beginBlock = true;
}
}
retStr += QString::number(fids.back().getNumber());
if (!fids.back().getLetter().isEmpty()) retStr += fids.back().getLetter();
}
return retStr;
}

View file

@ -666,42 +666,46 @@ void StopMotionSaveInFolderPopup::updateParentFolder() {
//=============================================================================
FrameNumberLineEdit::FrameNumberLineEdit(QWidget *parent, int value)
FrameNumberLineEdit::FrameNumberLineEdit(QWidget* parent, TFrameId fId,
bool acceptLetter)
: LineEdit(parent) {
setFixedWidth(54);
m_intValidator = new QIntValidator(this);
setValue(value);
m_intValidator->setRange(1, 9999);
setFixedWidth(60);
if (acceptLetter) {
QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr());
m_regexpValidator = new QRegExpValidator(QRegExp(regExpStr), this);
TProjectManager* pm = TProjectManager::instance();
pm->addListener(this);
} else
m_regexpValidator = new QRegExpValidator(QRegExp("^\\d{1,4}$"), this);
QRegExp rx("^[0-9]{1,4}[A-Ia-i]?$");
m_regexpValidator = new QRegExpValidator(rx, this);
m_regexpValidator_alt =
new QRegExpValidator(QRegExp("^\\d{1,3}[A-Ia-i]?$"), this);
updateValidator();
setValue(fId);
}
//-----------------------------------------------------------------------------
void FrameNumberLineEdit::updateValidator() {
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled())
setValidator(m_regexpValidator);
setValidator(m_regexpValidator_alt);
else
setValidator(m_intValidator);
setValidator(m_regexpValidator);
}
//-----------------------------------------------------------------------------
void FrameNumberLineEdit::setValue(int value) {
if (value <= 0)
value = 1;
else if (value > 9999)
value = 9999;
void FrameNumberLineEdit::setValue(TFrameId fId) {
QString str;
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) {
str = convertToFrameWithLetter(value, 3);
if (!fId.getLetter().isEmpty()) {
// need some warning?
}
str = convertToFrameWithLetter(fId.getNumber(), 3);
} else {
str.setNum(value);
while (str.length() < 4) str.push_front("0");
str = QString::fromStdString(fId.expand());
}
setText(str);
setCursorPosition(0);
@ -709,22 +713,44 @@ void FrameNumberLineEdit::setValue(int value) {
//-----------------------------------------------------------------------------
int FrameNumberLineEdit::getValue() {
TFrameId FrameNumberLineEdit::getValue() {
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) {
QString str = text();
int f;
// if no letters added
if (str.at(str.size() - 1).isDigit())
return str.toInt() * 10;
f = str.toInt() * 10;
else {
return str.left(str.size() - 1).toInt() * 10 +
letterToNum(str.at(str.size() - 1));
f = str.left(str.size() - 1).toInt() * 10 +
letterToNum(str.at(str.size() - 1));
}
} else
return text().toInt();
return TFrameId(f);
} else {
QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr());
QRegExp rx(regExpStr);
int pos = rx.indexIn(text());
if (pos < 0) return TFrameId();
if (rx.cap(2).isEmpty())
return TFrameId(rx.cap(1).toInt());
else
return TFrameId(rx.cap(1).toInt(), rx.cap(2));
}
}
//-----------------------------------------------------------------------------
void FrameNumberLineEdit::onProjectSwitched() {
QRegExpValidator* oldValidator = m_regexpValidator;
QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr());
m_regexpValidator = new QRegExpValidator(QRegExp(regExpStr), this);
updateValidator();
if (oldValidator) delete oldValidator;
}
void FrameNumberLineEdit::onProjectChanged() { onProjectSwitched(); }
//-----------------------------------------------------------------------------
void FrameNumberLineEdit::focusInEvent(QFocusEvent *e) {
m_textOnFocusIn = text();
}
@ -3578,7 +3604,7 @@ void StopMotionController::onFileTypeActivated() {
//-----------------------------------------------------------------------------
void StopMotionController::onFrameNumberChanged() {
m_stopMotion->setFrameNumber(m_frameNumberEdit->getValue());
m_stopMotion->setFrameNumber(m_frameNumberEdit->getValue().getNumber());
}
//-----------------------------------------------------------------------------

View file

@ -8,6 +8,9 @@
#include "toonzqt/dvdialog.h"
#include "toonzqt/lineedit.h"
#include "tfilepath.h"
#include "toonz/tproject.h"
// TnzQt includes
#include "toonzqt/tabbar.h"
#include "toonzqt/gutil.h"
@ -69,23 +72,28 @@ class IntLineEdit;
// "Show ABC Appendix to the Frame Number in Xsheet Cell" is active.
//-----------------------------------------------------------------------------
class FrameNumberLineEdit : public DVGui::LineEdit {
class FrameNumberLineEdit : public DVGui::LineEdit,
public TProjectManager::Listener {
Q_OBJECT
/* having two validators and switch them according to the preferences*/
QIntValidator *m_intValidator;
QRegExpValidator *m_regexpValidator;
QRegExpValidator *m_regexpValidator, *m_regexpValidator_alt;
void updateValidator();
QString m_textOnFocusIn;
public:
FrameNumberLineEdit(QWidget *parent = 0, int value = 1);
FrameNumberLineEdit(QWidget* parent = 0, TFrameId fId = TFrameId(1),
bool acceptLetter = true);
~FrameNumberLineEdit() {}
/*! Set text in field to \b value. */
void setValue(int value);
void setValue(TFrameId fId);
/*! Return an integer with text field value. */
int getValue();
TFrameId getValue();
// TProjectManager::Listener
void onProjectSwitched() override;
void onProjectChanged() override;
protected:
/*! If focus is lost and current text value is out of range emit signal

View file

@ -411,7 +411,10 @@ static void cleanupLevel(TXshSimpleLevel *xl, std::set<TFrameId> fidsInXsheet,
QString::fromStdString(fid.expand()));
continue;
}
TRasterImageP original = xl->getFrameToCleanup(fid);
CleanupParameters *params = scene->getProperties()->getCleanupParameters();
// if lines are not processed, obtain the original sampled image
bool toBeLineProcessed = params->m_lineProcessingMode != lpNone;
TRasterImageP original = xl->getFrameToCleanup(fid, toBeLineProcessed);
if (!original) {
string err = " *error* missed frame";
m_userLog.error(err);
@ -419,11 +422,9 @@ static void cleanupLevel(TXshSimpleLevel *xl, std::set<TFrameId> fidsInXsheet,
continue;
}
CleanupParameters *params = scene->getProperties()->getCleanupParameters();
if (params->m_lineProcessingMode == lpNone) {
TRasterImageP ri;
if (params->m_autocenterType == CleanupTypes::AUTOCENTER_NONE)
TRasterImageP ri(original);
/*if (params->m_autocenterType == CleanupTypes::AUTOCENTER_NONE)
ri = original;
else {
bool autocentered;
@ -432,7 +433,9 @@ static void cleanupLevel(TXshSimpleLevel *xl, std::set<TFrameId> fidsInXsheet,
m_userLog.error("The autocentering failed on the current drawing.");
cout << "The autocentering failed on the current drawing." << endl;
}
}
}*/
cl->process(original, false, ri, false, true, true, nullptr,
ri->getRaster());
updater.update(fid, ri);
continue;
}

View file

@ -102,8 +102,8 @@ TFrameId getNewFrameId(TXshSimpleLevel *sl, int row) {
TFrameId fid(row + 1);
if (sl->isFid(fid)) {
fid = TFrameId(fid.getNumber(), 'a');
while (fid.getLetter() < 'z' && sl->isFid(fid))
fid = TFrameId(fid.getNumber(), fid.getLetter() + 1);
while (fid.getLetter().toUtf8().at(0) < 'z' && sl->isFid(fid))
fid = TFrameId(fid.getNumber(), fid.getLetter().toUtf8().at(0) + 1);
}
return fid;
}
@ -123,9 +123,15 @@ TFrameId getDesiredFId(TXshCellColumn *column, int r0, TXshSimpleLevel *sl,
if (neighborFId.isEmptyFrame()) neighborFId = tmpFId;
if (maxFId < tmpFId) maxFId = tmpFId;
}
if (maxFId.getLetter() && maxFId.getLetter() < 'z' && maxFId == neighborFId)
return TFrameId(maxFId.getNumber(), maxFId.getLetter() + 1);
else
QByteArray suffix = maxFId.getLetter().toUtf8();
// increment letter
if (suffix.size() == 1 &&
((suffix.at(0) >= 'A' && suffix.at(0) < 'Z') ||
(suffix.at(0) >= 'a' && suffix.at(0) < 'z')) &&
maxFId == neighborFId) {
return TFrameId(maxFId.getNumber(), suffix.at(0) + 1);
} else
return TFrameId(maxFId.getNumber() + 1);
}

View file

@ -1827,6 +1827,15 @@ bool ToolUtils::doUpdateXSheet(TXshSimpleLevel *sl,
bool ToolUtils::renumberForInsertFId(TXshSimpleLevel *sl, const TFrameId &fid,
const TFrameId &maxFid, TXsheet *xsh) {
auto getNextLetter = [](const QString &letter) {
if (letter.isEmpty()) return QString('a');
if (letter == 'z' || letter == 'Z') return QString();
QByteArray byteArray = letter.toUtf8();
// return incrementing the last letter
byteArray.data()[byteArray.size() - 1]++;
return QString::fromUtf8(byteArray);
};
std::vector<TFrameId> fids;
std::vector<TFrameId> oldFrames;
sl->getFids(oldFrames);
@ -1840,10 +1849,10 @@ bool ToolUtils::renumberForInsertFId(TXshSimpleLevel *sl, const TFrameId &fid,
for (auto itr = fidsSet.upper_bound(maxFid); itr != fidsSet.end(); ++itr) {
if (*itr > tmpFid) break;
fIdsToBeShifted.push_back(*itr);
if (fid.getLetter()) {
if ((*itr).getLetter() < 'z')
tmpFid = TFrameId((*itr).getNumber(),
((*itr).getLetter()) ? (*itr).getLetter() + 1 : 'a');
if (!fid.getLetter().isEmpty()) {
QString nextLetter = getNextLetter((*itr).getLetter());
if (!nextLetter.isEmpty())
tmpFid = TFrameId((*itr).getNumber(), nextLetter);
else
tmpFid = TFrameId((*itr).getNumber() + 1);
} else
@ -1854,11 +1863,10 @@ bool ToolUtils::renumberForInsertFId(TXshSimpleLevel *sl, const TFrameId &fid,
for (TFrameId &tmpFid : fids) {
if (fIdsToBeShifted.contains(tmpFid)) {
if (fid.getLetter()) {
if (tmpFid.getLetter() < 'z')
tmpFid =
TFrameId(tmpFid.getNumber(),
(tmpFid.getLetter()) ? tmpFid.getLetter() + 1 : 'a');
if (!fid.getLetter().isEmpty()) {
QString nextLetter = getNextLetter(tmpFid.getLetter());
if (!nextLetter.isEmpty())
tmpFid = TFrameId(tmpFid.getNumber(), nextLetter);
else
tmpFid = TFrameId(tmpFid.getNumber() + 1);
} else

View file

@ -66,29 +66,46 @@ AudioRecordingPopup::AudioRecordingPopup()
m_saveButton = new QPushButton(tr("Save and Insert"));
m_pauseRecordingButton = new QPushButton(this);
m_pausePlaybackButton = new QPushButton(this);
// m_refreshDevicesButton = new QPushButton(tr("Refresh"));
m_duration = new QLabel("00:00");
m_playDuration = new QLabel("00:00");
m_refreshDevicesButton = new QPushButton(this);
m_duration = new QLabel("00:00.000");
m_playDuration = new QLabel("00:00.000");
m_deviceListCB = new QComboBox();
m_audioLevelsDisplay = new AudioLevelsDisplay(this);
m_playXSheetCB = new QCheckBox(tr("Sync with Scene"), this);
m_playXSheetCB = new QCheckBox(tr("Sync with XSheet/Timeline"), this);
m_timer = new QElapsedTimer();
m_recordedLevels = QMap<qint64, double>();
m_oldElapsed = 0;
m_probe = new QAudioProbe;
m_player = new QMediaPlayer(this);
m_console = FlipConsole::getCurrent();
m_audioRecorder = new QAudioRecorder;
m_recordButton->setMaximumWidth(25);
m_playButton->setMaximumWidth(25);
m_pauseRecordingButton->setMaximumWidth(25);
m_pausePlaybackButton->setMaximumWidth(25);
m_labelDevice = new QLabel(tr("Device: "));
m_labelSamplerate = new QLabel(tr("Sample rate: "));
m_labelSamplefmt = new QLabel(tr("Sample format: "));
m_comboSamplerate = new QComboBox();
m_comboSamplefmt = new QComboBox();
m_comboSamplerate->addItem(tr("8000 Hz"), QVariant::fromValue(8000));
m_comboSamplerate->addItem(tr("11025 Hz"), QVariant::fromValue(11025));
m_comboSamplerate->addItem(tr("22050 Hz"), QVariant::fromValue(22050));
m_comboSamplerate->addItem(tr("44100 Hz"), QVariant::fromValue(44100));
m_comboSamplerate->addItem(tr("48000 Hz"), QVariant::fromValue(48000));
m_comboSamplerate->addItem(tr("96000 Hz"), QVariant::fromValue(96000));
m_comboSamplerate->setCurrentIndex(3); // 44.1KHz
m_comboSamplefmt->addItem(tr("Mono 8-Bits"), QVariant::fromValue(9));
m_comboSamplefmt->addItem(tr("Stereo 8-Bits"), QVariant::fromValue(10));
m_comboSamplefmt->addItem(tr("Mono 16-Bits"), QVariant::fromValue(17));
m_comboSamplefmt->addItem(tr("Stereo 16-Bits"), QVariant::fromValue(18));
m_comboSamplefmt->setCurrentIndex(2); // Mono 16-Bits
m_recordButton->setMaximumWidth(32);
m_playButton->setMaximumWidth(32);
m_pauseRecordingButton->setMaximumWidth(32);
m_pausePlaybackButton->setMaximumWidth(32);
m_refreshDevicesButton->setMaximumWidth(25);
QString playDisabled = QString(":Resources/play_disabled.svg");
QString pauseDisabled = QString(":Resources/pause_disabled.svg");
QString stopDisabled = QString(":Resources/stop_disabled.svg");
QString recordDisabled = QString(":Resources/record_disabled.svg");
QString refreshDisabled = QString(":Resources/repeat_icon.svg");
m_pauseIcon = createQIcon("pause");
m_pauseIcon.addFile(pauseDisabled, QSize(), QIcon::Disabled);
@ -98,6 +115,9 @@ AudioRecordingPopup::AudioRecordingPopup()
m_recordIcon.addFile(recordDisabled, QSize(), QIcon::Disabled);
m_stopIcon = createQIcon("stop");
m_stopIcon.addFile(stopDisabled, QSize(), QIcon::Disabled);
m_refreshIcon = createQIcon("repeat");
m_refreshIcon.addFile(refreshDisabled, QSize(), QIcon::Disabled);
m_pauseRecordingButton->setIcon(m_pauseIcon);
m_pauseRecordingButton->setIconSize(QSize(17, 17));
m_playButton->setIcon(m_playIcon);
@ -106,12 +126,32 @@ AudioRecordingPopup::AudioRecordingPopup()
m_recordButton->setIconSize(QSize(17, 17));
m_pausePlaybackButton->setIcon(m_pauseIcon);
m_pausePlaybackButton->setIconSize(QSize(17, 17));
m_refreshDevicesButton->setIcon(m_refreshIcon);
m_refreshDevicesButton->setIconSize(QSize(17, 17));
QStringList inputs = m_audioRecorder->audioInputs();
m_deviceListCB->addItems(inputs);
QString selectedInput = m_audioRecorder->defaultAudioInput();
m_deviceListCB->setCurrentText(selectedInput);
m_audioRecorder->setAudioInput(selectedInput);
// Enumerate devices and initialize default device
enumerateAudioDevices("");
QAudioDeviceInfo m_audioDeviceInfo = QAudioDeviceInfo::defaultInputDevice();
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(1);
format.setSampleSize(16);
format.setSampleType(QAudioFormat::SignedInt);
format.setByteOrder(QAudioFormat::LittleEndian);
format.setCodec("audio/pcm");
if (!m_audioDeviceInfo.isFormatSupported(format)) {
format = m_audioDeviceInfo.nearestFormat(format);
}
m_audioInput = new QAudioInput(m_audioDeviceInfo, format);
m_audioWriterWAV = new AudioWriterWAV(format);
// Tool tips to provide additional info to the user
m_deviceListCB->setToolTip(tr("Audio input device to record"));
m_comboSamplerate->setToolTip(tr("Number of samples per second, 44.1KHz = CD Quality"));
m_comboSamplefmt->setToolTip(tr("Number of channels and bits per sample, 16-bits recommended"));
m_playXSheetCB->setToolTip(tr("Play animation from current frame while recording/playback"));
m_saveButton->setToolTip(tr("Save recording and insert into new column"));
m_refreshDevicesButton->setToolTip(tr("Refresh list of connected audio input devices"));
m_topLayout->setMargin(5);
m_topLayout->setSpacing(8);
@ -124,11 +164,19 @@ AudioRecordingPopup::AudioRecordingPopup()
recordGridLay->setHorizontalSpacing(2);
recordGridLay->setVerticalSpacing(3);
{
recordGridLay->addWidget(m_deviceListCB, 0, 0, 1, 4, Qt::AlignCenter);
// recordGridLay->addWidget(m_refreshDevicesButton, 0, 3, Qt::AlignLeft);
recordGridLay->addWidget(new QLabel(tr(" ")), 1, 0, Qt::AlignCenter);
recordGridLay->addWidget(m_audioLevelsDisplay, 2, 0, 1, 4,
recordGridLay->addWidget(m_labelDevice, 0, 0, 1, 2, Qt::AlignRight);
recordGridLay->addWidget(m_deviceListCB, 0, 2, 1, 2, Qt::AlignLeft);
recordGridLay->addWidget(m_labelSamplerate, 1, 0, 1, 2, Qt::AlignRight);
recordGridLay->addWidget(m_comboSamplerate, 1, 2, 1, 1, Qt::AlignLeft);
recordGridLay->addWidget(m_refreshDevicesButton, 1, 3, Qt::AlignRight);
recordGridLay->addWidget(m_labelSamplefmt, 2, 0, 1, 2, Qt::AlignRight);
recordGridLay->addWidget(m_comboSamplefmt, 2, 2, 1, 2, Qt::AlignLeft);
recordGridLay->addWidget(m_audioLevelsDisplay, 3, 0, 1, 4,
Qt::AlignCenter);
recordGridLay->addWidget(m_playXSheetCB, 4, 0, 1, 5, Qt::AlignCenter);
QHBoxLayout *recordLay = new QHBoxLayout();
recordLay->setSpacing(4);
recordLay->setContentsMargins(0, 0, 0, 0);
@ -139,7 +187,7 @@ AudioRecordingPopup::AudioRecordingPopup()
recordLay->addWidget(m_duration);
recordLay->addStretch();
}
recordGridLay->addLayout(recordLay, 3, 0, 1, 4, Qt::AlignCenter);
recordGridLay->addLayout(recordLay, 5, 0, 1, 4, Qt::AlignCenter);
QHBoxLayout *playLay = new QHBoxLayout();
playLay->setSpacing(4);
playLay->setContentsMargins(0, 0, 0, 0);
@ -150,11 +198,9 @@ AudioRecordingPopup::AudioRecordingPopup()
playLay->addWidget(m_playDuration);
playLay->addStretch();
}
recordGridLay->addLayout(playLay, 4, 0, 1, 4, Qt::AlignCenter);
recordGridLay->addWidget(new QLabel(tr(" ")), 5, 0, Qt::AlignCenter);
recordGridLay->addWidget(m_saveButton, 6, 0, 1, 4,
Qt::AlignCenter | Qt::AlignVCenter);
recordGridLay->addWidget(m_playXSheetCB, 7, 0, 1, 4,
recordGridLay->addLayout(playLay, 6, 0, 1, 4, Qt::AlignCenter);
recordGridLay->addWidget(new QLabel(tr(" ")), 7, 0, Qt::AlignCenter);
recordGridLay->addWidget(m_saveButton, 8, 0, 1, 4,
Qt::AlignCenter | Qt::AlignVCenter);
}
recordGridLay->setColumnStretch(0, 0);
@ -172,23 +218,6 @@ AudioRecordingPopup::AudioRecordingPopup()
m_playXSheetCB->setChecked(true);
m_probe->setSource(m_audioRecorder);
QAudioEncoderSettings audioSettings;
audioSettings.setCodec("audio/PCM");
// setting the sample rate to some value (like 44100)
// may cause divide-by-zero crash in QAudioDeviceInfo::nearestFormat()
// so here we set the value to -1, as the documentation says;
// "A value of -1 indicates the encoder should make an optimal choice"
audioSettings.setSampleRate(-1);
audioSettings.setChannelCount(1);
audioSettings.setBitRate(16);
audioSettings.setEncodingMode(QMultimedia::ConstantBitRateEncoding);
audioSettings.setQuality(QMultimedia::HighQuality);
m_audioRecorder->setContainerFormat("wav");
m_audioRecorder->setEncodingSettings(audioSettings);
connect(m_probe, SIGNAL(audioBufferProbed(QAudioBuffer)), this,
SLOT(processBuffer(QAudioBuffer)));
connect(m_playXSheetCB, SIGNAL(stateChanged(int)), this,
SLOT(onPlayXSheetCBChanged(int)));
connect(m_saveButton, SIGNAL(clicked()), this, SLOT(onSaveButtonPressed()));
@ -199,16 +228,18 @@ AudioRecordingPopup::AudioRecordingPopup()
SLOT(onPauseRecordingButtonPressed()));
connect(m_pausePlaybackButton, SIGNAL(clicked()), this,
SLOT(onPausePlaybackButtonPressed()));
connect(m_audioRecorder, SIGNAL(durationChanged(qint64)), this,
connect(m_audioWriterWAV, SIGNAL(update(qint64)), this,
SLOT(updateRecordDuration(qint64)));
connect(m_console, SIGNAL(playStateChanged(bool)), this,
if (m_console) connect(m_console, SIGNAL(playStateChanged(bool)), this,
SLOT(onPlayStateChanged(bool)));
connect(m_deviceListCB, SIGNAL(currentTextChanged(const QString)), this,
SLOT(onInputDeviceChanged()));
// connect(m_refreshDevicesButton, SIGNAL(clicked()), this,
// SLOT(onRefreshButtonPressed()));
// connect(m_audioRecorder, SIGNAL(availableAudioInputsChanged()), this,
// SLOT(onRefreshButtonPressed()));
connect(m_refreshDevicesButton, SIGNAL(clicked()), this,
SLOT(onRefreshButtonPressed()));
connect(m_comboSamplerate, SIGNAL(currentTextChanged(const QString)), this,
SLOT(onAudioSettingChanged()));
connect(m_comboSamplefmt, SIGNAL(currentTextChanged(const QString)), this,
SLOT(onAudioSettingChanged()));
}
//-----------------------------------------------------------------------------
@ -218,11 +249,24 @@ AudioRecordingPopup::~AudioRecordingPopup() {}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::onRecordButtonPressed() {
if (m_audioRecorder->state() == QAudioRecorder::StoppedState) {
if (m_audioRecorder->status() == QMediaRecorder::UnavailableStatus) {
#if QT_VERSION >= 0x051000
if (m_audioInput->state() == QAudio::InterruptedState) {
DVGui::warning(
tr("The microphone is not available: "
"\nPlease select a different device or check the microphone."));
return;
} else if (m_audioInput->state() == QAudio::StoppedState) {
if (!m_console) {
DVGui::warning(
tr("Record failed: "
"\nMake sure there's XSheet or Timeline in the room."));
#else
if (m_audioInput->state() == QAudio::StoppedState) {
if (!m_console) {
DVGui::warning(
tr("The microphone is not available: "
"\nPlease select a different device or check the microphone."));
#endif
return;
}
// clear the player in case the file is open there
@ -236,25 +280,36 @@ void AudioRecordingPopup::onRecordButtonPressed() {
// (rarely)
// could cause a crash. I think OT tried to import the level before the
// final file was fully copied to the new location
m_audioRecorder->setOutputLocation(
QUrl::fromLocalFile(m_filePath.getQString()));
if (TSystem::doesExistFileOrLevel(m_filePath)) {
TSystem::removeFileOrLevel(m_filePath);
}
// The audio writer support either writing to buffer or directly to disk
// each method have their own pros and cons
// For now using false to mimic previous QAudioRecorder behaviour
m_audioWriterWAV->restart(m_audioInput->format());
if (!m_audioWriterWAV->start(m_filePath.getQString(), false)) {
DVGui::warning(
tr("Failed to save WAV file:\nMake sure you have write permissions "
"in folder."));
return;
}
m_recordButton->setIcon(m_stopIcon);
m_saveButton->setDisabled(true);
m_playButton->setDisabled(true);
m_pausePlaybackButton->setDisabled(true);
m_pauseRecordingButton->setEnabled(true);
m_deviceListCB->setDisabled(true);
m_refreshDevicesButton->setDisabled(true);
m_comboSamplerate->setDisabled(true);
m_comboSamplefmt->setDisabled(true);
m_recordedLevels.clear();
m_oldElapsed = 0;
m_pausedTime = 0;
m_startPause = 0;
m_endPause = 0;
m_stoppedAtEnd = false;
m_playDuration->setText("00:00");
m_playDuration->setText("00:00.000");
m_timer->restart();
m_audioRecorder->record();
m_audioInput->start(m_audioWriterWAV);
// this sometimes sets to one frame off, so + 1.
m_currentFrame = TApp::instance()->getCurrentFrame()->getFrame() + 1;
if (m_syncPlayback && !m_isPlaying) {
@ -264,13 +319,20 @@ void AudioRecordingPopup::onRecordButtonPressed() {
}
} else {
m_audioRecorder->stop();
m_audioLevelsDisplay->setLevel(0);
m_audioInput->stop();
bool success = m_audioWriterWAV->stop();
if (success) {
m_saveButton->setEnabled(true);
m_playButton->setEnabled(true);
}
m_audioLevelsDisplay->setLevel(-1, -1);
m_recordButton->setIcon(m_recordIcon);
m_saveButton->setEnabled(true);
m_playButton->setEnabled(true);
m_pauseRecordingButton->setDisabled(true);
m_pauseRecordingButton->setIcon(m_pauseIcon);
m_deviceListCB->setEnabled(true);
m_refreshDevicesButton->setEnabled(true);
m_comboSamplerate->setEnabled(true);
m_comboSamplefmt->setEnabled(true);
if (m_syncPlayback) {
if (m_isPlaying) {
m_console->pressButton(FlipConsole::ePause);
@ -279,21 +341,29 @@ void AudioRecordingPopup::onRecordButtonPressed() {
TApp::instance()->getCurrentFrame()->setCurrentFrame(m_currentFrame);
}
m_isPlaying = false;
if (!success) {
DVGui::warning(tr(
"Failed to save WAV file:\nMake sure you have write permissions in folder."));
}
}
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::updateRecordDuration(qint64 duration) {
// this is only called every second or so - sometimes duration ~= 950
// this gives some padding so it doesn't take two seconds to show one second
// has passed
if (duration % 1000 > 850) duration += 150;
int minutes = duration / 60000;
int seconds = (duration / 1000) % 60;
int milis = duration % 1000;
QString strMinutes = QString::number(minutes).rightJustified(2, '0');
QString strSeconds = QString::number(seconds).rightJustified(2, '0');
m_duration->setText(strMinutes + ":" + strSeconds);
QString strMilis = QString::number(milis).rightJustified(3, '0');
m_duration->setText(strMinutes + ":" + strSeconds + "." + strMilis);
// Show and record amplitude
qreal level = m_audioWriterWAV->level();
qreal peakL = m_audioWriterWAV->peakLevel();
m_audioLevelsDisplay->setLevel(level, peakL);
m_recordedLevels[duration / 20] = level;
}
//-----------------------------------------------------------------------------
@ -301,15 +371,17 @@ void AudioRecordingPopup::updateRecordDuration(qint64 duration) {
void AudioRecordingPopup::updatePlaybackDuration(qint64 duration) {
int minutes = duration / 60000;
int seconds = (duration / 1000) % 60;
int milis = duration % 1000;
QString strMinutes = QString::number(minutes).rightJustified(2, '0');
QString strSeconds = QString::number(seconds).rightJustified(2, '0');
m_playDuration->setText(strMinutes + ":" + strSeconds);
QString strMilis = QString::number(milis).rightJustified(3, '0');
m_playDuration->setText(strMinutes + ":" + strSeconds + "." + strMilis);
// the qmediaplayer probe doesn't work on all platforms, so we fake it by
// using
// a map that is made during recording
if (m_recordedLevels.contains(duration / 20)) {
m_audioLevelsDisplay->setLevel(m_recordedLevels.value(duration / 20));
m_audioLevelsDisplay->setLevel(m_recordedLevels.value(duration / 20), -1);
}
}
@ -328,6 +400,10 @@ void AudioRecordingPopup::onPlayButtonPressed() {
m_recordButton->setDisabled(true);
m_saveButton->setDisabled(true);
m_pausePlaybackButton->setEnabled(true);
m_deviceListCB->setDisabled(true);
m_refreshDevicesButton->setDisabled(true);
m_comboSamplerate->setDisabled(true);
m_comboSamplefmt->setDisabled(true);
m_stoppedAtEnd = false;
m_player->play();
// this sometimes sets to one frame off, so + 1.
@ -343,25 +419,29 @@ void AudioRecordingPopup::onPlayButtonPressed() {
m_playButton->setIcon(m_playIcon);
m_pausePlaybackButton->setDisabled(true);
m_pausePlaybackButton->setIcon(m_pauseIcon);
m_deviceListCB->setEnabled(true);
m_refreshDevicesButton->setEnabled(true);
m_comboSamplerate->setEnabled(true);
m_comboSamplefmt->setEnabled(true);
}
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::onPauseRecordingButtonPressed() {
if (m_audioRecorder->state() == QAudioRecorder::StoppedState) {
if (m_audioInput->state() == QAudio::StoppedState) {
return;
} else if (m_audioRecorder->state() == QAudioRecorder::PausedState) {
} else if (m_audioInput->state() == QAudio::SuspendedState) {
m_endPause = m_timer->elapsed();
m_pausedTime += m_endPause - m_startPause;
m_audioRecorder->record();
m_audioInput->resume();
m_pauseRecordingButton->setIcon(m_pauseIcon);
if (m_syncPlayback && !m_isPlaying && !m_stoppedAtEnd) {
m_console->pressButton(FlipConsole::ePlay);
m_isPlaying = true;
}
} else {
m_audioRecorder->pause();
m_audioInput->suspend();
m_pauseRecordingButton->setIcon(m_recordIcon);
m_startPause = m_timer->elapsed();
if (m_syncPlayback && m_isPlaying) {
@ -398,7 +478,7 @@ void AudioRecordingPopup::onPausePlaybackButtonPressed() {
void AudioRecordingPopup::onMediaStateChanged(QMediaPlayer::State state) {
// stopping can happen through the stop button or the file ending
if (state == QMediaPlayer::StoppedState) {
m_audioLevelsDisplay->setLevel(0);
m_audioLevelsDisplay->setLevel(-1, -1);
if (m_syncPlayback) {
if (m_isPlaying) {
m_console->pressButton(FlipConsole::ePause);
@ -410,6 +490,10 @@ void AudioRecordingPopup::onMediaStateChanged(QMediaPlayer::State state) {
m_pausePlaybackButton->setIcon(m_pauseIcon);
m_pausePlaybackButton->setDisabled(true);
m_recordButton->setEnabled(true);
m_deviceListCB->setEnabled(true);
m_refreshDevicesButton->setEnabled(true);
m_comboSamplerate->setEnabled(true);
m_comboSamplefmt->setEnabled(true);
m_saveButton->setEnabled(true);
m_isPlaying = false;
}
@ -426,36 +510,36 @@ void AudioRecordingPopup::onPlayXSheetCBChanged(int status) {
//-----------------------------------------------------------------------------
// Refresh isn't working right now, but I'm leaving the code in case a future
// change
// makes it work
void AudioRecordingPopup::onRefreshButtonPressed() {
QAudioDeviceInfo m_audioDeviceInfo =
m_deviceListCB->itemData(m_deviceListCB->currentIndex())
.value<QAudioDeviceInfo>();
// void AudioRecordingPopup::onRefreshButtonPressed() {
// m_deviceListCB->clear();
// QStringList inputs = m_audioRecorder->audioInputs();
// int count = inputs.count();
// m_deviceListCB->addItems(inputs);
// QString selectedInput = m_audioRecorder->defaultAudioInput();
// m_deviceListCB->setCurrentText(selectedInput);
//
//}
enumerateAudioDevices(m_audioDeviceInfo.deviceName());
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::onInputDeviceChanged() {
m_audioRecorder->setAudioInput(m_deviceListCB->currentText());
reinitAudioInput();
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::onAudioSettingChanged() {
reinitAudioInput();
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::onSaveButtonPressed() {
if (m_audioRecorder->state() != QAudioRecorder::StoppedState) {
m_audioRecorder->stop();
m_audioLevelsDisplay->setLevel(0);
if (m_audioInput->state() != QAudio::StoppedState) {
m_audioInput->stop();
m_audioLevelsDisplay->setLevel(-1, -1);
}
if (m_player->state() != QMediaPlayer::StoppedState) {
m_player->stop();
m_audioLevelsDisplay->setLevel(0);
m_audioLevelsDisplay->setLevel(-1, -1);
}
if (!TSystem::doesExistFileOrLevel(m_filePath)) return;
@ -499,31 +583,6 @@ void AudioRecordingPopup::makePaths() {
//-----------------------------------------------------------------------------
void AudioRecordingPopup::processBuffer(const QAudioBuffer &buffer) {
// keep from processing too many times
// get 50 signals per second
if (m_timer->elapsed() < m_oldElapsed + 20) return;
m_oldElapsed = m_timer->elapsed() - m_pausedTime;
qint16 value = 0;
if (!buffer.format().isValid() ||
buffer.format().byteOrder() != QAudioFormat::LittleEndian)
return;
if (buffer.format().codec() != "audio/pcm") return;
const qint16 *data = buffer.constData<qint16>();
qreal maxValue = 0;
qreal tempValue = 0;
for (int i = 0; i < buffer.frameCount(); ++i) {
tempValue = qAbs(qreal(data[i]));
if (tempValue > maxValue) maxValue = tempValue;
}
maxValue /= SHRT_MAX;
m_audioLevelsDisplay->setLevel(maxValue);
m_recordedLevels[m_oldElapsed / 20] = maxValue;
}
void AudioRecordingPopup::onPlayStateChanged(bool playing) {
// m_isPlaying = playing;
if (!playing && m_isPlaying) m_stoppedAtEnd = true;
@ -545,28 +604,254 @@ void AudioRecordingPopup::resetEverything() {
m_pauseRecordingButton->setIcon(m_pauseIcon);
m_pauseRecordingButton->setDisabled(true);
m_pausePlaybackButton->setDisabled(true);
m_deviceListCB->setEnabled(true);
m_refreshDevicesButton->setEnabled(true);
m_comboSamplerate->setEnabled(true);
m_comboSamplefmt->setEnabled(true);
m_recordedLevels.clear();
m_duration->setText("00:00");
m_playDuration->setText("00:00");
m_audioLevelsDisplay->setLevel(0);
m_duration->setText("00:00.000");
m_playDuration->setText("00:00.000");
m_audioLevelsDisplay->setLevel(-1, -1);
if (!m_console) {
m_console = FlipConsole::getCurrent();
if (m_console)
connect(m_console, SIGNAL(playStateChanged(bool)), this,
SLOT(onPlayStateChanged(bool)));
}
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::hideEvent(QHideEvent *event) {
if (m_audioRecorder->state() != QAudioRecorder::StoppedState) {
m_audioRecorder->stop();
if (m_audioInput->state() != QAudio::StoppedState) {
m_audioInput->stop();
m_audioWriterWAV->stop();
}
if (m_player->state() != QMediaPlayer::StoppedState) {
m_player->stop();
}
// make sure the file is freed before deleting
delete m_player;
m_player = new QMediaPlayer(this);
// this should only remove files that haven't been used in the scene
// make paths checks to only create path names that don't exist yet.
if (TSystem::doesExistFileOrLevel(TFilePath(m_filePath.getQString()))) {
TSystem::removeFileOrLevel(TFilePath(m_filePath.getQString()));
}
// Free up memory used in recording
m_recordedLevels.clear();
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::enumerateAudioDevices(const QString &selectedDeviceName) {
const QAudioDeviceInfo &defaultDeviceInfo =
QAudioDeviceInfo::defaultInputDevice();
m_blockAudioSettings = true;
m_deviceListCB->clear();
m_deviceListCB->addItem(defaultDeviceInfo.deviceName(),
QVariant::fromValue(defaultDeviceInfo));
for (auto &deviceInfo :
QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) {
if (deviceInfo != defaultDeviceInfo &&
m_deviceListCB->findText(deviceInfo.deviceName()) == -1) {
m_deviceListCB->addItem(deviceInfo.deviceName(),
QVariant::fromValue(deviceInfo));
}
}
int deviceIndex = m_deviceListCB->findText(selectedDeviceName);
if (deviceIndex != -1) m_deviceListCB->setCurrentIndex(deviceIndex);
m_blockAudioSettings = false;
}
//-----------------------------------------------------------------------------
void AudioRecordingPopup::reinitAudioInput() {
if (m_blockAudioSettings) return;
QAudioDeviceInfo m_audioDeviceInfo =
m_deviceListCB->itemData(m_deviceListCB->currentIndex())
.value<QAudioDeviceInfo>();
int samplerate =
m_comboSamplerate->itemData(m_comboSamplerate->currentIndex())
.value<int>();
int sampletype =
m_comboSamplefmt->itemData(m_comboSamplefmt->currentIndex()).value<int>();
int bitdepth = sampletype & 56;
int channels = sampletype & 7;
QAudioFormat format;
format.setSampleRate(samplerate);
format.setChannelCount(channels);
format.setSampleSize(bitdepth);
format.setSampleType(bitdepth == 8 ? QAudioFormat::UnSignedInt
: QAudioFormat::SignedInt);
format.setByteOrder(QAudioFormat::LittleEndian);
format.setCodec("audio/pcm");
if (!m_audioDeviceInfo.isFormatSupported(format)) {
DVGui::warning(tr(
"Audio format unsupported:\nNearest format will be internally used."));
format = m_audioDeviceInfo.nearestFormat(format);
}
// Recreate input
delete m_audioInput;
m_audioInput = new QAudioInput(m_audioDeviceInfo, format);
m_audioWriterWAV->restart(format);
}
//-----------------------------------------------------------------------------
// AudioWriterWAV Class
//-----------------------------------------------------------------------------
// IODevice to write standard WAV files, performs peak level calc
//
// 8-bits audio must be unsigned
// 16-bits audio must be signed
// 32-bits isn't supported
AudioWriterWAV::AudioWriterWAV(const QAudioFormat &format)
: m_level(0.0)
, m_peakL(0.0)
, m_maxAmp(0.0)
, m_wrRawB(0)
, m_wavFile(NULL)
, m_wavBuff(NULL) {
restart(format);
}
bool AudioWriterWAV::restart(const QAudioFormat &format) {
m_format = format;
if (m_format.sampleSize() == 8) {
m_rbytesms = 1000.0 / (m_format.sampleRate() * m_format.channelCount());
m_maxAmp = 127.0;
} else if (m_format.sampleSize() == 16) {
m_rbytesms = 500.0 / (m_format.sampleRate() * m_format.channelCount());
m_maxAmp = 32767.0;
} else {
// 32-bits isn't supported
m_rbytesms = 250.0 / (m_format.sampleRate() * m_format.channelCount());
m_maxAmp = 1.0;
}
m_wrRawB = 0;
m_peakL = 0.0;
if (m_wavBuff) m_wavBuff->clear();
return this->reset();
}
// Just a tiny define to avoid a magic number
// this is the size of a WAV header with PCM format
#define AWWAV_HEADER_SIZE 44
bool AudioWriterWAV::start(const QString &filename, bool useMem) {
open(QIODevice::WriteOnly);
m_filename = filename;
if (useMem) {
m_wavBuff = new QByteArray();
} else {
m_wavFile = new QFile(m_filename);
if (!m_wavFile->open(QIODevice::WriteOnly | QIODevice::Truncate))
return false;
m_wavFile->seek(AWWAV_HEADER_SIZE); // skip header
}
m_wrRawB = 0;
m_peakL = 0.0;
return true;
}
bool AudioWriterWAV::stop() {
close();
if (m_wavBuff) {
// Using memory
QFile file;
file.setFileName(m_filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return false;
writeWAVHeader(file);
file.write(m_wavBuff->constData(), m_wavBuff->size());
delete m_wavBuff;
m_wavBuff = NULL;
} else {
// Using disk directly
writeWAVHeader(*m_wavFile);
m_wavFile->close();
delete m_wavFile;
m_wavFile = NULL;
}
m_wrRawB = 0;
m_peakL = 0.0;
return true;
}
void AudioWriterWAV::writeWAVHeader(QFile &file) {
quint16 channels = m_format.channelCount();
quint32 samplerate = m_format.sampleRate();
quint16 bitrate = m_format.sampleSize();
qint64 pos = file.pos();
file.seek(0);
QDataStream out(&file);
out.setByteOrder(QDataStream::LittleEndian);
out.writeRawData("RIFF", 4);
out << (quint32)(m_wrRawB + AWWAV_HEADER_SIZE);
out.writeRawData("WAVEfmt ", 8);
out << (quint32)16 << (quint16)1; // magic numbers!
out << channels << samplerate;
out << quint32(samplerate * channels * bitrate / 8);
out << quint16(channels * bitrate / 8);
out << bitrate;
out.writeRawData("data", 4);
out << (quint32)m_wrRawB;
}
qint64 AudioWriterWAV::readData(char *data, qint64 maxlen) {
Q_UNUSED(data)
Q_UNUSED(maxlen)
return 0;
}
qint64 AudioWriterWAV::writeData(const char *data, qint64 len) {
int tmp, peak = 0.0;
// Measure peak
if (m_format.sampleSize() == 8) {
const quint8 *sdata = (const quint8 *)data;
int slen = len;
for (int i = 0; i < slen; ++i) {
tmp = qAbs<int>(sdata[i] - 128);
if (tmp > peak) peak = tmp;
}
} else if (m_format.sampleSize() == 16) {
const qint16 *sdata = (const qint16 *)data;
int slen = len / 2;
for (int i = 0; i < slen; ++i) {
tmp = qAbs<int>(sdata[i]);
if (tmp > peak) peak = tmp;
}
} else {
// 32-bits isn't supported
peak = -1;
}
m_level = qreal(peak) / m_maxAmp;
if (m_level > m_peakL) m_peakL = m_level;
// Write to memory or disk
if (m_wavBuff) {
m_wavBuff->append(data, len);
} else {
m_wavFile->write(data, len);
}
m_wrRawB += len;
// Emit an update
emit update(qreal(m_wrRawB) * m_rbytesms);
return len;
}
//-----------------------------------------------------------------------------
@ -574,14 +859,15 @@ void AudioRecordingPopup::hideEvent(QHideEvent *event) {
//-----------------------------------------------------------------------------
AudioLevelsDisplay::AudioLevelsDisplay(QWidget *parent)
: QWidget(parent), m_level(0.0) {
: QWidget(parent), m_level(0.0), m_peakL(0.0) {
setFixedHeight(20);
setFixedWidth(300);
}
void AudioLevelsDisplay::setLevel(qreal level) {
if (m_level != level) {
void AudioLevelsDisplay::setLevel(qreal level, qreal peakLevel) {
if (m_level != level || m_peakL != peakLevel) {
m_level = level;
m_peakL = peakLevel;
update();
}
}
@ -591,20 +877,29 @@ void AudioLevelsDisplay::paintEvent(QPaintEvent *event) {
QPainter painter(this);
QColor color;
if (m_level < 0.5) {
if (m_level < 0.0) {
return; // draw nothing...
} else if (m_level < 0.5) {
color = Qt::green;
}
else if (m_level < 0.75) {
} else if (m_level < 0.75) {
color = QColor(204, 205, 0); // yellow
} else if (m_level < 0.95) {
color = QColor(255, 115, 0); // orange
} else
color = Qt::red;
qreal widthLevel = m_level * width();
painter.fillRect(0, 0, widthLevel, height(), color);
int widthLevel = m_level * width();
int widthPeakL = m_peakL * width();
painter.fillRect(widthLevel, 0, width(), height(), Qt::black);
if (widthPeakL >= 0) {
if (m_peakL >= 0.995) {
painter.fillRect(width() - 4, 0, 4, height(), Qt::red);
} else {
painter.setPen(QColor(64, 64, 64)); // very dark gray
painter.drawLine(widthPeakL, 0, widthPeakL, height());
}
}
painter.fillRect(0, 0, widthLevel, height(), color);
}
//-----------------------------------------------------------------------------

View file

@ -15,14 +15,13 @@
class QComboBox;
class QCheckBox;
class QPushButton;
class QAudioRecorder;
class QLabel;
class AudioLevelsDisplay;
class FlipConsole;
class QAudioProbe;
class QAudioBuffer;
class QMediaPlayer;
class QElapsedTimer;
class AudioWriterWAV;
//=============================================================================
// AudioRecordingPopup
@ -31,24 +30,22 @@ class QElapsedTimer;
class AudioRecordingPopup : public DVGui::Dialog {
Q_OBJECT
QString m_deviceName;
QPushButton
*m_recordButton, // *m_refreshDevicesButton, -refresh not working for now
*m_recordButton, *m_refreshDevicesButton,
*m_playButton,
*m_pauseRecordingButton, *m_pausePlaybackButton, *m_saveButton;
QComboBox *m_deviceListCB;
QAudioRecorder *m_audioRecorder;
QAudioInput *m_audioInput;
AudioWriterWAV *m_audioWriterWAV;
QLabel *m_duration, *m_playDuration;
QCheckBox *m_playXSheetCB;
int m_currentFrame;
AudioLevelsDisplay *m_audioLevelsDisplay;
QAudioProbe *m_probe;
QMediaPlayer *m_player;
TFilePath m_filePath;
FlipConsole *m_console;
QElapsedTimer *m_timer;
QMap<qint64, double> m_recordedLevels;
qint64 m_oldElapsed;
qint64 m_startPause = 0;
qint64 m_endPause = 0;
qint64 m_pausedTime = 0;
@ -56,7 +53,11 @@ class AudioRecordingPopup : public DVGui::Dialog {
QIcon m_pauseIcon;
QIcon m_recordIcon;
QIcon m_stopIcon;
QIcon m_refreshIcon;
bool m_isPlaying, m_syncPlayback, m_stoppedAtEnd;
QLabel *m_labelDevice, *m_labelSamplerate, *m_labelSamplefmt;
QComboBox *m_comboSamplerate, *m_comboSamplefmt;
bool m_blockAudioSettings;
public:
AudioRecordingPopup();
@ -67,6 +68,8 @@ protected:
void hideEvent(QHideEvent *event);
void makePaths();
void resetEverything();
void enumerateAudioDevices(const QString &deviceName);
void reinitAudioInput();
private slots:
void onRecordButtonPressed();
@ -76,12 +79,47 @@ private slots:
void onSaveButtonPressed();
void onPauseRecordingButtonPressed();
void onPausePlaybackButtonPressed();
void processBuffer(const QAudioBuffer &buffer);
void onPlayStateChanged(bool playing);
void onPlayXSheetCBChanged(int status);
void onMediaStateChanged(QMediaPlayer::State state);
void onInputDeviceChanged();
// void onRefreshButtonPressed();
void onRefreshButtonPressed();
void onAudioSettingChanged();
};
//=============================================================================
// AudioWriterWAV
//-----------------------------------------------------------------------------
class AudioWriterWAV : public QIODevice {
Q_OBJECT
public:
AudioWriterWAV(const QAudioFormat &format);
bool restart(const QAudioFormat &format);
bool start(const QString &filename, bool useMem);
bool stop();
qint64 readData(char *data, qint64 maxlen) override;
qint64 writeData(const char *data, qint64 len) override;
qreal level() const { return m_level; }
qreal peakLevel() const { return m_peakL; }
private:
QString m_filename;
QFile *m_wavFile;
QByteArray *m_wavBuff; // if not null then use memory
QAudioFormat m_format;
quint64 m_wrRawB; // Written raw bytes
qreal m_rbytesms;
qreal m_maxAmp;
qreal m_level, m_peakL;
void writeWAVHeader(QFile &file);
signals:
void update(qint64 duration);
};
//=============================================================================
@ -94,12 +132,13 @@ public:
explicit AudioLevelsDisplay(QWidget *parent = 0);
// Using [0; 1.0] range
void setLevel(qreal level);
void setLevel(qreal level, qreal peak);
protected:
void paintEvent(QPaintEvent *event);
private:
qreal m_level;
qreal m_peakL;
};
#endif

View file

@ -196,9 +196,9 @@ AutoInputCellNumberPopup::AutoInputCellNumberPopup()
"AutoInputCellNumberPopup") {
setWindowTitle(tr("Auto Input Cell Number"));
m_from = new FrameNumberLineEdit(this);
m_from = new FrameNumberLineEdit(this, TFrameId(1), false);
m_increment = new DVGui::IntLineEdit(this, 0, 0);
m_to = new FrameNumberLineEdit(this);
m_to = new FrameNumberLineEdit(this, TFrameId(1), false);
m_interval = new DVGui::IntLineEdit(this, 0, 0);
m_step = new DVGui::IntLineEdit(this, 1, 1);
m_repeat = new DVGui::IntLineEdit(this, 1, 1);
@ -301,8 +301,8 @@ void AutoInputCellNumberPopup::doExecute(bool overwrite) {
}
AutoInputCellNumberUndo *undo = new AutoInputCellNumberUndo(
m_increment->getValue(), m_interval->getValue(), m_step->getValue(),
m_repeat->getValue(), m_from->getValue(), m_to->getValue(), r0, r1,
overwrite, columnIndices, levels);
m_repeat->getValue(), m_from->getValue().getNumber(),
m_to->getValue().getNumber(), r0, r1, overwrite, columnIndices, levels);
// if no cells will be arranged, then return
if (undo->rowsCount() == 0) {
DVGui::MsgBox(DVGui::WARNING,

View file

@ -3013,6 +3013,13 @@ static void dRenumberCells(int col, int r0, int r1) {
levelsTable[sl].push_back(std::make_pair(oldFid, newFid));
}
}
auto getNextLetter = [](const QString &letter) {
if (letter.isEmpty()) return QString('a');
QByteArray byteArray = letter.toUtf8();
// return incrementing the last letter
byteArray.data()[byteArray.size() - 1]++;
return QString::fromUtf8(byteArray);
};
// Ensure renumber consistency in case some destination fid would overwrite
// some unrenumbered fid in the level
@ -3022,8 +3029,7 @@ static void dRenumberCells(int col, int r0, int r1) {
if (cellsMap.find(it->second) == cellsMap.end() &&
it->first.getSimpleLevel()->isFid(it->second.getFrameId())) {
TFrameId &fid = it->second.m_frameId;
fid = TFrameId(fid.getNumber(),
fid.getLetter() ? fid.getLetter() + 1 : 'a',
fid = TFrameId(fid.getNumber(), getNextLetter(fid.getLetter()),
fid.getZeroPadding(), fid.getStartSeqInd());
}
}
@ -3218,8 +3224,8 @@ static void createNewDrawing(TXsheet *xsh, int row, int col,
TFrameId fid(row + 1);
if (sl->isFid(fid)) {
fid = TFrameId(fid.getNumber(), 'a');
while (fid.getLetter() < 'z' && sl->isFid(fid))
fid = TFrameId(fid.getNumber(), fid.getLetter() + 1);
while (fid.getLetter().toUtf8().at(0) < 'z' && sl->isFid(fid))
fid = TFrameId(fid.getNumber(), fid.getLetter().toUtf8().at(0) + 1);
}
// add the new frame
sl->setFrame(fid, sl->createEmptyFrame());

View file

@ -565,6 +565,8 @@ bool CleanupPopup::analyzeCleanupList() {
m_overwriteDialog->reset();
}
m_overwriteDialog->enableOptions(inputPath == outputPath);
// Prompt user for file conflict resolution
clt.m_resolution =
Resolution(m_overwriteDialog->execute(&clt.m_outputPath));
@ -634,7 +636,7 @@ bool CleanupPopup::analyzeCleanupList() {
TPointD outDpi;
m_params->getOutputImageInfo(outRes, outDpi.x, outDpi.y);
if (oldRes != outRes) {
if (oldRes != outRes && inputPath != outputPath) {
DVGui::warning(
tr("The resulting resolution of level \"%1\"\ndoes not match "
"with that of previously cleaned up level drawings.\n\nPlease "
@ -789,7 +791,13 @@ TImageP CleanupPopup::currentImage() const {
if (!isValidPosition(m_idx)) return TImageP();
const CleanupLevel &cl = m_cleanupLevels[m_idx.first];
return cl.m_sl->getFrameToCleanup(cl.m_frames[m_idx.second]);
// if lines are not processed, obtain the original sampled image
bool toBeLineProcessed =
TCleanupper::instance()->getParameters()->m_lineProcessingMode != lpNone;
return cl.m_sl->getFrameToCleanup(cl.m_frames[m_idx.second],
toBeLineProcessed);
}
//-----------------------------------------------------------------------------
@ -1195,19 +1203,35 @@ void CleanupPopup::cleanupFrame() {
TCleanupper *cl = TCleanupper::instance();
const CleanupParameters *params = cl->getParameters();
// Obtain the source dpi. Changed it to be done once at the first frame of
// each level in order to avoid the following problem:
// If the original raster level has no dpi (such as TGA images), obtaining
// dpi in every frame causes dpi mismatch between the first frame and the
// following frames, since the value
// TXshSimpleLevel::m_properties->getDpi() will be changed to the
// dpi of cleanup camera (= TLV's dpi) after finishing the first frame.
if (m_firstLevelFrame) {
TPointD dpi;
original->getDpi(dpi.x, dpi.y);
if (dpi.x == 0 && dpi.y == 0) dpi = sl->getProperties()->getDpi();
cl->setSourceDpi(dpi);
}
if (params->m_lineProcessingMode == lpNone) {
// No line processing
TRasterImageP ri(original);
if (params->m_autocenterType != CleanupTypes::AUTOCENTER_NONE) {
/*if (params->m_autocenterType != CleanupTypes::AUTOCENTER_NONE) {
bool autocentered;
ri = cl->autocenterOnly(original, false, autocentered);
if (!autocentered)
DVGui::warning(
QObject::tr("The autocentering failed on the current drawing."));
}
}*/
cl->process(original, false, ri, false, true, true, nullptr,
ri->getRaster());
sl->setFrame(fid, ri);
if (TRaster32P(ri->getRaster())) sl->setFrame(fid, ri);
// Update the associated file. In case the operation throws, oh well the
// image gets skipped.
@ -1220,20 +1244,6 @@ void CleanupPopup::cleanupFrame() {
} else {
// Perform main processing
// Obtain the source dpi. Changed it to be done once at the first frame of
// each level in order to avoid the following problem:
// If the original raster level has no dpi (such as TGA images), obtaining
// dpi in every frame causes dpi mismatch between the first frame and the
// following frames, since the value
// TXshSimpleLevel::m_properties->getDpi() will be changed to the
// dpi of cleanup camera (= TLV's dpi) after finishing the first frame.
if (m_firstLevelFrame) {
TPointD dpi;
original->getDpi(dpi.x, dpi.y);
if (dpi.x == 0 && dpi.y == 0) dpi = sl->getProperties()->getDpi();
cl->setSourceDpi(dpi);
}
CleanupPreprocessedImage *cpi;
{
TRasterImageP resampledRaster;
@ -1503,6 +1513,14 @@ void CleanupPopup::OverwriteDialog::reset() {
//-----------------------------------------------------------------------------
void CleanupPopup::OverwriteDialog::enableOptions(bool writingOnSource) {
if (writingOnSource && m_buttonGroup->button(REPLACE)->isChecked())
m_buttonGroup->button(OVERWRITE)->setChecked(true);
m_buttonGroup->button(REPLACE)->setDisabled(writingOnSource);
}
//-----------------------------------------------------------------------------
QString CleanupPopup::OverwriteDialog::acceptResolution(void *obj,
int resolution,
bool applyToAll) {

View file

@ -144,6 +144,7 @@ public:
OverwriteDialog();
void reset() override;
void enableOptions(bool writingOnSource);
private:
DVGui::LineEdit *m_suffix;

View file

@ -405,7 +405,7 @@ void CleanupSettingsModel::rebuildPreview() {
void CleanupSettingsModel::processFrame(TXshSimpleLevel *sl, TFrameId fid) {
assert(sl);
TRasterImageP imageToCleanup = sl->getFrameToCleanup(fid);
TRasterImageP imageToCleanup = sl->getFrameToCleanup(fid, true);
if (!imageToCleanup) return;
// Store the original image
@ -741,5 +741,6 @@ TFilePath CleanupSettingsModel::getOutputPath(TXshSimpleLevel *sl,
const TFilePath &outDir = params->getPath(scene);
return lineProcessing ? (outDir + inPath.getWideName()).withType("tlv")
: (outDir + inPath.getLevelNameW()).withType("tif");
: (outDir + inPath.getLevelNameW())
.withType(params->m_lpNoneFormat);
}

View file

@ -7,6 +7,7 @@
#include "toonz/tscenehandle.h"
#include "toonz/toonzscene.h"
#include "toonz/toonzfolders.h"
#include "toonz/cleanupcolorstyles.h"
// ToonzQt includes
#include "toonzqt/gutil.h"
@ -101,6 +102,8 @@ CleanupSettingsPane::CleanupSettingsPane(QWidget *parent)
m_aaValueLabel = new QLabel(tr("MLAA Intensity:"));
m_aaValue = new IntField(this);
m_lineProcessing = new QComboBox(this);
m_lpNoneFormatLabel = new QLabel(tr("Format:"));
m_lpNoneFormat = new QComboBox(this);
m_paletteViewer = new CleanupPaletteViewer(this);
m_pathField = new CleanupSaveInField(this, QString(""));
@ -143,6 +146,13 @@ CleanupSettingsPane::CleanupSettingsPane(QWidget *parent)
items << tr("None") << tr("Greyscale") << tr("Color");
m_lineProcessing->addItems(items);
items.clear();
items << "tif"
<< "png"
<< "jpg"
<< "tga";
m_lpNoneFormat->addItems(items);
m_sharpness->setValues(90, 0, 100);
m_despeckling->setValues(2, 0, 20);
m_aaValue->setValues(70, 0, 100);
@ -223,15 +233,15 @@ CleanupSettingsPane::CleanupSettingsPane(QWidget *parent)
lineProcLay->addWidget(m_aaValueLabel, 4, 0,
Qt::AlignRight | Qt::AlignVCenter);
lineProcLay->addWidget(m_aaValue, 4, 1);
lineProcLay->addWidget(m_lpNoneFormatLabel, 5, 0,
Qt::AlignRight | Qt::AlignVCenter);
lineProcLay->addWidget(m_lpNoneFormat, 5, 1,
Qt::AlignLeft | Qt::AlignVCenter);
lineProcLay->addWidget(m_paletteViewer, 5, 0, 1, 2);
lineProcLay->addWidget(m_paletteViewer, 6, 0, 1, 2);
}
lineProcLay->setRowStretch(0, 0);
lineProcLay->setRowStretch(1, 0);
lineProcLay->setRowStretch(2, 0);
lineProcLay->setRowStretch(3, 0);
lineProcLay->setRowStretch(4, 0);
lineProcLay->setRowStretch(5, 1);
for (int r = 0; r <= 5; r++) lineProcLay->setRowStretch(r, 0);
lineProcLay->setRowStretch(6, 1);
lineProcLay->setColumnStretch(0, 0);
lineProcLay->setColumnStretch(1, 1);
@ -286,6 +296,8 @@ CleanupSettingsPane::CleanupSettingsPane(QWidget *parent)
SLOT(onGenericSettingsChange()));
ret = ret && connect(m_lineProcessing, SIGNAL(activated(int)),
SLOT(onGenericSettingsChange()));
ret = ret && connect(m_lpNoneFormat, SIGNAL(activated(int)),
SLOT(onGenericSettingsChange()));
ret = ret && connect(m_despeckling, SIGNAL(valueChanged(bool)),
SLOT(onGenericSettingsChange()));
ret = ret && connect(m_aaValue, SIGNAL(valueChanged(bool)),
@ -404,6 +416,8 @@ void CleanupSettingsPane::updateGui(CleanupParameters *params,
m_sharpness->setValue(params->m_sharpness);
m_despeckling->setValue(params->m_despeckling);
m_aaValue->setValue(params->m_aaValue);
m_lpNoneFormat->setCurrentText(
QString::fromStdString(params->m_lpNoneFormat));
updateVisibility();
@ -462,6 +476,8 @@ void CleanupSettingsPane::updateVisibility() {
for (QWidget *w : m_lpWidgets) w->setVisible(lp);
m_aaValueLabel->setVisible(MLAA);
m_aaValue->setVisible(MLAA);
m_lpNoneFormatLabel->setVisible(!lp);
m_lpNoneFormat->setVisible(!lp);
m_paletteViewer->setMode(lpGrey);
m_paletteViewer->setContrastEnabled(m_antialias->currentIndex() == 0);
@ -525,15 +541,30 @@ void CleanupSettingsPane::onGenericSettingsChange() {
params->m_flipy = m_flipY->isChecked();
//------
params->m_lineProcessingMode = m_lineProcessing->currentIndex();
params->m_noAntialias = (m_antialias->currentIndex() > 0);
params->m_postAntialias = (m_antialias->currentIndex() == 2);
params->m_despeckling = m_despeckling->getValue();
params->m_aaValue = m_aaValue->getValue();
if (params->m_lineProcessingMode == lpNone)
params->m_transparencyCheckEnabled = false;
if (params->m_lineProcessingMode != m_lineProcessing->currentIndex()) {
int oldMode = params->m_lineProcessingMode;
params->m_lineProcessingMode = m_lineProcessing->currentIndex();
if (params->m_lineProcessingMode == lpNone) {
params->m_transparencyCheckEnabled = false;
}
// When switching from/to Greyscale processing, replace the brightness and
// contrast values by the registered ones.
if (oldMode == lpGrey || params->m_lineProcessingMode == lpGrey) {
TCleanupStyle *blackStyle =
dynamic_cast<TCleanupStyle *>(params->m_cleanupPalette->getStyle(1));
double b = params->m_altBrightness;
double c = params->m_altContrast;
params->m_altBrightness = blackStyle->getBrightness();
params->m_altContrast = blackStyle->getContrast();
blackStyle->setBrightness(b);
blackStyle->setContrast(c);
}
}
params->m_noAntialias = (m_antialias->currentIndex() > 0);
params->m_postAntialias = (m_antialias->currentIndex() == 2);
params->m_despeckling = m_despeckling->getValue();
params->m_aaValue = m_aaValue->getValue();
params->m_lpNoneFormat = m_lpNoneFormat->currentText().toStdString();
//------
m_cameraWidget->getFields(model->getCurrentParameters());

View file

@ -62,6 +62,8 @@ private:
QLabel *m_aaValueLabel;
DVGui::IntField *m_aaValue;
QComboBox *m_lineProcessing;
QLabel *m_lpNoneFormatLabel;
QComboBox *m_lpNoneFormat;
//----Cleanup Palette
CleanupPaletteViewer *m_paletteViewer;
//----Bottom Parts

View file

@ -45,6 +45,8 @@
// TnzBase includes
#include "tfx.h"
#include "tfxattributes.h"
#include "tparamcontainer.h"
#include "tparamset.h"
// TnzCore includes
#include "tstroke.h"
@ -100,9 +102,24 @@ void getColumnLinkedFxs(TFx *startFx, TFx *newStartFx,
}
}
//------------------------------------------------------
template <typename ParamCont>
void setGrammerToParams(const ParamCont *cont,
const TSyntax::Grammar *grammer) {
for (int p = 0; p != cont->getParamCount(); ++p) {
TParam &param = *cont->getParam(p);
if (TDoubleParam *dp = dynamic_cast<TDoubleParam *>(&param))
dp->setGrammar(grammer);
else if (TParamSet *paramSet = dynamic_cast<TParamSet *>(&param))
setGrammerToParams(paramSet, grammer);
}
}
//-----------------------------------------------------------------------------
void cloneNotColumnLinkedFxsAndOutputsFx(TXsheet *xsh, TXsheet *newXsh) {
void cloneNotColumnLinkedFxsAndOutputsFx(
TXsheet *xsh, TXsheet *newXsh, QMap<TFx *, TFx *> *fxTable = nullptr) {
int columnCount = xsh->getColumnCount();
assert(newXsh->getColumnCount() == columnCount);
@ -136,6 +153,9 @@ void cloneNotColumnLinkedFxsAndOutputsFx(TXsheet *xsh, TXsheet *newXsh) {
newFxDag->getInternalFxs()->addFx(newFx);
if (fxDag->getTerminalFxs()->containsFx(fx))
newFxDag->getTerminalFxs()->addFx(newFx);
// if the fx has not unique name then let assignUniqueId() set the default
// name
if (newFx->getName() == newFx->getFxId()) newFx->setName(L"");
newFxDag->assignUniqueId(newFx);
clonedFxs[fx] = newFx;
notColumnLinkedClonedFxs.append(newFx);
@ -203,6 +223,17 @@ void cloneNotColumnLinkedFxsAndOutputsFx(TXsheet *xsh, TXsheet *newXsh) {
newOutputFx->getInputPort(0)->setFx(newInputFx);
}
}
// reset grammers for all parameters of cloned fxs
// or they fails to refer to other parameters via expression
TSyntax::Grammar *grammer = newXsh->getStageObjectTree()->getGrammar();
QMap<TFx *, TFx *>::const_iterator it;
for (it = clonedFxs.constBegin(); it != clonedFxs.constEnd(); ++it) {
setGrammerToParams(it.value()->getParams(), grammer);
// register to the fx table for expression management
if (fxTable) fxTable->insert(it.key(), it.value());
}
}
//-----------------------------------------------------------------------------
@ -1077,11 +1108,13 @@ void ColumnCmd::cloneChild(int index) {
data->storeColumns(indices, childXsh, 0);
data->storeColumnFxs(indices, childXsh, 0);
std::list<int> restoredSplineIds;
QMap<TStageObjectId, TStageObjectId> idTable;
QMap<TFx *, TFx *> fxTable;
data->restoreObjects(indices, restoredSplineIds, newChildXsh,
StageObjectsData::eDoClone);
StageObjectsData::eDoClone, idTable, fxTable);
delete data;
cloneNotColumnLinkedFxsAndOutputsFx(childXsh, newChildXsh);
cloneNotColumnLinkedFxsAndOutputsFx(childXsh, newChildXsh, &fxTable);
cloneXsheetTStageObjectTree(childXsh, newChildXsh);
/*--以下は、Clone SubXsheet
SubXsheet内にある子SubXsheetをクローンする関数
@ -1094,6 +1127,10 @@ void ColumnCmd::cloneChild(int index) {
newChildXsh->getFxDag()->getXsheetFx()->getAttributes()->setDagNodePos(
childXsh->getFxDag()->getXsheetFx()->getAttributes()->getDagNodePos());
ExpressionReferenceManager::instance()->refreshXsheetRefInfo(newChildXsh);
ExpressionReferenceManager::instance()->transferReference(
childXsh, newChildXsh, idTable, fxTable);
newChildXsh->updateFrameCount();
/*-- TXshChildLevel作成時にsetCellした1つ目のセルを消去 --*/

View file

@ -23,6 +23,8 @@
#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"
@ -74,6 +76,8 @@ TEnv::IntVar XShPdfExportPrintSoundtrack("XShPdfExportPrintSoundtrack", 0);
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
@ -90,6 +94,12 @@ TEnv::StringVar XShPdfExportImgPath("XShPdfExportImgPath", "");
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 {
@ -287,6 +297,86 @@ XSheetPDFDataType dataStr2Type(const QString& str) {
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;
}
} // namespace
//---------------------------------------------------------
@ -652,7 +742,7 @@ void XSheetPDFTemplate::drawDialogBlock(QPainter& painter, const int framePage,
painter.restore();
// register sound cells
if (m_info.drawSound)
if (m_info.drawSound || m_noteColumn)
registerSoundRects(painter, param(DialogColWidth), bodyId);
}
painter.restore();
@ -859,7 +949,7 @@ void XSheetPDFTemplate::drawContinuousLine(QPainter& painter, QRect rect,
}
void XSheetPDFTemplate::drawCellNumber(QPainter& painter, QRect rect,
TXshCell& cell) {
TXshCell& cell, bool isKey) {
QFont font = painter.font();
font.setPixelSize(param(RowHeight) - mm2px(1));
font.setLetterSpacing(QFont::PercentageSpacing, 100);
@ -874,12 +964,38 @@ void XSheetPDFTemplate::drawCellNumber(QPainter& painter, QRect rect,
str = getFrameNumberWithLetters(cell.m_frameId.getNumber());
} else {
str = QString::number(cell.m_frameId.getNumber());
if (cell.m_frameId.getLetter() != '\0') str += cell.m_frameId.getLetter();
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 >= 0x051100
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());
@ -1024,6 +1140,153 @@ void XSheetPDFTemplate::drawSound(QPainter& painter, int framePage) {
}
}
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) {}
@ -1101,6 +1364,10 @@ void XSheetPDFTemplate::drawXsheetContents(QPainter& painter, int 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;
@ -1135,14 +1402,23 @@ void XSheetPDFTemplate::drawXsheetContents(QPainter& painter, int framePage,
TXshCell cell = column->getCell(f);
if (cell.m_level != level) cell.m_level = nullptr;
int markId = column->getCellMark(r);
// cotinuous line
if (r != 0 && r != 72 && prevCell == cell) {
if (drawCLFlag)
// draw tick mark
if (markId >= 0 && m_info.tick1MarkId == markId)
drawTickMark(painter, m_cellRects[c][r], m_info.tick1MarkType);
else if (markId >= 0 && m_info.tick2MarkId == markId)
drawTickMark(painter, m_cellRects[c][r], m_info.tick2MarkType);
else if (drawCLFlag)
drawContinuousLine(painter, m_cellRects[c][r], cell.isEmpty());
}
// draw cell
else {
drawCellNumber(painter, m_cellRects[c][r], cell);
bool drawKeyMark = (markId >= 0 && m_info.keyMarkId == markId);
drawCellNumber(painter, m_cellRects[c][r], cell, drawKeyMark);
drawCLFlag = (m_info.continuousLineMode == Line_Always)
? true
: (m_info.continuousLineMode == Line_None)
@ -1602,8 +1878,10 @@ ExportXsheetPdfPopup::ExportXsheetPdfPopup()
new QCheckBox(tr("Put Serial Frame Numbers Over Pages"), this);
m_levelNameOnBottomCB =
new QCheckBox(tr("Print Level Names On The Bottom"), this);
m_sceneNameEdit = new QLineEdit(this);
m_memoEdit = new QTextEdit(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);
@ -1620,6 +1898,15 @@ ExportXsheetPdfPopup::ExportXsheetPdfPopup()
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);
@ -1636,6 +1923,7 @@ ExportXsheetPdfPopup::ExportXsheetPdfPopup()
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);
@ -1747,22 +2035,44 @@ ExportXsheetPdfPopup::ExportXsheetPdfPopup()
exportLay->addWidget(m_continuousLineCombo, 2, 1, 1, 2,
Qt::AlignLeft | Qt::AlignVCenter);
exportLay->addWidget(m_addDateTimeCB, 3, 0, 1, 3,
Qt::AlignLeft | Qt::AlignVCenter);
exportLay->addWidget(m_addScenePathCB, 4, 0, 1, 3,
Qt::AlignLeft | Qt::AlignVCenter);
exportLay->addWidget(m_drawSoundCB, 5, 0, 1, 3,
Qt::AlignLeft | Qt::AlignVCenter);
exportLay->addWidget(m_addSceneNameCB, 6, 0, 1, 2,
Qt::AlignLeft | Qt::AlignVCenter);
exportLay->addWidget(m_sceneNameEdit, 6, 2,
Qt::AlignLeft | Qt::AlignVCenter);
exportLay->addWidget(m_levelNameOnBottomCB, 7, 0, 1, 3,
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("Memo:"), this), 8, 0,
exportLay->addWidget(new QLabel(tr("Inbetween mark:"), 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("Reverse sheet mark:"), 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, 8, 1, 1, 2);
exportLay->addWidget(m_memoEdit, 7, 1, 1, 2);
}
exportLay->setColumnStretch(2, 1);
exportGBox->setLayout(exportLay);
@ -1831,6 +2141,11 @@ ExportXsheetPdfPopup::ExportXsheetPdfPopup()
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)));
@ -1849,6 +2164,16 @@ ExportXsheetPdfPopup::ExportXsheetPdfPopup()
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
@ -1932,6 +2257,7 @@ void ExportXsheetPdfPopup::initialize() {
m_columns.clear();
m_soundColumns.clear();
m_noteColumns.clear();
for (int col = 0; col < xsheet->getColumnCount(); col++) {
if (xsheet->isColumnEmpty(col)) continue;
@ -1941,6 +2267,13 @@ void ExportXsheetPdfPopup::initialize() {
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
@ -1964,10 +2297,20 @@ void ExportXsheetPdfPopup::initialize() {
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
@ -1983,6 +2326,7 @@ void ExportXsheetPdfPopup::saveSettings() {
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 =
@ -1995,6 +2339,12 @@ void ExportXsheetPdfPopup::saveSettings() {
(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
@ -2013,6 +2363,7 @@ void ExportXsheetPdfPopup::loadSettings() {
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));
@ -2035,6 +2386,21 @@ void ExportXsheetPdfPopup::loadSettings() {
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() {
@ -2095,8 +2461,20 @@ void ExportXsheetPdfPopup::setInfo() {
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
@ -2364,6 +2742,15 @@ void ExportXsheetPdfPopup::onNext() {
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(

View file

@ -21,6 +21,7 @@ class QComboBox;
class QCheckBox;
class TXshLevelColumn;
class TXshSoundColumn;
class TXshSoundTextColumn;
namespace DVGui {
class FileField;
class ColorField;
@ -85,6 +86,12 @@ typedef void (*DecoFunc)(QPainter&, QRect, QMap<XSheetPDFDataType, QRect>&,
enum ExportArea { Area_Actions = 0, Area_Cells };
enum ContinuousLineMode { Line_Always = 0, Line_MoreThan3s, Line_None };
enum TickMarkType {
TickMark_Dot = 0,
TickMark_Circle,
TickMark_Filled,
TickMark_Asterisk
};
struct XSheetPDFFormatInfo {
QColor lineColor;
@ -101,6 +108,11 @@ struct XSheetPDFFormatInfo {
bool serialFrameNumber;
bool drawLevelNameOnBottom;
ContinuousLineMode continuousLineMode;
int tick1MarkId;
int tick2MarkId;
int keyMarkId;
TickMarkType tick1MarkType;
TickMarkType tick2MarkType;
};
class XSheetPDFTemplate {
@ -138,6 +150,7 @@ protected:
// column and column name (if manually specified)
QList<QPair<TXshLevelColumn*, QString>> m_columns;
QList<TXshSoundColumn*> m_soundColumns;
TXshSoundTextColumn* m_noteColumn;
int m_duration;
bool m_useExtraColumns;
@ -172,12 +185,15 @@ protected:
void addInfo(int w, QString lbl, DecoFunc f = nullptr);
void drawContinuousLine(QPainter& painter, QRect rect, bool isEmpty);
void drawCellNumber(QPainter& painter, QRect rect, TXshCell& cell);
void drawCellNumber(QPainter& painter, QRect rect, TXshCell& cell,
bool isKey);
void drawTickMark(QPainter& painter, QRect rect, TickMarkType type);
void drawEndMark(QPainter& painter, QRect upperRect);
void drawLevelName(QPainter& painter, QRect rect, QString name,
bool isBottom = false);
void drawLogo(QPainter& painter);
void drawSound(QPainter& painter, int framePage);
void drawDialogue(QPainter& painter, int framePage);
int param(const std::string& id, int defaultValue = 0) {
if (!m_params.contains(id)) std::cout << id << std::endl;
@ -201,6 +217,9 @@ public:
void setSoundColumns(const QList<TXshSoundColumn*>& soundColumns) {
m_soundColumns = soundColumns;
}
void setNoteColumn(TXshSoundTextColumn* noteColumn) {
m_noteColumn = noteColumn;
}
void setInfo(const XSheetPDFFormatInfo& info);
};
@ -262,11 +281,13 @@ class ExportXsheetPdfPopup final : public DVGui::Dialog {
XsheetPdfPreviewArea* m_previewArea;
DVGui::FileField* m_pathFld;
QLineEdit* m_fileNameFld;
QComboBox *m_templateCombo, *m_exportAreaCombo, *m_continuousLineCombo;
QComboBox *m_templateCombo, *m_exportAreaCombo, *m_continuousLineCombo,
*m_dialogueColCombo;
DVGui::ColorField* m_lineColorFld;
QCheckBox *m_addDateTimeCB, *m_addScenePathCB, *m_drawSoundCB,
*m_addSceneNameCB, *m_serialFrameNumberCB, *m_levelNameOnBottomCB;
*m_addSceneNameCB, *m_serialFrameNumberCB, *m_levelNameOnBottomCB,
*m_drawDialogueCB;
QFontComboBox *m_templateFontCB, *m_contentsFontCB;
QTextEdit* m_memoEdit;
@ -281,9 +302,13 @@ class ExportXsheetPdfPopup final : public DVGui::Dialog {
int m_totalPageCount;
QPushButton *m_prev, *m_next;
QComboBox *m_tick1IdCombo, *m_tick2IdCombo, *m_keyIdCombo;
QComboBox *m_tick1MarkCombo, *m_tick2MarkCombo;
// column and column name (if manually specified)
QList<QPair<TXshLevelColumn*, QString>> m_columns;
QList<TXshSoundColumn*> m_soundColumns;
QMap<int, TXshSoundTextColumn*> m_noteColumns;
int m_duration;
XSheetPDFTemplate* m_currentTmpl;
@ -315,6 +340,8 @@ protected slots:
void onLogoImgPathChanged();
void onPrev();
void onNext();
void onTickIdComboActivated();
};
#endif

View file

@ -310,6 +310,21 @@ void ExpressionReferenceManager::onSceneSwitched() {
//-----------------------------------------------------------------------------
void ExpressionReferenceManager::refreshXsheetRefInfo(TXsheet* xsh) {
xsh->setObserver(this);
m_model->refreshData(xsh);
xsh->getExpRefMonitor()->clearAll();
for (int i = 0; i < m_model->getStageObjectsChannelCount(); i++) {
checkRef(m_model->getStageObjectChannel(i), xsh);
}
for (int i = 0; i < m_model->getFxsChannelCount(); i++) {
checkRef(m_model->getFxChannel(i), xsh);
}
onXsheetSwitched();
}
//-----------------------------------------------------------------------------
void ExpressionReferenceManager::onXsheetSwitched() {
TXsheet* xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
xsh->setObserver(this);
@ -772,7 +787,8 @@ void ExpressionReferenceManager::transferReference(
// 1. create 3 tables for replacing; column indices, parameter pointers, and
// expression texts. Note that moving columns in the same xsheet does not need
// to replace the parameter pointers since they are swapped along with columns.
// to replace the parameter pointers since they are swapped along with
// columns.
QMap<int, int> colIdReplaceTable;
QMap<TDoubleParam*, TDoubleParam*> curveReplaceTable;
std::map<std::string, std::string> exprReplaceTable;

View file

@ -79,6 +79,7 @@ public:
bool askIfParamIsIgnoredOnSave(bool saveSubXsheet);
void refreshXsheetRefInfo(TXsheet* xsh);
protected slots:
void onSceneSwitched();
void onXsheetSwitched();

View file

@ -1193,7 +1193,9 @@ QMenu *FileBrowser::getContextMenu(QWidget *parent, int index) {
}
for (i = 0; i < files.size(); i++)
if (!TFileType::isViewable(TFileType::getInfo(files[i]))) break;
if (!TFileType::isViewable(TFileType::getInfo(files[i])) &&
files[i].getType() != "tpl")
break;
if (i == files.size()) {
std::string type = files[0].getType();
for (j = 0; j < files.size(); j++)

View file

@ -15,6 +15,12 @@
#include "convertpopup.h"
#include "matchline.h"
#include "colormodelbehaviorpopup.h"
//#if defined(x64)
//#include "penciltestpopup.h" // FrameNumberLineEdit
//#else
//#include "penciltestpopup_qt.h"
//#endif
#include "../stopmotion/stopmotioncontroller.h" // FrameNumberLineEdit
// TnzQt includes
#include "toonzqt/gutil.h"
@ -473,8 +479,9 @@ TFilePath GenericLoadFilePopup::getPath() {
// GenericSaveFilePopup implementation
//***********************************************************************************
GenericSaveFilePopup::GenericSaveFilePopup(const QString &title)
: FileBrowserPopup(title, Options(FOR_SAVING)) {
GenericSaveFilePopup::GenericSaveFilePopup(const QString &title,
QWidget *customWidget)
: FileBrowserPopup(title, Options(FOR_SAVING), "", customWidget) {
connect(m_nameField, SIGNAL(returnPressedNow()), m_okButton,
SLOT(animateClick()));
}
@ -707,8 +714,8 @@ LoadLevelPopup::LoadLevelPopup()
QPushButton *showSubsequenceButton = createShowButton(this);
QLabel *subsequenceLabel = new QLabel(tr("Load Subsequence Level"), this);
m_subsequenceFrame = new QFrame(this);
m_fromFrame = new DVGui::IntLineEdit(this, 1, 1);
m_toFrame = new DVGui::IntLineEdit(this, 1, 1);
m_fromFrame = new FrameNumberLineEdit(this, TFrameId(1));
m_toFrame = new FrameNumberLineEdit(this, TFrameId(1));
//----Arrangement in Xsheet
m_arrLvlPropWidget = new QWidget(this);
@ -716,8 +723,8 @@ LoadLevelPopup::LoadLevelPopup()
QLabel *arrangementLabel =
new QLabel(tr("Level Settings & Arrangement in Scene"), this);
m_arrangementFrame = new QFrame(this);
m_xFrom = new DVGui::IntLineEdit(this, 1, 1);
m_xTo = new DVGui::IntLineEdit(this, 1, 1);
m_xFrom = new FrameNumberLineEdit(this, TFrameId(1));
m_xTo = new FrameNumberLineEdit(this, TFrameId(1));
m_stepCombo = new QComboBox(this);
m_incCombo = new QComboBox(this);
m_posFrom = new DVGui::IntLineEdit(this, 1, 1);
@ -968,12 +975,12 @@ void LoadLevelPopup::onNameSetEditted() {
} else {
m_notExistLabel->show();
m_fromFrame->setText("1");
m_toFrame->setText("1");
m_fromFrame->setValue(TFrameId(1));
m_toFrame->setValue(TFrameId(1));
m_subsequenceFrame->setEnabled(true);
m_xFrom->setText("1");
m_xTo->setText("1");
m_xFrom->setValue(TFrameId(1));
m_xTo->setValue(TFrameId(1));
m_levelName->setText(QString::fromStdString(path.getName()));
@ -998,26 +1005,39 @@ void LoadLevelPopup::updatePosTo() {
return;
}
int xFrom = m_xFrom->text().toInt();
int xTo = m_xTo->text().toInt();
TFrameId xFrom = m_xFrom->getValue();
TFrameId xTo = m_xTo->getValue();
int frameLength;
bool isScene = (QString::fromStdString(fp.getType()) == "tnz");
if (isScene) { // scene does not consider frame suffixes
xFrom = TFrameId(xFrom.getNumber());
xTo = TFrameId(xTo.getNumber());
}
auto frameLengthBetweenFIds = [&]() {
if (xFrom > xTo) return 0;
int ret = xTo.getNumber() - xFrom.getNumber() + 1;
if (!xTo.getLetter().isEmpty()) ret++;
return ret;
};
//--- if loading the "missing" level
if (m_notExistLabel->isVisible()) {
int inc = m_incCombo->currentIndex();
if (inc == 0) // Inc = Auto
{
frameLength = (xTo - xFrom + 1) * ((m_stepCombo->currentIndex() == 0)
? 1
: m_stepCombo->currentIndex());
frameLength =
frameLengthBetweenFIds() * ((m_stepCombo->currentIndex() == 0)
? 1
: m_stepCombo->currentIndex());
} else // Inc =! Auto
{
int loopAmount;
loopAmount = tceil((double)(xTo - xFrom + 1) / (double)inc);
loopAmount = tceil((double)(frameLengthBetweenFIds()) / (double)inc);
frameLength = loopAmount * ((m_stepCombo->currentIndex() == 0)
? inc
: m_stepCombo->currentIndex());
@ -1028,7 +1048,7 @@ void LoadLevelPopup::updatePosTo() {
else if (m_incCombo->currentIndex() == 0) // Inc = Auto
{
if (isScene) {
frameLength = xTo - xFrom + 1;
frameLength = frameLengthBetweenFIds();
} else {
std::vector<TFrameId> fIds = getCurrentFIds();
//--- If loading the level with sequential files, reuse the list of
@ -1036,32 +1056,23 @@ void LoadLevelPopup::updatePosTo() {
if (fIds.size() != 0) {
if (m_stepCombo->currentIndex() == 0) // Step = Auto
{
frameLength = 0;
std::vector<TFrameId>::iterator it;
int firstFrame = 0;
int lastFrame = 0;
for (it = fIds.begin(); it != fIds.end(); it++) {
if (xFrom <= it->getNumber()) {
firstFrame = it->getNumber();
if (xFrom <= *it && *it <= xTo)
frameLength++;
else if (xTo < *it)
break;
}
}
for (it = fIds.begin(); it != fIds.end(); it++) {
if (it->getNumber() <= xTo) {
lastFrame = it->getNumber();
}
}
frameLength = lastFrame - firstFrame + 1;
} else // Step != Auto
{
std::vector<TFrameId>::iterator it;
int loopAmount = 0;
for (it = fIds.begin(); it != fIds.end(); it++) {
if (xFrom <= it->getNumber() && it->getNumber() <= xTo)
loopAmount++;
if (xFrom <= *it && *it <= xTo) loopAmount++;
}
frameLength = loopAmount * m_stepCombo->currentIndex();
}
}
// loading another type of level such as tlv
else {
@ -1074,29 +1085,20 @@ void LoadLevelPopup::updatePosTo() {
if (m_stepCombo->currentIndex() == 0) // Step = Auto
{
frameLength = 0;
TLevel::Iterator it;
int firstFrame = 0;
int lastFrame = 0;
for (it = level->begin(); it != level->end(); it++) {
if (xFrom <= it->first.getNumber()) {
firstFrame = it->first.getNumber();
if (xFrom <= it->first && it->first <= xTo)
frameLength++;
else if (xTo < it->first)
break;
}
}
for (it = level->begin(); it != level->end(); it++) {
if (it->first.getNumber() <= xTo) {
lastFrame = it->first.getNumber();
}
}
frameLength = lastFrame - firstFrame + 1;
} else // Step != Auto
{
TLevel::Iterator it;
int loopAmount = 0;
for (it = level->begin(); it != level->end(); it++) {
if (xFrom <= it->first.getNumber() &&
it->first.getNumber() <= xTo)
loopAmount++;
if (xFrom <= it->first && it->first <= xTo) loopAmount++;
}
frameLength = loopAmount * m_stepCombo->currentIndex();
}
@ -1110,7 +1112,7 @@ void LoadLevelPopup::updatePosTo() {
else {
int inc = m_incCombo->currentIndex();
int loopAmount;
loopAmount = tceil((double)(xTo - xFrom + 1) / (double)inc);
loopAmount = tceil((double)(frameLengthBetweenFIds()) / (double)inc);
frameLength = loopAmount * ((m_stepCombo->currentIndex() == 0)
? inc
: m_stepCombo->currentIndex());
@ -1123,8 +1125,8 @@ void LoadLevelPopup::updatePosTo() {
/*! if the from / to values in the subsequent box, update m_xFrom and m_xTo
*/
void LoadLevelPopup::onSubsequentFrameChanged() {
m_xFrom->setText(m_fromFrame->text());
m_xTo->setText(m_toFrame->text());
m_xFrom->setValue(m_fromFrame->getValue());
m_xTo->setValue(m_toFrame->getValue());
updatePosTo();
}
@ -1192,9 +1194,9 @@ bool LoadLevelPopup::execute() {
//---- SubSequent load
// if loading the "missing" level
if (m_notExistLabel->isVisible()) {
int firstFrameNumber = m_fromFrame->text().toInt();
int lastFrameNumber = m_toFrame->text().toInt();
setLoadingLevelRange(firstFrameNumber, lastFrameNumber);
TFrameId firstLoadingFId = m_fromFrame->getValue();
TFrameId lastLoadingFId = m_toFrame->getValue();
setLoadingLevelRange(firstLoadingFId, lastLoadingFId);
} else if (m_subsequenceFrame->isEnabled() &&
m_subsequenceFrame->isVisible()) {
std::vector<TFrameId> fIds = getCurrentFIds();
@ -1220,11 +1222,10 @@ bool LoadLevelPopup::execute() {
return false;
}
}
int firstFrameNumber = m_fromFrame->text().toInt();
int lastFrameNumber = m_toFrame->text().toInt();
if (firstFrame.getNumber() != firstFrameNumber ||
lastFrame.getNumber() != lastFrameNumber)
setLoadingLevelRange(firstFrameNumber, lastFrameNumber);
TFrameId firstLoadingFId = m_fromFrame->getValue();
TFrameId lastLoadingFId = m_toFrame->getValue();
if (firstFrame != firstLoadingFId || lastFrame != lastLoadingFId)
setLoadingLevelRange(firstLoadingFId, lastLoadingFId);
}
IoCmd::LoadResourceArguments args(fp);
@ -1237,20 +1238,27 @@ bool LoadLevelPopup::execute() {
args.frameIdsSet.push_back(*getCurrentFIdsSet().begin());
else if (m_notExistLabel->isVisible()) {
int firstFrameNumber = m_fromFrame->text().toInt();
int lastFrameNumber = m_toFrame->text().toInt();
TFrameId firstLoadingFId = m_fromFrame->getValue();
TFrameId lastLoadingFId = m_toFrame->getValue();
// putting the Fids in order to avoid LoadInfo later
std::vector<TFrameId> tmp_fids;
for (int i = firstFrameNumber; i <= lastFrameNumber; i++) {
int i = firstLoadingFId.getNumber();
if (!firstLoadingFId.getLetter().isEmpty()) {
tmp_fids.push_back(firstLoadingFId);
i++;
}
for (; i <= lastLoadingFId.getNumber(); i++) {
tmp_fids.push_back(TFrameId(i));
}
if (!lastLoadingFId.getLetter().isEmpty())
tmp_fids.push_back(lastLoadingFId);
args.frameIdsSet.push_back(tmp_fids);
}
int xFrom = m_xFrom->text().toInt();
if (xFrom) args.xFrom = xFrom;
int xTo = m_xTo->text().toInt();
if (xTo) args.xTo = xTo;
TFrameId xFrom = m_xFrom->getValue();
if (!xFrom.isEmptyFrame()) args.xFrom = xFrom;
TFrameId xTo = m_xTo->getValue();
if (!xTo.isEmptyFrame()) args.xTo = xTo;
args.levelName = m_levelName->text().toStdWString();
args.step = m_stepCombo->currentIndex();
@ -1372,9 +1380,8 @@ void LoadLevelPopup::updateBottomGUI() {
disableAll();
return;
} else if (ext == "tpl") {
QString str;
m_fromFrame->setText(str.number(1));
m_toFrame->setText(str.number(1));
m_fromFrame->setText("1");
m_toFrame->setText("1");
m_subsequenceFrame->setEnabled(false);
m_xFrom->setText("1");
@ -1420,13 +1427,12 @@ void LoadLevelPopup::updateBottomGUI() {
return;
}
}
m_fromFrame->setText(QString().number(firstFrame.getNumber()));
m_toFrame->setText(QString().number(lastFrame.getNumber()));
m_fromFrame->setValue(firstFrame);
m_toFrame->setValue(lastFrame);
m_subsequenceFrame->setEnabled(true);
m_xFrom->setText(m_fromFrame->text());
m_xTo->setText(m_toFrame->text());
m_xFrom->setValue(firstFrame);
m_xTo->setValue(lastFrame);
// if some option in the preferences is selected, load the level with
// removing

View file

@ -32,6 +32,7 @@ class QPushButton;
class QComboBox;
class QGroupBox;
class QCheckBox;
class FrameNumberLineEdit;
namespace DVGui {
class ColorField;
@ -184,7 +185,7 @@ protected:
//! asks the user for a \a single file path to save something to.
class GenericSaveFilePopup : public FileBrowserPopup {
public:
GenericSaveFilePopup(const QString &title);
GenericSaveFilePopup(const QString &title, QWidget *customWidget = nullptr);
/*!
This function shows the popup and blocks until a suitable
@ -266,11 +267,11 @@ class LoadLevelPopup final : public FileBrowserPopup {
Q_OBJECT
QFrame *m_subsequenceFrame;
DVGui::IntLineEdit *m_fromFrame, *m_toFrame;
FrameNumberLineEdit *m_fromFrame, *m_toFrame;
QWidget *m_arrLvlPropWidget;
QFrame *m_arrangementFrame;
DVGui::IntLineEdit *m_xFrom, *m_xTo;
FrameNumberLineEdit *m_xFrom, *m_xTo;
QComboBox *m_stepCombo, *m_incCombo;
DVGui::IntLineEdit *m_posFrom, *m_posTo;

View file

@ -23,6 +23,7 @@
#include "toonzqt/icongenerator.h"
#include "toonzqt/gutil.h"
#include "historytypes.h"
#include "toonzqt/menubarcommand.h"
// TnzLib includes
#include "toonz/tproject.h"
@ -30,6 +31,9 @@
#include "toonz/sceneresources.h"
#include "toonz/preferences.h"
#include "toonz/tscenehandle.h"
#include "toonz/studiopalette.h"
#include "toonz/palettecontroller.h"
#include "toonz/tpalettehandle.h"
// TnzCore includes
#include "tfiletype.h"
@ -185,6 +189,8 @@ public:
return str;
}
};
TPaletteP viewedPalette;
//-----------------------------------------------------------------------------
} // namespace
@ -372,12 +378,21 @@ void FileSelection::viewFile() {
getSelectedFiles(files);
int i = 0;
for (i = 0; i < files.size(); i++) {
if (!TFileType::isViewable(TFileType::getInfo(files[0]))) continue;
if (!TFileType::isViewable(TFileType::getInfo(files[i])) &&
files[i].getType() != "tpl")
continue;
if (Preferences::instance()->isDefaultViewerEnabled() &&
(files[i].getType() == "avi"))
QDesktopServices::openUrl(QUrl("file:///" + toQString(files[i])));
else {
else if (files[i].getType() == "tpl") {
viewedPalette = StudioPalette::instance()->getPalette(files[i], false);
TApp::instance()
->getPaletteController()
->getCurrentLevelPalette()
->setPalette(viewedPalette.getPointer());
CommandManager::instance()->execute("MI_OpenPalette");
} else {
FlipBook *fb = ::viewFile(files[i]);
if (fb) {
FileBrowserPopup::setModalBrowserToParent(fb->parentWidget());

View file

@ -711,9 +711,9 @@ void FilmstripFrames::paintEvent(QPaintEvent *evt) {
}
// for sequential frame
else {
char letter = fid.getLetter();
text = QString::number(fid.getNumber()).rightJustified(4, '0') +
(letter != '\0' ? QString(letter) : "");
QString letter = fid.getLetter();
text = QString::number(fid.getNumber()).rightJustified(4, '0') +
(!letter.isEmpty() ? letter : "");
}
p.drawText(tmp_frameRect.adjusted(0, 0, -3, 2), text,
QTextOption(Qt::AlignRight | Qt::AlignBottom));

View file

@ -51,7 +51,8 @@
//=============================================================================
TFrameId operator+(const TFrameId &fid, int d) {
return TFrameId(fid.getNumber() + d, fid.getLetter());
return TFrameId(fid.getNumber() + d, fid.getLetter(), fid.getZeroPadding(),
fid.getStartSeqInd());
}
//-----------------------------------------------------------------------------
@ -1341,6 +1342,17 @@ public:
int getHistoryType() override { return HistoryType::FilmStrip; }
};
QString getNextLetter(const QString &letter) {
// 空なら a を返す
if (letter.isEmpty()) return QString('a');
// 1文字かつ z または Z ならEmptyを返す
if (letter == 'z' || letter == 'Z') return QString();
QByteArray byteArray = letter.toUtf8();
// それ以外の場合、最後の文字をとにかく1進めて返す
byteArray.data()[byteArray.size() - 1]++;
return QString::fromUtf8(byteArray);
};
} // namespace
//=============================================================================
@ -1356,10 +1368,14 @@ void FilmstripCmd::addFrames(TXshSimpleLevel *sl, int start, int end,
std::vector<TFrameId> oldFids;
sl->getFids(oldFids);
TFrameId tmplFid;
if (!oldFids.empty()) tmplFid = oldFids.front();
std::set<TFrameId> fidsToInsert;
int frame = 0;
for (frame = start; frame <= end; frame += step)
fidsToInsert.insert(TFrameId(frame));
fidsToInsert.insert(TFrameId(frame, "", tmplFid.getZeroPadding(),
tmplFid.getStartSeqInd()));
makeSpaceForFids(sl, fidsToInsert);
@ -1487,10 +1503,11 @@ void FilmstripCmd::renumber(
// make sure that srcFid has not been used. add a letter if this is needed
if (tmp.count(tarFid) > 0) {
do {
char letter = tarFid.getLetter();
tarFid = TFrameId(tarFid.getNumber(), letter == 0 ? 'a' : letter + 1);
} while (tarFid.getLetter() <= 'z' && tmp.count(tarFid) > 0);
if (tarFid.getLetter() > 'z') {
tarFid =
TFrameId(tarFid.getNumber(), getNextLetter(tarFid.getLetter()),
tarFid.getZeroPadding(), tarFid.getStartSeqInd());
} while (!tarFid.getLetter().isEmpty() && tmp.count(tarFid) > 0);
if (tarFid.getLetter().isEmpty()) {
// todo: error message
return;
}
@ -1546,7 +1563,8 @@ void FilmstripCmd::renumber(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
std::vector<TFrameId>::iterator j = fids.begin();
for (it = frames.begin(); it != frames.end(); ++it) {
TFrameId srcFid(*it);
TFrameId dstFid(frame);
TFrameId dstFid(frame, "", srcFid.getZeroPadding(),
srcFid.getStartSeqInd());
frame += stepFrame;
// faccio il controllo su tmp e non su fids. considera:
// fids = [1,2,3,4], renumber = [2->3,3->5]
@ -1579,7 +1597,8 @@ void FilmstripCmd::renumber(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
it2 = frames.begin();
std::set<TFrameId> newFrames;
for (i = 0; i < frames.size(); i++, it2++)
newFrames.insert(TFrameId(startFrame + (i * stepFrame), it2->getLetter()));
newFrames.insert(TFrameId(startFrame + (i * stepFrame), it2->getLetter(),
it2->getZeroPadding(), it2->getStartSeqInd()));
assert(frames.size() == newFrames.size());
frames.swap(newFrames);
@ -2763,13 +2782,9 @@ void FilmstripCmd::renumberDrawing(TXshSimpleLevel *sl, const TFrameId &oldFid,
if (it == fids.end()) return;
TFrameId newFid = desiredNewFid;
while (std::find(fids.begin(), fids.end(), newFid) != fids.end()) {
char letter = newFid.getLetter();
if (letter == 'z') return;
if (letter == 0)
letter = 'a';
else
letter++;
newFid = TFrameId(newFid.getNumber(), letter);
QString nextLetter = getNextLetter(newFid.getLetter());
if (nextLetter.isEmpty()) return;
newFid = TFrameId(newFid.getNumber(), nextLetter);
}
*it = newFid;
if (Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled()) {

View file

@ -88,52 +88,51 @@ TFx *createPresetFxByName(TFilePath path) {
}
//-----------------------------------------------------------------------------
// same as createMacroFxByPath() in addfxcontextmenu.cpp
TFx *createMacroFxByPath(TFilePath path) {
TIStream is(path);
TPersist *p = 0;
is >> p;
TMacroFx *fx = dynamic_cast<TMacroFx *>(p);
if (!fx) return 0;
fx->setName(path.getWideName());
// Assign a unic ID to each fx in the macro!
TApp *app = TApp::instance();
TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
if (!xsh) return fx;
FxDag *fxDag = xsh->getFxDag();
if (!fxDag) return fx;
std::vector<TFxP> fxs;
fxs = fx->getFxs();
QMap<std::wstring, std::wstring> oldNewId;
int i;
for (i = 0; i < fxs.size(); i++) {
std::wstring oldId = fxs[i]->getFxId();
fxDag->assignUniqueId(fxs[i].getPointer());
oldNewId[oldId] = fxs[i]->getFxId();
}
try {
TIStream is(path);
TPersist *p = 0;
is >> p;
TMacroFx *fx = dynamic_cast<TMacroFx *>(p);
if (!fx) return 0;
fx->setName(path.getWideName());
// Assign a unic ID to each fx in the macro!
TApp *app = TApp::instance();
TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
if (!xsh) return fx;
FxDag *fxDag = xsh->getFxDag();
if (!fxDag) return fx;
std::vector<TFxP> fxs;
fxs = fx->getFxs();
QMap<std::wstring, std::wstring> oldNewId;
int i;
for (i = 0; i < fxs.size(); i++) {
std::wstring oldId = fxs[i]->getFxId();
fxDag->assignUniqueId(fxs[i].getPointer());
std::wstring newId = fxs[i]->getFxId();
oldNewId[oldId] = newId;
QStack<QPair<std::string, TFxPort *>> newPortNames;
// changing the id of the internal effects of a macro breaks the links
// between the name of the port and the port to which it is linked :
// I have to change the names of the ports and remap them within the macro
int j;
for (j = 0; j < fx->getInputPortCount(); j++) {
QString inputName = QString::fromStdString(fx->getInputPortName(j));
if (inputName.endsWith(QString::fromStdWString(oldId))) {
QString newInputName = inputName;
newInputName.replace(QString::fromStdWString(oldId),
QString::fromStdWString(newId));
fx->renamePort(inputName.toStdString(), newInputName.toStdString());
}
}
}
// Devo cambiare il nome alle porte: contengono l'id dei vecchi effetti
for (i = fx->getInputPortCount() - 1; i >= 0; i--) {
std::string oldPortName = fx->getInputPortName(i);
std::string inFxOldId = oldPortName;
inFxOldId.erase(0, inFxOldId.find_last_of("_") + 1);
assert(oldNewId.contains(::to_wstring(inFxOldId)));
std::string inFxNewId = ::to_string(oldNewId[ ::to_wstring(inFxOldId)]);
std::string newPortName = oldPortName;
newPortName.erase(newPortName.find_last_of("_") + 1,
newPortName.size() - 1);
newPortName.append(inFxNewId);
TFxPort *fxPort = fx->getInputPort(i);
newPortNames.append(QPair<std::string, TFxPort *>(newPortName, fxPort));
fx->removeInputPort(oldPortName);
return fx;
} catch (...) {
return 0;
}
while (!newPortNames.isEmpty()) {
QPair<std::string, TFxPort *> newPort = newPortNames.pop();
fx->addInputPort(newPort.first, *newPort.second);
}
return fx;
}
} // anonymous namespace

View file

@ -324,7 +324,8 @@ bool beforeCellsInsert(TXsheet *xsh, int row, int &col, int rowCount,
for (i = 0; i < rowCount && xsh->getCell(row + i, col).isEmpty(); i++) {
}
int type = column ? column->getColumnType() : newLevelColumnType;
int type = (column && !column->isEmpty()) ? column->getColumnType()
: newLevelColumnType;
// If some used cells in range or column type mismatch must insert a column.
if (col < 0 || i < rowCount || newLevelColumnType != type) {
col += 1;
@ -891,9 +892,9 @@ TXshLevel *loadLevel(ToonzScene *scene,
const IoCmd::LoadResourceArguments::ResourceData &rd,
const TFilePath &castFolder, int row0, int &col0, int row1,
int &col1, bool expose, std::vector<TFrameId> &fIds,
int xFrom = -1, int xTo = -1, std::wstring levelName = L"",
int step = -1, int inc = -1, int frameCount = -1,
bool doesFileActuallyExist = true) {
TFrameId xFrom = TFrameId(), TFrameId xTo = TFrameId(),
std::wstring levelName = L"", int step = -1, int inc = -1,
int frameCount = -1, bool doesFileActuallyExist = true) {
TFilePath actualPath = scene->decodeFilePath(rd.m_path);
LoadLevelUndo *undo = 0;
@ -1022,12 +1023,15 @@ TXshLevel *loadLevel(ToonzScene *scene,
// loadResource(scene, path, castFolder, row, col, expose)
//---------------------------------------------------------------------------
TXshLevel *loadResource(
ToonzScene *scene, const IoCmd::LoadResourceArguments::ResourceData &rd,
const TFilePath &castFolder, int row0, int &col0, int row1, int &col1,
bool expose, std::vector<TFrameId> fIds = std::vector<TFrameId>(),
int xFrom = -1, int xTo = -1, std::wstring levelName = L"", int step = -1,
int inc = -1, int frameCount = -1, bool doesFileActuallyExist = true) {
TXshLevel *loadResource(ToonzScene *scene,
const IoCmd::LoadResourceArguments::ResourceData &rd,
const TFilePath &castFolder, int row0, int &col0,
int row1, int &col1, bool expose,
std::vector<TFrameId> fIds = std::vector<TFrameId>(),
TFrameId xFrom = TFrameId(), TFrameId xTo = TFrameId(),
std::wstring levelName = L"", int step = -1,
int inc = -1, int frameCount = -1,
bool doesFileActuallyExist = true) {
IoCmd::LoadResourceArguments::ResourceData actualRd(rd);
actualRd.m_path = scene->decodeFilePath(rd.m_path);
@ -2253,7 +2257,7 @@ static int loadPSDResource(IoCmd::LoadResourceArguments &args,
assert(childLevel);
childXsh = childLevel->getXsheet();
}
int subCol0 = args.col0;
int subCol0 = 0;
loadedPsdLevelIndex.clear();
// for each layer in psd
for (int i = 0; i < popup->getPsdLevelCount(); i++) {
@ -2265,7 +2269,7 @@ static int loadPSDResource(IoCmd::LoadResourceArguments &args,
count +=
createSubXSheetFromPSDFolder(args, childXsh, subCol0, i, popup);
else
count += createSubXSheetFromPSDFolder(args, xsh, subCol0, i, popup);
count += createSubXSheetFromPSDFolder(args, xsh, col0, i, popup);
} else {
TFilePath psdpath = popup->getPsdPath(i);
TXshLevel *xl = 0;
@ -2280,14 +2284,14 @@ static int loadPSDResource(IoCmd::LoadResourceArguments &args,
// lo importo nell'xsheet
if (popup->subxsheet() && childXsh) {
childXsh->exposeLevel(0, subCol0, xl);
subCol0++;
} else {
// move the current column to the right
col0++;
app->getCurrentColumn()->setColumnIndex(col0);
}
args.loadedLevels.push_back(xl);
subCol0++;
count++;
// move the current column to the right
col0++;
app->getCurrentColumn()->setColumnIndex(col0);
}
}
}

View file

@ -127,7 +127,7 @@ public:
std::vector<TXshLevel *> loadedLevels; //!< [\p Out] Levels loaded by
//! resource loading procedures.
int xFrom, xTo;
TFrameId xFrom, xTo;
std::wstring levelName;
int step, inc, frameCount;
bool doesFileActuallyExist;

View file

@ -512,6 +512,14 @@ void LevelCmd::addMissingLevelsToCast(const QList<TXshColumnP> &columns) {
}
void LevelCmd::addMissingLevelsToCast(std::set<TXshLevel *> &levels) {
// remove zerary fx levels which are not registered in the cast
for (auto it = levels.begin(); it != levels.end();) {
if ((*it)->getZeraryFxLevel())
it = levels.erase(it);
else
++it;
}
if (levels.empty()) return;
TUndoManager::manager()->beginBlock();
TLevelSet *levelSet =

View file

@ -3066,6 +3066,16 @@ void MainWindow::defineActions() {
"");
createStopMotionAction(MI_StopMotionToggleUseLiveViewImages,
QT_TR_NOOP("Show original live view images."), "");
// create cell mark actions
for (int markId = 0; markId < 12; markId++) {
std::string cmdId = (std::string)MI_SetCellMark + std::to_string(markId);
std::string labelStr =
QT_TR_NOOP("Set Cell Mark ") + std::to_string(markId);
QAction *action =
createAction(cmdId.c_str(), labelStr.c_str(), "", "", CellMarkCommandType);
action->setData(markId);
}
}
//-----------------------------------------------------------------------------

View file

@ -471,6 +471,9 @@
#define MI_ExportTvpJson "MI_ExportTvpJson"
#define MI_ExportXsheetPDF "MI_ExportXsheetPDF"
// mark id is added for each actual command (i.g. MI_SetCellMark1)
#define MI_SetCellMark "MI_SetCellMark"
#define MI_ToggleAutoCreate "MI_ToggleAutoCreate"
#define MI_ToggleCreationInHoldCells "MI_ToggleCreationInHoldCells"
#define MI_ToggleAutoStretch "MI_ToggleAutoStretch"

View file

@ -19,10 +19,15 @@
#include "toonzqt/checkbox.h"
#include "toonzqt/gutil.h"
// TnzLib
#include "toonz/filepathproperties.h"
// TnzCore includes
#include "tsystem.h"
#include "tenv.h"
#include "tapp.h"
#include "tfilepath.h"
#include "toonz/tscenehandle.h"
#include "toonz/toonzscene.h"
#include "toonz/preferences.h"
@ -35,9 +40,19 @@
#include <QComboBox>
#include <QStandardPaths>
#include <QGroupBox>
#include <QTabWidget>
#include <QStackedWidget>
#include <QButtonGroup>
#include <QRadioButton>
using namespace DVGui;
namespace {
enum { Rule_Standard = 0, Rule_Custom };
}
//===================================================================
TFilePath getDocumentsPath() {
@ -85,6 +100,33 @@ ProjectPopup::ProjectPopup(bool isModal)
new CheckBox("*Separate assets into scene sub-folders");
m_useSubSceneCbs->setMaximumHeight(WidgetHeight);
m_rulePreferenceBG = new QButtonGroup(this);
QRadioButton *standardRB = new QRadioButton(tr("Standard"), this);
QRadioButton *customRB =
new QRadioButton(QString("[Experimental] ") + tr("Custom"), this);
m_acceptNonAlphabetSuffixCB =
new CheckBox(tr("Accept Non-alphabet Suffix"), this);
m_letterCountCombo = new QComboBox(this);
//-----
m_rulePreferenceBG->addButton(standardRB, Rule_Standard);
m_rulePreferenceBG->addButton(customRB, Rule_Custom);
m_rulePreferenceBG->setExclusive(true);
standardRB->setToolTip(tr(
"In the standard mode files with the following file name are handled as sequencial images:\n\
[LEVEL_NAME][\".\"or\"_\"][FRAME_NUMBER][SUFFIX].[EXTENSION]\n\
For [SUFFIX] zero or one occurrences of alphabet (a-z, A-Z) can be used in the standard mode."));
customRB->setToolTip(
tr("In the custom mode you can customize the file path rules.\n\
Note that this mode uses regular expression for file name validation and may slow the operation."));
m_letterCountCombo->addItem(tr("1"), 1);
m_letterCountCombo->addItem(tr("2"), 2);
m_letterCountCombo->addItem(tr("3"), 3);
m_letterCountCombo->addItem(tr("5"), 5);
m_letterCountCombo->addItem(tr("Unlimited"), 0);
m_settingsLabel = new QLabel(tr("Settings"), this);
m_settingsBox = createSettingsBox();
@ -127,7 +169,12 @@ ProjectPopup::ProjectPopup(bool isModal)
SLOT(setVisible(bool)));
pm->addListener(this);
//---------
connect(m_rulePreferenceBG, SIGNAL(buttonClicked(int)), this,
SLOT(onRulePreferenceToggled(int)));
}
//-----------------------------------------------------------------------------
QFrame *ProjectPopup::createSettingsBox() {
@ -136,49 +183,72 @@ QFrame *ProjectPopup::createSettingsBox() {
TProjectManager *pm = TProjectManager::instance();
QGridLayout *lay = new QGridLayout();
lay->setMargin(5);
lay->setHorizontalSpacing(5);
lay->setVerticalSpacing(10);
{
std::vector<std::string> folderNames;
pm->getFolderNames(folderNames);
int i;
for (i = 0; i < (int)folderNames.size(); i++) {
std::string name = folderNames[i];
QString qName = QString::fromStdString(name);
FileField *ff = new FileField(0, qName);
m_folderFlds.append(qMakePair(name, ff));
bool assetFolder = false;
if (qName == "drawings" || qName == "extras" || qName == "inputs")
assetFolder = true;
QLabel *label = new QLabel("+" + qName + (assetFolder ? "*" : ""), this);
lay->addWidget(label, i + 4, 0, Qt::AlignRight | Qt::AlignVCenter);
lay->addWidget(ff, i + 4, 1);
}
/*
std::vector<std::tuple<QString, std::string>> cbs = {
std::make_tuple(tr("Append $scenepath to +drawings"),
TProject::Drawings),
std::make_tuple(tr("Append $scenepath to +inputs"), TProject::Inputs),
std::make_tuple(tr("Append $scenepath to +extras"), TProject::Extras) };
int currentRow = lay->rowCount();
QTabWidget *tabWidget = new QTabWidget(this);
for (int i = 0; i < cbs.size(); ++i) {
auto const &name = std::get<0>(cbs[i]);
auto const &folderName = std::get<1>(cbs[i]);
CheckBox *cb = new CheckBox(name);
cb->setMaximumHeight(WidgetHeight);
lay->addWidget(cb, currentRow + i, 1);
m_useScenePathCbs.append(qMakePair(folderName, cb));
cb->hide();
QVBoxLayout *settingsLayout = new QVBoxLayout();
settingsLayout->setMargin(5);
settingsLayout->setSpacing(10);
{
settingsLayout->addWidget(tabWidget, 1);
// project folder settings
QWidget *projectFolderPanel = new QWidget(this);
QGridLayout *folderLayout = new QGridLayout();
folderLayout->setMargin(5);
folderLayout->setHorizontalSpacing(5);
folderLayout->setVerticalSpacing(10);
{
std::vector<std::string> folderNames;
pm->getFolderNames(folderNames);
int i;
for (i = 0; i < (int)folderNames.size(); i++) {
std::string name = folderNames[i];
QString qName = QString::fromStdString(name);
FileField *ff = new FileField(0, qName);
m_folderFlds.append(qMakePair(name, ff));
bool assetFolder = false;
if (qName == "drawings" || qName == "extras" || qName == "inputs")
assetFolder = true;
QLabel *label = new QLabel("+" + qName + (assetFolder ? "*" : ""), this);
folderLayout->addWidget(label, i + 4, 0, Qt::AlignRight | Qt::AlignVCenter);
folderLayout->addWidget(ff, i + 4, 1);
}
int currentRow = folderLayout->rowCount();
folderLayout->addWidget(m_useSubSceneCbs, currentRow, 1);
}
*/
int currentRow = lay->rowCount();
lay->addWidget(m_useSubSceneCbs, currentRow, 1);
projectFolderPanel->setLayout(folderLayout);
tabWidget->addTab(projectFolderPanel, tr("Project Folder"));
// file path settings
QWidget *filePathPanel = new QWidget(this);
QVBoxLayout *fpLayout = new QVBoxLayout();
fpLayout->setMargin(5);
fpLayout->setSpacing(10);
{
fpLayout->addWidget(m_rulePreferenceBG->buttons()[0], 0); // standardRB
fpLayout->addWidget(m_rulePreferenceBG->buttons()[1], 0); // customRB
// add some indent
QGridLayout *customLay = new QGridLayout();
customLay->setMargin(10);
customLay->setHorizontalSpacing(10);
customLay->setVerticalSpacing(10);
{
customLay->addWidget(m_acceptNonAlphabetSuffixCB, 0, 0, 1, 2);
customLay->addWidget(
new QLabel(tr("Maximum Letter Count For Suffix"), this), 1, 0);
customLay->addWidget(m_letterCountCombo, 1, 1);
}
customLay->setColumnStretch(2, 1);
fpLayout->addLayout(customLay, 0);
fpLayout->addStretch(1);
}
filePathPanel->setLayout(fpLayout);
tabWidget->addTab(filePathPanel, tr("File Path Rules"));
}
projectSettingsBox->setLayout(lay);
projectSettingsBox->setLayout(settingsLayout);
return projectSettingsBox;
}
@ -208,6 +278,18 @@ void ProjectPopup::updateFieldsFromProject(TProject *project) {
m_useSubSceneCbs->blockSignals(true);
m_useSubSceneCbs->setChecked(project->getUseSubScenePath());
m_useSubSceneCbs->blockSignals(false);
// file path
FilePathProperties *fpProp = project->getFilePathProperties();
bool useStandard = fpProp->useStandard();
bool acceptNonAlphabet = fpProp->acceptNonAlphabetSuffix();
int letterCount = fpProp->letterCountForSuffix();
m_rulePreferenceBG->button((useStandard) ? Rule_Standard : Rule_Custom)
->setChecked(true);
onRulePreferenceToggled((useStandard) ? Rule_Standard : Rule_Custom);
m_acceptNonAlphabetSuffixCB->setChecked(acceptNonAlphabet);
m_letterCountCombo->setCurrentIndex(
m_letterCountCombo->findData(letterCount));
}
//-----------------------------------------------------------------------------
@ -229,6 +311,20 @@ void ProjectPopup::updateProjectFromFields(TProject *project) {
*/
bool useScenePath = m_useSubSceneCbs->isChecked();
project->setUseSubScenePath(useScenePath);
// file path
FilePathProperties *fpProp = project->getFilePathProperties();
bool useStandard = m_rulePreferenceBG->checkedId() == Rule_Standard;
bool acceptNonAlphabet = m_acceptNonAlphabetSuffixCB->isChecked();
int letterCount = m_letterCountCombo->currentData().toInt();
fpProp->setUseStandard(useStandard);
fpProp->setAcceptNonAlphabetSuffix(acceptNonAlphabet);
fpProp->setLetterCountForSuffix(letterCount);
if (TFilePath::setFilePathProperties(useStandard, acceptNonAlphabet,
letterCount))
DvDirModel::instance()->refreshFolderChild(QModelIndex()); // refresh all
TProjectManager::instance()->notifyProjectChanged();
}
@ -246,6 +342,13 @@ void ProjectPopup::showEvent(QShowEvent *) {
updateFieldsFromProject(currentProject.getPointer());
}
//-----------------------------------------------------------------------------
void ProjectPopup::onRulePreferenceToggled(int id) {
m_acceptNonAlphabetSuffixCB->setEnabled((id == Rule_Custom));
m_letterCountCombo->setEnabled((id == Rule_Custom));
}
//=============================================================================
/*! \class ProjectSettingsPopup
\brief The ProjectSettingsPopup class provides a dialog to
@ -269,7 +372,7 @@ ProjectSettingsPopup::ProjectSettingsPopup() : ProjectPopup(false) {
int i;
for (i = 0; i < m_folderFlds.size(); i++) {
FileField *ff = m_folderFlds[i].second;
connect(ff, SIGNAL(pathChanged()), this, SLOT(onFolderChanged()));
connect(ff, SIGNAL(pathChanged()), this, SLOT(onSomethingChanged()));
}
/*
for (i = 0; i < m_useScenePathCbs.size(); i++) {
@ -278,8 +381,16 @@ ProjectSettingsPopup::ProjectSettingsPopup() : ProjectPopup(false) {
SLOT(onUseSceneChekboxChanged(int)));
}
*/
connect(m_useSubSceneCbs, SIGNAL(stateChanged(int)), this,
SLOT(onUseSceneChekboxChanged(int)));
connect(m_useSubSceneCbs, SIGNAL(stateChanged(int)), this, SLOT(onSomethingChanged()));
// file path settings
connect(m_rulePreferenceBG, SIGNAL(buttonClicked(int)), this,
SLOT(onSomethingChanged()));
connect(m_acceptNonAlphabetSuffixCB, SIGNAL(clicked(bool)), this,
SLOT(onSomethingChanged()));
connect(m_letterCountCombo, SIGNAL(activated(int)), this,
SLOT(onSomethingChanged()));
}
//-----------------------------------------------------------------------------
@ -374,21 +485,7 @@ void ProjectSettingsPopup::onProjectChanged() {
//-----------------------------------------------------------------------------
void ProjectSettingsPopup::onFolderChanged() {
TProjectP project = TProjectManager::instance()->getCurrentProject();
updateProjectFromFields(project.getPointer());
try {
project->save();
} catch (TSystemException se) {
DVGui::warning(QString::fromStdWString(se.getMessage()));
return;
}
DvDirModel::instance()->refreshFolder(project->getProjectFolder());
}
//-----------------------------------------------------------------------------
void ProjectSettingsPopup::onUseSceneChekboxChanged(int) {
void ProjectSettingsPopup::onSomethingChanged() {
TProjectP project = TProjectManager::instance()->getCurrentProject();
updateProjectFromFields(project.getPointer());
try {
@ -556,6 +653,12 @@ void ProjectCreatePopup::showEvent(QShowEvent *) {
setSizePolicy(sizePolicy);
setFixedSize(width(), height());
setSizeGripEnabled(false);
// default file path settings
m_rulePreferenceBG->button(Rule_Standard)->setChecked(true);
onRulePreferenceToggled(Rule_Standard);
m_acceptNonAlphabetSuffixCB->setChecked(false);
m_letterCountCombo->setCurrentIndex(m_letterCountCombo->findData(1));
}
void ProjectCreatePopup::setPath(QString path) {

View file

@ -16,11 +16,12 @@ namespace DVGui {
class FileField;
class LineEdit;
class CheckBox;
}
} // namespace DVGui
class QComboBox;
class QGridLayout;
class QGroupBox;
class QButtonGroup;
//=============================================================================
// ProjectPopup
@ -46,6 +47,11 @@ protected:
QFrame *m_settingsBox;
QPushButton *m_showSettingsButton;
// file path settings
QButtonGroup *m_rulePreferenceBG;
DVGui::CheckBox *m_acceptNonAlphabetSuffixCB;
QComboBox *m_letterCountCombo;
public:
ProjectPopup(bool isModal);
// da TProjectManager::Listener
@ -60,6 +66,9 @@ public:
protected:
void showEvent(QShowEvent *) override;
protected slots:
void onRulePreferenceToggled(int);
};
//=============================================================================
@ -75,8 +84,7 @@ public:
ProjectSettingsPopup();
public slots:
void onFolderChanged();
void onUseSceneChekboxChanged(int);
void onSomethingChanged();
void projectChanged();
void onProjectChanged() override;

View file

@ -32,6 +32,7 @@
#include <QApplication>
#include <QMainWindow>
#include <QPainter>
#include <QPushButton>
using namespace DVGui;
@ -43,6 +44,46 @@ const int labelSize = 110;
//-----------------------------------------------------------------------------
class EditCellMarkUndo final : public TUndo {
int m_id;
TSceneProperties::CellMark m_markBefore, m_markAfter;
EditCellMarkUndo(int id) : m_id(id) {
m_markBefore = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCellMark(id);
}
public:
EditCellMarkUndo(int id, TPixel32 color) : EditCellMarkUndo(id) {
m_markAfter = {m_markBefore.name, color};
}
EditCellMarkUndo(int id, QString name) : EditCellMarkUndo(id) {
m_markAfter = {name, m_markBefore.color};
}
void set(const TSceneProperties::CellMark &mark) const {
TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->setCellMark(mark, m_id);
TApp::instance()->getCurrentScene()->notifySceneChanged();
}
void undo() const override { set(m_markBefore); }
void redo() const override { set(m_markAfter); }
int getSize() const override { return sizeof *this; }
QString getHistoryString() override {
return QObject::tr("Edit Cell Mark #%1").arg(QString::number(m_id));
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
} // namespace
@ -77,12 +118,129 @@ QImage::Format_ARGB32);
};
*/
//=============================================================================
// CellMarksPopup
//-----------------------------------------------------------------------------
CellMarksPopup::CellMarksPopup(QWidget *parent) : QDialog(parent) {
setWindowTitle(tr("Cell Marks Settings"));
QList<TSceneProperties::CellMark> marks = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCellMarks();
QGridLayout *layout = new QGridLayout();
layout->setMargin(10);
layout->setHorizontalSpacing(5);
layout->setVerticalSpacing(10);
{
int id = 0;
for (auto mark : marks) {
ColorField *colorF = new ColorField(this, false, mark.color, 20);
colorF->hideChannelsFields(true);
QLineEdit *nameF = new QLineEdit(mark.name, this);
m_fields.append({id, colorF, nameF});
int row = layout->rowCount();
layout->addWidget(new QLabel(QString("%1:").arg(id), this), row, 0,
Qt::AlignRight | Qt::AlignVCenter);
layout->addWidget(colorF, row, 1);
layout->addWidget(nameF, row, 2);
connect(colorF, SIGNAL(colorChanged(const TPixel32 &, bool)), this,
SLOT(onColorChanged(const TPixel32 &, bool)));
connect(nameF, SIGNAL(editingFinished()), this, SLOT(onNameChanged()));
id++;
}
}
layout->setColumnStretch(2, 1);
setLayout(layout);
}
void CellMarksPopup::update() {
QList<TSceneProperties::CellMark> marks = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCellMarks();
assert(marks.count() == m_fields.count());
int id = 0;
for (auto mark : marks) {
assert(m_fields[id].id == id);
m_fields[id].colorField->setColor(mark.color);
m_fields[id].nameField->setText(mark.name);
id++;
}
}
void CellMarksPopup::onColorChanged(const TPixel32 &color, bool isDragging) {
if (isDragging) return;
// obtain id
int id = -1;
ColorField *colorF = qobject_cast<ColorField *>(sender());
for (auto field : m_fields) {
if (field.colorField == colorF) {
id = field.id;
break;
}
}
if (id < 0) return;
// return if the value is unchanged
TPixel32 oldColor = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCellMark(id)
.color;
if (color == oldColor) return;
EditCellMarkUndo *undo = new EditCellMarkUndo(id, color);
undo->redo();
TUndoManager::manager()->add(undo);
}
void CellMarksPopup::onNameChanged() {
// obtain id
int id = -1;
QLineEdit *nameF = qobject_cast<QLineEdit *>(sender());
for (auto field : m_fields) {
if (field.nameField == nameF) {
id = field.id;
break;
}
}
if (id < 0) return;
// return if the value is unchanged
QString oldName = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCellMark(id)
.name;
if (nameF->text() == oldName) return;
// reject empty string
if (nameF->text().isEmpty()) {
nameF->setText(oldName);
return;
}
EditCellMarkUndo *undo = new EditCellMarkUndo(id, nameF->text());
undo->redo();
TUndoManager::manager()->add(undo);
}
//=============================================================================
// SceneSettingsPopup
//-----------------------------------------------------------------------------
SceneSettingsPopup::SceneSettingsPopup()
: QDialog(TApp::instance()->getMainWindow()) {
: QDialog(TApp::instance()->getMainWindow()), m_cellMarksPopup(nullptr) {
setWindowTitle(tr("Scene Settings"));
setObjectName("SceneSettings");
TSceneProperties *sprop = getProperties();
@ -124,6 +282,9 @@ SceneSettingsPopup::SceneSettingsPopup()
m_colorFilterOnRenderCB->setChecked(
sprop->isColumnColorFilterOnRenderEnabled());
QPushButton *editCellMarksButton =
new QPushButton(tr("Edit Cell Marks"), this);
// layout
QGridLayout *mainLayout = new QGridLayout();
mainLayout->setMargin(10);
@ -164,6 +325,12 @@ SceneSettingsPopup::SceneSettingsPopup()
// Use Color Filter and Transparency for Rendering
mainLayout->addWidget(m_colorFilterOnRenderCB, 6, 0, 1, 4);
// cell marks
mainLayout->addWidget(new QLabel(tr("Cell Marks:"), this), 7, 0,
Qt::AlignRight | Qt::AlignVCenter);
mainLayout->addWidget(editCellMarksButton, 7, 1, 1, 4,
Qt::AlignLeft | Qt::AlignVCenter);
}
mainLayout->setColumnStretch(0, 0);
mainLayout->setColumnStretch(1, 0);
@ -201,6 +368,9 @@ SceneSettingsPopup::SceneSettingsPopup()
// Use Color Filter and Transparency for Rendering
ret = ret && connect(m_colorFilterOnRenderCB, SIGNAL(stateChanged(int)), this,
SLOT(onColorFilterOnRenderChanged()));
// Cell Marks
ret = ret && connect(editCellMarksButton, SIGNAL(clicked()), this,
SLOT(onEditCellMarksButtonClicked()));
assert(ret);
}
@ -254,6 +424,8 @@ void SceneSettingsPopup::update() {
m_startFrameFld->setValue(markerOffset + 1);
m_colorFilterOnRenderCB->setChecked(
sprop->isColumnColorFilterOnRenderEnabled());
if (m_cellMarksPopup) m_cellMarksPopup->update();
}
//-----------------------------------------------------------------------------
@ -368,6 +540,14 @@ void SceneSettingsPopup::onColorFilterOnRenderChanged() {
TApp::instance()->getCurrentScene()->notifySceneChanged();
}
//-----------------------------------------------------------------------------
void SceneSettingsPopup::onEditCellMarksButtonClicked() {
if (!m_cellMarksPopup) m_cellMarksPopup = new CellMarksPopup(this);
m_cellMarksPopup->show();
m_cellMarksPopup->raise();
}
//=============================================================================
OpenPopupCommandHandler<SceneSettingsPopup> openSceneSettingsPopup(

View file

@ -13,6 +13,25 @@
// forward declaration
class TSceneProperties;
class QComboBox;
class QLineEdit;
class CellMarksPopup final : public QDialog {
Q_OBJECT
struct MarkerField {
int id;
DVGui::ColorField *colorField;
QLineEdit *nameField;
};
QList<MarkerField> m_fields;
public:
CellMarksPopup(QWidget *parent);
void update();
protected slots:
void onColorChanged(const TPixel32 &, bool);
void onNameChanged();
};
//=============================================================================
// SceneSettingsPopup
@ -37,6 +56,8 @@ class SceneSettingsPopup final : public QDialog {
TSceneProperties *getProperties() const;
CellMarksPopup *m_cellMarksPopup;
public:
SceneSettingsPopup();
void configureNotify();
@ -61,6 +82,8 @@ public slots:
void setBgColor(const TPixel32 &value, bool isDragging);
void onColorFilterOnRenderChanged();
void onEditCellMarksButtonClicked();
};
#endif // SCENESETTINGSPOPUP_H

View file

@ -223,6 +223,8 @@ ShortcutTree::ShortcutTree(QWidget *parent) : QTreeWidget(parent) {
addFolder(tr("Help"), MenuHelpCommandType, menuCommandFolder);
addFolder(tr("Right-click Menu Commands"), RightClickMenuCommandType);
QTreeWidgetItem *rcmSubFolder = m_folders.back();
addFolder(tr("Cell Mark"), CellMarkCommandType, rcmSubFolder);
addFolder(tr("Tools"), ToolCommandType);
addFolder(tr("Tool Modifiers"), ToolModifierCommandType);
@ -470,7 +472,7 @@ ShortcutPopup::ShortcutPopup()
connect(searchEdit, SIGNAL(textChanged(const QString &)), this,
SLOT(onSearchTextChanged(const QString &)));
connect(m_presetChoiceCB, SIGNAL(currentIndexChanged(int)),
SLOT(onPresetChanged(int)));
SLOT(onPresetChanged()));
connect(m_exportButton, SIGNAL(clicked()), SLOT(onExportButton()));
connect(m_deletePresetButton, SIGNAL(clicked()), SLOT(onDeletePreset()));
connect(m_savePresetButton, SIGNAL(clicked()), SLOT(onSavePreset()));
@ -495,8 +497,8 @@ void ShortcutPopup::onSearchTextChanged(const QString &text) {
//-----------------------------------------------------------------------------
void ShortcutPopup::onPresetChanged(int index) {
if (m_presetChoiceCB->currentText() == "Load from file...") {
void ShortcutPopup::onPresetChanged() {
if (m_presetChoiceCB->currentData().toString() == QString("LoadFromFile")) {
importPreset();
}
}
@ -607,7 +609,10 @@ void ShortcutPopup::onExportButton(TFilePath fp) {
if (fp == TFilePath()) return;
}
showDialog(tr("Saving Shortcuts"));
QString shortcutString = "[shortcuts]\n";
QSettings preset(toQString(fp), QSettings::IniFormat);
preset.beginGroup("shortcuts");
for (int commandType = UndefinedCommandType; commandType <= MenuCommandType;
commandType++) {
std::vector<QAction *> actions;
@ -618,24 +623,22 @@ void ShortcutPopup::onExportButton(TFilePath fp) {
std::string shortcut =
CommandManager::instance()->getShortcutFromAction(action);
if (shortcut != "") {
shortcutString = shortcutString + QString::fromStdString(id) + "=" +
QString::fromStdString(shortcut) + "\n";
preset.setValue(QString::fromStdString(id),
QString::fromStdString(shortcut));
}
}
}
QFile file(fp.getQString());
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << shortcutString;
file.close();
preset.endGroup();
m_dialog->hide();
}
//-----------------------------------------------------------------------------
void ShortcutPopup::onDeletePreset() {
// change this to 4 once RETAS shortcuts are updated
if (m_presetChoiceCB->currentIndex() <= 3) {
// change this to 5 once RETAS shortcuts are updated
if (m_presetChoiceCB->currentIndex() <= 4) {
DVGui::MsgBox(DVGui::CRITICAL, tr("Included presets cannot be deleted."));
return;
}
@ -649,7 +652,7 @@ void ShortcutPopup::onDeletePreset() {
}
TFilePath presetDir =
ToonzFolder::getMyModuleDir() + TFilePath("shortcutpresets");
QString presetName = m_presetChoiceCB->currentText();
QString presetName = m_presetChoiceCB->currentData().toString();
if (TSystem::doesExistFileOrLevel(presetDir +
TFilePath(presetName + ".ini"))) {
TSystem::deleteFile(presetDir + TFilePath(presetName + ".ini"));
@ -693,48 +696,26 @@ void ShortcutPopup::importPreset() {
//-----------------------------------------------------------------------------
void ShortcutPopup::onLoadPreset() {
QString preset = m_presetChoiceCB->currentText();
TFilePath presetDir =
ToonzFolder::getMyModuleDir() + TFilePath("shortcutpresets");
TFilePath defaultPresetDir =
ToonzFolder::getProfileFolder() + TFilePath("layouts/shortcuts");
if (preset == "") return;
if (preset == "Load from file...") {
QString preset = m_presetChoiceCB->currentData().toString();
TFilePath presetDir;
if (m_presetChoiceCB->currentIndex() <= 4)
presetDir =
ToonzFolder::getProfileFolder() + TFilePath("layouts/shortcuts");
else
presetDir = ToonzFolder::getMyModuleDir() + TFilePath("shortcutpresets");
if (preset.isEmpty()) return;
if (preset == QString("LoadFromFile")) {
importPreset();
return;
}
if (!showConfirmDialog()) return;
showDialog(tr("Setting Shortcuts"));
if (preset == "Tahoma2D") {
TFilePath presetFilePath(preset + ".ini");
if (TSystem::doesExistFileOrLevel(presetDir + presetFilePath)) {
clearAllShortcuts(false);
TFilePath fp = defaultPresetDir + TFilePath("deftahoma2d.ini");
setPresetShortcuts(fp);
return;
} else if (preset == "Toon Boom Harmony") {
clearAllShortcuts(false);
TFilePath fp = defaultPresetDir + TFilePath("otharmony.ini");
setPresetShortcuts(fp);
return;
} else if (preset == "Adobe Animate") {
clearAllShortcuts(false);
TFilePath fp = defaultPresetDir + TFilePath("otanimate.ini");
setPresetShortcuts(fp);
return;
} else if (preset == "Adobe Flash Pro") {
clearAllShortcuts(false);
TFilePath fp = defaultPresetDir + TFilePath("otadobe.ini");
setPresetShortcuts(fp);
return;
} else if (preset == "RETAS PaintMan") {
clearAllShortcuts(false);
TFilePath fp = defaultPresetDir + TFilePath("otretas.ini");
setPresetShortcuts(fp);
return;
} else if (TSystem::doesExistFileOrLevel(presetDir +
TFilePath(preset + ".ini"))) {
clearAllShortcuts(false);
TFilePath fp = presetDir + TFilePath(preset + ".ini");
TFilePath fp = presetDir + presetFilePath;
setPresetShortcuts(fp);
return;
}
@ -743,14 +724,16 @@ void ShortcutPopup::onLoadPreset() {
//-----------------------------------------------------------------------------
QStringList ShortcutPopup::buildPresets() {
QStringList presets;
presets << ""
<< "Tahoma2D"
//<< "RETAS PaintMan"
<< "Toon Boom Harmony"
<< "Adobe Animate"
<< "Adobe Flash Pro";
void ShortcutPopup::buildPresets() {
m_presetChoiceCB->clear();
m_presetChoiceCB->addItem("", QString(""));
m_presetChoiceCB->addItem("Tahoma2D", QString("deftahoma2d"));
// m_presetChoiceCB->addItem("RETAS PaintMan", QString("otretas"));
m_presetChoiceCB->addItem("Toon Boom Harmony", QString("otharmony"));
m_presetChoiceCB->addItem("Adobe Animate", QString("otanimate"));
m_presetChoiceCB->addItem("Adobe Flash Pro", QString("otadobe"));
TFilePath presetDir =
ToonzFolder::getMyModuleDir() + TFilePath("shortcutpresets");
if (TSystem::doesExistFileOrLevel(presetDir)) {
@ -763,12 +746,10 @@ QStringList ShortcutPopup::buildPresets() {
}
}
customPresets.sort();
presets = presets + customPresets;
for (auto customPreset : customPresets)
m_presetChoiceCB->addItem(customPreset, customPreset);
}
presets << tr("Load from file...");
m_presetChoiceCB->clear();
m_presetChoiceCB->addItems(presets);
return presets;
m_presetChoiceCB->addItem(tr("Load from file..."), QString("LoadFromFile"));
}
//-----------------------------------------------------------------------------
@ -808,19 +789,9 @@ void ShortcutPopup::setCurrentPresetPref(QString name) {
void ShortcutPopup::getCurrentPresetPref() {
QString name = Preferences::instance()->getShortcutPreset();
if (name == "DELETED")
m_presetChoiceCB->setCurrentText("");
else if (name == "deftahoma2d")
m_presetChoiceCB->setCurrentText("Tahoma2D");
else if (name == "otharmony")
m_presetChoiceCB->setCurrentText("Toon Boom Harmony");
else if (name == "otadobe")
m_presetChoiceCB->setCurrentText("Adobe Animate(Flash)");
else if (name == "otretas")
m_presetChoiceCB->setCurrentText("RETAS PaintMan");
if (name == "DELETED") name = "";
else
m_presetChoiceCB->setCurrentText(name);
m_presetChoiceCB->setCurrentIndex(m_presetChoiceCB->findData(name));
}
OpenPopupCommandHandler<ShortcutPopup> openShortcutPopup(MI_ShortcutPopup);

View file

@ -115,7 +115,7 @@ private:
bool showConfirmDialog();
bool showOverwriteDialog(QString name);
void importPreset();
QStringList buildPresets();
void buildPresets();
void showEvent(QShowEvent *se) override;
void setCurrentPresetPref(QString preset);
void getCurrentPresetPref();
@ -123,7 +123,7 @@ private:
protected slots:
void clearAllShortcuts(bool warning = true);
void onSearchTextChanged(const QString &text);
void onPresetChanged(int index);
void onPresetChanged();
void onExportButton(TFilePath fp = TFilePath());
void onDeletePreset();
void onSavePreset();

View file

@ -1297,7 +1297,7 @@ void collapseColumns(std::set<int> indices, bool columnsOnly) {
data->storeColumns(indices, xsh, StageObjectsData::eDoClone);
data->storeColumnFxs(indices, xsh, StageObjectsData::eDoClone);
ExpressionReferenceMonitor *monitor = xsh->getExpRefMonitor()->clone();
// ExpressionReferenceMonitor *monitor = xsh->getExpRefMonitor()->clone();
ToonzScene *scene = app->getCurrentScene()->getScene();
TXshLevel *xl = scene->createNewLevel(CHILD_XSHLEVEL);
@ -1320,6 +1320,7 @@ void collapseColumns(std::set<int> indices, bool columnsOnly) {
if (!columnsOnly)
bringPegbarsInsideChildXsheet(xsh, childXsh, indices, newIndices, idTable);
ExpressionReferenceManager::instance()->refreshXsheetRefInfo(childXsh);
ExpressionReferenceManager::instance()->transferReference(xsh, childXsh,
idTable, fxTable);
@ -1408,7 +1409,7 @@ void collapseColumns(std::set<int> indices,
StageObjectsData::eDoClone);
data->storeColumnFxs(indices, xsh, StageObjectsData::eDoClone);
ExpressionReferenceMonitor *monitor = xsh->getExpRefMonitor()->clone();
// ExpressionReferenceMonitor *monitor = xsh->getExpRefMonitor()->clone();
ToonzScene *scene = app->getCurrentScene()->getScene();
TXshLevel *xl = scene->createNewLevel(CHILD_XSHLEVEL);
@ -1427,6 +1428,7 @@ void collapseColumns(std::set<int> indices,
fxTable);
childXsh->updateFrameCount();
ExpressionReferenceManager::instance()->refreshXsheetRefInfo(childXsh);
ExpressionReferenceManager::instance()->transferReference(xsh, childXsh,
idTable, fxTable);
@ -1472,7 +1474,7 @@ void collapseColumns(std::set<int> indices, const std::set<TFx *> &fxs,
data->storeColumns(indices, xsh, StageObjectsData::eDoClone);
data->storeFxs(fxs, xsh, StageObjectsData::eDoClone);
ExpressionReferenceMonitor *monitor = xsh->getExpRefMonitor()->clone();
// ExpressionReferenceMonitor *monitor = xsh->getExpRefMonitor()->clone();
ToonzScene *scene = app->getCurrentScene()->getScene();
TXshLevel *xl = scene->createNewLevel(CHILD_XSHLEVEL);
@ -1491,6 +1493,7 @@ void collapseColumns(std::set<int> indices, const std::set<TFx *> &fxs,
if (!columnsOnly)
bringPegbarsInsideChildXsheet(xsh, childXsh, indices, newIndices, idTable);
ExpressionReferenceManager::instance()->refreshXsheetRefInfo(childXsh);
ExpressionReferenceManager::instance()->transferReference(xsh, childXsh,
idTable, fxTable);

View file

@ -574,6 +574,7 @@ void PaletteViewerPanel::onFreezeButtonToggled(bool frozen) {
// Cambio il livello corrente
if (!frozen) {
m_frozenPalette = nullptr;
std::set<TXshSimpleLevel *> levels;
TXsheet *xsheet = app->getCurrentXsheet()->getXsheet();
int row, column;
@ -605,6 +606,7 @@ void PaletteViewerPanel::onFreezeButtonToggled(bool frozen) {
app->getCurrentLevel()->setLevel(level);
m_paletteViewer->setPaletteHandle(ph);
} else {
m_frozenPalette = ph->getPalette();
m_paletteHandle->setPalette(ph->getPalette());
m_paletteViewer->setPaletteHandle(m_paletteHandle);
}
@ -796,30 +798,31 @@ void ColorFieldEditorController::edit(DVGui::ColorField *colorField) {
connect(m_currentColorField, SIGNAL(colorChanged(const TPixel32 &, bool)),
SLOT(onColorChanged(const TPixel32 &, bool)));
connect(m_colorFieldHandle, SIGNAL(colorStyleChanged(bool)),
SLOT(onColorStyleChanged()));
SLOT(onColorStyleChanged(bool)));
}
//-----------------------------------------------------------------------------
void ColorFieldEditorController::hide() {
disconnect(m_colorFieldHandle, SIGNAL(colorStyleChanged(bool)), this,
SLOT(onColorStyleChanged()));
SLOT(onColorStyleChanged(bool)));
}
//-----------------------------------------------------------------------------
void ColorFieldEditorController::onColorStyleChanged() {
void ColorFieldEditorController::onColorStyleChanged(bool isDragging) {
if (!m_currentColorField) return;
assert(!!m_palette);
TPixel32 color = m_palette->getStyle(1)->getMainColor();
if (m_currentColorField->getColor() == color) return;
if (m_currentColorField->getColor() == color && isDragging) return;
m_currentColorField->setColor(color);
m_currentColorField->notifyColorChanged(color, false);
m_currentColorField->notifyColorChanged(color, isDragging);
}
//-----------------------------------------------------------------------------
void ColorFieldEditorController::onColorChanged(const TPixel32 &color, bool) {
void ColorFieldEditorController::onColorChanged(const TPixel32 &color,
bool isDragging) {
if (!m_currentColorField) return;
TColorStyle *style = m_palette->getStyle(1);
if (style->getMainColor() == color) return;
@ -827,7 +830,7 @@ void ColorFieldEditorController::onColorChanged(const TPixel32 &color, bool) {
TApp::instance()
->getPaletteController()
->getCurrentPalette()
->notifyColorStyleChanged();
->notifyColorStyleChanged(isDragging);
}
//=============================================================================

View file

@ -44,6 +44,7 @@ class PaletteViewerPanel final : public StyleShortcutSwitchablePanel {
PaletteViewer *m_paletteViewer;
bool m_isFrozen;
TPaletteP m_frozenPalette;
public:
PaletteViewerPanel(QWidget *parent);
@ -133,7 +134,7 @@ public:
void hide() override;
protected slots:
void onColorStyleChanged();
void onColorStyleChanged(bool);
void onColorChanged(const TPixel32 &color, bool);
};

View file

@ -250,12 +250,13 @@ void TvpJsonLayer::build(int index, ToonzScene* scene, TXshCellColumn* column) {
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled())
instance_name = getFrameNumberWithLetters(fid.getNumber());
else {
std::string frameNumber("");
QString frameNumber("");
// set number
if (fid.getNumber() >= 0) frameNumber = std::to_string(fid.getNumber());
if (fid.getNumber() >= 0)
frameNumber = QString::number(fid.getNumber());
// add letter
if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter());
instance_name = QString::fromStdString(frameNumber);
if (!fid.getLetter().isEmpty()) frameNumber += fid.getLetter();
instance_name = frameNumber;
}
fid.setZeroPadding(frameFormats[cell.m_level.getPointer()].first);
@ -365,7 +366,7 @@ void TvpJsonClip::build(ToonzScene* scene, TXsheet* xsheet) {
continue;
}
TvpJsonLayer layer;
layer.build(col, scene, column);
layer.build(m_layers.size(), scene, column);
if (!layer.isEmpty()) m_layers.append(layer);
}
}

View file

@ -4,6 +4,8 @@
#include "tsystem.h"
#include "toonzqt/filefield.h"
#include "toonz/toonzscene.h"
#include "toonz/tscenehandle.h"
#include "toonz/sceneproperties.h"
#include <QMainWindow>
#include <QTableView>
@ -11,9 +13,20 @@
#include <QScrollArea>
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
using namespace DVGui;
namespace {
QIcon getColorChipIcon(TPixel32 color) {
QPixmap pm(15, 15);
pm.fill(QColor(color.r, color.g, color.b));
return QIcon(pm);
}
} // namespace
//=============================================================================
XDTSImportPopup::XDTSImportPopup(QStringList levelNames, ToonzScene* scene,
TFilePath scenePath)
: m_scene(scene)
@ -24,6 +37,26 @@ XDTSImportPopup::XDTSImportPopup(QStringList levelNames, ToonzScene* scene,
QPushButton* loadButton = new QPushButton(tr("Load"), this);
QPushButton* cancelButton = new QPushButton(tr("Cancel"), this);
m_tick1Combo = new QComboBox(this);
m_tick2Combo = new QComboBox(this);
QList<TSceneProperties::CellMark> marks = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCellMarks();
for (int i = 0; i < 2; i++) {
QComboBox* combo = (i == 0) ? m_tick1Combo : m_tick2Combo;
combo->addItem(tr("None"), -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++;
}
}
m_tick1Combo->setCurrentIndex(m_tick1Combo->findData(0));
m_tick2Combo->setCurrentIndex(m_tick2Combo->findData(1));
QString description =
tr("Please specify the level locations. Suggested paths "
"are input in the fields with blue border.");
@ -62,6 +95,24 @@ XDTSImportPopup::XDTSImportPopup(QStringList levelNames, ToonzScene* scene,
fieldsArea->setWidget(fieldsWidget);
m_topLayout->addWidget(fieldsArea, 1);
// cell mark area
QGridLayout* markLay = new QGridLayout();
markLay->setMargin(0);
markLay->setHorizontalSpacing(10);
markLay->setVerticalSpacing(10);
{
markLay->addWidget(new QLabel(tr("Inbetween symbol mark"), this), 0, 0,
Qt::AlignRight | Qt::AlignVCenter);
markLay->addWidget(m_tick1Combo, 0, 1);
markLay->addWidget(new QLabel(tr("Reverse sheet symbol mark"), this), 1, 0,
Qt::AlignRight | Qt::AlignVCenter);
markLay->addWidget(m_tick2Combo, 1, 1);
}
markLay->setColumnStretch(2, 1);
m_topLayout->addLayout(markLay, 0);
connect(loadButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
@ -174,8 +225,17 @@ void XDTSImportPopup::updateSuggestions(const QString samplePath) {
}
}
//-----------------------------------------------------------------------------
QString XDTSImportPopup::getLevelPath(QString levelName) {
FileField* field = m_fields.value(levelName);
if (!field) return QString();
return field->getPath();
}
}
//-----------------------------------------------------------------------------
void XDTSImportPopup::getMarkerIds(int& tick1Id, int& tick2Id) {
tick1Id = m_tick1Combo->currentData().toInt();
tick2Id = m_tick2Combo->currentData().toInt();
}

View file

@ -10,19 +10,23 @@ namespace DVGui {
class FileField;
}
class ToonzScene;
class QComboBox;
class XDTSImportPopup : public DVGui::Dialog {
Q_OBJECT
QMap<QString, DVGui::FileField *> m_fields;
QMap<QString, DVGui::FileField*> m_fields;
QStringList m_pathSuggestedLevels;
ToonzScene *m_scene;
ToonzScene* m_scene;
QComboBox *m_tick1Combo, *m_tick2Combo;
void updateSuggestions(const QString samplePath);
public:
XDTSImportPopup(QStringList levelNames, ToonzScene *scene,
XDTSImportPopup(QStringList levelNames, ToonzScene* scene,
TFilePath scenePath);
QString getLevelPath(QString levelName);
void getMarkerIds(int& tick1Id, int& tick2Id);
protected slots:
void onPathChanged();
};

View file

@ -32,10 +32,22 @@
#include <QApplication>
#include <QDesktopServices>
#include <QUrl>
#include <QComboBox>
#include <QLabel>
using namespace XdtsIo;
namespace {
static QByteArray identifierStr("exchangeDigitalTimeSheet Save Data");
QIcon getColorChipIcon(TPixel32 color) {
QPixmap pm(15, 15);
pm.fill(QColor(color.r, color.g, color.b));
return QIcon(pm);
}
int _tick1Id = -1;
int _tick2Id = -1;
bool _exportAllColumn = true;
} // namespace
//-----------------------------------------------------------------------------
void XdtsHeader::read(const QJsonObject &json) {
QRegExp rx("\\d{1,4}");
@ -60,21 +72,30 @@ void XdtsHeader::write(QJsonObject &json) const {
//-----------------------------------------------------------------------------
TFrameId XdtsFrameDataItem::str2Fid(const QString &str) const {
if (str.isEmpty()) return TFrameId::EMPTY_FRAME;
bool ok;
int frame = str.toInt(&ok);
if (ok) return TFrameId(frame);
// separate the last word as suffix
frame = str.left(str.size() - 1).toInt(&ok);
if (!ok) return TFrameId(-1); // EMPTY
if (!str[str.size() - 1].isLetter()) return TFrameId(-1); // EMPTY
char c = str[str.size() - 1].toLatin1();
return TFrameId(frame, c);
QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr());
QRegExp rx(regExpStr);
int pos = rx.indexIn(str);
if (pos < 0) return TFrameId();
if (rx.cap(2).isEmpty())
return TFrameId(rx.cap(1).toInt());
else
return TFrameId(rx.cap(1).toInt(), rx.cap(2));
}
QString XdtsFrameDataItem::fid2Str(const TFrameId &fid) const {
if (fid.getLetter() == 0) return QString::number(fid.getNumber());
return QString::number(fid.getNumber()) + QString(fid.getLetter());
if (fid.getNumber() == -1)
return QString("SYMBOL_NULL_CELL");
else if (fid.getNumber() == SYMBOL_TICK_1)
return QString("SYMBOL_TICK_1");
else if (fid.getNumber() == SYMBOL_TICK_2)
return QString("SYMBOL_TICK_2");
else if (fid.getLetter().isEmpty())
return QString::number(fid.getNumber());
return QString::number(fid.getNumber()) + fid.getLetter();
}
void XdtsFrameDataItem::read(const QJsonObject &json) {
@ -101,11 +122,13 @@ TFrameId XdtsFrameDataItem::getFrameId() const {
if (val == "SYMBOL_NULL_CELL")
return TFrameId(-1); // EMPTY
// ignore sheet symbols for now
else if (val == "SYMBOL_HYPHEN" || val == "SYMBOL_TICK_1" ||
val == "SYMBOL_TICK_2")
else if (val == "SYMBOL_HYPHEN")
return TFrameId(-2); // IGNORE
// return -1;
// return cell number
else if (val == "SYMBOL_TICK_1")
return TFrameId(SYMBOL_TICK_1);
else if (val == "SYMBOL_TICK_2")
return TFrameId(SYMBOL_TICK_2);
// return cell number
return str2Fid(m_values.at(0));
}
@ -169,7 +192,8 @@ static bool frameLessThan(const QPair<int, TFrameId> &v1,
return v1.first < v2.first;
}
QVector<TFrameId> XdtsFieldTrackItem::getCellFrameIdTrack() const {
QVector<TFrameId> XdtsFieldTrackItem::getCellFrameIdTrack(
QList<int> &tick1, QList<int> &tick2) const {
QList<QPair<int, TFrameId>> frameFids;
for (const XdtsTrackFrameItem &frame : m_frames)
frameFids.append(frame.frameFid());
@ -193,7 +217,15 @@ QVector<TFrameId> XdtsFieldTrackItem::getCellFrameIdTrack() const {
TFrameId cellFid = frameFid.second;
if (cellFid.getNumber() == -2) // IGNORE case
cells.append((cells.isEmpty()) ? TFrameId(-1) : cells.last());
else
else if (cellFid.getNumber() ==
XdtsFrameDataItem::SYMBOL_TICK_1) { // SYMBOL_TICK_1
cells.append((cells.isEmpty()) ? TFrameId(-1) : cells.last());
tick1.append(currentFrame);
} else if (cellFid.getNumber() ==
XdtsFrameDataItem::SYMBOL_TICK_2) { // SYMBOL_TICK_2
cells.append((cells.isEmpty()) ? TFrameId(-1) : cells.last());
tick2.append(currentFrame);
} else
cells.append(cellFid);
currentFrame++;
}
@ -217,7 +249,14 @@ QString XdtsFieldTrackItem::build(TXshCellColumn *column) {
// handle as the empty cell
if (!level || cell.m_level != level) cell = TXshCell();
// continue if the cell is continuous
if (prevCell == cell) continue;
if (prevCell == cell) {
// cell mark to ticks
if (_tick1Id >= 0 && column->getCellMark(row) == _tick1Id)
addFrame(row, TFrameId(XdtsFrameDataItem::SYMBOL_TICK_1));
else if (_tick2Id >= 0 && column->getCellMark(row) == _tick2Id)
addFrame(row, TFrameId(XdtsFrameDataItem::SYMBOL_TICK_2));
continue;
}
if (cell.isEmpty())
addFrame(row, TFrameId(-1));
@ -266,29 +305,37 @@ QList<int> XdtsTimeTableFieldItem::getOccupiedColumns() const {
return ret;
}
QVector<TFrameId> XdtsTimeTableFieldItem::getColumnTrack(int col) const {
QVector<TFrameId> XdtsTimeTableFieldItem::getColumnTrack(
int col, QList<int> &tick1, QList<int> &tick2) const {
for (const XdtsFieldTrackItem &track : m_tracks) {
if (track.getTrackNo() != col) continue;
return track.getCellFrameIdTrack();
return track.getCellFrameIdTrack(tick1, tick2);
}
return QVector<TFrameId>();
}
void XdtsTimeTableFieldItem::build(TXsheet *xsheet, QStringList &columnLabels) {
m_fieldId = CELL;
m_fieldId = CELL;
int exportCol = 0;
for (int col = 0; col < xsheet->getFirstFreeColumnIndex(); col++) {
if (xsheet->isColumnEmpty(col)) {
columnLabels.append("");
exportCol++;
continue;
}
TXshCellColumn *column = xsheet->getColumn(col)->getCellColumn();
// skip non-cell column
if (!column) {
columnLabels.append("");
continue;
}
XdtsFieldTrackItem track(col);
// skip inactive column
if (!_exportAllColumn && !column->isPreviewVisible()) {
continue;
}
XdtsFieldTrackItem track(exportCol);
columnLabels.append(track.build(column));
if (!track.isEmpty()) m_tracks.append(track);
exportCol++;
}
}
//-----------------------------------------------------------------------------
@ -501,6 +548,9 @@ bool XdtsIo::loadXdtsScene(ToonzScene *scene, const TFilePath &scenePath) {
return false;
}
int tick1Id, tick2Id;
popup.getMarkerIds(tick1Id, tick2Id);
TXsheet *xsh = scene->getXsheet();
XdtsTimeTableFieldItem cellField = xdtsData.timeTable().getCellField();
XdtsTimeTableHeaderItem cellHeader = xdtsData.timeTable().getCellHeader();
@ -508,9 +558,10 @@ bool XdtsIo::loadXdtsScene(ToonzScene *scene, const TFilePath &scenePath) {
QStringList layerNames = cellHeader.getLayerNames();
QList<int> columns = cellField.getOccupiedColumns();
for (int column : columns) {
QString levelName = layerNames.at(column);
TXshLevel *level = levels.value(levelName);
QVector<TFrameId> track = cellField.getColumnTrack(column);
QString levelName = layerNames.at(column);
TXshLevel *level = levels.value(levelName);
QList<int> tick1, tick2;
QVector<TFrameId> track = cellField.getColumnTrack(column, tick1, tick2);
int row = 0;
std::vector<TFrameId>::iterator it;
@ -528,6 +579,15 @@ bool XdtsIo::loadXdtsScene(ToonzScene *scene, const TFilePath &scenePath) {
xsh->setCell(row, column, TXshCell(level, TFrameId(lastFid)));
}
// set cell marks
TXshCellColumn *cellColumn = xsh->getColumn(column)->getCellColumn();
if (tick1Id >= 0) {
for (auto tick1f : tick1) cellColumn->setCellMark(tick1f, tick1Id);
}
if (tick2Id >= 0) {
for (auto tick2f : tick2) cellColumn->setCellMark(tick2f, tick2Id);
}
TStageObject *pegbar =
xsh->getStageObject(TStageObjectId::ColumnId(column));
if (pegbar) pegbar->setName(levelName.toStdString());
@ -569,18 +629,80 @@ void ExportXDTSCommand::execute() {
else
duration = xsheet->getFrameCount();
XdtsData xdtsData;
xdtsData.build(xsheet, QString::fromStdString(fp.getName()), duration);
if (xdtsData.isEmpty()) {
DVGui::error(QObject::tr("No columns can be exported."));
return;
{
_tick1Id = -1;
_tick2Id = -1;
_exportAllColumn = true;
XdtsData pre_xdtsData;
pre_xdtsData.build(xsheet, QString::fromStdString(fp.getName()), duration);
if (pre_xdtsData.isEmpty()) {
DVGui::error(QObject::tr("No columns can be exported."));
return;
}
}
static GenericSaveFilePopup *savePopup = 0;
static QComboBox *tick1Id = nullptr;
static QComboBox *tick2Id = nullptr;
static QComboBox *targetColumnCombo = nullptr;
auto 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(tr("None"), -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));
};
if (!savePopup) {
// create custom widget
QWidget *custonWidget = new QWidget();
tick1Id = new QComboBox();
tick2Id = new QComboBox();
refreshCellMarkComboItems(tick1Id);
refreshCellMarkComboItems(tick2Id);
tick1Id->setCurrentIndex(tick1Id->findData(0));
tick2Id->setCurrentIndex(tick2Id->findData(1));
targetColumnCombo = new QComboBox();
targetColumnCombo->addItem(tr("All columns"), true);
targetColumnCombo->addItem(tr("Only active columns"), false);
targetColumnCombo->setCurrentIndex(targetColumnCombo->findData(true));
QGridLayout *customLay = new QGridLayout();
customLay->setMargin(0);
customLay->setSpacing(10);
{
customLay->addWidget(new QLabel(tr("Inbetween symbol mark")), 0, 0,
Qt::AlignRight | Qt::AlignVCenter);
customLay->addWidget(tick1Id, 0, 1);
customLay->addWidget(new QLabel(tr("Reverse sheet symbol mark")), 1, 0,
Qt::AlignRight | Qt::AlignVCenter);
customLay->addWidget(tick2Id, 1, 1);
customLay->addWidget(new QLabel(tr("Target column")), 2, 0,
Qt::AlignRight | Qt::AlignVCenter);
customLay->addWidget(targetColumnCombo, 2, 1);
}
customLay->setColumnStretch(0, 1);
custonWidget->setLayout(customLay);
savePopup = new GenericSaveFilePopup(
QObject::tr("Export Exchange Digital Time Sheet (XDTS)"));
QObject::tr("Export Exchange Digital Time Sheet (XDTS)"), custonWidget);
savePopup->addFilterType("xdts");
} else {
refreshCellMarkComboItems(tick1Id);
refreshCellMarkComboItems(tick2Id);
}
if (!scene->isUntitled())
savePopup->setFolder(fp.getParentDir());
@ -598,6 +720,16 @@ void ExportXDTSCommand::execute() {
return;
}
_tick1Id = tick1Id->currentData().toInt();
_tick2Id = tick2Id->currentData().toInt();
_exportAllColumn = targetColumnCombo->currentData().toBool();
XdtsData xdtsData;
xdtsData.build(xsheet, QString::fromStdString(fp.getName()), duration);
if (xdtsData.isEmpty()) {
DVGui::error(QObject::tr("No columns can be exported."));
return;
}
QJsonObject xdtsObject;
xdtsData.write(xdtsObject);
QJsonDocument saveDoc(xdtsObject);

View file

@ -83,10 +83,11 @@ class XdtsFrameDataItem {
QString fid2Str(const TFrameId &) const;
public:
enum { SYMBOL_TICK_1 = -100, SYMBOL_TICK_2 = -200 };
XdtsFrameDataItem() : m_id(Default) {}
XdtsFrameDataItem(TFrameId fId) : m_id(Default) {
m_values.append((fId.getNumber() == -1) ? QString("SYMBOL_NULL_CELL")
: fid2Str(fId));
m_values.append(fid2Str(fId));
}
void read(const QJsonObject &json);
void write(QJsonObject &json) const;
@ -132,7 +133,8 @@ public:
void write(QJsonObject &json) const;
bool isEmpty() const { return m_frames.isEmpty(); }
int getTrackNo() const { return m_trackNo; }
QVector<TFrameId> getCellFrameIdTrack() const;
QVector<TFrameId> getCellFrameIdTrack(QList<int> &tick1,
QList<int> &tick2) const;
QString build(TXshCellColumn *);
void addFrame(int frame, TFrameId fId) {
@ -154,7 +156,8 @@ public:
void write(QJsonObject &json) const;
bool isCellField() { return m_fieldId == CELL; }
QList<int> getOccupiedColumns() const;
QVector<TFrameId> getColumnTrack(int col) const;
QVector<TFrameId> getColumnTrack(int col, QList<int> &tick1,
QList<int> &tick2) const;
void build(TXsheet *, QStringList &);
};

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,7 @@
#include "orientation.h"
#include "toonz/txshcell.h"
#include "tundo.h"
// forward declaration
class XsheetViewer;
@ -17,6 +18,20 @@ class TXshSoundTextColumn;
namespace XsheetGUI {
class SetCellMarkUndo final : public TUndo {
int m_row, m_col;
int m_idBefore, m_idAfter;
public:
SetCellMarkUndo(int row, int col, int idAfter);
void setId(int id) const;
void undo() const override;
void redo() const override;
int getSize() const override;
QString getHistoryString() override;
int getHistoryType() override;
};
class NoteWidget;
class DragTool;
@ -103,6 +118,7 @@ class CellArea final : public QWidget {
bool showLevelName = true);
void drawSoundTextCell(QPainter &p, int row, int col);
void drawSoundCell(QPainter &p, int row, int col, bool isReference = false);
void drawSoundTextColumn(QPainter &p, int r0, int r1, int col);
void drawPaletteCell(QPainter &p, int row, int col, bool isReference = false);
void drawKeyframe(QPainter &p, const QRect toBeUpdated);
@ -166,7 +182,8 @@ protected:
/*!Crea il menu' del tasto destro che si visualizza quando si clicca sulla
cella,
distinguendo i due casi: cella piena, cella vuota.*/
void createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell);
void createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell, int row,
int col);
//! Crea il menu' del tasto destro che si visualizza si clicca su un key
//! frame.
void createKeyMenu(QMenu &menu);
@ -182,6 +199,7 @@ protected slots:
void onStepChanged(QAction *);
// replace level with another level in the cast
void onReplaceByCastedLevel(QAction *action);
void onSetCellMark();
};
} // namespace XsheetGUI

View file

@ -1043,7 +1043,7 @@ void ColumnArea::DrawHeader::drawColumnName() const {
// ZeraryFx columns store name elsewhere
TXshZeraryFxColumn *zColumn = dynamic_cast<TXshZeraryFxColumn *>(column);
if (zColumn)
if (zColumn && !isEmpty)
name = ::to_string(zColumn->getZeraryColumnFx()->getZeraryFx()->getName());
QRect columnName = o->rect((col < 0) ? PredefinedRect::CAMERA_LAYER_NAME

View file

@ -60,6 +60,7 @@
#include "duplicatepopup.h"
#include "menubarcommandids.h"
#include "columncommand.h"
#include "xshcellviewer.h" // SetCellMarkUndo
// Qt includes
#include <QClipboard>
@ -2199,6 +2200,43 @@ public:
} ToggleXsheetCameraColumnCommand;
//-----------------------------------------------------------------------------
class SetCellMarkCommand final : public MenuItemHandler {
int m_markId;
public:
SetCellMarkCommand(int markId)
: MenuItemHandler(
((std::string)MI_SetCellMark + std::to_string(markId)).c_str())
, m_markId(markId) {}
void execute() override {
TApp *app = TApp::instance();
TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
int currentRow = app->getCurrentFrame()->getFrame();
int currentColumn = app->getCurrentColumn()->getColumnIndex();
if (!xsh->getColumn(currentColumn)) return;
TXshCellColumn *cellColumn = xsh->getColumn(currentColumn)->getCellColumn();
if (!cellColumn) return;
XsheetGUI::SetCellMarkUndo *undo =
new XsheetGUI::SetCellMarkUndo(currentRow, currentColumn, m_markId);
undo->redo();
TUndoManager::manager()->add(undo);
}
};
SetCellMarkCommand CellMarkCommand0(0);
SetCellMarkCommand CellMarkCommand1(1);
SetCellMarkCommand CellMarkCommand2(2);
SetCellMarkCommand CellMarkCommand3(3);
SetCellMarkCommand CellMarkCommand4(4);
SetCellMarkCommand CellMarkCommand5(5);
SetCellMarkCommand CellMarkCommand6(6);
SetCellMarkCommand CellMarkCommand7(7);
SetCellMarkCommand CellMarkCommand8(8);
SetCellMarkCommand CellMarkCommand9(9);
SetCellMarkCommand CellMarkCommand10(10);
SetCellMarkCommand CellMarkCommand11(11);
//============================================================

View file

@ -551,7 +551,7 @@ public:
int i;
for (i = 1; i < count; i++)
if (m_sourceCells[i].m_level != cell.m_level ||
m_sourceCells[i].m_frameId.getLetter() != 0)
!m_sourceCells[i].m_frameId.getLetter().isEmpty())
return;
// check if all the selected cells have the same frame number

View file

@ -162,6 +162,7 @@ set(HEADERS
../include/toonz/preferencesitemids.h
../include/toonz/txsheetcolumnchange.h
../include/toonz/expressionreferencemonitor.h
../include/toonz/filepathproperties.h
)
set(SOURCES
@ -320,6 +321,7 @@ set(SOURCES
txshmeshcolumn.cpp
textureutils.cpp
boardsettings.cpp
filepathproperties.cpp
)
if(BUILD_TARGET_WIN)

View file

@ -6,6 +6,7 @@
#include "toonz/toonzscene.h"
#include "toonz/sceneproperties.h"
#include "toonz/txshleveltypes.h"
#include "toonz/cleanupcolorstyles.h"
#include "tsystem.h"
#include "tenv.h"
#include "tconvert.h"
@ -193,7 +194,10 @@ CleanupParameters::CleanupParameters()
, m_dirtyFlag(false)
//, m_resName("")
, m_offx_lock(false)
, m_offy_lock(false) {}
, m_offy_lock(false)
, m_altBrightness(0)
, m_altContrast(50)
, m_lpNoneFormat("tif") {}
//---------------------------------------------------------
@ -300,8 +304,11 @@ void CleanupParameters::assign(const CleanupParameters *param,
if (clonePalette && param->m_cleanupPalette)
m_cleanupPalette = param->m_cleanupPalette->clone();
m_offx_lock = param->m_offx_lock;
m_offy_lock = param->m_offy_lock;
m_offx_lock = param->m_offx_lock;
m_offy_lock = param->m_offy_lock;
m_altBrightness = param->m_altBrightness;
m_altContrast = param->m_altContrast;
m_lpNoneFormat = param->m_lpNoneFormat;
}
//---------------------------------------------------------
@ -330,10 +337,10 @@ void CleanupParameters::saveData(TOStream &os) const {
attr.clear();
std::string flip =
std::string(m_flipx ? "x" : "") + std::string(m_flipy ? "y" : "");
if (flip != "") attr["flip"] = flip;
if (flip != "") attr["flip"] = flip;
if (m_rotate != 0) attr["rotate"] = std::to_string(m_rotate);
if (m_offx != 0.0) attr["xoff"] = std::to_string(m_offx);
if (m_offy != 0.0) attr["yoff"] = std::to_string(m_offy);
if (m_offx != 0.0) attr["xoff"] = std::to_string(m_offx);
if (m_offy != 0.0) attr["yoff"] = std::to_string(m_offy);
os.openCloseChild("transform", attr);
}
@ -366,6 +373,8 @@ void CleanupParameters::saveData(TOStream &os) const {
os.openCloseChild("fdg", attr);
attr.clear();
if (m_path != TFilePath()) os.child("path") << m_path;
os.child("altBrightnessContrast") << m_altBrightness << m_altContrast;
os.child("lpNoneFormat") << m_lpNoneFormat;
}
//---------------------------------------------------------
@ -380,6 +389,9 @@ void CleanupParameters::loadData(TIStream &is, bool globalParams) {
m_lineProcessingMode = lpNone;
m_noAntialias = false;
m_postAntialias = false;
// hold brightness and contrast values of another processing mode
m_altBrightness = -1.0;
m_altContrast = -1.0;
while (is.matchTag(tagName)) {
if (tagName == "cleanupPalette") {
@ -390,42 +402,42 @@ void CleanupParameters::loadData(TIStream &is, bool globalParams) {
m_camera.loadData(is);
is.closeChild();
} else if (tagName == "autoCenter") {
m_autocenterType = AUTOCENTER_FDG;
std::string s = is.getTagAttribute("type");
m_autocenterType = AUTOCENTER_FDG;
std::string s = is.getTagAttribute("type");
if (s != "" && isInt(s)) m_autocenterType = (AUTOCENTER_TYPE)std::stoi(s);
s = is.getTagAttribute("pegHoles");
s = is.getTagAttribute("pegHoles");
if (s != "" && isInt(s)) m_pegSide = (PEGS_SIDE)std::stoi(s);
} else if (tagName == "transform") {
std::string s = is.getTagAttribute("flip");
m_flipx = (s.find("x") != std::string::npos);
m_flipy = (s.find("y") != std::string::npos);
s = is.getTagAttribute("rotate");
if (s != "" && isInt(s)) m_rotate = std::stoi(s);
s = is.getTagAttribute("xoff");
std::string s = is.getTagAttribute("flip");
m_flipx = (s.find("x") != std::string::npos);
m_flipy = (s.find("y") != std::string::npos);
s = is.getTagAttribute("rotate");
if (s != "" && isInt(s)) m_rotate = std::stoi(s);
s = is.getTagAttribute("xoff");
if (s != "" && isDouble(s)) m_offx = std::stod(s);
s = is.getTagAttribute("yoff");
s = is.getTagAttribute("yoff");
if (s != "" && isDouble(s)) m_offy = std::stod(s);
} else if (tagName == "lineProcessing") {
m_lineProcessingMode = lpGrey;
std::string s = is.getTagAttribute("sharpness");
m_lineProcessingMode = lpGrey;
std::string s = is.getTagAttribute("sharpness");
if (s != "" && isDouble(s)) m_sharpness = std::stod(s);
s = is.getTagAttribute("autoAdjust");
if (s != "" && isDouble(s))
m_autoAdjustMode = (CleanupTypes::AUTO_ADJ_MODE)std::stoi(s);
s = is.getTagAttribute("mode");
s = is.getTagAttribute("mode");
if (s != "" && s == "color") m_lineProcessingMode = lpColor;
} else if (tagName == "despeckling") {
std::string s = is.getTagAttribute("value");
std::string s = is.getTagAttribute("value");
if (s != "" && isInt(s)) m_despeckling = std::stoi(s);
} else if (tagName == "aaValue") {
std::string s = is.getTagAttribute("value");
std::string s = is.getTagAttribute("value");
if (s != "" && isInt(s)) m_aaValue = std::stoi(s);
} else if (tagName == "noAntialias")
m_noAntialias = true;
else if (tagName == "MLAA")
m_postAntialias = true;
else if (tagName == "closestField") {
std::string s = is.getTagAttribute("value");
std::string s = is.getTagAttribute("value");
if (s != "" && isDouble(s)) m_closestField = std::stod(s);
} else if (tagName == "fdg") {
std::string s = is.getTagAttribute("name");
@ -433,10 +445,26 @@ void CleanupParameters::loadData(TIStream &is, bool globalParams) {
} else if (tagName == "path") {
is >> m_path;
is.closeChild();
} else if (tagName == "altBrightnessContrast") {
is >> m_altBrightness >> m_altContrast;
is.closeChild();
} else if (tagName == "lpNoneFormat") {
is >> m_lpNoneFormat;
is.closeChild();
} else
is.skipCurrentTag();
}
if ((m_altBrightness < 0.0 || m_altContrast < 0.0) && m_cleanupPalette &&
m_cleanupPalette->getStyleCount() >= 2) {
TCleanupStyle *blackStyle =
dynamic_cast<TCleanupStyle *>(m_cleanupPalette->getStyle(1));
if (blackStyle) {
m_altBrightness = blackStyle->getBrightness();
m_altContrast = blackStyle->getContrast();
}
}
CleanupParameters::LastSavedParameters.assign(this);
if (globalParams) CleanupParameters::GlobalParameters.assign(this);
}

View file

@ -0,0 +1,38 @@
#include "toonz/filepathproperties.h"
// TnzCore includes
#include "tstream.h"
FilePathProperties::FilePathProperties()
: m_useStandard(true)
, m_acceptNonAlphabetSuffix(false)
, m_letterCountForSuffix(1) {}
bool FilePathProperties::isDefault() {
return (m_useStandard == true && m_acceptNonAlphabetSuffix == false &&
m_letterCountForSuffix == 1);
}
void FilePathProperties::saveData(TOStream& os) const {
os.child("useStandard") << ((m_useStandard) ? 1 : 0);
os.child("acceptNonAlphabetSuffix") << ((m_acceptNonAlphabetSuffix) ? 1 : 0);
os.child("letterCountForSuffix") << m_letterCountForSuffix;
}
// make sure to let TFilePath to know the new properties!
void FilePathProperties::loadData(TIStream& is) {
int val;
std::string tagName;
while (is.matchTag(tagName)) {
if (tagName == "useStandard") {
is >> val;
m_useStandard = (val == 1);
} else if (tagName == "acceptNonAlphabetSuffix") {
is >> val;
m_acceptNonAlphabetSuffix = (val == 1);
} else if (tagName == "letterCountForSuffix") {
is >> m_letterCountForSuffix;
}
is.closeChild();
}
}

View file

@ -129,6 +129,9 @@ inline void setFxParamToCurrentScene(TFx *fx, TXsheet *xsh) {
void initializeFx(TXsheet *xsh, TFx *fx) {
if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx))
fx = zcfx->getZeraryFx();
// if the fx has not unique name then let assignUniqueId() set the default
// name
if (fx->getName() != L"" && fx->getName() == fx->getFxId()) fx->setName(L"");
xsh->getFxDag()->assignUniqueId(fx);
setFxParamToCurrentScene(fx, xsh);

View file

@ -335,6 +335,9 @@ TopToBottomOrientation::TopToBottomOrientation() {
addRect(PredefinedRect::KEYFRAME_AREA,
QRect(CELL_WIDTH - KEY_ICON_WIDTH, 0, KEY_ICON_WIDTH, CELL_HEIGHT));
addRect(PredefinedRect::DRAG_AREA, QRect(0, 0, CELL_DRAG_WIDTH, CELL_HEIGHT));
int markSize = CELL_HEIGHT * 8 / 10; // 80% size
addRect(PredefinedRect::CELL_MARK_AREA,
QRect(CELL_DRAG_WIDTH - 3, 2, markSize, markSize));
QRect soundRect(CELL_DRAG_WIDTH, 0,
CELL_WIDTH - CELL_DRAG_WIDTH - SOUND_PREVIEW_WIDTH,
CELL_HEIGHT);
@ -1111,6 +1114,9 @@ LeftToRightOrientation::LeftToRightOrientation() {
EXTENDER_HEIGHT));
addRect(PredefinedRect::KEYFRAME_AREA, keyRect);
addRect(PredefinedRect::DRAG_AREA, QRect(0, 0, CELL_WIDTH, CELL_DRAG_HEIGHT));
int markSize = CELL_HEIGHT / 2; // 50% size (12px)
addRect(PredefinedRect::CELL_MARK_AREA,
QRect(1, CELL_DRAG_HEIGHT + 1, markSize, markSize));
QRect soundRect(0, CELL_DRAG_HEIGHT, CELL_WIDTH,
CELL_HEIGHT - CELL_DRAG_HEIGHT - SOUND_PREVIEW_HEIGHT);
addRect(PredefinedRect::SOUND_TRACK, soundRect);

View file

@ -94,7 +94,7 @@ inline bool formatLess(const Preferences::LevelFormat &a,
//=================================================================
void getDefaultLevelFormats(LevelFormatVector &lfv) {
lfv.resize(3);
lfv.resize(2);
{
LevelFormat &lf = lfv[0];
@ -215,6 +215,13 @@ void getValue(QSettings &settings,
++it;
}
changed = true;
}
// remove the "empty" condition which may inserted due to the previous bug
else if ((*it).m_name.isEmpty() &&
(*it).m_pathFormat == QRegExp(".*", Qt::CaseInsensitive) &&
(*it).m_priority == 1 && (*it).m_options == LevelOptions()) {
it = lfv.erase(it);
changed = true;
} else
++it;
}

View file

@ -22,6 +22,23 @@
#include "tproperty.h"
#include "tiio.h"
namespace {
const TSceneProperties::CellMark cellMarkDefault[12] = {
{QObject::tr("Red"), TPixel32(167, 55, 55)},
{QObject::tr("Orange"), TPixel32(195, 115, 40)},
{QObject::tr("Yellow"), TPixel32(214, 183, 22)},
{QObject::tr("Light Green"), TPixel32(165, 179, 57)},
{QObject::tr("Green"), TPixel32(82, 157, 79)},
{QObject::tr("Light Blue"), TPixel32(71, 142, 165)},
{QObject::tr("Blue"), TPixel32(64, 103, 172)},
{QObject::tr("Dark Blue"), TPixel32(60, 49, 187)},
{QObject::tr("Purple"), TPixel32(108, 66, 170)},
{QObject::tr("Pink"), TPixel32(161, 75, 140)},
{QObject::tr("Dark Pink"), TPixel32(111, 29, 108)},
{QObject::tr("White"), TPixel32(255, 255, 255)}};
}
//=============================================================================
TSceneProperties::TSceneProperties()
@ -47,6 +64,9 @@ TSceneProperties::TSceneProperties()
m_notesColor.push_back(TPixel32(145, 240, 145));
m_notesColor.push_back(TPixel32(130, 255, 210));
m_notesColor.push_back(TPixel32(150, 245, 255));
// Default Cell Marks
for (int i = 0; i < 12; i++) m_cellMarks.push_back(cellMarkDefault[i]);
}
//-----------------------------------------------------------------------------
@ -77,7 +97,7 @@ void TSceneProperties::assign(const TSceneProperties *sprop) {
if (sprop != this) {
m_cameras = sprop->m_cameras;
for (int i = 0; i < (int)m_cameras.size(); i++)
for (int i = 0; i < (int)m_cameras.size(); i++)
m_cameras[i] = new TCamera(*m_cameras[i]);
}
m_bgColor = sprop->m_bgColor;
@ -142,7 +162,7 @@ void TSceneProperties::setFieldGuideSize(int size) {
void TSceneProperties::setFieldGuideAspectRatio(double ar) {
assert(ar >= 0);
if (ar <= 0) ar = 1;
if (ar <= 0) ar = 1;
m_fieldGuideAspectRatio = ar;
}
@ -196,8 +216,8 @@ void TSceneProperties::saveData(TOStream &os) const {
os.child("threadsIndex") << out.getThreadIndex();
os.child("maxTileSizeIndex") << out.getMaxTileSizeIndex();
os.child("subcameraPrev") << (out.isSubcameraPreview() ? 1 : 0);
os.child("stereoscopic") << (rs.m_stereoscopic ? 1 : 0)
<< rs.m_stereoscopicShift;
os.child("stereoscopic")
<< (rs.m_stereoscopic ? 1 : 0) << rs.m_stereoscopicShift;
switch (rs.m_quality) {
case TRenderSettings::StandardResampleQuality:
@ -313,6 +333,12 @@ void TSceneProperties::saveData(TOStream &os) const {
os.openChild("noteColors");
for (i = 0; i < m_notesColor.size(); i++) os << m_notesColor.at(i);
os.closeChild();
if (!hasDefaultCellMarks()) {
os.openChild("cellMarks");
for (auto mark : m_cellMarks) os << mark.name.toStdString() << mark.color;
os.closeChild();
}
}
//-----------------------------------------------------------------------------
@ -413,7 +439,7 @@ void TSceneProperties::loadData(TIStream &is, bool isLoadingProject) {
if (name == "preview")
outPtr = m_previewProp;
else if (name == "main")
outPtr = m_outputProp;
outPtr = m_outputProp;
TOutputProperties &out = *outPtr;
TRenderSettings renderSettings;
if (globFrom != -1)
@ -697,6 +723,15 @@ void TSceneProperties::loadData(TIStream &is, bool isLoadingProject) {
assert(i == 7);
} else if (tagName == "cameraCaputureSaveInPath") {
is >> m_camCapSaveInPath;
} else if (tagName == "cellMarks") {
int i = 0;
while (!is.eos()) {
TPixel32 color;
std::string name;
is >> name >> color;
m_cellMarks.replace(i, {QString::fromStdString(name), color});
i++;
}
} else {
throw TException("unexpected property tag: " + tagName);
}
@ -770,3 +805,34 @@ TPixel32 TSceneProperties::getNoteColor(int colorIndex) const {
void TSceneProperties::setNoteColor(TPixel32 color, int colorIndex) {
m_notesColor[colorIndex] = color;
}
//-----------------------------------------------------------------------------
QList<TSceneProperties::CellMark> TSceneProperties::getCellMarks() const {
return m_cellMarks;
}
//-----------------------------------------------------------------------------
TSceneProperties::CellMark TSceneProperties::getCellMark(int index) const {
return m_cellMarks[index];
}
//-----------------------------------------------------------------------------
void TSceneProperties::setCellMark(const TSceneProperties::CellMark &mark,
int index) {
m_cellMarks[index] = mark;
}
//-----------------------------------------------------------------------------
// check if the cell mark settings are modified
bool TSceneProperties::hasDefaultCellMarks() const {
if (m_cellMarks.size() != 12) return false;
for (int i = 0; i < 12; i++) {
if (m_cellMarks.at(i).name != cellMarkDefault[i].name ||
m_cellMarks.at(i).color != cellMarkDefault[i].color)
return false;
}
return true;
}

View file

@ -206,10 +206,10 @@ QScriptValue Scene::getCell(int row, int col) {
if (sl) {
QScriptValue level = create(engine(), new Level(sl));
QScriptValue fid;
if (cell.m_frameId.getLetter() == 0)
if (cell.m_frameId.getLetter().isEmpty())
fid = cell.m_frameId.getNumber();
else
fid = QString::fromStdString(cell.m_frameId.expand());
fid = QString::fromStdString(cell.m_frameId.expand());
QScriptValue result = engine()->newObject();
result.setProperty("level", level);
result.setProperty("fid", fid);

View file

@ -160,7 +160,7 @@ HSVColor HSVColor::fromRGB(double r, double g, double b) {
h = 2.0 + (b - r) / delta;
else if (b == max)
h = 4.0 + (r - g) / delta;
h = h * 60.0;
h = h * 60.0;
if (h < 0) h += 360.0;
}
@ -569,7 +569,7 @@ TRasterP TCleanupper::processColors(const TRasterP &rin) {
CleanupPreprocessedImage *TCleanupper::process(
TRasterImageP &image, bool first_image, TRasterImageP &onlyResampledImage,
bool isCameraTest, bool returnResampled, bool onlyForSwatch,
TAffine *resampleAff) {
TAffine *resampleAff, TRasterP templateForResampled) {
TAffine aff;
double blur;
TDimension outDim(0, 0);
@ -682,7 +682,9 @@ CleanupPreprocessedImage *TCleanupper::process(
TRasterP tmp_ras;
if (returnResampled || (fromGr8 && toGr8)) {
if (fromGr8 && toGr8)
if (templateForResampled)
tmp_ras = templateForResampled->create(outDim.lx, outDim.ly);
else if (fromGr8 && toGr8)
tmp_ras = TRasterGR8P(outDim);
else
tmp_ras = TRaster32P(outDim);
@ -709,7 +711,7 @@ CleanupPreprocessedImage *TCleanupper::process(
flt_type = TRop::Hann2;
TRop::resample(tmp_ras, image->getRaster(), aff, flt_type, blur);
if ((TRaster32P)tmp_ras)
if ((TRaster32P)tmp_ras && !templateForResampled)
// Add white background to deal with semitransparent pixels
TRop::addBackground(tmp_ras, TPixel32::White);

View file

@ -10,6 +10,7 @@
#include "toonz/toonzfolders.h"
#include "toonz/cleanupparameters.h"
#include "toonz/preferences.h"
#include "toonz/filepathproperties.h"
// TnzBase includes
#include "tenv.h"
@ -17,6 +18,7 @@
// TnzCore includes
#include "tsystem.h"
#include "tstream.h"
#include "tfilepath.h"
#include "tfilepath_io.h"
#include "tconvert.h"
@ -321,11 +323,18 @@ TFilePath getDesktopPath() {
\see TProjectManager and TOStream.
*/
TProject::TProject() : m_name(), m_path(), m_sprop(new TSceneProperties()) {}
TProject::TProject()
: m_name()
, m_path()
, m_sprop(new TSceneProperties())
, m_fpProp(new FilePathProperties()) {}
//-------------------------------------------------------------------
TProject::~TProject() { delete m_sprop; }
TProject::~TProject() {
delete m_sprop;
delete m_fpProp;
}
//-------------------------------------------------------------------
/*! Associates the \b name to the specified \b path.
@ -615,6 +624,13 @@ bool TProject::save(const TFilePath &projectPath) {
os.openChild("sceneProperties");
getSceneProperties().saveData(os);
os.closeChild();
if (!getFilePathProperties()->isDefault()) {
os.openChild("filePathProperties");
getFilePathProperties()->saveData(os);
os.closeChild();
}
os.closeChild();
// crea (se necessario) le directory relative ai vari folder
@ -725,6 +741,9 @@ void TProject::load(const TFilePath &projectPath) {
}
setSceneProperties(sprop);
is.matchEndTag();
} else if (tagName == "filePathProperties") {
m_fpProp->loadData(is);
is.matchEndTag();
}
}
@ -1038,6 +1057,12 @@ TProjectP TProjectManager::getCurrentProject() {
assert(TProject::isAProjectPath(fp));
currentProject = new TProject();
currentProject->load(fp);
// update TFilePath condition on loading the current project
FilePathProperties *fpProp = currentProject->getFilePathProperties();
TFilePath::setFilePathProperties(fpProp->useStandard(),
fpProp->acceptNonAlphabetSuffix(),
fpProp->letterCountForSuffix());
}
return currentProject;
}

View file

@ -19,6 +19,7 @@
#include "toonz/txshleveltypes.h"
#include <QMap>
#include "tstream.h"
namespace {
QMap<int, QPair<QString, TPixel32>> filterColors;
@ -144,12 +145,12 @@ void TXshCellColumn::getCells(int row, int rowCount, TXshCell cells[]) {
}
if (n + src > cellCount) n = cellCount - src;
TXshCell *dstCell = cells;
TXshCell *endDstCell = dstCell + dst;
TXshCell *dstCell = cells;
TXshCell *endDstCell = dstCell + dst;
while (dstCell < endDstCell) *dstCell++ = emptyCell;
endDstCell += n;
while (dstCell < endDstCell) *dstCell++ = m_cells[src++];
endDstCell = cells + rowCount;
endDstCell = cells + rowCount;
while (dstCell < endDstCell) *dstCell++ = emptyCell;
}
@ -243,7 +244,7 @@ bool TXshCellColumn::setCells(int row, int rowCount, const TXshCell cells[]) {
if (row > c_rb) // sono oltre l'ultima riga
{
if (oldCellCount == 0) m_first = row; // row 'e la nuova firstrow
int newCellCount = row - m_first + rowCount;
int newCellCount = row - m_first + rowCount;
m_cells.resize(newCellCount);
} else if (row < m_first) {
int delta = m_first - row;
@ -278,8 +279,9 @@ bool TXshCellColumn::setCells(int row, int rowCount, const TXshCell cells[]) {
//-----------------------------------------------------------------------------
void TXshCellColumn::insertEmptyCells(int row, int rowCount) {
if (m_cells.empty()) return; // se la colonna e' vuota non devo inserire
// celle
if (m_cells.empty())
return; // se la colonna e' vuota non devo inserire
// celle
if (row >= m_first + (int)m_cells.size()) return; // dopo:non inserisco nulla
if (row <= m_first) // prima
@ -426,6 +428,70 @@ bool TXshCellColumn::getLevelRange(int row, int &r0, int &r1) const {
return true;
}
//-----------------------------------------------------------------------------
void TXshCellColumn::saveCellMarks(TOStream &os) {
if (m_cellMarkIds.isEmpty()) return;
// gather frame numbers with the same id
QMap<int, QString> idStrMap;
QMap<int, int>::const_iterator i = m_cellMarkIds.constBegin();
while (i != m_cellMarkIds.constEnd()) {
if (!idStrMap.contains(i.value()))
idStrMap.insert(i.value(), QString::number(i.key()));
else
idStrMap[i.value()] += " " + QString::number(i.key());
++i;
}
os.openChild("cellMarks");
QMap<int, QString>::const_iterator j = idStrMap.constBegin();
while (j != idStrMap.constEnd()) {
std::map<std::string, std::string> attr;
attr["id"] = std::to_string(j.key());
os.openChild("cellMark", attr);
os << j.value();
os.closeChild();
++j;
}
os.closeChild();
}
bool TXshCellColumn::loadCellMarks(std::string tagName, TIStream &is) {
if (tagName != "cellMarks") return false;
m_cellMarkIds.clear();
while (is.openChild(tagName)) {
if (tagName == "cellMark") {
int id;
QString frameStr;
if (is.getTagParam("id", id)) {
is >> frameStr;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QStringList frameStrList = frameStr.split(" ", Qt::SkipEmptyParts);
#else
QStringList frameStrList = frameStr.split(" ", QString::SkipEmptyParts);
#endif
for (auto fStr : frameStrList) m_cellMarkIds.insert(fStr.toInt(), id);
}
}
is.closeChild();
}
return true;
}
void TXshCellColumn::setCellMark(int frame, int id) {
if (id < 0)
m_cellMarkIds.remove(frame);
else
m_cellMarkIds.insert(frame, id);
}
int TXshCellColumn::getCellMark(int frame) const {
return m_cellMarkIds.value(frame, -1);
}
QMap<int, int> TXshCellColumn::getCellMarks() const { return m_cellMarkIds; }
void TXshCellColumn::clearCellMarks() { m_cellMarkIds.clear(); }
//=============================================================================
// TXshColumn

View file

@ -1061,8 +1061,8 @@ int TXsheet::exposeLevel(int row, int col, TXshLevel *xl, bool overwrite) {
//-----------------------------------------------------------------------------
// customized version for load level popup
int TXsheet::exposeLevel(int row, int col, TXshLevel *xl,
std::vector<TFrameId> &fIds_, int xFrom, int xTo,
int step, int inc, int frameCount,
std::vector<TFrameId> &fIds_, TFrameId xFrom,
TFrameId xTo, int step, int inc, int frameCount,
bool doesFileActuallyExist) {
if (!xl) return 0;
std::vector<TFrameId> fids;
@ -1104,7 +1104,7 @@ int TXsheet::exposeLevel(int row, int col, TXshLevel *xl,
{
std::vector<TFrameId>::iterator it;
it = fids.begin();
while (it->getNumber() < xFrom) it++;
while (*it < xFrom) it++;
if (step == 0) // Step = Auto
{
@ -1112,14 +1112,12 @@ int TXsheet::exposeLevel(int row, int col, TXshLevel *xl,
next_it = it;
next_it++;
int startFrame = it->getNumber();
for (int f = startFrame; f < startFrame + frameCount; f++) {
if (next_it != fids.end() && f >= next_it->getNumber()) {
for (int f = 0; f < frameCount; f++) {
setCell(row++, col, TXshCell(xl, *it));
if (next_it != fids.end()) {
it++;
next_it++;
}
setCell(row++, col, TXshCell(xl, *it));
}
}
@ -1143,7 +1141,7 @@ int TXsheet::exposeLevel(int row, int col, TXshLevel *xl,
loopCount = frameCount / step;
for (int loop = 0; loop < loopCount; loop++) {
TFrameId id(xFrom + loop * inc, fids.begin()->getLetter());
TFrameId id(xFrom.getNumber() + loop * inc, xFrom.getLetter());
for (int s = 0; s < step; s++) {
setCell(row++, col, TXshCell(xl, id));
}
@ -1224,6 +1222,12 @@ void TXsheet::loadData(TIStream &is) {
}
}
}
} else if (tagName == "cameraColumn") {
while (is.openChild(tagName)) {
if (!m_cameraColumn->getCellColumn()->loadCellMarks(tagName, is))
throw TException("Camera Column, unknown tag: " + tagName);
is.closeChild();
}
} else if (tagName == "pegbars") {
TPersist *p = m_imp->m_pegTree;
m_imp->m_pegTree->loadData(is, this);
@ -1280,6 +1284,14 @@ void TXsheet::saveData(TOStream &os) {
if (column && c < getFirstFreeColumnIndex()) os << column.getPointer();
}
os.closeChild();
// save cell marks in the camera column
if (!m_cameraColumn->getCellColumn()->getCellMarks().isEmpty()) {
os.openChild("cameraColumn");
m_cameraColumn->getCellColumn()->saveCellMarks(os);
os.closeChild();
}
os.openChild("pegbars");
m_imp->m_pegTree->saveData(os, getFirstFreeColumnIndex(), this);
// os << *(m_imp->m_pegTree);

View file

@ -17,24 +17,17 @@ TFrameId qstringToFrameId(QString str) {
return TFrameId::EMPTY_FRAME;
else if (str == "-" || str == "-2")
return TFrameId::NO_FRAME;
TFrameId fid;
int s = 0;
QString number;
char letter(0);
for (s = 0; s < str.size(); s++) {
QChar c = str.at(s);
if (c.isNumber()) number.append(c);
#if QT_VERSION >= 0x050500
else
letter = c.toLatin1();
#else
else
letter = c.toAscii();
#endif
}
return TFrameId(number.toInt(), letter);
}
QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr());
QRegExp rx(regExpStr);
int pos = rx.indexIn(str);
if (pos < 0) return TFrameId();
if (rx.cap(2).isEmpty())
return TFrameId(rx.cap(1).toInt());
else
return TFrameId(rx.cap(1).toInt(), rx.cap(2));
}
} // namespace
//-----------------------------------------------------------------------------
@ -123,13 +116,13 @@ void TXshLevelColumn::loadData(TIStream &is) {
while (is.openChild(tagName)) {
if (tagName == "cell") {
TPersist *p = 0;
QString str;
std::string str;
int row = 1, rowCount = 1, increment = 0;
TFilePath path;
is >> row >> rowCount >> p >> str >> increment;
TFrameId fid = qstringToFrameId(str);
assert((fid.getLetter() == 0 && rowCount >= 0) ||
(fid.getLetter() != 0 && rowCount == 1));
TFrameId fid = qstringToFrameId(QString::fromStdString(str));
assert((fid.getLetter().isEmpty() && rowCount >= 0) ||
(!fid.getLetter().isEmpty() && rowCount == 1));
TXshLevel *xshLevel = dynamic_cast<TXshLevel *>(p);
if (xshLevel) {
int fidNumber = fid.getNumber();
@ -158,9 +151,10 @@ void TXshLevelColumn::loadData(TIStream &is) {
{
TFxSet fxSet;
fxSet.loadData(is);
} else {
} else if (loadCellMarks(tagName, is)) {
// do nothing
} else
throw TException("TXshLevelColumn, unknown tag: " + tagName);
}
is.closeChild();
}
}
@ -182,11 +176,11 @@ void TXshLevelColumn::saveData(TOStream &os) {
int n = 1, inc = 0, dr = fid.getNumber();
// If fid has not letter save more than one cell and its incrementation;
// otherwise save one cell.
if (r < r1 && fid.getLetter() == 0) {
if (r < r1 && fid.getLetter().isEmpty()) {
TXshCell cell2 = getCell(r + 1);
TFrameId fid2 = cell2.m_frameId;
if (cell2.m_level.getPointer() == cell.m_level.getPointer() &&
fid2.getLetter() == 0) {
fid2.getLetter().isEmpty()) {
inc = cell2.m_frameId.getNumber() - dr;
n++;
for (;;) {
@ -194,7 +188,7 @@ void TXshLevelColumn::saveData(TOStream &os) {
cell2 = getCell(r + n);
TFrameId fid2 = cell2.m_frameId;
if (cell2.m_level.getPointer() != cell.m_level.getPointer() ||
fid2.getLetter() != 0)
!fid2.getLetter().isEmpty())
break;
if (fid2.getNumber() != dr + n * inc) break;
n++;
@ -208,6 +202,9 @@ void TXshLevelColumn::saveData(TOStream &os) {
os.closeChild();
}
os.child("fx") << m_fx;
// cell marks
saveCellMarks(os);
}
//-----------------------------------------------------------------------------

View file

@ -24,28 +24,16 @@ TFrameId qstringToFrameId(QString str) {
else if (str == "-" || str == "-2")
return TFrameId::NO_FRAME;
TFrameId fid;
QString number;
char letter(0);
int s, strSize = str.size();
for (s = 0; s < strSize; ++s) {
QChar c = str.at(s);
if (c.isNumber())
number.append(c);
else
#if QT_VERSION >= 0x050500
letter = c.toLatin1();
#else
letter = c.toAscii();
#endif
}
return TFrameId(number.toInt(), letter);
}
QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr());
QRegExp rx(regExpStr);
int pos = rx.indexIn(str);
if (pos < 0) return TFrameId();
if (rx.cap(2).isEmpty())
return TFrameId(rx.cap(1).toInt());
else
return TFrameId(rx.cap(1).toInt(), rx.cap(2));
}
} // namespace
//*******************************************************************************
// TXshMeshColumn implementation
@ -94,12 +82,12 @@ void TXshMeshColumn::saveData(TOStream &os) {
// If fid has no letter save more than one cell and its increment -
// otherwise save just one cell
if (r < r1 && fid.getLetter() == 0) {
if (r < r1 && fid.getLetter().isEmpty()) {
TXshCell cell2 = getCell(r + 1);
TFrameId fid2 = cell2.m_frameId;
if (cell2.m_level.getPointer() == cell.m_level.getPointer() &&
fid2.getLetter() == 0) {
fid2.getLetter().isEmpty()) {
inc = cell2.m_frameId.getNumber() - dr;
for (++n;; ++n) {
if (r + n > r1) break;
@ -108,7 +96,7 @@ void TXshMeshColumn::saveData(TOStream &os) {
TFrameId fid2 = cell2.m_frameId;
if (cell2.m_level.getPointer() != cell.m_level.getPointer() ||
fid2.getLetter() != 0)
!fid2.getLetter().isEmpty())
break;
if (fid2.getNumber() != dr + n * inc) break;
@ -123,6 +111,8 @@ void TXshMeshColumn::saveData(TOStream &os) {
}
os.closeChild();
}
// cell marks
saveCellMarks(os);
}
//------------------------------------------------------------------
@ -150,16 +140,16 @@ void TXshMeshColumn::loadData(TIStream &is) {
while (is.openChild(tagName)) {
if (tagName == "cell") {
TPersist *p = 0;
QString str;
std::string str;
int row = 1, rowCount = 1, increment = 0;
TFilePath path;
is >> row >> rowCount >> p >> str >> increment;
TFrameId fid = qstringToFrameId(str);
assert((fid.getLetter() == 0 && rowCount >= 0) ||
(fid.getLetter() != 0 && rowCount == 1));
TFrameId fid = qstringToFrameId(QString::fromStdString(str));
assert((fid.getLetter().isEmpty() && rowCount >= 0) ||
(!fid.getLetter().isEmpty() && rowCount == 1));
TXshLevel *xshLevel = dynamic_cast<TXshLevel *>(p);
if (xshLevel) {
@ -179,6 +169,8 @@ void TXshMeshColumn::loadData(TIStream &is) {
is.skipCurrentTag();
}
is.closeChild();
} else if (loadCellMarks(tagName, is)) {
is.closeChild();
} else
is.skipCurrentTag();

View file

@ -73,6 +73,8 @@ void TXshPaletteColumn::loadData(TIStream &is) {
TPersist *p = 0;
is >> p;
if (TFx *fx = dynamic_cast<TFx *>(p)) setFx(fx);
} else if (loadCellMarks(tagName, is)) {
// do nothing
} else {
throw TException("TXshLevelColumn, unknown tag: " + tagName);
}
@ -107,6 +109,9 @@ void TXshPaletteColumn::saveData(TOStream &os) {
os.closeChild();
}
os.child("fx") << m_fx;
// cell marks
saveCellMarks(os);
}
PERSIST_IDENTIFIER(TXshPaletteColumn, "paletteColumn")

View file

@ -485,7 +485,8 @@ int TXshSimpleLevel::guessStep() const {
TFrameId firstFid = *ft++, secondFid = *ft++;
if (firstFid.getLetter() != 0 || secondFid.getLetter() != 0) return 1;
if (!firstFid.getLetter().isEmpty() || !secondFid.getLetter().isEmpty())
return 1;
int step = secondFid.getNumber() - firstFid.getNumber();
if (step == 1) return 1;
@ -494,7 +495,7 @@ int TXshSimpleLevel::guessStep() const {
// (cerco di limitare il numero di volte in cui devo controllare tutta la
// lista)
TFrameId lastFid = *m_frames.rbegin();
if (lastFid.getLetter() != 0) return 1;
if (!lastFid.getLetter().isEmpty()) return 1;
if (lastFid.getNumber() != firstFid.getNumber() + step * (frameCount - 1))
return 1;
@ -502,7 +503,7 @@ int TXshSimpleLevel::guessStep() const {
for (int i = 2; ft != m_frames.end(); ++ft, ++i) {
const TFrameId &fid = *ft;
if (fid.getLetter() != 0) return 1;
if (!fid.getLetter().isEmpty()) return 1;
if (fid.getNumber() != firstFid.getNumber() + step * i) return 1;
}
@ -642,7 +643,8 @@ void TXshSimpleLevel::loadAllIconsAndPutInCache(bool cacheImagesAsWell) {
//-----------------------------------------------------------------------------
TRasterImageP TXshSimpleLevel::getFrameToCleanup(const TFrameId &fid) const {
TRasterImageP TXshSimpleLevel::getFrameToCleanup(const TFrameId &fid,
bool toBeLineProcessed) const {
assert(m_type != UNKNOWN_XSHLEVEL);
FramesSet::const_iterator ft = m_frames.find(fid);
@ -652,8 +654,12 @@ TRasterImageP TXshSimpleLevel::getFrameToCleanup(const TFrameId &fid) const {
std::string imageId = getImageId(fid, flag ? Scanned : 0);
ImageLoader::BuildExtData extData(this, fid, 1);
TRasterImageP img = ImageManager::instance()->getImage(
imageId, ImageManager::dontPutInCache, &extData);
UCHAR imFlags = ImageManager::dontPutInCache;
// if lines are not processed, obtain the original sampled image
if (!toBeLineProcessed) imFlags |= ImageManager::is64bitEnabled;
TRasterImageP img =
ImageManager::instance()->getImage(imageId, imFlags, &extData);
if (!img) return img;
double x_dpi, y_dpi;

View file

@ -262,6 +262,13 @@ void TXshSoundColumn::loadData(TIStream &is) {
is >> status;
setStatusWord(status);
}
std::string tagName;
while (is.openChild(tagName)) {
if (!loadCellMarks(tagName, is))
throw TException("TXshLevelColumn, unknown tag: " + tagName);
is.closeChild();
}
}
//-----------------------------------------------------------------------------
@ -274,6 +281,8 @@ void TXshSoundColumn::saveData(TOStream &os) {
int i;
for (i = 0; i < levelsCount; i++) m_levels.at(i)->saveData(os);
os << getStatusWord();
// cell marks
saveCellMarks(os);
}
//-----------------------------------------------------------------------------

View file

@ -68,18 +68,28 @@ void TXshSoundTextColumn::loadData(TIStream &is) {
if (tagName == "cells") {
while (is.openChild(tagName)) {
if (tagName == "cell") {
TPersist *p = 0;
int row = 1;
int fidNumber = 1;
TPersist *p = 0;
std::string rowRangeStr = "1";
int fidNumber = 1;
TFilePath path;
is >> row >> fidNumber >> p;
is >> rowRangeStr >> fidNumber >> p;
TXshLevel *xshLevel = dynamic_cast<TXshLevel *>(p);
TXshCell cell(xshLevel, TFrameId(fidNumber));
setCell(row, cell);
QString _rowRangeStr = QString::fromStdString(rowRangeStr);
QStringList rows = _rowRangeStr.split('-');
if (rows.size() == 1)
setCell(rows[0].toInt(), cell);
else if (rows.size() == 2) {
for (int r = rows[0].toInt(); r <= rows[1].toInt(); r++)
setCell(r, cell);
}
} else
throw TException("TXshLevelColumn, unknown tag(2): " + tagName);
is.closeChild();
}
} else if (loadCellMarks(tagName, is)) {
// do nothing
} else
throw TException("TXshLevelColumn, unknown tag: " + tagName);
is.closeChild();
@ -92,14 +102,47 @@ void TXshSoundTextColumn::saveData(TOStream &os) {
int r0, r1;
if (getRange(r0, r1)) {
os.openChild("cells");
TXshCell prevCell;
int fromR = r0;
for (int r = r0; r <= r1; r++) {
TXshCell cell = getCell(r);
if (cell.isEmpty()) continue;
TFrameId fid = cell.m_frameId;
os.child("cell") << r << fid.getNumber() << cell.m_level.getPointer();
if (cell != prevCell) {
if (!prevCell.isEmpty()) {
int toR = r - 1;
TFrameId fid = prevCell.m_frameId;
if (fromR == toR)
os.child("cell")
<< toR << fid.getNumber() << prevCell.m_level.getPointer();
else {
QString rangeStr = QString("%1-%2").arg(fromR).arg(toR);
os.child("cell") << rangeStr.toStdString() << fid.getNumber()
<< prevCell.m_level.getPointer();
}
}
prevCell = cell;
fromR = r;
}
assert(cell == prevCell);
if (r == r1) {
if (!cell.isEmpty()) {
int toR = r;
TFrameId fid = cell.m_frameId;
if (fromR == toR)
os.child("cell")
<< toR << fid.getNumber() << cell.m_level.getPointer();
else {
QString rangeStr = QString("%1-%2").arg(fromR).arg(toR);
os.child("cell") << rangeStr.toStdString() << fid.getNumber()
<< cell.m_level.getPointer();
}
}
}
}
os.closeChild();
}
// cell marks
saveCellMarks(os);
}
PERSIST_IDENTIFIER(TXshSoundTextColumn, "soundTextColumn")

View file

@ -29,7 +29,8 @@ TXshZeraryFxColumn::TXshZeraryFxColumn(int frameCount)
TXshZeraryFxColumn::TXshZeraryFxColumn(const TXshZeraryFxColumn &src)
: m_zeraryColumnFx(new TZeraryColumnFx())
, m_zeraryFxLevel(new TXshZeraryFxLevel()) {
, m_zeraryFxLevel(new TXshZeraryFxLevel())
, m_iconVisible(false) {
m_zeraryColumnFx->addRef();
m_zeraryColumnFx->setColumn(this);
m_zeraryFxLevel->addRef();
@ -161,6 +162,8 @@ void TXshZeraryFxColumn::loadData(TIStream &is) {
throw TException("expected <cell>");
is.closeChild();
}
} else if (loadCellMarks(tagName, is)) {
// do nothing
} else
throw TException("expected <status> or <cells>");
is.closeChild();
@ -185,6 +188,8 @@ void TXshZeraryFxColumn::saveData(TOStream &os) {
}
os.closeChild();
}
// cell marks
saveCellMarks(os);
}
//-----------------------------------------------------------------------------

View file

@ -129,7 +129,8 @@ void CommandManager::define(CommandId id, CommandType type,
(node->m_enabled &&
(node->m_handler || node->m_qaction->actionGroup() != 0)) ||
node->m_type == MiscCommandType ||
node->m_type == ToolModifierCommandType);
node->m_type == ToolModifierCommandType ||
node->m_type == CellMarkCommandType);
m_qactionTable[qaction] = node;
qaction->setShortcutContext(Qt::ApplicationShortcut);
@ -371,7 +372,7 @@ QAction *CommandManager::createAction(CommandId id, QObject *parent,
if (!refAction) return 0;
QString text = refAction->text();
if (node->m_onText != "" && node->m_offText != "")
text = state ? node->m_onText : node->m_offText;
text = state ? node->m_onText : node->m_offText;
QAction *action = new QAction(text, parent);
action->setShortcut(refAction->shortcut());
return action;
@ -533,24 +534,24 @@ void DVMenuAction::setActions(QList<QString> actions) {
namespace {
QString changeStringNumber(QString str, int index) {
QString newStr = str;
int n = 3;
QString newStr = str;
int n = 3;
if (index >= 10) n = 4;
QString number;
newStr.replace(0, n, number.number(index + 1) + QString(". "));
return newStr;
}
}
} // namespace
//-----------------------------------------------------------------------------
void DVMenuAction::onTriggered(QAction *action) {
QVariant data = action->data();
QVariant data = action->data();
if (data.isValid()) m_triggeredActionIndex = data.toInt();
CommandManager::instance()->execute(action, menuAction());
int oldIndex = m_triggeredActionIndex;
if (m_triggeredActionIndex != -1) m_triggeredActionIndex = -1;
QString str = data.toString();
QString str = data.toString();
QAction *tableAction =
CommandManager::instance()->getAction(str.toStdString().c_str());
if (tableAction || oldIndex == 0) return;

View file

@ -990,10 +990,20 @@ std::vector<TStageObjectId> StageObjectsData::restoreObjects(
dynamic_cast<TXshZeraryFxColumn *>(pastedColumn)) {
TZeraryColumnFx *zfx = zc->getZeraryColumnFx();
TFx *zeraryFx = zfx->getZeraryFx();
if (zeraryFx && doClone) {
std::wstring app = zeraryFx->getName();
fxDag->assignUniqueId(zeraryFx);
zeraryFx->setName(app);
if (zeraryFx) {
if (doClone) {
// if the fx has not unique name then let assignUniqueId() set the
// default name
if (zeraryFx->getName() == zeraryFx->getFxId())
zeraryFx->setName(L"");
fxDag->assignUniqueId(zeraryFx);
} else
fxDag->updateFxIdTable(zeraryFx);
if (TXshZeraryFxColumn *orig_zc =
dynamic_cast<TXshZeraryFxColumn *>(column)) {
if (TFx *origZeraryFx = orig_zc->getZeraryColumnFx()->getZeraryFx())
fxTable[origZeraryFx] = zeraryFx;
}
}
}
}
@ -1038,8 +1048,9 @@ std::vector<TStageObjectId> StageObjectsData::restoreObjects(
if (doClone) {
fx = fxOrig->clone(false);
fx->setName(fxOrig->getName());
// if the fx has not unique name then let assignUniqueId() set the default
// name
if (fx->getName() == fx->getFxId()) fx->setName(L"");
fx->getAttributes()->setId(fxOrig->getAttributes()->getId());
fx->getAttributes()->passiveCacheDataIdx() = -1;
@ -1084,7 +1095,10 @@ std::vector<TStageObjectId> StageObjectsData::restoreObjects(
linkedFx = fx->clone(false);
linkedFx->linkParams(fx);
linkedFx->setName(oldLinkedFx->getName());
// if the fx has not unique name then let assignUniqueId() set the
// default name
if (linkedFx->getName() == linkedFx->getFxId())
linkedFx->setName(L"");
linkedFx->getAttributes()->setId(
oldLinkedFx->getAttributes()->getId());
linkedFx->getAttributes()->passiveCacheDataIdx() = -1;

View file

@ -1020,8 +1020,8 @@ SplineAimChanger::~SplineAimChanger() {}
void SplineAimChanger::mouseMoveEvent(QGraphicsSceneMouseEvent *me) {
if (m_buttonState == Qt::LeftButton) {
bool increase = false;
int delta = me->screenPos().y() - me->lastScreenPos().y();
bool increase = false;
int delta = me->screenPos().y() - me->lastScreenPos().y();
if (delta < 0) increase = true;
m_delta += abs(delta);
if (m_delta > 15) {
@ -2250,10 +2250,9 @@ StageSchematicGroupNode::StageSchematicGroupNode(
, m_root(root)
, m_groupedObj(groupedObj) {
SchematicViewer *viewer = scene->getSchematicViewer();
int i;
for (i = 0; i < m_groupedObj.size(); i++) m_groupedObj[i]->addRef();
bool ret = true;
for (i = 0; i < m_groupedObj.size(); i++) m_groupedObj[i]->addRef();
bool ret = true;
std::wstring name = m_stageObject->getGroupName(false);
m_name = QString::fromStdWString(name);