IPlugControls is a comprehensive demonstration of every UI control available in iPlug2’s IControls library. This example serves as both a reference and a testbed for visual customization.
What You’ll Learn
Control Types Every available control: knobs, sliders, buttons, meters, and more
Bitmap Controls Using PNG and SVG graphics for custom control appearances
Vector Styling Customizing IVectorBase controls with colors, shapes, and effects
Data Visualization Scopes, meters, and realtime display controls
Project Structure
Examples/IPlugControls/
├── IPlugControls.h # Plugin class and enums
├── IPlugControls.cpp # Implementation with all controls
├── config.h # Plugin configuration
├── IconsForkAwesome.h # Font Awesome icon definitions
├── IconsFontaudio.h # Audio-specific icon definitions
└── resources/ # Images, SVGs, and fonts
Parameters
The example uses minimal parameters:
enum EParams
{
kParamGain = 0 ,
kParamMode ,
kParamFreq1 ,
kParamFreq2 ,
kNumParams
};
Controls that need direct access are tagged:
enum EControlTags
{
kCtrlTagDialogResult = 0 ,
kCtrlTagVectorButton ,
kCtrlTagVectorSliderV ,
kCtrlTagVectorSliderH ,
kCtrlTagTabSwitch ,
kCtrlTagRadioButton ,
kCtrlTagScope ,
kCtrlTagDisplay ,
kCtrlTagMeter ,
kCtrlTagPeakAvgMeter ,
kCtrlTagRTText ,
kCtrlTagRedLED ,
kCtrlTagGreenLED ,
kCtrlTagBlueLED ,
kCtrlTagAboutBox ,
kCtrlTags
};
Control tags allow you to reference specific controls later, especially for sending realtime data from the DSP thread.
Control Categories
The example is organized into distinct control families:
Basic Text Controls
// Static text display
pGraphics -> AttachControl ( new ITextControl (
nextCell (). GetFromTop ( 20. f ),
"Result..." ,
DEFAULT_TEXT,
COLOR_LIGHT_GRAY
), kCtrlTagDialogResult);
// Clickable URL
pGraphics -> AttachControl ( new IURLControl (
sameCell (). SubRectVertical ( 4 , 2 ). GetMidVPadded ( 10. f ),
"IURLControl" ,
"https://iplug2.github.io" ,
DEFAULT_TEXT
));
// Editable text
pGraphics -> AttachControl ( new IEditableTextControl (
sameCell (). SubRectVertical ( 4 , 3 ). GetMidVPadded ( 10. f ),
"IEditableTextControl" ,
DEFAULT_TEXT
));
// Text toggle with icons
pGraphics -> AttachControl ( new ITextToggleControl (
sameCell (). SubRectVertical ( 4 , 1 ). GetGridCell ( 1 , 0 , 3 , 3 ),
nullptr ,
ICON_FK_SQUARE_O, // Unchecked icon
ICON_FK_CHECK_SQUARE, // Checked icon
forkAwesomeText
));
Bitmap Controls
Bitmap controls use PNG images for custom appearances:
// Load bitmaps
const IBitmap knobBitmap = pGraphics -> LoadBitmap (PNGKNOB_FN, 60 ); // 60 frames
const IBitmap switchBitmap = pGraphics -> LoadBitmap (PNGSWITCH_FN, 2 , true );
const IBitmap buttonBitmap = pGraphics -> LoadBitmap (PNGBUTTON_FN, 10 );
const IBitmap sliderHandleBitmap = pGraphics -> LoadBitmap (PNGSLIDERHANDLE_FN);
const IBitmap sliderTrackBitmap = pGraphics -> LoadBitmap (PNGSLIDERTRACK_FN);
// Bitmap knob (filmstrip)
pGraphics -> AttachControl ( new IBKnobControl (
sameCell (). GetPadded ( - 5. ),
knobBitmap,
kParamGain
));
// Bitmap button
pGraphics -> AttachControl ( new IBButtonControl (
sameCell (). FracRectVertical ( 0.6 f , true ),
buttonBitmap,
[]( IControl * pCaller ) {
pCaller -> SetAnimation ([]( IControl * pCaller ){
auto progress = pCaller -> GetAnimationProgress ();
if (progress > 1. ) {
pCaller -> OnEndAnimation ();
return ;
}
pCaller -> SetValue ( Clip (progress + .5 , 0. , 1. ));
}, 100 );
}
));
// Bitmap slider
pGraphics -> AttachControl ( new IBSliderControl (
sameCell (). GetCentredInside (( float ) sliderHandleBitmap . W (), 100. f ),
sliderHandleBitmap,
sliderTrackBitmap,
kParamGain,
EDirection ::Vertical
));
Bitmap filmstrips should have frames arranged vertically for knobs and horizontally for switches.
SVG Controls
SVG controls use scalable vector graphics:
// Load SVGs
const ISVG sliderHandleSVG = pGraphics -> LoadSVG (SVGSLIDERHANDLE_FN);
const ISVG sliderTrackSVG = pGraphics -> LoadSVG (SVGSLIDERTRACK_FN);
const ISVG knobSVG = pGraphics -> LoadSVG (SVGKNOBROTATE_FN);
// SVG knob (rotates the graphic)
pGraphics -> AttachControl ( new ISVGKnobControl (
sameCell (). GetCentredInside ( 100 ),
knobSVG,
kParamGain
));
// SVG slider
pGraphics -> AttachControl ( new ISVGSliderControl (
sameCell (). GetCentredInside ( 30 , 100 ),
sliderHandleSVG,
sliderTrackSVG,
kParamGain,
EDirection ::Vertical
));
SVG controls scale perfectly at any resolution and are ideal for high-DPI displays.
IVector Controls
IVector controls are procedurally drawn and highly customizable:
// Define a reusable style
const IVStyle style {
true , // Show label
true , // Show value
{
DEFAULT_BGCOLOR, // Background
DEFAULT_FGCOLOR, // Foreground
DEFAULT_PRCOLOR, // Pressed
COLOR_BLACK, // Frame
DEFAULT_HLCOLOR, // Highlight
DEFAULT_SHCOLOR, // Shadow
COLOR_BLACK, // Extra 1
DEFAULT_X2COLOR, // Extra 2
DEFAULT_X3COLOR // Extra 3
},
IText ( 12. f , EAlign ::Center) // Label text
};
// Vector knob
pGraphics -> AttachControl ( new IVKnobControl (
nextCell (). GetCentredInside ( 110. ),
kParamGain,
"IVKnobControl" ,
style,
true // Show pointer/indicator
));
// Vector slider
pGraphics -> AttachControl ( new IVSliderControl (
nextCell (),
kParamGain,
"IVSliderControl" ,
style . WithRoundness ( 1. f ), // Modify style
true , // Show label
EDirection ::Vertical, // Direction
DEFAULT_GEARING, // Mouse sensitivity
6. f , // Track size
6. f , // Handle size
true // Show value
));
// Range slider (two parameters)
pGraphics -> AttachControl ( new IVRangeSliderControl (
sameCell (). SubRectVertical ( 3 , 1 ),
{kParamFreq1, kParamFreq2}, // Two parameter IDs
"IVRangeSliderControl" ,
style,
EDirection ::Horizontal
));
// Simple button with action
auto button1action = [ pGraphics ]( IControl * pCaller ) {
SplashClickActionFunc (pCaller);
pGraphics -> ShowMessageBox ( "Message" , "Title" , kMB_YESNO,
[ & ]( EMsgBoxResult result ) {
WDL_String str;
str . SetFormatted ( 32 , " %s pressed" , kMessageResultStrs [result]);
pGraphics -> GetControlWithTag (kCtrlTagDialogResult)
-> As < ITextControl >()-> SetStr ( str . Get ());
}
);
};
pGraphics -> AttachControl ( new IVButtonControl (
nextCell (). SubRectVertical ( 3 , 0 ),
button1action,
"IVButtonControl" ,
style,
false // Don't draw value text
));
// Toggle button
pGraphics -> AttachControl ( new IVToggleControl (
sameCell (). SubRectVertical ( 3 , 1 ),
SplashClickActionFunc,
"IVToggleControl" ,
style . WithValueText (forkAwesomeText),
"" , // Off text
ICON_FK_CHECK // On text (icon)
));
// Menu button
pGraphics -> AttachControl ( new IVMenuButtonControl (
sameCell (). SubRectVertical ( 3 , 2 ),
kParamMode,
"IVMenuButtonControl" ,
style
));
Switch Controls
// Standard switch
pGraphics -> AttachControl ( new IVSwitchControl (
nextCell (). SubRectVertical ( 3 , 0 ),
kParamMode,
"IVSwitchControl" ,
style . WithValueText ( IText ( 24. f , EAlign ::Center))
));
// Radio buttons
pGraphics -> AttachControl ( new IVRadioButtonControl (
nextCell (). GetCentredInside ( 110. ),
kParamMode,
{ "one" , "two" , "three" , "four" }, // Options
"IVRadioButtonControl" ,
style,
EVShape ::Ellipse, // Shape
EDirection ::Vertical, // Layout
10. f // Spacing
));
// Tab switch with icons
pGraphics -> AttachControl ( new IVTabSwitchControl (
nextCell (). SubRectVertical ( 3 , 0 ),
SplashClickActionFunc,
{ICON_FAU_FILTER_LOWPASS, ICON_FAU_FILTER_BANDPASS, ICON_FAU_FILTER_HIGHPASS},
"IVTabSwitchControl" ,
style . WithValueText (fontaudioText),
EVShape ::EndsRounded
));
// Slide switch
pGraphics -> AttachControl ( new IVSlideSwitchControl (
sameCell (). SubRectVertical ( 3 , 1 ),
kParamMode,
"IVSlideSwitchControl" ,
style,
true // Horizontal
));
XY Pad and Multi-Slider
// XY pad controlling two parameters
pGraphics -> AttachControl ( new IVXYPadControl (
nextCell (),
{kParamFreq1, kParamFreq2},
"IVXYPadControl" ,
style
));
// Multi-slider for controlling multiple values
pGraphics -> AttachControl ( new IVMultiSliderControl < 4 >(
nextCell (),
"IVMultiSliderControl" ,
style
));
Visualization Controls
// Linear meter
pGraphics -> AttachControl ( new IVMeterControl < 2 >(
nextCell (),
"IVMeterControl - Lin" ,
style . WithColor (kFG, COLOR_WHITE . WithOpacity ( 0.3 f )),
EDirection ::Vertical,
{ "L" , "R" } // Channel labels
), kCtrlTagMeter);
// Peak/Average meter (logarithmic)
pGraphics -> AttachControl ( new IVPeakAvgMeterControl < 2 >(
nextCell (),
"IVPeakAvgMeterControl - Log" ,
style . WithColor (kFG, COLOR_WHITE . WithOpacity ( 0.3 f ))
), kCtrlTagPeakAvgMeter);
// Oscilloscope
pGraphics -> AttachControl ( new IVScopeControl < 2 , kScopeBufferSize * 2 >(
nextCell (),
"IVScopeControl" ,
style . WithColor (kFG, COLOR_BLACK)
), kCtrlTagScope);
// Waveform display
pGraphics -> AttachControl ( new IVDisplayControl (
nextCell (),
"IVDisplayControl" ,
style,
EDirection ::Vertical,
- 1. , // Min value
1. , // Max value
0. , // Initial offset
512 // Buffer size
), kCtrlTagDisplay);
Keyboard and Wheel Controls
// Piano keyboard
pGraphics -> AttachControl ( new IVKeyboardControl (
keyboardBounds,
36 , // Start note (C1)
72 // End note (C5)
), kCtrlTagKeyboard)-> SetActionFunction ([ this ]( IControl * pControl ){
this -> FlashBlueLED ();
});
// Pitch bend wheel
pGraphics -> AttachControl ( new IWheelControl (
wheelsBounds . FracRectHorizontal ( 0.5 )
), kCtrlTagBender);
// Mod wheel
pGraphics -> AttachControl ( new IWheelControl (
wheelsBounds . FracRectHorizontal ( 0.5 , true ),
IMidiMsg :: EControlChangeMsg ::kModWheel
));
LED Indicators
// LED with manual control
pGraphics -> AttachControl ( new ILEDControl (
sameCell (). SubRectVertical ( 4 , 1 ). SubRectHorizontal ( 3 , 0 ). GetCentredInside ( 20. f ),
COLOR_RED
), kCtrlTagRedLED);
pGraphics -> AttachControl ( new ILEDControl (
sameCell (). SubRectVertical ( 4 , 1 ). SubRectHorizontal ( 3 , 1 ). GetCentredInside ( 20. f ),
COLOR_GREEN
), kCtrlTagGreenLED);
// LED with decay animation
pGraphics -> AttachControl ( new ILEDControl (
sameCell (). SubRectVertical ( 4 , 1 ). SubRectHorizontal ( 3 , 2 ). GetCentredInside ( 20. f ),
0.5 f // Decay time
), kCtrlTagBlueLED);
Trigger LED with decay:
void IPlugControls :: FlashBlueLED ()
{
GetUI ()-> GetControlWithTag (kCtrlTagBlueLED)
-> As < ILEDControl >()-> TriggerWithDecay ( 1000 );
}
Plot Control
// Plot multiple functions
pGraphics -> AttachControl ( new IVPlotControl (
nextCell (),
{
{COLOR_RED, []( double x ){ return std :: sin (x * 6.2 ); }},
{COLOR_BLUE, []( double x ){ return std :: cos (x * 6.2 ); }},
{COLOR_GREEN, []( double x ){ return x > 0.5 ; }}
},
32 , // Number of points
"IVPlotControl" ,
style
));
Custom Lambda Control
// Completely custom drawing
pGraphics -> AttachControl ( new ILambdaControl (
sameCell (). GetScaledAboutCentre ( 0.5 ),
[]( ILambdaControl * pCaller , IGraphics & g , IRECT & r ) {
const float radius = r . W ();
const float x = r . MW ();
const float y = r . MH ();
const float rotate = float ( pCaller -> GetAnimationProgress () * PI);
for ( int index = 0 , limit = 40 ; index < limit; ++ index)
{
float firstAngle = float ((index * 2 * PI) / limit);
float secondAngle = float (((index + 1 ) * 2 * PI) / limit);
g . PathTriangle (
x, y,
x + std :: sin (firstAngle + rotate) * radius,
y + std :: cos (firstAngle + rotate) * radius,
x + std :: sin (secondAngle + rotate) * radius,
y + std :: cos (secondAngle + rotate) * radius
);
if (index % 2 )
g . PathFill (COLOR_RED);
else
g . PathFill ( pCaller -> mMouseInfo . ms . L ? COLOR_VIOLET : COLOR_BLUE);
}
},
1000 , // Animation duration
false // Loop animation
));
ILambdaControl allows completely custom drawing without creating a new control class.
Audio Processing for Visualization
The example generates test signals for visualizing controls:
void IPlugControls :: ProcessBlock ( sample ** inputs , sample ** outputs , int nFrames )
{
const double phaseIncr1 = ( 1. / GetSampleRate ()) * GetParam (kParamFreq1)-> Value ();
const double phaseIncr2 = ( 1. / GetSampleRate ()) * GetParam (kParamFreq2)-> Value ();
for ( int s = 0 ; s < nFrames; s ++ ) {
static double phase1 = 0. ;
static double phase2 = 0. ;
outputs [ 0 ][s] = cos (phase1 += phaseIncr1);
outputs [ 1 ][s] = sin (phase2 += phaseIncr2);
}
// Send data to UI controls
mDisplaySender . ProcessBlock (outputs, nFrames, kCtrlTagDisplay);
mScopeSender . ProcessBlock (outputs, nFrames, kCtrlTagScope);
mMeterSender . ProcessBlock (outputs, nFrames, kCtrlTagMeter);
mPeakAvgMeterSender . ProcessBlock (outputs, nFrames, kCtrlTagPeakAvgMeter);
// Store single value for RT text display
mLastOutputData . vals [ 0 ] = ( float ) outputs [ 0 ][ 0 ];
mRTTextSender . PushData (mLastOutputData);
// Zero outputs (visualization only)
for ( int s = 0 ; s < nFrames; s ++ ) {
outputs [ 0 ][s] = 0. ;
outputs [ 1 ][s] = 0. ;
}
}
Data Sender Classes
Different sender types for different visualization needs:
IBufferSender < 2 , kScopeBufferSize, kScopeBufferSize * 2 > mScopeSender;
IBufferSender < 1 > mDisplaySender;
IPeakSender < 2 > mMeterSender;
ISender < 1 > mRTTextSender;
IPeakAvgSender < 2 > mPeakAvgMeterSender { - 90.0 , true , 10.0 f , 5.0 f , 100.0 f , 1000.0 f };
IBufferSender Sends audio buffers for scope/waveform display
IPeakSender Sends peak values for simple meters
IPeakAvgSender Sends peak and average for professional meters
ISender Generic data sender for custom visualizations
Style Customization Panel
The example includes interactive style modification:
// Dynamic style sliders
for ( auto label : { "Widget Frac" , "Roundness" , "Shadow Offset" , "Frame Thickness" , "Angle" })
{
pGraphics -> AttachControl ( new IVSliderControl (
sameCell (). GetGridCell (slider, 0 , 5 , 1 ),
[ pGraphics , slider ]( IControl * pCaller ){
SplashClickActionFunc (pCaller);
pGraphics -> ForControlInGroup ( "vcontrols" , [ pCaller , slider ]( IControl * pControl ) {
IVectorBase * pVControl = pControl -> As < IVectorBase > ();
float val = static_cast < float > ( pCaller -> GetValue ());
switch (slider) {
case 0 : pVControl -> SetWidgetFrac (val); break ;
case 1 : pVControl -> SetRoundness (val); break ;
case 2 : pVControl -> SetShadowOffset (val * 5. f ); break ;
case 3 : pVControl -> SetFrameThickness (val * 5. f ); break ;
case 4 : pVControl -> SetAngle (val * 360. f ); break ;
default : break ;
}
});
},
label,
style,
true ,
EDirection ::Horizontal
));
slider ++ ;
}
The ForControlInGroup method allows batch operations on tagged controls.
Font Icons
The example demonstrates two icon fonts:
Fork Awesome Icons
#define ICON_FK_CHECK " \uf00c "
#define ICON_FK_SQUARE_O " \uf096 "
#define ICON_FK_CHECK_SQUARE " \uf14a "
#define ICON_FK_CIRCLE_O " \uf10c "
#define ICON_FK_CHECK_CIRCLE " \uf058 "
Fontaudio Icons
#define ICON_FAU_FILTER_LOWPASS " \ue900 "
#define ICON_FAU_FILTER_BANDPASS " \ue901 "
#define ICON_FAU_FILTER_HIGHPASS " \ue902 "
Key Takeaways
Control Variety Dozens of controls for every use case
Flexible Styling IVStyle allows comprehensive visual customization
Multiple Backends Bitmap, SVG, and vector rendering options
Realtime Data ISender classes for thread-safe visualization
Icon Fonts Font Awesome and Fontaudio for scalable icons
Interactive Testing Live style modification to preview changes
Next Steps
IGraphics Guide Learn UI construction in depth
IControl Reference Complete control API documentation
Custom Controls Create your own control classes