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.

1099 lines
27KB

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