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.

1117 lines
28KB

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