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