1 #include "stylepickertool.h"
2 
3 // TnzTools includes
4 #include "tools/tool.h"
5 #include "tools/cursors.h"
6 #include "tools/stylepicker.h"
7 #include "tools/toolhandle.h"
8 
9 // TnzQt includes
10 #include "toonzqt/tselectionhandle.h"
11 #include "toonzqt/styleselection.h"
12 #include "toonzqt/gutil.h"
13 
14 // TnzLib includes
15 #include "toonz/txshsimplelevel.h"
16 #include "toonz/txshlevelhandle.h"
17 #include "toonz/tpalettehandle.h"
18 #include "toonz/stage2.h"
19 #include "toonz/tframehandle.h"
20 #include "toonz/txsheethandle.h"
21 #include "toonz/preferences.h"
22 #include "toonz/tcolumnhandle.h"
23 #include "toonz/dpiscale.h"
24 #include "toonz/palettecontroller.h"
25 #include "toonz/txshleveltypes.h"
26 #include "toonz/txshpalettelevel.h"
27 
28 // TnzCore includes
29 #include "drawutil.h"
30 #include "tvectorimage.h"
31 #include "ttoonzimage.h"
32 #include "tundo.h"
33 #include "tmsgcore.h"
34 
35 #define LINES L"Lines"
36 #define AREAS L"Areas"
37 #define ALL L"Lines & Areas"
38 
39 //========================================================================
40 // Pick Style Tool
41 //------------------------------------------------------------------------
42 
StylePickerTool()43 StylePickerTool::StylePickerTool()
44     : TTool("T_StylePicker")
45     , m_currentStyleId(0)
46     , m_colorType("Mode:")
47     , m_passivePick("Passive Pick", false)
48     , m_organizePalette("Organize Palette", false)
49     , m_paletteToBeOrganized(NULL) {
50   m_prop.bind(m_colorType);
51   m_colorType.addValue(AREAS);
52   m_colorType.addValue(LINES);
53   m_colorType.addValue(ALL);
54   m_colorType.setId("Mode");
55   bind(TTool::CommonLevels);
56 
57   m_prop.bind(m_passivePick);
58   m_passivePick.setId("PassivePick");
59 
60   m_prop.bind(m_organizePalette);
61   m_organizePalette.setId("OrganizePalette");
62 }
63 
leftButtonDown(const TPointD & pos,const TMouseEvent & e)64 void StylePickerTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
65   m_oldStyleId = m_currentStyleId =
66       getApplication()->getCurrentLevelStyleIndex();
67   pick(pos, e, false);
68 }
69 
leftButtonDrag(const TPointD & pos,const TMouseEvent & e)70 void StylePickerTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
71   pick(pos, e);
72 }
73 
pick(const TPointD & pos,const TMouseEvent & e,bool isDragging)74 void StylePickerTool::pick(const TPointD &pos, const TMouseEvent &e,
75                            bool isDragging) {
76   // Area = 0, Line = 1, All = 2
77   int modeValue = m_colorType.getIndex();
78 
79   //------------------------------------
80   // MultiLayerStylePicker
81   /*---
82                   PickしたStyleId = 0、かつ
83                   Preference で MultiLayerStylePickerが有効、かつ
84                   Scene編集モード、かつ
85                   下のカラムから拾った色がTransparentでない場合、
86                   → カレントLevelを移動する。
87   ---*/
88   if (Preferences::instance()->isMultiLayerStylePickerEnabled() &&
89       getApplication()->getCurrentFrame()->isEditingScene()) {
90     double pickRange = 10.0;
91     int superPickedColumnId =
92         getViewer()->posToColumnIndex(e.m_pos, pickRange, false);
93 
94     if (superPickedColumnId >= 0 /*-- 何かColumnに当たった場合 --*/
95         && getApplication()->getCurrentColumn()->getColumnIndex() !=
96                superPickedColumnId) /*-- かつ、Current Columnでない場合 --*/
97     {
98       /*-- そのColumnからPickを試みる --*/
99       int currentFrame = getApplication()->getCurrentFrame()->getFrame();
100       TXshCell pickedCell =
101           getApplication()->getCurrentXsheet()->getXsheet()->getCell(
102               currentFrame, superPickedColumnId);
103       TImageP pickedImage           = pickedCell.getImage(false).getPointer();
104       TToonzImageP picked_ti        = pickedImage;
105       TVectorImageP picked_vi       = pickedImage;
106       TXshSimpleLevel *picked_level = pickedCell.getSimpleLevel();
107       if ((picked_ti || picked_vi) && picked_level) {
108         TPointD tmpMousePosition = getColumnMatrix(superPickedColumnId).inv() *
109                                    getViewer()->winToWorld(e.m_pos);
110 
111         TPointD tmpDpiScale = getCurrentDpiScale(picked_level, getCurrentFid());
112 
113         tmpMousePosition.x /= tmpDpiScale.x;
114         tmpMousePosition.y /= tmpDpiScale.y;
115 
116         TAffine aff =
117             getViewer()->getViewMatrix() * getColumnMatrix(superPickedColumnId);
118         double scale2 = aff.det();
119         StylePicker superPicker(pickedImage);
120         int picked_subsampling =
121             picked_level->getImageSubsampling(pickedCell.getFrameId());
122         int superPicked_StyleId = superPicker.pickStyleId(
123             TScale(1.0 / picked_subsampling) * tmpMousePosition +
124                 TPointD(-0.5, -0.5),
125             pickRange, scale2, modeValue);
126         /*-- 何かStyleが拾えて、Transparentでない場合 --*/
127         if (superPicked_StyleId > 0) {
128           /*-- Levelの移動 --*/
129           getApplication()->getCurrentLevel()->setLevel(picked_level);
130           /*-- Columnの移動 --*/
131           getApplication()->getCurrentColumn()->setColumnIndex(
132               superPickedColumnId);
133           /*-- 選択の解除 --*/
134           if (getApplication()->getCurrentSelection()->getSelection())
135             getApplication()
136                 ->getCurrentSelection()
137                 ->getSelection()
138                 ->selectNone();
139           /*-- StyleIdの移動 --*/
140           getApplication()->setCurrentLevelStyleIndex(superPicked_StyleId,
141                                                       !isDragging);
142           return;
143         }
144       }
145     }
146   }
147   /*-- MultiLayerStylePicker ここまで --*/
148   //------------------------------------
149   TImageP image    = getImage(false);
150   TToonzImageP ti  = image;
151   TVectorImageP vi = image;
152   TXshSimpleLevel *level =
153       getApplication()->getCurrentLevel()->getSimpleLevel();
154   if ((!ti && !vi) || !level) return;
155 
156   /*-- 画面外をpickしても拾えないようにする --*/
157   if (!m_viewer->getGeometry().contains(pos)) return;
158 
159   TAffine aff     = getViewer()->getViewMatrix() * getCurrentColumnMatrix();
160   double scale2   = aff.det();
161   int subsampling = level->getImageSubsampling(getCurrentFid());
162   StylePicker picker(image);
163   int styleId =
164       picker.pickStyleId(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5),
165                          10.0, scale2, modeValue);
166 
167   if (styleId < 0) return;
168 
169   if (modeValue == 1)  // LINES
170   {
171     /*-- pickLineモードのとき、取得Styleが0の場合はカレントStyleを変えない。
172      * --*/
173     if (styleId == 0) return;
174     /*--
175      * pickLineモードのとき、PurePaintの部分をクリックしてもカレントStyleを変えない
176      * --*/
177     if (ti && picker.pickTone(TScale(1.0 / subsampling) * pos +
178                               TPointD(-0.5, -0.5)) == 255)
179       return;
180   }
181 
182   /*--- Styleを選択している場合は選択を解除する ---*/
183   TSelection *selection =
184       TTool::getApplication()->getCurrentSelection()->getSelection();
185   if (selection) {
186     TStyleSelection *styleSelection =
187         dynamic_cast<TStyleSelection *>(selection);
188     if (styleSelection) styleSelection->selectNone();
189   }
190 
191   // When clicking and switching between studio palette and level palette, the
192   // signal broadcastColorStyleSwitched is not emitted if the picked style is
193   // previously selected one.
194   // Therefore here I set the "forceEmit" flag to true in order to emit the
195   // signal whenever the picking with mouse press.
196   getApplication()->setCurrentLevelStyleIndex(styleId, !isDragging);
197 }
198 
mouseMove(const TPointD & pos,const TMouseEvent & e)199 void StylePickerTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
200   if (!m_passivePick.getValue()) return;
201   /*--- PassiveにStyleを拾う機能 ---*/
202   PaletteController *controller =
203       TTool::getApplication()->getPaletteController();
204 
205   TImageP image    = getImage(false);
206   TToonzImageP ti  = image;
207   TVectorImageP vi = image;
208   TXshSimpleLevel *level =
209       getApplication()->getCurrentLevel()->getSimpleLevel();
210   if ((!ti && !vi) || !level || !m_viewer->getGeometry().contains(pos)) {
211     controller->notifyStylePassivePicked(-1, -1, -1);
212     return;
213   }
214 
215   TAffine aff     = getViewer()->getViewMatrix() * getCurrentColumnMatrix();
216   double scale2   = aff.det();
217   int subsampling = level->getImageSubsampling(getCurrentFid());
218   StylePicker picker(image);
219   TPointD pickPos(TScale(1.0 / subsampling) * pos + TPointD(-0.5, -0.5));
220   int inkStyleId   = picker.pickStyleId(pickPos, 10.0, scale2, 1);
221   int paintStyleId = picker.pickStyleId(pickPos, 10.0, scale2, 0);
222   int tone         = picker.pickTone(pickPos);
223   controller->notifyStylePassivePicked(inkStyleId, paintStyleId, tone);
224 }
225 
getCursorId() const226 int StylePickerTool::getCursorId() const {
227   int ret;
228 
229   if (!Preferences::instance()->isMultiLayerStylePickerEnabled()) {
230     TImageP img      = getImage(false);
231     TVectorImageP vi = img;
232     TToonzImageP ti  = img;
233 
234     if (!vi && !ti) return ToolCursor::CURSOR_NO;
235   }
236 
237   /* in case the "organize palette" option is active */
238   if (m_organizePalette.getValue())
239     ret = ToolCursor::PickerCursorOrganize;
240   else if (m_colorType.getValue() == LINES)
241     ret = ToolCursor::PickerCursorLine;
242   else if (m_colorType.getValue() == AREAS)
243     ret = ToolCursor::PickerCursorArea;
244   else  // line&areas
245     ret = ToolCursor::PickerCursor;
246 
247   if (ToonzCheck::instance()->getChecks() & ToonzCheck::eBlackBg)
248     ret = ret | ToolCursor::Ex_Negate;
249   return ret;
250 }
251 
onPropertyChanged(std::string propertyName)252 bool StylePickerTool::onPropertyChanged(std::string propertyName) {
253   if (propertyName == m_organizePalette.getName()) {
254     if (m_organizePalette.getValue()) {
255       if (!startOrganizePalette()) {
256         m_organizePalette.setValue(false);
257         getApplication()->getCurrentTool()->notifyToolChanged();
258         return false;
259       }
260     } else {
261       std::cout << "End Organize Palette" << std::endl;
262       m_paletteToBeOrganized = NULL;
263     }
264   }
265   return true;
266 }
267 
startOrganizePalette()268 bool StylePickerTool::startOrganizePalette() {
269   /* Check if the organizing operation is available */
270   TXshLevel *level = getApplication()->getCurrentLevel()->getLevel();
271   if (!level) {
272     DVGui::error(tr("No current level."));
273     return false;
274   }
275   if (level->getType() != PLI_XSHLEVEL && level->getType() != TZP_XSHLEVEL &&
276       level->getType() != PLT_XSHLEVEL) {
277     DVGui::error(tr("Current level has no available palette."));
278     return false;
279   }
280   /* palette should have more than one page to organize */
281   TPalette *pal = NULL;
282   if (level->getType() == PLT_XSHLEVEL)
283     pal = level->getPaletteLevel()->getPalette();
284   else
285     pal = level->getSimpleLevel()->getPalette();
286   if (!pal || pal->getPageCount() < 2) {
287     DVGui::error(
288         tr("Palette must have more than one palette to be organized."));
289     return false;
290   }
291 
292   m_paletteToBeOrganized = pal;
293 
294   std::cout << "Start Organize Palette" << std::endl;
295 
296   return true;
297 }
298 
299 /*
300   If the working palette is changed, then deactivate the "organize palette"
301   toggle.
302 */
onImageChanged()303 void StylePickerTool::onImageChanged() {
304   std::cout << "StylePickerTool::onImageChanged" << std::endl;
305   if (!m_organizePalette.getValue() || !m_paletteToBeOrganized) return;
306 
307   TXshLevel *level = getApplication()->getCurrentLevel()->getLevel();
308   if (!level) {
309     m_organizePalette.setValue(false);
310     getApplication()->getCurrentTool()->notifyToolChanged();
311     return;
312   }
313   TPalette *pal = NULL;
314   if (level->getType() == PLT_XSHLEVEL)
315     pal = level->getPaletteLevel()->getPalette();
316   else if (level->getSimpleLevel()) {
317     pal = level->getSimpleLevel()->getPalette();
318   }
319   if (!pal || pal != m_paletteToBeOrganized) {
320     m_organizePalette.setValue(false);
321     getApplication()->getCurrentTool()->notifyToolChanged();
322     return;
323   }
324 }
325 
326 //-------------------------------------------------------------------------------------------------------
327 
updateTranslation()328 void StylePickerTool::updateTranslation() {
329   m_colorType.setQStringName(tr("Mode:"));
330   m_colorType.setItemUIName(LINES, tr("Lines"));
331   m_colorType.setItemUIName(AREAS, tr("Areas"));
332   m_colorType.setItemUIName(ALL, tr("Lines & Areas"));
333   m_passivePick.setQStringName(tr("Passive Pick"));
334   m_organizePalette.setQStringName(tr("Organize Palette"));
335 }
336 
337 //-------------------------------------------------------------------------------------------------------
338 
339 StylePickerTool stylePickerTool;
340