#include "sceneviewer.h"
#include "sceneviewercontextmenu.h"
// Toonz includes
#include "tapp.h"
#include "menubarcommandids.h"
#include "onionskinmaskgui.h"
// TnzTools includes
#include "tools/toolhandle.h"
#include "tools/toolcommandids.h"
#include "tools/strokeselection.h"
// TnzQt includes
#include "toonzqt/menubarcommand.h"
#include "toonzqt/viewcommandids.h"
#include "toonzqt/selection.h"
#include "toonzqt/imageutils.h"
// TnzLib includes
#include "toonz/txsheethandle.h"
#include "toonz/tcolumnhandle.h"
#include "toonz/tframehandle.h"
#include "toonz/tobjecthandle.h"
#include "toonz/tstageobjecttree.h"
#include "toonz/tscenehandle.h"
#include "toonz/txshcolumn.h"
#include "toonz/tstageobjectspline.h"
#include "toonz/tstageobjectid.h"
#include "toonz/preferences.h"
// TnzCore includes
#include "tvectorimage.h"
// Qt includes
#include <QMenu>
#include <QContextMenuEvent>
#include <QSignalMapper>
static void addShowHideStageObjectCmd(QMenu *menu, const TStageObjectId &id,
bool isShow) {
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
TStageObject *pegbar = xsh->getStageObject(id);
QString cmdStr;
if (id.isCamera())
cmdStr = (isShow ? "Show " : "Hide ") +
QString::fromStdString(pegbar->getName());
else
cmdStr = (isShow ? "Show Column" : "Hide Column") +
QString::fromStdString(pegbar->getName());
QAction *showHideAction = new QAction(cmdStr, menu);
showHideAction->setData((int)id.getCode());
menu->addAction(showHideAction);
}
static void onShowHideSelectObject(QAction *action) {
TApp *app = TApp::instance();
TStageObjectId id;
id.setCode(action->data().toInt());
if (id == TStageObjectId::NoneId) return;
if (action->text().startsWith("Show ") ||
action->text().startsWith("Hide ")) {
if (id.isColumn()) {
app->getCurrentXsheet()
->getXsheet()
->getColumn(id.getIndex())
->setCamstandVisible(action->text().startsWith("Show "));
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}
} else if (action->text().startsWith("Select ")) {
if (id.isColumn()) {
app->getCurrentColumn()->setColumnIndex(id.getIndex());
app->getCurrentObject()->setObjectId(id);
} else {
app->getCurrentObject()->setObjectId(id);
app->getCurrentTool()->setTool(T_Edit);
}
}
}
static int addShowHideStageObjectCmds(const std::vector<int> &columnIndexes,
QMenu *menu, bool isShow) {
int ii, columnIndex = -1;
bool flag = true;
for (ii = columnIndexes.size() - 1; ii >= 0; ii--) {
TStageObjectId id = TStageObjectId::ColumnId(columnIndexes[ii]);
TXshColumn *col =
TApp::instance()->getCurrentXsheet()->getXsheet()->getColumn(
columnIndexes[ii]);
if (!col) continue;
if (!isShow && col->isCamstandVisible()) {
if (columnIndex == -1) columnIndex = columnIndexes[ii];
if (flag) {
menu->addSeparator();
flag = false;
}
addShowHideStageObjectCmd(menu, id, false);
} else if (isShow && !col->isCamstandVisible()) {
if (flag) {
menu->addSeparator();
flag = false;
}
addShowHideStageObjectCmd(menu, id, true);
}
}
return columnIndex;
}
SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent)
: QMenu(parent), m_viewer(parent), m_groupIndexToBeEntered(-1) {
TApp *app = TApp::instance();
bool isEditingLevel = app->getCurrentFrame()->isEditingLevel();
bool ret = true;
QAction *action = 0;
CommandManager *commandManager = CommandManager::instance();
/*- サブカメラの消去 -*/
if (parent->isEditPreviewSubcamera()) {
action = addAction(tr("Reset Subcamera"));
ret =
ret &&
parent->connect(action, SIGNAL(triggered()), SLOT(doDeleteSubCamera()));
addSeparator();
}
// tool
TTool *tool = app->getCurrentTool()->getTool();
if (tool && tool->isEnabled()) tool->addContextMenuItems(this);
// fullscreen
if (ImageUtils::FullScreenWidget *fsWidget =
dynamic_cast<ImageUtils::FullScreenWidget *>(
m_viewer->parentWidget())) {
bool isFullScreen = (fsWidget->windowState() & Qt::WindowFullScreen) != 0;
action =
commandManager->createAction(V_ShowHideFullScreen, this, !isFullScreen);
addAction(action);
ret = ret &&
parent->connect(action, SIGNAL(triggered()), fsWidget,
SLOT(toggleFullScreen()));
}
// swap compared
if (parent->canSwapCompared()) {
action = addAction(tr("Swap Compared Images"));
ret = ret &&
parent->connect(action, SIGNAL(triggered()), SLOT(swapCompared()));
}
// reset
action = commandManager->createAction(V_ZoomReset, this);
addAction(action);
ret = ret &&
parent->connect(action, SIGNAL(triggered()), SLOT(resetSceneViewer()));
if (!isEditingLevel) {
// fit camera
action = commandManager->createAction(V_ZoomFit, this);
addAction(action);
ret = ret &&
parent->connect(action, SIGNAL(triggered()), SLOT(fitToCamera()));
}
// actual pixel size
action = commandManager->createAction(V_ActualPixelSize, this);
addAction(action);
ret =
ret &&
parent->connect(action, SIGNAL(triggered()), SLOT(setActualPixelSize()));
// onion skin
if (Preferences::instance()->isOnionSkinEnabled() &&
!parent->isPreviewEnabled())
OnioniSkinMaskGUI::addOnionSkinCommand(this);
// Zero Thick
if (!parent->isPreviewEnabled())
ZeroThickToggleGui::addZeroThickCommand(this);
// preview
if (parent->isPreviewEnabled()) {
addSeparator();
// save previewed frames
action = addAction(tr("Save Previewed Frames"));
action->setShortcut(QKeySequence(
CommandManager::instance()->getKeyFromId(MI_SavePreviewedFrames)));
ret = ret &&
parent->connect(action, SIGNAL(triggered()), this,
SLOT(savePreviewedFrames()));
// regenerate preview
action = addAction(tr("Regenerate Preview"));
action->setShortcut(QKeySequence(
CommandManager::instance()->getKeyFromId(MI_RegeneratePreview)));
ret =
ret &&
parent->connect(action, SIGNAL(triggered()), SLOT(regeneratePreview()));
// regenerate frame preview
action = addAction(tr("Regenerate Frame Preview"));
action->setShortcut(QKeySequence(
CommandManager::instance()->getKeyFromId(MI_RegenerateFramePr)));
ret = ret &&
parent->connect(action, SIGNAL(triggered()),
SLOT(regeneratePreviewFrame()));
}
assert(ret);
}
SceneViewerContextMenu::~SceneViewerContextMenu() {}
void SceneViewerContextMenu::addEnterGroupCommands(const TPointD &pos) {
bool ret = true;
TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
if (!vi) return;
if (vi->isInsideGroup() > 0) {
addAction(CommandManager::instance()->getAction(MI_ExitGroup));
}
StrokeSelection *ss =
dynamic_cast<StrokeSelection *>(TSelection::getCurrent());
if (!ss) return;
for (int i = 0; i < vi->getStrokeCount(); i++)
if (ss->isSelected(i) && vi->canEnterGroup(i)) {
m_groupIndexToBeEntered = i;
addAction(CommandManager::instance()->getAction(MI_EnterGroup));
return;
}
assert(ret);
}
static QString getName(TStageObject *obj) {
return QString::fromStdString(obj->getFullName());
}
void SceneViewerContextMenu::addShowHideCommand(QMenu *menu,
TXshColumn *column) {
bool isHidden = !column->isCamstandVisible();
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
TStageObject *stageObject =
xsh->getStageObject(TStageObjectId::ColumnId(column->getIndex()));
QString text = (isHidden ? tr("Show ") : tr("Hide ")) + getName(stageObject);
QAction *action = new QAction(text, this);
action->setData(column->getIndex());
connect(action, SIGNAL(triggered()), this, SLOT(onShowHide()));
menu->addAction(action);
}
void SceneViewerContextMenu::addSelectCommand(QMenu *menu,
const TStageObjectId &id) {
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
TStageObject *stageObject = xsh->getStageObject(id);
if (!stageObject) return;
QString text = getName(stageObject);
if (menu == this) text = tr("Select ") + text;
QAction *action = new QAction(text, this);
action->setData(id.getCode());
connect(action, SIGNAL(triggered()), this, SLOT(onSetCurrent()));
menu->addAction(action);
}
void SceneViewerContextMenu::addLevelCommands(std::vector<int> &indices) {
addSeparator();
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
TStageObjectId currentId =
TApp::instance()->getCurrentObject()->getObjectId();
/*- Xsheet内の、空でないColumnを登録 -*/
std::vector<TXshColumn *> columns;
for (int i = 0; i < (int)indices.size(); i++) {
if (xsh->isColumnEmpty(indices[i])) continue;
TXshColumn *column = xsh->getColumn(indices[i]);
if (column) {
columns.push_back(column);
}
}
if (!columns.empty()) {
// show/hide
if (columns.size() > 1) {
QMenu *subMenu = addMenu(tr("Show / Hide"));
for (int i = 0; i < (int)columns.size(); i++)
addShowHideCommand(subMenu, columns[i]);
} else
addShowHideCommand(this, columns[0]);
addSeparator();
}
// selection
/*
if(selectableColumns.size()==1)
{
addSelectCommand(this,
TStageObjectId::ColumnId(selectableColumns[0]->getIndex()));
}
else
*/
/*-- Scene内の全Objectを選択可能にする --*/
TStageObjectId id;
QMenu *cameraMenu = addMenu(tr("Select Camera"));
QMenu *pegbarMenu = addMenu(tr("Select Pegbar"));
QMenu *columnMenu = addMenu(tr("Select Column"));
bool flag = false;
for (int i = 0; i < xsh->getStageObjectTree()->getStageObjectCount(); i++) {
id = xsh->getStageObjectTree()->getStageObject(i)->getId();
if (id.isColumn()) {
int columnIndex = id.getIndex();
if (xsh->isColumnEmpty(columnIndex))
continue;
else {
addSelectCommand(columnMenu, id);
flag = true;
}
} else if (id.isTable())
addSelectCommand(this, id);
else if (id.isCamera())
addSelectCommand(cameraMenu, id);
else if (id.isPegbar())
addSelectCommand(pegbarMenu, id);
}
/*- カラムがひとつも無かったらDisable -*/
if (!flag) columnMenu->setEnabled(false);
}
//-----------------------------------------------------------------------------
void SceneViewerContextMenu::enterVectorImageGroup() {
if (m_groupIndexToBeEntered == -1) return;
TVectorImageP vi =
(TVectorImageP)TTool::getImage(false); // getCurrentImage();
if (!vi) return;
vi->enterGroup(m_groupIndexToBeEntered);
TSelection *selection = TSelection::getCurrent();
if (selection) selection->selectNone();
m_viewer->update();
}
//-----------------------------------------------------------------------------
void SceneViewerContextMenu::exitVectorImageGroup() {
TVectorImageP vi =
(TVectorImageP)TTool::getImage(false); // getCurrentImage();
if (!vi) return;
vi->exitGroup();
m_viewer->update();
}
//-----------------------------------------------------------------------------
void SceneViewerContextMenu::onShowHide() {
int columnIndex = qobject_cast<QAction *>(sender())->data().toInt();
TXsheetHandle *xsheetHandle = TApp::instance()->getCurrentXsheet();
TXshColumn *column = xsheetHandle->getXsheet()->getColumn(columnIndex);
if (column) {
column->setCamstandVisible(!column->isCamstandVisible());
xsheetHandle->notifyXsheetChanged();
}
}
//-----------------------------------------------------------------------------
void SceneViewerContextMenu::onSetCurrent() {
TStageObjectId id;
id.setCode(qobject_cast<QAction *>(sender())->data().toUInt());
TApp *app = TApp::instance();
if (id.isColumn()) {
app->getCurrentColumn()->setColumnIndex(id.getIndex());
app->getCurrentObject()->setObjectId(id);
} else {
app->getCurrentObject()->setObjectId(id);
app->getCurrentTool()->setTool(T_Edit);
}
}
//-----------------------------------------------------------------------------
void SceneViewerContextMenu::savePreviewedFrames() {
Previewer::instance(m_viewer->getPreviewMode() ==
SceneViewer::SUBCAMERA_PREVIEW)
->saveRenderedFrames();
}
class ZeroThickToggle : public MenuItemHandler {
public:
ZeroThickToggle() : MenuItemHandler(MI_ZeroThick) {}
void execute() {
QAction *action = CommandManager::instance()->getAction(MI_ZeroThick);
if (!action)
return;
bool checked = action->isChecked();
enableZeroThick(checked);
}
static void enableZeroThick(bool enable = true) {
Preferences::instance()->setShow0ThickLines(enable);
TApp::instance()->getCurrentScene()->notifySceneChanged();
}
} ZeroThickToggle;
void ZeroThickToggleGui::addZeroThickCommand(QMenu *menu) {
static ZeroThickToggleHandler switcher;
if (Preferences::instance()->getShow0ThickLines()) {
QAction *hideZeroThick = menu->addAction(QString(QObject::tr("Hide Zero Thickness Lines")));
menu->connect(hideZeroThick, SIGNAL(triggered()),
&switcher, SLOT(deactivate()));
}
else {
QAction *showZeroThick = menu->addAction(QString(QObject::tr("Show Zero Thickness Lines")));
menu->connect(showZeroThick, SIGNAL(triggered()),
&switcher, SLOT(activate()));
}
}
void ZeroThickToggleGui::ZeroThickToggleHandler::activate() {
ZeroThickToggle::enableZeroThick(true);
}
void ZeroThickToggleGui::ZeroThickToggleHandler::deactivate() {
ZeroThickToggle::enableZeroThick(false);
}