New Feature : Adding Clapperboard (#2314)

* clapperboard

* fixed image item and added aspect ratio prop

* board -> clapperboard
This commit is contained in:
shun-iwasawa 2018-10-16 15:24:43 +09:00 committed by masafumi-inoue
parent fb35734678
commit cd46940982
20 changed files with 2226 additions and 28 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -0,0 +1,190 @@
<clapperboardSettingsPreset>
<duration>
24
</duration>
<boardItems>
<item>
<type>
ScenePath_Full
</type>
<name>
"Scene file path"
</name>
<rect>
0.15 0.566708 0.7 0.0433166
</rect>
<maximumFontSize>
300
</maximumFontSize>
<color>
0 0 0 255
</color>
<font>
Verdana 0 0
</font>
</item>
<item>
<type>
UserName
</type>
<name>
"User name"
</name>
<rect>
0.7 0.9 0.2 0.05
</rect>
<maximumFontSize>
300
</maximumFontSize>
<color>
0 128 0 255
</color>
<font>
Verdana 0 1
</font>
</item>
<item>
<type>
CurrentDate
</type>
<name>
"Rendering date"
</name>
<rect>
0.1 0.9 0.2 0.05
</rect>
<maximumFontSize>
300
</maximumFontSize>
<color>
0 0 0 255
</color>
<font>
Verdana 0 0
</font>
</item>
<item>
<type>
FreeText
</type>
<name>
"Type some description here"
</name>
<rect>
0.15 0.629176 0.55 0.248329
</rect>
<text>
""
</text>
<maximumFontSize>
40
</maximumFontSize>
<color>
0 0 64 255
</color>
<font>
Verdana 0 0
</font>
</item>
<item>
<type>
Duration_SecFrame
</type>
<name>
"Scene duration"
</name>
<rect>
0.351376 0.424454 0.3 0.125546
</rect>
<maximumFontSize>
300
</maximumFontSize>
<color>
0 0 0 255
</color>
<font>
Verdana 0 0
</font>
</item>
<item>
<type>
SceneName
</type>
<name>
Scene
</name>
<rect>
0.35 0.25 0.3 0.2
</rect>
<maximumFontSize>
300
</maximumFontSize>
<color>
0 0 0 255
</color>
<font>
Verdana 1 0
</font>
</item>
<item>
<type>
FreeText
</type>
<name>
"Episode #"
</name>
<rect>
0.15 0.3 0.2 0.2
</rect>
<text>
"#"
</text>
<maximumFontSize>
120
</maximumFontSize>
<color>
0 0 0 255
</color>
<font>
Verdana 0 0
</font>
</item>
<item>
<type>
ProjectName
</type>
<name>
Title
</name>
<rect>
0.15 0.1 0.7 0.15
</rect>
<maximumFontSize>
300
</maximumFontSize>
<color>
0 0 0 255
</color>
<font>
Verdana 1 0
</font>
</item>
<item>
<type>
Image
</type>
<name>
Background
</name>
<rect>
0 0 1 1
</rect>
<imgPath>
1 "clapperboards\\images\\board1.png"
</imgPath>
<imgARMode>
0
</imgARMode>
</item>
</boardItems>
</clapperboardSettingsPreset>

View file

@ -0,0 +1,141 @@
#pragma once
#ifndef BOARDSETTINGS_H
#define BOARDSETTINGS_H
#include "traster.h"
#include "tfilepath.h"
// TnzCore includes
#include "tstream.h"
#include <QList>
#include <QRectF>
#include <QColor>
#include <QPainter>
#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
class ToonzScene;
class DVAPI BoardItem {
public:
enum Type {
FreeText = 0,
ProjectName,
SceneName,
Duration_Frame,
Duration_SecFrame,
Duration_HHMMSSFF,
CurrentDate,
CurrentDateTime,
UserName,
ScenePath_Aliased,
ScenePath_Full,
MoviePath_Aliased,
MoviePath_Full,
Image,
TypeCount
};
private:
QString m_name;
Type m_type;
// item region, represented by ratio to the whole
QRectF m_rect;
// Basically the font size will be automatically
// adjusted to fit the item region.
// The maximum font size can be used to make the font
// size smaller.
int m_maximumFontSize;
// font color
QColor m_color;
// font (familiy, bold, italic)
QFont m_font;
QString m_text;
TFilePath m_imgPath;
Qt::AspectRatioMode m_imgARMode = Qt::KeepAspectRatio;
QString getContentText(ToonzScene*);
public:
BoardItem();
QRectF getRatioRect() { return m_rect; }
void setRatioRect(QRectF rect) { m_rect = rect; }
// returns the item rect in pixels
QRectF getItemRect(QSize imgSize);
void drawItem(QPainter& p, QSize imgSize, int shrink, ToonzScene* scene);
QString getName() { return m_name; }
void setName(QString name) { m_name = name; }
Type getType() { return m_type; }
void setType(Type type) { m_type = type; }
int getMaximumFontSize() { return m_maximumFontSize; }
void setMaximumFontSize(int size) { m_maximumFontSize = size; }
QColor getColor() { return m_color; }
void setColor(QColor color) { m_color = color; }
QFont& font() { return m_font; }
QString getFreeText() { return m_text; }
void setFreeText(QString text) { m_text = text; }
TFilePath getImgPath() { return m_imgPath; }
void setImgPath(TFilePath path) { m_imgPath = path; }
Qt::AspectRatioMode getImgARMode() { return m_imgARMode; }
void setImgARMode(Qt::AspectRatioMode mode) { m_imgARMode = mode; }
void saveData(TOStream& os);
void loadData(TIStream& is);
};
class DVAPI BoardSettings {
bool m_active = false;
int m_duration = 0;
QList<BoardItem> m_items;
public:
BoardSettings();
QImage getBoardImage(TDimension& dim, int shrink, ToonzScene* scene);
TRaster32P getBoardRaster(TDimension& dim, int shrink, ToonzScene* scene);
int getDuration() { return m_duration; }
bool isActive() { return m_active; }
void setActive(bool on) { m_active = on; }
int getItemCount() { return m_items.count(); }
BoardItem& getItem(int index) { return m_items[index]; }
void setDuration(int f) { m_duration = f; }
void addNewItem(int insertAt = 0);
void removeItem(int index);
void swapItems(int, int);
void saveData(TOStream& os, bool forPreset = false);
void loadData(TIStream& is);
};
#endif

View file

@ -96,7 +96,7 @@ class DVAPI ChannelField final : public QWidget {
public:
ChannelField(QWidget *parent = 0, const QString &string = "", int value = 0,
int maxValue = 255, bool horizontal = false, int labelWidth = 13,
int sliderWidth = 40);
int sliderWidth = -1);
~ChannelField() {}
@ -145,7 +145,7 @@ public:
ColorField(QWidget *parent = 0, bool isAlphaActive = true,
TPixel32 color = TPixel32(0, 0, 0, 255), int squareSize = 40,
bool useStyleEditor = true);
bool useStyleEditor = true, int sliderWidth = -1);
~ColorField() {}

View file

@ -20,6 +20,7 @@
class TPropertyGroup;
class TWidget;
class TRenderSettings;
class BoardSettings;
//=============================================================================
//! The TOutputProperties class provides a container for output properties and
@ -91,6 +92,8 @@ private:
bool m_subcameraPreview;
BoardSettings *m_boardSettings;
public:
/*!
Constructs TOutputProperties with default value.
@ -216,6 +219,8 @@ machine's CPU).
bool isSubcameraPreview() const { return m_subcameraPreview; }
void setSubcameraPreview(bool enabled) { m_subcameraPreview = enabled; }
BoardSettings *getBoardSettings() const { return m_boardSettings; }
};
//--------------------------------------------

View file

@ -158,6 +158,7 @@ set(MOC_HEADERS
reframepopup.h
autoinputcellnumberpopup.h
colormodelbehaviorpopup.h
boardsettingspopup.h
# Tracker file
dummyprocessor.h
metnum.h
@ -331,6 +332,7 @@ set(SOURCES
reframepopup.cpp
autoinputcellnumberpopup.cpp
colormodelbehaviorpopup.cpp
boardsettingspopup.cpp
# Tracker file
dummyprocessor.cpp
metnum.cpp

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100%"
height="100%"
viewBox="0 0 18 18"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="down.svg"><metadata
id="metadata12"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs10" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1375"
inkscape:window-height="637"
id="namedview8"
showgrid="false"
inkscape:zoom="13.111111"
inkscape:cx="-6.4830508"
inkscape:cy="9"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" /><path
d="M 11,9 11,2 7,2 7,9 3,9 9,16 15,9 11,9 Z"
style="fill:#e0e0e0"
id="path4"
inkscape:connector-curvature="0" /><path
d="M 6,8 6,1 12,1 12,8 17,8 8.929,17 1,8 6,8 Z M 9,15.568 14.545,9 11,9 11,2 7,2 7,9 3.41,9 9,15.568 Z"
style="fill:#111111"
id="path6"
inkscape:connector-curvature="0" /></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100%"
height="100%"
viewBox="0 0 18 18"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="up.svg"><metadata
id="metadata12"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs10" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1375"
inkscape:window-height="637"
id="namedview8"
showgrid="false"
inkscape:zoom="13.111111"
inkscape:cx="-6.4830508"
inkscape:cy="9"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" /><path
d="m 7,9 0,7 4,0 0,-7 4,0 L 9,2 3,9 7,9 Z"
style="fill:#e0e0e0"
id="path4"
inkscape:connector-curvature="0" /><path
d="M 12,10 12,17 6,17 6,10 1,10 9.071,1 17,10 12,10 Z M 9,2.432 3.455,9 7,9 7,16 11,16 11,9 14.59,9 9,2.432 Z"
style="fill:#111111"
id="path6"
inkscape:connector-curvature="0" /></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,175 @@
#pragma once
#ifndef BOARDSETTINGSPOPUP_H
#define BOARDSETTINGSPOPUP_H
#include "toonzqt/dvdialog.h"
#include "tpixel.h"
#include "filebrowserpopup.h"
#include <QWidget>
#include <QStackedWidget>
class TOutputProperties;
class QLineEdit;
class QTextEdit;
class QComboBox;
class QFontComboBox;
class QListWidget;
class BoardItem;
namespace DVGui {
class FileField;
class ColorField;
class IntLineEdit;
}
//=============================================================================
class BoardView : public QWidget {
Q_OBJECT
enum DragItem {
None = 0,
Translate,
TopLeftCorner,
TopRightCorner,
BottomRightCorner,
BottomLeftCorner,
TopEdge,
RightEdge,
BottomEdge,
LeftEdge
} m_dragItem = None;
QImage m_boardImg;
bool m_valid = false;
QRectF m_boardImgRect;
QRectF m_dragStartItemRect;
QPointF m_dragStartPos;
public:
BoardView(QWidget* parent = nullptr);
void invalidate() { m_valid = false; }
protected:
void paintEvent(QPaintEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
};
//=============================================================================
class ItemInfoView : public QStackedWidget {
Q_OBJECT
QLineEdit* m_nameEdit;
DVGui::IntLineEdit* m_maxFontSizeEdit;
QComboBox* m_typeCombo;
QTextEdit* m_textEdit;
DVGui::FileField* m_imgPathField;
QFontComboBox* m_fontCombo;
QPushButton *m_boldButton, *m_italicButton;
DVGui::ColorField* m_fontColorField;
QComboBox* m_imgARModeCombo;
QWidget *m_fontPropBox, *m_imgPropBox;
public:
ItemInfoView(QWidget* parent = nullptr);
void setCurrentItem(int index);
protected slots:
void onNameEdited();
void onMaxFontSizeEdited();
void onTypeComboActivated(int);
void onFreeTextChanged();
void onImgPathChanged();
void onFontComboChanged(const QFont&);
void onBoldButtonClicked(bool);
void onItalicButtonClicked(bool);
void onFontColorChanged(const TPixel32&, bool);
void onImgARModeComboActivated();
signals:
// if updateListView is true then update the list view as well
void itemPropertyChanged(bool updateListView);
};
//=============================================================================
class ItemListView : public QWidget {
Q_OBJECT
QListWidget* m_list;
QPushButton *m_deleteItemBtn, *m_moveUpBtn, *m_moveDownBtn;
public:
ItemListView(QWidget* parent = nullptr);
void initialize();
void updateCurrentItem();
protected slots:
void onCurrentItemSwitched(int);
void onNewItemButtonClicked();
void onDeleteItemButtonClicked();
void onMoveUpButtonClicked();
void onMoveDownButtonClicked();
signals:
void currentItemSwitched(int);
void itemAddedOrDeleted();
};
//=============================================================================
class BoardSettingsPopup : public DVGui::Dialog {
Q_OBJECT
BoardView* m_boardView;
ItemInfoView* m_itemInfoView;
ItemListView* m_itemListView;
DVGui::IntLineEdit* m_durationEdit;
void initialize();
void initializeItemTypeString(); // call once on the first launch
public:
static BoardItem* currentBoardItem;
BoardSettingsPopup(QWidget* parent = nullptr);
protected:
void showEvent(QShowEvent*) override { initialize(); }
void hideEvent(QHideEvent*) override;
protected slots:
void onCurrentItemSwitched(int);
void onItemAddedOrDeleted();
void onItemPropertyChanged(bool updateListView);
void onDurationEdited();
void onLoadPreset();
void onSavePreset();
};
//=============================================================================
class SaveBoardPresetFilePopup final : public GenericSaveFilePopup {
public:
SaveBoardPresetFilePopup();
protected:
void showEvent(QShowEvent*) override;
};
//=============================================================================
class LoadBoardPresetFilePopup final : public GenericLoadFilePopup {
public:
LoadBoardPresetFilePopup();
protected:
void showEvent(QShowEvent*) override;
};
#endif

View file

@ -156,7 +156,7 @@ public:
//! The GenericLoadFilePopup is a simple, standard Toonz popup that
//! asks the user for \a single file to be loaded from disk.
class GenericLoadFilePopup final : public FileBrowserPopup {
class GenericLoadFilePopup : public FileBrowserPopup {
public:
GenericLoadFilePopup(const QString &title);
@ -175,7 +175,7 @@ protected:
//! The GenericSaveFilePopup is a simple, standard Toonz popup that
//! asks the user for a \a single file path to save something to.
class GenericSaveFilePopup final : public FileBrowserPopup {
class GenericSaveFilePopup : public FileBrowserPopup {
public:
GenericSaveFilePopup(const QString &title);

View file

@ -8,6 +8,7 @@
#include "tapp.h"
#include "camerasettingspopup.h"
#include "pane.h"
#include "boardsettingspopup.h"
// TnzQt includes
#include "toonzqt/menubarcommand.h"
@ -25,6 +26,7 @@
#include "toonz/preferences.h"
#include "toutputproperties.h"
#include "toonz/tcamera.h"
#include "toonz/boardsettings.h"
// TnzBase includes
#include "trasterfx.h"
@ -166,6 +168,11 @@ OutputSettingsPopup::OutputSettingsPopup(bool isPreview)
otherSettingsLabel = new QLabel(tr("Other Settings"), this);
otherSettingsFrame = new QFrame(this);
m_renderButton = new QPushButton(tr("Render"), this);
// Board
m_addBoard = new DVGui::CheckBox(tr("Add Clapperboard"), this);
m_boardSettingsBtn = new QPushButton(tr("Edit Clapperboard..."), this);
// Gamma
m_gammaFld = new DVGui::DoubleLineEdit();
// Dominant Field
@ -457,39 +464,43 @@ OutputSettingsPopup::OutputSettingsPopup(bool isPreview)
otherSettingsLay->setHorizontalSpacing(5);
otherSettingsLay->setVerticalSpacing(10);
{
// clapperboard
otherSettingsLay->addWidget(m_addBoard, 0, 0);
otherSettingsLay->addWidget(m_boardSettingsBtn, 0, 2, 1, 2);
// Gamma
otherSettingsLay->addWidget(new QLabel(tr("Gamma:"), this), 0, 0,
otherSettingsLay->addWidget(new QLabel(tr("Gamma:"), this), 1, 0,
Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_gammaFld, 0, 1, 1, 3);
otherSettingsLay->addWidget(m_gammaFld, 1, 1, 1, 3);
// Dominant Field
otherSettingsLay->addWidget(new QLabel(tr("Dominant Field:"), this),
1, 0, Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_dominantFieldOm, 1, 1, 1, 4);
2, 0, Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_dominantFieldOm, 2, 1, 1, 4);
// Scene Settings' FPS
otherSettingsLay->addWidget(
new QLabel(tr("Frame Rate (linked to Scene Settings):"), this), 2,
new QLabel(tr("Frame Rate (linked to Scene Settings):"), this), 3,
0, Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_frameRateFld, 2, 1, 1, 3);
otherSettingsLay->addWidget(m_frameRateFld, 3, 1, 1, 3);
// Strech
otherSettingsLay->addWidget(new QLabel(tr("Stretch from FPS:"), this),
3, 0, Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_stretchFromFld, 3, 1);
otherSettingsLay->addWidget(new QLabel(tr(" To:"), this), 3, 2,
4, 0, Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_stretchFromFld, 4, 1);
otherSettingsLay->addWidget(new QLabel(tr(" To:"), this), 4, 2,
Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_stretchToFld, 3, 3);
otherSettingsLay->addWidget(m_stretchToFld, 4, 3);
// new in V6.1
// Multimedia rendering enum
otherSettingsLay->addWidget(
new QLabel(tr("Multiple Rendering:"), this), 4, 0,
new QLabel(tr("Multiple Rendering:"), this), 5, 0,
Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_multimediaOm, 4, 1, 1, 4);
otherSettingsLay->addWidget(m_multimediaOm, 5, 1, 1, 4);
otherSettingsLay->addWidget(m_doStereoscopy, 5, 0);
otherSettingsLay->addWidget(new QLabel(tr("Camera Shift:")), 5, 1,
otherSettingsLay->addWidget(m_doStereoscopy, 6, 0);
otherSettingsLay->addWidget(new QLabel(tr("Camera Shift:")), 6, 1,
Qt::AlignRight | Qt::AlignVCenter);
otherSettingsLay->addWidget(m_stereoShift, 5, 2);
otherSettingsLay->addWidget(m_stereoShift, 6, 2);
otherSettingsLay->addLayout(bottomGridLay, 6, 0, 4, 5);
otherSettingsLay->addLayout(bottomGridLay, 7, 0, 4, 5);
}
otherSettingsLay->setColumnStretch(0, 0);
otherSettingsLay->setColumnStretch(1, 0);
@ -548,6 +559,12 @@ OutputSettingsPopup::OutputSettingsPopup(bool isPreview)
SLOT(onChannelWidthChanged(int)));
if (!isPreview) {
// clapperboard
ret = ret && connect(m_addBoard, SIGNAL(stateChanged(int)), this,
SLOT(onAddBoardChecked(int)));
ret = ret && connect(m_boardSettingsBtn, SIGNAL(clicked()), this,
SLOT(onBoardSettingsBtnClicked()));
ret = ret && connect(m_gammaFld, SIGNAL(editingFinished()),
SLOT(onGammaFldEditFinished()));
ret = ret && connect(m_dominantFieldOm, SIGNAL(currentIndexChanged(int)),
@ -862,6 +879,18 @@ void OutputSettingsPopup::updateField() {
m_stretchToFld->setValue(renderSettings.m_timeStretchTo);
m_frameRateFld->setValue(prop->getFrameRate());
// clapperboard
BoardSettings *boardSettings = prop->getBoardSettings();
m_addBoard->setChecked(boardSettings->isActive());
// clapperboard is only available with movie formats
if (isMovieType(m_fileFormat->currentText().toStdString())) {
m_addBoard->setEnabled(true);
m_boardSettingsBtn->setEnabled(m_addBoard->isChecked());
} else {
m_addBoard->setEnabled(false);
m_boardSettingsBtn->setEnabled(false);
}
}
//-----------------------------------------------------------------------------
@ -960,6 +989,15 @@ void OutputSettingsPopup::onFormatChanged(const QString &str) {
m_threadsComboOm->setDisabled(false);
m_threadsComboOm->setCurrentIndex(2);
}
// clapperboard is only available with movie formats
if (isMovieType(str.toStdString())) {
m_addBoard->setEnabled(true);
m_boardSettingsBtn->setEnabled(m_addBoard->isChecked());
} else {
m_addBoard->setEnabled(false);
m_boardSettingsBtn->setEnabled(false);
}
}
//-----------------------------------------------------------------------------
@ -1574,6 +1612,21 @@ void OutputSettingsPopup::onFrameRateEditingFinished() {
//-----------------------------------------------------------------------------
void OutputSettingsPopup::onAddBoardChecked(int state) {
BoardSettings *boardSettings = getProperties()->getBoardSettings();
boardSettings->setActive(state == Qt::Checked);
m_boardSettingsBtn->setEnabled(state == Qt::Checked);
}
void OutputSettingsPopup::onBoardSettingsBtnClicked() {
std::cout << "board settings button clicked" << std::endl;
BoardSettingsPopup popup(this);
popup.exec();
}
//-----------------------------------------------------------------------------
OpenPopupCommandHandler<OutputSettingsPopup> openOutputSettingsPopup(
MI_OutputSettings);
OpenPopupCommandHandler<PreviewSettingsPopup> openPreviewSettingsPopup(

View file

@ -53,6 +53,10 @@ class OutputSettingsPopup : public DVGui::Dialog {
CameraSettingsPopup *m_cameraSettings;
QComboBox *m_presetCombo;
// clapperboard
DVGui::CheckBox *m_addBoard;
QPushButton *m_boardSettingsBtn;
bool m_isPreviewSettings;
void updatePresetComboItems();
@ -97,6 +101,9 @@ protected slots:
void onCameraSettingsChanged();
/*-- Scene Settings のFPSを編集できるようにする --*/
void onFrameRateEditingFinished();
// clapperboard
void onAddBoardChecked(int state);
void onBoardSettingsBtnClicked();
};
class PreviewSettingsPopup final : public OutputSettingsPopup {

View file

@ -468,5 +468,7 @@
<file>Resources/shift_and_trace.svg</file>
<file>Resources/shift_and_trace_edit.svg</file>
<file>Resources/shift_and_trace_reset.svg</file>
<file>Resources/up.svg</file>
<file>Resources/down.svg</file>
</qresource>
</RCC>

View file

@ -156,6 +156,7 @@ set(MOC_HEADERS
texturemanager.h
imagebuilders.h
../include/orientation.h
../include/toonz/boardsettings.h
)
set(HEADERS ${MOC_HEADERS})
@ -317,6 +318,7 @@ set(SOURCES
plasticdeformerfx.cpp
txshmeshcolumn.cpp
textureutils.cpp
boardsettings.cpp
)
if(BUILD_TARGET_WIN)

View file

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

View file

@ -20,6 +20,7 @@
#include "toonz/trasterimageutils.h"
#include "toonz/levelupdater.h"
#include "toutputproperties.h"
#include "toonz/boardsettings.h"
// tcg includes
#include "tcg/tcg_macros.h"
@ -160,6 +161,8 @@ public:
std::pair<bool, int> saveFrame(double frame,
const std::pair<TRasterP, TRasterP> &rasters);
std::string getRenderCacheId();
void addBoard();
};
//---------------------------------------------------------
@ -374,7 +377,15 @@ std::pair<bool, int> MovieRenderer::Imp::saveFrame(
m_renderSettings.m_timeStretchFrom;
int fr = (stretchFac != 1) ? tround(frame * stretchFac) : int(frame);
TFrameId fid(fr + 1);
int boardDuration = 0;
if (m_movieType) {
BoardSettings *bs =
m_scene->getProperties()->getOutputProperties()->getBoardSettings();
boardDuration = (bs->isActive()) ? bs->getDuration() : 0;
}
TFrameId fid(fr + 1 + boardDuration);
if (m_levelUpdaterA.get()) {
assert(m_levelUpdaterB.get() || !rasters.second);
@ -474,6 +485,8 @@ void MovieRenderer::Imp::doRenderRasterCompleted(const RenderData &renderData) {
if (m_levelUpdaterB.get())
m_levelUpdaterB->getLevelWriter()->saveSoundTrack(m_st.getPointer());
}
addBoard();
}
// Output frames must be *cloned*, since the supplied rasters will be
@ -732,6 +745,40 @@ void MovieRenderer::Imp::onRenderFinished(bool isCanceled) {
// eventually be deleted.
}
//---------------------------------------------------------
void MovieRenderer::Imp::addBoard() {
BoardSettings *boardSettings =
m_scene->getProperties()->getOutputProperties()->getBoardSettings();
if (!boardSettings->isActive()) return;
int duration = boardSettings->getDuration();
if (duration == 0) return;
// Get the image size
int shrinkX = m_renderSettings.m_shrinkX,
shrinkY = m_renderSettings.m_shrinkY;
TDimensionD cameraRes(double(m_frameSize.lx) / shrinkX,
double(m_frameSize.ly) / shrinkY);
TDimension cameraResI(cameraRes.lx, cameraRes.ly);
TRaster32P boardRas =
boardSettings->getBoardRaster(cameraResI, shrinkX, m_scene);
if (m_levelUpdaterA.get()) {
// Flush images
try {
TRasterImageP img(boardRas);
for (int f = 0; f < duration; f++) {
m_levelUpdaterA->update(TFrameId(f + 1), img);
if (m_levelUpdaterB.get())
m_levelUpdaterB->update(TFrameId(f + 1), img);
}
} catch (...) {
// Nothing. The images could not be saved for whatever reason.
// Failure is reported.
}
}
}
//======================================================================================
//======================

View file

@ -2,6 +2,9 @@
#include "toutputproperties.h"
// TnzLib includes
#include "toonz/boardsettings.h"
// TnzBase includes
#include "trasterfx.h"
@ -37,7 +40,8 @@ TOutputProperties::TOutputProperties()
, m_multimediaRendering(0)
, m_maxTileSizeIndex(0)
, m_threadIndex(2)
, m_subcameraPreview(false) {
, m_subcameraPreview(false)
, m_boardSettings(new BoardSettings()) {
m_renderSettings = new TRenderSettings();
}
@ -56,7 +60,8 @@ TOutputProperties::TOutputProperties(const TOutputProperties &src)
, m_multimediaRendering(src.m_multimediaRendering)
, m_maxTileSizeIndex(src.m_maxTileSizeIndex)
, m_threadIndex(src.m_threadIndex)
, m_subcameraPreview(src.m_subcameraPreview) {
, m_subcameraPreview(src.m_subcameraPreview)
, m_boardSettings(new BoardSettings(*src.m_boardSettings)) {
std::map<std::string, TPropertyGroup *>::iterator ft,
fEnd = m_formatProperties.end();
for (ft = m_formatProperties.begin(); ft != fEnd; ++ft) {
@ -100,6 +105,9 @@ TOutputProperties &TOutputProperties::operator=(const TOutputProperties &src) {
for (sft = src.m_formatProperties.begin(); sft != sfEnd; ++sft)
m_formatProperties[sft->first] = sft->second->clone();
delete m_boardSettings;
m_boardSettings = new BoardSettings(*src.m_boardSettings);
return *this;
}

View file

@ -11,6 +11,7 @@
#include "toonz/txshleveltypes.h"
#include "toonz/preferences.h"
#include "cleanuppalette.h"
#include "toonz/boardsettings.h"
// TnzBase includes
#include "toutputproperties.h"
@ -293,6 +294,12 @@ void TSceneProperties::saveData(TOStream &os) const {
}
os.closeChild();
if (out.getBoardSettings() && out.getBoardSettings()->getDuration()) {
os.openChild("clapperboardSettings");
out.getBoardSettings()->saveData(os);
os.closeChild();
}
os.closeChild(); // </output>
}
os.closeChild();
@ -654,6 +661,9 @@ void TSceneProperties::loadData(TIStream &is, bool isLoadingProject) {
} else
throw TException("unexpected tag: " + tagName);
} // end while
} else if (tagName == "clapperboardSettings") {
assert(out.getBoardSettings());
out.getBoardSettings()->loadData(is);
} else {
throw TException("unexpected property tag: " + tagName);
}

View file

@ -203,6 +203,7 @@ ChannelField::ChannelField(QWidget *parent, const QString &string, int value,
m_channelSlider->setRange(0, maxValue);
m_channelSlider->setValue(value);
if (sliderWidth > 0) m_channelSlider->setFixedWidth(sliderWidth);
//----layout
QGridLayout *mainLayout = new QGridLayout(this);
@ -339,7 +340,7 @@ ColorField::ColorFieldEditorController *ColorField::m_editorController = 0;
Return ColorField current color.
*/
ColorField::ColorField(QWidget *parent, bool isAlphaActive, TPixel32 color,
int squareSize, bool useStyleEditor)
int squareSize, bool useStyleEditor, int sliderWidth)
: QWidget(parent)
, m_color(color)
, m_notifyEditingChange(true)
@ -355,16 +356,20 @@ ColorField::ColorField(QWidget *parent, bool isAlphaActive, TPixel32 color,
m_colorSample = new StyleSample(this, squareSize, squareSize);
m_colorSample->setColor(m_color);
m_redChannel = new ChannelField(this, tr("R:"), m_color.r);
m_redChannel =
new ChannelField(this, tr("R:"), m_color.r, 255, false, 13, sliderWidth);
connect(m_redChannel, SIGNAL(valueChanged(int, bool)),
SLOT(onRedChannelChanged(int, bool)));
m_greenChannel = new ChannelField(this, tr("G:"), m_color.g);
m_greenChannel =
new ChannelField(this, tr("G:"), m_color.g, 255, false, 13, sliderWidth);
connect(m_greenChannel, SIGNAL(valueChanged(int, bool)),
SLOT(onGreenChannelChanged(int, bool)));
m_blueChannel = new ChannelField(this, tr("B:"), m_color.b);
m_blueChannel =
new ChannelField(this, tr("B:"), m_color.b, 255, false, 13, sliderWidth);
connect(m_blueChannel, SIGNAL(valueChanged(int, bool)),
SLOT(onBlueChannelChanged(int, bool)));
m_alphaChannel = new ChannelField(this, tr("A:"), m_color.m);
m_alphaChannel =
new ChannelField(this, tr("A:"), m_color.m, 255, false, 13, sliderWidth);
connect(m_alphaChannel, SIGNAL(valueChanged(int, bool)),
SLOT(onAlphaChannelChanged(int, bool)));