示例#1
0
bool
KnobGui::isSecretRecursive() const
{
    // If the Knob is within a group, only show it if the group is unfolded!
    // To test it:
    // try TuttlePinning: fold all groups, then switch from perspective to affine to perspective.
    //  VISIBILITY is different from SECRETNESS. The code considers that both things are equivalent, which is wrong.
    // Of course, this check has to be *recursive* (in case the group is within a folded group)
    KnobPtr knob = getKnob();
    bool isViewerKnob = _imp->container->isInViewerUIKnob();
    bool showit = isViewerKnob ? !knob->getInViewerContextSecret() : !knob->getIsSecret();
    KnobPtr parentKnob = knob->getParentKnob();
    KnobGroup* parentIsGroup = dynamic_cast<KnobGroup*>( parentKnob.get() );

    while (showit && parentKnob && parentIsGroup) {
        KnobGuiGroup* parentGui = dynamic_cast<KnobGuiGroup*>( _imp->container->getKnobGui(parentKnob).get() );
        // check for secretness and visibility of the group
        bool parentSecret = isViewerKnob ? parentKnob->getInViewerContextSecret() : parentKnob->getIsSecret();
        if ( parentSecret || ( parentGui && !parentGui->isChecked() ) ) {
            showit = false; // one of the including groups is folder, so this item is hidden
        }
        // prepare for next loop iteration
        parentKnob = parentKnob->getParentKnob();
        parentIsGroup = dynamic_cast<KnobGroup*>( parentKnob.get() );
    }

    return !showit;
}
示例#2
0
void
KnobGui::setSecret()
{
    bool showit = !isSecretRecursive();

    if (showit) {
        show(); //
    } else {
        hide();
    }
    KnobGuiGroup* isGrp = dynamic_cast<KnobGuiGroup*>(this);
    if (isGrp) {
        const std::list<KnobGuiWPtr>& children = isGrp->getChildren();
        for (std::list<KnobGuiWPtr>::const_iterator it = children.begin(); it != children.end(); ++it) {
            KnobGuiPtr k = it->lock();
            if (!k) {
                continue;
            }
            k->setSecret();
        }
    }
}
KnobGuiPtr
DockablePanelPrivate::findKnobGuiOrCreate(const KnobPtr & knob,
                                          bool makeNewLine,
                                          QWidget* lastRowWidget,
                                          const std::vector< boost::shared_ptr< KnobI > > & knobsOnSameLine)
{
    assert(knob);
    boost::shared_ptr<KnobGroup> isGroup = boost::dynamic_pointer_cast<KnobGroup>(knob);
    boost::shared_ptr<KnobPage> isPage = boost::dynamic_pointer_cast<KnobPage>(knob);
    for (KnobsGuiMapping::const_iterator it = _knobs.begin(); it != _knobs.end(); ++it) {
        if ( (it->first.lock() == knob) && it->second ) {
            if (isPage) {
                return it->second;
            } else if ( isGroup && ( ( !isGroup->isTab() && it->second->hasWidgetBeenCreated() ) || isGroup->isTab() ) ) {
                return it->second;
            } else if ( it->second->hasWidgetBeenCreated() ) {
                return it->second;
            } else {
                break;
            }
        }
    }


    if (isPage) {
        if ( isPage->getChildren().empty() ) {
            return KnobGuiPtr();
        }
        getOrCreatePage(isPage);
        KnobsVec children = isPage->getChildren();
        initializeKnobVector(children, lastRowWidget);

        return KnobGuiPtr();
    }

    KnobGuiPtr ret = createKnobGui(knob);
    if (!ret) {
        return KnobGuiPtr();
    }

    KnobPtr parentKnob = knob->getParentKnob();
    boost::shared_ptr<KnobGroup> parentIsGroup = boost::dynamic_pointer_cast<KnobGroup>(parentKnob);
    KnobGuiGroup* parentGui = 0;
    /// if this knob is within a group, make sure the group is created so far
    if (parentIsGroup) {
        parentGui = dynamic_cast<KnobGuiGroup*>( findKnobGuiOrCreate( parentKnob, true, ret->getFieldContainer() ).get() );
    }

    ///So far the knob could have no parent, in which case we force it to be in the default page.
    if (!parentKnob) {
        boost::shared_ptr<KnobPage> defPage = ensureDefaultPageKnobCreated();
        defPage->addKnob(knob);
        parentKnob = defPage;
    }

    ///if widgets for the KnobGui have already been created, don't do the following
    ///For group only create the gui if it is not  a tab.
    if ( isGroup  && isGroup->isTab() ) {
        boost::shared_ptr<KnobPage> parentIsPage = boost::dynamic_pointer_cast<KnobPage>(parentKnob);
        if (!parentKnob || parentIsPage) {
            PageMap::iterator page = _pages.end();
            if (!parentKnob) {
                page = getDefaultPage(knob);
            } else {
                page = getOrCreatePage(parentIsPage);
            }
            bool existed = true;
            if (!page->second.groupAsTab) {
                existed = false;
                page->second.groupAsTab = new TabGroup(_publicInterface);
            }
            page->second.groupAsTab->addTab( isGroup, QString::fromUtf8( isGroup->getLabel().c_str() ) );

            ///retrieve the form layout
            QGridLayout* layout;
            if (_useScrollAreasForTabs) {
                layout = dynamic_cast<QGridLayout*>( dynamic_cast<QScrollArea*>(page->second.tab)->widget()->layout() );
            } else {
                layout = dynamic_cast<QGridLayout*>( page->second.tab->layout() );
            }
            assert(layout);
            if (!existed) {
                layout->addWidget(page->second.groupAsTab, page->second.currentRow, 0, 1, 2);
            }

            page->second.groupAsTab->refreshTabSecretNess( isGroup.get() );
        } else {
            assert(parentIsGroup);
            assert(parentGui);
            TabGroup* groupAsTab = parentGui->getOrCreateTabWidget();

            groupAsTab->addTab( isGroup, QString::fromUtf8( isGroup->getLabel().c_str() ) );

            if ( parentIsGroup && parentIsGroup->isTab() ) {
                ///insert the tab in the layout of the parent
                ///Find the page in the parentParent group
                KnobPtr parentParent = parentKnob->getParentKnob();
                assert(parentParent);
                boost::shared_ptr<KnobGroup> parentParentIsGroup = boost::dynamic_pointer_cast<KnobGroup>(parentParent);
                boost::shared_ptr<KnobPage> parentParentIsPage = boost::dynamic_pointer_cast<KnobPage>(parentParent);
                assert(parentParentIsGroup || parentParentIsPage);
                TabGroup* parentTabGroup = 0;
                if (parentParentIsPage) {
                    PageMap::iterator page = getOrCreatePage(parentParentIsPage);
                    assert( page != _pages.end() );
                    parentTabGroup = page->second.groupAsTab;
                } else {
                    KnobsGuiMapping::iterator it = findKnobGui(parentParent);
                    assert( it != _knobs.end() );
                    KnobGuiGroup* parentParentGroupGui = dynamic_cast<KnobGuiGroup*>( it->second.get() );
                    assert(parentParentGroupGui);
                    parentTabGroup = parentParentGroupGui->getOrCreateTabWidget();
                }

                QGridLayout* layout = parentTabGroup->addTab( parentIsGroup, QString::fromUtf8( parentIsGroup->getLabel().c_str() ) );
                assert(layout);
                layout->addWidget(groupAsTab, 0, 0, 1, 2);
            } else {
                boost::shared_ptr<KnobPage> topLevelPage = knob->getTopLevelPage();
                PageMap::iterator page = getOrCreatePage(topLevelPage);
                assert( page != _pages.end() );
                ///retrieve the form layout
                QGridLayout* layout;
                if (_useScrollAreasForTabs) {
                    layout = dynamic_cast<QGridLayout*>(
                        dynamic_cast<QScrollArea*>(page->second.tab)->widget()->layout() );
                } else {
                    layout = dynamic_cast<QGridLayout*>( page->second.tab->layout() );
                }
                assert(layout);

                layout->addWidget(groupAsTab, page->second.currentRow, 0, 1, 2);
            }
            groupAsTab->refreshTabSecretNess( isGroup.get() );
        }
    } else if ( !ret->hasWidgetBeenCreated() ) {
        KnobPtr parentKnobTmp = parentKnob;
        while (parentKnobTmp) {
            KnobPtr parent = parentKnobTmp->getParentKnob();
            if (!parent) {
                break;
            } else {
                parentKnobTmp = parent;
            }
        }

        ////find in which page the knob should be
        boost::shared_ptr<KnobPage> isTopLevelParentAPage = boost::dynamic_pointer_cast<KnobPage>(parentKnobTmp);
        assert(isTopLevelParentAPage);

        PageMap::iterator page = getOrCreatePage(isTopLevelParentAPage);
        assert( page != _pages.end() );

        ///retrieve the form layout
        QGridLayout* layout;
        if (_useScrollAreasForTabs) {
            layout = dynamic_cast<QGridLayout*>(
                dynamic_cast<QScrollArea*>(page->second.tab)->widget()->layout() );
        } else {
            layout = dynamic_cast<QGridLayout*>( page->second.tab->layout() );
        }
        assert(layout);


        ///if the knob has specified that it didn't want to trigger a new line, decrement the current row
        /// index of the tab

        if (!makeNewLine) {
            --page->second.currentRow;
        }

        QWidget* fieldContainer = 0;
        QHBoxLayout* fieldLayout = 0;

        if (makeNewLine) {
            ///if new line is not turned off, create a new line
            fieldContainer = new QWidget(page->second.tab);
            fieldLayout = new QHBoxLayout(fieldContainer);
            fieldLayout->setContentsMargins( TO_DPIX(3), 0, 0, TO_DPIY(NATRON_SETTINGS_VERTICAL_SPACING_PIXELS) );
            fieldLayout->setSpacing( TO_DPIY(2) );
            fieldLayout->setAlignment(Qt::AlignLeft);
        } else {
            ///otherwise re-use the last row's widget and layout
            assert(lastRowWidget);
            fieldContainer = lastRowWidget;
            fieldLayout = dynamic_cast<QHBoxLayout*>( fieldContainer->layout() );
        }

        assert(fieldContainer);
        assert(fieldLayout);

        ///Create the label if needed
        KnobClickableLabel* label = 0;
        Label* warningLabel = 0;
        std::string descriptionLabel;
        KnobString* isStringKnob = dynamic_cast<KnobString*>( knob.get() );
        bool isLabelKnob = isStringKnob && isStringKnob->isLabel();
        if (isLabelKnob) {
            descriptionLabel = isStringKnob->getValue();
        } else {
            descriptionLabel = knob->getLabel();
        }
        const std::string& labelIconFilePath = knob->getIconLabel();
        QWidget *labelContainer = 0;
        QHBoxLayout *labelLayout = 0;
        const bool hasLabel = ret->isLabelVisible() || isLabelKnob;
        if (hasLabel) {
            if (makeNewLine) {
                labelContainer = new QWidget(page->second.tab);
                labelLayout = new QHBoxLayout(labelContainer);
                labelLayout->setContentsMargins( TO_DPIX(3), 0, 0, TO_DPIY(NATRON_SETTINGS_VERTICAL_SPACING_PIXELS) );
                labelLayout->setSpacing( TO_DPIY(2) );
            }

            label = new KnobClickableLabel(QString(), ret, page->second.tab);
            warningLabel = new Label(page->second.tab);
            warningLabel->setVisible(false);
            QFontMetrics fm(label->font(), 0);
            int pixSize = fm.height();
            QPixmap stdErrorPix;
            stdErrorPix = getStandardIcon(QMessageBox::Critical, pixSize, label);
            warningLabel->setPixmap(stdErrorPix);

            bool pixmapSet = false;
            if ( !labelIconFilePath.empty() ) {
                QPixmap pix;

                if (labelIconFilePath == "dialog-warning") {
                    pix = getStandardIcon(QMessageBox::Warning, pixSize, label);
                } else if (labelIconFilePath == "dialog-question") {
                    pix = getStandardIcon(QMessageBox::Question, pixSize, label);
                } else if (labelIconFilePath == "dialog-error") {
                    pix = stdErrorPix;
                } else if (labelIconFilePath == "dialog-information") {
                    pix = getStandardIcon(QMessageBox::Information, pixSize, label);
                } else {
                    pix.load( QString::fromUtf8( labelIconFilePath.c_str() ) );
                    if (pix.width() != pixSize) {
                        pix = pix.scaled(pixSize, pixSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                    }
                }
                if ( !pix.isNull() ) {
                    pixmapSet = true;
                    label->setPixmap(pix);
                }
            }
            if (!pixmapSet) {
                QString labelStr( QString::fromUtf8( descriptionLabel.c_str() ) );
                /*labelStr += ":";*/
                if ( ret->isLabelBold() ) {
                    label->setBold(true);
                }
                label->setText_overload(labelStr );
            }
            QObject::connect( label, SIGNAL(clicked(bool)), ret.get(), SIGNAL(labelClicked(bool)) );


            if (makeNewLine) {
                labelLayout->addWidget(warningLabel);
                labelLayout->addWidget(label);
            }
        }

        /*
         * Find out in which layout the knob should be: either in the layout of the page or in the layout of
         * the nearest parent group tab in the hierarchy
         */
        boost::shared_ptr<KnobGroup> closestParentGroupTab;
        KnobPtr parentTmp = parentKnob;
        assert(parentKnobTmp);
        while (!closestParentGroupTab) {
            boost::shared_ptr<KnobGroup> parentGroup = boost::dynamic_pointer_cast<KnobGroup>(parentTmp);
            if ( parentGroup && parentGroup->isTab() ) {
                closestParentGroupTab = parentGroup;
            }
            parentTmp = parentTmp->getParentKnob();
            if (!parentTmp) {
                break;
            }
        }

        if (closestParentGroupTab) {
            /*
             * At this point we know that the parent group (which is a tab in the TabWidget) will have at least 1 knob
             * so ensure it is added to the TabWidget.
             * There are 2 possibilities, either the parent of the group tab is another group, in which case we have to
             * make sure the TabWidget is visible in the parent TabWidget of the group, otherwise we just add the TabWidget
             * to the on of the page.
             */

            KnobPtr parentParent = closestParentGroupTab->getParentKnob();
            KnobGroup* parentParentIsGroup = dynamic_cast<KnobGroup*>( parentParent.get() );
            boost::shared_ptr<KnobPage> parentParentIsPage = boost::dynamic_pointer_cast<KnobPage>(parentParent);

            assert(parentParentIsGroup || parentParentIsPage);
            if (parentParentIsGroup) {
                KnobGuiGroup* parentParentGroupGui = dynamic_cast<KnobGuiGroup*>( findKnobGuiOrCreate( parentParent, true,
                                                                                                       ret->getFieldContainer() ).get() );
                assert(parentParentGroupGui);
                if (parentParentGroupGui) {
                    TabGroup* groupAsTab = parentParentGroupGui->getOrCreateTabWidget();
                    assert(groupAsTab);
                    layout = groupAsTab->addTab( closestParentGroupTab, QString::fromUtf8( closestParentGroupTab->getLabel().c_str() ) );
                }
            } else if (parentParentIsPage) {
                PageMap::iterator page = getOrCreatePage(parentParentIsPage);
                assert( page != _pages.end() );
                assert(page->second.groupAsTab);
                layout = page->second.groupAsTab->addTab( closestParentGroupTab, QString::fromUtf8( closestParentGroupTab->getLabel().c_str() ) );
            }
            assert(layout);
        }

        ///fill the fieldLayout with the widgets
        ret->createGUI(layout, fieldContainer, labelContainer, label, warningLabel, fieldLayout, makeNewLine, knobsOnSameLine);


        ret->setEnabledSlot();

        ///Must add the row to the layout before calling setSecret()
        if (makeNewLine) {
            int rowIndex;
            if (closestParentGroupTab) {
                rowIndex = layout->rowCount();
            } else if ( parentGui && knob->isDynamicallyCreated() ) {
                const std::list<KnobGuiWPtr>& children = parentGui->getChildren();
                if ( children.empty() ) {
                    rowIndex = parentGui->getActualIndexInLayout();
                } else {
                    rowIndex = children.back().lock()->getActualIndexInLayout();
                }
                ++rowIndex;
            } else {
                rowIndex = page->second.currentRow;
            }


            const bool labelOnSameColumn = ret->isLabelOnSameColumn();


            if (!hasLabel) {
                layout->addWidget(fieldContainer, rowIndex, 0, 1, 2);
            } else {
                if (label) {
                    if (labelOnSameColumn) {
                        labelLayout->addWidget(fieldContainer);
                        layout->addWidget(labelContainer, rowIndex, 0, 1, 2);
                    } else {
                        layout->addWidget(labelContainer, rowIndex, 0, 1, 1, Qt::AlignRight);
                        layout->addWidget(fieldContainer, rowIndex, 1, 1, 1);
                    }
                }
            }


            //if (closestParentGroupTab) {
            ///See http://stackoverflow.com/questions/14033902/qt-qgridlayout-automatically-centers-moves-items-to-the-middle for
            ///a bug of QGridLayout: basically all items are centered, but we would like to add stretch in the bottom of the layout.
            ///To do this we add an empty widget with an expanding vertical size policy.
            /*QWidget* foundSpacer = 0;
               for (int i = 0; i < layout->rowCount(); ++i) {
                QLayoutItem* item = layout->itemAtPosition(i, 0);
                if (!item) {
                    continue;
                }
                QWidget* w = item->widget();
                if (!w) {
                    continue;
                }
                if (w->objectName() == QString::fromUtf8("emptyWidget")) {
                    foundSpacer = w;
                    break;
                }
               }
               if (foundSpacer) {
                layout->removeWidget(foundSpacer);
               } else {
                foundSpacer = new QWidget(layout->parentWidget());
                foundSpacer->setObjectName(QString::fromUtf8("emptyWidget"));
                foundSpacer->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

               }

               ///And add our stretch
               layout->addWidget(foundSpacer,layout->rowCount(), 0, 1, 2);*/
            // }
        } // makeNewLine

        ret->setSecret();

        if ( knob->isNewLineActivated() && ret->shouldAddStretch() ) {
            fieldLayout->addStretch();
        }


        ///increment the row count
        ++page->second.currentRow;

        if (parentIsGroup && parentGui) {
            parentGui->addKnob(ret);
        }
    } //  if ( !ret->hasWidgetBeenCreated() && ( !isGroup || !isGroup->isTab() ) ) {