DISTRHO Plugin Framework
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.

400 lines
10KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "../ImageSlider.hpp"
  17. #include <cmath>
  18. START_NAMESPACE_DGL
  19. // -----------------------------------------------------------------------
  20. ImageSlider::ImageSlider(Window& parent, const Image& image) noexcept
  21. : Widget(parent),
  22. fImage(image),
  23. fMinimum(0.0f),
  24. fMaximum(1.0f),
  25. fStep(0.0f),
  26. fValue(0.5f),
  27. fValueTmp(fValue),
  28. fDragging(false),
  29. fInverted(false),
  30. fStartedX(0),
  31. fStartedY(0),
  32. fCallback(nullptr),
  33. fStartPos(),
  34. fEndPos(),
  35. fSliderArea(),
  36. leakDetector_ImageSlider()
  37. {
  38. Widget::setNeedsFullViewport(true);
  39. }
  40. ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept
  41. : Widget(widget->getParentWindow()),
  42. fImage(image),
  43. fMinimum(0.0f),
  44. fMaximum(1.0f),
  45. fStep(0.0f),
  46. fValue(0.5f),
  47. fValueTmp(fValue),
  48. fDragging(false),
  49. fInverted(false),
  50. fStartedX(0),
  51. fStartedY(0),
  52. fCallback(nullptr),
  53. fStartPos(),
  54. fEndPos(),
  55. fSliderArea(),
  56. leakDetector_ImageSlider()
  57. {
  58. Widget::setNeedsFullViewport(true);
  59. }
  60. ImageSlider::ImageSlider(const ImageSlider& imageSlider) noexcept
  61. : Widget(imageSlider.getParentWindow()),
  62. fImage(imageSlider.fImage),
  63. fMinimum(imageSlider.fMinimum),
  64. fMaximum(imageSlider.fMaximum),
  65. fStep(imageSlider.fStep),
  66. fValue(imageSlider.fValue),
  67. fValueTmp(fValue),
  68. fDragging(false),
  69. fInverted(imageSlider.fInverted),
  70. fStartedX(0),
  71. fStartedY(0),
  72. fCallback(imageSlider.fCallback),
  73. fStartPos(imageSlider.fStartPos),
  74. fEndPos(imageSlider.fEndPos),
  75. fSliderArea(imageSlider.fSliderArea),
  76. leakDetector_ImageSlider()
  77. {
  78. Widget::setNeedsFullViewport(true);
  79. }
  80. ImageSlider& ImageSlider::operator=(const ImageSlider& imageSlider) noexcept
  81. {
  82. fImage = imageSlider.fImage;
  83. fMinimum = imageSlider.fMinimum;
  84. fMaximum = imageSlider.fMaximum;
  85. fStep = imageSlider.fStep;
  86. fValue = imageSlider.fValue;
  87. fValueTmp = fValue;
  88. fDragging = false;
  89. fInverted = imageSlider.fInverted;
  90. fStartedX = 0;
  91. fStartedY = 0;
  92. fCallback = imageSlider.fCallback;
  93. fStartPos = imageSlider.fStartPos;
  94. fEndPos = imageSlider.fEndPos;
  95. fSliderArea = imageSlider.fSliderArea;
  96. return *this;
  97. }
  98. float ImageSlider::getValue() const noexcept
  99. {
  100. return fValue;
  101. }
  102. void ImageSlider::setStartPos(const Point<int>& startPos) noexcept
  103. {
  104. fStartPos = startPos;
  105. _recheckArea();
  106. }
  107. void ImageSlider::setStartPos(int x, int y) noexcept
  108. {
  109. setStartPos(Point<int>(x, y));
  110. }
  111. void ImageSlider::setEndPos(const Point<int>& endPos) noexcept
  112. {
  113. fEndPos = endPos;
  114. _recheckArea();
  115. }
  116. void ImageSlider::setEndPos(int x, int y) noexcept
  117. {
  118. setEndPos(Point<int>(x, y));
  119. }
  120. void ImageSlider::setInverted(bool inverted) noexcept
  121. {
  122. if (fInverted == inverted)
  123. return;
  124. fInverted = inverted;
  125. repaint();
  126. }
  127. void ImageSlider::setRange(float min, float max) noexcept
  128. {
  129. if (fValue < min)
  130. {
  131. fValue = min;
  132. repaint();
  133. if (fCallback != nullptr)
  134. {
  135. try {
  136. fCallback->imageSliderValueChanged(this, fValue);
  137. } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min");
  138. }
  139. }
  140. else if (fValue > max)
  141. {
  142. fValue = max;
  143. repaint();
  144. if (fCallback != nullptr)
  145. {
  146. try {
  147. fCallback->imageSliderValueChanged(this, fValue);
  148. } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max");
  149. }
  150. }
  151. fMinimum = min;
  152. fMaximum = max;
  153. }
  154. void ImageSlider::setStep(float step) noexcept
  155. {
  156. fStep = step;
  157. }
  158. void ImageSlider::setValue(float value, bool sendCallback) noexcept
  159. {
  160. if (d_isEqual(fValue, value))
  161. return;
  162. fValue = value;
  163. if (d_isZero(fStep))
  164. fValueTmp = value;
  165. repaint();
  166. if (sendCallback && fCallback != nullptr)
  167. {
  168. try {
  169. fCallback->imageSliderValueChanged(this, fValue);
  170. } DISTRHO_SAFE_EXCEPTION("ImageSlider::setValue");
  171. }
  172. }
  173. void ImageSlider::setCallback(Callback* callback) noexcept
  174. {
  175. fCallback = callback;
  176. }
  177. void ImageSlider::onDisplay()
  178. {
  179. #if 0 // DEBUG, paints slider area
  180. glColor3f(0.4f, 0.5f, 0.1f);
  181. glRecti(fSliderArea.getX(), fSliderArea.getY(), fSliderArea.getX()+fSliderArea.getWidth(), fSliderArea.getY()+fSliderArea.getHeight());
  182. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  183. #endif
  184. const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum);
  185. int x, y;
  186. if (fStartPos.getY() == fEndPos.getY())
  187. {
  188. // horizontal
  189. if (fInverted)
  190. x = fEndPos.getX() - static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX()));
  191. else
  192. x = fStartPos.getX() + static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX()));
  193. y = fStartPos.getY();
  194. }
  195. else
  196. {
  197. // vertical
  198. x = fStartPos.getX();
  199. if (fInverted)
  200. y = fEndPos.getY() - static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY()));
  201. else
  202. y = fStartPos.getY() + static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY()));
  203. }
  204. fImage.drawAt(x, y);
  205. }
  206. bool ImageSlider::onMouse(const MouseEvent& ev)
  207. {
  208. if (ev.button != 1)
  209. return false;
  210. if (ev.press)
  211. {
  212. if (! fSliderArea.contains(ev.pos))
  213. return false;
  214. float vper;
  215. const int x = ev.pos.getX();
  216. const int y = ev.pos.getY();
  217. if (fStartPos.getY() == fEndPos.getY())
  218. {
  219. // horizontal
  220. vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth());
  221. }
  222. else
  223. {
  224. // vertical
  225. vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight());
  226. }
  227. float value;
  228. if (fInverted)
  229. value = fMaximum - vper * (fMaximum - fMinimum);
  230. else
  231. value = fMinimum + vper * (fMaximum - fMinimum);
  232. if (value < fMinimum)
  233. {
  234. fValueTmp = value = fMinimum;
  235. }
  236. else if (value > fMaximum)
  237. {
  238. fValueTmp = value = fMaximum;
  239. }
  240. else if (d_isNotZero(fStep))
  241. {
  242. fValueTmp = value;
  243. const float rest = std::fmod(value, fStep);
  244. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  245. }
  246. fDragging = true;
  247. fStartedX = x;
  248. fStartedY = y;
  249. if (fCallback != nullptr)
  250. fCallback->imageSliderDragStarted(this);
  251. setValue(value, true);
  252. return true;
  253. }
  254. else if (fDragging)
  255. {
  256. if (fCallback != nullptr)
  257. fCallback->imageSliderDragFinished(this);
  258. fDragging = false;
  259. return true;
  260. }
  261. return false;
  262. }
  263. bool ImageSlider::onMotion(const MotionEvent& ev)
  264. {
  265. if (! fDragging)
  266. return false;
  267. const bool horizontal = fStartPos.getY() == fEndPos.getY();
  268. const int x = ev.pos.getX();
  269. const int y = ev.pos.getY();
  270. if ((horizontal && fSliderArea.containsX(x)) || (fSliderArea.containsY(y) && ! horizontal))
  271. {
  272. float vper;
  273. if (horizontal)
  274. {
  275. // horizontal
  276. vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth());
  277. }
  278. else
  279. {
  280. // vertical
  281. vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight());
  282. }
  283. float value;
  284. if (fInverted)
  285. value = fMaximum - vper * (fMaximum - fMinimum);
  286. else
  287. value = fMinimum + vper * (fMaximum - fMinimum);
  288. if (value < fMinimum)
  289. {
  290. fValueTmp = value = fMinimum;
  291. }
  292. else if (value > fMaximum)
  293. {
  294. fValueTmp = value = fMaximum;
  295. }
  296. else if (d_isNotZero(fStep))
  297. {
  298. fValueTmp = value;
  299. const float rest = std::fmod(value, fStep);
  300. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  301. }
  302. setValue(value, true);
  303. }
  304. else if (horizontal)
  305. {
  306. if (x < fSliderArea.getX())
  307. setValue(fInverted ? fMaximum : fMinimum, true);
  308. else
  309. setValue(fInverted ? fMinimum : fMaximum, true);
  310. }
  311. else
  312. {
  313. if (y < fSliderArea.getY())
  314. setValue(fInverted ? fMaximum : fMinimum, true);
  315. else
  316. setValue(fInverted ? fMinimum : fMaximum, true);
  317. }
  318. return true;
  319. }
  320. void ImageSlider::_recheckArea() noexcept
  321. {
  322. if (fStartPos.getY() == fEndPos.getY())
  323. {
  324. // horizontal
  325. fSliderArea = Rectangle<int>(fStartPos.getX(),
  326. fStartPos.getY(),
  327. fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(),
  328. static_cast<int>(fImage.getHeight()));
  329. }
  330. else
  331. {
  332. // vertical
  333. fSliderArea = Rectangle<int>(fStartPos.getX(),
  334. fStartPos.getY(),
  335. static_cast<int>(fImage.getWidth()),
  336. fEndPos.getY() + static_cast<int>(fImage.getHeight()) - fStartPos.getY());
  337. }
  338. }
  339. // -----------------------------------------------------------------------
  340. END_NAMESPACE_DGL