MoveTool.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "MoveTool.h"
  8. #include "../Image.h"
  9. #include "../ImageEditor.h"
  10. #include "../Layer.h"
  11. #include <LibGUI/Action.h>
  12. #include <LibGUI/Menu.h>
  13. #include <LibGUI/Painter.h>
  14. #include <LibGUI/Window.h>
  15. namespace PixelPaint {
  16. void MoveTool::on_mousedown(Layer* layer, MouseEvent& event)
  17. {
  18. if (event.image_event().button() == GUI::MouseButton::Secondary) {
  19. m_editor->start_panning(event.raw_event().position());
  20. return;
  21. }
  22. if (!layer)
  23. return;
  24. auto& layer_event = event.layer_event();
  25. auto& image_event = event.image_event();
  26. if (layer_event.button() != GUI::MouseButton::Primary)
  27. return;
  28. if (!layer->rect().contains(layer_event.position()) && !m_mouse_in_resize_corner)
  29. return;
  30. m_scaling = m_mouse_in_resize_corner;
  31. m_layer_being_moved = *layer;
  32. m_event_origin = image_event.position();
  33. m_layer_origin = layer->location();
  34. }
  35. void MoveTool::on_mousemove(Layer* layer, MouseEvent& event)
  36. {
  37. if (m_editor->is_panning()) {
  38. m_editor->pan_to(event.raw_event().position());
  39. return;
  40. }
  41. if (!layer)
  42. return;
  43. constexpr int sensitivity = 20;
  44. Gfx::IntPoint grab_rect_position = Gfx::IntPoint(layer->location().x() + layer->size().width() - sensitivity / 2, layer->location().y() + layer->size().height() - sensitivity / 2);
  45. Gfx::IntRect grab_rect = Gfx::IntRect(grab_rect_position, Gfx::IntSize(sensitivity, sensitivity));
  46. auto updated_is_in_lower_right_corner = grab_rect.contains(event.image_event().position()); // check if the mouse is in the lower right corner
  47. if (m_mouse_in_resize_corner != updated_is_in_lower_right_corner) {
  48. m_mouse_in_resize_corner = updated_is_in_lower_right_corner;
  49. m_editor->update_tool_cursor();
  50. }
  51. if (m_scaling) {
  52. auto& cursor_location = event.image_event().position();
  53. auto width = abs(m_layer_being_moved->location().x() - cursor_location.x());
  54. auto height = abs(m_layer_being_moved->location().y() - cursor_location.y());
  55. if (m_keep_ascept_ratio) {
  56. if (abs(width - m_layer_being_moved->size().width()) > abs(height - m_layer_being_moved->size().height())) {
  57. height = width * m_layer_being_moved->size().height() / m_layer_being_moved->size().width();
  58. } else {
  59. width = height * m_layer_being_moved->size().width() / m_layer_being_moved->size().height();
  60. }
  61. }
  62. m_new_layer_size = Gfx::IntSize(width, height);
  63. // TODO: Change this according to which direction the user is scaling
  64. m_new_scaled_layer_location = Gfx::IntPoint(m_layer_being_moved->location().x(), m_layer_being_moved->location().y());
  65. }
  66. auto& image_event = event.image_event();
  67. if (!m_layer_being_moved || m_scaling)
  68. return;
  69. auto delta = image_event.position() - m_event_origin;
  70. m_layer_being_moved->set_location(m_layer_origin.translated(delta));
  71. m_editor->layers_did_change();
  72. }
  73. void MoveTool::on_mouseup(Layer* layer, MouseEvent& event)
  74. {
  75. if (event.image_event().button() == GUI::MouseButton::Secondary) {
  76. m_editor->stop_panning();
  77. m_editor->set_override_cursor(cursor());
  78. return;
  79. }
  80. if (!layer)
  81. return;
  82. auto& layer_event = event.layer_event();
  83. if (layer_event.button() != GUI::MouseButton::Primary)
  84. return;
  85. if (m_scaling) {
  86. m_editor->active_layer()->resize(m_new_layer_size, m_new_scaled_layer_location, Gfx::Painter::ScalingMode::BilinearBlend);
  87. }
  88. m_scaling = false;
  89. m_layer_being_moved = nullptr;
  90. m_editor->update_tool_cursor();
  91. m_editor->did_complete_action(tool_name());
  92. }
  93. void MoveTool::on_keydown(GUI::KeyEvent& event)
  94. {
  95. if (event.key() == Key_Shift)
  96. m_keep_ascept_ratio = true;
  97. if (m_scaling)
  98. return;
  99. if (event.modifiers() != 0)
  100. return;
  101. auto* layer = m_editor->active_layer();
  102. if (!layer)
  103. return;
  104. auto new_location = layer->location();
  105. switch (event.key()) {
  106. case Key_Up:
  107. new_location.translate_by(0, -1);
  108. break;
  109. case Key_Down:
  110. new_location.translate_by(0, 1);
  111. break;
  112. case Key_Left:
  113. new_location.translate_by(-1, 0);
  114. break;
  115. case Key_Right:
  116. new_location.translate_by(1, 0);
  117. break;
  118. default:
  119. return;
  120. }
  121. layer->set_location(new_location);
  122. m_editor->layers_did_change();
  123. }
  124. void MoveTool::on_keyup(GUI::KeyEvent& event)
  125. {
  126. if (event.key() == Key_Shift)
  127. m_keep_ascept_ratio = false;
  128. }
  129. Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> MoveTool::cursor()
  130. {
  131. if (m_mouse_in_resize_corner || m_scaling)
  132. return Gfx::StandardCursor::ResizeDiagonalTLBR;
  133. return Gfx::StandardCursor::Move;
  134. }
  135. }