1 | // Aseprite UI Library |
2 | // Copyright (C) 2018-2021 Igara Studio S.A. |
3 | // Copyright (C) 2001-2018 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "ui/manager.h" |
13 | |
14 | #include "os/surface.h" |
15 | #include "os/system.h" |
16 | #include "os/window.h" |
17 | #include "ui/overlay_manager.h" |
18 | |
19 | #include <vector> |
20 | |
21 | namespace ui { |
22 | |
23 | using namespace gfx; |
24 | |
25 | void move_region(Display* display, const Region& region, int dx, int dy) |
26 | { |
27 | ASSERT(display); |
28 | if (!display) |
29 | return; |
30 | |
31 | os::Window* window = display->nativeWindow(); |
32 | ASSERT(window); |
33 | if (!window) |
34 | return; |
35 | |
36 | auto overlays = ui::OverlayManager::instance(); |
37 | gfx::Rect bounds = region.bounds(); |
38 | bounds |= gfx::Rect(bounds).offset(dx, dy); |
39 | overlays->restoreOverlappedAreas(bounds); |
40 | |
41 | os::Surface* surface = window->surface(); |
42 | os::SurfaceLock lock(surface); |
43 | |
44 | // Fast path, move one rectangle. |
45 | if (region.isRect()) { |
46 | gfx::Rect rc = region.bounds(); |
47 | surface->scrollTo(rc, dx, dy); |
48 | |
49 | rc.offset(dx, dy); |
50 | display->dirtyRect(rc); |
51 | } |
52 | // As rectangles in the region internals are separated by bands |
53 | // through the y-axis, we can sort the rectangles by y-axis and then |
54 | // by x-axis to move rectangle by rectangle depending on the dx/dy |
55 | // direction so we don't overlap each rectangle. |
56 | else if (region.isComplex()) { |
57 | std::size_t nrects = region.size(); |
58 | std::vector<gfx::Rect> rcs(nrects); |
59 | std::copy(region.begin(), region.end(), rcs.begin()); |
60 | |
61 | std::sort( |
62 | rcs.begin(), rcs.end(), |
63 | [dx, dy](const gfx::Rect& a, const gfx::Rect& b){ |
64 | if (dy < 0) { |
65 | if (a.y < b.y) |
66 | return true; |
67 | else if (a.y == b.y) { |
68 | if (dx < 0) |
69 | return a.x < b.x; |
70 | else |
71 | return a.x > b.x; |
72 | } |
73 | else |
74 | return false; |
75 | } |
76 | else { |
77 | if (a.y > b.y) |
78 | return true; |
79 | else if (a.y == b.y) { |
80 | if (dx < 0) |
81 | return a.x < b.x; |
82 | else |
83 | return a.x > b.x; |
84 | } |
85 | else |
86 | return false; |
87 | } |
88 | }); |
89 | |
90 | for (gfx::Rect& rc : rcs) { |
91 | surface->scrollTo(rc, dx, dy); |
92 | |
93 | rc.offset(dx, dy); |
94 | display->dirtyRect(rc); |
95 | } |
96 | } |
97 | |
98 | overlays->drawOverlays(); |
99 | } |
100 | |
101 | } // namespace ui |
102 | |