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.

522 lines
14KB

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