1 
2 
3 #include "onionskinmaskgui.h"
4 #include "tapp.h"
5 #include "toonz/tonionskinmaskhandle.h"
6 #include "toonz/tframehandle.h"
7 #include "toonz/txshlevelhandle.h"
8 #include "toonz/txsheethandle.h"
9 #include "toonz/tcolumnhandle.h"
10 #include "toonz/txshsimplelevel.h"
11 
12 #include "toonz/onionskinmask.h"
13 
14 #include <QMenu>
15 
16 //=============================================================================
17 // OnioniSkinMaskGUI::OnionSkinSwitcher
18 //-----------------------------------------------------------------------------
19 
getMask() const20 OnionSkinMask OnioniSkinMaskGUI::OnionSkinSwitcher::getMask() const {
21   return TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask();
22 }
23 
24 //------------------------------------------------------------------------------
25 
setMask(const OnionSkinMask & mask)26 void OnioniSkinMaskGUI::OnionSkinSwitcher::setMask(const OnionSkinMask &mask) {
27   TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(mask);
28   TApp::instance()->getCurrentOnionSkin()->notifyOnionSkinMaskChanged();
29 }
30 
31 //------------------------------------------------------------------------------
32 
isActive() const33 bool OnioniSkinMaskGUI::OnionSkinSwitcher::isActive() const {
34   OnionSkinMask osm = getMask();
35   return osm.isEnabled() && !osm.isEmpty();
36 }
37 
38 //------------------------------------------------------------------------------
39 
isWholeScene() const40 bool OnioniSkinMaskGUI::OnionSkinSwitcher::isWholeScene() const {
41   OnionSkinMask osm = getMask();
42   return osm.isWholeScene();
43 }
44 
45 //------------------------------------------------------------------------------
46 
activate()47 void OnioniSkinMaskGUI::OnionSkinSwitcher::activate() {
48   OnionSkinMask osm = getMask();
49   if (osm.isEnabled() && !osm.isEmpty()) return;
50   if (osm.isEmpty()) {
51     osm.setMos(-1, true);
52     osm.setMos(-2, true);
53     osm.setMos(-3, true);
54   }
55   osm.enable(true);
56   setMask(osm);
57 }
58 
59 //------------------------------------------------------------------------------
60 
deactivate()61 void OnioniSkinMaskGUI::OnionSkinSwitcher::deactivate() {
62   OnionSkinMask osm = getMask();
63   if (!osm.isEnabled() || osm.isEmpty()) return;
64   osm.enable(false);
65   setMask(osm);
66 }
67 
68 //------------------------------------------------------------------------------
69 
setWholeScene()70 void OnioniSkinMaskGUI::OnionSkinSwitcher::setWholeScene() {
71   OnionSkinMask osm = getMask();
72   osm.setIsWholeScene(true);
73   setMask(osm);
74 }
75 
76 //------------------------------------------------------------------------------
77 
setSingleLevel()78 void OnioniSkinMaskGUI::OnionSkinSwitcher::setSingleLevel() {
79   OnionSkinMask osm = getMask();
80   osm.setIsWholeScene(false);
81   setMask(osm);
82 }
83 
clearFOS()84 void OnioniSkinMaskGUI::OnionSkinSwitcher::clearFOS() {
85   OnionSkinMask osm = getMask();
86 
87   for (int i = (osm.getFosCount() - 1); i >= 0; i--)
88     osm.setFos(osm.getFos(i), false);
89 
90   setMask(osm);
91 }
92 
clearMOS()93 void OnioniSkinMaskGUI::OnionSkinSwitcher::clearMOS() {
94   OnionSkinMask osm = getMask();
95 
96   for (int i = (osm.getMosCount() - 1); i >= 0; i--)
97     osm.setMos(osm.getMos(i), false);
98 
99   setMask(osm);
100 }
101 
clearOS()102 void OnioniSkinMaskGUI::OnionSkinSwitcher::clearOS() {
103   clearFOS();
104   clearMOS();
105 }
106 
107 //------------------------------------------------------------------------------
108 
addOnionSkinCommand(QMenu * menu,bool isFilmStrip)109 void OnioniSkinMaskGUI::addOnionSkinCommand(QMenu *menu, bool isFilmStrip) {
110   static OnioniSkinMaskGUI::OnionSkinSwitcher switcher;
111   if (switcher.isActive()) {
112     QAction *dectivateOnionSkin =
113         menu->addAction(QString(QObject::tr("Deactivate Onion Skin")));
114     menu->connect(dectivateOnionSkin, SIGNAL(triggered()), &switcher,
115                   SLOT(deactivate()));
116     if (!isFilmStrip) {
117       if (switcher.isWholeScene()) {
118         QAction *limitOnionSkinToLevel =
119             menu->addAction(QString(QObject::tr("Limit Onion Skin To Level")));
120         menu->connect(limitOnionSkinToLevel, SIGNAL(triggered()), &switcher,
121                       SLOT(setSingleLevel()));
122       } else {
123         QAction *extendOnionSkinToScene =
124             menu->addAction(QString(QObject::tr("Extend Onion Skin To Scene")));
125         menu->connect(extendOnionSkinToScene, SIGNAL(triggered()), &switcher,
126                       SLOT(setWholeScene()));
127       }
128       OnionSkinMask osm = switcher.getMask();
129       if (osm.getFosCount() || osm.getMosCount()) {
130         QAction *clearAllOnionSkins = menu->addAction(
131             QString(QObject::tr("Clear All Onion Skin Markers")));
132         menu->connect(clearAllOnionSkins, SIGNAL(triggered()), &switcher,
133                       SLOT(clearOS()));
134       }
135       if (osm.getFosCount() && osm.getMosCount()) {
136         QAction *clearFixedOnionSkins = menu->addAction(
137             QString(QObject::tr("Clear All Fixed Onion Skin Markers")));
138         menu->connect(clearFixedOnionSkins, SIGNAL(triggered()), &switcher,
139                       SLOT(clearFOS()));
140         QAction *clearRelativeOnionSkins = menu->addAction(
141             QString(QObject::tr("Clear All Relative Onion Skin Markers")));
142         menu->connect(clearRelativeOnionSkins, SIGNAL(triggered()), &switcher,
143                       SLOT(clearMOS()));
144       }
145     }
146   } else {
147     QAction *activateOnionSkin =
148         menu->addAction(QString(QObject::tr("Activate Onion Skin")));
149     menu->connect(activateOnionSkin, SIGNAL(triggered()), &switcher,
150                   SLOT(activate()));
151   }
152 }
153 
154 //------------------------------------------------------------------------------
155 
resetShiftTraceFrameOffset()156 void OnioniSkinMaskGUI::resetShiftTraceFrameOffset() {
157   auto setGhostOffset = [](int firstOffset, int secondOffset) {
158     OnionSkinMask osm =
159         TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask();
160     osm.setShiftTraceGhostFrameOffset(0, firstOffset);
161     osm.setShiftTraceGhostFrameOffset(1, secondOffset);
162     TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(osm);
163   };
164 
165   TApp *app = TApp::instance();
166   if (app->getCurrentFrame()->isEditingLevel()) {
167     TXshSimpleLevel *level = app->getCurrentLevel()->getSimpleLevel();
168     if (!level) {
169       setGhostOffset(0, 0);
170       return;
171     }
172     TFrameId fid     = app->getCurrentFrame()->getFid();
173     int firstOffset  = (fid > level->getFirstFid()) ? -1 : 0;
174     int secondOffset = (fid < level->getLastFid()) ? 1 : 0;
175 
176     setGhostOffset(firstOffset, secondOffset);
177   } else {  // when scene frame is selected
178     TXsheet *xsh       = app->getCurrentXsheet()->getXsheet();
179     int col            = app->getCurrentColumn()->getColumnIndex();
180     TXshColumn *column = xsh->getColumn(col);
181     if (!column || column->isEmpty()) {
182       setGhostOffset(0, 0);
183       return;
184     }
185     int r0, r1;
186     column->getRange(r0, r1);
187     int row         = app->getCurrentFrame()->getFrame();
188     TXshCell cell   = xsh->getCell(row, col);
189     int firstOffset = -1;
190     while (1) {
191       int r = row + firstOffset;
192       if (r < r0) {
193         firstOffset = 0;
194         break;
195       }
196       if (!xsh->getCell(r, col).isEmpty() && xsh->getCell(r, col) != cell) {
197         break;
198       }
199       firstOffset--;
200     }
201     int secondOffset = 1;
202     while (1) {
203       int r = row + secondOffset;
204       if (r > r1) {
205         secondOffset = 0;
206         break;
207       }
208       if (!xsh->getCell(r, col).isEmpty() && xsh->getCell(r, col) != cell) {
209         break;
210       }
211       secondOffset++;
212     }
213     setGhostOffset(firstOffset, secondOffset);
214   }
215 }
216