| 
									
										
										
										
											2015-02-12 23:16:25 +08:00
										 |  |  | // Aseprite
 | 
					
						
							| 
									
										
										
										
											2024-03-06 05:50:24 +08:00
										 |  |  | // Copyright (C) 2018-2024  Igara Studio S.A.
 | 
					
						
							| 
									
										
										
										
											2018-03-16 23:26:38 +08:00
										 |  |  | // Copyright (C) 2001-2018  David Capello
 | 
					
						
							| 
									
										
										
										
											2015-02-12 23:16:25 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-08-27 04:02:58 +08:00
										 |  |  | // This program is distributed under the terms of
 | 
					
						
							|  |  |  | // the End-User License Agreement for Aseprite.
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #ifdef HAVE_CONFIG_H
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   #include "config.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/ui/editor/standby_state.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "app/app.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  | #include "app/app_menus.h"
 | 
					
						
							| 
									
										
										
										
											2014-01-29 10:56:44 +08:00
										 |  |  | #include "app/color_picker.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-03 05:13:47 +08:00
										 |  |  | #include "app/commands/cmd_eyedropper.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-30 03:35:34 +08:00
										 |  |  | #include "app/commands/commands.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/commands/params.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-07 21:07:21 +08:00
										 |  |  | #include "app/doc_range.h"
 | 
					
						
							| 
									
										
										
										
											2020-06-09 03:19:00 +08:00
										 |  |  | #include "app/i18n/strings.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/ini_file.h"
 | 
					
						
							| 
									
										
										
										
											2015-05-13 22:46:49 +08:00
										 |  |  | #include "app/pref/preferences.h"
 | 
					
						
							| 
									
										
										
										
											2016-12-01 08:07:30 +08:00
										 |  |  | #include "app/tools/active_tool.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/tools/ink.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-24 19:08:34 +08:00
										 |  |  | #include "app/tools/pick_ink.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/tools/tool.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  | #include "app/ui/app_menuitem.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-15 10:24:49 +08:00
										 |  |  | #include "app/ui/doc_view.h"
 | 
					
						
							| 
									
										
										
										
											2022-03-09 07:40:11 +08:00
										 |  |  | #include "app/ui/editor/dragging_value_state.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/ui/editor/drawing_state.h"
 | 
					
						
							|  |  |  | #include "app/ui/editor/editor.h"
 | 
					
						
							|  |  |  | #include "app/ui/editor/editor_customization_delegate.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-17 03:28:48 +08:00
										 |  |  | #include "app/ui/editor/glue.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/ui/editor/handle_type.h"
 | 
					
						
							|  |  |  | #include "app/ui/editor/moving_cel_state.h"
 | 
					
						
							|  |  |  | #include "app/ui/editor/moving_pixels_state.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  | #include "app/ui/editor/moving_selection_state.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  | #include "app/ui/editor/moving_slice_state.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-04 01:05:28 +08:00
										 |  |  | #include "app/ui/editor/moving_symmetry_state.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-30 03:35:34 +08:00
										 |  |  | #include "app/ui/editor/pivot_helpers.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/ui/editor/pixels_movement.h"
 | 
					
						
							|  |  |  | #include "app/ui/editor/scrolling_state.h"
 | 
					
						
							| 
									
										
										
										
											2024-06-12 09:31:13 +08:00
										 |  |  | #include "app/ui/editor/select_text_box_state.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/ui/editor/tool_loop_impl.h"
 | 
					
						
							|  |  |  | #include "app/ui/editor/transform_handles.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  | #include "app/ui/editor/vec2.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-20 07:08:21 +08:00
										 |  |  | #include "app/ui/editor/zooming_state.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-04 01:05:28 +08:00
										 |  |  | #include "app/ui/main_window.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  | #include "app/ui/skin/skin_theme.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | #include "app/ui/status_bar.h"
 | 
					
						
							|  |  |  | #include "app/ui_context.h"
 | 
					
						
							| 
									
										
										
										
											2020-06-09 03:19:00 +08:00
										 |  |  | #include "app/util/layer_utils.h"
 | 
					
						
							| 
									
										
										
										
											2015-04-02 20:55:18 +08:00
										 |  |  | #include "app/util/new_image_from_mask.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-29 03:44:21 +08:00
										 |  |  | #include "app/util/readable_time.h"
 | 
					
						
							| 
									
										
										
										
											2023-10-05 07:00:49 +08:00
										 |  |  | #include "app/util/tile_flags_utils.h"
 | 
					
						
							| 
									
										
										
										
											2015-06-17 02:04:00 +08:00
										 |  |  | #include "base/pi.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  | #include "base/vector2d.h"
 | 
					
						
							| 
									
										
										
										
											2019-04-11 01:04:01 +08:00
										 |  |  | #include "doc/grid.h"
 | 
					
						
							| 
									
										
										
										
											2014-10-21 09:21:31 +08:00
										 |  |  | #include "doc/layer.h"
 | 
					
						
							| 
									
										
										
										
											2023-07-08 05:40:06 +08:00
										 |  |  | #include "doc/layer_tilemap.h"
 | 
					
						
							| 
									
										
										
										
											2014-10-21 09:21:31 +08:00
										 |  |  | #include "doc/mask.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  | #include "doc/slice.h"
 | 
					
						
							| 
									
										
										
										
											2014-10-21 09:21:31 +08:00
										 |  |  | #include "doc/sprite.h"
 | 
					
						
							| 
									
										
										
										
											2020-05-09 04:39:55 +08:00
										 |  |  | #include "fmt/format.h"
 | 
					
						
							| 
									
										
										
										
											2015-04-02 20:55:18 +08:00
										 |  |  | #include "gfx/rect.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-09 23:58:43 +08:00
										 |  |  | #include "os/surface.h"
 | 
					
						
							|  |  |  | #include "os/system.h"
 | 
					
						
							| 
									
										
										
										
											2012-06-18 09:49:58 +08:00
										 |  |  | #include "ui/alert.h"
 | 
					
						
							|  |  |  | #include "ui/message.h"
 | 
					
						
							|  |  |  | #include "ui/view.h"
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 21:31:13 +08:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2015-08-14 08:47:30 +08:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2016-04-20 01:24:27 +08:00
										 |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2015-08-14 08:47:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | namespace app { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-18 09:02:54 +08:00
										 |  |  | using namespace ui; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | StandbyState::StandbyState() | 
					
						
							|  |  |  |   : m_decorator(new Decorator(this)) | 
					
						
							| 
									
										
										
										
											2016-04-26 02:26:46 +08:00
										 |  |  |   , m_transformSelectionHandlesAreVisible(false) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StandbyState::~StandbyState() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   delete m_decorator; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-11 06:32:42 +08:00
										 |  |  | void StandbyState::onEnterState(Editor* editor) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-18 22:40:11 +08:00
										 |  |  |   StateWithWheelBehavior::onEnterState(editor); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   editor->setDecorator(m_decorator); | 
					
						
							| 
									
										
										
										
											2015-07-30 03:35:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-14 21:09:15 +08:00
										 |  |  |   m_pivotVisConn = Preferences::instance().selection.pivotVisibility.AfterChange.connect( | 
					
						
							| 
									
										
										
										
											2020-07-04 08:51:46 +08:00
										 |  |  |     [this, editor] { onPivotChange(editor); }); | 
					
						
							| 
									
										
										
										
											2015-08-14 21:09:15 +08:00
										 |  |  |   m_pivotPosConn = Preferences::instance().selection.pivotPosition.AfterChange.connect( | 
					
						
							| 
									
										
										
										
											2020-07-04 08:51:46 +08:00
										 |  |  |     [this, editor] { onPivotChange(editor); }); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-26 02:20:53 +08:00
										 |  |  | void StandbyState::onActiveToolChange(Editor* editor, tools::Tool* tool) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   // If the user change from a selection tool to a non-selection tool,
 | 
					
						
							|  |  |  |   // or viceversa, we've to show or hide the transformation handles.
 | 
					
						
							| 
									
										
										
										
											2016-04-26 02:26:46 +08:00
										 |  |  |   bool needDecorators = (tool && tool->getInk(0)->isSelection()); | 
					
						
							| 
									
										
										
										
											2016-10-26 06:15:36 +08:00
										 |  |  |   if (m_transformSelectionHandlesAreVisible != needDecorators || !editor->layer() || | 
					
						
							|  |  |  |       !editor->layer()->isReference()) { | 
					
						
							| 
									
										
										
										
											2016-04-26 02:26:46 +08:00
										 |  |  |     m_transformSelectionHandlesAreVisible = false; | 
					
						
							|  |  |  |     editor->invalidate(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-29 08:17:07 +08:00
										 |  |  | bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   if (editor->hasCapture()) | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   UIContext* context = UIContext::instance(); | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |   tools::Ink* clickedInk = editor->getCurrentEditorInk(); | 
					
						
							| 
									
										
										
										
											2015-04-21 03:27:09 +08:00
										 |  |  |   Site site; | 
					
						
							|  |  |  |   editor->getSite(&site); | 
					
						
							| 
									
										
										
										
											2018-07-07 22:54:44 +08:00
										 |  |  |   Doc* document = site.document(); | 
					
						
							| 
									
										
										
										
											2015-04-21 03:27:09 +08:00
										 |  |  |   Layer* layer = site.layer(); | 
					
						
							| 
									
										
										
										
											2013-01-21 05:40:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // When an editor is clicked the current view is changed.
 | 
					
						
							| 
									
										
										
										
											2018-07-15 10:24:49 +08:00
										 |  |  |   context->setActiveView(editor->getDocView()); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-31 04:10:10 +08:00
										 |  |  |   // Move symmetry
 | 
					
						
							|  |  |  |   Decorator::Handles handles; | 
					
						
							|  |  |  |   if (m_decorator->getSymmetryHandles(editor, handles)) { | 
					
						
							|  |  |  |     for (const auto& handle : handles) { | 
					
						
							|  |  |  |       if (handle.bounds.contains(msg->position())) { | 
					
						
							|  |  |  |         auto mode = (handle.align & (TOP | BOTTOM) ? app::gen::SymmetryMode::HORIZONTAL : | 
					
						
							|  |  |  |                                                      app::gen::SymmetryMode::VERTICAL); | 
					
						
							|  |  |  |         bool horz = (mode == app::gen::SymmetryMode::HORIZONTAL); | 
					
						
							|  |  |  |         auto& symmetry = Preferences::instance().document(editor->document()).symmetry; | 
					
						
							|  |  |  |         auto& axis = (horz ? symmetry.xAxis : symmetry.yAxis); | 
					
						
							|  |  |  |         editor->setState(EditorStatePtr(new MovingSymmetryState(editor, msg, mode, axis))); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   // Start scroll loop
 | 
					
						
							| 
									
										
										
										
											2017-01-07 04:44:08 +08:00
										 |  |  |   if (editor->checkForScroll(msg) || editor->checkForZoom(msg)) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |     return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Move cel X,Y coordinates
 | 
					
						
							| 
									
										
										
										
											2012-01-12 11:46:04 +08:00
										 |  |  |   if (clickedInk->isCelMovement()) { | 
					
						
							| 
									
										
										
										
											2014-11-17 05:33:31 +08:00
										 |  |  |     // Handle "Auto Select Layer"
 | 
					
						
							|  |  |  |     if (editor->isAutoSelectLayer()) { | 
					
						
							| 
									
										
										
										
											2016-10-14 06:58:42 +08:00
										 |  |  |       gfx::PointF cursor = editor->screenToEditorF(msg->position()); | 
					
						
							| 
									
										
										
										
											2014-11-24 11:09:22 +08:00
										 |  |  |       ColorPicker picker; | 
					
						
							| 
									
										
										
										
											2016-10-14 06:58:42 +08:00
										 |  |  |       picker.pickColor(site, cursor, editor->projection(), ColorPicker::FromComposition); | 
					
						
							| 
									
										
										
										
											2014-11-17 05:33:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-09 06:00:49 +08:00
										 |  |  |       const view::RealRange& range = context->range(); | 
					
						
							| 
									
										
										
										
											2017-02-08 11:28:46 +08:00
										 |  |  |       if (picker.layer() && !range.contains(picker.layer())) { | 
					
						
							| 
									
										
										
										
											2014-11-17 05:33:31 +08:00
										 |  |  |         layer = picker.layer(); | 
					
						
							|  |  |  |         if (layer) { | 
					
						
							|  |  |  |           editor->setLayer(layer); | 
					
						
							|  |  |  |           editor->flashCurrentLayer(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-01 06:58:04 +08:00
										 |  |  |     if (layer) { | 
					
						
							| 
									
										
										
										
											2014-11-24 22:50:02 +08:00
										 |  |  |       // TODO we should be able to move the `Background' with tiled mode
 | 
					
						
							| 
									
										
										
										
											2013-03-12 07:29:45 +08:00
										 |  |  |       if (layer->isBackground()) { | 
					
						
							| 
									
										
										
										
											2022-01-07 19:35:20 +08:00
										 |  |  |         StatusBar::instance()->showTip(1000, Strings::statusbar_tips_cannot_move_bg_layer()); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-06-16 02:27:38 +08:00
										 |  |  |       else if (!layer->isVisibleHierarchy()) { | 
					
						
							| 
									
										
										
										
											2020-05-09 04:39:55 +08:00
										 |  |  |         StatusBar::instance()->showTip(1000, | 
					
						
							| 
									
										
										
										
											2024-06-21 07:14:29 +08:00
										 |  |  |                                        Strings::statusbar_tips_layer_x_is_hidden(layer->name())); | 
					
						
							| 
									
										
										
										
											2014-11-30 20:43:33 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-06-16 02:27:38 +08:00
										 |  |  |       else if (!layer->isMovable() || !layer->isEditableHierarchy()) { | 
					
						
							| 
									
										
										
										
											2024-06-21 07:14:29 +08:00
										 |  |  |         StatusBar::instance()->showTip(1000, Strings::statusbar_tips_layer_locked(layer->name())); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2016-12-01 06:58:04 +08:00
										 |  |  |         MovingCelCollect collect(editor, layer); | 
					
						
							|  |  |  |         if (collect.empty()) { | 
					
						
							| 
									
										
										
										
											2022-01-07 19:35:20 +08:00
										 |  |  |           StatusBar::instance()->showTip(1000, Strings::statusbar_tips_nothing_to_move()); | 
					
						
							| 
									
										
										
										
											2016-11-08 04:16:40 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-12-01 06:58:04 +08:00
										 |  |  |         else { | 
					
						
							|  |  |  |           try { | 
					
						
							|  |  |  |             // Change to MovingCelState
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |             HandleType handle = MovePixelsHandle; | 
					
						
							| 
									
										
										
										
											2016-12-01 06:58:04 +08:00
										 |  |  |             if (resizeCelBounds(editor).contains(msg->position())) | 
					
						
							|  |  |  |               handle = ScaleSEHandle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             MovingCelState* newState = new MovingCelState(editor, msg, handle, collect); | 
					
						
							|  |  |  |             editor->setState(EditorStatePtr(newState)); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-07-15 09:47:03 +08:00
										 |  |  |           catch (const LockedDocException&) { | 
					
						
							| 
									
										
										
										
											2016-12-01 06:58:04 +08:00
										 |  |  |             // TODO break the background task that is locking this sprite
 | 
					
						
							|  |  |  |             StatusBar::instance()->showTip(1000, | 
					
						
							| 
									
										
										
										
											2022-01-07 19:35:20 +08:00
										 |  |  |                                            Strings::statusbar_tips_recovery_task_using_sprite()); | 
					
						
							| 
									
										
										
										
											2016-12-01 06:58:04 +08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2016-11-08 04:16:40 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-17 05:33:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |   // Call the eyedropper command
 | 
					
						
							|  |  |  |   if (clickedInk->isEyedropper()) { | 
					
						
							| 
									
										
										
										
											2015-08-20 05:05:03 +08:00
										 |  |  |     editor->captureMouse(); | 
					
						
							| 
									
										
										
										
											2018-03-16 23:26:38 +08:00
										 |  |  |     callEyedropper(editor, msg); | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-12 09:31:13 +08:00
										 |  |  |   // Handle Slice tool
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |   if (clickedInk->isSlice()) { | 
					
						
							|  |  |  |     EditorHit hit = editor->calcHit(msg->position()); | 
					
						
							|  |  |  |     switch (hit.type()) { | 
					
						
							|  |  |  |       case EditorHit::SliceBounds: | 
					
						
							|  |  |  |       case EditorHit::SliceCenter: | 
					
						
							|  |  |  |         if (msg->left()) { | 
					
						
							| 
									
										
										
										
											2019-05-03 03:26:13 +08:00
										 |  |  |           // If we click outside all slices, we clear the selection of slices.
 | 
					
						
							|  |  |  |           if (!hit.slice() || !site.selectedSlices().contains(hit.slice()->id())) { | 
					
						
							|  |  |  |             editor->clearSlicesSelection(); | 
					
						
							| 
									
										
										
										
											2019-05-07 21:28:37 +08:00
										 |  |  |             editor->selectSlice(hit.slice()); | 
					
						
							| 
									
										
										
										
											2019-05-03 03:26:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             site = Site(); | 
					
						
							|  |  |  |             editor->getSite(&site); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           MovingSliceState* newState = | 
					
						
							|  |  |  |             new MovingSliceState(editor, msg, hit, site.selectedSlices()); | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |           editor->setState(EditorStatePtr(newState)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |           Menu* popupMenu = AppMenus::instance()->getSlicePopupMenu(); | 
					
						
							|  |  |  |           if (popupMenu) { | 
					
						
							|  |  |  |             Params params; | 
					
						
							| 
									
										
										
										
											2019-05-03 03:26:13 +08:00
										 |  |  |             // When the editor doesn't have a set of selected slices,
 | 
					
						
							|  |  |  |             // we set the specific clicked slice for the commands (in
 | 
					
						
							|  |  |  |             // other case, those commands will get the selected set of
 | 
					
						
							|  |  |  |             // slices from Site::selectedSlices() field).
 | 
					
						
							|  |  |  |             if (!editor->hasSelectedSlices()) | 
					
						
							|  |  |  |               params.set("id", base::convert_to<std::string>(hit.slice()->id()).c_str()); | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |             AppMenuItem::setContextParams(params); | 
					
						
							| 
									
										
										
										
											2021-03-20 05:57:56 +08:00
										 |  |  |             popupMenu->showPopup(msg->position(), editor->display()); | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |             AppMenuItem::setContextParams(Params()); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-12 09:31:13 +08:00
										 |  |  |   // Handle Text tool
 | 
					
						
							|  |  |  |   if (clickedInk->isText()) { | 
					
						
							|  |  |  |     EditorStatePtr newState(new SelectTextBoxState(editor, msg)); | 
					
						
							|  |  |  |     editor->setState(newState); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-01 08:07:30 +08:00
										 |  |  |   // Only if the selected tool or quick tool is selection, we give the
 | 
					
						
							|  |  |  |   // possibility to transform/move the selection. In other case,
 | 
					
						
							|  |  |  |   // e.g. when selection is used with right-click mode, the
 | 
					
						
							|  |  |  |   // transformation is disabled.
 | 
					
						
							|  |  |  |   auto activeToolManager = App::instance()->activeToolManager(); | 
					
						
							|  |  |  |   if (clickedInk->isSelection() && ((activeToolManager->selectedTool() && | 
					
						
							|  |  |  |                                      activeToolManager->selectedTool()->getInk(0)->isSelection()) || | 
					
						
							|  |  |  |                                     (activeToolManager->quickTool() && | 
					
						
							|  |  |  |                                      activeToolManager->quickTool()->getInk(0)->isSelection()))) { | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |     // Transform selected pixels
 | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |     if (editor->isActive() && document->isMaskVisible() && | 
					
						
							| 
									
										
										
										
											2017-09-08 23:07:21 +08:00
										 |  |  |         m_decorator->getTransformHandles(editor) && | 
					
						
							|  |  |  |         (!Preferences::instance().selection.modifiersDisableHandles() || | 
					
						
							|  |  |  |          msg->modifiers() == kKeyNoneModifier)) { | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |       TransformHandles* transfHandles = m_decorator->getTransformHandles(editor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Get the handle covered by the mouse.
 | 
					
						
							|  |  |  |       HandleType handle = | 
					
						
							|  |  |  |         transfHandles->getHandleAtPoint(editor, msg->position(), getTransformation(editor)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (handle != NoHandle) { | 
					
						
							|  |  |  |         int x, y, opacity; | 
					
						
							| 
									
										
										
										
											2015-04-21 03:27:09 +08:00
										 |  |  |         Image* image = site.image(&x, &y, &opacity); | 
					
						
							| 
									
										
										
										
											2015-01-28 22:04:07 +08:00
										 |  |  |         if (layer && image) { | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |           // Change to MovingPixelsState
 | 
					
						
							|  |  |  |           transformSelection(editor, msg, handle); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |     // Move selection edges
 | 
					
						
							|  |  |  |     if (overSelectionEdges(editor, msg->position())) { | 
					
						
							|  |  |  |       transformSelection(editor, msg, MoveSelectionHandle); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |     // Move selected pixels
 | 
					
						
							| 
									
										
										
										
											2017-09-28 00:07:37 +08:00
										 |  |  |     if (layer && editor->canStartMovingSelectionPixels() && msg->left()) { | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |       // Change to MovingPixelsState
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |       transformSelection(editor, msg, MovePixelsHandle); | 
					
						
							| 
									
										
										
										
											2014-08-25 06:37:24 +08:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Start the Tool-Loop
 | 
					
						
							| 
									
										
										
										
											2016-12-08 20:37:28 +08:00
										 |  |  |   if (layer && (layer->isImage() || clickedInk->isSelection())) { | 
					
						
							| 
									
										
										
										
											2020-09-01 06:02:34 +08:00
										 |  |  |     tools::Pointer pointer = pointer_from_msg(editor, msg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 03:04:18 +08:00
										 |  |  |     // Shift+click on Pencil tool starts a line onMouseDown() when the
 | 
					
						
							|  |  |  |     // preview (onKeyDown) is disabled.
 | 
					
						
							|  |  |  |     if (!Preferences::instance().editor.straightLinePreview() && | 
					
						
							| 
									
										
										
										
											2022-01-07 04:44:43 +08:00
										 |  |  |         checkStartDrawingStraightLine(editor, msg, &pointer)) { | 
					
						
							| 
									
										
										
										
											2017-09-09 03:04:18 +08:00
										 |  |  |       // Send first mouse down to draw the straight line and start the
 | 
					
						
							|  |  |  |       // freehand mode.
 | 
					
						
							|  |  |  |       editor->getState()->onMouseDown(editor, msg); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 23:32:39 +08:00
										 |  |  |     // Disable layer edges to avoid showing the modified cel
 | 
					
						
							|  |  |  |     // information by ExpandCelCanvas (i.e. the cel origin is changed
 | 
					
						
							|  |  |  |     // to 0,0 coordinate.)
 | 
					
						
							|  |  |  |     auto& layerEdgesOption = editor->docPref().show.layerEdges; | 
					
						
							|  |  |  |     bool layerEdges = layerEdgesOption(); | 
					
						
							|  |  |  |     if (layerEdges) | 
					
						
							|  |  |  |       layerEdgesOption(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-07 03:54:39 +08:00
										 |  |  |     startDrawingState(editor, msg, DrawingType::Regular, pointer); | 
					
						
							| 
									
										
										
										
											2016-05-04 23:32:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Restore layer edges
 | 
					
						
							|  |  |  |     if (layerEdges) | 
					
						
							|  |  |  |       layerEdgesOption(true); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-29 08:17:07 +08:00
										 |  |  | bool StandbyState::onMouseUp(Editor* editor, MouseMessage* msg) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   editor->releaseMouse(); | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-29 08:17:07 +08:00
										 |  |  | bool StandbyState::onMouseMove(Editor* editor, MouseMessage* msg) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |   // We control eyedropper tool from here. TODO move this to another place
 | 
					
						
							|  |  |  |   if (msg->left() || msg->right()) { | 
					
						
							|  |  |  |     tools::Ink* clickedInk = editor->getCurrentEditorInk(); | 
					
						
							| 
									
										
										
										
											2015-08-20 05:05:03 +08:00
										 |  |  |     if (clickedInk->isEyedropper() && editor->hasCapture()) { | 
					
						
							| 
									
										
										
										
											2018-03-16 23:26:38 +08:00
										 |  |  |       callEyedropper(editor, msg); | 
					
						
							| 
									
										
										
										
											2015-08-20 05:05:03 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   editor->updateStatusBar(); | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 22:33:05 +08:00
										 |  |  | bool StandbyState::onDoubleClick(Editor* editor, MouseMessage* msg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (editor->hasCapture()) | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tools::Ink* ink = editor->getCurrentEditorInk(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Select a tile with double-click
 | 
					
						
							| 
									
										
										
										
											2018-11-16 06:17:19 +08:00
										 |  |  |   if (ink->isSelection() && Preferences::instance().selection.doubleclickSelectTile()) { | 
					
						
							| 
									
										
										
										
											2020-02-17 19:28:30 +08:00
										 |  |  |     // Drop pixels if we are in moving pixels state
 | 
					
						
							| 
									
										
										
										
											2020-04-09 04:29:47 +08:00
										 |  |  |     if (dynamic_cast<MovingPixelsState*>(editor->getState().get())) | 
					
						
							| 
									
										
										
										
											2020-02-17 19:28:30 +08:00
										 |  |  |       editor->backToPreviousState(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 23:42:29 +08:00
										 |  |  |     // Start a tool-loop selecting tiles.
 | 
					
						
							|  |  |  |     startDrawingState(editor, msg, DrawingType::SelectTiles, pointer_from_msg(editor, msg)); | 
					
						
							| 
									
										
										
										
											2016-03-19 23:04:39 +08:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2016-03-19 22:33:05 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-05-07 21:33:05 +08:00
										 |  |  |   // Show slice properties when we double-click it
 | 
					
						
							|  |  |  |   else if (ink->isSlice()) { | 
					
						
							|  |  |  |     EditorHit hit = editor->calcHit(msg->position()); | 
					
						
							|  |  |  |     if (hit.slice()) { | 
					
						
							|  |  |  |       Command* cmd = Commands::instance()->byId(CommandId::SliceProperties()); | 
					
						
							|  |  |  |       Params params; | 
					
						
							|  |  |  |       params.set("id", base::convert_to<std::string>(hit.slice()->id()).c_str()); | 
					
						
							| 
									
										
										
										
											2019-06-04 09:57:20 +08:00
										 |  |  |       UIContext::instance()->executeCommandFromMenuOrShortcut(cmd, params); | 
					
						
							| 
									
										
										
										
											2019-05-07 21:33:05 +08:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-03-19 22:33:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 23:44:47 +08:00
										 |  |  | bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |   tools::Ink* ink = editor->getCurrentEditorInk(); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // See if the cursor is in some selection handle.
 | 
					
						
							|  |  |  |   if (m_decorator->onSetCursor(ink, editor, mouseScreenPos)) | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-19 06:01:46 +08:00
										 |  |  |   auto theme = skin::SkinTheme::get(editor); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |   if (ink) { | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |     // If the current tool change selection (e.g. rectangular marquee, etc.)
 | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |     if (ink->isSelection()) { | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |       if (overSelectionEdges(editor, mouseScreenPos)) { | 
					
						
							| 
									
										
										
										
											2022-02-19 06:01:46 +08:00
										 |  |  |         editor->showMouseCursor(kCustomCursor, theme->cursors.moveSelection()); | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |       // Move pixels
 | 
					
						
							| 
									
										
										
										
											2017-09-28 00:07:37 +08:00
										 |  |  |       if (editor->canStartMovingSelectionPixels()) { | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |         EditorCustomizationDelegate* customization = editor->getCustomizationDelegate(); | 
					
						
							| 
									
										
										
										
											2015-08-26 00:29:19 +08:00
										 |  |  |         if ((customization) && | 
					
						
							| 
									
										
										
										
											2015-09-12 07:04:02 +08:00
										 |  |  |             int(customization->getPressedKeyAction(KeyContext::TranslatingSelection) & | 
					
						
							|  |  |  |                 KeyAction::CopySelection)) | 
					
						
							| 
									
										
										
										
											2015-06-25 23:44:47 +08:00
										 |  |  |           editor->showMouseCursor(kArrowPlusCursor); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2015-06-25 23:44:47 +08:00
										 |  |  |           editor->showMouseCursor(kMoveCursor); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-05-03 05:42:02 +08:00
										 |  |  |       else | 
					
						
							|  |  |  |         editor->showBrushPreview(mouseScreenPos); | 
					
						
							|  |  |  |       return true; | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |     else if (ink->isCelMovement()) { | 
					
						
							| 
									
										
										
										
											2016-10-26 06:15:36 +08:00
										 |  |  |       if (resizeCelBounds(editor).contains(mouseScreenPos)) | 
					
						
							|  |  |  |         editor->showMouseCursor(kSizeSECursor); | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         editor->showMouseCursor(kMoveCursor); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |     else if (ink->isSlice()) { | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |       EditorHit hit = editor->calcHit(mouseScreenPos); | 
					
						
							|  |  |  |       switch (hit.type()) { | 
					
						
							|  |  |  |         case EditorHit::None: | 
					
						
							|  |  |  |           // Do nothing, continue
 | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         case EditorHit::SliceBounds: | 
					
						
							|  |  |  |         case EditorHit::SliceCenter: | 
					
						
							|  |  |  |           switch (hit.border()) { | 
					
						
							| 
									
										
										
										
											2017-03-16 23:08:56 +08:00
										 |  |  |             case CENTER | MIDDLE: editor->showMouseCursor(kMoveCursor); break; | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |             case TOP | LEFT:      editor->showMouseCursor(kSizeNWCursor); break; | 
					
						
							|  |  |  |             case TOP:             editor->showMouseCursor(kSizeNCursor); break; | 
					
						
							|  |  |  |             case TOP | RIGHT:     editor->showMouseCursor(kSizeNECursor); break; | 
					
						
							|  |  |  |             case LEFT:            editor->showMouseCursor(kSizeWCursor); break; | 
					
						
							|  |  |  |             case RIGHT:           editor->showMouseCursor(kSizeECursor); break; | 
					
						
							|  |  |  |             case BOTTOM | LEFT:   editor->showMouseCursor(kSizeSWCursor); break; | 
					
						
							|  |  |  |             case BOTTOM:          editor->showMouseCursor(kSizeSCursor); break; | 
					
						
							|  |  |  |             case BOTTOM | RIGHT:  editor->showMouseCursor(kSizeSECursor); break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           return true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-06-28 09:58:38 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-06-12 09:31:13 +08:00
										 |  |  |     else if (ink->isText()) { | 
					
						
							|  |  |  |       editor->showMouseCursor(kCrosshairCursor); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-09 07:40:11 +08:00
										 |  |  |   return StateWithWheelBehavior::onSetCursor(editor, mouseScreenPos); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-29 08:17:07 +08:00
										 |  |  | bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-09-09 03:04:18 +08:00
										 |  |  |   if (Preferences::instance().editor.straightLinePreview() && | 
					
						
							| 
									
										
										
										
											2022-01-07 04:44:43 +08:00
										 |  |  |       checkStartDrawingStraightLine(editor, nullptr, nullptr)) | 
					
						
							| 
									
										
										
										
											2017-12-07 02:20:29 +08:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2022-03-09 07:40:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Keys keys = KeyboardShortcuts::instance()->getDragActionsFromKeyMessage(KeyContext::MouseWheel, | 
					
						
							|  |  |  |                                                                           msg); | 
					
						
							| 
									
										
										
										
											2023-06-06 05:32:47 +08:00
										 |  |  |   if (editor->hasMouse() && !keys.empty()) { | 
					
						
							| 
									
										
										
										
											2022-09-02 22:56:07 +08:00
										 |  |  |     // Don't enter DraggingValueState to change brush size if we are
 | 
					
						
							|  |  |  |     // in a selection-like tool
 | 
					
						
							|  |  |  |     if (keys.size() == 1 && keys[0]->wheelAction() == WheelAction::BrushSize && | 
					
						
							|  |  |  |         editor->getCurrentEditorInk()->isSelection()) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-09 07:40:11 +08:00
										 |  |  |     EditorStatePtr newState(new DraggingValueState(editor, keys)); | 
					
						
							|  |  |  |     editor->setState(newState); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-13 11:22:29 +08:00
										 |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-29 08:17:07 +08:00
										 |  |  | bool StandbyState::onKeyUp(Editor* editor, KeyMessage* msg) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool StandbyState::onUpdateStatusBar(Editor* editor) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |   tools::Ink* ink = editor->getCurrentEditorInk(); | 
					
						
							| 
									
										
										
										
											2014-07-30 12:28:15 +08:00
										 |  |  |   const Sprite* sprite = editor->sprite(); | 
					
						
							| 
									
										
										
										
											2021-03-03 00:50:49 +08:00
										 |  |  |   gfx::PointF spritePos = editor->screenToEditorF(editor->mousePosInDisplay()) - | 
					
						
							| 
									
										
										
										
											2017-11-11 02:04:09 +08:00
										 |  |  |                           gfx::PointF(editor->mainTilePosition()); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (!sprite) { | 
					
						
							| 
									
										
										
										
											2018-11-13 04:52:05 +08:00
										 |  |  |     StatusBar::instance()->showDefaultText(); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   // For eye-dropper
 | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |   else if (ink->isEyedropper()) { | 
					
						
							| 
									
										
										
										
											2020-08-22 05:07:37 +08:00
										 |  |  |     Site site = editor->getSite(); | 
					
						
							| 
									
										
										
										
											2015-07-03 05:13:47 +08:00
										 |  |  |     EyedropperCommand cmd; | 
					
						
							|  |  |  |     app::Color color = Preferences::instance().colorBar.fgColor(); | 
					
						
							| 
									
										
										
										
											2020-08-22 05:07:37 +08:00
										 |  |  |     doc::tile_t tile = Preferences::instance().colorBar.fgTile(); | 
					
						
							| 
									
										
										
										
											2016-10-14 06:58:42 +08:00
										 |  |  |     cmd.pickSample(site, spritePos, editor->projection(), color, tile); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-15 23:30:15 +08:00
										 |  |  |     std::string buf = | 
					
						
							|  |  |  |       fmt::format(" :pos: {} {}", int(std::floor(spritePos.x)), int(std::floor(spritePos.y))); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-22 05:07:37 +08:00
										 |  |  |     if (site.tilemapMode() == TilemapMode::Tiles) | 
					
						
							| 
									
										
										
										
											2022-07-16 04:30:39 +08:00
										 |  |  |       StatusBar::instance()->showTile(0, tile, buf); | 
					
						
							| 
									
										
										
										
											2020-08-22 05:07:37 +08:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2022-07-16 04:30:39 +08:00
										 |  |  |       StatusBar::instance()->showColor(0, color, buf); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2019-04-11 01:04:01 +08:00
										 |  |  |     Site site = editor->getSite(); | 
					
						
							| 
									
										
										
										
											2015-02-12 23:16:25 +08:00
										 |  |  |     Mask* mask = (editor->document()->isMaskVisible() ? editor->document()->mask() : NULL); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-15 23:30:15 +08:00
										 |  |  |     std::string buf = | 
					
						
							| 
									
										
										
										
											2022-07-16 03:32:49 +08:00
										 |  |  |       fmt::format(":pos: {} {}", int(std::floor(spritePos.x)), int(std::floor(spritePos.y))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Cel* cel = nullptr; | 
					
						
							|  |  |  |     if (editor->showAutoCelGuides()) { | 
					
						
							|  |  |  |       cel = editor->getSite().cel(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cel) { | 
					
						
							|  |  |  |       buf += fmt::format(" :start: {} {} :size: {} {}", | 
					
						
							|  |  |  |                          cel->bounds().x, | 
					
						
							|  |  |  |                          cel->bounds().y, | 
					
						
							|  |  |  |                          cel->bounds().w, | 
					
						
							|  |  |  |                          cel->bounds().h); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       buf += fmt::format(" :size: {} {}", sprite->width(), sprite->height()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-11-13 04:52:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (mask) | 
					
						
							| 
									
										
										
										
											2022-07-15 23:30:15 +08:00
										 |  |  |       buf += fmt::format(" :selsize: {} {}", mask->bounds().w, mask->bounds().h); | 
					
						
							| 
									
										
										
										
											2016-04-20 02:51:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 00:45:23 +08:00
										 |  |  |     if (sprite->totalFrames() > 1) { | 
					
						
							| 
									
										
										
										
											2022-07-15 23:30:15 +08:00
										 |  |  |       buf += fmt::format(" :frame: {} :clock: {}/{}", | 
					
						
							| 
									
										
										
										
											2019-04-11 01:04:01 +08:00
										 |  |  |                          site.frame() + editor->docPref().timeline.firstFrame(), | 
					
						
							|  |  |  |                          human_readable_time(sprite->frameDuration(site.frame())).c_str(), | 
					
						
							| 
									
										
										
										
											2017-07-29 03:44:21 +08:00
										 |  |  |                          human_readable_time(sprite->totalAnimationDuration()).c_str()); | 
					
						
							| 
									
										
										
										
											2016-04-20 00:45:23 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-11 01:04:01 +08:00
										 |  |  |     if ((editor->docPref().show.grid()) || (site.layer() && site.layer()->isTilemap())) { | 
					
						
							|  |  |  |       doc::Grid grid = site.grid(); | 
					
						
							|  |  |  |       if (!grid.isEmpty()) { | 
					
						
							|  |  |  |         gfx::Point pt = grid.canvasToTile(gfx::Point(spritePos)); | 
					
						
							| 
									
										
										
										
											2022-07-16 04:30:39 +08:00
										 |  |  |         buf += fmt::format(" :grid: {} {}", pt.x, pt.y); | 
					
						
							| 
									
										
										
										
											2019-08-05 19:37:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-10 02:26:16 +08:00
										 |  |  |         // Number of columns of the current grid/tilemap to show a
 | 
					
						
							|  |  |  |         // "tile index", i.e. a linear index that might be used in a
 | 
					
						
							|  |  |  |         // 1D array to represent the current grid tile/cell. If it's 0
 | 
					
						
							|  |  |  |         // we don't show the index.
 | 
					
						
							|  |  |  |         int tileIndexColumns = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 19:37:58 +08:00
										 |  |  |         // Show the tile index of this specific tile
 | 
					
						
							|  |  |  |         if (site.layer() && site.layer()->isTilemap() && site.image()) { | 
					
						
							|  |  |  |           if (site.image()->bounds().contains(pt)) { | 
					
						
							| 
									
										
										
										
											2023-08-08 04:50:15 +08:00
										 |  |  |             doc::tile_t t = site.image()->getPixel(pt.x, pt.y); | 
					
						
							|  |  |  |             doc::tile_index ti = doc::tile_geti(t); | 
					
						
							|  |  |  |             doc::tile_flags tf = doc::tile_getf(t); | 
					
						
							|  |  |  |             std::string str; | 
					
						
							| 
									
										
										
										
											2023-10-05 07:00:49 +08:00
										 |  |  |             build_tile_flags_string(tf, str); | 
					
						
							| 
									
										
										
										
											2023-08-08 04:50:15 +08:00
										 |  |  |             buf += fmt::format(" [{}{}]", ti, str); | 
					
						
							| 
									
										
										
										
											2024-12-10 02:26:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Show tile index for a tilemaps (using the tilemap size)
 | 
					
						
							|  |  |  |             tileIndexColumns = site.image()->width(); | 
					
						
							| 
									
										
										
										
											2019-08-05 19:37:58 +08:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-12-10 02:26:16 +08:00
										 |  |  |         // Show the tile index for a regular layer/grid
 | 
					
						
							|  |  |  |         else if (sprite->bounds().contains(gfx::Point(spritePos))) { | 
					
						
							|  |  |  |           tileIndexColumns = int( | 
					
						
							|  |  |  |             std::ceil(double(sprite->bounds().w - grid.origin().x) / grid.tileSize().w)); | 
					
						
							| 
									
										
										
										
											2024-09-10 21:30:35 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-12-10 02:26:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (tileIndexColumns > 0 && pt.x >= 0 && pt.y >= 0) | 
					
						
							|  |  |  |           buf += fmt::format(" :search: {}", pt.x + pt.y * tileIndexColumns); | 
					
						
							| 
									
										
										
										
											2019-05-18 05:11:14 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-04-20 02:51:34 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |     if (editor->docPref().show.slices()) { | 
					
						
							|  |  |  |       int count = 0; | 
					
						
							|  |  |  |       for (auto slice : editor->document()->sprite()->slices()) { | 
					
						
							|  |  |  |         auto key = slice->getByFrame(editor->frame()); | 
					
						
							|  |  |  |         if (key && | 
					
						
							|  |  |  |             key->bounds().contains(int(std::floor(spritePos.x)), int(std::floor(spritePos.y)))) { | 
					
						
							|  |  |  |           if (++count == 3) { | 
					
						
							| 
									
										
										
										
											2022-07-15 23:30:15 +08:00
										 |  |  |             buf += fmt::format(" :slice: ..."); | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-15 23:30:15 +08:00
										 |  |  |           buf += fmt::format(" :slice: {}", slice->name()); | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 00:45:23 +08:00
										 |  |  |     StatusBar::instance()->setStatusText(0, buf); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 23:42:29 +08:00
										 |  |  | DrawingState* StandbyState::startDrawingState(Editor* editor, | 
					
						
							| 
									
										
										
										
											2022-01-07 03:54:39 +08:00
										 |  |  |                                               const ui::MouseMessage* msg, | 
					
						
							| 
									
										
										
										
											2020-02-16 23:42:29 +08:00
										 |  |  |                                               const DrawingType drawingType, | 
					
						
							|  |  |  |                                               const tools::Pointer& pointer) | 
					
						
							| 
									
										
										
										
											2017-06-17 03:28:48 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   // We need to clear and redraw the brush boundaries after the
 | 
					
						
							|  |  |  |   // first mouse pressed/point shape if drawn. This is to avoid
 | 
					
						
							|  |  |  |   // graphical glitches (invalid areas in the ToolLoop's src/dst
 | 
					
						
							|  |  |  |   // images).
 | 
					
						
							|  |  |  |   HideBrushPreview hide(editor->brushPreview()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tools::ToolLoop* toolLoop = create_tool_loop(editor, | 
					
						
							|  |  |  |                                                UIContext::instance(), | 
					
						
							| 
									
										
										
										
											2017-11-28 00:53:56 +08:00
										 |  |  |                                                pointer.button(), | 
					
						
							| 
									
										
										
										
											2020-02-16 23:42:29 +08:00
										 |  |  |                                                (drawingType == DrawingType::LineFreehand), | 
					
						
							| 
									
										
										
										
											2025-06-20 12:31:22 +08:00
										 |  |  |                                                (drawingType == DrawingType::SelectTiles)); | 
					
						
							| 
									
										
										
										
											2017-06-17 03:28:48 +08:00
										 |  |  |   if (!toolLoop) | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-20 00:17:09 +08:00
										 |  |  |   EditorStatePtr newState(new DrawingState(editor, toolLoop, drawingType)); | 
					
						
							| 
									
										
										
										
											2017-06-17 03:28:48 +08:00
										 |  |  |   editor->setState(newState); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static_cast<DrawingState*>(newState.get())->initToolLoop(editor, msg, pointer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return static_cast<DrawingState*>(newState.get()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-28 00:53:56 +08:00
										 |  |  | bool StandbyState::checkStartDrawingStraightLine(Editor* editor, | 
					
						
							| 
									
										
										
										
											2022-01-07 04:44:43 +08:00
										 |  |  |                                                  const ui::MouseMessage* msg, | 
					
						
							| 
									
										
										
										
											2020-09-01 06:02:34 +08:00
										 |  |  |                                                  const tools::Pointer* pointer) | 
					
						
							| 
									
										
										
										
											2017-06-17 03:42:37 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   // Start line preview with shift key
 | 
					
						
							| 
									
										
										
										
											2020-09-01 06:02:34 +08:00
										 |  |  |   if (canCheckStartDrawingStraightLine() && editor->startStraightLineWithFreehandTool(pointer)) { | 
					
						
							|  |  |  |     tools::Pointer::Button pointerButton = (pointer ? pointer->button() : tools::Pointer::Left); | 
					
						
							| 
									
										
										
										
											2024-12-17 01:52:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-17 03:42:37 +08:00
										 |  |  |     DrawingState* drawingState = startDrawingState( | 
					
						
							| 
									
										
										
										
											2022-01-07 03:54:39 +08:00
										 |  |  |       editor, | 
					
						
							|  |  |  |       msg, | 
					
						
							| 
									
										
										
										
											2017-06-17 03:42:37 +08:00
										 |  |  |       DrawingType::LineFreehand, | 
					
						
							|  |  |  |       tools::Pointer(editor->document()->lastDrawingPoint(), | 
					
						
							| 
									
										
										
										
											2020-04-24 22:19:35 +08:00
										 |  |  |                      tools::Vec2(0.0f, 0.0f), | 
					
						
							| 
									
										
										
										
											2020-04-22 09:27:49 +08:00
										 |  |  |                      pointerButton, | 
					
						
							| 
									
										
										
										
											2020-09-01 06:02:34 +08:00
										 |  |  |                      pointer ? pointer->type() : PointerType::Unknown, | 
					
						
							|  |  |  |                      pointer ? pointer->pressure() : 0.0f)); | 
					
						
							| 
									
										
										
										
											2017-06-17 03:42:37 +08:00
										 |  |  |     if (drawingState) { | 
					
						
							| 
									
										
										
										
											2024-04-02 03:12:04 +08:00
										 |  |  |       // Disable stabilizer so that it does not affect the line preview
 | 
					
						
							|  |  |  |       drawingState->disableMouseStabilizer(); | 
					
						
							| 
									
										
										
										
											2024-06-21 07:14:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-17 03:42:37 +08:00
										 |  |  |       drawingState->sendMovementToToolLoop(tools::Pointer( | 
					
						
							| 
									
										
										
										
											2021-03-03 00:50:49 +08:00
										 |  |  |         pointer ? pointer->point() : editor->screenToEditor(editor->mousePosInDisplay()), | 
					
						
							| 
									
										
										
										
											2020-04-24 22:19:35 +08:00
										 |  |  |         tools::Vec2(0.0f, 0.0f), | 
					
						
							| 
									
										
										
										
											2020-04-22 09:27:49 +08:00
										 |  |  |         pointerButton, | 
					
						
							| 
									
										
										
										
											2020-09-01 06:02:34 +08:00
										 |  |  |         pointer ? pointer->type() : tools::Pointer::Type::Unknown, | 
					
						
							|  |  |  |         pointer ? pointer->pressure() : 0.0f)); | 
					
						
							| 
									
										
										
										
											2017-06-17 03:42:37 +08:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-12 01:16:01 +08:00
										 |  |  | Transformation StandbyState::getTransformation(Editor* editor) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-12 01:16:01 +08:00
										 |  |  |   Transformation t = editor->document()->getTransformation(); | 
					
						
							| 
									
										
										
										
											2015-07-30 03:35:34 +08:00
										 |  |  |   set_pivot_from_preferences(t); | 
					
						
							|  |  |  |   return t; | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-14 08:47:30 +08:00
										 |  |  | void StandbyState::startSelectionTransformation(Editor* editor, | 
					
						
							|  |  |  |                                                 const gfx::Point& move, | 
					
						
							|  |  |  |                                                 double angle) | 
					
						
							| 
									
										
										
										
											2014-08-08 12:00:02 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   transformSelection(editor, NULL, NoHandle); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 20:48:56 +08:00
										 |  |  |   if (auto movingPixels = dynamic_cast<MovingPixelsState*>(editor->getState().get())) { | 
					
						
							| 
									
										
										
										
											2020-09-19 06:29:43 +08:00
										 |  |  |     movingPixels->translate(gfx::PointF(move)); | 
					
						
							| 
									
										
										
										
											2015-08-14 08:47:30 +08:00
										 |  |  |     if (std::fabs(angle) > 1e-5) | 
					
						
							|  |  |  |       movingPixels->rotate(angle); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-08-08 12:00:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-07 03:22:44 +08:00
										 |  |  | void StandbyState::startFlipTransformation(Editor* editor, doc::algorithm::FlipType flipType) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   transformSelection(editor, NULL, NoHandle); | 
					
						
							| 
									
										
										
										
											2018-07-15 09:47:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 20:48:56 +08:00
										 |  |  |   if (auto movingPixels = dynamic_cast<MovingPixelsState*>(editor->getState().get())) | 
					
						
							| 
									
										
										
										
											2018-07-07 03:22:44 +08:00
										 |  |  |     movingPixels->flip(flipType); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-07-15 09:47:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-29 08:17:07 +08:00
										 |  |  | void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleType handle) | 
					
						
							| 
									
										
										
										
											2012-01-06 10:21:51 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-07-07 22:54:44 +08:00
										 |  |  |   Doc* document = editor->document(); | 
					
						
							| 
									
										
										
										
											2018-07-15 10:24:49 +08:00
										 |  |  |   for (auto docView : UIContext::instance()->getAllDocViews(document)) { | 
					
						
							| 
									
										
										
										
											2016-02-13 12:33:43 +08:00
										 |  |  |     if (docView->editor()->isMovingPixels()) { | 
					
						
							| 
									
										
										
										
											2015-08-15 00:06:26 +08:00
										 |  |  |       // TODO Transfer moving pixels state to this editor
 | 
					
						
							| 
									
										
										
										
											2016-02-13 12:33:43 +08:00
										 |  |  |       docView->editor()->dropMovingPixels(); | 
					
						
							| 
									
										
										
										
											2015-08-15 00:06:26 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |   // Special case: Move only selection edges
 | 
					
						
							|  |  |  |   if (handle == MoveSelectionHandle) { | 
					
						
							|  |  |  |     EditorStatePtr newState(new MovingSelectionState(editor, msg)); | 
					
						
							|  |  |  |     editor->setState(newState); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 21:30:40 +08:00
										 |  |  |   Layer* layer = editor->layer(); | 
					
						
							|  |  |  |   if (layer && layer->isReference()) { | 
					
						
							|  |  |  |     StatusBar::instance()->showTip( | 
					
						
							| 
									
										
										
										
											2024-06-21 07:14:29 +08:00
										 |  |  |       1000, | 
					
						
							|  |  |  |       Strings::statusbar_tips_non_transformable_reference_layer(layer->name())); | 
					
						
							| 
									
										
										
										
											2016-11-07 21:30:40 +08:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 03:19:00 +08:00
										 |  |  |   if (layer_is_locked(editor)) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-30 06:53:28 +08:00
										 |  |  |   try { | 
					
						
							| 
									
										
										
										
											2020-10-03 06:03:53 +08:00
										 |  |  |     Site site = editor->getSite(); | 
					
						
							|  |  |  |     ImageRef tmpImage; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (site.layer() && site.layer()->isTilemap() && site.tilemapMode() == TilemapMode::Tiles) { | 
					
						
							|  |  |  |       tmpImage.reset(new_tilemap_from_mask(site, site.document()->mask())); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       tmpImage.reset(new_image_from_mask(site, Preferences::instance().experimental.newBlend())); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-06-26 01:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-01 21:43:03 +08:00
										 |  |  |     ASSERT(tmpImage); | 
					
						
							|  |  |  |     if (!tmpImage) { | 
					
						
							|  |  |  |       // We've received a bug report with this case, we're not sure
 | 
					
						
							|  |  |  |       // yet how to reproduce it. Probably new_tilemap_from_mask() can
 | 
					
						
							|  |  |  |       // return nullptr (e.g. when site.cel() is nullptr?)
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Clear brush preview, as the extra cel will be replaced with the
 | 
					
						
							|  |  |  |     // transformed image.
 | 
					
						
							|  |  |  |     editor->brushPreview().hide(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-30 06:53:28 +08:00
										 |  |  |     PixelsMovementPtr pixelsMovement(new PixelsMovement(UIContext::instance(), | 
					
						
							| 
									
										
										
										
											2020-10-03 06:03:53 +08:00
										 |  |  |                                                         site, | 
					
						
							| 
									
										
										
										
											2018-08-09 04:27:26 +08:00
										 |  |  |                                                         tmpImage.get(), | 
					
						
							| 
									
										
										
										
											2015-07-24 09:42:14 +08:00
										 |  |  |                                                         document->mask(), | 
					
						
							|  |  |  |                                                         "Transformation")); | 
					
						
							| 
									
										
										
										
											2013-12-30 06:53:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // If the Ctrl key is pressed start dragging a copy of the selection
 | 
					
						
							| 
									
										
										
										
											2021-06-01 21:43:03 +08:00
										 |  |  |     EditorCustomizationDelegate* customization = editor->getCustomizationDelegate(); | 
					
						
							| 
									
										
										
										
											2015-08-26 00:29:19 +08:00
										 |  |  |     if ((customization) && | 
					
						
							| 
									
										
										
										
											2015-09-12 07:04:02 +08:00
										 |  |  |         int(customization->getPressedKeyAction(KeyContext::TranslatingSelection) & | 
					
						
							|  |  |  |             KeyAction::CopySelection)) | 
					
						
							| 
									
										
										
										
											2013-12-30 06:53:28 +08:00
										 |  |  |       pixelsMovement->copyMask(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       pixelsMovement->cutMask(); | 
					
						
							| 
									
										
										
										
											2012-01-06 10:21:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-30 06:53:28 +08:00
										 |  |  |     editor->setState(EditorStatePtr(new MovingPixelsState(editor, msg, pixelsMovement, handle))); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-07-15 09:47:03 +08:00
										 |  |  |   catch (const LockedDocException&) { | 
					
						
							| 
									
										
										
										
											2013-12-30 06:53:28 +08:00
										 |  |  |     // Other editor is locking the document.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO steal the PixelsMovement of the other editor and use it for this one.
 | 
					
						
							| 
									
										
										
										
											2022-01-07 19:35:20 +08:00
										 |  |  |     StatusBar::instance()->showTip(1000, Strings::statusbar_tips_sprite_locked_somewhere()); | 
					
						
							| 
									
										
										
										
											2015-06-25 23:44:47 +08:00
										 |  |  |     editor->showMouseCursor(kForbiddenCursor); | 
					
						
							| 
									
										
										
										
											2013-12-30 06:53:28 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-16 00:59:41 +08:00
										 |  |  |   catch (const std::bad_alloc&) { | 
					
						
							| 
									
										
										
										
											2022-01-07 19:35:20 +08:00
										 |  |  |     StatusBar::instance()->showTip(1000, Strings::statusbar_tips_not_enough_transform_memory()); | 
					
						
							| 
									
										
										
										
											2015-06-25 23:44:47 +08:00
										 |  |  |     editor->showMouseCursor(kForbiddenCursor); | 
					
						
							| 
									
										
										
										
											2015-04-16 00:59:41 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-01-06 10:21:51 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 23:26:38 +08:00
										 |  |  | void StandbyState::callEyedropper(Editor* editor, const ui::MouseMessage* msg) | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   tools::Ink* clickedInk = editor->getCurrentEditorInk(); | 
					
						
							|  |  |  |   if (!clickedInk->isEyedropper()) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 23:26:38 +08:00
										 |  |  |   EyedropperCommand* eyedropper = (EyedropperCommand*)Commands::instance()->byId( | 
					
						
							|  |  |  |     CommandId::Eyedropper()); | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  |   bool fg = (static_cast<tools::PickInk*>(clickedInk)->target() == tools::PickInk::Fg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 23:26:38 +08:00
										 |  |  |   eyedropper->executeOnMousePos(UIContext::instance(), editor, msg->position(), fg); | 
					
						
							| 
									
										
										
										
											2014-11-13 22:23:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 03:35:34 +08:00
										 |  |  | void StandbyState::onPivotChange(Editor* editor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (editor->isActive() && editor->editorFlags() & Editor::kShowMask && | 
					
						
							|  |  |  |       editor->document()->isMaskVisible() && !editor->document()->mask()->isFrozen()) { | 
					
						
							|  |  |  |     editor->invalidate(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 06:15:36 +08:00
										 |  |  | gfx::Rect StandbyState::resizeCelBounds(Editor* editor) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   gfx::Rect bounds; | 
					
						
							|  |  |  |   Cel* refCel = (editor->layer() && editor->layer()->isReference() ? | 
					
						
							|  |  |  |                    editor->layer()->cel(editor->frame()) : | 
					
						
							|  |  |  |                    nullptr); | 
					
						
							|  |  |  |   if (refCel) { | 
					
						
							|  |  |  |     bounds = editor->editorToScreen(refCel->boundsF()); | 
					
						
							|  |  |  |     bounds.w /= 4; | 
					
						
							|  |  |  |     bounds.h /= 4; | 
					
						
							|  |  |  |     bounds.x += 3 * bounds.w; | 
					
						
							|  |  |  |     bounds.y += 3 * bounds.h; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return bounds; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  | bool StandbyState::overSelectionEdges(Editor* editor, const gfx::Point& mouseScreenPos) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // Move selection edges
 | 
					
						
							| 
									
										
										
										
											2017-04-07 05:41:18 +08:00
										 |  |  |   if (Preferences::instance().selection.moveEdges() && editor->isActive() && | 
					
						
							| 
									
										
										
										
											2020-05-19 04:58:22 +08:00
										 |  |  |       editor->document()->isMaskVisible() && editor->document()->hasMaskBoundaries() && | 
					
						
							| 
									
										
										
										
											2017-04-07 05:41:18 +08:00
										 |  |  |       // TODO improve this check, how we can know that we aren't in the MovingPixelsState
 | 
					
						
							|  |  |  |       !dynamic_cast<MovingPixelsState*>(editor->getState().get())) { | 
					
						
							| 
									
										
										
										
											2017-11-09 02:59:33 +08:00
										 |  |  |     gfx::Point mainOffset(editor->mainTilePosition()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |     // For each selection edge
 | 
					
						
							| 
									
										
										
										
											2020-05-19 04:58:22 +08:00
										 |  |  |     for (const auto& seg : editor->document()->maskBoundaries()) { | 
					
						
							| 
									
										
										
										
											2017-11-09 02:59:33 +08:00
										 |  |  |       gfx::Rect segBounds = seg.bounds(); | 
					
						
							|  |  |  |       segBounds.offset(mainOffset); | 
					
						
							|  |  |  |       segBounds = editor->editorToScreen(segBounds); | 
					
						
							| 
									
										
										
										
											2017-04-07 02:26:01 +08:00
										 |  |  |       if (seg.vertical()) | 
					
						
							|  |  |  |         segBounds.w = 1; | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         segBounds.h = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (gfx::Rect(segBounds).enlarge(2 * guiscale()).contains(mouseScreenPos) && | 
					
						
							|  |  |  |           !gfx::Rect(segBounds).shrink(2 * guiscale()).contains(mouseScreenPos)) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | //////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Decorator
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StandbyState::Decorator::Decorator(StandbyState* standbyState) | 
					
						
							|  |  |  |   : m_transfHandles(NULL) | 
					
						
							|  |  |  |   , m_standbyState(standbyState) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StandbyState::Decorator::~Decorator() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   delete m_transfHandles; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TransformHandles* StandbyState::Decorator::getTransformHandles(Editor* editor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (!m_transfHandles) | 
					
						
							|  |  |  |     m_transfHandles = new TransformHandles(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return m_transfHandles; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  | bool StandbyState::Decorator::onSetCursor(tools::Ink* ink, | 
					
						
							|  |  |  |                                           Editor* editor, | 
					
						
							|  |  |  |                                           const gfx::Point& mouseScreenPos) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |   if (!editor->isActive()) | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |     return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-08 23:07:21 +08:00
										 |  |  |   if (ink && ink->isSelection() && editor->document()->isMaskVisible() && | 
					
						
							|  |  |  |       (!Preferences::instance().selection.modifiersDisableHandles() || | 
					
						
							| 
									
										
										
										
											2024-03-06 05:50:24 +08:00
										 |  |  |        os::System::instance()->keyModifiers() == kKeyNoneModifier)) { | 
					
						
							| 
									
										
										
										
											2022-02-19 06:01:46 +08:00
										 |  |  |     auto theme = skin::SkinTheme::get(editor); | 
					
						
							| 
									
										
										
										
											2016-07-12 01:16:01 +08:00
										 |  |  |     const Transformation transformation(m_standbyState->getTransformation(editor)); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |     TransformHandles* tr = getTransformHandles(editor); | 
					
						
							|  |  |  |     HandleType handle = tr->getHandleAtPoint(editor, mouseScreenPos, transformation); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 05:41:18 +08:00
										 |  |  |     CursorType newCursorType = kArrowCursor; | 
					
						
							|  |  |  |     const Cursor* newCursor = nullptr; | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto corners = transformation.transformedCorners(); | 
					
						
							|  |  |  |     auto A = corners[Transformation::Corners::LEFT_TOP]; | 
					
						
							|  |  |  |     auto B = corners[Transformation::Corners::RIGHT_TOP]; | 
					
						
							|  |  |  |     auto C = corners[Transformation::Corners::LEFT_BOTTOM]; | 
					
						
							|  |  |  |     auto D = corners[Transformation::Corners::RIGHT_BOTTOM]; | 
					
						
							|  |  |  |     vec2 v; | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (handle) { | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |       case ScaleNWHandle: | 
					
						
							|  |  |  |       case RotateNWHandle: v = to_vec2(A - D); break; | 
					
						
							|  |  |  |       case ScaleNEHandle: | 
					
						
							|  |  |  |       case RotateNEHandle: v = to_vec2(B - C); break; | 
					
						
							|  |  |  |       case ScaleSWHandle: | 
					
						
							|  |  |  |       case RotateSWHandle: v = to_vec2(C - B); break; | 
					
						
							|  |  |  |       case ScaleSEHandle: | 
					
						
							|  |  |  |       case RotateSEHandle: v = to_vec2(D - A); break; | 
					
						
							|  |  |  |       case ScaleNHandle:   v = to_vec2(A - C); break; | 
					
						
							|  |  |  |       case ScaleEHandle:   v = to_vec2(B - A); break; | 
					
						
							|  |  |  |       case ScaleSHandle:   v = to_vec2(C - A); break; | 
					
						
							|  |  |  |       case ScaleWHandle:   v = to_vec2(A - B); break; | 
					
						
							| 
									
										
										
										
											2020-09-19 06:29:43 +08:00
										 |  |  |       case SkewNHandle: | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |         v = to_vec2(B - A); | 
					
						
							|  |  |  |         v = vec2(v.y, -v.x); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2020-09-19 06:29:43 +08:00
										 |  |  |       case SkewEHandle: | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |         v = to_vec2(D - B); | 
					
						
							|  |  |  |         v = vec2(v.y, -v.x); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2020-09-19 06:29:43 +08:00
										 |  |  |       case SkewSHandle: | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |         v = to_vec2(C - D); | 
					
						
							|  |  |  |         v = vec2(v.y, -v.x); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case SkewWHandle: | 
					
						
							|  |  |  |         v = to_vec2(A - C); | 
					
						
							|  |  |  |         v = vec2(v.y, -v.x); | 
					
						
							| 
									
										
										
										
											2020-09-19 06:29:43 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2021-06-11 22:46:56 +08:00
										 |  |  |       case PivotHandle: break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         // The cursor will be set by Editor::onSetCursor()
 | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |     double angle = v.angle(); | 
					
						
							|  |  |  |     angle = base::fmod_radians(angle) + PI; | 
					
						
							|  |  |  |     ASSERT(angle >= 0.0 && angle <= 2 * PI); | 
					
						
							| 
									
										
										
										
											2022-06-10 21:31:13 +08:00
										 |  |  |     const int angleInt = std::clamp<int>(std::floor(8.0 * angle / (2.0 * PI) + 0.5), 0, 8) % 8; | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (handle == PivotHandle) { | 
					
						
							|  |  |  |       newCursorType = kHandCursor; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (handle >= ScaleNWHandle && handle <= ScaleSEHandle) { | 
					
						
							|  |  |  |       const CursorType rotated_size_cursors[8] = { kSizeWCursor,  kSizeNWCursor, kSizeNCursor, | 
					
						
							|  |  |  |                                                    kSizeNECursor, kSizeECursor,  kSizeSECursor, | 
					
						
							|  |  |  |                                                    kSizeSCursor,  kSizeSWCursor }; | 
					
						
							|  |  |  |       newCursorType = rotated_size_cursors[angleInt]; | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-19 06:29:43 +08:00
										 |  |  |     else if (handle >= RotateNWHandle && handle <= RotateSEHandle) { | 
					
						
							| 
									
										
										
										
											2017-04-07 05:41:18 +08:00
										 |  |  |       const Cursor* rotated_rotate_cursors[8] = { | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |         theme->cursors.rotateW(),  theme->cursors.rotateNw(), theme->cursors.rotateN(), | 
					
						
							|  |  |  |         theme->cursors.rotateNe(), theme->cursors.rotateE(),  theme->cursors.rotateSe(), | 
					
						
							|  |  |  |         theme->cursors.rotateS(),  theme->cursors.rotateSw() | 
					
						
							| 
									
										
										
										
											2017-04-07 05:41:18 +08:00
										 |  |  |       }; | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |       newCursor = rotated_rotate_cursors[angleInt]; | 
					
						
							| 
									
										
										
										
											2020-09-19 06:29:43 +08:00
										 |  |  |       newCursorType = kCustomCursor; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (handle >= SkewNHandle && handle <= SkewSHandle) { | 
					
						
							| 
									
										
										
										
											2020-09-23 04:12:10 +08:00
										 |  |  |       const Cursor* rotated_skew_cursors[8] = { theme->cursors.skewW(), theme->cursors.skewNw(), | 
					
						
							|  |  |  |                                                 theme->cursors.skewN(), theme->cursors.skewNe(), | 
					
						
							|  |  |  |                                                 theme->cursors.skewE(), theme->cursors.skewSe(), | 
					
						
							|  |  |  |                                                 theme->cursors.skewS(), theme->cursors.skewSw() }; | 
					
						
							|  |  |  |       newCursor = rotated_skew_cursors[angleInt]; | 
					
						
							| 
									
										
										
										
											2017-04-07 05:41:18 +08:00
										 |  |  |       newCursorType = kCustomCursor; | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-07 05:41:18 +08:00
										 |  |  |     editor->showMouseCursor(newCursorType, newCursor); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:27:43 +08:00
										 |  |  |   // Move symmetry
 | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |   Handles handles; | 
					
						
							|  |  |  |   if (getSymmetryHandles(editor, handles)) { | 
					
						
							|  |  |  |     for (const auto& handle : handles) { | 
					
						
							|  |  |  |       if (handle.bounds.contains(mouseScreenPos)) { | 
					
						
							|  |  |  |         switch (handle.align) { | 
					
						
							|  |  |  |           case TOP: | 
					
						
							|  |  |  |           case BOTTOM: editor->showMouseCursor(kSizeWECursor); break; | 
					
						
							|  |  |  |           case LEFT: | 
					
						
							|  |  |  |           case RIGHT:  editor->showMouseCursor(kSizeNSCursor); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void StandbyState::Decorator::postRenderDecorator(EditorPostRender* render) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   Editor* editor = render->getEditor(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Draw transformation handles (if the mask is visible and isn't frozen).
 | 
					
						
							| 
									
										
										
										
											2015-04-27 21:08:48 +08:00
										 |  |  |   if (editor->isActive() && editor->editorFlags() & Editor::kShowMask && | 
					
						
							| 
									
										
										
										
											2014-07-30 12:28:15 +08:00
										 |  |  |       editor->document()->isMaskVisible() && !editor->document()->mask()->isFrozen()) { | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |     // And draw only when the user has a selection tool as active tool.
 | 
					
						
							| 
									
										
										
										
											2014-08-19 19:17:57 +08:00
										 |  |  |     tools::Ink* ink = editor->getCurrentEditorInk(); | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-26 02:26:46 +08:00
										 |  |  |     if (ink->isSelection()) { | 
					
						
							| 
									
										
										
										
											2020-07-22 03:39:51 +08:00
										 |  |  |       getTransformHandles(editor)->drawHandles(editor, | 
					
						
							|  |  |  |                                                render->getGraphics(), | 
					
						
							|  |  |  |                                                m_standbyState->getTransformation(editor)); | 
					
						
							| 
									
										
										
										
											2016-04-26 02:26:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       m_standbyState->m_transformSelectionHandlesAreVisible = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Draw transformation handles (if the mask is visible and isn't frozen).
 | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |   Handles handles; | 
					
						
							|  |  |  |   if (StandbyState::Decorator::getSymmetryHandles(editor, handles)) { | 
					
						
							| 
									
										
										
										
											2022-02-19 06:01:46 +08:00
										 |  |  |     auto theme = skin::SkinTheme::get(editor); | 
					
						
							| 
									
										
										
										
											2018-08-09 23:58:43 +08:00
										 |  |  |     os::Surface* part = theme->parts.transformationHandle()->bitmap(0); | 
					
						
							| 
									
										
										
										
											2024-11-27 22:39:54 +08:00
										 |  |  |     ui::Graphics g(editor->display(), editor->display()->backLayer()->surface(), 0, 0); | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |     for (const auto& handle : handles) | 
					
						
							|  |  |  |       g.drawRgbaSurface(part, handle.bounds.x, handle.bounds.y); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-08 02:25:10 +08:00
										 |  |  | void StandbyState::Decorator::getInvalidDecoratoredRegion(Editor* editor, gfx::Region& region) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |   Handles handles; | 
					
						
							|  |  |  |   if (getSymmetryHandles(editor, handles)) { | 
					
						
							|  |  |  |     for (const auto& handle : handles) | 
					
						
							|  |  |  |       region.createUnion(region, gfx::Region(handle.bounds)); | 
					
						
							| 
									
										
										
										
											2015-12-08 02:25:10 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  | bool StandbyState::Decorator::getSymmetryHandles(Editor* editor, Handles& handles) | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  | { | 
					
						
							|  |  |  |   // Draw transformation handles (if the mask is visible and isn't frozen).
 | 
					
						
							|  |  |  |   if (editor->isActive() && editor->editorFlags() & Editor::kShowSymmetryLine && | 
					
						
							|  |  |  |       Preferences::instance().symmetryMode.enabled()) { | 
					
						
							|  |  |  |     const auto& symmetry = Preferences::instance().document(editor->document()).symmetry; | 
					
						
							|  |  |  |     auto mode = symmetry.mode(); | 
					
						
							|  |  |  |     if (mode != app::gen::SymmetryMode::NONE) { | 
					
						
							| 
									
										
										
										
											2017-11-10 05:19:18 +08:00
										 |  |  |       gfx::Rect mainTileBounds(editor->mainTilePosition(), editor->sprite()->bounds().size()); | 
					
						
							|  |  |  |       gfx::Rect canvasBounds(gfx::Point(0, 0), editor->canvasSize()); | 
					
						
							|  |  |  |       gfx::RectF editorViewport(View::getView(editor)->viewportBounds()); | 
					
						
							| 
									
										
										
										
											2022-02-19 06:01:46 +08:00
										 |  |  |       auto theme = skin::SkinTheme::get(editor); | 
					
						
							| 
									
										
										
										
											2018-08-09 23:58:43 +08:00
										 |  |  |       os::Surface* part = theme->parts.transformationHandle()->bitmap(0); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:56:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-02 02:05:23 +08:00
										 |  |  |       if ((int(mode) & int(app::gen::SymmetryMode::HORIZONTAL)) || | 
					
						
							|  |  |  |           (int(mode) & int(app::gen::SymmetryMode::RIGHT_DIAG)) || | 
					
						
							|  |  |  |           (int(mode) & int(app::gen::SymmetryMode::LEFT_DIAG))) { | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |         double pos = symmetry.xAxis(); | 
					
						
							|  |  |  |         gfx::PointF pt1, pt2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-10 05:19:18 +08:00
										 |  |  |         pt1 = gfx::PointF(mainTileBounds.x + pos, canvasBounds.y); | 
					
						
							| 
									
										
										
										
											2016-12-06 02:20:17 +08:00
										 |  |  |         pt1 = editor->editorToScreenF(pt1); | 
					
						
							| 
									
										
										
										
											2017-11-10 05:19:18 +08:00
										 |  |  |         pt2 = gfx::PointF(mainTileBounds.x + pos, canvasBounds.y2()); | 
					
						
							| 
									
										
										
										
											2016-12-06 02:20:17 +08:00
										 |  |  |         pt2 = editor->editorToScreenF(pt2); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:56:53 +08:00
										 |  |  |         pt1.y = std::max(pt1.y - part->height(), editorViewport.y); | 
					
						
							|  |  |  |         pt2.y = std::min(pt2.y, editorViewport.point2().y - part->height()); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |         pt1.x -= part->width() / 2; | 
					
						
							|  |  |  |         pt2.x -= part->width() / 2; | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         handles.push_back( | 
					
						
							| 
									
										
										
										
											2017-04-20 06:25:57 +08:00
										 |  |  |           Handle(TOP, gfx::Rect(int(pt1.x), int(pt1.y), part->width(), part->height()))); | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |         handles.push_back( | 
					
						
							| 
									
										
										
										
											2017-04-20 06:25:57 +08:00
										 |  |  |           Handle(BOTTOM, gfx::Rect(int(pt2.x), int(pt2.y), part->width(), part->height()))); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-02 02:05:23 +08:00
										 |  |  |       if ((int(mode) & int(app::gen::SymmetryMode::VERTICAL)) || | 
					
						
							|  |  |  |           (int(mode) & int(app::gen::SymmetryMode::RIGHT_DIAG)) || | 
					
						
							|  |  |  |           (int(mode) & int(app::gen::SymmetryMode::LEFT_DIAG))) { | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |         double pos = symmetry.yAxis(); | 
					
						
							|  |  |  |         gfx::PointF pt1, pt2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-10 05:19:18 +08:00
										 |  |  |         pt1 = gfx::PointF(canvasBounds.x, mainTileBounds.y + pos); | 
					
						
							| 
									
										
										
										
											2016-12-06 02:20:17 +08:00
										 |  |  |         pt1 = editor->editorToScreenF(pt1); | 
					
						
							| 
									
										
										
										
											2017-11-10 05:19:18 +08:00
										 |  |  |         pt2 = gfx::PointF(canvasBounds.x2(), mainTileBounds.y + pos); | 
					
						
							| 
									
										
										
										
											2016-12-06 02:20:17 +08:00
										 |  |  |         pt2 = editor->editorToScreenF(pt2); | 
					
						
							| 
									
										
										
										
											2015-12-06 21:56:53 +08:00
										 |  |  |         pt1.x = std::max(pt1.x - part->width(), editorViewport.x); | 
					
						
							|  |  |  |         pt2.x = std::min(pt2.x, editorViewport.point2().x - part->width()); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |         pt1.y -= part->height() / 2; | 
					
						
							|  |  |  |         pt2.y -= part->height() / 2; | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         handles.push_back( | 
					
						
							| 
									
										
										
										
											2017-04-20 06:25:57 +08:00
										 |  |  |           Handle(LEFT, gfx::Rect(int(pt1.x), int(pt1.y), part->width(), part->height()))); | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:37 +08:00
										 |  |  |         handles.push_back( | 
					
						
							| 
									
										
										
										
											2017-04-20 06:25:57 +08:00
										 |  |  |           Handle(RIGHT, gfx::Rect(int(pt2.x), int(pt2.y), part->width(), part->height()))); | 
					
						
							| 
									
										
										
										
											2015-10-29 07:00:18 +08:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2012-01-06 06:45:03 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-06 08:20:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | } // namespace app
 |