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