DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

ExampleUIStates.cpp (9532B)


      1 /*
      2  * DISTRHO Plugin Framework (DPF)
      3  * Copyright (C) 2012-2021 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 
     17 #include "DistrhoUI.hpp"
     18 #include "Color.hpp"
     19 
     20 START_NAMESPACE_DISTRHO
     21 
     22 /**
     23   We need a few classes from DGL.
     24  */
     25 using DGL_NAMESPACE::Color;
     26 using DGL_NAMESPACE::GraphicsContext;
     27 using DGL_NAMESPACE::Rectangle;
     28 
     29 // -----------------------------------------------------------------------------------------------------------
     30 
     31 class ExampleUIParameters : public UI
     32 {
     33 public:
     34     /**
     35       Get key name from an index.
     36     */
     37     static const char* getStateKeyFromIndex(const uint32_t index) noexcept
     38     {
     39         switch (index)
     40         {
     41         case 0: return "top-left";
     42         case 1: return "top-center";
     43         case 2: return "top-right";
     44         case 3: return "middle-left";
     45         case 4: return "middle-center";
     46         case 5: return "middle-right";
     47         case 6: return "bottom-left";
     48         case 7: return "bottom-center";
     49         case 8: return "bottom-right";
     50         }
     51 
     52         return "unknown";
     53     }
     54 
     55     /* constructor */
     56     ExampleUIParameters()
     57         : UI(512, 512)
     58     {
     59        /**
     60           Initialize the grid to all off per default.
     61         */
     62         std::memset(fParamGrid, 0, sizeof(bool)*9);
     63 
     64         // TODO explain why this is here
     65         setGeometryConstraints(128, 128, true);
     66     }
     67 
     68 protected:
     69    /* --------------------------------------------------------------------------------------------------------
     70     * DSP/Plugin Callbacks */
     71 
     72    /**
     73       This plugin has no parameters, so we can safely ignore this.
     74     */
     75     void parameterChanged(uint32_t, float) override {}
     76 
     77    /**
     78       A program has been loaded on the plugin side.
     79       This is called by the host to inform the UI about program changes.
     80     */
     81     void programLoaded(uint32_t index) override
     82     {
     83         switch (index)
     84         {
     85         case 0:
     86             fParamGrid[0] = false;
     87             fParamGrid[1] = false;
     88             fParamGrid[2] = false;
     89             fParamGrid[3] = false;
     90             fParamGrid[4] = false;
     91             fParamGrid[5] = false;
     92             fParamGrid[6] = false;
     93             fParamGrid[7] = false;
     94             fParamGrid[8] = false;
     95             break;
     96         case 1:
     97             fParamGrid[0] = true;
     98             fParamGrid[1] = true;
     99             fParamGrid[2] = false;
    100             fParamGrid[3] = false;
    101             fParamGrid[4] = true;
    102             fParamGrid[5] = true;
    103             fParamGrid[6] = true;
    104             fParamGrid[7] = false;
    105             fParamGrid[8] = true;
    106             break;
    107         }
    108         repaint();
    109     }
    110 
    111    /**
    112       A state has changed on the plugin side.
    113       This is called by the host to inform the UI about state changes.
    114     */
    115     void stateChanged(const char* key, const char* value) override
    116     {
    117         const bool valueOnOff = (std::strcmp(value, "true") == 0);
    118 
    119         // check which block changed
    120         /**/ if (std::strcmp(key, "top-left") == 0)
    121             fParamGrid[0] = valueOnOff;
    122         else if (std::strcmp(key, "top-center") == 0)
    123             fParamGrid[1] = valueOnOff;
    124         else if (std::strcmp(key, "top-right") == 0)
    125             fParamGrid[2] = valueOnOff;
    126         else if (std::strcmp(key, "middle-left") == 0)
    127             fParamGrid[3] = valueOnOff;
    128         else if (std::strcmp(key, "middle-center") == 0)
    129             fParamGrid[4] = valueOnOff;
    130         else if (std::strcmp(key, "middle-right") == 0)
    131             fParamGrid[5] = valueOnOff;
    132         else if (std::strcmp(key, "bottom-left") == 0)
    133             fParamGrid[6] = valueOnOff;
    134         else if (std::strcmp(key, "bottom-center") == 0)
    135             fParamGrid[7] = valueOnOff;
    136         else if (std::strcmp(key, "bottom-right") == 0)
    137             fParamGrid[8] = valueOnOff;
    138 
    139         // trigger repaint
    140         repaint();
    141     }
    142 
    143    /* --------------------------------------------------------------------------------------------------------
    144     * Widget Callbacks */
    145 
    146    /**
    147       The OpenGL drawing function.
    148       This UI will draw a 3x3 grid, with on/off states according to plugin state.
    149     */
    150     void onDisplay() override
    151     {
    152         const GraphicsContext& context(getGraphicsContext());
    153 
    154         const uint width = getWidth();
    155         const uint height = getHeight();
    156         const uint minwh = std::min(width, height);
    157         const uint bgColor = getBackgroundColor();
    158 
    159         Rectangle<double> r;
    160 
    161         // if host doesn't respect aspect-ratio but supports ui background, draw out-of-bounds color from it
    162         if (width != height && bgColor != 0)
    163         {
    164             const int red   = (bgColor >> 24) & 0xff;
    165             const int green = (bgColor >> 16) & 0xff;
    166             const int blue  = (bgColor >>  8) & 0xff;
    167             Color(red, green, blue).setFor(context);
    168 
    169             if (width > height)
    170             {
    171                 r.setPos(height, 0);
    172                 r.setSize(width-height, height);
    173             }
    174             else
    175             {
    176                 r.setPos(0, width);
    177                 r.setSize(width, height-width);
    178             }
    179 
    180             r.draw(context);
    181         }
    182 
    183         r.setWidth(minwh/3 - 6);
    184         r.setHeight(minwh/3 - 6);
    185 
    186         // draw left, center and right columns
    187         for (int i=0; i<3; ++i)
    188         {
    189             r.setX(3 + i*minwh/3);
    190 
    191             // top
    192             r.setY(3);
    193 
    194             if (fParamGrid[0+i])
    195                 Color(0.8f, 0.5f, 0.3f).setFor(context);
    196             else
    197                 Color(0.3f, 0.5f, 0.8f).setFor(context);
    198 
    199             r.draw(context);
    200 
    201             // middle
    202             r.setY(3 + minwh/3);
    203 
    204             if (fParamGrid[3+i])
    205                 Color(0.8f, 0.5f, 0.3f).setFor(context);
    206             else
    207                 Color(0.3f, 0.5f, 0.8f).setFor(context);
    208 
    209             r.draw(context);
    210 
    211             // bottom
    212             r.setY(3 + minwh*2/3);
    213 
    214             if (fParamGrid[6+i])
    215                 Color(0.8f, 0.5f, 0.3f).setFor(context);
    216             else
    217                 Color(0.3f, 0.5f, 0.8f).setFor(context);
    218 
    219             r.draw(context);
    220         }
    221     }
    222 
    223    /**
    224       Mouse press event.
    225       This UI will de/activate blocks when you click them and report it as a state change to the plugin.
    226     */
    227     bool onMouse(const MouseEvent& ev) override
    228     {
    229         // Test for left-clicked + pressed first.
    230         if (ev.button != 1 || ! ev.press)
    231             return false;
    232 
    233         const uint width = getWidth();
    234         const uint height = getHeight();
    235 
    236         Rectangle<double> r;
    237 
    238         r.setWidth(width/3 - 6);
    239         r.setHeight(height/3 - 6);
    240 
    241         // handle left, center and right columns
    242         for (int i=0; i<3; ++i)
    243         {
    244             r.setX(3 + i*width/3);
    245 
    246             // top
    247             r.setY(3);
    248 
    249             if (r.contains(ev.pos))
    250             {
    251                 // index that this block applies to
    252                 const uint32_t index = 0+i;
    253 
    254                 // invert block state
    255                 fParamGrid[index] = !fParamGrid[index];
    256 
    257                 // report change to host (and thus plugin)
    258                 setState(getStateKeyFromIndex(index), fParamGrid[index] ? "true" : "false");
    259 
    260                 // trigger repaint
    261                 repaint();
    262                 break;
    263             }
    264 
    265             // middle
    266             r.setY(3 + height/3);
    267 
    268             if (r.contains(ev.pos))
    269             {
    270                 // same as before
    271                 const uint32_t index = 3+i;
    272                 fParamGrid[index] = !fParamGrid[index];
    273                 setState(getStateKeyFromIndex(index), fParamGrid[index] ? "true" : "false");
    274                 repaint();
    275                 break;
    276             }
    277 
    278             // bottom
    279             r.setY(3 + height*2/3);
    280 
    281             if (r.contains(ev.pos))
    282             {
    283                 // same as before
    284                 const uint32_t index = 6+i;
    285                 fParamGrid[index] = !fParamGrid[index];
    286                 setState(getStateKeyFromIndex(index), fParamGrid[index] ? "true" : "false");
    287                 repaint();
    288                 break;
    289             }
    290         }
    291 
    292         return true;
    293     }
    294 
    295     // -------------------------------------------------------------------------------------------------------
    296 
    297 private:
    298    /**
    299       Our states used to display the grid.
    300       The host does not know about these.
    301     */
    302     bool fParamGrid[9];
    303 
    304    /**
    305       Set our UI class as non-copyable and add a leak detector just in case.
    306     */
    307     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExampleUIParameters)
    308 };
    309 
    310 /* ------------------------------------------------------------------------------------------------------------
    311  * UI entry point, called by DPF to create a new UI instance. */
    312 
    313 UI* createUI()
    314 {
    315     return new ExampleUIParameters();
    316 }
    317 
    318 // -----------------------------------------------------------------------------------------------------------
    319 
    320 END_NAMESPACE_DISTRHO