The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

512 lines
14KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. RectangleList::RectangleList() noexcept
  18. {
  19. }
  20. RectangleList::RectangleList (const Rectangle<int>& rect)
  21. {
  22. addWithoutMerging (rect);
  23. }
  24. RectangleList::RectangleList (const RectangleList& other)
  25. : rects (other.rects)
  26. {
  27. }
  28. RectangleList& RectangleList::operator= (const RectangleList& other)
  29. {
  30. rects = other.rects;
  31. return *this;
  32. }
  33. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  34. RectangleList::RectangleList (RectangleList&& other) noexcept
  35. : rects (static_cast <Array <Rectangle<int> >&&> (other.rects))
  36. {
  37. }
  38. RectangleList& RectangleList::operator= (RectangleList&& other) noexcept
  39. {
  40. rects = static_cast <Array <Rectangle<int> >&&> (other.rects);
  41. return *this;
  42. }
  43. #endif
  44. RectangleList::~RectangleList()
  45. {
  46. }
  47. //==============================================================================
  48. void RectangleList::clear()
  49. {
  50. rects.clearQuick();
  51. }
  52. Rectangle<int> RectangleList::getRectangle (const int index) const noexcept
  53. {
  54. if (isPositiveAndBelow (index, rects.size()))
  55. return rects.getReference (index);
  56. return Rectangle<int>();
  57. }
  58. bool RectangleList::isEmpty() const noexcept
  59. {
  60. return rects.size() == 0;
  61. }
  62. //==============================================================================
  63. RectangleList::Iterator::Iterator (const RectangleList& list) noexcept
  64. : current (nullptr),
  65. owner (list),
  66. index (list.rects.size())
  67. {
  68. }
  69. RectangleList::Iterator::~Iterator()
  70. {
  71. }
  72. bool RectangleList::Iterator::next() noexcept
  73. {
  74. if (--index >= 0)
  75. {
  76. current = &(owner.rects.getReference (index));
  77. return true;
  78. }
  79. return false;
  80. }
  81. //==============================================================================
  82. void RectangleList::add (const Rectangle<int>& rect)
  83. {
  84. if (! rect.isEmpty())
  85. {
  86. if (rects.size() == 0)
  87. {
  88. rects.add (rect);
  89. }
  90. else
  91. {
  92. bool anyOverlaps = false;
  93. for (int j = rects.size(); --j >= 0;)
  94. {
  95. Rectangle<int>& ourRect = rects.getReference (j);
  96. if (rect.intersects (ourRect))
  97. {
  98. if (rect.contains (ourRect))
  99. rects.remove (j);
  100. else if (! ourRect.reduceIfPartlyContainedIn (rect))
  101. anyOverlaps = true;
  102. }
  103. }
  104. if (anyOverlaps && rects.size() > 0)
  105. {
  106. RectangleList r (rect);
  107. for (int i = rects.size(); --i >= 0;)
  108. {
  109. const Rectangle<int>& ourRect = rects.getReference (i);
  110. if (rect.intersects (ourRect))
  111. {
  112. r.subtract (ourRect);
  113. if (r.rects.size() == 0)
  114. return;
  115. }
  116. }
  117. rects.addArray (r.rects);
  118. }
  119. else
  120. {
  121. rects.add (rect);
  122. }
  123. }
  124. }
  125. }
  126. void RectangleList::addWithoutMerging (const Rectangle<int>& rect)
  127. {
  128. if (! rect.isEmpty())
  129. rects.add (rect);
  130. }
  131. void RectangleList::add (const int x, const int y, const int w, const int h)
  132. {
  133. add (Rectangle<int> (x, y, w, h));
  134. }
  135. void RectangleList::add (const RectangleList& other)
  136. {
  137. for (const Rectangle<int>* r = other.begin(), * const e = other.end(); r != e; ++r)
  138. add (*r);
  139. }
  140. void RectangleList::subtract (const Rectangle<int>& rect)
  141. {
  142. const int originalNumRects = rects.size();
  143. if (originalNumRects > 0)
  144. {
  145. const int x1 = rect.pos.x;
  146. const int y1 = rect.pos.y;
  147. const int x2 = x1 + rect.w;
  148. const int y2 = y1 + rect.h;
  149. for (int i = getNumRectangles(); --i >= 0;)
  150. {
  151. Rectangle<int>& r = rects.getReference (i);
  152. const int rx1 = r.pos.x;
  153. const int ry1 = r.pos.y;
  154. const int rx2 = rx1 + r.w;
  155. const int ry2 = ry1 + r.h;
  156. if (! (x2 <= rx1 || x1 >= rx2 || y2 <= ry1 || y1 >= ry2))
  157. {
  158. if (x1 > rx1 && x1 < rx2)
  159. {
  160. if (y1 <= ry1 && y2 >= ry2 && x2 >= rx2)
  161. {
  162. r.w = x1 - rx1;
  163. }
  164. else
  165. {
  166. r.pos.x = x1;
  167. r.w = rx2 - x1;
  168. rects.insert (++i, Rectangle<int> (rx1, ry1, x1 - rx1, ry2 - ry1));
  169. ++i;
  170. }
  171. }
  172. else if (x2 > rx1 && x2 < rx2)
  173. {
  174. r.pos.x = x2;
  175. r.w = rx2 - x2;
  176. if (y1 > ry1 || y2 < ry2 || x1 > rx1)
  177. {
  178. rects.insert (++i, Rectangle<int> (rx1, ry1, x2 - rx1, ry2 - ry1));
  179. ++i;
  180. }
  181. }
  182. else if (y1 > ry1 && y1 < ry2)
  183. {
  184. if (x1 <= rx1 && x2 >= rx2 && y2 >= ry2)
  185. {
  186. r.h = y1 - ry1;
  187. }
  188. else
  189. {
  190. r.pos.y = y1;
  191. r.h = ry2 - y1;
  192. rects.insert (++i, Rectangle<int> (rx1, ry1, rx2 - rx1, y1 - ry1));
  193. ++i;
  194. }
  195. }
  196. else if (y2 > ry1 && y2 < ry2)
  197. {
  198. r.pos.y = y2;
  199. r.h = ry2 - y2;
  200. if (x1 > rx1 || x2 < rx2 || y1 > ry1)
  201. {
  202. rects.insert (++i, Rectangle<int> (rx1, ry1, rx2 - rx1, y2 - ry1));
  203. ++i;
  204. }
  205. }
  206. else
  207. {
  208. rects.remove (i);
  209. }
  210. }
  211. }
  212. }
  213. }
  214. bool RectangleList::subtract (const RectangleList& otherList)
  215. {
  216. for (int i = otherList.rects.size(); --i >= 0 && rects.size() > 0;)
  217. subtract (otherList.rects.getReference (i));
  218. return rects.size() > 0;
  219. }
  220. bool RectangleList::clipTo (const Rectangle<int>& rect)
  221. {
  222. bool notEmpty = false;
  223. if (rect.isEmpty())
  224. {
  225. clear();
  226. }
  227. else
  228. {
  229. for (int i = rects.size(); --i >= 0;)
  230. {
  231. Rectangle<int>& r = rects.getReference (i);
  232. if (! rect.intersectRectangle (r.pos.x, r.pos.y, r.w, r.h))
  233. rects.remove (i);
  234. else
  235. notEmpty = true;
  236. }
  237. }
  238. return notEmpty;
  239. }
  240. bool RectangleList::clipTo (const RectangleList& other)
  241. {
  242. if (rects.size() == 0)
  243. return false;
  244. RectangleList result;
  245. for (int j = 0; j < rects.size(); ++j)
  246. {
  247. const Rectangle<int>& rect = rects.getReference (j);
  248. for (int i = other.rects.size(); --i >= 0;)
  249. {
  250. Rectangle<int> r (other.rects.getReference (i));
  251. if (rect.intersectRectangle (r.pos.x, r.pos.y, r.w, r.h))
  252. result.rects.add (r);
  253. }
  254. }
  255. swapWith (result);
  256. return ! isEmpty();
  257. }
  258. bool RectangleList::getIntersectionWith (const Rectangle<int>& rect, RectangleList& destRegion) const
  259. {
  260. destRegion.clear();
  261. if (! rect.isEmpty())
  262. {
  263. for (int i = rects.size(); --i >= 0;)
  264. {
  265. Rectangle<int> r (rects.getReference (i));
  266. if (rect.intersectRectangle (r.pos.x, r.pos.y, r.w, r.h))
  267. destRegion.rects.add (r);
  268. }
  269. }
  270. return destRegion.rects.size() > 0;
  271. }
  272. void RectangleList::swapWith (RectangleList& otherList) noexcept
  273. {
  274. rects.swapWith (otherList.rects);
  275. }
  276. //==============================================================================
  277. void RectangleList::consolidate()
  278. {
  279. for (int i = 0; i < getNumRectangles() - 1; ++i)
  280. {
  281. Rectangle<int>& r = rects.getReference (i);
  282. const int rx1 = r.pos.x;
  283. const int ry1 = r.pos.y;
  284. const int rx2 = rx1 + r.w;
  285. const int ry2 = ry1 + r.h;
  286. for (int j = rects.size(); --j > i;)
  287. {
  288. Rectangle<int>& r2 = rects.getReference (j);
  289. const int jrx1 = r2.pos.x;
  290. const int jry1 = r2.pos.y;
  291. const int jrx2 = jrx1 + r2.w;
  292. const int jry2 = jry1 + r2.h;
  293. // if the vertical edges of any blocks are touching and their horizontals don't
  294. // line up, split them horizontally..
  295. if (jrx1 == rx2 || jrx2 == rx1)
  296. {
  297. if (jry1 > ry1 && jry1 < ry2)
  298. {
  299. r.h = jry1 - ry1;
  300. rects.add (Rectangle<int> (rx1, jry1, rx2 - rx1, ry2 - jry1));
  301. i = -1;
  302. break;
  303. }
  304. if (jry2 > ry1 && jry2 < ry2)
  305. {
  306. r.h = jry2 - ry1;
  307. rects.add (Rectangle<int> (rx1, jry2, rx2 - rx1, ry2 - jry2));
  308. i = -1;
  309. break;
  310. }
  311. else if (ry1 > jry1 && ry1 < jry2)
  312. {
  313. r2.h = ry1 - jry1;
  314. rects.add (Rectangle<int> (jrx1, ry1, jrx2 - jrx1, jry2 - ry1));
  315. i = -1;
  316. break;
  317. }
  318. else if (ry2 > jry1 && ry2 < jry2)
  319. {
  320. r2.h = ry2 - jry1;
  321. rects.add (Rectangle<int> (jrx1, ry2, jrx2 - jrx1, jry2 - ry2));
  322. i = -1;
  323. break;
  324. }
  325. }
  326. }
  327. }
  328. for (int i = 0; i < rects.size() - 1; ++i)
  329. {
  330. Rectangle<int>& r = rects.getReference (i);
  331. for (int j = rects.size(); --j > i;)
  332. {
  333. if (r.enlargeIfAdjacent (rects.getReference (j)))
  334. {
  335. rects.remove (j);
  336. i = -1;
  337. break;
  338. }
  339. }
  340. }
  341. }
  342. //==============================================================================
  343. bool RectangleList::containsPoint (const int x, const int y) const noexcept
  344. {
  345. for (const Rectangle<int>* r = rects.begin(), * const e = rects.end(); r != e; ++r)
  346. if (r->contains (x, y))
  347. return true;
  348. return false;
  349. }
  350. bool RectangleList::containsRectangle (const Rectangle<int>& rectangleToCheck) const
  351. {
  352. if (rects.size() > 1)
  353. {
  354. RectangleList r (rectangleToCheck);
  355. for (int i = rects.size(); --i >= 0;)
  356. {
  357. r.subtract (rects.getReference (i));
  358. if (r.rects.size() == 0)
  359. return true;
  360. }
  361. }
  362. else if (rects.size() > 0)
  363. {
  364. return rects.getReference (0).contains (rectangleToCheck);
  365. }
  366. return false;
  367. }
  368. bool RectangleList::intersectsRectangle (const Rectangle<int>& rectangleToCheck) const noexcept
  369. {
  370. for (const Rectangle<int>* r = rects.begin(), * const e = rects.end(); r != e; ++r)
  371. if (r->intersects (rectangleToCheck))
  372. return true;
  373. return false;
  374. }
  375. bool RectangleList::intersects (const RectangleList& other) const noexcept
  376. {
  377. for (const Rectangle<int>* r = rects.begin(), * const e = rects.end(); r != e; ++r)
  378. if (other.intersectsRectangle (*r))
  379. return true;
  380. return false;
  381. }
  382. Rectangle<int> RectangleList::getBounds() const noexcept
  383. {
  384. if (rects.size() <= 1)
  385. {
  386. if (rects.size() == 0)
  387. return Rectangle<int>();
  388. return rects.getReference (0);
  389. }
  390. else
  391. {
  392. const Rectangle<int>& r = rects.getReference (0);
  393. int minX = r.pos.x;
  394. int minY = r.pos.y;
  395. int maxX = minX + r.w;
  396. int maxY = minY + r.h;
  397. for (int i = rects.size(); --i > 0;)
  398. {
  399. const Rectangle<int>& r2 = rects.getReference (i);
  400. minX = jmin (minX, r2.pos.x);
  401. minY = jmin (minY, r2.pos.y);
  402. maxX = jmax (maxX, r2.getRight());
  403. maxY = jmax (maxY, r2.getBottom());
  404. }
  405. return Rectangle<int> (minX, minY, maxX - minX, maxY - minY);
  406. }
  407. }
  408. void RectangleList::offsetAll (const int dx, const int dy) noexcept
  409. {
  410. for (Rectangle<int>* r = rects.begin(), * const e = rects.end(); r != e; ++r)
  411. {
  412. r->pos.x += dx;
  413. r->pos.y += dy;
  414. }
  415. }
  416. //==============================================================================
  417. Path RectangleList::toPath() const
  418. {
  419. Path p;
  420. for (int i = 0; i < rects.size(); ++i)
  421. p.addRectangle (rects.getReference (i));
  422. return p;
  423. }