Here is a function from Slayer that does this, minus the image part, but you can add that easily. This is not exactly what you need, but it will definitely get you started!
This is the starting GUI, with nothing added:
new GuiScrollCtrl() {
profile = "ColorScrollProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "120 45";
extent = "343 110";
minExtent = "8 2";
enabled = "1";
visible = "1";
clipToParent = "1";
willFirstRespond = "0";
hScrollBar = "alwaysOff";
vScrollBar = "alwaysOn";
constantThumbHeight = "0";
childMargin = "1 0";
rowHeight = "40";
columnWidth = "30";
new GuiSwatchCtrl(Slayer_Rules_Points) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "1 0";
extent = "337 3";
minExtent = "8 2";
enabled = "1";
visible = "1";
clipToParent = "1";
color = "0 0 0 0";
NTNameCount = "0";
};
};
This is the function that actually adds the list parts:
function SlayerClient_ServerPrefHandlerSO::addRule(%this,%category,%title,%type,%variable)
{
%gui = "Slayer_Rules_" @ %category; //%gui is a swatch control within a scroll control
if(!isObject(%gui))
return;
%value = SlayerClient_Support::getDynamicVariable(%variable);
if(%gui.getCount() <= 0)
%pos = "3 3"; //the first rule swatch has an offset of 3 on each side
else
%pos = 3 SPC getWord(%gui.getObject(%gui.getCount()-1).position,1) + getWord(%gui.getObject(%gui.getCount()-1).extent,1) + 3; //we want 3px space between each box
%ext = getWord(%gui.extent,0)-6 SPC 30;
%swatch = new GuiSwatchCtrl() //make the swatch
{
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = %pos;
extent = %ext;
minExtent = "8 2";
visible = "1";
color = "50 50 50 50";
};
%txt = new GuiMLTextCtrl() //let's add a title
{
profile = "Slayer_TextProfile";
horizSizing = "right";
vertSizing = "center";
position = "3 1"; //this is properly set below
extent = (getWord(%ext,0) / 3) - 10 SPC "14"; //the title takes up 1/3 of the rule swatch
minExtent = "8 2";
visible = "1";
lineSpacing = "2";
allowColorChars = "0";
maxChars = "-1";
text = %title;
maxBitmapHeight = "-1";
selectable = "1";
};
%swatch.add(%txt);
//let's determine how big the other control should be, since we already took 1/3 of the space for our title
%extX = getWord(%swatch.extent,0) - getWord(%txt.extent,0);
%pos = getWord(%swatch.extent,0) - %extX + 10 SPC 0;
%extX -= 15;
switch$(getWord(%type,0))
{
case string:
%ctrl = new GuiTextEditCtrl()
{
profile = "GuiTextEditProfile";
horizSizing = "right";
vertSizing = "center";
position = %pos;
extent = %extX SPC 18;
minExtent = "8 2";
visible = "1";
variable = %variable;
maxLength = getWord(%type,1);
historySize = "0";
password = "0";
tabComplete = "0";
sinkAllKeyEvents = "0";
};
//-----------------------------------------
//I snipped a bunch of stuff here to make this post shorter
}
%swatch.add(%ctrl);
%ctrl.setCenteredY();
%guiExtY = getWord(%gui.extent,1);
%swatchExtY = getWord(%swatch.extent,1);
%swatchPosY = getWord(%swatch.position,1);
%extX = getWord(%gui.extent,0);
%extY = %guiExtY + %swatchExtY + 3;
%gui.extent = %extX SPC %extY; //extend the master swatch to fit the new rule swatch
%gui.add(%swatch); //add the new rule swatch to the master swatch
%txt.forceReflow(); //make the text fit in the text box
%txt.setCenteredY();
%gui.setVisible(1); //refresh so that the scroll box works
return %swatch;
}
And here is the ::setCenteredY function used above:
function GuiControl::setCenteredY(%this)
{
%parent = %this.getGroup();
if(!isObject(%parent))
return;
%parExtY = getWord(%parent.getExtent(),1);
%extY = getWord(%this.getExtent(),1);
%posY = (%parExtY / 2) - (%extY / 2);
%this.position = getWord(%this.getPosition(),0) SPC %posY;
}
Edit: I forgot about the selection part...
To make it click-able, create a GuiBitmapButtonCtrl using the "base/client/ui/btnBlank" file. Then set it to the same size as the swatch and parent it.