Put the chain first in the sidebar
The source images took the top of the sidebar and most of its height, which made the list of files look like the subject of the window rather than its input. The chain is what the interface is about, so it now comes first with the selected stage's params right below it, taking the free space; the sources sit at the bottom in a collapsed expander whose label carries the count, with their own "Add images" button instead of the one that used to be in the header bar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+64
-25
@@ -85,13 +85,6 @@ void EffectorWindow::buildUi() {
|
||||
menuButton_.set_popover(static_cast<Gtk::PopoverMenu&>(buildMainMenu()));
|
||||
header->pack_end(menuButton_);
|
||||
|
||||
auto* addButton = Gtk::make_managed<Gtk::Button>();
|
||||
addButton->set_icon_name("list-add-symbolic");
|
||||
addButton->set_tooltip_text("Add images");
|
||||
addButton->signal_clicked().connect(sigc::mem_fun(*this, &EffectorWindow::onAddImages));
|
||||
header->pack_start(*addButton);
|
||||
addButton_ = addButton;
|
||||
|
||||
saveButton_.set_sensitive(false);
|
||||
saveButton_.signal_clicked().connect(sigc::mem_fun(*this, &EffectorWindow::onSave));
|
||||
header->pack_end(saveButton_);
|
||||
@@ -120,24 +113,64 @@ void EffectorWindow::buildUi() {
|
||||
root->append(*paned);
|
||||
}
|
||||
|
||||
// The chain is what the interface is about, so it comes first and the params
|
||||
// of the selected stage sit right below it. The sources are a prerequisite,
|
||||
// not the subject: they live at the bottom in a collapsed expander.
|
||||
Gtk::Widget& EffectorWindow::buildSidebar() {
|
||||
auto* sidebar = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 12);
|
||||
sidebar->set_margin(12);
|
||||
|
||||
sidebar->append(*sectionLabel("Source images"));
|
||||
sidebar->append(buildChainSection());
|
||||
|
||||
paramHeading_.set_xalign(0.0F);
|
||||
paramHeading_.add_css_class("heading");
|
||||
sidebar->append(paramHeading_);
|
||||
paramGrid_.set_column_spacing(8);
|
||||
paramGrid_.set_row_spacing(6);
|
||||
auto* paramScroller = Gtk::make_managed<Gtk::ScrolledWindow>();
|
||||
paramScroller->set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC);
|
||||
paramScroller->set_child(paramGrid_);
|
||||
paramScroller->set_vexpand(true);
|
||||
sidebar->append(*paramScroller);
|
||||
rebuildChainRows();
|
||||
buildParamWidgets();
|
||||
|
||||
sidebar->append(*Gtk::make_managed<Gtk::Separator>(Gtk::Orientation::HORIZONTAL));
|
||||
|
||||
sourceList_.set_selection_mode(Gtk::SelectionMode::NONE);
|
||||
sourceList_.add_css_class("boxed-list");
|
||||
auto* empty = Gtk::make_managed<Gtk::Label>("No images yet");
|
||||
empty->set_margin_top(18);
|
||||
empty->set_margin_bottom(18);
|
||||
empty->set_margin_top(12);
|
||||
empty->set_margin_bottom(12);
|
||||
sourceList_.set_placeholder(*empty);
|
||||
|
||||
auto* scroller = Gtk::make_managed<Gtk::ScrolledWindow>();
|
||||
scroller->set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC);
|
||||
scroller->set_child(sourceList_);
|
||||
scroller->set_size_request(-1, 170);
|
||||
scroller->set_vexpand(true);
|
||||
sidebar->append(*scroller);
|
||||
scroller->set_size_request(-1, 140);
|
||||
scroller->set_margin_top(6);
|
||||
|
||||
auto* sourcesBox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
sourcesBox->append(*scroller);
|
||||
|
||||
// Same shape as "Add effect": the icon and the text are put together by
|
||||
// hand because set_label() and set_icon_name() replace one another.
|
||||
auto* addBox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 6);
|
||||
addBox->append(*Gtk::make_managed<Gtk::Image>(
|
||||
Gio::ThemedIcon::create("list-add-symbolic")));
|
||||
addBox->append(*Gtk::make_managed<Gtk::Label>("Add images"));
|
||||
auto* addButton = Gtk::make_managed<Gtk::Button>();
|
||||
addButton->set_child(*addBox);
|
||||
addButton->set_halign(Gtk::Align::START);
|
||||
addButton->set_tooltip_text("Add source images");
|
||||
addButton->signal_clicked().connect(sigc::mem_fun(*this, &EffectorWindow::onAddImages));
|
||||
sourcesBox->append(*addButton);
|
||||
addButton_ = addButton;
|
||||
|
||||
sourcesExpander_.set_child(*sourcesBox);
|
||||
sourcesExpander_.set_expanded(false);
|
||||
updateSourcesLabel();
|
||||
sidebar->append(sourcesExpander_);
|
||||
|
||||
sidebar->append(*sectionLabel("Canvas"));
|
||||
auto* grid = Gtk::make_managed<Gtk::Grid>();
|
||||
@@ -163,17 +196,6 @@ Gtk::Widget& EffectorWindow::buildSidebar() {
|
||||
grid->attach(heightSpin_, 1, 1);
|
||||
sidebar->append(*grid);
|
||||
|
||||
sidebar->append(buildChainSection());
|
||||
|
||||
paramHeading_.set_xalign(0.0F);
|
||||
paramHeading_.add_css_class("heading");
|
||||
sidebar->append(paramHeading_);
|
||||
paramGrid_.set_column_spacing(8);
|
||||
paramGrid_.set_row_spacing(6);
|
||||
sidebar->append(paramGrid_);
|
||||
rebuildChainRows();
|
||||
buildParamWidgets();
|
||||
|
||||
auto* seedBox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 8);
|
||||
auto* seedLabel = Gtk::make_managed<Gtk::Label>("Seed");
|
||||
seedLabel->set_xalign(0.0F);
|
||||
@@ -187,6 +209,15 @@ Gtk::Widget& EffectorWindow::buildSidebar() {
|
||||
return *sidebar;
|
||||
}
|
||||
|
||||
// The expander is collapsed by default, so its label carries the count that
|
||||
// used to be plain to see in the list.
|
||||
void EffectorWindow::updateSourcesLabel() {
|
||||
int count = 0;
|
||||
while (sourceList_.get_row_at_index(count) != nullptr) ++count;
|
||||
sourcesExpander_.set_label(count == 0 ? "Source images"
|
||||
: "Source images (" + std::to_string(count) + ")");
|
||||
}
|
||||
|
||||
Gtk::Widget& EffectorWindow::buildPreview() {
|
||||
picture_.set_can_shrink(true);
|
||||
picture_.set_content_fit(Gtk::ContentFit::CONTAIN);
|
||||
@@ -565,6 +596,7 @@ void EffectorWindow::appendSourceRow(const std::string& path) {
|
||||
|
||||
row->set_child(*box);
|
||||
sourceList_.append(*row);
|
||||
updateSourcesLabel();
|
||||
}
|
||||
|
||||
void EffectorWindow::removeSource(Gtk::ListBoxRow* row) {
|
||||
@@ -575,6 +607,7 @@ void EffectorWindow::removeSource(Gtk::ListBoxRow* row) {
|
||||
}
|
||||
});
|
||||
sourceList_.remove(*row);
|
||||
updateSourcesLabel();
|
||||
requestRender();
|
||||
}
|
||||
|
||||
@@ -622,7 +655,12 @@ Gtk::Widget& EffectorWindow::buildChainSection() {
|
||||
chainList_.set_placeholder(*empty);
|
||||
chainList_.signal_row_selected().connect(
|
||||
[this](Gtk::ListBoxRow*) { onStageSelected(); });
|
||||
box->append(chainList_);
|
||||
|
||||
auto* scroller = Gtk::make_managed<Gtk::ScrolledWindow>();
|
||||
scroller->set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC);
|
||||
scroller->set_child(chainList_);
|
||||
scroller->set_size_request(-1, 150);
|
||||
box->append(*scroller);
|
||||
|
||||
// set_label() and set_icon_name() replace one another, so the icon and the
|
||||
// text are put together by hand.
|
||||
@@ -995,6 +1033,7 @@ void EffectorWindow::applyProject(const Project& project, const std::string& pat
|
||||
|
||||
void EffectorWindow::clearSources() {
|
||||
while (auto* row = sourceList_.get_row_at_index(0)) sourceList_.remove(*row);
|
||||
updateSourcesLabel();
|
||||
mutateSources([](SourceList& list) { list.clear(); });
|
||||
loadQueue_.clear();
|
||||
if (loading_) dropLoadedImages_ = true;
|
||||
|
||||
@@ -48,6 +48,7 @@ private:
|
||||
void closeLoadWindow();
|
||||
void cancelLoad();
|
||||
void appendSourceRow(const std::string& path);
|
||||
void updateSourcesLabel(); // the collapsed expander shows the count
|
||||
void removeSource(Gtk::ListBoxRow* row);
|
||||
|
||||
Gtk::Widget& buildChainSection();
|
||||
@@ -139,6 +140,7 @@ private:
|
||||
std::unique_ptr<Gtk::Window> loadWindow_;
|
||||
Gtk::ProgressBar* loadBar_ = nullptr;
|
||||
Gtk::Label* loadFileLabel_ = nullptr;
|
||||
Gtk::Expander sourcesExpander_;
|
||||
Gtk::ListBox sourceList_;
|
||||
Gtk::SpinButton widthSpin_;
|
||||
Gtk::SpinButton heightSpin_;
|
||||
|
||||
Reference in New Issue
Block a user