// ContextObserver impl void onActiveSiteChange(const Site& site) override { if (isVisible()) setCel(static_cast<app::Document*>(const_cast<doc::Document*>(site.document())), const_cast<Cel*>(site.cel())); else if (m_document) setCel(nullptr, nullptr); }
void ContextFlags::update(Context* context) { Site site = context->activeSite(); Document* document = static_cast<Document*>(site.document()); m_flags = 0; if (document) { m_flags |= HasActiveDocument; if (document->lock(Document::ReadLock, 0)) { m_flags |= ActiveDocumentIsReadable; if (document->isMaskVisible()) m_flags |= HasVisibleMask; Sprite* sprite = site.sprite(); if (sprite) { m_flags |= HasActiveSprite; if (sprite->backgroundLayer()) m_flags |= HasBackgroundLayer; Layer* layer = site.layer(); if (layer) { m_flags |= HasActiveLayer; if (layer->isBackground()) m_flags |= ActiveLayerIsBackground; if (layer->isVisible()) m_flags |= ActiveLayerIsVisible; if (layer->isEditable()) m_flags |= ActiveLayerIsEditable; if (layer->isImage()) { m_flags |= ActiveLayerIsImage; Cel* cel = layer->cel(site.frame()); if (cel) { m_flags |= HasActiveCel; if (cel->image()) m_flags |= HasActiveImage; } } } } if (document->lockToWrite(0)) m_flags |= ActiveDocumentIsWritable; document->unlock(); } } }
void RotateCommand::onExecute(Context* context) { { Site site = context->activeSite(); CelList cels; bool rotateSprite = false; // Flip the mask or current cel if (m_flipMask) { auto range = App::instance()->timeline()->range(); if (range.enabled()) cels = get_unique_cels(site.sprite(), range); else if (site.cel()) { // If we want to rotate the visible mask for the current cel, // we can go to MovingPixelsState. if (static_cast<app::Document*>(site.document())->isMaskVisible()) { // Select marquee tool if (tools::Tool* tool = App::instance()->toolBox() ->getToolById(tools::WellKnownTools::RectangularMarquee)) { ToolBar::instance()->selectTool(tool); current_editor->startSelectionTransformation(gfx::Point(0, 0), m_angle); return; } } cels.push_back(site.cel()); } } // Flip the whole sprite else if (site.sprite()) { for (Cel* cel : site.sprite()->uniqueCels()) cels.push_back(cel); rotateSprite = true; } if (cels.empty()) // Nothing to do return; ContextReader reader(context); { RotateJob job(reader, m_angle, cels, rotateSprite); job.startJob(); job.waitJob(); } reader.document()->generateMaskBoundaries(); update_screen_for_document(reader.document()); } }
bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg) { if (editor->hasCapture()) return true; UIContext* context = UIContext::instance(); tools::Ink* clickedInk = editor->getCurrentEditorInk(); Site site; editor->getSite(&site); app::Document* document = static_cast<app::Document*>(site.document()); Layer* layer = site.layer(); // When an editor is clicked the current view is changed. context->setActiveView(editor->getDocumentView()); // Start scroll loop if (checkForScroll(editor, msg) || checkForZoom(editor, msg)) return true; // Move cel X,Y coordinates if (clickedInk->isCelMovement()) { // Handle "Auto Select Layer" if (editor->isAutoSelectLayer()) { gfx::Point cursor = editor->screenToEditor(msg->position()); ColorPicker picker; picker.pickColor(site, cursor, ColorPicker::FromComposition); if (layer != picker.layer()) { layer = picker.layer(); if (layer) { editor->setLayer(layer); editor->flashCurrentLayer(); } } } if ((layer) && (layer->type() == ObjectType::LayerImage)) { // TODO we should be able to move the `Background' with tiled mode if (layer->isBackground()) { StatusBar::instance()->showTip(1000, "The background layer cannot be moved"); } else if (!layer->isVisible()) { StatusBar::instance()->showTip(1000, "Layer '%s' is hidden", layer->name().c_str()); } else if (!layer->isMovable() || !layer->isEditable()) { StatusBar::instance()->showTip(1000, "Layer '%s' is locked", layer->name().c_str()); } else { // Change to MovingCelState editor->setState(EditorStatePtr(new MovingCelState(editor, msg))); } } return true; } // Call the eyedropper command if (clickedInk->isEyedropper()) { callEyedropper(editor); return true; } if (clickedInk->isSelection()) { // Transform selected pixels if (document->isMaskVisible() && m_decorator->getTransformHandles(editor)) { TransformHandles* transfHandles = m_decorator->getTransformHandles(editor); // Get the handle covered by the mouse. HandleType handle = transfHandles->getHandleAtPoint(editor, msg->position(), document->getTransformation()); if (handle != NoHandle) { int x, y, opacity; Image* image = site.image(&x, &y, &opacity); if (layer && image) { if (!layer->isEditable()) { StatusBar::instance()->showTip(1000, "Layer '%s' is locked", layer->name().c_str()); return true; } // Change to MovingPixelsState transformSelection(editor, msg, handle); } return true; } } // Move selected pixels if (layer && editor->isInsideSelection() && msg->left()) { if (!layer->isEditable()) { StatusBar::instance()->showTip(1000, "Layer '%s' is locked", layer->name().c_str()); return true; } // Change to MovingPixelsState transformSelection(editor, msg, MoveHandle); return true; } } // Start the Tool-Loop if (layer) { tools::ToolLoop* toolLoop = create_tool_loop(editor, context); if (toolLoop) { EditorStatePtr newState(new DrawingState(toolLoop)); editor->setState(newState); static_cast<DrawingState*>(newState.get()) ->initToolLoop(editor, msg); } return true; } return true; }
bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg) { if (editor->hasCapture()) return true; UIContext* context = UIContext::instance(); tools::Ink* clickedInk = editor->getCurrentEditorInk(); Site site; editor->getSite(&site); app::Document* document = static_cast<app::Document*>(site.document()); Layer* layer = site.layer(); // When an editor is clicked the current view is changed. context->setActiveView(editor->getDocumentView()); // Start scroll loop if (checkForScroll(editor, msg) || checkForZoom(editor, msg)) return true; // Move cel X,Y coordinates if (clickedInk->isCelMovement()) { // Handle "Auto Select Layer" if (editor->isAutoSelectLayer()) { gfx::Point cursor = editor->screenToEditor(msg->position()); ColorPicker picker; picker.pickColor(site, cursor, ColorPicker::FromComposition); DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range(); // Change layer only when the layer is diffrent from current one, and // the range we selected is not with multiple cels. bool layerChanged = (layer != picker.layer()); bool rangeEnabled = range.enabled(); bool rangeSingleCel = ((range.type() == DocumentRange::kCels) && (range.layers() == 1) && (range.frames() == 1)); if (layerChanged && (!rangeEnabled || rangeSingleCel)) { layer = picker.layer(); if (layer) { editor->setLayer(layer); editor->flashCurrentLayer(); } } } if ((layer) && (layer->type() == ObjectType::LayerImage)) { // TODO we should be able to move the `Background' with tiled mode if (layer->isBackground()) { StatusBar::instance()->showTip(1000, "The background layer cannot be moved"); } else if (!layer->isVisible()) { StatusBar::instance()->showTip(1000, "Layer '%s' is hidden", layer->name().c_str()); } else if (!layer->isMovable() || !layer->isEditable()) { StatusBar::instance()->showTip(1000, "Layer '%s' is locked", layer->name().c_str()); } else if (!layer->cel(editor->frame())) { StatusBar::instance()->showTip(1000, "Cel is empty, nothing to move"); } else { // Change to MovingCelState editor->setState(EditorStatePtr(new MovingCelState(editor, msg))); } } return true; } // Call the eyedropper command if (clickedInk->isEyedropper()) { editor->captureMouse(); callEyedropper(editor); return true; } if (clickedInk->isSelection()) { // Transform selected pixels if (editor->isActive() && document->isMaskVisible() && m_decorator->getTransformHandles(editor)) { TransformHandles* transfHandles = m_decorator->getTransformHandles(editor); // Get the handle covered by the mouse. HandleType handle = transfHandles->getHandleAtPoint(editor, msg->position(), document->getTransformation()); if (handle != NoHandle) { int x, y, opacity; Image* image = site.image(&x, &y, &opacity); if (layer && image) { if (!layer->isEditable()) { StatusBar::instance()->showTip(1000, "Layer '%s' is locked", layer->name().c_str()); return true; } // Change to MovingPixelsState transformSelection(editor, msg, handle); } return true; } } // Move selected pixels if (layer && editor->isInsideSelection() && msg->left()) { if (!layer->isEditable()) { StatusBar::instance()->showTip(1000, "Layer '%s' is locked", layer->name().c_str()); return true; } // Change to MovingPixelsState transformSelection(editor, msg, MoveHandle); return true; } } // Move symmetry gfx::Rect box1, box2; if (m_decorator->getSymmetryHandles(editor, box1, box2) && (box1.contains(msg->position()) || box2.contains(msg->position()))) { auto& symmetry = Preferences::instance().document(editor->document()).symmetry; auto mode = symmetry.mode(); bool horz = (mode == app::gen::SymmetryMode::HORIZONTAL); auto& axis = (horz ? symmetry.xAxis: symmetry.yAxis); editor->setState( EditorStatePtr(new MovingSymmetryState(editor, msg, mode, axis))); return true; } // Start the Tool-Loop if (layer) { tools::ToolLoop* toolLoop = create_tool_loop(editor, context); if (toolLoop) { EditorStatePtr newState(new DrawingState(toolLoop)); editor->setState(newState); static_cast<DrawingState*>(newState.get()) ->initToolLoop(editor, msg); } return true; } return true; }
ExpandCelCanvas::ExpandCelCanvas(Site site, TiledMode tiledMode, Transaction& transaction, Flags flags) : m_document(static_cast<app::Document*>(site.document())) , m_sprite(site.sprite()) , m_layer(site.layer()) , m_cel(NULL) , m_celImage(NULL) , m_celCreated(false) , m_flags(flags) , m_srcImage(NULL) , m_dstImage(NULL) , m_closed(false) , m_committed(false) , m_transaction(transaction) { ASSERT(!singleton); singleton = this; create_buffers(); if (m_layer->isImage()) { m_cel = m_layer->cel(site.frame()); if (m_cel) m_celImage = m_cel->imageRef(); } // Create a new cel if (m_cel == NULL) { m_celCreated = true; m_cel = new Cel(site.frame(), ImageRef(NULL)); } m_origCelPos = m_cel->position(); // Region to draw gfx::Rect celBounds( m_cel->x(), m_cel->y(), m_celImage ? m_celImage->width(): m_sprite->width(), m_celImage ? m_celImage->height(): m_sprite->height()); gfx::Rect spriteBounds(0, 0, m_sprite->width(), m_sprite->height()); if (tiledMode == TiledMode::NONE) { // Non-tiled m_bounds = celBounds.createUnion(spriteBounds); } else { // Tiled m_bounds = spriteBounds; } // We have to adjust the cel position to match the m_dstImage // position (the new m_dstImage will be used in RenderEngine to // draw this cel). m_cel->setPosition(m_bounds.x, m_bounds.y); if (m_celCreated) { getDestCanvas(); m_cel->data()->setImage(m_dstImage); static_cast<LayerImage*>(m_layer)->addCel(m_cel); } }
PixelsMovement::PixelsMovement( Context* context, Site site, const Image* moveThis, const Mask* mask, const char* operationName) : m_reader(context) , m_site(site) , m_document(static_cast<app::Document*>(site.document())) , m_sprite(site.sprite()) , m_layer(site.layer()) , m_transaction(context, operationName) , m_setMaskCmd(nullptr) , m_isDragging(false) , m_adjustPivot(false) , m_handle(NoHandle) , m_originalImage(Image::createCopy(moveThis)) , m_opaque(false) , m_maskColor(m_sprite->transparentColor()) { gfx::Transformation transform(mask->bounds()); set_pivot_from_preferences(transform); m_initialData = transform; m_currentData = transform; m_initialMask = new Mask(*mask); m_currentMask = new Mask(*mask); m_pivotVisConn = Preferences::instance().selection.pivotVisibility.AfterChange.connect( base::Bind<void>(&PixelsMovement::onPivotChange, this)); m_pivotPosConn = Preferences::instance().selection.pivotPosition.AfterChange.connect( base::Bind<void>(&PixelsMovement::onPivotChange, this)); m_rotAlgoConn = Preferences::instance().selection.rotationAlgorithm.AfterChange.connect( base::Bind<void>(&PixelsMovement::onRotationAlgorithmChange, this)); // The extra cel must be null, because if it's not null, it means // that someone else is using it (e.g. the editor brush preview), // and its owner could destroy our new "extra cel". ASSERT(!m_document->extraCel()); redrawExtraImage(); redrawCurrentMask(); // If the mask isn't in the document (e.g. it's from Paste command), // we've to replace the document mask and generate its boundaries. // // This is really tricky. PixelsMovement is used in two situations: // 1) When the current selection is transformed, and // 2) when the user pastes the clipboard content. // // In the first case, the current document selection is used. And a // cutMask() command could be called after PixelsMovement ctor. We // need the following stack of Cmd instances in the Transaction: // - cmd::ClearMask: clears the old mask) // - cmd::SetMask (m_setMaskCmd): replaces the old mask with a new mask // The new mask in m_setMaskCmd is replaced each time the mask is modified. // // In the second case, the mask isn't in the document, is a new mask // used to paste the pixels, so we've to replace the document mask. // The Transaction contains just a: // - cmd::SetMask // // The main point here is that cmd::SetMask must be the last item in // the Transaction using the mask (because we use cmd::SetMask::setNewMask()). // // TODO Simplify this code in some way or make explicit both usages if (mask != m_document->mask()) { updateDocumentMask(); update_screen_for_document(m_document); } }