LayerListWidget.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Mustafa Quraish <mustafa@cs.toronto.edu>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "LayerListWidget.h"
  8. #include "Image.h"
  9. #include "ImageEditor.h"
  10. #include "Layer.h"
  11. #include <LibGUI/Painter.h>
  12. #include <LibGfx/Palette.h>
  13. REGISTER_WIDGET(PixelPaint, LayerListWidget);
  14. namespace PixelPaint {
  15. LayerListWidget::LayerListWidget()
  16. {
  17. set_should_hide_unnecessary_scrollbars(false);
  18. horizontal_scrollbar().set_visible(false);
  19. }
  20. LayerListWidget::~LayerListWidget()
  21. {
  22. if (m_image)
  23. m_image->remove_client(*this);
  24. }
  25. size_t LayerListWidget::to_gadget_index(size_t layer_index) const
  26. {
  27. return m_image->layer_count() - layer_index - 1;
  28. }
  29. size_t LayerListWidget::to_layer_index(size_t gadget_index) const
  30. {
  31. return m_image->layer_count() - gadget_index - 1;
  32. }
  33. void LayerListWidget::set_image(Image* image)
  34. {
  35. if (m_image == image)
  36. return;
  37. if (m_image)
  38. m_image->remove_client(*this);
  39. m_image = image;
  40. if (m_image)
  41. m_image->add_client(*this);
  42. rebuild_gadgets();
  43. }
  44. void LayerListWidget::rebuild_gadgets()
  45. {
  46. m_gadgets.clear();
  47. if (m_image) {
  48. for (int layer_index = m_image->layer_count() - 1; layer_index >= 0; --layer_index) {
  49. m_gadgets.append({ static_cast<size_t>(layer_index), {}, false, {} });
  50. }
  51. }
  52. relayout_gadgets();
  53. }
  54. void LayerListWidget::resize_event(GUI::ResizeEvent& event)
  55. {
  56. AbstractScrollableWidget::resize_event(event);
  57. relayout_gadgets();
  58. }
  59. void LayerListWidget::get_gadget_rects(Gadget const& gadget, Gfx::IntRect& outer_rect, Gfx::IntRect& thumbnail_rect, Gfx::IntRect& text_rect)
  60. {
  61. outer_rect = gadget.rect;
  62. outer_rect.translate_by(0, -vertical_scrollbar().value());
  63. outer_rect.translate_by(frame_thickness(), frame_thickness());
  64. if (gadget.is_moving) {
  65. outer_rect.translate_by(0, gadget.movement_delta.y());
  66. }
  67. thumbnail_rect = { outer_rect.x(), outer_rect.y(), outer_rect.height(), outer_rect.height() };
  68. thumbnail_rect.shrink(8, 8);
  69. text_rect = { thumbnail_rect.right() + 10, outer_rect.y(), outer_rect.width(), outer_rect.height() };
  70. text_rect.intersect(outer_rect);
  71. }
  72. void LayerListWidget::paint_event(GUI::PaintEvent& event)
  73. {
  74. GUI::Painter painter(*this);
  75. painter.add_clip_rect(event.rect());
  76. painter.fill_rect(event.rect(), palette().button());
  77. if (!m_image)
  78. return;
  79. painter.fill_rect(event.rect(), palette().button());
  80. auto paint_gadget = [&](auto& gadget) {
  81. auto& layer = m_image->layer(gadget.layer_index);
  82. Gfx::IntRect adjusted_rect;
  83. Gfx::IntRect thumbnail_rect;
  84. Gfx::IntRect text_rect;
  85. get_gadget_rects(gadget, adjusted_rect, thumbnail_rect, text_rect);
  86. if (gadget.is_moving) {
  87. painter.fill_rect(adjusted_rect, palette().selection().lightened(1.5f));
  88. } else if (layer.is_selected()) {
  89. painter.fill_rect(adjusted_rect, palette().selection());
  90. }
  91. painter.draw_rect(adjusted_rect, palette().color(ColorRole::BaseText));
  92. painter.draw_scaled_bitmap(thumbnail_rect, layer.bitmap(), layer.bitmap().rect());
  93. if (layer.is_visible()) {
  94. painter.draw_text(text_rect, layer.name(), Gfx::TextAlignment::CenterLeft, layer.is_selected() ? palette().selection_text() : palette().button_text());
  95. painter.draw_rect(thumbnail_rect, palette().color(ColorRole::BaseText));
  96. } else {
  97. painter.draw_text(text_rect, layer.name(), Gfx::TextAlignment::CenterLeft, palette().color(ColorRole::DisabledText));
  98. painter.draw_rect(thumbnail_rect, palette().color(ColorRole::DisabledText));
  99. }
  100. };
  101. for (auto& gadget : m_gadgets) {
  102. if (!gadget.is_moving)
  103. paint_gadget(gadget);
  104. }
  105. if (m_moving_gadget_index.has_value())
  106. paint_gadget(m_gadgets[m_moving_gadget_index.value()]);
  107. Gfx::StylePainter::paint_frame(painter, rect(), palette(), Gfx::FrameShape::Box, Gfx::FrameShadow::Sunken, 2);
  108. }
  109. Optional<size_t> LayerListWidget::gadget_at(Gfx::IntPoint const& position)
  110. {
  111. for (size_t i = 0; i < m_gadgets.size(); ++i) {
  112. if (m_gadgets[i].rect.contains(position))
  113. return i;
  114. }
  115. return {};
  116. }
  117. void LayerListWidget::mousedown_event(GUI::MouseEvent& event)
  118. {
  119. if (!m_image)
  120. return;
  121. if (event.button() != GUI::MouseButton::Left)
  122. return;
  123. Gfx::IntPoint translated_event_point = { 0, vertical_scrollbar().value() + event.y() };
  124. auto maybe_gadget_index = gadget_at(translated_event_point);
  125. if (!maybe_gadget_index.has_value())
  126. return;
  127. auto gadget_index = maybe_gadget_index.value();
  128. m_moving_gadget_index = gadget_index;
  129. m_selected_gadget_index = gadget_index;
  130. m_moving_event_origin = translated_event_point;
  131. auto& gadget = m_gadgets[m_moving_gadget_index.value()];
  132. auto& layer = m_image->layer(to_layer_index(gadget_index));
  133. set_selected_layer(&layer);
  134. gadget.is_moving = true;
  135. gadget.movement_delta = {};
  136. update();
  137. }
  138. void LayerListWidget::mousemove_event(GUI::MouseEvent& event)
  139. {
  140. if (!m_image)
  141. return;
  142. if (!m_moving_gadget_index.has_value())
  143. return;
  144. Gfx::IntPoint translated_event_point = { 0, vertical_scrollbar().value() + event.y() };
  145. auto delta = translated_event_point - m_moving_event_origin;
  146. auto& gadget = m_gadgets[m_moving_gadget_index.value()];
  147. VERIFY(gadget.is_moving);
  148. gadget.movement_delta = delta;
  149. auto adjusted_rect = gadget.rect;
  150. adjusted_rect.translate_by(gadget.movement_delta);
  151. scroll_into_view(adjusted_rect, false, true);
  152. relayout_gadgets();
  153. }
  154. void LayerListWidget::mouseup_event(GUI::MouseEvent& event)
  155. {
  156. if (!m_image)
  157. return;
  158. if (event.button() != GUI::MouseButton::Left)
  159. return;
  160. if (!m_moving_gadget_index.has_value())
  161. return;
  162. size_t old_index = m_moving_gadget_index.value();
  163. size_t new_index = hole_index_during_move();
  164. if (new_index >= m_image->layer_count())
  165. new_index = m_image->layer_count() - 1;
  166. m_moving_gadget_index = {};
  167. auto old_layer_index = to_layer_index(old_index);
  168. auto new_layer_index = to_layer_index(new_index);
  169. m_image->change_layer_index(old_layer_index, new_layer_index);
  170. }
  171. void LayerListWidget::context_menu_event(GUI::ContextMenuEvent& event)
  172. {
  173. Gfx::IntPoint translated_event_point = { 0, vertical_scrollbar().value() + event.position().y() };
  174. auto gadget_index = gadget_at(translated_event_point);
  175. if (gadget_index.has_value()) {
  176. m_selected_gadget_index = gadget_index.value();
  177. auto& layer = m_image->layer(to_layer_index(m_selected_gadget_index));
  178. set_selected_layer(&layer);
  179. }
  180. if (on_context_menu_request)
  181. on_context_menu_request(event);
  182. }
  183. void LayerListWidget::image_did_add_layer(size_t layer_index)
  184. {
  185. if (m_moving_gadget_index.has_value()) {
  186. m_gadgets[m_moving_gadget_index.value()].is_moving = false;
  187. m_moving_gadget_index = {};
  188. }
  189. auto gadget_index = to_gadget_index(layer_index);
  190. Gadget gadget { gadget_index, {}, false, {} };
  191. m_gadgets.insert(gadget_index, gadget);
  192. relayout_gadgets();
  193. }
  194. void LayerListWidget::image_did_remove_layer(size_t layer_index)
  195. {
  196. if (m_moving_gadget_index.has_value()) {
  197. m_gadgets[m_moving_gadget_index.value()].is_moving = false;
  198. m_moving_gadget_index = {};
  199. }
  200. // No -1 here since a layer has already been removed.
  201. auto gadget_index = m_image->layer_count() - layer_index;
  202. m_gadgets.remove(gadget_index);
  203. m_selected_gadget_index = to_gadget_index(0);
  204. relayout_gadgets();
  205. }
  206. void LayerListWidget::image_did_modify_layer_properties(size_t layer_index)
  207. {
  208. update(m_gadgets[to_gadget_index(layer_index)].rect);
  209. }
  210. void LayerListWidget::image_did_modify_layer_bitmap(size_t layer_index)
  211. {
  212. Gfx::IntRect adjusted_rect;
  213. Gfx::IntRect thumbnail_rect;
  214. Gfx::IntRect text_rect;
  215. get_gadget_rects(m_gadgets[to_gadget_index(layer_index)], adjusted_rect, thumbnail_rect, text_rect);
  216. update(thumbnail_rect);
  217. }
  218. void LayerListWidget::image_did_modify_layer_stack()
  219. {
  220. rebuild_gadgets();
  221. }
  222. static constexpr int gadget_height = 40;
  223. static constexpr int gadget_spacing = -1;
  224. static constexpr int vertical_step = gadget_height + gadget_spacing;
  225. size_t LayerListWidget::hole_index_during_move() const
  226. {
  227. VERIFY(is_moving_gadget());
  228. auto& moving_gadget = m_gadgets[m_moving_gadget_index.value()];
  229. int center_y_of_moving_gadget = moving_gadget.rect.translated(0, moving_gadget.movement_delta.y()).center().y();
  230. int top_of_gadgets = max(0, height() - m_total_gadget_height);
  231. return (center_y_of_moving_gadget - top_of_gadgets) / vertical_step;
  232. }
  233. void LayerListWidget::select_bottom_layer()
  234. {
  235. if (!m_image || !m_image->layer_count())
  236. return;
  237. m_selected_gadget_index = to_gadget_index(0);
  238. set_selected_layer(&m_image->layer(0));
  239. }
  240. void LayerListWidget::select_top_layer()
  241. {
  242. if (!m_image || !m_image->layer_count())
  243. return;
  244. m_selected_gadget_index = 0;
  245. set_selected_layer(&m_image->layer(to_layer_index(0)));
  246. }
  247. void LayerListWidget::cycle_through_selection(int delta)
  248. {
  249. if (!m_image || !m_image->layer_count())
  250. return;
  251. auto current_index = static_cast<int>(m_selected_gadget_index);
  252. current_index += delta;
  253. if (current_index < 0)
  254. current_index = m_gadgets.size() - 1;
  255. if (current_index > static_cast<int>(m_gadgets.size()) - 1)
  256. current_index = 0;
  257. m_selected_gadget_index = current_index;
  258. auto selected_layer_index = to_layer_index(m_selected_gadget_index);
  259. set_selected_layer(&m_image->layer(selected_layer_index));
  260. }
  261. void LayerListWidget::relayout_gadgets()
  262. {
  263. m_total_gadget_height = static_cast<int>(m_gadgets.size()) * vertical_step + 6;
  264. int y = max(0, height() - m_total_gadget_height);
  265. Optional<size_t> hole_index;
  266. if (is_moving_gadget())
  267. hole_index = hole_index_during_move();
  268. size_t index = 0;
  269. for (auto& gadget : m_gadgets) {
  270. if (gadget.is_moving)
  271. continue;
  272. if (index == hole_index)
  273. y += vertical_step;
  274. gadget.rect = { 0, y, widget_inner_rect().width(), gadget_height };
  275. y += vertical_step;
  276. ++index;
  277. }
  278. set_content_size({ widget_inner_rect().width(), m_total_gadget_height });
  279. vertical_scrollbar().set_range(0, max(m_total_gadget_height - height(), 0));
  280. update();
  281. }
  282. void LayerListWidget::set_selected_layer(Layer* layer)
  283. {
  284. if (!m_image)
  285. return;
  286. for (size_t i = 0; i < m_image->layer_count(); ++i) {
  287. if (layer == &m_image->layer(i)) {
  288. m_image->layer(i).set_selected(true);
  289. m_selected_gadget_index = to_gadget_index(i);
  290. scroll_into_view(m_gadgets[m_selected_gadget_index].rect, false, true);
  291. } else {
  292. m_image->layer(i).set_selected(false);
  293. }
  294. }
  295. if (on_layer_select)
  296. on_layer_select(layer);
  297. update();
  298. }
  299. }