Collection of DPF-based plugins for packaging
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.

1078 lines
27KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2016 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 "Common.hpp"
  17. #include "WidgetPrivateData.hpp"
  18. START_NAMESPACE_DGL
  19. // -----------------------------------------------------------------------
  20. ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image)
  21. : Window(parent.getApp(), parent),
  22. Widget((Window&)*this),
  23. fImgBackground(image)
  24. {
  25. Window::setResizable(false);
  26. Window::setSize(image.getSize());
  27. Window::setTitle("About");
  28. }
  29. ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image)
  30. : Window(widget->getParentApp(), widget->getParentWindow()),
  31. Widget((Window&)*this),
  32. fImgBackground(image)
  33. {
  34. Window::setResizable(false);
  35. Window::setSize(image.getSize());
  36. Window::setTitle("About");
  37. }
  38. void ImageAboutWindow::setImage(const Image& image)
  39. {
  40. if (fImgBackground == image)
  41. return;
  42. fImgBackground = image;
  43. Window::setSize(image.getSize());
  44. }
  45. void ImageAboutWindow::onDisplay()
  46. {
  47. fImgBackground.draw();
  48. }
  49. bool ImageAboutWindow::onKeyboard(const KeyboardEvent& ev)
  50. {
  51. if (ev.press && ev.key == kCharEscape)
  52. {
  53. Window::close();
  54. return true;
  55. }
  56. return false;
  57. }
  58. bool ImageAboutWindow::onMouse(const MouseEvent& ev)
  59. {
  60. if (ev.press)
  61. {
  62. Window::close();
  63. return true;
  64. }
  65. return false;
  66. }
  67. void ImageAboutWindow::onReshape(uint width, uint height)
  68. {
  69. Widget::setSize(width, height);
  70. Window::onReshape(width, height);
  71. }
  72. // -----------------------------------------------------------------------
  73. struct ImageButton::PrivateData {
  74. ButtonImpl impl;
  75. Image imageNormal;
  76. Image imageHover;
  77. Image imageDown;
  78. PrivateData(Widget* const s, const Image& normal, const Image& hover, const Image& down)
  79. : impl(s),
  80. imageNormal(normal),
  81. imageHover(hover),
  82. imageDown(down) {}
  83. DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData)
  84. };
  85. // -----------------------------------------------------------------------
  86. ImageButton::ImageButton(Window& parent, const Image& image)
  87. : Widget(parent),
  88. pData(new PrivateData(this, image, image, image))
  89. {
  90. setSize(image.getSize());
  91. }
  92. ImageButton::ImageButton(Window& parent, const Image& imageNormal, const Image& imageDown)
  93. : Widget(parent),
  94. pData(new PrivateData(this, imageNormal, imageNormal, imageDown))
  95. {
  96. DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageDown.getSize());
  97. setSize(imageNormal.getSize());
  98. }
  99. ImageButton::ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown)
  100. : Widget(parent),
  101. pData(new PrivateData(this, imageNormal, imageHover, imageDown))
  102. {
  103. DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageHover.getSize() && imageHover.getSize() == imageDown.getSize());
  104. setSize(imageNormal.getSize());
  105. }
  106. ImageButton::ImageButton(Widget* widget, const Image& image)
  107. : Widget(widget->getParentWindow()),
  108. pData(new PrivateData(this, image, image, image))
  109. {
  110. setSize(image.getSize());
  111. }
  112. ImageButton::ImageButton(Widget* widget, const Image& imageNormal, const Image& imageDown)
  113. : Widget(widget->getParentWindow()),
  114. pData(new PrivateData(this, imageNormal, imageNormal, imageDown))
  115. {
  116. DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageDown.getSize());
  117. setSize(imageNormal.getSize());
  118. }
  119. ImageButton::ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown)
  120. : Widget(widget->getParentWindow()),
  121. pData(new PrivateData(this, imageNormal, imageHover, imageDown))
  122. {
  123. DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageHover.getSize() && imageHover.getSize() == imageDown.getSize());
  124. setSize(imageNormal.getSize());
  125. }
  126. ImageButton::~ImageButton()
  127. {
  128. delete pData;
  129. }
  130. void ImageButton::setCallback(Callback* callback) noexcept
  131. {
  132. pData->impl.callback_img = callback;
  133. }
  134. void ImageButton::onDisplay()
  135. {
  136. switch (pData->impl.state)
  137. {
  138. case ButtonImpl::kStateDown:
  139. pData->imageDown.draw();
  140. break;
  141. case ButtonImpl::kStateHover:
  142. pData->imageHover.draw();
  143. break;
  144. default:
  145. pData->imageNormal.draw();
  146. break;
  147. }
  148. }
  149. bool ImageButton::onMouse(const MouseEvent& ev)
  150. {
  151. return pData->impl.onMouse(ev);
  152. }
  153. bool ImageButton::onMotion(const MotionEvent& ev)
  154. {
  155. return pData->impl.onMotion(ev);
  156. }
  157. // -----------------------------------------------------------------------
  158. ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation) noexcept
  159. : Widget(parent),
  160. fImage(image),
  161. fMinimum(0.0f),
  162. fMaximum(1.0f),
  163. fStep(0.0f),
  164. fValue(0.5f),
  165. fValueDef(fValue),
  166. fValueTmp(fValue),
  167. fUsingDefault(false),
  168. fUsingLog(false),
  169. fOrientation(orientation),
  170. fRotationAngle(0),
  171. fDragging(false),
  172. fLastX(0),
  173. fLastY(0),
  174. fCallback(nullptr),
  175. fIsImgVertical(image.getHeight() > image.getWidth()),
  176. fImgLayerWidth(fIsImgVertical ? image.getWidth() : image.getHeight()),
  177. fImgLayerHeight(fImgLayerWidth),
  178. fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerHeight : image.getWidth()/fImgLayerWidth),
  179. fIsReady(false),
  180. fTextureId(0)
  181. {
  182. glGenTextures(1, &fTextureId);
  183. setSize(fImgLayerWidth, fImgLayerHeight);
  184. }
  185. ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation) noexcept
  186. : Widget(widget->getParentWindow()),
  187. fImage(image),
  188. fMinimum(0.0f),
  189. fMaximum(1.0f),
  190. fStep(0.0f),
  191. fValue(0.5f),
  192. fValueDef(fValue),
  193. fValueTmp(fValue),
  194. fUsingDefault(false),
  195. fUsingLog(false),
  196. fOrientation(orientation),
  197. fRotationAngle(0),
  198. fDragging(false),
  199. fLastX(0),
  200. fLastY(0),
  201. fCallback(nullptr),
  202. fIsImgVertical(image.getHeight() > image.getWidth()),
  203. fImgLayerWidth(fIsImgVertical ? image.getWidth() : image.getHeight()),
  204. fImgLayerHeight(fImgLayerWidth),
  205. fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerHeight : image.getWidth()/fImgLayerWidth),
  206. fIsReady(false),
  207. fTextureId(0)
  208. {
  209. glGenTextures(1, &fTextureId);
  210. setSize(fImgLayerWidth, fImgLayerHeight);
  211. }
  212. ImageKnob::ImageKnob(const ImageKnob& imageKnob)
  213. : Widget(imageKnob.getParentWindow()),
  214. fImage(imageKnob.fImage),
  215. fMinimum(imageKnob.fMinimum),
  216. fMaximum(imageKnob.fMaximum),
  217. fStep(imageKnob.fStep),
  218. fValue(imageKnob.fValue),
  219. fValueDef(imageKnob.fValueDef),
  220. fValueTmp(fValue),
  221. fUsingDefault(imageKnob.fUsingDefault),
  222. fUsingLog(imageKnob.fUsingLog),
  223. fOrientation(imageKnob.fOrientation),
  224. fRotationAngle(imageKnob.fRotationAngle),
  225. fDragging(false),
  226. fLastX(0),
  227. fLastY(0),
  228. fCallback(imageKnob.fCallback),
  229. fIsImgVertical(imageKnob.fIsImgVertical),
  230. fImgLayerWidth(imageKnob.fImgLayerWidth),
  231. fImgLayerHeight(imageKnob.fImgLayerHeight),
  232. fImgLayerCount(imageKnob.fImgLayerCount),
  233. fIsReady(false),
  234. fTextureId(0)
  235. {
  236. glGenTextures(1, &fTextureId);
  237. setSize(fImgLayerWidth, fImgLayerHeight);
  238. }
  239. ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob)
  240. {
  241. fImage = imageKnob.fImage;
  242. fMinimum = imageKnob.fMinimum;
  243. fMaximum = imageKnob.fMaximum;
  244. fStep = imageKnob.fStep;
  245. fValue = imageKnob.fValue;
  246. fValueDef = imageKnob.fValueDef;
  247. fValueTmp = fValue;
  248. fUsingDefault = imageKnob.fUsingDefault;
  249. fUsingLog = imageKnob.fUsingLog;
  250. fOrientation = imageKnob.fOrientation;
  251. fRotationAngle = imageKnob.fRotationAngle;
  252. fDragging = false;
  253. fLastX = 0;
  254. fLastY = 0;
  255. fCallback = imageKnob.fCallback;
  256. fIsImgVertical = imageKnob.fIsImgVertical;
  257. fImgLayerWidth = imageKnob.fImgLayerWidth;
  258. fImgLayerHeight = imageKnob.fImgLayerHeight;
  259. fImgLayerCount = imageKnob.fImgLayerCount;
  260. fIsReady = false;
  261. if (fTextureId != 0)
  262. {
  263. glDeleteTextures(1, &fTextureId);
  264. fTextureId = 0;
  265. }
  266. glGenTextures(1, &fTextureId);
  267. setSize(fImgLayerWidth, fImgLayerHeight);
  268. return *this;
  269. }
  270. ImageKnob::~ImageKnob()
  271. {
  272. if (fTextureId != 0)
  273. {
  274. glDeleteTextures(1, &fTextureId);
  275. fTextureId = 0;
  276. }
  277. }
  278. float ImageKnob::getValue() const noexcept
  279. {
  280. return fValue;
  281. }
  282. // NOTE: value is assumed to be scaled if using log
  283. void ImageKnob::setDefault(float value) noexcept
  284. {
  285. fValueDef = value;
  286. fUsingDefault = true;
  287. }
  288. void ImageKnob::setRange(float min, float max) noexcept
  289. {
  290. DISTRHO_SAFE_ASSERT_RETURN(max > min,);
  291. if (fValue < min)
  292. {
  293. fValue = min;
  294. repaint();
  295. if (fCallback != nullptr)
  296. {
  297. try {
  298. fCallback->imageKnobValueChanged(this, fValue);
  299. } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange < min");
  300. }
  301. }
  302. else if (fValue > max)
  303. {
  304. fValue = max;
  305. repaint();
  306. if (fCallback != nullptr)
  307. {
  308. try {
  309. fCallback->imageKnobValueChanged(this, fValue);
  310. } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange > max");
  311. }
  312. }
  313. fMinimum = min;
  314. fMaximum = max;
  315. }
  316. void ImageKnob::setStep(float step) noexcept
  317. {
  318. fStep = step;
  319. }
  320. // NOTE: value is assumed to be scaled if using log
  321. void ImageKnob::setValue(float value, bool sendCallback) noexcept
  322. {
  323. if (d_isEqual(fValue, value))
  324. return;
  325. fValue = value;
  326. if (d_isZero(fStep))
  327. fValueTmp = value;
  328. if (fRotationAngle == 0)
  329. fIsReady = false;
  330. repaint();
  331. if (sendCallback && fCallback != nullptr)
  332. {
  333. try {
  334. fCallback->imageKnobValueChanged(this, fValue);
  335. } DISTRHO_SAFE_EXCEPTION("ImageKnob::setValue");
  336. }
  337. }
  338. void ImageKnob::setUsingLogScale(bool yesNo) noexcept
  339. {
  340. fUsingLog = yesNo;
  341. }
  342. void ImageKnob::setCallback(Callback* callback) noexcept
  343. {
  344. fCallback = callback;
  345. }
  346. void ImageKnob::setOrientation(Orientation orientation) noexcept
  347. {
  348. if (fOrientation == orientation)
  349. return;
  350. fOrientation = orientation;
  351. }
  352. void ImageKnob::setRotationAngle(int angle)
  353. {
  354. if (fRotationAngle == angle)
  355. return;
  356. fRotationAngle = angle;
  357. fIsReady = false;
  358. }
  359. void ImageKnob::setImageLayerCount(uint count) noexcept
  360. {
  361. DISTRHO_SAFE_ASSERT_RETURN(count > 1,);
  362. fImgLayerCount = count;
  363. if (fIsImgVertical)
  364. fImgLayerHeight = fImage.getHeight()/count;
  365. else
  366. fImgLayerWidth = fImage.getWidth()/count;
  367. setSize(fImgLayerWidth, fImgLayerHeight);
  368. }
  369. void ImageKnob::onDisplay()
  370. {
  371. const float normValue = ((fUsingLog ? _invlogscale(fValue) : fValue) - fMinimum) / (fMaximum - fMinimum);
  372. glEnable(GL_TEXTURE_2D);
  373. glBindTexture(GL_TEXTURE_2D, fTextureId);
  374. if (! fIsReady)
  375. {
  376. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  377. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  378. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  379. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  380. static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
  381. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
  382. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  383. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  384. uint imageDataOffset = 0;
  385. if (fRotationAngle == 0)
  386. {
  387. DISTRHO_SAFE_ASSERT_RETURN(fImgLayerCount > 0,);
  388. DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);
  389. const uint& v1(fIsImgVertical ? fImgLayerWidth : fImgLayerHeight);
  390. const uint& v2(fIsImgVertical ? fImgLayerHeight : fImgLayerWidth);
  391. const uint layerDataSize = v1 * v2 * ((fImage.getFormat() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 4 : 3);
  392. /* */ imageDataOffset = layerDataSize * uint(normValue * float(fImgLayerCount-1));
  393. }
  394. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
  395. static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
  396. fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset);
  397. fIsReady = true;
  398. }
  399. const int w = static_cast<int>(getWidth());
  400. const int h = static_cast<int>(getHeight());
  401. if (fRotationAngle != 0)
  402. {
  403. glPushMatrix();
  404. const int w2 = w/2;
  405. const int h2 = h/2;
  406. glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
  407. glRotatef(normValue*static_cast<float>(fRotationAngle), 0.0f, 0.0f, 1.0f);
  408. Rectangle<int>(-w2, -h2, w, h).draw();
  409. glPopMatrix();
  410. }
  411. else
  412. {
  413. Rectangle<int>(0, 0, w, h).draw();
  414. }
  415. glBindTexture(GL_TEXTURE_2D, 0);
  416. glDisable(GL_TEXTURE_2D);
  417. }
  418. bool ImageKnob::onMouse(const MouseEvent& ev)
  419. {
  420. if (ev.button != 1)
  421. return false;
  422. if (ev.press)
  423. {
  424. if (! contains(ev.pos))
  425. return false;
  426. if ((ev.mod & kModifierShift) != 0 && fUsingDefault)
  427. {
  428. setValue(fValueDef, true);
  429. fValueTmp = fValue;
  430. return true;
  431. }
  432. fDragging = true;
  433. fLastX = ev.pos.getX();
  434. fLastY = ev.pos.getY();
  435. if (fCallback != nullptr)
  436. fCallback->imageKnobDragStarted(this);
  437. return true;
  438. }
  439. else if (fDragging)
  440. {
  441. if (fCallback != nullptr)
  442. fCallback->imageKnobDragFinished(this);
  443. fDragging = false;
  444. return true;
  445. }
  446. return false;
  447. }
  448. bool ImageKnob::onMotion(const MotionEvent& ev)
  449. {
  450. if (! fDragging)
  451. return false;
  452. bool doVal = false;
  453. float d, value = 0.0f;
  454. if (fOrientation == ImageKnob::Horizontal)
  455. {
  456. if (const int movX = ev.pos.getX() - fLastX)
  457. {
  458. d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
  459. value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movX));
  460. doVal = true;
  461. }
  462. }
  463. else if (fOrientation == ImageKnob::Vertical)
  464. {
  465. if (const int movY = fLastY - ev.pos.getY())
  466. {
  467. d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
  468. value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movY));
  469. doVal = true;
  470. }
  471. }
  472. if (! doVal)
  473. return false;
  474. if (fUsingLog)
  475. value = _logscale(value);
  476. if (value < fMinimum)
  477. {
  478. fValueTmp = value = fMinimum;
  479. }
  480. else if (value > fMaximum)
  481. {
  482. fValueTmp = value = fMaximum;
  483. }
  484. else if (d_isNotZero(fStep))
  485. {
  486. fValueTmp = value;
  487. const float rest = std::fmod(value, fStep);
  488. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  489. }
  490. setValue(value, true);
  491. fLastX = ev.pos.getX();
  492. fLastY = ev.pos.getY();
  493. return true;
  494. }
  495. bool ImageKnob::onScroll(const ScrollEvent& ev)
  496. {
  497. if (! contains(ev.pos))
  498. return false;
  499. const float d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
  500. float value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * 10.f * ev.delta.getY());
  501. if (fUsingLog)
  502. value = _logscale(value);
  503. if (value < fMinimum)
  504. {
  505. fValueTmp = value = fMinimum;
  506. }
  507. else if (value > fMaximum)
  508. {
  509. fValueTmp = value = fMaximum;
  510. }
  511. else if (d_isNotZero(fStep))
  512. {
  513. fValueTmp = value;
  514. const float rest = std::fmod(value, fStep);
  515. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  516. }
  517. setValue(value, true);
  518. return true;
  519. }
  520. // -----------------------------------------------------------------------
  521. float ImageKnob::_logscale(float value) const
  522. {
  523. const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum);
  524. const float a = fMaximum/std::exp(fMaximum*b);
  525. return a * std::exp(b*value);
  526. }
  527. float ImageKnob::_invlogscale(float value) const
  528. {
  529. const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum);
  530. const float a = fMaximum/std::exp(fMaximum*b);
  531. return std::log(value/a)/b;
  532. }
  533. // -----------------------------------------------------------------------
  534. ImageSlider::ImageSlider(Window& parent, const Image& image) noexcept
  535. : Widget(parent),
  536. fImage(image),
  537. fMinimum(0.0f),
  538. fMaximum(1.0f),
  539. fStep(0.0f),
  540. fValue(0.5f),
  541. fValueTmp(fValue),
  542. fDragging(false),
  543. fInverted(false),
  544. fValueIsSet(false),
  545. fStartedX(0),
  546. fStartedY(0),
  547. fCallback(nullptr),
  548. fStartPos(),
  549. fEndPos(),
  550. fSliderArea()
  551. {
  552. pData->needsFullViewport = true;
  553. }
  554. ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept
  555. : Widget(widget->getParentWindow()),
  556. fImage(image),
  557. fMinimum(0.0f),
  558. fMaximum(1.0f),
  559. fStep(0.0f),
  560. fValue(0.5f),
  561. fValueTmp(fValue),
  562. fDragging(false),
  563. fInverted(false),
  564. fValueIsSet(false),
  565. fStartedX(0),
  566. fStartedY(0),
  567. fCallback(nullptr),
  568. fStartPos(),
  569. fEndPos(),
  570. fSliderArea()
  571. {
  572. pData->needsFullViewport = true;
  573. }
  574. float ImageSlider::getValue() const noexcept
  575. {
  576. return fValue;
  577. }
  578. void ImageSlider::setValue(float value, bool sendCallback) noexcept
  579. {
  580. if (! fValueIsSet)
  581. fValueIsSet = true;
  582. if (d_isEqual(fValue, value))
  583. return;
  584. fValue = value;
  585. if (d_isZero(fStep))
  586. fValueTmp = value;
  587. repaint();
  588. if (sendCallback && fCallback != nullptr)
  589. {
  590. try {
  591. fCallback->imageSliderValueChanged(this, fValue);
  592. } DISTRHO_SAFE_EXCEPTION("ImageSlider::setValue");
  593. }
  594. }
  595. void ImageSlider::setStartPos(const Point<int>& startPos) noexcept
  596. {
  597. fStartPos = startPos;
  598. _recheckArea();
  599. }
  600. void ImageSlider::setStartPos(int x, int y) noexcept
  601. {
  602. setStartPos(Point<int>(x, y));
  603. }
  604. void ImageSlider::setEndPos(const Point<int>& endPos) noexcept
  605. {
  606. fEndPos = endPos;
  607. _recheckArea();
  608. }
  609. void ImageSlider::setEndPos(int x, int y) noexcept
  610. {
  611. setEndPos(Point<int>(x, y));
  612. }
  613. void ImageSlider::setInverted(bool inverted) noexcept
  614. {
  615. if (fInverted == inverted)
  616. return;
  617. fInverted = inverted;
  618. repaint();
  619. }
  620. void ImageSlider::setRange(float min, float max) noexcept
  621. {
  622. fMinimum = min;
  623. fMaximum = max;
  624. if (fValue < min)
  625. {
  626. fValue = min;
  627. repaint();
  628. if (fCallback != nullptr && fValueIsSet)
  629. {
  630. try {
  631. fCallback->imageSliderValueChanged(this, fValue);
  632. } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min");
  633. }
  634. }
  635. else if (fValue > max)
  636. {
  637. fValue = max;
  638. repaint();
  639. if (fCallback != nullptr && fValueIsSet)
  640. {
  641. try {
  642. fCallback->imageSliderValueChanged(this, fValue);
  643. } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max");
  644. }
  645. }
  646. }
  647. void ImageSlider::setStep(float step) noexcept
  648. {
  649. fStep = step;
  650. }
  651. void ImageSlider::setCallback(Callback* callback) noexcept
  652. {
  653. fCallback = callback;
  654. }
  655. void ImageSlider::onDisplay()
  656. {
  657. #if 0 // DEBUG, paints slider area
  658. glColor3f(0.4f, 0.5f, 0.1f);
  659. glRecti(fSliderArea.getX(), fSliderArea.getY(), fSliderArea.getX()+fSliderArea.getWidth(), fSliderArea.getY()+fSliderArea.getHeight());
  660. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  661. #endif
  662. const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum);
  663. int x, y;
  664. if (fStartPos.getY() == fEndPos.getY())
  665. {
  666. // horizontal
  667. if (fInverted)
  668. x = fEndPos.getX() - static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX()));
  669. else
  670. x = fStartPos.getX() + static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX()));
  671. y = fStartPos.getY();
  672. }
  673. else
  674. {
  675. // vertical
  676. x = fStartPos.getX();
  677. if (fInverted)
  678. y = fEndPos.getY() - static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY()));
  679. else
  680. y = fStartPos.getY() + static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY()));
  681. }
  682. fImage.drawAt(x, y);
  683. }
  684. bool ImageSlider::onMouse(const MouseEvent& ev)
  685. {
  686. if (ev.button != 1)
  687. return false;
  688. if (ev.press)
  689. {
  690. if (! fSliderArea.contains(ev.pos))
  691. return false;
  692. float vper;
  693. const int x = ev.pos.getX();
  694. const int y = ev.pos.getY();
  695. if (fStartPos.getY() == fEndPos.getY())
  696. {
  697. // horizontal
  698. vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth());
  699. }
  700. else
  701. {
  702. // vertical
  703. vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight());
  704. }
  705. float value;
  706. if (fInverted)
  707. value = fMaximum - vper * (fMaximum - fMinimum);
  708. else
  709. value = fMinimum + vper * (fMaximum - fMinimum);
  710. if (value < fMinimum)
  711. {
  712. fValueTmp = value = fMinimum;
  713. }
  714. else if (value > fMaximum)
  715. {
  716. fValueTmp = value = fMaximum;
  717. }
  718. else if (d_isNotZero(fStep))
  719. {
  720. fValueTmp = value;
  721. const float rest = std::fmod(value, fStep);
  722. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  723. }
  724. fDragging = true;
  725. fStartedX = x;
  726. fStartedY = y;
  727. if (fCallback != nullptr)
  728. fCallback->imageSliderDragStarted(this);
  729. setValue(value, true);
  730. return true;
  731. }
  732. else if (fDragging)
  733. {
  734. if (fCallback != nullptr)
  735. fCallback->imageSliderDragFinished(this);
  736. fDragging = false;
  737. return true;
  738. }
  739. return false;
  740. }
  741. bool ImageSlider::onMotion(const MotionEvent& ev)
  742. {
  743. if (! fDragging)
  744. return false;
  745. const bool horizontal = fStartPos.getY() == fEndPos.getY();
  746. const int x = ev.pos.getX();
  747. const int y = ev.pos.getY();
  748. if ((horizontal && fSliderArea.containsX(x)) || (fSliderArea.containsY(y) && ! horizontal))
  749. {
  750. float vper;
  751. if (horizontal)
  752. {
  753. // horizontal
  754. vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth());
  755. }
  756. else
  757. {
  758. // vertical
  759. vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight());
  760. }
  761. float value;
  762. if (fInverted)
  763. value = fMaximum - vper * (fMaximum - fMinimum);
  764. else
  765. value = fMinimum + vper * (fMaximum - fMinimum);
  766. if (value < fMinimum)
  767. {
  768. fValueTmp = value = fMinimum;
  769. }
  770. else if (value > fMaximum)
  771. {
  772. fValueTmp = value = fMaximum;
  773. }
  774. else if (d_isNotZero(fStep))
  775. {
  776. fValueTmp = value;
  777. const float rest = std::fmod(value, fStep);
  778. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  779. }
  780. setValue(value, true);
  781. }
  782. else if (horizontal)
  783. {
  784. if (x < fSliderArea.getX())
  785. setValue(fInverted ? fMaximum : fMinimum, true);
  786. else
  787. setValue(fInverted ? fMinimum : fMaximum, true);
  788. }
  789. else
  790. {
  791. if (y < fSliderArea.getY())
  792. setValue(fInverted ? fMaximum : fMinimum, true);
  793. else
  794. setValue(fInverted ? fMinimum : fMaximum, true);
  795. }
  796. return true;
  797. }
  798. void ImageSlider::_recheckArea() noexcept
  799. {
  800. if (fStartPos.getY() == fEndPos.getY())
  801. {
  802. // horizontal
  803. fSliderArea = Rectangle<int>(fStartPos.getX(),
  804. fStartPos.getY(),
  805. fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(),
  806. static_cast<int>(fImage.getHeight()));
  807. }
  808. else
  809. {
  810. // vertical
  811. fSliderArea = Rectangle<int>(fStartPos.getX(),
  812. fStartPos.getY(),
  813. static_cast<int>(fImage.getWidth()),
  814. fEndPos.getY() + static_cast<int>(fImage.getHeight()) - fStartPos.getY());
  815. }
  816. }
  817. // -----------------------------------------------------------------------
  818. ImageSwitch::ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept
  819. : Widget(parent),
  820. fImageNormal(imageNormal),
  821. fImageDown(imageDown),
  822. fIsDown(false),
  823. fCallback(nullptr)
  824. {
  825. DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
  826. setSize(fImageNormal.getSize());
  827. }
  828. ImageSwitch::ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept
  829. : Widget(widget->getParentWindow()),
  830. fImageNormal(imageNormal),
  831. fImageDown(imageDown),
  832. fIsDown(false),
  833. fCallback(nullptr)
  834. {
  835. DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
  836. setSize(fImageNormal.getSize());
  837. }
  838. ImageSwitch::ImageSwitch(const ImageSwitch& imageSwitch) noexcept
  839. : Widget(imageSwitch.getParentWindow()),
  840. fImageNormal(imageSwitch.fImageNormal),
  841. fImageDown(imageSwitch.fImageDown),
  842. fIsDown(imageSwitch.fIsDown),
  843. fCallback(imageSwitch.fCallback)
  844. {
  845. DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
  846. setSize(fImageNormal.getSize());
  847. }
  848. ImageSwitch& ImageSwitch::operator=(const ImageSwitch& imageSwitch) noexcept
  849. {
  850. fImageNormal = imageSwitch.fImageNormal;
  851. fImageDown = imageSwitch.fImageDown;
  852. fIsDown = imageSwitch.fIsDown;
  853. fCallback = imageSwitch.fCallback;
  854. DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
  855. setSize(fImageNormal.getSize());
  856. return *this;
  857. }
  858. bool ImageSwitch::isDown() const noexcept
  859. {
  860. return fIsDown;
  861. }
  862. void ImageSwitch::setDown(bool down) noexcept
  863. {
  864. if (fIsDown == down)
  865. return;
  866. fIsDown = down;
  867. repaint();
  868. }
  869. void ImageSwitch::setCallback(Callback* callback) noexcept
  870. {
  871. fCallback = callback;
  872. }
  873. void ImageSwitch::onDisplay()
  874. {
  875. if (fIsDown)
  876. fImageDown.draw();
  877. else
  878. fImageNormal.draw();
  879. }
  880. bool ImageSwitch::onMouse(const MouseEvent& ev)
  881. {
  882. if (ev.press && contains(ev.pos))
  883. {
  884. fIsDown = !fIsDown;
  885. repaint();
  886. if (fCallback != nullptr)
  887. fCallback->imageSwitchClicked(this, fIsDown);
  888. return true;
  889. }
  890. return false;
  891. }
  892. // -----------------------------------------------------------------------
  893. END_NAMESPACE_DGL