My hope is to have an expandable solution.
For example, if I also had a button that generated windows with gradient backgrounds - it would be nice to have them minimize to a second panel, while the solid backgrounds minimized to the first panel.
I forgot how to do this myself, so I made a quick mock-up of how to re-parent Views to do a “pop-out” / “minimize” behavior. I’m not totally sure what you’re going for, but this might be a starting point.
(
// Map of a view to it's container (a separate window or an "icon")
~iconViews = ();
~expandedViews = ();
~rootView = View(bounds:300@300).layout_(VLayout(
ToolBar(
~add = MenuAction("add"),
~collect = MenuAction("collect")
),
View().layout_(
~iconLayout = VLayout().spacing_(8);
),
nil
));
// Function to take a view and pop it out into a separate window
~expandView = {
|view|
var windowView;
windowView = View(bounds:200@200).front;
windowView.layout_(VLayout(
view
));
view.visible = true;
// track new view
~expandedViews[view] = windowView;
// remove old view
~iconViews[view].remove;
~iconViews[view] = nil;
};
// Function to take a view, put it inside of an "icon"
// with the same background color, and place it in the main
// window.
~collectView = {
|view|
var iconView;
iconView = View().minSize_(64@64);
iconView.background = view.background;
iconView.layout_(HLayout(
view
).spacing_(0).margins_(0));
// When we click an icon, expand its view.
iconView.mouseUpAction = { ~expandView.(view) };
~iconLayout.add(iconView);
// HIDE our view when it's in icon mode but keep it's state.
// Commenting this out also works, the view will continue to be
// visible when in the main window.
view.visible = false;
// track new icon
~iconViews[view] = iconView;
// remove old expanded window
~expandedViews[view].remove;
~expandedViews[view] = nil;
};
// Make some random knobs in a view.
~add.action = {
var newView;
newView = View().background_(Color.rand);
newView.layout_(VLayout(
Knob(),
Knob(),
Knob(),
));
~expandView.(newView);
};
// Find all expanded views and call ~collectView on them.
~collect.action = {
~expandedViews.keys.do {
|view|
view.postln;
~collectView.(view)
}
};
~rootView.front;
)
Here’s a version of this I like better, where views minimize to a toolbar button (with a colored icon), and the toolbar buttons that have a drop-down menu that actually show the original UI.
Also, a cute trick is to replace the colored icon on the iconView with a screenshot of the actual view you’re minimizing:
(
// Map of a view to it's container (a separate window or an "icon")
~iconViews = ();
~expandedViews = ();
~rootView = View(bounds:300@300).layout_(VLayout(
ToolBar(
~add = MenuAction("add"),
~collect = MenuAction("collect"),
),
View().layout_(
~iconLayout = VLayout().spacing_(8);
),
nil
));
// Function to take a view and pop it out into a separate window
~expandView = {
|view|
var windowView;
windowView = View(bounds:200@200).front;
windowView.layout_(VLayout(
view
));
view.visible = true;
// track new view
~expandedViews[view] = windowView;
// remove old view
~iconViews[view].remove;
~iconViews[view] = nil;
};
// Function to take a view, put it inside of an "icon"
// with the same background color, and place it in the main
// window.
~collectView = {
|view|
var iconView;
iconView = ToolBar().minSize_(64@64);
iconView.addAction(
MenuAction()
.action_({ ~expandView.(view) })
.icon_(Image.color(64, 64, view.background))
.menu_(Menu(view.asMenuAction))
);
// When we click an icon, expand its view.
iconView.mouseUpAction = { ~expandView.(view) };
~iconLayout.add(iconView);
// HIDE our view when it's in icon mode but keep it's state.
// Commenting this out also works, the view will continue to be
// visible when in the main window.
view.visible = false;
// track new icon
~iconViews[view] = iconView;
// remove old expanded window
~expandedViews[view].remove;
~expandedViews[view] = nil;
};
// Make some random knobs in a view.
~add.action = {
var newView;
newView = View().background_(Color.rand);
newView.layout_(VLayout(
Knob(),
Knob(),
Knob(),
));
~expandView.(newView);
};
// Find all expanded views and call ~collectView on them.
~collect.action = {
~expandedViews.keys.do {
|view|
view.postln;
~collectView.(view)
}
};
~rootView.front;
)
Not to push my luck too much, but is there a straightforward way to collect the icons with GridLayout instead of VLayout?
I’m new to Layout Management in SuperCollider and having a little trouble understanding the documentation.
Definitely - I originally wrote the example with GridLayout, but I switched it because it requires a couple of extra tricky things that made it more convoluted as example code.
Other than actually switching the VLayout for GridLayout, the only thing you’ll have to change: the add method of GridLayout requires that you specify a row and column, so instead of ~iconLayout.add(iconView), you’ll need ~iconLayout.add(iconView, row, col); - and you’ll need to keep track of these row and column numbers yourself. I think you can probably just use ~iconViews.size to calculate what the next empty row+column combination is.