diff --git a/src/cli/options.cpp b/src/cli/options.cpp index ac8437f..582e2ec 100644 --- a/src/cli/options.cpp +++ b/src/cli/options.cpp @@ -160,7 +160,6 @@ Options parseOptions(int argc, char** argv) { if (const auto* format = canvasFormatByKey(options.format)) { canvasFormatSize(*format, options.dpi, options.width, options.height); } - if (options.effects.empty()) options.effects.push_back(defaultEffectName()); return options; } @@ -169,7 +168,8 @@ std::string usage(const char* programName) { out << "Usage: " << programName << " [options] [image ...]\n\n" << "Image effects app. Runs the GTK interface unless --output is given.\n\n" << "Options:\n" - << " -e, --effect NAME effect to apply, repeat to cascade (default: " << defaultEffectName() << ")\n" + << " -e, --effect NAME effect to apply, repeat to cascade (--output" + " defaults to " << defaultEffectName() << ")\n" << " -o, --output FILE render headlessly to this file and exit\n" << " -s, --size WxH canvas size, each side " << kMinCanvasSide << "-" << kMaxCanvasSide << " (default: 1920x1080)\n" diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 59a53f3..355413d 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -49,7 +49,8 @@ EffectorWindow::EffectorWindow(const Options& initial) { set_default_size(1180, 760); effects_ = effects(); - stages_.push_back({effects_.front(), effects_.front()->defaults()}); + // The chain starts empty: the interface opens on "No effects yet" and the + // user picks the first stage, rather than being handed one at random. seed_ = Rng::randomSeed(); renderDone_.connect(sigc::mem_fun(*this, &EffectorWindow::onRenderFinished)); @@ -191,6 +192,15 @@ Gtk::Widget& EffectorWindow::buildSidebar() { return *sidebar; } +// Only the first stage is ever handed the sources, so whether the chain wants +// them at all is `chainNeedsSources`. An effect that starts from nothing (blur, +// text) makes the whole sources section beside the point, so it is hidden +// rather than left there to be filled in vain. This is the same declarative +// answer the render gate uses -- no effect is named here. +void EffectorWindow::updateSourcesVisible() { + sourcesExpander_.set_visible(chainNeedsSources(stages_)); +} + // 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() { @@ -952,6 +962,7 @@ void EffectorWindow::rebuildChainRows() { selectStage(selectedStage_); suspendStageSelect_ = false; + updateSourcesVisible(); } void EffectorWindow::selectStage(int index) { @@ -1242,9 +1253,7 @@ void EffectorWindow::clearSources() { } void EffectorWindow::onNewProject() { - Project fresh; - fresh.stages.push_back({effects_.front(), effects_.front()->defaults()}); - applyProject(fresh, ""); + applyProject(Project(), ""); // same empty chain the window opens with } void EffectorWindow::onOpenProject() { diff --git a/src/gui/window.hpp b/src/gui/window.hpp index 1deb21e..1a5cee9 100644 --- a/src/gui/window.hpp +++ b/src/gui/window.hpp @@ -49,6 +49,8 @@ private: void cancelLoad(); void appendSourceRow(const std::string& path); void updateSourcesLabel(); // the collapsed expander shows the count + // The whole sources section only shows while the chain asks for sources. + void updateSourcesVisible(); Gtk::Widget& buildCanvasSection(); // "" while "Custom" is picked, otherwise the format's key. diff --git a/src/main.cpp b/src/main.cpp index 79fe47c..fe5aa36 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,14 @@ namespace { int renderHeadless(const effector::Options& options) { - const auto stages = effector::buildChain(options); + auto stages = effector::buildChain(options); + // A headless run always renders something, so with no -e the default + // effect stands in. The interface has no such need: it opens on an empty + // chain and waits for the user to add the first stage. + if (stages.empty()) { + const auto effect = effector::effectByName(effector::defaultEffectName()); + stages.push_back({effect, effect->defaults()}); + } std::vector failures;