1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2020 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 
19 #include "extra/String.hpp"
20 
21 #include "DistrhoPluginInfo.h"
22 #include "NanoButton.hpp"
23 
24 START_NAMESPACE_DISTRHO
25 
26 const char* kStateKeys[kStateCount] = {
27     "file1",
28     "file2",
29     "file3",
30 };
31 
32 // -----------------------------------------------------------------------------------------------------------
33 
setupButton(Button & btn,int y)34 static void setupButton(Button& btn, int y)
35 {
36     btn.setAbsolutePos(5, y);
37     btn.setLabel("Open...");
38     btn.setSize(100, 30);
39 }
40 
41 class FileHandlingExampleUI : public UI,
42                               public Button::Callback
43 {
44 public:
45     static const uint kInitialWidth  = 600;
46     static const uint kInitialHeight = 350;
47 
FileHandlingExampleUI()48     FileHandlingExampleUI()
49         : UI(kInitialWidth, kInitialHeight),
50           fButton1(this, this),
51           fButton2(this, this),
52           fButton3(this, this),
53           fScale(1.0f)
54     {
55         std::memset(fParameters, 0, sizeof(fParameters));
56         std::memset(fStrBuf, 0, sizeof(fStrBuf));
57 
58         setupButton(fButton1, 5);
59         setupButton(fButton2, 105);
60         setupButton(fButton3, 205);
61 
62 #ifdef DGL_NO_SHARED_RESOURCES
63         createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
64 #else
65         loadSharedResources();
66 #endif
67 
68         setGeometryConstraints(kInitialWidth, kInitialHeight, true);
69     }
70 
71 protected:
72    /* --------------------------------------------------------------------------------------------------------
73     * DSP/Plugin Callbacks */
74 
75    /**
76       A parameter has changed on the plugin side.@n
77       This is called by the host to inform the UI about parameter changes.
78     */
parameterChanged(uint32_t index,float value)79     void parameterChanged(uint32_t index, float value) override
80     {
81         fParameters[index] = value;
82         repaint();
83     }
84 
85    /**
86       A state has changed on the plugin side.@n
87       This is called by the host to inform the UI about state changes.
88     */
stateChanged(const char * key,const char * value)89     void stateChanged(const char* key, const char* value) override
90     {
91         States stateId = kStateCount;
92 
93         /**/ if (std::strcmp(key, "file1") == 0)
94             stateId = kStateFile1;
95         else if (std::strcmp(key, "file2") == 0)
96             stateId = kStateFile2;
97         else if (std::strcmp(key, "file3") == 0)
98             stateId = kStateFile3;
99 
100         if (stateId == kStateCount)
101             return;
102 
103         fState[stateId] = value;
104         repaint();
105     }
106 
107    /* --------------------------------------------------------------------------------------------------------
108     * Widget Callbacks */
109 
110    /**
111       The NanoVG drawing function.
112     */
onNanoDisplay()113     void onNanoDisplay() override
114     {
115         const float lineHeight = 20 * fScale;
116         float y;
117 
118         fontSize(15.0f * fScale);
119         textLineHeight(lineHeight);
120 
121         // ---------------------------------------------------------------------------------------
122         // File 1
123 
124         y = 45.0f * fScale;
125 
126         if (fState[kStateFile1].isNotEmpty())
127         {
128             drawLeft(0.0f, y, "Name:");
129             drawRight(0.0f, y, fState[kStateFile1]);
130             y += lineHeight;
131 
132             drawLeft(0.0f, y, "Size:");
133             drawRight(0.0f, y, getTextBufFileSize(fParameters[kParameterFileSize1]));
134             y += lineHeight;
135         }
136         else
137         {
138             drawLeft(0.0f, y, "No file loaded");
139         }
140 
141         // ---------------------------------------------------------------------------------------
142         // File 2
143 
144         y = 145.0f * fScale;
145 
146         if (fState[kStateFile2].isNotEmpty())
147         {
148             drawLeft(0.0f, y, "Name:");
149             drawRight(0.0f, y, fState[kStateFile2]);
150             y += lineHeight;
151 
152             drawLeft(0.0f, y, "Size:");
153             drawRight(0.0f, y, getTextBufFileSize(fParameters[kParameterFileSize2]));
154             y += lineHeight;
155         }
156         else
157         {
158             drawLeft(0.0f, y, "No file loaded");
159         }
160 
161         // ---------------------------------------------------------------------------------------
162         // File 3
163 
164         y = 245.0f * fScale;
165 
166         if (fState[kStateFile3].isNotEmpty())
167         {
168             drawLeft(0.0f, y, "Name:");
169             drawRight(0.0f, y, fState[kStateFile3]);
170             y += lineHeight;
171 
172             drawLeft(0.0f, y, "Size:");
173             drawRight(0.0f, y, getTextBufFileSize(fParameters[kParameterFileSize3]));
174             y += lineHeight;
175         }
176         else
177         {
178             drawLeft(0.0f, y, "No file loaded");
179         }
180     }
181 
onResize(const ResizeEvent & ev)182     void onResize(const ResizeEvent& ev) override
183     {
184         fScale = static_cast<float>(ev.size.getHeight())/kInitialHeight;
185 
186         UI::onResize(ev);
187     }
188 
buttonClicked(Button * const button,bool)189     void buttonClicked(Button* const button, bool) override
190     {
191         States stateId = kStateCount;
192 
193         /**/ if (button == &fButton1)
194             stateId = kStateFile1;
195         else if (button == &fButton2)
196             stateId = kStateFile2;
197         else if (button == &fButton3)
198             stateId = kStateFile3;
199 
200         if (stateId == kStateCount)
201             return;
202 
203         requestStateFile(kStateKeys[stateId]);
204     }
205 
206     // -------------------------------------------------------------------------------------------------------
207 
208 private:
209     // Parameters
210     float fParameters[kParameterCount];
211 
212     // State (files)
213     String fState[kStateCount];
214     Button fButton1, fButton2, fButton3;
215 
216     // UI stuff
217     float fScale;
218 
219     // temp buf for text
220     char fStrBuf[0xff];
221 
222     // helpers for putting text into fStrBuf and returning it
getTextBufFileSize(const float value)223     const char* getTextBufFileSize(const float value)
224     {
225         /**/ if (value > 1024*1024)
226             std::snprintf(fStrBuf, 0xfe, "%.2f GiB", value/(1024*1024));
227         else if (value > 1024)
228             std::snprintf(fStrBuf, 0xfe, "%.2f MiB", value/1024);
229         else
230             std::snprintf(fStrBuf, 0xfe, "%.2f KiB", value);
231         return fStrBuf;
232     }
233 
234     // helpers for drawing text
drawLeft(const float x,const float y,const char * const text)235     void drawLeft(const float x, const float y, const char* const text)
236     {
237         beginPath();
238         fillColor(200, 200, 200);
239         textAlign(ALIGN_RIGHT|ALIGN_TOP);
240         textBox(x, y, 100 * fScale, text);
241         closePath();
242     }
243 
drawRight(const float x,const float y,const char * const text)244     void drawRight(const float x, const float y, const char* const text)
245     {
246         beginPath();
247         fillColor(255, 255, 255);
248         textAlign(ALIGN_LEFT|ALIGN_TOP);
249         textBox(x + (105 * fScale), y, (kInitialWidth - x) * fScale, text);
250         closePath();
251     }
252 
253    /**
254       Set our UI class as non-copyable and add a leak detector just in case.
255     */
256     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileHandlingExampleUI)
257 };
258 
259 /* ------------------------------------------------------------------------------------------------------------
260  * UI entry point, called by DPF to create a new UI instance. */
261 
createUI()262 UI* createUI()
263 {
264     return new FileHandlingExampleUI();
265 }
266 
267 // -----------------------------------------------------------------------------------------------------------
268 
269 END_NAMESPACE_DISTRHO
270