void UndoCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document(writer.document()); DocumentUndo* undo = document->getUndo(); Sprite* sprite = document->sprite(); if (context->settings()->undoGotoModified()) { SpritePosition spritePosition; SpritePosition currentPosition(writer.location()->layerIndex(), writer.location()->frame()); if (m_type == Undo) spritePosition = undo->getNextUndoSpritePosition(); else spritePosition = undo->getNextRedoSpritePosition(); if (spritePosition != currentPosition) { current_editor->setLayer(sprite->indexToLayer(spritePosition.layerIndex())); current_editor->setFrame(spritePosition.frameNumber()); // Draw the current layer/frame (which is not undone yet) so the // user can see the doUndo/doRedo effect. current_editor->drawSpriteClipped( gfx::Region(gfx::Rect(0, 0, sprite->width(), sprite->height()))); ui::dirty_display_flag = true; gui_feedback(); base::this_thread::sleep_for(0.01); } } StatusBar::instance() ->showTip(1000, "%s %s", (m_type == Undo ? "Undid": "Redid"), (m_type == Undo ? undo->getNextUndoLabel(): undo->getNextRedoLabel())); // Effectively undo/redo. if (m_type == Undo) undo->doUndo(); else undo->doRedo(); document->generateMaskBoundaries(); document->destroyExtraCel(); // Regenerate extras update_screen_for_document(document); set_current_palette(writer.palette(), false); }
void UndoCommand::onExecute(Context* context) { ActiveDocumentWriter document(context); DocumentUndo* undo = document->getUndo(); Sprite* sprite = document->getSprite(); if (get_config_bool("Options", "UndoGotoModified", true)) { SpritePosition spritePosition; if (m_type == Undo) spritePosition = undo->getNextUndoSpritePosition(); else spritePosition = undo->getNextRedoSpritePosition(); if (spritePosition != sprite->getCurrentPosition()) { sprite->setCurrentPosition(spritePosition); current_editor->drawSpriteSafe(0, 0, sprite->getWidth(), sprite->getHeight()); update_screen_for_document(document); ui::dirty_display_flag = true; gui_feedback(); base::this_thread::sleep_for(0.01); } } StatusBar::instance() ->showTip(1000, "%s %s", (m_type == Undo ? "Undid": "Redid"), (m_type == Undo ? undo->getNextUndoLabel(): undo->getNextRedoLabel())); if (m_type == Undo) undo->doUndo(); else undo->doRedo(); document->generateMaskBoundaries(); document->destroyExtraCel(); // Regenerate extras update_screen_for_document(document); }
// Manager event handler. bool CustomizedGuiManager::onProcessMessage(Message* msg) { switch (msg->type()) { case kCloseAppMessage: { // Execute the "Exit" command. Command* command = CommandsModule::instance()->getCommandByName(CommandId::Exit); UIContext::instance()->executeCommand(command); } break; case kDropFilesMessage: { // If the main window is not the current foreground one. We // discard the drop-files event. if (getForegroundWindow() != App::instance()->getMainWindow()) break; const DropFilesMessage::Files& files = static_cast<DropFilesMessage*>(msg)->files(); // Open all files Command* cmd_open_file = CommandsModule::instance()->getCommandByName(CommandId::OpenFile); Params params; for (DropFilesMessage::Files::const_iterator it = files.begin(); it != files.end(); ++it) { params.set("filename", it->c_str()); UIContext::instance()->executeCommand(cmd_open_file, ¶ms); } } break; case kQueueProcessingMessage: gui_feedback(); break; case kKeyDownMessage: { Window* toplevel_window = getTopWindow(); // If there is a foreground window as top level... if (toplevel_window && toplevel_window != App::instance()->getMainWindow() && toplevel_window->isForeground()) { // We just do not process keyboard shortcuts for menus and tools break; } for (Shortcut* shortcut : *shortcuts) { if (shortcut->is_pressed(msg)) { // Cancel menu-bar loops (to close any popup menu) App::instance()->getMainWindow()->getMenuBar()->cancelMenuLoop(); switch (shortcut->type) { case Shortcut::Type::ChangeTool: { tools::Tool* current_tool = UIContext::instance()->settings()->getCurrentTool(); tools::Tool* select_this_tool = shortcut->tool; tools::ToolBox* toolbox = App::instance()->getToolBox(); std::vector<tools::Tool*> possibles; // Iterate over all tools for (tools::ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) { Shortcut* shortcut = get_keyboard_shortcut_for_tool(*it); // Collect all tools with the pressed keyboard-shortcut if (shortcut && shortcut->is_pressed(msg)) possibles.push_back(*it); } if (possibles.size() >= 2) { bool done = false; for (size_t i=0; i<possibles.size(); ++i) { if (possibles[i] != current_tool && ToolBar::instance()->isToolVisible(possibles[i])) { select_this_tool = possibles[i]; done = true; break; } } if (!done) { for (size_t i=0; i<possibles.size(); ++i) { // If one of the possibilities is the current tool if (possibles[i] == current_tool) { // We select the next tool in the possibilities select_this_tool = possibles[(i+1) % possibles.size()]; break; } } } } ToolBar::instance()->selectTool(select_this_tool); return true; } case Shortcut::Type::ExecuteCommand: { Command* command = shortcut->command; // Commands are executed only when the main window is // the current window running at foreground. UI_FOREACH_WIDGET(getChildren(), it) { Window* child = static_cast<Window*>(*it); // There are a foreground window executing? if (child->isForeground()) { break; } // Is it the desktop and the top-window= else if (child->isDesktop() && child == App::instance()->getMainWindow()) { // OK, so we can execute the command represented // by the pressed-key in the message... UIContext::instance()->executeCommand(command, shortcut->params); return true; } } break; } case Shortcut::Type::EditorQuicktool: { // Do nothing, it is used in the editor through the // get_selected_quicktool() function. break; } } break; } } break; }
// Returns false when the user stop the click-loop: releases the // button or press the second click (depend of the mode) int Editor::editor_click(int *x, int *y, int *update, void (*scroll_callback) (int before_change)) { int prev_x, prev_y; poll_keyboard(); if (click_first) { click_first = false; if (click_mode == MODE_CLICKANDCLICK) { do { jmouse_poll(); gui_feedback(); } while (jmouse_b(0)); jmouse_set_position(click_start_x, click_start_y); clear_keybuf(); } } *update = jmouse_poll(); screenToEditor(click_last_x, click_last_y, &prev_x, &prev_y); click_prev_last_b = click_last_b; click_last_x = jmouse_x(0); click_last_y = jmouse_y(0); click_last_b = jmouse_b(0); screenToEditor(click_last_x, click_last_y, x, y); /* the mouse was moved */ if (*update) { View* view = View::getView(this); gfx::Rect vp = view->getViewportBounds(); /* update scroll */ if (jmouse_control_infinite_scroll(vp)) { if (scroll_callback) (*scroll_callback)(true); /* smooth scroll movement */ if (get_config_bool("Options", "MoveSmooth", true)) { jmouse_set_position(MID(vp.x+1, click_last_x, vp.x+vp.w-2), MID(vp.y+1, click_last_y, vp.y+vp.h-2)); } /* this is better for high resolutions: scroll movement by big steps */ else { jmouse_set_position((click_last_x != jmouse_x(0)) ? (click_last_x + (vp.x+vp.w/2))/2: jmouse_x(0), (click_last_y != jmouse_y(0)) ? (click_last_y + (vp.y+vp.h/2))/2: jmouse_y(0)); } gfx::Point scroll = view->getViewScroll(); setEditorScroll(scroll.x+click_last_x-jmouse_x(0), scroll.y+click_last_y-jmouse_y(0), true); click_last_x = jmouse_x(0); click_last_y = jmouse_y(0); if (scroll_callback) (*scroll_callback)(false); } // If the cursor hasn't subpixel movement if (!editor_cursor_is_subpixel()) { // Check if the mouse change to other pixel of the sprite *update = ((prev_x != *x) || (prev_y != *y)); } else { // Check if the mouse change to other pixel of the screen *update = ((prev_x != click_last_x) || (prev_y != click_last_y)); } } /* click-and-click mode */ if (click_mode == MODE_CLICKANDCLICK) { if (click_last_b) { click_prev_last_b = click_last_b; do { jmouse_poll(); gui_feedback(); } while (jmouse_b(0)); jmouse_set_position(click_last_x, click_last_y); clear_keybuf(); return false; } else { return true; } } /* click-and-release mode */ else { return (click_last_b) ? true: false; } }
// Gives to the user the possibility to move the sprite's layer in the // current editor, returns true if the position was changed. int interactive_move_layer(int mode, bool use_undo, int (*callback)()) { Editor* editor = current_editor; Document* document = editor->getDocument(); undo::UndoHistory* undo = document->getUndoHistory(); Sprite* sprite = document->getSprite(); ASSERT(sprite->getCurrentLayer()->is_image()); LayerImage* layer = static_cast<LayerImage*>(sprite->getCurrentLayer()); Cel *cel = layer->getCel(sprite->getCurrentFrame()); int start_x, new_x; int start_y, new_y; int start_b; int ret; int update = false; int quiet_clock = -1; int first_time = true; int begin_x; int begin_y; if (!cel) return false; begin_x = cel->getX(); begin_y = cel->getY(); editor->hideDrawingCursor(); jmouse_set_cursor(JI_CURSOR_MOVE); editor->editor_click_start(mode, &start_x, &start_y, &start_b); do { if (update) { cel->setPosition(begin_x - start_x + new_x, begin_y - start_y + new_y); // Update layer-bounds. editor->invalidate(); // Update status bar. app_get_statusbar()->setStatusText (0, "Pos %3d %3d Offset %3d %3d", (int)cel->getX(), (int)cel->getY(), (int)(cel->getX() - begin_x), (int)(cel->getY() - begin_y)); /* update clock */ quiet_clock = ji_clock; first_time = false; } /* call the user's routine */ if (callback) (*callback)(); /* redraw dirty widgets */ jwidget_flush_redraw(ji_get_default_manager()); jmanager_dispatch_messages(ji_get_default_manager()); gui_feedback(); } while (editor->editor_click(&new_x, &new_y, &update, NULL)); new_x = cel->getX(); new_y = cel->getY(); cel->setPosition(begin_x, begin_y); /* the position was changed */ if (!editor->editor_click_cancel()) { if (use_undo && undo->isEnabled()) { undo->setLabel("Cel Movement"); undo->setModification(undo::ModifyDocument); undo->pushUndoer(new undoers::SetCelPosition(undo->getObjects(), cel)); } cel->setPosition(new_x, new_y); ret = true; } /* the position wasn't changed */ else { ret = false; } /* redraw the sprite in all editors */ update_screen_for_document(document); /* restore the cursor */ editor->showDrawingCursor(); editor->editor_click_done(); return ret; }