diff --git a/src/widgets/editor.h b/src/widgets/editor.h index 46f3228c3..4c0300101 100644 --- a/src/widgets/editor.h +++ b/src/widgets/editor.h @@ -68,8 +68,7 @@ class Editor : public Widget // editor states enum State { EDITOR_STATE_STANDBY, - EDITOR_STATE_MOVING_SCROLL, - EDITOR_STATE_MOVING_PIXELS, + EDITOR_STATE_SCROLLING, EDITOR_STATE_DRAWING, }; @@ -142,6 +141,7 @@ public: void editor_draw_mask_safe(); void flashCurrentLayer(); + void setMaskColorForPixelsMovement(color_t color); void screen_to_editor(int xin, int yin, int *xout, int *yout); void editor_to_screen(int xin, int yin, int *xout, int *yout); diff --git a/src/widgets/editor/editor.cpp b/src/widgets/editor/editor.cpp index 14e34b5c6..46c112650 100644 --- a/src/widgets/editor/editor.cpp +++ b/src/widgets/editor/editor.cpp @@ -131,9 +131,16 @@ void Editor::editor_set_sprite(Sprite* sprite) if (this->hasMouse()) jmanager_free_mouse(); // TODO Why is this here? Review this code + // The editor must be stand-by state + ASSERT(m_state == EDITOR_STATE_STANDBY); + + // Change the sprite m_sprite = sprite; if (m_sprite) { + // Get the preferred sprite's settings to edit it PreferredEditorSettings preferred = m_sprite->getPreferredEditorSettings(); + + // Change the editor's configuration using the retrieved sprite's settings m_zoom = preferred.zoom; editor_update(); @@ -141,11 +148,13 @@ void Editor::editor_set_sprite(Sprite* sprite) m_offset_y + preferred.scroll_y, false); } + // In this case sprite is NULL else { editor_update(); - editor_set_scroll(0, 0, false); + editor_set_scroll(0, 0, false); // No scroll } + // Redraw the entire editor (because we have a new sprite to draw) dirty(); } @@ -562,6 +571,15 @@ void Editor::flashCurrentLayer() } } +void Editor::setMaskColorForPixelsMovement(color_t color) +{ + ASSERT(m_sprite != NULL); + ASSERT(m_pixelsMovement != NULL); + + int imgtype = m_sprite->getImgType(); + m_pixelsMovement->setMaskColor(get_color_for_image(imgtype, color)); +} + void Editor::deleteDecorators() { for (std::vector::iterator @@ -653,6 +671,7 @@ void Editor::dropPixels() m_state = EDITOR_STATE_STANDBY; releaseMouse(); + app_get_statusbar()->hideMovePixelsOptions(); editor_update_statusbar_for_standby(); } @@ -745,7 +764,7 @@ void Editor::editor_update_statusbar_for_pixel_movement() { Rect bounds = m_pixelsMovement->getImageBounds(); app_get_statusbar()->setStatusText - (100, "Pos %d %d, Size %d %d [Press ENTER to drop]", + (100, "Pos %d %d, Size %d %d", bounds.x, bounds.y, bounds.w, bounds.h); } @@ -976,19 +995,6 @@ bool Editor::onProcessMessage(JMessage msg) return true; } } - // Moving pixels loop - else if (m_state == EDITOR_STATE_MOVING_PIXELS) { - if (m_insideSelection) { - // Re-catch the image - int x, y; - screen_to_editor(msg->mouse.x, msg->mouse.y, &x, &y); - m_pixelsMovement->catchImageAgain(x, y); - return true; - } - else { - dropPixels(); - } - } if (!hasCapture()) { UIContext* context = UIContext::instance(); @@ -997,18 +1003,39 @@ bool Editor::onProcessMessage(JMessage msg) set_current_editor(this); context->set_current_sprite(m_sprite); - // Move the scroll + // Start scroll loop if (msg->mouse.middle || m_space_pressed || current_tool->getInk(msg->mouse.right ? 1: 0)->isScrollMovement()) { - m_state = EDITOR_STATE_MOVING_SCROLL; + m_state = EDITOR_STATE_SCROLLING; editor_setcursor(msg->mouse.x, msg->mouse.y); + captureMouse(); + return true; } + + if (m_pixelsMovement) { + // Start "moving pixels" loop + if (m_insideSelection) { + // Re-catch the image + int x, y; + screen_to_editor(msg->mouse.x, msg->mouse.y, &x, &y); + m_pixelsMovement->catchImageAgain(x, y); + + captureMouse(); + return true; + } + // End "moving pixels" loop + else { + // Drop pixels (e.g. to start drawing) + dropPixels(); + } + } + // Move frames position - else if ((m_ctrl_pressed && - !current_tool->getInk(msg->mouse.right ? 1: 0)->isSelection()) || - current_tool->getInk(msg->mouse.right ? 1: 0)->isCelMovement()) { + if ((m_ctrl_pressed && + !current_tool->getInk(msg->mouse.right ? 1: 0)->isSelection()) || + current_tool->getInk(msg->mouse.right ? 1: 0)->isCelMovement()) { if ((m_sprite->getCurrentLayer()) && (m_sprite->getCurrentLayer()->type == GFXOBJ_LAYER_IMAGE)) { // TODO you can move the `Background' with tiled mode @@ -1026,9 +1053,8 @@ bool Editor::onProcessMessage(JMessage msg) bool click2 = get_config_bool("Options", "MoveClick2", FALSE); interactive_move_layer(click2 ? MODE_CLICKANDCLICK: MODE_CLICKANDRELEASE, - TRUE, NULL); + TRUE, NULL); // TODO remove this routine } - return true; } } // Move selected pixels @@ -1045,9 +1071,6 @@ bool Editor::onProcessMessage(JMessage msg) return true; } - // Change editor's state - m_state = EDITOR_STATE_MOVING_PIXELS; - // Copy the mask to the extra cel image Image* tmpImage = NewImageFromMask(m_sprite); x = m_sprite->getMask()->x; @@ -1064,8 +1087,14 @@ bool Editor::onProcessMessage(JMessage msg) screen_to_editor(msg->mouse.x, msg->mouse.y, &x, &y); m_pixelsMovement->catchImage(x, y); + // Setup mask color + setMaskColorForPixelsMovement(app_get_statusbar()->getTransparentColor()); + + // Update status bar editor_update_statusbar_for_pixel_movement(); + app_get_statusbar()->showMovePixelsOptions(); } + captureMouse(); } // Call the eyedropper command else if (m_alt_pressed || @@ -1104,10 +1133,9 @@ bool Editor::onProcessMessage(JMessage msg) // Redraw it (without pen preview) if (thick) editor_draw_cursor(msg->mouse.x, msg->mouse.y); - } - // Capture the mouse - captureMouse(); + captureMouse(); + } } return true; @@ -1116,7 +1144,7 @@ bool Editor::onProcessMessage(JMessage msg) break; // Move the scroll - if (m_state == EDITOR_STATE_MOVING_SCROLL) { + if (m_state == EDITOR_STATE_SCROLLING) { JWidget view = jwidget_get_view(this); JRect vp = jview_get_viewport_position(view); int scroll_x, scroll_y; @@ -1137,12 +1165,12 @@ bool Editor::onProcessMessage(JMessage msg) } } // Moving pixels - else if (m_state == EDITOR_STATE_MOVING_PIXELS) { - // Infinite scroll - controlInfiniteScroll(msg); - + else if (m_pixelsMovement) { // If there is a button pressed if (m_pixelsMovement->isDragging()) { + // Infinite scroll + controlInfiniteScroll(msg); + // Get the position of the mouse in the sprite int x, y; screen_to_editor(msg->mouse.x, msg->mouse.y, &x, &y); @@ -1254,16 +1282,15 @@ bool Editor::onProcessMessage(JMessage msg) clear_keybuf(); } - // Moving pixels - else if (m_state == EDITOR_STATE_MOVING_PIXELS) { - // Drop the image temporarily in this location (where the user releases the mouse) - m_pixelsMovement->dropImageTemporarily(); - return true; - } - else { + else if (m_state != EDITOR_STATE_STANDBY) { ASSERT(m_toolLoopManager == NULL); m_state = EDITOR_STATE_STANDBY; } + // Moving pixels + else if (m_pixelsMovement) { + // Drop the image temporarily in this location (where the user releases the mouse) + m_pixelsMovement->dropImageTemporarily(); + } editor_setcursor(msg->mouse.x, msg->mouse.y); editor_update_statusbar_for_standby(); @@ -1290,7 +1317,7 @@ bool Editor::onProcessMessage(JMessage msg) case KEY_LCONTROL: case KEY_RCONTROL: // If the user press the CTRL key when he is dragging pixels (but not pressing the mouse buttons)... - if (!m_ctrl_pressed && !jmouse_b(0) && m_state == EDITOR_STATE_MOVING_PIXELS) { + if (!m_ctrl_pressed && !jmouse_b(0) && m_pixelsMovement) { // Drop pixels (sure the user will press the mouse button to start dragging a copy) dropPixels(); } @@ -1309,20 +1336,6 @@ bool Editor::onProcessMessage(JMessage msg) if (m_state == EDITOR_STATE_DRAWING) return true; - if (m_state == EDITOR_STATE_MOVING_PIXELS) { - dropPixels(); - - // Resend the key/message to the manager - if (msg->key.scancode != KEY_ENTER && - msg->key.scancode != KEY_ENTER_PAD) { - JMessage newmsg = jmessage_new_copy_without_dests(msg); - jmessage_add_dest(newmsg, ji_get_default_manager()); - jmanager_enqueue_message(newmsg); - } - - // Used - return true; - } break; case JM_KEYRELEASED: @@ -1361,8 +1374,7 @@ bool Editor::onProcessMessage(JMessage msg) case JM_WHEEL: if (m_state == EDITOR_STATE_STANDBY || - m_state == EDITOR_STATE_DRAWING || - m_state == EDITOR_STATE_MOVING_PIXELS) { + m_state == EDITOR_STATE_DRAWING) { // There are and sprite in the editor and the mouse is inside if (m_sprite && this->hasMouse()) { int dz = jmouse_z(1) - jmouse_z(0); @@ -1518,46 +1530,11 @@ void Editor::editor_setcursor(int x, int y) switch (m_state) { - case EDITOR_STATE_MOVING_SCROLL: + case EDITOR_STATE_SCROLLING: hide_drawing_cursor(); jmouse_set_cursor(JI_CURSOR_SCROLL); break; - case EDITOR_STATE_MOVING_PIXELS: - { - UIContext* context = UIContext::instance(); - Tool* current_tool = context->getSettings()->getCurrentTool(); - - int x, y; - screen_to_editor(jmouse_x(0), jmouse_y(0), &x, &y); - - // Move selection - if (m_pixelsMovement->isDragging() || - m_sprite->getMask()->contains_point(x, y)) { - hide_drawing_cursor(); - jmouse_set_cursor(JI_CURSOR_MOVE); - - if (!m_insideSelection) - m_insideSelection = true; - return; - } - - if (m_insideSelection) - m_insideSelection = false; - - // Draw - if (m_cursor_candraw) { - jmouse_set_cursor(JI_CURSOR_NULL); - show_drawing_cursor(); - } - // Forbidden - else { - hide_drawing_cursor(); - jmouse_set_cursor(JI_CURSOR_FORBIDDEN); - } - } - break; - case EDITOR_STATE_DRAWING: if (current_tool->getInk(0)->isEyedropper()) { hide_drawing_cursor(); @@ -1577,8 +1554,38 @@ void Editor::editor_setcursor(int x, int y) editor_update_candraw(); // TODO remove this + // Pixels movement + if (m_pixelsMovement) { + int x, y; + screen_to_editor(jmouse_x(0), jmouse_y(0), &x, &y); + + // Move selection + if (m_pixelsMovement->isDragging() || + m_sprite->getMask()->contains_point(x, y)) { + hide_drawing_cursor(); + jmouse_set_cursor(JI_CURSOR_MOVE); + + if (!m_insideSelection) + m_insideSelection = true; + return; + } + + if (m_insideSelection) + m_insideSelection = false; + + // Draw + if (m_cursor_candraw) { + jmouse_set_cursor(JI_CURSOR_NULL); + show_drawing_cursor(); + } + // Forbidden + else { + hide_drawing_cursor(); + jmouse_set_cursor(JI_CURSOR_FORBIDDEN); + } + } // Eyedropper - if (m_alt_pressed) { + else if (m_alt_pressed) { hide_drawing_cursor(); jmouse_set_cursor(JI_CURSOR_EYEDROPPER); } diff --git a/src/widgets/statebar.cpp b/src/widgets/statebar.cpp index 1be1e9678..88f1e52bc 100644 --- a/src/widgets/statebar.cpp +++ b/src/widgets/statebar.cpp @@ -24,6 +24,7 @@ #include #include "jinete/jinete.h" +#include "Vaca/Size.h" #include "app.h" #include "commands/commands.h" @@ -35,6 +36,7 @@ #include "modules/palettes.h" #include "modules/skinneable_theme.h" #include "raster/cel.h" +#include "raster/image.h" #include "raster/layer.h" #include "raster/sprite.h" #include "raster/undo.h" @@ -42,6 +44,7 @@ #include "tools/tool.h" #include "ui_context.h" #include "util/misc.h" +#include "widgets/colbut.h" #include "widgets/editor.h" #include "widgets/statebar.h" @@ -55,6 +58,7 @@ enum { static bool tipwindow_msg_proc(JWidget widget, JMessage msg); +static bool transparent_color_change_hook(JWidget widget, void *data); static bool slider_change_hook(JWidget widget, void *data); static void button_command(JWidget widget, void *data); @@ -91,40 +95,62 @@ StatusBar::StatusBar() m_tipwindow = NULL; m_hot_layer = -1; + // The extra pixel in left and right borders are necessary so + // m_commandsBox and m_movePixelsBox do not overlap the upper-left + // and upper-right pixels drawn in JM_DRAW message (see putpixels) + jwidget_set_border(this, 1*jguiscale(), 0, 1*jguiscale(), 0); + // Construct the commands box - Widget* box1 = jbox_new(JI_HORIZONTAL); - Widget* box2 = jbox_new(JI_HORIZONTAL | JI_HOMOGENEOUS); - Widget* box3 = jbox_new(JI_HORIZONTAL); - m_slider = jslider_new(0, 255, 255); + { + Widget* box1 = jbox_new(JI_HORIZONTAL); + Widget* box2 = jbox_new(JI_HORIZONTAL | JI_HOMOGENEOUS); + Widget* box3 = jbox_new(JI_HORIZONTAL); + m_slider = jslider_new(0, 255, 255); - setup_mini_look(m_slider); + setup_mini_look(m_slider); - ICON_NEW(m_b_first, GFX_ANI_FIRST, ACTION_FIRST); - ICON_NEW(m_b_prev, GFX_ANI_PREV, ACTION_PREV); - ICON_NEW(m_b_play, GFX_ANI_PLAY, ACTION_PLAY); - ICON_NEW(m_b_next, GFX_ANI_NEXT, ACTION_NEXT); - ICON_NEW(m_b_last, GFX_ANI_LAST, ACTION_LAST); + ICON_NEW(m_b_first, GFX_ANI_FIRST, ACTION_FIRST); + ICON_NEW(m_b_prev, GFX_ANI_PREV, ACTION_PREV); + ICON_NEW(m_b_play, GFX_ANI_PLAY, ACTION_PLAY); + ICON_NEW(m_b_next, GFX_ANI_NEXT, ACTION_NEXT); + ICON_NEW(m_b_last, GFX_ANI_LAST, ACTION_LAST); - HOOK(m_slider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0); - jwidget_set_min_size(m_slider, JI_SCREEN_W/5, 0); + HOOK(m_slider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0); + jwidget_set_min_size(m_slider, JI_SCREEN_W/5, 0); - jwidget_set_border(this, 1*jguiscale(), 0, 0, 0); - jwidget_set_border(box1, 2*jguiscale(), 1*jguiscale(), 2*jguiscale(), 2*jguiscale()); - jwidget_noborders(box2); - jwidget_noborders(box3); - jwidget_expansive(box3, true); + jwidget_set_border(box1, 2*jguiscale(), 1*jguiscale(), 2*jguiscale(), 2*jguiscale()); + jwidget_noborders(box2); + jwidget_noborders(box3); + jwidget_expansive(box3, true); - jwidget_add_child(box2, m_b_first); - jwidget_add_child(box2, m_b_prev); - jwidget_add_child(box2, m_b_play); - jwidget_add_child(box2, m_b_next); - jwidget_add_child(box2, m_b_last); + jwidget_add_child(box2, m_b_first); + jwidget_add_child(box2, m_b_prev); + jwidget_add_child(box2, m_b_play); + jwidget_add_child(box2, m_b_next); + jwidget_add_child(box2, m_b_last); - jwidget_add_child(box1, box3); - jwidget_add_child(box1, box2); - jwidget_add_child(box1, m_slider); + jwidget_add_child(box1, box3); + jwidget_add_child(box1, box2); + jwidget_add_child(box1, m_slider); - m_commandsBox = box1; + m_commandsBox = box1; + } + + // Construct move-pixels box + { + Widget* filler = jbox_new(JI_HORIZONTAL); + jwidget_expansive(filler, true); + + m_movePixelsBox = jbox_new(JI_HORIZONTAL); + m_transparentLabel = new Label("Transparent Color:"); + m_transparentColor = colorbutton_new(color_mask(), IMAGE_RGB); + + jwidget_add_child(m_movePixelsBox, filler); + jwidget_add_child(m_movePixelsBox, m_transparentLabel); + jwidget_add_child(m_movePixelsBox, m_transparentColor); + + HOOK(m_transparentColor, SIGNAL_COLORBUTTON_CHANGE, transparent_color_change_hook, 1); + } App::instance()->CurrentToolChange.connect(&StatusBar::onCurrentToolChange, this); } @@ -253,6 +279,27 @@ void StatusBar::showTool(int msecs, Tool* tool) } } +void StatusBar::showMovePixelsOptions() +{ + if (!jwidget_has_child(this, m_movePixelsBox)) { + jwidget_add_child(this, m_movePixelsBox); + jwidget_dirty(this); + } +} + +void StatusBar::hideMovePixelsOptions() +{ + if (jwidget_has_child(this, m_movePixelsBox)) { + jwidget_remove_child(this, m_movePixelsBox); + jwidget_dirty(this); + } +} + +color_t StatusBar::getTransparentColor() +{ + return colorbutton_get_color(m_transparentColor); +} + ////////////////////////////////////////////////////////////////////// // Progress bars stuff @@ -321,13 +368,25 @@ bool StatusBar::onProcessMessage(JMessage msg) jwidget_set_rect(m_commandsBox, rc); jrect_free(rc); } + { + JRect rc = jrect_new_copy(this->rc); + Vaca::Size reqSize = m_movePixelsBox->getPreferredSize(); + rc->x1 = rc->x2 - reqSize.w; + rc->x2 -= this->border_width.r; + jwidget_set_rect(m_movePixelsBox, rc); + jrect_free(rc); + } return true; case JM_CLOSE: if (!jwidget_has_child(this, m_commandsBox)) { - /* append the "commands_box" to destroy it in the jwidget_free */ + // Append the "m_commandsBox" so it is destroyed in StatusBar dtor. jwidget_add_child(this, m_commandsBox); } + if (!jwidget_has_child(this, m_movePixelsBox)) { + // Append the "m_movePixelsBox" so it is destroyed in StatusBar dtor. + jwidget_add_child(this, m_movePixelsBox); + } break; case JM_DRAW: { @@ -515,21 +574,23 @@ bool StatusBar::onProcessMessage(JMessage msg) case JM_MOUSEENTER: { bool state = (UIContext::instance()->get_current_sprite() != NULL); - if (!jwidget_has_child(this, m_commandsBox) && state) { - m_b_first->setEnabled(state); - m_b_prev->setEnabled(state); - m_b_play->setEnabled(state); - m_b_next->setEnabled(state); - m_b_last->setEnabled(state); + if (!jwidget_has_child(this, m_movePixelsBox)) { + if (!jwidget_has_child(this, m_commandsBox) && state) { + m_b_first->setEnabled(state); + m_b_prev->setEnabled(state); + m_b_play->setEnabled(state); + m_b_next->setEnabled(state); + m_b_last->setEnabled(state); - updateFromLayer(); + updateFromLayer(); - jwidget_add_child(this, m_commandsBox); - jwidget_dirty(this); - } - else { - // Status text for donations - setStatusText(0, "Click the \"Donate\" button to support ASE development"); + jwidget_add_child(this, m_commandsBox); + jwidget_dirty(this); + } + else { + // Status text for donations + setStatusText(0, "Click the \"Donate\" button to support ASE development"); + } } break; } @@ -669,6 +730,13 @@ static bool tipwindow_msg_proc(JWidget widget, JMessage msg) return false; } +static bool transparent_color_change_hook(JWidget widget, void *data) +{ + if (current_editor) + current_editor->setMaskColorForPixelsMovement(app_get_statusbar()->getTransparentColor()); + return true; +} + static bool slider_change_hook(JWidget widget, void *data) { try { diff --git a/src/widgets/statebar.h b/src/widgets/statebar.h index 3cc4c282a..c1f9d4f33 100644 --- a/src/widgets/statebar.h +++ b/src/widgets/statebar.h @@ -57,6 +57,11 @@ public: void showColor(int msecs, const char* text, color_t color, int alpha); void showTool(int msecs, Tool* tool); + void showMovePixelsOptions(); + void hideMovePixelsOptions(); + + color_t getTransparentColor(); + // Methods to add and remove progress bars Progress* addProgress(); void removeProgress(Progress* progress); @@ -92,6 +97,11 @@ private: Widget* m_b_next; // Go to next frame Widget* m_b_last; // Go to last frame + // Box with move-pixels commands (when the user drag-and-drop selected pixels using the editor) + Widget* m_movePixelsBox; + Widget* m_transparentLabel; + Widget* m_transparentColor; + // Tip window Frame* m_tipwindow;