/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . * * 2024-2024 Daniel Gao */ #include "framing.h" #include "aspectratios.h" #include "paramsedited.h" #include "resize.h" #include "../rtengine/procparams.h" #include #include #include namespace { using namespace rtengine; using rtengine::procparams::FramingParams; constexpr int EMPTY_COMBO_INDEX = -1; // Framing method combo box data constexpr int INDEX_STANDARD = 0; constexpr int INDEX_BBOX = 1; constexpr int INDEX_FIXED = 2; constexpr int INDEX_FRAMING_METHOD_UNCHANGED = 3; constexpr std::array FRAMING_METHODS = { "TP_FRAMING_METHOD_STANDARD", "TP_FRAMING_METHOD_BBOX", "TP_FRAMING_METHOD_FIXED" }; int mapFramingMethod(FramingParams::FramingMethod framingMethod) { using FramingMethod = FramingParams::FramingMethod; switch (framingMethod) { case FramingMethod::STANDARD: return INDEX_STANDARD; case FramingMethod::BBOX: return INDEX_BBOX; case FramingMethod::FIXED_SIZE: return INDEX_FIXED; default: return INDEX_STANDARD; } } FramingParams::FramingMethod mapFramingMethod(int comboIndex) { using FramingMethod = FramingParams::FramingMethod; switch (comboIndex) { case INDEX_STANDARD: return FramingMethod::STANDARD; case INDEX_BBOX: return FramingMethod::BBOX; case INDEX_FIXED: return FramingMethod::FIXED_SIZE; default: return FramingMethod::STANDARD; } } // Orientation combo box data constexpr int INDEX_AS_IMAGE = 0; constexpr int INDEX_LANDSCAPE = 1; constexpr int INDEX_PORTRAIT = 2; constexpr int INDEX_ORIENTATION_UNCHANGED = 3; constexpr std::array ORIENTATION = { "GENERAL_ASIMAGE", "GENERAL_LANDSCAPE", "GENERAL_PORTRAIT" }; int mapOrientation(FramingParams::Orientation orientation) { using Orientation = FramingParams::Orientation; switch (orientation) { case Orientation::AS_IMAGE: return INDEX_AS_IMAGE; case Orientation::LANDSCAPE: return INDEX_LANDSCAPE; case Orientation::PORTRAIT: return INDEX_PORTRAIT; default: return INDEX_AS_IMAGE; } } FramingParams::Orientation mapOrientation(int comboIndex) { using Orientation = FramingParams::Orientation; switch (comboIndex) { case INDEX_AS_IMAGE: return Orientation::AS_IMAGE; case INDEX_LANDSCAPE: return Orientation::LANDSCAPE; case INDEX_PORTRAIT: return Orientation::PORTRAIT; default: return Orientation::AS_IMAGE; } } // Border sizing method combo box data constexpr int INDEX_SIZE_RELATIVE = 0; constexpr int INDEX_SIZE_ABSOLUTE = 1; constexpr int INDEX_SIZE_UNCHANGED = 2; constexpr std::array BORDER_SIZE_METHODS = { "TP_FRAMING_BORDER_SIZE_RELATIVE", "TP_FRAMING_BORDER_SIZE_ABSOLUTE" }; int mapBorderSizeMethod(FramingParams::BorderSizing sizing) { using BorderSizing = FramingParams::BorderSizing; switch (sizing) { case BorderSizing::PERCENTAGE: return INDEX_SIZE_RELATIVE; case BorderSizing::FIXED_SIZE: return INDEX_SIZE_ABSOLUTE; default: return INDEX_SIZE_RELATIVE; } } FramingParams::BorderSizing mapBorderSizeMethod(int comboIndex) { using BorderSizing = FramingParams::BorderSizing; switch (comboIndex) { case INDEX_SIZE_RELATIVE: return BorderSizing::PERCENTAGE; case INDEX_SIZE_ABSOLUTE: return BorderSizing::FIXED_SIZE; default: return BorderSizing::PERCENTAGE; } } // Relative sizing basis combo box data constexpr int INDEX_BASIS_AUTO = 0; constexpr int INDEX_BASIS_WIDTH = 1; constexpr int INDEX_BASIS_HEIGHT = 2; constexpr int INDEX_BASIS_LONG = 3; constexpr int INDEX_BASIS_SHORT = 4; constexpr int INDEX_BASIS_UNCHANGED = 5; constexpr std::array BORDER_SIZE_BASIS = { "TP_FRAMING_BASIS_AUTO", "TP_FRAMING_BASIS_WIDTH", "TP_FRAMING_BASIS_HEIGHT", "TP_FRAMING_BASIS_LONG_SIDE", "TP_FRAMING_BASIS_SHORT_SIDE" }; int mapBasis(FramingParams::Basis basis) { using Basis = FramingParams::Basis; switch(basis) { case Basis::AUTO: return INDEX_BASIS_AUTO; case Basis::WIDTH: return INDEX_BASIS_WIDTH; case Basis::HEIGHT: return INDEX_BASIS_HEIGHT; case Basis::LONG: return INDEX_BASIS_LONG; case Basis::SHORT: return INDEX_BASIS_SHORT; default: return INDEX_BASIS_AUTO; } } FramingParams::Basis mapBasis(int comboIndex) { using Basis = FramingParams::Basis; switch(comboIndex) { case INDEX_BASIS_AUTO: return Basis::AUTO; case INDEX_BASIS_WIDTH: return Basis::WIDTH; case INDEX_BASIS_HEIGHT: return Basis::HEIGHT; case INDEX_BASIS_LONG: return Basis::LONG; case INDEX_BASIS_SHORT: return Basis::SHORT; default: return Basis::AUTO; } } constexpr int INITIAL_IMG_WIDTH = 100000; constexpr int INITIAL_IMG_HEIGHT = 100000; constexpr int ROW_SPACING = 4; constexpr float FRAME_LABEL_ALIGN_X = 0.025; constexpr float FRAME_LABEL_ALIGN_Y = 0.5; Gtk::Label* createGridLabel(const char* text) { Gtk::Label* label = Gtk::manage(new Gtk::Label(M(text))); label->set_halign(Gtk::ALIGN_START); return label; } MySpinButton* createSpinButton() { MySpinButton* button = Gtk::manage(new MySpinButton()); button->set_width_chars(5); button->set_digits(0); button->set_increments(1, 100); setExpandAlignProperties(button, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER); return button; } } // namespace const Glib::ustring Framing::TOOL_NAME = "framing"; class Framing::AspectRatios { public: static constexpr int INDEX_CURRENT = 0; AspectRatios() : ratios{{M("GENERAL_CURRENT")}} { fillAspectRatios(ratios); } void fillCombo(MyComboBoxText* combo) const { for (const auto& aspectRatio : ratios) { combo->append(aspectRatio.label); } combo->set_active(INDEX_CURRENT); } int unchangedIndex() const { return ratios.size(); } double value(int index) const { return ratios.at(index).value; } int findIndex(double aspectRatio) const { if (aspectRatio == FramingParams::AS_IMAGE_ASPECT_RATIO) return INDEX_CURRENT; for (size_t i = 1; i < ratios.size(); i++) { if (ratios[i].value == aspectRatio) return i; } // Couldn't find a matching value return INDEX_CURRENT; } private: std::vector ratios; }; Framing::DimensionGui::DimensionGui(Gtk::Box* parent, const char* text) { box = Gtk::manage(new Gtk::Box()); Gtk::Label* label = Gtk::manage(new Gtk::Label(M(text))); setExpandAlignProperties(label, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); value = createSpinButton(); box->pack_start(*label); box->pack_start(*value); parent->pack_start(*box); } void Framing::DimensionGui::connect(Framing& framing, CallbackFunc callback) { connection = value->signal_value_changed().connect(sigc::mem_fun(framing, callback), true); } Framing::Framing() : FoldableToolPanel(this, TOOL_NAME, M("TP_FRAMING_LABEL"), false, true), aspectRatioData(new AspectRatios), imgWidth(INITIAL_IMG_WIDTH), imgHeight(INITIAL_IMG_HEIGHT), lastAllowUpscaling(false), lastMinSizeEnabled(false) { setupFramingMethodGui(); pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL))); setupBorderSizeGui(); pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL))); setupBorderColorsGui(); } Framing::~Framing() { idleRegister.destroy(); } void Framing::setupFramingMethodGui() { Gtk::Grid* combos = Gtk::manage(new Gtk::Grid()); combos->set_row_spacing(ROW_SPACING); framingMethod = Gtk::manage(new MyComboBoxText()); for (auto label : FRAMING_METHODS) { framingMethod->append(M(label)); } framingMethod->set_active(INDEX_STANDARD); framingMethod->set_hexpand(); framingMethod->set_halign(Gtk::ALIGN_FILL); combos->attach(*createGridLabel("TP_FRAMING_METHOD"), 0, 0); combos->attach(*framingMethod, 1, 0); aspectRatioLabel = createGridLabel("TP_FRAMING_ASPECT_RATIO"); aspectRatio = Gtk::manage(new MyComboBoxText()); aspectRatioData->fillCombo(aspectRatio); aspectRatio->set_hexpand(); aspectRatio->set_halign(Gtk::ALIGN_FILL); combos->attach(*aspectRatioLabel, 0, 1); combos->attach(*aspectRatio, 1, 1); orientationLabel = createGridLabel("TP_FRAMING_ORIENTATION"); orientation = Gtk::manage(new MyComboBoxText()); for (auto label : ORIENTATION) { orientation->append(M(label)); } orientation->set_active(INDEX_AS_IMAGE); orientation->set_hexpand(); orientation->set_halign(Gtk::ALIGN_FILL); combos->attach(*orientationLabel, 0, 2); combos->attach(*orientation, 1, 2); pack_start(*combos); width = DimensionGui(this, "TP_FRAMING_FRAMED_WIDTH"); width.setRange(Resize::MIN_SIZE, Resize::MAX_SCALE * imgWidth); width.setValue(imgWidth); height = DimensionGui(this, "TP_FRAMING_FRAMED_HEIGHT"); height.setRange(Resize::MIN_SIZE, Resize::MAX_SCALE * imgHeight); height.setValue(imgHeight); allowUpscaling = Gtk::manage(new Gtk::CheckButton(M("TP_FRAMING_ALLOW_UPSCALING"))); pack_start(*allowUpscaling); updateFramingMethodGui(); framingMethodChanged = framingMethod->signal_changed().connect( sigc::mem_fun(*this, &Framing::onFramingMethodChanged)); aspectRatioChanged = aspectRatio->signal_changed().connect( sigc::mem_fun(*this, &Framing::onAspectRatioChanged)); orientationChanged = orientation->signal_changed().connect( sigc::mem_fun(*this, &Framing::onOrientationChanged)); width.connect(*this, &Framing::onWidthChanged); height.connect(*this, &Framing::onHeightChanged); allowUpscalingConnection = allowUpscaling->signal_toggled().connect( sigc::mem_fun(*this, &Framing::onAllowUpscalingToggled)); } void Framing::setupBorderSizeGui() { Gtk::Grid* combos = Gtk::manage(new Gtk::Grid()); combos->set_row_spacing(ROW_SPACING); borderSizeMethod = Gtk::manage(new MyComboBoxText()); for (auto label : BORDER_SIZE_METHODS) { borderSizeMethod->append(M(label)); } borderSizeMethod->set_active(INDEX_SIZE_RELATIVE); borderSizeMethod->set_hexpand(); borderSizeMethod->set_halign(Gtk::ALIGN_FILL); combos->attach(*createGridLabel("TP_FRAMING_BORDER_SIZE_METHOD"), 0, 0); combos->attach(*borderSizeMethod, 1, 0); basisLabel = createGridLabel("TP_FRAMING_BASIS"); basis = Gtk::manage(new MyComboBoxText()); for (auto label : BORDER_SIZE_BASIS) { basis->append(M(label)); } basis->set_active(INDEX_BASIS_AUTO); basis->set_hexpand(); basis->set_halign(Gtk::ALIGN_FILL); combos->attach(*basisLabel, 0, 1); combos->attach(*basis, 1, 1); pack_start(*combos); relativeBorderSize = Gtk::manage(new Adjuster(M("TP_FRAMING_BORDER_SIZE"), 0, 1, 0.01, 0.1)); pack_start(*relativeBorderSize); minSizeFrame = Gtk::manage(new Gtk::Frame()); minSizeFrame->set_label_align(FRAME_LABEL_ALIGN_X, FRAME_LABEL_ALIGN_Y); minSizeEnabled = Gtk::manage(new Gtk::CheckButton(M("TP_FRAMING_LIMIT_MINIMUM"))); minSizeFrame->set_label_widget(*minSizeEnabled); minSizeFrameContent = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); minWidth = DimensionGui(minSizeFrameContent, "TP_FRAMING_MIN_WIDTH"); minWidth.setRange(0, imgWidth); minWidth.setValue(0); minHeight = DimensionGui(minSizeFrameContent, "TP_FRAMING_MIN_HEIGHT"); minHeight.setRange(0, imgHeight); minHeight.setValue(0); minSizeFrame->add(*minSizeFrameContent); pack_start(*minSizeFrame); absWidth = DimensionGui(this, "TP_FRAMING_ABSOLUTE_WIDTH"); absWidth.setRange(0, imgWidth); absWidth.setValue(0); absHeight = DimensionGui(this, "TP_FRAMING_ABSOLUTE_HEIGHT"); absHeight.setRange(0, imgHeight); absHeight.setValue(0); updateBorderSizeGui(); borderSizeMethodChanged = borderSizeMethod->signal_changed().connect( sigc::mem_fun(*this, &Framing::onBorderSizeMethodChanged)); basisChanged = basis->signal_changed().connect( sigc::mem_fun(*this, &Framing::onBasisChanged)); relativeBorderSize->setAdjusterListener(this); minSizeEnabledConnection = minSizeEnabled->signal_toggled().connect( sigc::mem_fun(*this, &Framing::onMinSizeToggled)); minWidth.connect(*this, &Framing::onMinWidthChanged); minHeight.connect(*this, &Framing::onMinHeightChanged); absWidth.connect(*this, &Framing::onAbsWidthChanged); absHeight.connect(*this, &Framing::onAbsHeightChanged); } void Framing::setupBorderColorsGui() { Gtk::Frame* const frame = Gtk::manage(new Gtk::Frame()); Gtk::Label* const label = Gtk::manage(new Gtk::Label(M("TP_FRAMING_BORDER_COLOR"))); frame->set_label_align(FRAME_LABEL_ALIGN_X, FRAME_LABEL_ALIGN_Y); frame->set_label_widget(*label); Gtk::Box* const box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); redAdj = Gtk::manage(new Adjuster(M("TP_FRAMING_RED"), 0, 65535, 1, 65535)); box->add(*redAdj); greenAdj = Gtk::manage(new Adjuster(M("TP_FRAMING_GREEN"), 0, 65535, 1, 65535)); box->add(*greenAdj); blueAdj = Gtk::manage(new Adjuster(M("TP_FRAMING_BLUE"), 0, 65535, 1, 65535)); box->add(*blueAdj); frame->add(*box); pack_start(*frame); redAdj->setAdjusterListener(this); greenAdj->setAdjusterListener(this); blueAdj->setAdjusterListener(this); } void Framing::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { DisableListener disableListener(this); std::array blockers = { ConnectionBlocker(framingMethodChanged), ConnectionBlocker(aspectRatioChanged), ConnectionBlocker(orientationChanged), ConnectionBlocker(width.connection), ConnectionBlocker(height.connection), ConnectionBlocker(allowUpscalingConnection), ConnectionBlocker(borderSizeMethodChanged), ConnectionBlocker(basisChanged), ConnectionBlocker(minSizeEnabledConnection), ConnectionBlocker(minWidth.connection), ConnectionBlocker(minHeight.connection), ConnectionBlocker(absWidth.connection), ConnectionBlocker(absHeight.connection) }; BlockAdjusterEvents blockRelative(relativeBorderSize); BlockAdjusterEvents blockRed(redAdj); BlockAdjusterEvents blockGreen(greenAdj); BlockAdjusterEvents blockBlue(blueAdj); readParams(pp); readEdited(pedited); updateFramingMethodGui(); updateBorderSizeGui(); setDimensions(); } void Framing::readParams(const rtengine::procparams::ProcParams* pp) { const rtengine::procparams::FramingParams& params = pp->framing; setEnabled(params.enabled); framingMethod->set_active(mapFramingMethod(params.framingMethod)); aspectRatio->set_active(aspectRatioData->findIndex(params.aspectRatio)); orientation->set_active(mapOrientation(params.orientation)); width.setValue(params.framedWidth); width.isDirty = false; height.setValue(params.framedHeight); height.isDirty = false; allowUpscaling->set_active(params.allowUpscaling); lastAllowUpscaling = params.allowUpscaling; borderSizeMethod->set_active(mapBorderSizeMethod(params.borderSizingMethod)); basis->set_active(mapBasis(params.basis)); relativeBorderSize->setValue(params.relativeBorderSize); minSizeEnabled->set_active(params.minSizeEnabled); lastMinSizeEnabled = params.minSizeEnabled; minWidth.setValue(params.minWidth); minWidth.isDirty = false; minHeight.setValue(params.minHeight); minHeight.isDirty = false; absWidth.setValue(params.absWidth); absWidth.isDirty = false; absHeight.setValue(params.absHeight); absHeight.isDirty = false; redAdj->setValue(params.borderRed); greenAdj->setValue(params.borderGreen); blueAdj->setValue(params.borderBlue); } void Framing::readEdited(const ParamsEdited* pedited) { if (!pedited) return; const FramingParamsEdited& edits = pedited->framing; set_inconsistent(multiImage && !edits.enabled); if (!edits.framingMethod) { framingMethod->set_active(EMPTY_COMBO_INDEX); } if (!edits.aspectRatio) { aspectRatio->set_active(EMPTY_COMBO_INDEX); } if (!edits.orientation) { orientation->set_active(EMPTY_COMBO_INDEX); } width.isDirty = edits.framedWidth; height.isDirty = edits.framedHeight; allowUpscaling->set_inconsistent(edits.allowUpscaling); if (!edits.borderSizingMethod) { borderSizeMethod->set_active(EMPTY_COMBO_INDEX); } if (!edits.basis) { basis->set_active(EMPTY_COMBO_INDEX); } relativeBorderSize->setEditedState(edits.relativeBorderSize ? Edited : UnEdited); minSizeEnabled->set_inconsistent(edits.minSizeEnabled); minWidth.isDirty = edits.minWidth; minHeight.isDirty = edits.minHeight; absWidth.isDirty = edits.absWidth; absHeight.isDirty = edits.absHeight; redAdj->setEditedState(edits.borderRed ? Edited : UnEdited); greenAdj->setEditedState(edits.borderGreen ? Edited : UnEdited); blueAdj->setEditedState(edits.borderBlue ? Edited : UnEdited); } void Framing::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { writeParams(pp); writeEdited(pedited); } void Framing::writeParams(rtengine::procparams::ProcParams* pp) { rtengine::procparams::FramingParams& params = pp->framing; params.enabled = getEnabled(); params.framingMethod = mapFramingMethod(framingMethod->get_active_row_number()); params.aspectRatio = aspectRatioData->value(aspectRatio->get_active_row_number()); params.orientation = mapOrientation(orientation->get_active_row_number()); params.framedWidth = width.value->get_value_as_int(); params.framedHeight = height.value->get_value_as_int(); params.allowUpscaling = allowUpscaling->get_active(); params.borderSizingMethod = mapBorderSizeMethod(borderSizeMethod->get_active_row_number()); params.basis = mapBasis(basis->get_active_row_number()); params.relativeBorderSize = relativeBorderSize->getValue(); params.minSizeEnabled = minSizeEnabled->get_active(); params.minWidth = minWidth.value->get_value_as_int(); params.minHeight = minHeight.value->get_value_as_int(); params.absWidth = absWidth.value->get_value_as_int(); params.absHeight = absHeight.value->get_value_as_int(); params.borderRed = redAdj->getValue(); params.borderGreen = greenAdj->getValue(); params.borderBlue = blueAdj->getValue(); } void Framing::writeEdited(ParamsEdited* pedited) { if (!pedited) return; FramingParamsEdited& edits = pedited->framing; edits.enabled = !get_inconsistent(); edits.framingMethod = framingMethod->get_active_row_number() != INDEX_FRAMING_METHOD_UNCHANGED; edits.aspectRatio = aspectRatio->get_active_row_number() != aspectRatioData->unchangedIndex(); edits.orientation = orientation->get_active_row_number() != INDEX_ORIENTATION_UNCHANGED; edits.framedWidth = width.isDirty; edits.framedHeight = height.isDirty; edits.allowUpscaling = !allowUpscaling->get_inconsistent(); edits.borderSizingMethod = borderSizeMethod->get_active_row_number() != INDEX_SIZE_UNCHANGED; edits.basis = basis->get_active_row_number() != INDEX_BASIS_UNCHANGED; edits.relativeBorderSize = relativeBorderSize->getEditedState(); edits.minSizeEnabled = !minSizeEnabled->get_inconsistent(); edits.minWidth = minWidth.isDirty; edits.minHeight = minHeight.isDirty; edits.absWidth = absWidth.isDirty; edits.absHeight = absHeight.isDirty; edits.borderRed = redAdj->getEditedState(); edits.borderGreen = greenAdj->getEditedState(); edits.borderBlue = blueAdj->getEditedState(); } void Framing::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) { const FramingParams& params = defParams->framing; relativeBorderSize->setDefault(params.relativeBorderSize); redAdj->setDefault(params.borderRed); greenAdj->setDefault(params.borderGreen); blueAdj->setDefault(params.borderBlue); if (pedited) { const FramingParamsEdited& edits = pedited->framing; relativeBorderSize->setDefaultEditedState(edits.relativeBorderSize ? Edited : UnEdited); redAdj->setDefaultEditedState(edits.borderRed ? Edited : UnEdited); greenAdj->setDefaultEditedState(edits.borderGreen ? Edited : UnEdited); blueAdj->setDefaultEditedState(edits.borderBlue ? Edited : UnEdited); } else { relativeBorderSize->setDefaultEditedState(Irrelevant); redAdj->setDefaultEditedState(Irrelevant); greenAdj->setDefaultEditedState(Irrelevant); blueAdj->setDefaultEditedState(Irrelevant); } } void Framing::trimValues(rtengine::procparams::ProcParams* pp) { relativeBorderSize->trimValue(pp->framing.relativeBorderSize); redAdj->trimValue(pp->framing.borderRed); greenAdj->trimValue(pp->framing.borderGreen); blueAdj->trimValue(pp->framing.borderBlue); } void Framing::setBatchMode(bool batchMode) { framingMethod->append(M("GENERAL_UNCHANGED")); aspectRatio->append(M("GENERAL_UNCHANGED")); orientation->append(M("GENERAL_UNCHANGED")); borderSizeMethod->append(M("GENERAL_UNCHANGED")); basis->append(M("GENERAL_UNCHANGED")); ToolPanel::setBatchMode(batchMode); relativeBorderSize->showEditedCB(); redAdj->showEditedCB(); greenAdj->showEditedCB(); blueAdj->showEditedCB(); } void Framing::enabledChanged() { if (listener) { if (get_inconsistent()) { listener->panelChanged(EvFramingEnabled, M("GENERAL_UNCHANGED")); } else if (getEnabled()) { listener->panelChanged(EvFramingEnabled, M("GENERAL_ENABLED")); } else { listener->panelChanged(EvFramingEnabled, M("GENERAL_DISABLED")); } } } void Framing::update(int originalWidth, int originalHeight) { // This is how it is checked in resize.cc if (originalWidth && originalHeight) { imgWidth = originalWidth; imgHeight = originalHeight; } } void Framing::setAdjusterBehavior(bool addRelativeBorderSize, bool addRed, bool addGreen, bool addBlue) { relativeBorderSize->setAddMode(addRelativeBorderSize); redAdj->setAddMode(addRed); greenAdj->setAddMode(addGreen); blueAdj->setAddMode(addBlue); } void Framing::setDimensions() { idleRegister.add([this]() -> bool { std::array blockers = { ConnectionBlocker(width.connection), ConnectionBlocker(height.connection), ConnectionBlocker(minWidth.connection), ConnectionBlocker(minHeight.connection), ConnectionBlocker(absWidth.connection), ConnectionBlocker(absHeight.connection) }; // 16x the full image size is probably a reasonable max width.value->set_range(Resize::MIN_SIZE, Resize::MAX_SCALE * imgWidth); height.value->set_range(Resize::MIN_SIZE, Resize::MAX_SCALE * imgHeight); minWidth.value->set_range(0, Resize::MAX_SCALE * imgWidth); minHeight.value->set_range(0, Resize::MAX_SCALE * imgHeight); absWidth.value->set_range(0, Resize::MAX_SCALE * imgWidth); absHeight.value->set_range(0, Resize::MAX_SCALE * imgHeight); return false; }); } void Framing::updateFramingMethodGui() { if (batchMode) { aspectRatioLabel->show(); aspectRatio->show(); orientationLabel->show(); orientation->show(); width.show(); height.show(); allowUpscaling->show(); return; } int activeRow = framingMethod->get_active_row_number(); if (activeRow == INDEX_STANDARD) { aspectRatioLabel->show(); aspectRatio->show(); orientationLabel->show(); orientation->show(); width.hide(); height.hide(); allowUpscaling->hide(); } else if (activeRow == INDEX_BBOX) { aspectRatioLabel->show(); aspectRatio->show(); orientationLabel->show(); orientation->show(); width.show(); height.show(); allowUpscaling->show(); } else if (activeRow == INDEX_FIXED) { aspectRatioLabel->hide(); aspectRatio->hide(); orientationLabel->hide(); orientation->hide(); width.show(); height.show(); allowUpscaling->show(); } } void Framing::updateBorderSizeGui() { if (batchMode) { basisLabel->show(); basis->show(); relativeBorderSize->show(); minSizeFrame->show(); absWidth.show(); absHeight.show(); aspectRatio->set_sensitive(true); orientation->set_sensitive(true); minSizeFrameContent->set_sensitive(true); return; } int activeRow = borderSizeMethod->get_active_row_number(); if (activeRow == INDEX_SIZE_RELATIVE) { basisLabel->show(); basis->show(); relativeBorderSize->show(); minSizeFrame->show(); absWidth.hide(); absHeight.hide(); aspectRatio->set_sensitive(true); orientation->set_sensitive(true); } else if (activeRow == INDEX_SIZE_ABSOLUTE) { basisLabel->hide(); basis->hide(); relativeBorderSize->hide(); minSizeFrame->hide(); absWidth.show(); absHeight.show(); aspectRatio->set_sensitive(false); orientation->set_sensitive(false); } minSizeFrameContent->set_sensitive(minSizeEnabled->get_active()); } void Framing::adjusterChanged(Adjuster* adj, double newVal) { if (listener && (getEnabled() || batchMode)) { Glib::ustring costr; if (adj == relativeBorderSize) { costr = Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), adj->getValue()); } else { costr = Glib::ustring::format(static_cast(adj->getValue())); } if (adj == relativeBorderSize) { listener->panelChanged(EvFramingRelativeBorderSize, costr); } else if (adj == redAdj) { listener->panelChanged(EvFramingBorderRed, costr); } else if (adj == greenAdj) { listener->panelChanged(EvFramingBorderGreen, costr); } else if (adj == blueAdj) { listener->panelChanged(EvFramingBorderBlue, costr); } } } void Framing::onFramingMethodChanged() { updateFramingMethodGui(); if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingMethod, framingMethod->get_active_text()); } } void Framing::onAspectRatioChanged() { if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingAspectRatio, aspectRatio->get_active_text()); } } void Framing::onOrientationChanged() { if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingOrientation, orientation->get_active_text()); } } void Framing::onWidthChanged() { width.isDirty = true; if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingFramedWidth, Glib::ustring::format(width.value->get_value_as_int())); } } void Framing::onHeightChanged() { height.isDirty = true; if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingFramedHeight, Glib::ustring::format(height.value->get_value_as_int())); } } void Framing::onAllowUpscalingToggled() { if (batchMode) { if (allowUpscaling->get_inconsistent()) { allowUpscaling->set_inconsistent(false); ConnectionBlocker block(allowUpscalingConnection); allowUpscaling->set_active(false); } else if (lastAllowUpscaling) { allowUpscaling->set_inconsistent(true); } lastAllowUpscaling = allowUpscaling->get_active(); } if (listener && (getEnabled() || batchMode)) { if (allowUpscaling->get_inconsistent()) { listener->panelChanged(EvFramingAllowUpscaling, M("GENERAL_UNCHANGED")); } else if (allowUpscaling->get_active()) { listener->panelChanged(EvFramingAllowUpscaling, M("GENERAL_ENABLED")); } else { listener->panelChanged(EvFramingAllowUpscaling, M("GENERAL_DISABLED")); } } } void Framing::onBorderSizeMethodChanged() { updateBorderSizeGui(); if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingBorderSizingMethod, borderSizeMethod->get_active_text()); } } void Framing::onBasisChanged() { if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingBasis, basis->get_active_text()); } } void Framing::onMinSizeToggled() { if (batchMode) { if (minSizeEnabled->get_inconsistent()) { minSizeEnabled->set_inconsistent(false); ConnectionBlocker block(minSizeEnabledConnection); minSizeEnabled->set_active(false); } else if (lastMinSizeEnabled) { minSizeEnabled->set_inconsistent(true); } lastMinSizeEnabled = minSizeEnabled->get_active(); } updateBorderSizeGui(); if (listener && (getEnabled() || batchMode)) { if (minSizeEnabled->get_inconsistent()) { listener->panelChanged(EvFramingMinSizeEnabled, M("GENERAL_UNCHANGED")); } else if (minSizeEnabled->get_active()) { listener->panelChanged(EvFramingMinSizeEnabled, M("GENERAL_ENABLED")); } else { listener->panelChanged(EvFramingMinSizeEnabled, M("GENERAL_DISABLED")); } } } void Framing::onMinWidthChanged() { minWidth.isDirty = true; if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingMinWidth, Glib::ustring::format(minWidth.value->get_value_as_int())); } } void Framing::onMinHeightChanged() { minHeight.isDirty = true; if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingMinHeight, Glib::ustring::format(minHeight.value->get_value_as_int())); } } void Framing::onAbsWidthChanged() { absWidth.isDirty = true; if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingAbsWidth, Glib::ustring::format(absWidth.value->get_value_as_int())); } } void Framing::onAbsHeightChanged() { absHeight.isDirty = true; if (listener && (getEnabled() || batchMode)) { listener->panelChanged(EvFramingAbsHeight, Glib::ustring::format(absHeight.value->get_value_as_int())); } }