AnimItemDimViewKeyFrame
AnimationModuleViewPrivate::isNearbyKeyFrame(const ZoomContext& ctx, const QPoint & pt) const
{
    AnimItemDimViewKeyFrame ret;
    
    std::vector<CurveGuiPtr> curves = getVisibleCurves();

    for (std::vector<CurveGuiPtr>::const_iterator it = curves.begin(); it != curves.end(); ++it) {

        KeyFrameSet set = (*it)->getKeyFrames();

        for (KeyFrameSet::const_iterator it2 = set.begin(); it2 != set.end(); ++it2) {
            QPointF keyFramewidgetPos = ctx.toWidgetCoordinates( it2->getTime(), it2->getValue() );
            if ( (std::abs( pt.y() - keyFramewidgetPos.y() ) < TO_DPIX(CLICK_DISTANCE_TOLERANCE)) &&
                (std::abs( pt.x() - keyFramewidgetPos.x() ) < TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) {
                
                ret.key.key = *it2;
                StringAnimationManagerPtr stringAnim = (*it)->getItem()->getInternalAnimItem()->getStringAnimation();
                if (stringAnim) {
                    stringAnim->stringFromInterpolatedIndex(it2->getValue(), (*it)->getView(), &ret.key.string);
                }
                ret.id = (*it)->getCurveID();
                
                return ret;
            }
           
        }

    } // for all curves
    return ret;
} // CurveWidgetPrivate::isNearbyKeyFrame
Пример #2
0
void
KnobGuiColor::addExtraWidgets(QHBoxLayout* containerLayout)
{
    containerLayout->addSpacing( TO_DPIX(10) );
    KnobColorPtr knob = _knob.lock();
    if (!knob) {
        return;
    }
    KnobGuiPtr knobUI = getKnobGui();
    if (!knobUI) {
        return;
    }
    _colorLabel = new ColorPickerLabel( _useSimplifiedUI, knobUI->getLayoutType(), this, containerLayout->widget() );
    if (!_useSimplifiedUI && knobUI->getLayoutType() != KnobGui::eKnobLayoutTypeTableItemWidget) {
        _colorLabel->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("To pick a color on a viewer, click this and then press control + left click on any viewer.\n"
                                                                   "You can also pick the average color of a given rectangle by holding control + shift + left click\n. "
                                                                   "To deselect the picker left click anywhere."
                                                                   "Note that by default %1 converts to linear the color picked\n"
                                                                   "because all the processing pipeline is linear, but you can turn this off in the\n"
                                                                   "preferences panel.").arg( QString::fromUtf8(NATRON_APPLICATION_NAME) ), NATRON_NAMESPACE::WhiteSpaceNormal) );
    }

    QSize medSize( TO_DPIX(NATRON_MEDIUM_BUTTON_SIZE), TO_DPIY(NATRON_MEDIUM_BUTTON_SIZE) );
    QSize medIconSize( TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE), TO_DPIY(NATRON_MEDIUM_BUTTON_ICON_SIZE) );

    _colorLabel->setFixedSize(medSize);
    QObject::connect( _colorLabel, SIGNAL(pickingEnabled(bool)), this, SLOT(onColorLabelPickingEnabled(bool)) );
    containerLayout->addWidget(_colorLabel);

    if (_useSimplifiedUI) {
        containerLayout->addSpacing( TO_DPIX(5) );
    }

    if (knobUI->getLayoutType() != KnobGui::eKnobLayoutTypeTableItemWidget) {
        QPixmap buttonPix;
        appPTR->getIcon(NATRON_PIXMAP_COLORWHEEL, NATRON_MEDIUM_BUTTON_ICON_SIZE, &buttonPix);
        _colorDialogButton = new Button( QIcon(buttonPix), QString(), containerLayout->widget() );
        _colorDialogButton->setFixedSize(medSize);
        _colorDialogButton->setIconSize(medIconSize);
        _colorDialogButton->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("Open the color dialog."), NATRON_NAMESPACE::WhiteSpaceNormal) );
        _colorDialogButton->setFocusPolicy(Qt::NoFocus);
        QObject::connect( _colorDialogButton, SIGNAL(clicked()), this, SLOT(showColorDialog()) );
        containerLayout->addWidget(_colorDialogButton);
    }
    if (_useSimplifiedUI) {
        setWidgetsVisibleInternal(false);
        KnobGuiWidgets::enableRightClickMenu(getKnobGui(), _colorLabel, DimSpec::all(), getView());
    }
}
Пример #3
0
SpinBox::SpinBox(QWidget* parent,
                 SpinBoxTypeEnum type)
    : LineEdit(parent)
    , ignoreWheelEvent(false)
    , _imp( new SpinBoxPrivate(type) )
{
    QObject::connect( this, SIGNAL(returnPressed()), this, SLOT(interpretReturn()) );

    setValue(0);
    setMaximumWidth( TO_DPIX(SPINBOX_MAX_WIDTH) );
    setMinimumWidth( TO_DPIX(SPINBOX_MIN_WIDTH) );
    setFocusPolicy(Qt::WheelFocus); // mouse wheel gives focus too - see also SpinBox::focusInEvent()
    decimals(_imp->decimals);

    setType(type);
}
CurveGuiPtr
AnimationModuleViewPrivate::isNearbyCurve(const QPoint &pt, double* x, double *y) const
{
    QPointF curvePos = curveEditorZoomContext.toZoomCoordinates( pt.x(), pt.y() );

    std::vector<CurveGuiPtr> curves = getVisibleCurves();

    for (std::vector<CurveGuiPtr>::const_iterator it = curves.begin(); it != curves.end(); ++it) {

        AnimItemBasePtr item = (*it)->getItem();
        double yCurve = 0;
        
        try {
            yCurve = item->evaluateCurve( true /*useExpression*/, curvePos.x(), (*it)->getDimension(), (*it)->getView());
        } catch (...) {
        }
        
        double yWidget = curveEditorZoomContext.toWidgetCoordinates(0, yCurve).y();
        if ( (pt.y() < yWidget + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) && (pt.y() > yWidget - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) {
            if (x != NULL) {
                *x = curvePos.x();
            }
            if (y != NULL) {
                *y = yCurve;
            }
            
            return *it;
        }
    }

    return CurveGuiPtr();
} // isNearbyCurve
Пример #5
0
void
BackdropGuiPrivate::refreshLabelText(int nameHeight,
                                     const QString &text)
{
    QString textLabel = text;

    textLabel.replace( QString::fromUtf8("\n"), QString::fromUtf8("<br>") );
    textLabel.prepend( QString::fromUtf8("<div align=\"left\">") );
    textLabel.append( QString::fromUtf8("</div>") );
    QFont f;
    QColor color;
    if ( !text.isEmpty() ) {
        KnobGuiString::parseFont(textLabel, &f, &color);
        bool antialias = appPTR->getCurrentSettings()->isNodeGraphAntiAliasingEnabled();
        if (!antialias) {
            f.setStyleStrategy(QFont::NoAntialias);
        }
        label->setFont(f);
    }

    label->setHtml(textLabel);


    QRectF bbox = _publicInterface->boundingRect();

    //label->adjustSize();
    int w = std::max( bbox.width(), label->textWidth() * 1.2 );
    QRectF labelBbox = label->boundingRect();
    int h = std::max( labelBbox.height() + nameHeight + TO_DPIX(10), bbox.height() );
    _publicInterface->resize(w, h);
    _publicInterface->update();
}
Пример #6
0
void
BackdropGui::getInitialSize(int *w,
                            int *h) const
{
    *w = TO_DPIX(NATRON_BACKDROP_DEFAULT_WIDTH);
    *h = TO_DPIY(NATRON_BACKDROP_DEFAULT_HEIGHT);
}
Пример #7
0
QIcon
PropertiesBinWrapper::getIcon() const
{
    int iconSize = TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE);
    QPixmap p;
    appPTR->getIcon(NATRON_PIXMAP_PROPERTIES_PANEL, iconSize, &p);
    return QIcon(p);
}
Пример #8
0
QIcon
ViewerTab::getIcon() const
{
    int iconSize = TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE);
    QPixmap p;
    appPTR->getIcon(NATRON_PIXMAP_VIEWER_PANEL, iconSize, &p);
    return QIcon(p);
}
Пример #9
0
QIcon
ProgressPanel::getIcon() const
{
    int iconSize = TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE);
    QPixmap p;
    appPTR->getIcon(NATRON_PIXMAP_PROGRESS_PANEL, iconSize, &p);
    return QIcon(p);
}
AnimItemDimViewKeyFrame
AnimationModuleViewPrivate::isNearbyKeyFrameText(const QPoint& pt) const
{
    AnimItemDimViewKeyFrame ret;
    
    QFontMetrics fm( _publicInterface->font() );
    int yOffset = TO_DPIY(4);
    AnimationModuleBasePtr model = _model.lock();
    const AnimItemDimViewKeyFramesMap& selectedKeys = model->getSelectionModel()->getCurrentKeyFramesSelection();
    if (selectedKeys.empty() || selectedKeys.size() > 1) {
        return ret;
    }

    AnimItemDimViewKeyFramesMap::const_iterator curveIT = selectedKeys.begin();
    const KeyFrameWithStringSet& keys = curveIT->second;
    if (keys.empty() || keys.size() > 1) {
        return ret;
    }

    const KeyFrameWithString& key = *keys.begin();


    QPointF topLeftWidget = curveEditorZoomContext.toWidgetCoordinates( key.key.getTime(), key.key.getValue() );
    topLeftWidget.ry() += yOffset;

    QString coordStr =  QString::fromUtf8("x: %1, y: %2").arg( key.key.getTime() ).arg( key.key.getValue() );
    QPointF btmRightWidget( topLeftWidget.x() + fm.width(coordStr), topLeftWidget.y() + fm.height() );

    if ( (pt.x() >= topLeftWidget.x() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) && (pt.x() <= btmRightWidget.x() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) &&
        ( pt.y() >= topLeftWidget.y() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) && ( pt.y() <= btmRightWidget.y() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) {
        ret.key.key = key.key;
        StringAnimationManagerPtr stringAnim = curveIT->first.item->getInternalAnimItem()->getStringAnimation();
        if (stringAnim) {
            stringAnim->stringFromInterpolatedIndex(key.key.getValue(), curveIT->first.view, &ret.key.string);
        }
        ret.id = curveIT->first;

        return ret;
    }


    return ret;
}
std::pair<MoveTangentCommand::SelectedTangentEnum, AnimItemDimViewKeyFrame >
AnimationModuleViewPrivate::isNearbyTangent(const QPoint & pt) const
{
    
    std::pair<MoveTangentCommand::SelectedTangentEnum, AnimItemDimViewKeyFrame > ret;

    std::vector<CurveGuiPtr> curves = getVisibleCurves();

    for (std::vector<CurveGuiPtr>::const_iterator it = curves.begin(); it != curves.end(); ++it) {


        KeyFrameSet set = (*it)->getKeyFrames();
        
        for (KeyFrameSet::const_iterator it2 = set.begin(); it2 != set.end(); ++it2) {
            
            QPointF leftTanPos, rightTanPos;
            _publicInterface->getKeyTangentPoints(it2, set, &leftTanPos, &rightTanPos);
            QPointF leftTanPt = curveEditorZoomContext.toWidgetCoordinates(leftTanPos.x(), leftTanPos.y());
            QPointF rightTanPt = curveEditorZoomContext.toWidgetCoordinates( rightTanPos.x(), rightTanPos.y());
            if ( ( pt.x() >= (leftTanPt.x() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) &&
                ( pt.x() <= (leftTanPt.x() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) &&
                ( pt.y() <= (leftTanPt.y() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) &&
                ( pt.y() >= (leftTanPt.y() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) ) {
                
                ret.second.key.key = *it2;
                StringAnimationManagerPtr stringAnim = (*it)->getItem()->getInternalAnimItem()->getStringAnimation();
                if (stringAnim) {
                    stringAnim->stringFromInterpolatedIndex(it2->getValue(), (*it)->getView(), &ret.second.key.string);
                }
                ret.second.id = (*it)->getCurveID();
                ret.first = MoveTangentCommand::eSelectedTangentLeft;
                return ret;
            } else if ( ( pt.x() >= (rightTanPt.x() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) &&
                       ( pt.x() <= (rightTanPt.x() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) &&
                       ( pt.y() <= (rightTanPt.y() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) &&
                       ( pt.y() >= (rightTanPt.y() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) ) {
                ret.second.key.key = *it2;
                StringAnimationManagerPtr stringAnim = (*it)->getItem()->getInternalAnimItem()->getStringAnimation();
                if (stringAnim) {
                    stringAnim->stringFromInterpolatedIndex(it2->getValue(), (*it)->getView(), &ret.second.key.string);
                }
                ret.second.id = (*it)->getCurveID();
                ret.first = MoveTangentCommand::eSelectedTangentRight;
                return ret;
            }
        }
        
    } // for all curves
    return ret;
    
}
Пример #12
0
GeneralProgressDialog::GeneralProgressDialog(const QString& title, bool canCancel, QWidget* parent)
: QDialog(parent, Qt::WindowStaysOnTopHint)
, _imp(new GeneralProgressDialogPrivate(canCancel))
{
    setModal(false);
    setWindowTitle(tr("Progress"));
    
    assert(QThread::currentThread() == qApp->thread());
    
    _imp->mainLayout = new QVBoxLayout(this);
    _imp->descLabel = new Label(title,this);
    
    _imp->mainLayout->addWidget(_imp->descLabel);
    
    _imp->progressContainer = new QWidget(this);
    _imp->progressLayout = new QHBoxLayout(_imp->progressContainer);
    _imp->progressLayout->setContentsMargins(0, 0, 0, 0);
    _imp->mainLayout->addWidget(_imp->progressContainer);

    _imp->timeRemainingLabel = new Label(tr("Time to go:") + ' ' + tr("Estimating..."),_imp->progressContainer);
    _imp->progressLayout->addWidget(_imp->timeRemainingLabel);
    
    
    _imp->buttonsContainer = new QWidget(this);
    _imp->buttonsLayout = new QHBoxLayout(_imp->buttonsContainer);
    _imp->mainLayout->addWidget(_imp->buttonsContainer);

    
    _imp->progressBar = new QProgressBar(_imp->buttonsContainer);
    _imp->progressBar->setRange(0, 100);
    _imp->progressBar->setValue(0);
    _imp->buttonsLayout->addWidget(_imp->progressBar);
    
    if (canCancel) {
        
        _imp->cancelButton = new Button(QIcon(), tr("Cancel"), this);
        QObject::connect(_imp->cancelButton, SIGNAL(clicked(bool)), this, SLOT(onCancelRequested()));
        _imp->buttonsLayout->addWidget(_imp->cancelButton);
    }
    
    _imp->mainLayout->addStretch();
    
    onRefreshLabelTimeout();
    _imp->refreshLabelTimer.start(NATRON_PROGRESS_DIALOG_ETA_REFRESH_MS);
    QObject::connect(&_imp->refreshLabelTimer, SIGNAL(timeout()), this, SLOT(onRefreshLabelTimeout()));
    
    setMinimumWidth(TO_DPIX(400));

}
Пример #13
0
PreferencesPanel::PreferencesPanel(boost::shared_ptr<Settings> settings,
                                   Gui *parent)
    : QWidget(parent)
    , _gui(parent)
    , _settings(settings)
    , _changedKnobs()
    , _closeIsOK(false)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

    setWindowFlags(Qt::Window);
    setWindowTitle( tr("Preferences") );
    _mainLayout = new QVBoxLayout(this);
    _mainLayout->setContentsMargins(0, 0, 0, 0);
    _mainLayout->setSpacing(0);

    _panel = new DockablePanel(_gui, _settings.get(), _mainLayout, DockablePanel::eHeaderModeNoHeader, true, boost::shared_ptr<QUndoStack>(), QString(), QString(), false, QString(), this);
    _panel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    _mainLayout->addWidget(_panel);

    _buttonBox = new QDialogButtonBox(Qt::Horizontal);
    _restoreDefaultsB = new Button( tr("Restore defaults") );
    _restoreDefaultsB->setToolTip( GuiUtils::convertFromPlainText(tr("Restore default values for all preferences."), Qt::WhiteSpaceNormal) );

    _prefsHelp = new Button( tr("Help") );
    _prefsHelp->setToolTip( tr("Show help for preference") );

    _cancelB = new Button( tr("Discard") );
    _cancelB->setToolTip( GuiUtils::convertFromPlainText(tr("Cancel changes that were not saved and close the window."), Qt::WhiteSpaceNormal) );
    _okB = new Button( tr("Save") );
    _okB->setToolTip( GuiUtils::convertFromPlainText(tr("Save changes on disk and close the window."), Qt::WhiteSpaceNormal) );
    _buttonBox->addButton(_restoreDefaultsB, QDialogButtonBox::ResetRole);
    _buttonBox->addButton(_prefsHelp, QDialogButtonBox::ResetRole);
    _buttonBox->addButton(_cancelB, QDialogButtonBox::RejectRole);
    _buttonBox->addButton(_okB, QDialogButtonBox::AcceptRole);

    // _mainLayout->addStretch();
    _mainLayout->addWidget(_buttonBox);

    QObject::connect( _restoreDefaultsB, SIGNAL(clicked()), this, SLOT(restoreDefaults()) );
    QObject::connect( _prefsHelp, SIGNAL(clicked()), this, SLOT(openHelp()) );
    QObject::connect( _buttonBox, SIGNAL(rejected()), this, SLOT(cancelChanges()) );
    QObject::connect( _buttonBox, SIGNAL(accepted()), this, SLOT(saveChangesAndClose()) );
    QObject::connect( _settings.get(), SIGNAL(settingChanged(KnobI*)), this, SLOT(onSettingChanged(KnobI*)) );

    _panel->initializeKnobs();

    resize( TO_DPIX(900), TO_DPIY(600) );
}
Пример #14
0
void
GuiPrivate::createPropertiesBinGui()
{
    _propertiesBin = new PropertiesBinWrapper(kPropertiesBinName, _gui);
    _propertiesBin->setLabel( tr("Properties").toStdString() );

    QVBoxLayout* mainPropertiesLayout = new QVBoxLayout(_propertiesBin);
    mainPropertiesLayout->setContentsMargins(0, 0, 0, 0);
    mainPropertiesLayout->setSpacing(0);

    _propertiesScrollArea = new QScrollArea(_propertiesBin);

    ///Remove wheel autofocus
    _propertiesScrollArea->setFocusPolicy(Qt::StrongFocus);
    QObject::connect( _propertiesScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), _gui, SLOT(onPropertiesScrolled()) );
    _propertiesScrollArea->setObjectName( QString::fromUtf8("Properties") );
    assert(_nodeGraphArea);

    _propertiesContainer = new QWidget(_propertiesScrollArea);
    _propertiesContainer->setObjectName( QString::fromUtf8("_propertiesContainer") );
    _layoutPropertiesBin = new QVBoxLayout(_propertiesContainer);
    _layoutPropertiesBin->setSpacing(0);
    _layoutPropertiesBin->setContentsMargins(0, 0, 0, 0);
    _propertiesContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    _propertiesScrollArea->setWidget(_propertiesContainer);
    _propertiesScrollArea->setWidgetResizable(true);

    QWidget* propertiesAreaButtonsContainer = new QWidget(_propertiesBin);
    QHBoxLayout* propertiesAreaButtonsLayout = new QHBoxLayout(propertiesAreaButtonsContainer);
    propertiesAreaButtonsLayout->setContentsMargins(0, 0, 0, 0);
    propertiesAreaButtonsLayout->setSpacing(5);
    QPixmap closePanelPix;
    int smallSizeIcon = TO_DPIX(NATRON_SMALL_BUTTON_ICON_SIZE);
    appPTR->getIcon(NATRON_PIXMAP_CLOSE_PANEL, smallSizeIcon, &closePanelPix);
    _clearAllPanelsButton = new Button(QIcon(closePanelPix), QString(), propertiesAreaButtonsContainer);

    const QSize smallButtonSize( TO_DPIX(NATRON_SMALL_BUTTON_SIZE), TO_DPIY(NATRON_SMALL_BUTTON_SIZE) );
    const QSize smallButtonIconSize( TO_DPIX(NATRON_SMALL_BUTTON_ICON_SIZE), TO_DPIY(NATRON_SMALL_BUTTON_ICON_SIZE) );

    _clearAllPanelsButton->setFixedSize(smallButtonSize);
    _clearAllPanelsButton->setIconSize(smallButtonIconSize);
    _clearAllPanelsButton->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("Clears all the panels in the properties bin pane."),
                                                                      NATRON_NAMESPACE::WhiteSpaceNormal) );
    _clearAllPanelsButton->setFocusPolicy(Qt::NoFocus);
    QObject::connect( _clearAllPanelsButton, SIGNAL(clicked(bool)), _gui, SLOT(clearAllVisiblePanels()) );
    QPixmap minimizePix, maximizePix;
    appPTR->getIcon(NATRON_PIXMAP_MINIMIZE_WIDGET, smallSizeIcon, &minimizePix);
    appPTR->getIcon(NATRON_PIXMAP_MAXIMIZE_WIDGET, smallSizeIcon, &maximizePix);
    QIcon mIc;
    mIc.addPixmap(minimizePix, QIcon::Normal, QIcon::On);
    mIc.addPixmap(maximizePix, QIcon::Normal, QIcon::Off);
    _minimizeAllPanelsButtons = new Button(mIc, QString(), propertiesAreaButtonsContainer);
    _minimizeAllPanelsButtons->setCheckable(true);
    _minimizeAllPanelsButtons->setChecked(false);
    _minimizeAllPanelsButtons->setFixedSize(smallButtonSize);
    _minimizeAllPanelsButtons->setIconSize(smallButtonIconSize);
    _minimizeAllPanelsButtons->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("Minimize / Maximize all panels."), NATRON_NAMESPACE::WhiteSpaceNormal) );
    _minimizeAllPanelsButtons->setFocusPolicy(Qt::NoFocus);
    QObject::connect( _minimizeAllPanelsButtons, SIGNAL(clicked(bool)), _gui, SLOT(minimizeMaximizeAllPanels(bool)) );

    _maxPanelsOpenedSpinBox = new SpinBox(propertiesAreaButtonsContainer);
    _maxPanelsOpenedSpinBox->setMaximumSize(smallButtonSize);
    _maxPanelsOpenedSpinBox->setMinimum(1);
    _maxPanelsOpenedSpinBox->setMaximum(100);
    _maxPanelsOpenedSpinBox->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("Set the maximum of panels that can be opened at the same time "
                                                                           "in the properties bin pane. The special value of 0 indicates "
                                                                           "that an unlimited number of panels can be opened."),
                                                                        NATRON_NAMESPACE::WhiteSpaceNormal) );
    _maxPanelsOpenedSpinBox->setValue( appPTR->getCurrentSettings()->getMaxPanelsOpened() );
    QObject::connect( _maxPanelsOpenedSpinBox, SIGNAL(valueChanged(double)), _gui, SLOT(onMaxPanelsSpinBoxValueChanged(double)) );

    propertiesAreaButtonsLayout->addWidget(_maxPanelsOpenedSpinBox);
    propertiesAreaButtonsLayout->addWidget(_clearAllPanelsButton);
    propertiesAreaButtonsLayout->addWidget(_minimizeAllPanelsButtons);
    propertiesAreaButtonsLayout->addStretch();

    mainPropertiesLayout->addWidget(propertiesAreaButtonsContainer);
    mainPropertiesLayout->addWidget(_propertiesScrollArea);

    _propertiesBin->setVisible(false);
} // createPropertiesBinGui
Пример #15
0
void
ScaleSliderQWidget::paintEvent(QPaintEvent* /*e*/)
{
    if (_imp->mustInitializeSliderPosition) {
        if (_imp->minimum < _imp->maximum) {
            centerOn(_imp->minimum, _imp->maximum);
        }
        _imp->mustInitializeSliderPosition = false;
        seekScalePosition(_imp->value);
        _imp->initialized = true;
    }

    ///fill the background with the appropriate style color
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    p.setOpacity(1);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);

    double txtR, txtG, txtB;
    if (_imp->altered) {
        appPTR->getCurrentSettings()->getAltTextColor(&txtR, &txtG, &txtB);
    } else {
        appPTR->getCurrentSettings()->getTextColor(&txtR, &txtG, &txtB);
    }

    QColor textColor;
    textColor.setRgbF( Image::clamp<qreal>(txtR, 0., 1.),
                       Image::clamp<qreal>(txtG, 0., 1.),
                       Image::clamp<qreal>(txtB, 0., 1.) );

    QColor scaleColor;
    scaleColor.setRgbF(textColor.redF() / 2., textColor.greenF() / 2., textColor.blueF() / 2.);

    QFontMetrics fontM(_imp->font, 0);

    if (!_imp->useLineColor) {
        p.setPen(scaleColor);
    } else {
        p.setPen(_imp->lineColor);
    }

    QPointF btmLeft = _imp->zoomCtx.toZoomCoordinates(0, height() - 1);
    QPointF topRight = _imp->zoomCtx.toZoomCoordinates(width() - 1, 0);

    if ( btmLeft.x() == topRight.x() ) {
        return;
    }

    /*drawing X axis*/
    double lineYpos = height() - 1 - fontM.height()  - TO_DPIY(TICK_HEIGHT) / 2;
    p.drawLine(0, lineYpos, width() - 1, lineYpos);

    double tickBottom = _imp->zoomCtx.toZoomCoordinates( 0, height() - 1 - fontM.height() ).y();
    double tickTop = _imp->zoomCtx.toZoomCoordinates( 0, height() - 1 - fontM.height()  - TO_DPIY(TICK_HEIGHT) ).y();
    const double smallestTickSizePixel = 10.; // tick size (in pixels) for alpha = 0.
    const double largestTickSizePixel = 1000.; // tick size (in pixels) for alpha = 1.
    const double rangePixel =  width();
    const double range_min = btmLeft.x();
    const double range_max =  topRight.x();
    const double range = range_max - range_min;
    double smallTickSize;
    bool half_tick;
    ticks_size(range_min, range_max, rangePixel, smallestTickSizePixel, &smallTickSize, &half_tick);
    if ( (_imp->dataType == eDataTypeInt) && (smallTickSize < 1.) ) {
        smallTickSize = 1.;
        half_tick = false;
    }
    int m1, m2;
    const int ticks_max = 1000;
    double offset;
    ticks_bounds(range_min, range_max, smallTickSize, half_tick, ticks_max, &offset, &m1, &m2);
    std::vector<int> ticks;
    ticks_fill(half_tick, ticks_max, m1, m2, &ticks);
    const double smallestTickSize = range * smallestTickSizePixel / rangePixel;
    const double largestTickSize = range * largestTickSizePixel / rangePixel;
    const double minTickSizeTextPixel = fontM.width( QLatin1String("00") ); // AXIS-SPECIFIC
    const double minTickSizeText = range * minTickSizeTextPixel / rangePixel;
    for (int i = m1; i <= m2; ++i) {
        double value = i * smallTickSize + offset;
        const double tickSize = ticks[i - m1] * smallTickSize;
        const double alpha = ticks_alpha(smallestTickSize, largestTickSize, tickSize);
        QColor color(textColor);
        color.setAlphaF(alpha);
        QPen pen(color);
        pen.setWidthF(1.9);
        p.setPen(pen);

        // for Int slider, because smallTickSize is at least 1, isFloating can never be true
        bool isFloating = std::abs(std::floor(0.5 + value) - value) != 0.;
        assert( !(_imp->dataType == eDataTypeInt && isFloating) );
        bool renderFloating = _imp->dataType == eDataTypeDouble || !isFloating;

        if (renderFloating) {
            QPointF tickBottomPos = _imp->zoomCtx.toWidgetCoordinates(value, tickBottom);
            QPointF tickTopPos = _imp->zoomCtx.toWidgetCoordinates(value, tickTop);

            p.drawLine(tickBottomPos, tickTopPos);
        }

        if ( renderFloating && (tickSize > minTickSizeText) ) {
            const int tickSizePixel = rangePixel * tickSize / range;
            const QString s = QString::number(value);
            const int sSizePixel =  fontM.width(s);
            if (tickSizePixel > sSizePixel) {
                const int sSizeFullPixel = sSizePixel + minTickSizeTextPixel;
                double alphaText = 1.0; //alpha;
                if (tickSizePixel < sSizeFullPixel) {
                    // when the text size is between sSizePixel and sSizeFullPixel,
                    // draw it with a lower alpha
                    alphaText *= (tickSizePixel - sSizePixel) / (double)minTickSizeTextPixel;
                }
                QColor c = _imp->readOnly || !isEnabled() ? Qt::black : textColor;
                c.setAlphaF(alphaText);
                p.setFont(_imp->font);
                p.setPen(c);

                QPointF textPos = _imp->zoomCtx.toWidgetCoordinates( value, btmLeft.y() );

                p.drawText(textPos, s);
            }
        }
    }
    double positionValue = _imp->zoomCtx.toWidgetCoordinates(_imp->value, 0).x();
    QPointF sliderBottomLeft(positionValue - TO_DPIX(SLIDER_WIDTH) / 2, height() - 1 - fontM.height() / 2);
    QPointF sliderTopRight( positionValue + TO_DPIX(SLIDER_WIDTH) / 2, height() - 1 - fontM.height() / 2 - TO_DPIY(SLIDER_HEIGHT) );

    /*draw the slider*/
    p.setPen(_imp->sliderColor);
    p.fillRect(sliderBottomLeft.x(), sliderBottomLeft.y(), sliderTopRight.x() - sliderBottomLeft.x(), sliderTopRight.y() - sliderBottomLeft.y(), _imp->sliderColor);

    /*draw a black rect around the slider for contrast or orange when focused*/
    if ( !hasFocus() ) {
        p.setPen(Qt::black);
    } else {
        QPen pen = p.pen();
        pen.setColor( QColor(243, 137, 0) );
        QVector<qreal> dashStyle;
        qreal space = 2;
        dashStyle << 1 << space;
        pen.setDashPattern(dashStyle);
        p.setOpacity(0.8);
        p.setPen(pen);
    }

    p.drawLine( sliderBottomLeft.x(), sliderBottomLeft.y(), sliderBottomLeft.x(), sliderTopRight.y() );
    p.drawLine( sliderBottomLeft.x(), sliderTopRight.y(), sliderTopRight.x(), sliderTopRight.y() );
    p.drawLine( sliderTopRight.x(), sliderTopRight.y(), sliderTopRight.x(), sliderBottomLeft.y() );
    p.drawLine( sliderTopRight.x(), sliderBottomLeft.y(), sliderBottomLeft.x(), sliderBottomLeft.y() );
} // paintEvent
Пример #16
0
QSize
ScaleSliderQWidget::minimumSizeHint() const
{
    return QSize( TO_DPIX(150), TO_DPIY(20) );
}
Пример #17
0
void
KnobGuiValue::createWidget(QHBoxLayout* layout)
{
    
    connectKnobSignalSlots();
    
    _imp->container = new QWidget(layout->parentWidget());
    QHBoxLayout *containerLayout = new QHBoxLayout(_imp->container);
    layout->addWidget(_imp->container);
    
    containerLayout->setContentsMargins(0, 0, 0, 0);
    containerLayout->setSpacing(3);
    
    if (getKnobsCountOnSameLine() > 1) {
        disableSlider();
    }
    
    if (!isSliderDisabled()) {
        layout->parentWidget()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    }
    
    KnobPtr knob = _imp->getKnob();
    const int nDims = knob->getDimension();
    
    std::vector<double> increments, displayMins, displayMaxs, mins, maxs;
    std::vector<int> decimals;
    boost::shared_ptr<Knob<double> > doubleKnob = _imp->getKnobAsDouble();
    boost::shared_ptr<Knob<int> > intKnob = _imp->getKnobAsInt();
    if (doubleKnob) {
        displayMins = doubleKnob->getDisplayMinimums();
        displayMaxs = doubleKnob->getDisplayMaximums();
        mins = doubleKnob->getMinimums();
        maxs = doubleKnob->getMaximums();
    } else {
        const std::vector<int>& intDmins = intKnob->getDisplayMinimums();
        const std::vector<int>& intDMaxs = intKnob->getDisplayMaximums();
        const std::vector<int>& intMins = intKnob->getMinimums();
        const std::vector<int>& intMaxs = intKnob->getMaximums();
        assert(intDMaxs.size() == intDmins.size() && intDmins.size() == intMins.size() && intMins.size() == intMaxs.size());
        displayMins.resize(intDmins.size());
        displayMaxs.resize(intDmins.size());
        mins.resize(intDmins.size());
        maxs.resize(intDmins.size());
        
        for (std::size_t i = 0; i < intMins.size(); ++i) {
            displayMins[i] = intDmins[i];
            displayMaxs[i] = intDMaxs[i];
            mins[i] = intMins[i];
            maxs[i] = intMaxs[i];
        }
    }
    
    getIncrements(&increments);
    getDecimals(&decimals);
    
    std::vector<std::string> dimensionLabels(nDims);
    
    bool isRectangleParam = isRectangleType();
    // This is a rectangle parameter
    if (isRectangleParam) {
        dimensionLabels[0] = "x";
        dimensionLabels[1] = "y";
        dimensionLabels[2] = "w";
        dimensionLabels[3] = "h";
    } else {
        for (int i = 0; i < nDims; ++i) {
            dimensionLabels[i] = knob->getDimensionName(i);
        }
    }
    
    KnobGuiPtr thisShared = shared_from_this();
    
    SpinBox::SpinBoxTypeEnum type;
    if (doubleKnob) {
        type = SpinBox::eSpinBoxTypeDouble;
    } else {
        type = SpinBox::eSpinBoxTypeInt;
    }
    
    
    int nItemsPerRow = nDims;
    if (std::floor(nDims / 3. + 0.5) == nDims / 3.) {
        nItemsPerRow = 3;
    }
    if (std::floor(nDims / 4. + 0.5) == nDims / 4.) {
        nItemsPerRow = 4;
    }
    
    int nbRows = nDims / nItemsPerRow;
    assert(nbRows >= 1);
    QWidget* allSpinBoxesContainer = 0;
    QGridLayout* spinBoxesGrid = 0;
    if (nbRows == 1) {
        allSpinBoxesContainer = _imp->container;
    } else {
        allSpinBoxesContainer = new QWidget(_imp->container);
        spinBoxesGrid = new QGridLayout(allSpinBoxesContainer);
        spinBoxesGrid->setContentsMargins(0, 0, 0, 0);
        spinBoxesGrid->setVerticalSpacing(TO_DPIY(1));
        spinBoxesGrid->setHorizontalSpacing(TO_DPIX(1));
    }
    
    _imp->spinBoxes.resize(nDims);
    
    int rowIndex = 0;
    int columnIndex = 0;
    for (std::size_t i = 0; i < _imp->spinBoxes.size(); ++i) {
        
        QWidget *boxContainer = new QWidget(allSpinBoxesContainer);
        boxContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
        
        QHBoxLayout *boxContainerLayout = 0;
        boxContainerLayout = new QHBoxLayout(boxContainer);
        boxContainerLayout->setContentsMargins(0, 0, 0, 0);
        boxContainerLayout->setSpacing(3);
        
        
        Label *subDesc = 0;
        if (nDims != 1 && nbRows == 1) {
            subDesc = new Label(QString::fromUtf8(dimensionLabels[i].c_str()), boxContainer);
            boxContainerLayout->addWidget(subDesc);
        }
        
        SpinBox *box = new KnobSpinBox(layout->parentWidget(), type, thisShared , i);
        NumericKnobValidator* validator = new NumericKnobValidator(box,thisShared);
        box->setValidator(validator);
        QObject::connect( box, SIGNAL(valueChanged(double)), this, SLOT(onSpinBoxValueChanged()) );
        
        // Set the copy/link actions in the right click menu of the SpinBox
        enableRightClickMenu(box,i);
        
#ifdef SPINBOX_TAKE_PLUGIN_RANGE_INTO_ACCOUNT
        double min = mins[i];
        double max = maxs[i];
        valueAccordingToType(false, i, &min);
        valueAccordingToType(false, i, &max);
        box->setMaximum(max);
        box->setMinimum(min);
#endif
        
        
        
        if (type == SpinBox::eSpinBoxTypeDouble) {
            // Set the number of digits after the decimal point
            if (i < decimals.size()) {
                box->decimals(decimals[i]);
            }
        }
        
        if (i < increments.size()) {    
            double incr = 1;
            incr = increments[i];
            valueAccordingToType(false, i, &incr);
            box->setIncrement(incr);
        }
        boxContainerLayout->addWidget(box);
        if (!spinBoxesGrid) {
            containerLayout->addWidget(boxContainer);
        } else {
            spinBoxesGrid->addWidget(boxContainer, rowIndex, columnIndex);
        }
        _imp->spinBoxes[i] = std::make_pair(box, subDesc);
        
        ++columnIndex;
        if (columnIndex >= nItemsPerRow) {
            columnIndex = 0;
            ++rowIndex;
        }
    }
    
    if (spinBoxesGrid) {
        containerLayout->addWidget(allSpinBoxesContainer);
    }
    
    bool sliderVisible = false;
    if (!isSliderDisabled() && !isRectangleParam) {
        double dispmin = displayMins[0];
        double dispmax = displayMaxs[0];
        if (dispmin == -DBL_MAX) {
            dispmin = mins[0];
        }
        if (dispmax == DBL_MAX) {
            dispmax = maxs[0];
        }
        
        // denormalize if necessary
        double dispminGui = dispmin;
        double dispmaxGui = dispmax;
        valueAccordingToType(false, 0, &dispminGui);
        valueAccordingToType(false, 0, &dispmaxGui);
        
        bool spatial = isSpatialType();
        Format f;
        if (spatial) {
            getKnob()->getHolder()->getApp()->getProject()->getProjectDefaultFormat(&f);
        }
        if (dispminGui < -SLIDER_MAX_RANGE) {
            if (spatial) {
                dispminGui = -f.width();
            } else {
                dispminGui = -SLIDER_MAX_RANGE;
            }
        }
        if (dispmaxGui > SLIDER_MAX_RANGE) {
            if (spatial) {
                dispmaxGui = f.width();
            } else {
                dispmaxGui = SLIDER_MAX_RANGE;
            }
        }
        
        double value0 = _imp->getKnobValue(0);

        ScaleSliderQWidget::DataTypeEnum sliderType;
        if (doubleKnob) {
            sliderType = ScaleSliderQWidget::eDataTypeDouble;
        } else {
            sliderType = ScaleSliderQWidget::eDataTypeInt;
        }

        
        _imp->slider = new ScaleSliderQWidget(dispminGui, dispmaxGui, value0,knob->getEvaluateOnChange(),
                                         sliderType,getGui(), eScaleTypeLinear, layout->parentWidget());
        _imp->slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
        if (hasToolTip()) {
            _imp->slider->setToolTip( toolTip() );
        }
        QObject::connect(_imp->slider, SIGNAL(positionChanged(double)), this, SLOT(onSliderValueChanged(double)));
        QObject::connect(_imp->slider, SIGNAL(editingFinished(bool)), this, SLOT(onSliderEditingFinished(bool)));
        containerLayout->addWidget(_imp->slider);
        
        sliderVisible = shouldSliderBeVisible(dispminGui, dispmaxGui);
        
        // onDisplayMinMaxChanged takes original (maybe normalized) values
        onDisplayMinMaxChanged(dispmin, dispmax);
    }
Пример #18
0
void
Gui::setupUi()
{
    onProjectNameChanged(QString(), false);

    setMouseTracking(true);
    installEventFilter(this);
    assert( !isFullScreen() );

    //Gui::loadStyleSheet();

    ///Restores position, size of the main window as well as whether it was fullscreen or not.
    _imp->restoreGuiGeometry();


    _imp->_undoStacksGroup = new QUndoGroup;
    QObject::connect( _imp->_undoStacksGroup, SIGNAL(activeStackChanged(QUndoStack*)), this, SLOT(onCurrentUndoStackChanged(QUndoStack*)) );

    createMenuActions();

    /*CENTRAL AREA*/
    //======================
    _imp->_centralWidget = new QWidget(this);
    setCentralWidget(_imp->_centralWidget);
    _imp->_mainLayout = new QHBoxLayout(_imp->_centralWidget);
    _imp->_mainLayout->setContentsMargins(0, 0, 0, 0);
    _imp->_centralWidget->setLayout(_imp->_mainLayout);

    _imp->_leftRightSplitter = new Splitter(_imp->_centralWidget);
    _imp->_leftRightSplitter->setChildrenCollapsible(false);
    _imp->_leftRightSplitter->setObjectName(QString::fromUtf8(kMainSplitterObjectName));
    _imp->_splitters.push_back(_imp->_leftRightSplitter);
    _imp->_leftRightSplitter->setOrientation(Qt::Horizontal);
    _imp->_leftRightSplitter->setContentsMargins(0, 0, 0, 0);


    _imp->_toolBox = new AutoHideToolBar(this, _imp->_leftRightSplitter);
    _imp->_toolBox->setToolButtonStyle(Qt::ToolButtonIconOnly);
    _imp->_toolBox->setOrientation(Qt::Vertical);
    _imp->_toolBox->setMaximumWidth(TO_DPIX(NATRON_TOOL_BUTTON_SIZE));

    if (_imp->leftToolBarDisplayedOnHoverOnly) {
        _imp->refreshLeftToolBarVisibility( mapFromGlobal( QCursor::pos() ) );
    }

    _imp->_leftRightSplitter->addWidget(_imp->_toolBox);

    _imp->_mainLayout->addWidget(_imp->_leftRightSplitter);

    _imp->createNodeGraphGui();
    _imp->createCurveEditorGui();
    _imp->createDopeSheetGui();
    _imp->createScriptEditorGui();
    _imp->createProgressPanelGui();
    ///Must be absolutely called once _nodeGraphArea has been initialized.
    _imp->createPropertiesBinGui();

    createDefaultLayoutInternal(false);

    _imp->_projectGui = new ProjectGui(this);
    _imp->_projectGui->create(_imp->_appInstance->getProject(),
                              _imp->_layoutPropertiesBin,
                              this);

    initProjectGuiKnobs();


    setVisibleProjectSettingsPanel();

    _imp->_aboutWindow = new AboutWindow(this, this);
    _imp->_aboutWindow->hide();

    _imp->shortcutEditor = new ShortCutEditor(this);
    _imp->shortcutEditor->hide();


    //the same action also clears the ofx plugins caches, they are not the same cache but are used to the same end
    
    boost::shared_ptr<Project> project = _imp->_appInstance->getProject();
    QObject::connect( project.get(), SIGNAL(projectNameChanged(QString,bool)), this, SLOT(onProjectNameChanged(QString,bool)) );
    
    boost::shared_ptr<TimeLine> timeline = project->getTimeLine();
    QObject::connect( timeline.get(),SIGNAL(frameChanged(SequenceTime,int)), this,SLOT(renderViewersAndRefreshKnobsAfterTimelineTimeChange(SequenceTime,int)) );
    QObject::connect( timeline.get(),SIGNAL(frameAboutToChange()), this, SLOT(onTimelineTimeAboutToChange()));

    /*Searches recursively for all child objects of the given object,
       and connects matching signals from them to slots of object that follow the following form:

        void on_<object name>_<signal name>(<signal parameters>);

       Let's assume our object has a child object of type QPushButton with the object name button1.
       The slot to catch the button's clicked() signal would be:

       void on_button1_clicked();

       If object itself has a properly set object name, its own signals are also connected to its respective slots.
     */
    QMetaObject::connectSlotsByName(this);
    
    appPTR->setOFXHostHandle(_imp->_appInstance->getOfxHostOSHandle());
    
} // setupUi
Пример #19
0
 static double pointTolerance() { return TO_DPIX(12.); }
Пример #20
0
 static double pointSize() { return TO_DPIX(5.); }
Пример #21
0
ProgressPanel::ProgressPanel(Gui* gui)
: QWidget(gui)
, PanelWidget(this, gui)
, _imp(new ProgressPanelPrivate())
{
    
    _imp->mainLayout = new QVBoxLayout(this);
    _imp->mainLayout->setContentsMargins(0, 0, 0, 0);
    _imp->mainLayout->setSpacing(0);
    _imp->headerContainer = new QWidget(this);
    _imp->headerLayout = new QHBoxLayout(_imp->headerContainer);
    _imp->headerLayout->setSpacing(0);
   // _imp->headerLayout->setContentsMargins(0, 0, 0, 0);
    _imp->mainLayout->addWidget(_imp->headerContainer);
    
    
    _imp->queueTasksCheckbox = new QCheckBox(tr("Queue Renders"),_imp->headerContainer);
    _imp->queueTasksCheckbox->setToolTip(GuiUtils::convertFromPlainText(tr("When checked, renders will be queued in the Progress Panel and will start only when all other prior renders are done. This does not apply to other tasks such as Tracking or analysis."), Qt::WhiteSpaceNormal));
    _imp->queueTasksCheckbox->setChecked(appPTR->getCurrentSettings()->isRenderQueuingEnabled());
    QObject::connect(_imp->queueTasksCheckbox, SIGNAL(stateChanged(int)), this, SLOT(onQueueRendersCheckboxChecked()));
    _imp->headerLayout->addWidget(_imp->queueTasksCheckbox);
    
    _imp->headerLayout->addSpacing(TO_DPIX(20));
    
    _imp->removeTasksAfterFinishCheckbox = new QCheckBox(tr("Remove Finished Tasks"),_imp->headerContainer);
    _imp->removeTasksAfterFinishCheckbox->setToolTip(GuiUtils::convertFromPlainText(tr("When checked, finished tasks that can be paused"  " will be automatically removed from the task list when they are finished. When unchecked, the tasks may be restarted."), Qt::WhiteSpaceNormal));
    _imp->removeTasksAfterFinishCheckbox->setChecked(false);
    _imp->headerLayout->addWidget(_imp->removeTasksAfterFinishCheckbox);

    
    
    _imp->headerLayout->addStretch();
    
    
    _imp->view = new TableView(this);
    _imp->view->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    _imp->model = new TableModel(0,0, _imp->view);
    _imp->view->setSortingEnabled(false);
    _imp->view->setTableModel(_imp->model);
    
    _imp->mainLayout->addWidget(_imp->view);

    QObject::connect(_imp->view, SIGNAL(itemRightClicked(TableItem*)), this, SLOT(onItemRightClicked(TableItem*)));
    
    QStringList dimensionNames;
    dimensionNames
    << tr("Node")
    << tr("Progress")
    << tr("Status")
    << tr("Controls")
    << tr("Time remaining")
    << tr("Frame Range")
    << tr("Task");
    
    _imp->view->setColumnCount(dimensionNames.size());
    _imp->view->setHorizontalHeaderLabels(dimensionNames);
    //_imp->view->header()->setResizeMode(QHeaderView::Fixed);
    _imp->view->header()->setStretchLastSection(true);
    _imp->view->header()->resizeSection(COL_TIME_REMAINING, TO_DPIX(150));

    QItemSelectionModel* selModel = _imp->view->selectionModel();
    QObject::connect(selModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(onSelectionChanged(QItemSelection,QItemSelection)));
    
    QObject::connect(this, SIGNAL(s_doProgressStartOnMainThread(boost::shared_ptr<Node>, QString, QString,bool)), this, SLOT(doProgressStartOnMainThread(boost::shared_ptr<Node>, QString, QString,bool)));
    QObject::connect(this, SIGNAL(s_doProgressUpdateOnMainThread(ProgressTaskInfoPtr,double)), this, SLOT(doProgressOnMainThread(ProgressTaskInfoPtr,double)));
    
    QObject::connect(this, SIGNAL(s_doProgressEndOnMainThread(boost::shared_ptr<Node>)), this, SLOT(doProgressEndOnMainThread(boost::shared_ptr<Node>)));
                     
    
}
Пример #22
0
ProgressPanel::ProgressPanel(const std::string& scriptName, Gui* gui)
    : QWidget(gui)
    , PanelWidget(scriptName, this, gui)
    , _imp( new ProgressPanelPrivate() )
{
    _imp->mainLayout = new QVBoxLayout(this);
    _imp->mainLayout->setContentsMargins(0, 0, 0, 0);
    _imp->mainLayout->setSpacing(0);
    _imp->headerContainer = new QWidget(this);
    _imp->headerLayout = new QHBoxLayout(_imp->headerContainer);
    _imp->headerLayout->setSpacing(0);
    // _imp->headerLayout->setContentsMargins(0, 0, 0, 0);
    _imp->mainLayout->addWidget(_imp->headerContainer);


    _imp->queueTasksCheckbox = new QCheckBox(tr("Queue Renders"), _imp->headerContainer);
    _imp->queueTasksCheckbox->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("When checked, renders will be queued in the Progress Panel and will start only when all other prior renders are done. This does not apply to other tasks such as Tracking or analysis."), NATRON_NAMESPACE::WhiteSpaceNormal) );
    _imp->queueTasksCheckbox->setChecked( appPTR->getCurrentSettings()->isRenderQueuingEnabled() );
    QObject::connect( _imp->queueTasksCheckbox, SIGNAL(stateChanged(int)), this, SLOT(onQueueRendersCheckboxChecked()) );
    _imp->headerLayout->addWidget(_imp->queueTasksCheckbox);

    _imp->headerLayout->addSpacing( TO_DPIX(20) );

    _imp->removeTasksAfterFinishCheckbox = new QCheckBox(tr("Remove Finished Tasks"), _imp->headerContainer);
    _imp->removeTasksAfterFinishCheckbox->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("When checked, finished tasks that can be paused"  " will be automatically removed from the task list when they are finished. When unchecked, the tasks may be restarted."), NATRON_NAMESPACE::WhiteSpaceNormal) );
    _imp->removeTasksAfterFinishCheckbox->setChecked(false);
    _imp->headerLayout->addWidget(_imp->removeTasksAfterFinishCheckbox);


    _imp->headerLayout->addStretch();

    std::vector<std::pair<QString, QIcon> > headerData;
    headerData.push_back(std::make_pair(tr("Node"), QIcon()));
    headerData.push_back(std::make_pair(tr("Progress"), QIcon()));
    headerData.push_back(std::make_pair(tr("Status"), QIcon()));
    headerData.push_back(std::make_pair(tr("Controls"), QIcon()));
    headerData.push_back(std::make_pair(tr("Time remaining"), QIcon()));
    headerData.push_back(std::make_pair(tr("Frame Range"), QIcon()));
    headerData.push_back(std::make_pair(tr("Task"), QIcon()));


    _imp->view = new TableView(getGui(), this);
    _imp->view->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    _imp->model = TableModel::create(headerData.size(), TableModel::eTableModelTypeTable);
    _imp->view->setSortingEnabled(false);
    _imp->view->setTableModel(_imp->model);

    _imp->mainLayout->addWidget(_imp->view);

    QObject::connect( _imp->view, SIGNAL(itemRightClicked(QPoint, TableItemPtr)), this, SLOT(onItemRightClicked(QPoint, TableItemPtr)) );
   

    _imp->model->setHorizontalHeaderData(headerData);
    //_imp->view->header()->setResizeMode(QHeaderView::Fixed);
    _imp->view->header()->setStretchLastSection(true);
    _imp->view->header()->resizeSection( COL_TIME_REMAINING, TO_DPIX(150) );

    QItemSelectionModel* selModel = _imp->view->selectionModel();
    QObject::connect( selModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(onSelectionChanged(QItemSelection,QItemSelection)) );
    QObject::connect( this, SIGNAL(s_doProgressStartOnMainThread(NodePtr,QString,QString,bool)), this, SLOT(doProgressStartOnMainThread(NodePtr,QString,QString,bool)) );
    QObject::connect( this, SIGNAL(s_doProgressUpdateOnMainThread(ProgressTaskInfoPtr,double)), this, SLOT(doProgressOnMainThread(ProgressTaskInfoPtr,double)) );
    QObject::connect( this, SIGNAL(s_doProgressEndOnMainThread(NodePtr)), this, SLOT(doProgressEndOnMainThread(NodePtr)) );
}
Пример #23
0
ToolButton*
Gui::findOrCreateToolButton(const PluginGroupNodePtr & treeNode)
{

    // Do not create an action for non user creatable plug-ins
    bool isUserCreatable = true;
    PluginPtr internalPlugin = treeNode->getPlugin();
    if (internalPlugin && treeNode->getChildren().empty() && !internalPlugin->getIsUserCreatable()) {
        isUserCreatable = false;
    }
    if (!isUserCreatable) {
        return 0;
    }

    // Check for existing toolbuttons
    for (std::size_t i = 0; i < _imp->_toolButtons.size(); ++i) {
        if (_imp->_toolButtons[i]->getPluginToolButton() == treeNode) {
            return _imp->_toolButtons[i];
        }
    }

    // Check for parent toolbutton
    ToolButton* parentToolButton = NULL;
    if ( treeNode->getParent() ) {
        assert(treeNode->getParent() != treeNode);
        if (treeNode->getParent() != treeNode) {
            parentToolButton = findOrCreateToolButton( treeNode->getParent() );
        }
    }

    QString resourcesPath;
    if (internalPlugin) {
        resourcesPath = QString::fromUtf8(internalPlugin->getProperty<std::string>(kNatronPluginPropResourcesPath).c_str());
    }
    QString iconFilePath = resourcesPath;
    StrUtils::ensureLastPathSeparator(iconFilePath);
    iconFilePath += treeNode->getTreeNodeIconFilePath();

    QIcon toolButtonIcon, menuIcon;
    // Create tool icon
    if ( !iconFilePath.isEmpty() && QFile::exists(iconFilePath) ) {
        QPixmap pix(iconFilePath);
        int menuSize = TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE);
        int toolButtonSize = !treeNode->getParent() ? TO_DPIX(NATRON_TOOL_BUTTON_ICON_SIZE) : TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE);
        QPixmap menuPix = pix, toolbuttonPix = pix;
        if ( (std::max( menuPix.width(), menuPix.height() ) != menuSize) && !menuPix.isNull() ) {
            menuPix = menuPix.scaled(menuSize, menuSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        if ( (std::max( toolbuttonPix.width(), toolbuttonPix.height() ) != toolButtonSize) && !toolbuttonPix.isNull() ) {
            toolbuttonPix = toolbuttonPix.scaled(toolButtonSize, toolButtonSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        menuIcon.addPixmap(menuPix);
        toolButtonIcon.addPixmap(toolbuttonPix);
    } else {
        // Set default icon only if it has no parent, otherwise leave action without an icon
        if ( !treeNode->getParent() ) {
            QPixmap toolbuttonPix, menuPix;
            getPixmapForGrouping( &toolbuttonPix, TO_DPIX(NATRON_TOOL_BUTTON_ICON_SIZE), treeNode->getTreeNodeName() );
            toolButtonIcon.addPixmap(toolbuttonPix);
            getPixmapForGrouping( &menuPix, TO_DPIX(NATRON_TOOL_BUTTON_ICON_SIZE), treeNode->getTreeNodeName() );
            menuIcon.addPixmap(menuPix);
        }
    }

    // If the tool-button has no children, this is a leaf, we must create an action
    // At this point any plug-in MUST be in a toolbutton, so it must have a parent.
    assert(!treeNode->getChildren().empty() || treeNode->getParent());

    int majorVersion = internalPlugin ? internalPlugin->getProperty<unsigned int>(kNatronPluginPropVersion, 0) : 1;
    int minorVersion = internalPlugin ? internalPlugin->getProperty<unsigned int>(kNatronPluginPropVersion, 1) : 0;

    ToolButton* pluginsToolButton = new ToolButton(getApp(),
                                                   treeNode,
                                                   treeNode->getTreeNodeID(),
                                                   majorVersion,
                                                   minorVersion,
                                                   treeNode->getTreeNodeName(),
                                                   toolButtonIcon,
                                                   menuIcon);

    if (!treeNode->getChildren().empty()) {
        // For grouping items, create the menu
        Menu* menu = new Menu(this);
        menu->setTitle( pluginsToolButton->getLabel() );
        menu->setIcon(menuIcon);
        pluginsToolButton->setMenu(menu);
        pluginsToolButton->setAction( menu->menuAction() );
    } else {
        // This is a leaf (plug-in)
        assert(internalPlugin);
        assert(parentToolButton);

        // If this is the highest major version for this plug-in use normal label, otherwise also append the major version
        bool isHighestMajorVersionForPlugin = internalPlugin->getIsHighestMajorVersion();

        std::string pluginLabel = !isHighestMajorVersionForPlugin ? internalPlugin->getLabelVersionMajorEncoded() : internalPlugin->getLabelWithoutSuffix();

        QKeySequence defaultNodeShortcut;
        QString shortcutGroup = QString::fromUtf8(kShortcutGroupNodes);
        std::vector<std::string> groupingSplit = internalPlugin->getPropertyN<std::string>(kNatronPluginPropGrouping);
        for (std::size_t j = 0; j < groupingSplit.size(); ++j) {
            shortcutGroup.push_back( QLatin1Char('/') );
            shortcutGroup.push_back(QString::fromUtf8(groupingSplit[j].c_str()));
        }
        {
            // If the plug-in has a shortcut get it

            std::list<QKeySequence> keybinds = getKeybind(shortcutGroup, QString::fromUtf8(internalPlugin->getPluginID().c_str()));
            if (!keybinds.empty()) {
                defaultNodeShortcut = keybinds.front();
            }
        }

        QAction* defaultPresetAction = new QAction(this);
        defaultPresetAction->setShortcut(defaultNodeShortcut);
        defaultPresetAction->setShortcutContext(Qt::WidgetShortcut);
        defaultPresetAction->setText(QString::fromUtf8(pluginLabel.c_str()));
        defaultPresetAction->setIcon( pluginsToolButton->getMenuIcon() );
        QObject::connect( defaultPresetAction, SIGNAL(triggered()), pluginsToolButton, SLOT(onTriggered()) );


        const std::vector<PluginPresetDescriptor>& presets = internalPlugin->getPresetFiles();
        if (presets.empty()) {
            // If the node has no presets, just make an action, otherwise make a menu
            pluginsToolButton->setAction(defaultPresetAction);
        } else {


            Menu* menu = new Menu(this);
            menu->setTitle( pluginsToolButton->getLabel() );
            menu->setIcon(menuIcon);
            pluginsToolButton->setMenu(menu);
            pluginsToolButton->setAction( menu->menuAction() );

            defaultPresetAction->setText(QString::fromUtf8(pluginLabel.c_str()) + tr(" (Default)"));
            menu->addAction(defaultPresetAction);

            for (std::vector<PluginPresetDescriptor>::const_iterator it = presets.begin(); it!=presets.end(); ++it) {

                QKeySequence presetShortcut;
                {
                    // If the preset has a shortcut get it

                    std::string shortcutKey = internalPlugin->getPluginID();
                    shortcutKey += "_preset_";
                    shortcutKey += it->presetLabel.toStdString();

                    std::list<QKeySequence> keybinds = getKeybind(shortcutGroup, QString::fromUtf8(shortcutKey.c_str()));
                    if (!keybinds.empty()) {
                        presetShortcut = keybinds.front();
                    }
                }

                QString presetLabel = QString::fromUtf8(pluginLabel.c_str());
                presetLabel += QLatin1String(" (");
                presetLabel += it->presetLabel;
                presetLabel += QLatin1String(")");

                QAction* presetAction = new QAction(this);
                QPixmap presetPix;
                if (getPresetIcon(it->presetFilePath, it->presetIconFile, TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE), &presetPix)) {
                    presetAction->setIcon( presetPix );
                }
                presetAction->setShortcut(presetShortcut);
                presetAction->setShortcutContext(Qt::WidgetShortcut);
                presetAction->setText(presetLabel);
                presetAction->setData(it->presetLabel);
                QObject::connect( presetAction, SIGNAL(triggered()), pluginsToolButton, SLOT(onTriggered()) );

                menu->addAction(presetAction);
            }
        }

    } // if (!treeNode->getChildren().empty())

    // If it has a parent, add the new tool button as a child
    if (parentToolButton) {
        parentToolButton->tryAddChild(pluginsToolButton);
    }
    _imp->_toolButtons.push_back(pluginsToolButton);

    return pluginsToolButton;
} // findOrCreateToolButton
EditNodeViewerContextDialog::EditNodeViewerContextDialog(const KnobIPtr& knob, QWidget* parent)
: QDialog(parent)
, _imp(new EditNodeViewerContextDialogPrivate(knob))
{

    setWindowTitle(tr("Edit %1 viewer interface").arg(QString::fromUtf8(knob->getName().c_str())));

    _imp->vLayout = new QVBoxLayout(this);
    _imp->vLayout->setContentsMargins(0, 0, TO_DPIX(15), 0);

    _imp->mainContainer = new QWidget(this);
    _imp->mainLayout = new QFormLayout(_imp->mainContainer);
    _imp->mainLayout->setLabelAlignment(Qt::AlignVCenter | Qt::AlignRight);
    _imp->mainLayout->setFormAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    _imp->mainLayout->setSpacing(TO_DPIX(3));
    _imp->mainLayout->setContentsMargins(0, 0, TO_DPIX(15), 0);

    _imp->vLayout->addWidget(_imp->mainContainer);

    if (knob->isUserKnob()) {
        QWidget* rowContainer = new QWidget(this);
        QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer);
        rowLayout->setContentsMargins(0, 0, 0, 0);

        _imp->viewerUILabelLabel = new Label(tr("Viewer Interface Label:"), this);
        _imp->viewerUILabelEdit = new LineEdit(rowContainer);
        QString labelTooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The text label of the parameter that will appear in its viewer interface"), NATRON_NAMESPACE::WhiteSpaceNormal);
        _imp->viewerUILabelEdit->setToolTip(labelTooltip);
        _imp->viewerUILabelLabel->setToolTip(labelTooltip);

        if (knob) {
            _imp->viewerUILabelEdit->setText( QString::fromUtf8( knob->getInViewerContextLabel().c_str() ) );
        }
        rowLayout->addWidget(_imp->viewerUILabelEdit);
        rowLayout->addStretch();

        _imp->mainLayout->addRow(_imp->viewerUILabelLabel, rowContainer);
    }

    KnobButtonPtr isButtonKnob = toKnobButton(knob);

    if (knob->isUserKnob()) {
        QWidget* rowContainer = new QWidget(this);
        QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer);
        rowLayout->setContentsMargins(0, 0, 0, 0);

        QString text;
        if (isButtonKnob) {
            text = tr("Button Checked Icon:");
        } else {
            text = tr("Icon label:");
        }
        QString tooltip;
        if (isButtonKnob) {
            tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The icon of the button when checked"), NATRON_NAMESPACE::WhiteSpaceNormal);
        } else {
            tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("This icon will be used instead of the text label"), NATRON_NAMESPACE::WhiteSpaceNormal);
        }
        _imp->checkedIconLabel = new Label(text, this);
        _imp->checkedIconLineEdit = new LineEdit(rowContainer);
        _imp->checkedIconLineEdit->setToolTip(tooltip);
        _imp->checkedIconLabel->setToolTip(tooltip);

        _imp->checkedIconLineEdit->setText( QString::fromUtf8( knob->getInViewerContextIconFilePath(true).c_str() ) );

        rowLayout->addWidget(_imp->checkedIconLineEdit);
        rowLayout->addStretch();

        _imp->mainLayout->addRow(_imp->checkedIconLabel, rowContainer);
    }

    if (isButtonKnob && knob->isUserKnob()) {
        QWidget* rowContainer = new QWidget(this);
        QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer);
        rowLayout->setContentsMargins(0, 0, 0, 0);

        QString text;
        text = tr("Button Unchecked Icon:");

        QString tooltip;
        tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The icon of the button when unchecked"), NATRON_NAMESPACE::WhiteSpaceNormal);

        _imp->uncheckedIconLabel = new Label(text, this);
        _imp->uncheckedIconLineEdit = new LineEdit(rowContainer);
        _imp->uncheckedIconLineEdit->setToolTip(tooltip);
        _imp->uncheckedIconLabel->setToolTip(tooltip);

        _imp->uncheckedIconLineEdit->setText( QString::fromUtf8( knob->getInViewerContextIconFilePath(false).c_str() ) );

        rowLayout->addWidget(_imp->uncheckedIconLineEdit);
        rowLayout->addStretch();

        _imp->mainLayout->addRow(_imp->uncheckedIconLabel, rowContainer);
    }

    {
        QWidget* rowContainer = new QWidget(this);
        QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer);
        rowLayout->setContentsMargins(0, 0, 0, 0);

        QString text = tr("Layout Type:");
        QString tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The layout type for this parameter"), NATRON_NAMESPACE::WhiteSpaceNormal);
        _imp->layoutTypeLabel = new Label(text, this);
        _imp->layoutTypeChoice = new ComboBox(rowContainer);
        _imp->layoutTypeLabel->setToolTip(tooltip);
        _imp->layoutTypeChoice->setToolTip(tooltip);
        _imp->layoutTypeChoice->addItem(tr("Spacing (px)"), QIcon(), QKeySequence(), tr("The spacing in pixels to add after the parameter"));
        _imp->layoutTypeChoice->addItem(tr("Separator"), QIcon(), QKeySequence(), tr("A vertical line will be added after the parameter"));
        _imp->layoutTypeChoice->addItem(tr("Stretch After"), QIcon(), QKeySequence(), tr("The layout will be stretched between this parameter and the next"));
        _imp->layoutTypeChoice->addItem(tr("New Line"), QIcon(), QKeySequence(), tr("A new line will be added after this parameter"));

        ViewerContextLayoutTypeEnum type = knob->getInViewerContextLayoutType();
        _imp->layoutTypeChoice->setCurrentIndex_no_emit((int)type);

        QObject::connect(_imp->layoutTypeChoice, SIGNAL(currentIndexChanged(int)), this, SLOT(onLayoutTypeChoiceChanged(int)));
        rowLayout->addWidget(_imp->layoutTypeChoice);

        _imp->itemSpacingSpinbox = new SpinBox(rowContainer, SpinBox::eSpinBoxTypeInt);
        _imp->itemSpacingSpinbox->setMinimum(0);
        _imp->itemSpacingSpinbox->setValue(_imp->knob->getInViewerContextItemSpacing());
        _imp->itemSpacingSpinbox->setVisible(_imp->layoutTypeChoice->activeIndex() == 0);
        _imp->itemSpacingSpinbox->setToolTip(NATRON_NAMESPACE::convertFromPlainText(tr("The spacing in pixels to add after the parameter"), NATRON_NAMESPACE::WhiteSpaceNormal));
        rowLayout->addWidget(_imp->itemSpacingSpinbox);
        rowLayout->addStretch();

        _imp->mainLayout->addRow(_imp->layoutTypeLabel, rowContainer);
    }

    {
        QWidget* rowContainer = new QWidget(this);
        QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer);
        rowLayout->setContentsMargins(0, 0, 0, 0);

        QString text = tr("Hidden:");
        QString tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("When checked, the parameter will be hidden from the viewer interface"), NATRON_NAMESPACE::WhiteSpaceNormal);
        _imp->hiddenLabel = new Label(text, this);
        _imp->hiddenCheckbox = new AnimatedCheckBox(rowContainer);
        _imp->hiddenLabel->setToolTip(tooltip);
        _imp->hiddenCheckbox->setToolTip(tooltip);
        _imp->hiddenCheckbox->setChecked(knob->getInViewerContextSecret());
        rowLayout->addWidget(_imp->hiddenCheckbox);
        rowLayout->addStretch();

        _imp->mainLayout->addRow(_imp->hiddenLabel, rowContainer);
    }

   /* if (isButtonKnob) {
        QWidget* rowContainer = new QWidget(this);
        QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer);
        rowLayout->setContentsMargins(0, 0, 0, 0);

        QString text = tr("Add to Shortcut Editor:");
        QString tooltip = GuiUtils::convertFromPlainText(tr("When checked, the parameter can be attributed a shortcut from the Shortcut Editor"), Qt::WhiteSpaceNormal);
        _imp->addToShortcutEditorLabel = new Label(text, this);
        _imp->addToShortcutEditorCheckbox = new AnimatedCheckBox(rowContainer);
        _imp->addToShortcutEditorLabel->setToolTip(tooltip);
        _imp->addToShortcutEditorCheckbox->setToolTip(tooltip);
        _imp->addToShortcutEditorCheckbox->setChecked(knob->getInViewerContextHasShortcut());
        rowLayout->addWidget(_imp->addToShortcutEditorCheckbox);
        rowLayout->addStretch();

        _imp->mainLayout->addRow(_imp->addToShortcutEditorLabel, rowContainer);
    }*/


    QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::StandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel), Qt::Horizontal, this);
    QObject::connect( buttons, SIGNAL(rejected()), this, SLOT(reject()) );
    QObject::connect( buttons, SIGNAL(accepted()), this, SLOT(onOkClicked()) );
    _imp->vLayout->addWidget(buttons);
}
Пример #25
0
GCC_DIAG_UNUSED_PRIVATE_FIELD_OFF
//// /opt/local/include/QtGui/qmime.h:119:10: warning: private field 'type' is not used [-Wunused-private-field]
#include <QKeyEvent>
GCC_DIAG_UNUSED_PRIVATE_FIELD_ON
#include <QtCore/QCoreApplication>
#include <QApplication>
#include <QHBoxLayout> // in QtGui on Qt4, in QtWidgets on Qt5
#include <QVBoxLayout> // in QtGui on Qt4, in QtWidgets on Qt5
#include <QtCore/QThread>
#include <QtCore/QSettings>
#include <QtCore/QDebug>

#include "Engine/AppManager.h" // appPTR
#include "Engine/Knob.h"
#include "Engine/Utils.h" // convertFromPlainText

#include "Gui/AnimationModuleBase.h"
#include "Gui/AnimationModuleSelectionModel.h"
#include "Gui/AnimationModuleView.h"
#include "Gui/DialogButtonBox.h"
#include "Gui/LineEdit.h" // LineEdit
#include "Gui/SpinBox.h" // SpinBox
#include "Gui/Button.h" // Button
#include "Gui/SequenceFileDialog.h" // SequenceFileDialog
#include "Gui/GuiApplicationManager.h"
#include "Gui/Label.h" // Label
#include "Gui/AnimationModuleUndoRedo.h"

NATRON_NAMESPACE_ENTER

ImportExportCurveDialog::ImportExportCurveDialog(bool isExportDialog,
                                                 const std::vector<CurveGuiPtr > & curves,
                                                 Gui* gui,
                                                 QWidget* parent)
    : QDialog(parent)
    , _gui(gui)
    , _isExportDialog(isExportDialog)
    , _mainLayout(0)
    , _fileContainer(0)
    , _fileLayout(0)
    , _fileLabel(0)
    , _fileLineEdit(0)
    , _fileBrowseButton(0)
    , _startContainer(0)
    , _startLayout(0)
    , _startLabel(0)
    , _startLineEdit(0)
    , _incrContainer(0)
    , _incrLayout(0)
    , _incrLabel(0)
    , _incrLineEdit(0)
    , _endContainer(0)
    , _endLayout(0)
    , _endLabel(0)
    , _endLineEdit(0)
    , _curveColumns()
    , _buttonBox(0)
{
    // always running in the main thread
    assert( qApp && qApp->thread() == QThread::currentThread() );

    bool integerIncrement = false;
    double xstart = -std::numeric_limits<double>::infinity();
    double xend = std::numeric_limits<double>::infinity();
    for (size_t i = 0; i < curves.size(); ++i) {
        integerIncrement |= curves[i]->areKeyFramesTimeClampedToIntegers();
        std::pair<double,double> xrange = curves[i]->getInternalCurve()->getXRange();
        xstart = std::max(xstart, xrange.first);
        xend = std::min(xend, xrange.second);
    }
    if (xstart == -std::numeric_limits<double>::infinity()) {
        xstart = std::min(0., xend - 1.);
    }
    if (xend == std::numeric_limits<double>::infinity()) {
        xend = std::max(xstart + 1., 1.);
    }
    _mainLayout = new QVBoxLayout(this);
    _mainLayout->setContentsMargins(0, TO_DPIX(3), 0, 0);
    _mainLayout->setSpacing(TO_DPIX(2));
    setLayout(_mainLayout);

    //////File
    _fileContainer = new QWidget(this);
    _fileLayout = new QHBoxLayout(_fileContainer);
    _fileLabel = new Label(tr("File:"), _fileContainer);
    _fileLayout->addWidget(_fileLabel);
    _fileLineEdit = new LineEdit(_fileContainer);
    _fileLineEdit->setPlaceholderText( tr("File path...") );
    _fileLineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    _fileLayout->addWidget(_fileLineEdit);
    _fileBrowseButton = new Button(_fileContainer);
    QPixmap pix;
    appPTR->getIcon(NATRON_PIXMAP_OPEN_FILE, &pix);
    _fileBrowseButton->setIcon( QIcon(pix) );
    QObject::connect( _fileBrowseButton, SIGNAL(clicked()), this, SLOT(open_file()) );
    _fileLayout->addWidget(_fileBrowseButton);
    _mainLayout->addWidget(_fileContainer);

    //////x start value
    _startContainer = new QWidget(this);
    _startLayout = new QHBoxLayout(_startContainer);
    _startLabel = new Label(tr("X start value:"), _startContainer);
    _startLayout->addWidget(_startLabel);
    _startLineEdit = new LineEdit(_startContainer);
    _startLineEdit->setText(QString::number(xstart,'g',10));
    _startLineEdit->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("The X of the first value in the ASCII file. This can be a python expression."), NATRON_NAMESPACE::WhiteSpaceNormal) );
    _startLayout->addWidget(_startLineEdit);
    _mainLayout->addWidget(_startContainer);

    //////x increment
    _incrContainer = new QWidget(this);
    _incrLayout = new QHBoxLayout(_incrContainer);
    _incrLabel = new Label(tr("X increment:"), _incrContainer);
    _incrLayout->addWidget(_incrLabel);
    _incrLineEdit = new LineEdit(_incrContainer);
    if (xstart == 0. && xend == 1.) {
        _incrLineEdit->setText(QString::fromUtf8("1./255"));
    } else {
        _incrLineEdit->setText(QString::number(1));
    }
    _incrLineEdit->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("The X increment between two consecutive values. This can be a python expression."), NATRON_NAMESPACE::WhiteSpaceNormal) );
    _incrLayout->addWidget(_incrLineEdit);
    _mainLayout->addWidget(_incrContainer);

    //////x end value
    if (isExportDialog) {
        _endContainer = new QWidget(this);
        _endLayout = new QHBoxLayout(_endContainer);
        _endLabel = new Label(tr("X end value:"), _endContainer);
        _endLabel->setFont( QApplication::font() ); // necessary, or the labels will get the default font size
        _endLayout->addWidget(_endLabel);
        _endLineEdit = new LineEdit(_endContainer);
        _endLineEdit->setText(QString::number(xend,'g',10));
        _incrLineEdit->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("The X of the last value in the ASCII file. This can be a python expression."), NATRON_NAMESPACE::WhiteSpaceNormal) );
        _endLayout->addWidget(_endLineEdit);
        _mainLayout->addWidget(_endContainer);
    }

    ////curves columns
    for (U32 i = 0; i < curves.size(); ++i) {
        CurveColumn column;
        column._curve = curves[i];
        column._curveContainer = new QWidget(this);
        column._curveLayout = new QHBoxLayout(column._curveContainer);
        column._curveLabel = new Label( tr("%1 column:").arg( curves[i]->getName() ) );
        column._curveLabel->setFont( QApplication::font() ); // necessary, or the labels will get the default font size
        column._curveLayout->addWidget(column._curveLabel);
        column._curveSpinBox = new SpinBox(column._curveContainer, SpinBox::eSpinBoxTypeInt);
        column._curveSpinBox->setValue( (double)i + 1. );
        column._curveLayout->addWidget(column._curveSpinBox);
        _curveColumns.push_back(column);
        _mainLayout->addWidget(column._curveContainer);
    }
    /////buttons
    _buttonBox = new DialogButtonBox(QDialogButtonBox::StandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel), Qt::Horizontal, this);
    QObject::connect( _buttonBox, SIGNAL(rejected()), this, SLOT(reject()) );
    QObject::connect( _buttonBox, SIGNAL(accepted()), this, SLOT(accept()) );
    _mainLayout->addWidget(_buttonBox);

    QSettings settings( QString::fromUtf8(NATRON_ORGANIZATION_NAME), QString::fromUtf8(NATRON_APPLICATION_NAME) );
    QByteArray state;
    if (isExportDialog) {
        state = settings.value( QLatin1String("CurveWidgetExportDialog") ).toByteArray();
    } else {
        state = settings.value( QLatin1String("CurveWidgetImportDialog") ).toByteArray();
    }
    if ( !state.isEmpty() ) {
        restoreState(state);
    }
}
std::pair<MoveTangentCommand::SelectedTangentEnum, AnimItemDimViewKeyFrame >
AnimationModuleViewPrivate::isNearbySelectedTangentText(const QPoint & pt) const
{
    QFontMetrics fm( _publicInterface->font() );
    int yOffset = TO_DPIY(4);
    std::pair<MoveTangentCommand::SelectedTangentEnum, AnimItemDimViewKeyFrame > ret;
    
    AnimationModuleBasePtr model = _model.lock();
    const AnimItemDimViewKeyFramesMap& selectedKeys = model->getSelectionModel()->getCurrentKeyFramesSelection();
    if (selectedKeys.empty() || selectedKeys.size() > 1) {
        return ret;
    }

    AnimItemDimViewKeyFramesMap::const_iterator curveIT = selectedKeys.begin();
    const KeyFrameWithStringSet& keys = curveIT->second;
    if (keys.empty() || keys.size() > 1) {
        return ret;
    }

    const KeyFrameWithString& key = *keys.begin();
    CurvePtr curve = curveIT->first.item->getCurve(curveIT->first.dim, curveIT->first.view);
    if (!curve) {
        return ret;
    }
    KeyFrameSet curveKeys = curve->getKeyFrames_mt_safe();

    KeyFrameSet::iterator foundKey = Curve::findWithTime(curveKeys, curveKeys.begin(), key.key.getTime());
    assert(foundKey != curveKeys.end());
    if (foundKey == curveKeys.end()) {
        return ret;
    }
    for (KeyFrameWithStringSet::const_iterator it = keys.begin(); it != keys.end(); ++it) {


        QPointF leftTanPos, rightTanPos;
        _publicInterface->getKeyTangentPoints(foundKey, curveKeys, &leftTanPos, &rightTanPos);

        double rounding = std::pow(10., CURVEWIDGET_DERIVATIVE_ROUND_PRECISION);
        QPointF topLeft_LeftTanWidget = curveEditorZoomContext.toWidgetCoordinates( leftTanPos.x(), leftTanPos.y() );
        QPointF topLeft_RightTanWidget = curveEditorZoomContext.toWidgetCoordinates( rightTanPos.x(), rightTanPos.y() );
        topLeft_LeftTanWidget.ry() += yOffset;
        topLeft_RightTanWidget.ry() += yOffset;

        QString leftCoordStr =  QString( tr("l: %1") ).arg(std::floor( ( key.key.getLeftDerivative() * rounding ) + 0.5 ) / rounding);
        QString rightCoordStr =  QString( tr("r: %1") ).arg(std::floor( ( key.key.getRightDerivative() * rounding ) + 0.5 ) / rounding);
        QPointF btmRight_LeftTanWidget( topLeft_LeftTanWidget.x() + fm.width(leftCoordStr), topLeft_LeftTanWidget.y() + fm.height() );
        QPointF btmRight_RightTanWidget( topLeft_RightTanWidget.x() + fm.width(rightCoordStr), topLeft_RightTanWidget.y() + fm.height() );

        if ( (pt.x() >= topLeft_LeftTanWidget.x() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) && (pt.x() <= btmRight_LeftTanWidget.x() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) &&
            ( pt.y() >= topLeft_LeftTanWidget.y() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) && ( pt.y() <= btmRight_LeftTanWidget.y() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) {
            ret.second.key.key = key.key;
            StringAnimationManagerPtr stringAnim = curveIT->first.item->getInternalAnimItem()->getStringAnimation();
            if (stringAnim) {
                stringAnim->stringFromInterpolatedIndex(key.key.getValue(), curveIT->first.view, &ret.second.key.string);
            }
            ret.second.id = curveIT->first;
            ret.first = MoveTangentCommand::eSelectedTangentLeft;
        } else if ( (pt.x() >= topLeft_RightTanWidget.x() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) && (pt.x() <= btmRight_RightTanWidget.x() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) &&
                   ( pt.y() >= topLeft_RightTanWidget.y() - TO_DPIX(CLICK_DISTANCE_TOLERANCE)) && ( pt.y() <= btmRight_RightTanWidget.y() + TO_DPIX(CLICK_DISTANCE_TOLERANCE)) ) {
            ret.second.key.key = key.key;
            StringAnimationManagerPtr stringAnim = curveIT->first.item->getInternalAnimItem()->getStringAnimation();
            if (stringAnim) {
                stringAnim->stringFromInterpolatedIndex(key.key.getValue(), curveIT->first.view, &ret.second.key.string);
            }
            ret.second.id = curveIT->first;
            ret.first = MoveTangentCommand::eSelectedTangentRight;
        }



    } // for all curves
    return ret;

} // isNearbySelectedTangentText