diff --git a/kmplot/calculator.cpp b/kmplot/calculator.cpp index 5473b6b..9559538 100644 --- a/kmplot/calculator.cpp +++ b/kmplot/calculator.cpp @@ -1,98 +1,97 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2007 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "calculator.h" #include "equationedit.h" #include "equationeditorwidget.h" #include "xparser.h" #include #include #include #include #include //BEGIN class Calculator Calculator::Calculator( QWidget * parent ) : QDialog( parent ) { setModal( false ); QWidget * widget = new QWidget( this ); setWindowTitle( i18n("Calculator") ); - QVBoxLayout *layout = new QVBoxLayout( widget ); - layout->setMargin( 0 ); - + QVBoxLayout *layout = new QVBoxLayout( this ); + m_display = new KTextEdit( widget ); QSizePolicy displaySizePolicy = m_display->sizePolicy(); displaySizePolicy.setVerticalStretch( 10 ); displaySizePolicy.setVerticalPolicy( QSizePolicy::MinimumExpanding ); m_display->setSizePolicy( displaySizePolicy ); layout->addWidget( m_display ); m_input = new EquationEditorWidget( this ); layout->addWidget( m_input ); m_display->setReadOnly( true ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::accepted, this, &Calculator::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &Calculator::reject); layout->addWidget( buttonBox ); connect(m_input->edit, &EquationEdit::returnPressed, this, &Calculator::calculate); // Set minimum size and margin to avoid cutting the right side resize( 1.05*layout->minimumSize() ); m_input->edit->setFocus(); } Calculator::~Calculator() { m_input->deleteLater(); } void Calculator::calculate() { Parser::Error error; double value = XParser::self()->eval( m_input->edit->text(), &error ); m_displayText += m_input->edit->text().replace( '<', "<" ); if ( error == Parser::ParseSuccess ) m_displayText += " = " + Parser::number( value ) + ""; else m_displayText += " = ? (" + Parser::errorString( error ) + ")"; m_displayText += "
"; m_display->document()->setHtml( m_displayText ); m_display->verticalScrollBar()->setValue( m_display->verticalScrollBar()->maximum() ); m_input->edit->selectAll(); } //END class Calculator diff --git a/kmplot/equationeditor.cpp b/kmplot/equationeditor.cpp index ba98b28..ee31a97 100644 --- a/kmplot/equationeditor.cpp +++ b/kmplot/equationeditor.cpp @@ -1,56 +1,58 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2006 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "equationeditor.h" #include #include "equationeditorwidget.h" #include "equationeditwidget.h" EquationEditor::EquationEditor(QWidget* parent) : QDialog(parent) { m_widget = new EquationEditorWidget(this); m_widget->edit->showEditButton(false); m_widget->edit->m_equationEditWidget->setClearSelectionOnFocusOut(false); m_widget->layout()->setMargin(0); setWindowTitle(i18n("Equation Editor")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::rejected, this, &EquationEditor::reject); - m_widget->layout()->addWidget(buttonBox); + QVBoxLayout *dialogLayout = new QVBoxLayout (this); + dialogLayout->addWidget (m_widget); + dialogLayout->addWidget (buttonBox); connect(m_widget->edit, &EquationEdit::returnPressed, this, &EquationEditor::accept); } QString EquationEditor::text() const { return m_widget->edit->text(); } EquationEdit* EquationEditor::edit() const { return m_widget->edit; } diff --git a/kmplot/functiontools.cpp b/kmplot/functiontools.cpp index 45ad7db..209e323 100644 --- a/kmplot/functiontools.cpp +++ b/kmplot/functiontools.cpp @@ -1,239 +1,238 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2004 Fredrik Edemar * 2006 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "functiontools.h" #include "ui_functiontools.h" #include "view.h" #include "xparser.h" #include class FunctionToolsWidget : public QWidget, public Ui::FunctionTools { public: FunctionToolsWidget( QWidget * parent = 0 ) : QWidget( parent ) { setupUi(this); } }; //BEGIN class FunctionTools FunctionTools::FunctionTools(QWidget *parent ) : QDialog( parent ) { m_widget = new FunctionToolsWidget( this ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::rejected, this, &FunctionTools::reject); - m_widget->layout()->addWidget(buttonBox); - - // Adjust margins - m_widget->layout()->setMargin( 0 ); + QVBoxLayout *dialogLayout = new QVBoxLayout (this); + dialogLayout->addWidget (m_widget); + dialogLayout->addWidget (buttonBox); init( CalculateArea ); connect(m_widget->min, &EquationEdit::editingFinished, this, &FunctionTools::rangeEdited); connect(m_widget->max, &EquationEdit::editingFinished, this, &FunctionTools::rangeEdited); connect(m_widget->list, &QListWidget::currentRowChanged, this, &FunctionTools::equationSelected); } FunctionTools::~FunctionTools() { } void FunctionTools::init( Mode m ) { m_mode = m; switch ( m_mode ) { case FindMinimum: { m_widget->rangeTitle->setText( i18n("Search between:") ); setWindowTitle(i18n("Find Minimum Point")); break; } case FindMaximum: { m_widget->rangeTitle->setText( i18n("Search between:") ); setWindowTitle(i18n("Find Maximum Point")); break; } case CalculateArea: { m_widget->rangeTitle->setText( i18n("Calculate the area between:") ); setWindowTitle(i18n("Area Under Graph")); break; } } m_widget->min->setText( XParser::self()->number( View::self()->m_xmin ) ); m_widget->max->setText( XParser::self()->number( View::self()->m_xmax ) ); m_widget->min->setFocus(); updateEquationList(); setEquation( EquationPair( View::self()->m_currentPlot, 0 ) ); } void FunctionTools::updateEquationList() { EquationPair previousEquation = equation(); m_widget->list->clear(); m_equations.clear(); foreach ( Function * function, XParser::self()->m_ufkt ) { if ( function->type() != Function::Cartesian && function->type() != Function::Differential ) continue; QList plots = function->plots(); for ( int i = 0; i < function->eq.size(); ++i ) { foreach ( const Plot &plot, plots ) m_equations << EquationPair( plot, i ); } } foreach ( const EquationPair &eq, m_equations ) { Equation * equation = eq.first.function()->eq[ eq.second ]; QListWidgetItem * item = new QListWidgetItem( equation->fstr(), m_widget->list ); item->setTextColor( eq.first.color() ); } setEquation( previousEquation ); } EquationPair FunctionTools::equation( ) const { int row = m_widget->list->currentRow(); if ( row < 0 || row >= m_equations.size() ) return EquationPair(); else return m_equations[ row ]; } void FunctionTools::setEquation( const EquationPair & equation ) { int row = m_equations.indexOf( equation); if ( row < 0 ) row = 0; m_widget->list->setCurrentRow( row ); equationSelected( row ); } void FunctionTools::equationSelected( int equation ) { if ( equation < 0 || equation >= m_equations.size() ) return; EquationPair current = m_equations[ equation ]; switch ( m_mode ) { case FindMinimum: findMinimum( current ); break; case FindMaximum: findMaximum( current ); break; case CalculateArea: calculateArea( current ); break; } } void FunctionTools::rangeEdited() { switch ( m_mode ) { case FindMinimum: findMinimum( equation() ); break; case FindMaximum: findMaximum( equation() ); break; case CalculateArea: calculateArea( equation() ); break; } } void FunctionTools::findMinimum( const EquationPair & equation ) { if ( !equation.first.function() ) return; QPointF extremum = View::self()->findMinMaxValue( equation.first, View::Minimum, m_widget->min->value(), m_widget->max->value() ); m_widget->rangeResult->setText( i18n("Minimum is at x = %1, %2(x) = %3", extremum.x(), equation.first.function()->eq[0]->name(), extremum.y() ) ); } void FunctionTools::findMaximum( const EquationPair & equation ) { if ( !equation.first.function() ) return; QPointF extremum = View::self()->findMinMaxValue( equation.first, View::Maximum, m_widget->min->value(), m_widget->max->value() ); m_widget->rangeResult->setText( i18n("Maximum is at x = %1, %2(x) = %3", extremum.x(), equation.first.function()->eq[0]->name(), extremum.y() ) ); } void FunctionTools::calculateArea( const EquationPair & equation ) { if ( !equation.first.function() ) return; IntegralDrawSettings s; s.plot = equation.first; s.dmin = m_widget->min->value(); s.dmax = m_widget->max->value(); double area = View::self()->areaUnderGraph( s ); m_widget->rangeResult->setText( i18n("Area is %1", area ) ); } //END class FunctionTools diff --git a/kmplot/kconstanteditor.cpp b/kmplot/kconstanteditor.cpp index b0107cf..82514cb 100644 --- a/kmplot/kconstanteditor.cpp +++ b/kmplot/kconstanteditor.cpp @@ -1,276 +1,278 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2004 Fredrik Edemar * 2006 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "kconstanteditor.h" #include "kmplotio.h" #include "view.h" #include "xparser.h" #include #include #include #include #include #include #include #include "ui_constantseditor.h" class ConstantsEditorWidget : public QWidget, public Ui::ConstantsEditor { public: ConstantsEditorWidget( QWidget * parent = 0 ) : QWidget( parent ) { setupUi(this); } }; //BEGIN class KConstantEditor KConstantEditor::KConstantEditor( QWidget * parent ) : QDialog( parent ) { m_widget = new ConstantsEditorWidget( this ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::rejected, this, &KConstantEditor::reject); - m_widget->gridLayout->addWidget(buttonBox, 4, 1, 1, 1); + QVBoxLayout *dialogLayout = new QVBoxLayout (this); + dialogLayout->addWidget(m_widget); + dialogLayout->addWidget(buttonBox); m_widget->cmdNew->setIcon( QIcon::fromTheme("document-new") ); m_widget->cmdDelete->setIcon( QIcon::fromTheme("edit-delete") ); setWindowTitle( i18n("Constants Editor") ); connect( this, &KConstantEditor::finished, this, &KConstantEditor::dialogFinished ); m_constantValidator = new ConstantValidator( this ); m_widget->nameEdit->setValidator( m_constantValidator ); updateConstantsList(); connect( m_widget->nameEdit, &KLineEdit::textEdited, this, &KConstantEditor::constantNameEdited ); connect( m_widget->valueEdit, &EquationEdit::textEdited, this, &KConstantEditor::saveCurrentConstant ); connect( m_widget->nameEdit, &KLineEdit::textChanged, this, &KConstantEditor::checkValueValid ); connect( m_widget->valueEdit, &EquationEdit::textChanged, this, &KConstantEditor::checkValueValid ); connect( m_widget->cmdNew, &QPushButton::clicked, this, &KConstantEditor::cmdNew_clicked ); connect( m_widget->cmdDelete, &QPushButton::clicked, this, &KConstantEditor::cmdDelete_clicked ); connect( m_widget->constantList, &QTreeWidget::currentItemChanged, this, &KConstantEditor::selectedConstantChanged ); connect( m_widget->constantList, &QTreeWidget::itemClicked, this, &KConstantEditor::itemClicked ); connect( XParser::self()->constants(), &Constants::constantsChanged, this, &KConstantEditor::updateConstantsList ); checkValueValid(); } KConstantEditor::~KConstantEditor() { } void KConstantEditor::dialogFinished() { XParser::self()->reparseAllFunctions(); View::self()->drawPlot(); } void KConstantEditor::updateConstantsList( ) { m_widget->constantList->blockSignals( true ); // This assumes that constants have only been added or their value changed. // (since constants can only be removed via this dialog) ConstantList constants = XParser::self()->constants()->list( Constant::All ); for ( ConstantList::iterator it = constants.begin(); it != constants.end(); ++it ) { QList list = m_widget->constantList->findItems( it.key(), Qt::MatchExactly ); if ( !list.isEmpty() ) init( list.first(), it.key(), it.value() ); else { QTreeWidgetItem * item = new QTreeWidgetItem( m_widget->constantList ); init( item, it.key(), it.value() ); } } m_widget->constantList->blockSignals( false ); } void KConstantEditor::init( QTreeWidgetItem * item, const QString & name, const Constant & constant ) { item->setText( 0, name ); item->setText( 1, constant.value.expression() ); item->setData( 2, Qt::CheckStateRole, (constant.type & Constant::Document) ? Qt::Checked : Qt::Unchecked ); item->setData( 2, Qt::ToolTipRole, i18n("Check this to have the constant exported when saving.") ); // item->setData( 2, Qt::WhatsThisRole, i18n("Document constants are saved with the documents, and will be loaded again when the document is opened.") ); item->setData( 3, Qt::CheckStateRole, (constant.type & Constant::Global) ? Qt::Checked : Qt::Unchecked ); item->setData( 3, Qt::ToolTipRole, i18n("Check this to have the constant permanently available between instances of KmPlot.") ); // item->setData( 3, Qt::WhatsThisRole, i18n("Global constants are stored in KmPlot's settings. They are not lost when KmPlot is closed.") ); } void KConstantEditor::cmdNew_clicked() { QTreeWidgetItem * item = new QTreeWidgetItem( m_widget->constantList ); init( item, XParser::self()->constants()->generateUniqueName(), Constant() ); m_widget->constantList->setCurrentItem( item ); m_widget->nameEdit->setFocus(); } void KConstantEditor::cmdDelete_clicked() { QTreeWidgetItem * item = m_widget->constantList->currentItem(); if ( !item ) return; XParser::self()->constants()->remove( item->text(0) ); m_widget->nameEdit->clear(); m_widget->valueEdit->clear(); m_widget->constantList->takeTopLevelItem( m_widget->constantList->indexOfTopLevelItem( item ) ); delete item; m_widget->cmdDelete->setEnabled( m_widget->constantList->currentItem() != 0 ); } void KConstantEditor::selectedConstantChanged( QTreeWidgetItem * current ) { m_widget->cmdDelete->setEnabled( current != 0 ); QString name = current ? current->text(0) : QString(); QString value = current ? current->text(1) : QString(); m_previousConstantName = name; m_constantValidator->setWorkingName( m_previousConstantName ); m_widget->nameEdit->setText( name ); m_widget->valueEdit->setText( value ); } void KConstantEditor::constantNameEdited( const QString & newName ) { QTreeWidgetItem * current = m_widget->constantList->currentItem(); if ( !current ) { Constant constant; constant.value.updateExpression( m_widget->valueEdit->text() ); current = new QTreeWidgetItem( m_widget->constantList ); init( current, newName, constant ); } XParser::self()->constants()->remove( m_previousConstantName ); current->setText( 0, newName ); m_widget->constantList->setCurrentItem( current ); // make it the current item if no item was selected before m_previousConstantName = newName; m_constantValidator->setWorkingName( m_previousConstantName ); saveCurrentConstant(); } void KConstantEditor::saveCurrentConstant() { if ( m_widget->nameEdit->text().isEmpty() ) return; QTreeWidgetItem * current = m_widget->constantList->currentItem(); assert( current ); current->setText( 1, m_widget->valueEdit->text() ); Constant constant; constant.value.updateExpression( m_widget->valueEdit->text() ); // update type constant.type = 0; if ( current->data( 2, Qt::CheckStateRole ).toBool() ) constant.type |= Constant::Document; if ( current->data( 3, Qt::CheckStateRole ).toBool() ) constant.type |= Constant::Global; XParser::self()->constants()->add( m_widget->nameEdit->text(), constant ); } bool KConstantEditor::checkValueValid() { Parser::Error error; (double) XParser::self()->eval( m_widget->valueEdit->text(), & error ); bool valid = (error == Parser::ParseSuccess) && m_constantValidator->isValid( m_widget->nameEdit->text() ); m_widget->valueInvalidLabel->setVisible( !valid ); return valid; } void KConstantEditor::itemClicked() { QTimer::singleShot( 0, this, SLOT(saveCurrentConstant()) ); } //END class KConstantEditor //BEGIN class ConstantValidator ConstantValidator::ConstantValidator( KConstantEditor * parent ) : QValidator( parent ) { } bool ConstantValidator::isValid( const QString & name ) const { bool correct = XParser::self()->constants()->isValidName( name ); bool inUse = XParser::self()->constants()->have( name ) && (m_workingName != name); return correct && !inUse; } QValidator::State ConstantValidator::validate( QString & input, int & /*pos*/ ) const { return isValid( input ) ? Acceptable : Intermediate; } void ConstantValidator::setWorkingName( const QString & name ) { m_workingName = name; } //END class ConstantValidator diff --git a/kmplot/kgradientdialog.cpp b/kmplot/kgradientdialog.cpp index d46d6da..d53cbe4 100644 --- a/kmplot/kgradientdialog.cpp +++ b/kmplot/kgradientdialog.cpp @@ -1,553 +1,553 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2006 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "kgradientdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include const double SQRT_3 = 1.732050808; const double ArrowLength = 8; const double ArrowHalfWidth = ArrowLength/SQRT_3; //BEGIN class KGradientEditor KGradientEditor::KGradientEditor( QWidget * parent ) : QWidget( parent ) { m_haveArrow = false; m_clickOffset = 0; m_orientation = Qt::Horizontal; findGradientStop(); } KGradientEditor::~KGradientEditor() { } void KGradientEditor::setGradient( const QGradient & gradient ) { if ( m_gradient == gradient ) return; setGradient( gradient.stops() ); findGradientStop(); } void KGradientEditor::setColor( const QColor & color ) { // Hmm...why doesn't qvector have some sortof search / replace functionality? QGradientStops stops = m_gradient.stops(); for ( int i = 0; i < stops.size(); ++i ) { if ( stops[i] != m_currentStop ) continue; if ( stops[i].second == color ) return; m_currentStop.second = color; stops[i] = m_currentStop; break; } setGradient( stops ); } QSize KGradientEditor::minimumSizeHint() const { double w = 3 * ArrowHalfWidth; double h = 12 + ArrowLength; if ( m_orientation == Qt::Vertical ) qSwap( w, h ); return QSizeF( w, h ).toSize(); } void KGradientEditor::paintEvent( QPaintEvent * ) { QPainter painter( this ); //BEGIN draw gradient QRectF r; QLinearGradient lg; if ( m_orientation == Qt::Horizontal ) { lg = QLinearGradient( 0, 0, width(), 0 ); r = QRectF( ArrowHalfWidth-1, 0, width() - 2*ArrowHalfWidth + 1, height()-ArrowLength ); } else { lg = QLinearGradient( 0, 0, 0, height() ); r = QRectF( 0, ArrowHalfWidth-1, width()-ArrowLength, height() - 2*ArrowHalfWidth + 1 ); } lg.setStops( m_gradient.stops() ); painter.setBrush( lg ); painter.setPen( QPen( Qt::black, 1 ) ); painter.drawRect( r ); //END draw gradient //BEGIN draw arrows painter.setRenderHint( QPainter::Antialiasing, true ); QGradientStops stops = m_gradient.stops(); foreach ( const QGradientStop &stop, stops ) drawArrow( & painter, stop ); //END draw arrows } void KGradientEditor::drawArrow( QPainter * painter, const QGradientStop & stop ) { QPolygonF arrow(3); double mid = toArrowPos( stop.first ); if ( m_orientation == Qt::Horizontal ) { arrow[0] = QPointF( mid, height()-ArrowLength+0.5 ); arrow[1] = QPointF( mid+ArrowHalfWidth, height()-0.5 ); arrow[2] = QPointF( mid-ArrowHalfWidth, height()-0.5 ); } else { arrow[0] = QPointF( width()-ArrowLength+0.5, mid ); arrow[1] = QPointF( width()-0.5, mid+ArrowHalfWidth ); arrow[2] = QPointF( width()-0.5, mid-ArrowHalfWidth ); } bool selected = (stop == m_currentStop); QColor color( selected ? palette().color( QPalette::Dark ) : Qt::black ); painter->setPen( color ); painter->setBrush( stop.second ); painter->drawPolygon( arrow ); } void KGradientEditor::contextMenuEvent( QContextMenuEvent * e ) { // Prevent the "QWhatsThis" menu from popping up when right-clicking e->accept(); } void KGradientEditor::removeStop() { QGradientStops stops = m_gradient.stops(); for ( int i = 0; i < stops.size(); ++i ) { if ( stops[i] != m_currentStop ) continue; stops.remove( i ); break; } setGradient( stops ); findGradientStop(); } void KGradientEditor::mousePressEvent( QMouseEvent * e ) { if ( !getGradientStop( e->pos() ) ) return; e->accept(); if ( e->button() == Qt::RightButton ) removeStop(); else m_haveArrow = true; } bool KGradientEditor::getGradientStop( const QPoint & point ) { double dl; // the vertical (for horizontal layout) distance from the tip of the arrows if ( m_orientation == Qt::Horizontal ) dl = point.y() - (height() - ArrowLength); else dl = point.x() - (width() - ArrowLength); // Is the arrow in the strip? if ( dl < 0 ) return false; QGradientStops stops = m_gradient.stops(); // Iterate over stops in reverse as the last stops are displayed on top of // the first stops. for ( int i = stops.size()-1; i >= 0; --i ) { QGradientStop stop = stops[i]; double pos = toArrowPos( stop.first ); // Is the click inside the arrow? double lower = pos - dl*(ArrowHalfWidth/ArrowLength); double upper = pos + dl*(ArrowHalfWidth/ArrowLength); double x = (m_orientation == Qt::Horizontal) ? point.x() : point.y(); if ( x < lower || x > upper ) continue; // Is inside arrow! :) m_clickOffset = x - pos; setCurrentStop( stop ); return true; } return false; } void KGradientEditor::mouseMoveEvent( QMouseEvent * e ) { if ( !m_haveArrow ) return; e->accept(); QPoint point = e->pos(); // Hmm...why doesn't qvector have some sortof search / replace functionality? QGradientStops stops = m_gradient.stops(); for ( int i = 0; i < stops.size(); ++i ) { if ( stops[i] != m_currentStop ) continue; double x = (m_orientation == Qt::Horizontal) ? point.x() : point.y(); m_currentStop.first = fromArrowPos( x-m_clickOffset ); stops[i] = m_currentStop; break; } setGradient( stops ); } void KGradientEditor::mouseReleaseEvent( QMouseEvent * ) { m_haveArrow = false; } void KGradientEditor::mouseDoubleClickEvent( QMouseEvent * e ) { e->accept(); if ( getGradientStop( e->pos() ) ) return; // Create new stop QPoint point = e->pos(); double pos = fromArrowPos( (m_orientation == Qt::Horizontal) ? point.x() : point.y() ); QGradientStop stop; stop.first = pos; stop.second = Qt::red; QGradientStops stops = m_gradient.stops(); stops << stop; setGradient( stops ); setCurrentStop( stop ); } void KGradientEditor::setOrientation( Qt::Orientation orientation ) { m_orientation = orientation; update(); } void KGradientEditor::findGradientStop() { QGradientStops stops = m_gradient.stops(); // The QGradientStops should always have at least one stop in, since // QGradient returns a Black->White gradient if its stops are empty. Q_ASSERT( !stops.isEmpty() ); // Pick a stop in the center setCurrentStop( stops[ stops.size()/2 ] ); } void KGradientEditor::setCurrentStop( const QGradientStop & stop ) { if ( m_currentStop == stop ) return; bool colorChanged = stop.second != m_currentStop.second; m_currentStop = stop; update(); if ( colorChanged ) emit colorSelected( stop.second ); } void KGradientEditor::setGradient( const QGradientStops & stops ) { if ( stops == m_gradient.stops() ) return; m_gradient.setStops( stops ); update(); emit gradientChanged( m_gradient ); } double KGradientEditor::toArrowPos( double stop ) const { double l = (m_orientation == Qt::Horizontal) ? width() : height(); l -= 2*ArrowHalfWidth; return stop*l + ArrowHalfWidth; } double KGradientEditor::fromArrowPos( double pos ) const { double l = (m_orientation == Qt::Horizontal) ? width() : height(); l -= 2*ArrowHalfWidth; double stop = (pos - ArrowHalfWidth) / l; if ( stop < 0 ) stop = 0; else if ( stop > 1 ) stop = 1; return stop; } //END class KGradientEditor //BEGIN class KGradientDialog KGradientDialog::KGradientDialog( QWidget * parent, bool modal ) : QDialog( parent ) { QWidget * widget = new QWidget( this ); m_gradient = new KGradientEditor( widget ); m_colorDialog = new QColorDialog( widget ); m_colorDialog->setWindowFlags( Qt::Widget ); m_colorDialog->setOptions( QColorDialog::DontUseNativeDialog | QColorDialog::NoButtons ); QLabel * label = new QLabel( i18n("(Double-click on the gradient to add a stop)"), widget ); QPushButton * button = new QPushButton( i18n("Remove stop"), widget ); connect( button, &QPushButton::clicked, m_gradient, &KGradientEditor::removeStop ); QDialogButtonBox *buttonBox = new QDialogButtonBox(modal ? QDialogButtonBox::Ok|QDialogButtonBox::Cancel : QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::accepted, this, &KGradientDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &KGradientDialog::reject); //BEGIN layout widgets - QVBoxLayout * layout = new QVBoxLayout( widget ); + QVBoxLayout * layout = new QVBoxLayout( this ); layout->setMargin( 0 ); m_gradient->setFixedHeight( 24 ); layout->addWidget( m_gradient ); QHBoxLayout * hLayout = new QHBoxLayout; hLayout->addWidget( label ); hLayout->addStretch( 1 ); hLayout->addWidget( button ); layout->addLayout( hLayout ); layout->addWidget( m_colorDialog ); layout->addWidget( buttonBox ); resize( layout->minimumSize() ); //END layout widgets setWindowTitle( i18n("Choose a Gradient") ); setModal( modal ); connect( m_gradient, &KGradientEditor::colorSelected, m_colorDialog, &QColorDialog::setCurrentColor ); connect( m_colorDialog, &QColorDialog::currentColorChanged, m_gradient, &KGradientEditor::setColor ); connect( m_gradient, &KGradientEditor::gradientChanged, this, &KGradientDialog::gradientChanged ); m_colorDialog->setCurrentColor( m_gradient->color() ); } KGradientDialog::~KGradientDialog() { } // static int KGradientDialog::getGradient( QGradient & gradient, QWidget * parent ) { QPointer dlg = new KGradientDialog( parent, true ); dlg->setGradient( gradient ); int result = dlg->exec(); if ( result == Accepted ) gradient = dlg->gradient(); delete dlg; return result; } void KGradientDialog::setGradient( const QGradient & gradient ) { m_gradient->setGradient( gradient ); } QGradient KGradientDialog::gradient() const { return m_gradient->gradient(); } //END class KGradientDialog //BEGIN class KGradientButton KGradientButton::KGradientButton( QWidget * parent ) : QPushButton( parent ) { connect( this, &KGradientButton::clicked, this, &KGradientButton::chooseGradient ); } KGradientButton::~KGradientButton() { } void KGradientButton::initStyleOption( QStyleOptionButton * opt ) const { opt->init(this); opt->text.clear(); opt->icon = QIcon(); opt->features = QStyleOptionButton::None; } QSize KGradientButton::sizeHint() const { QStyleOptionButton opt; initStyleOption(&opt); return style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(40, 15), this). expandedTo(QApplication::globalStrut()); } void KGradientButton::setGradient( const QGradient & gradient ) { if ( m_gradient.stops() == gradient.stops() ) return; m_gradient.setStops( gradient.stops() ); emit gradientChanged( m_gradient ); } void KGradientButton::chooseGradient() { int result = KGradientDialog::getGradient( m_gradient, this ); if ( result == KGradientDialog::Accepted ) emit gradientChanged( m_gradient ); } void KGradientButton::paintEvent( QPaintEvent * ) { // Mostly copied verbatim from KColorButton - thanks! :) QPainter painter(this); // First, we need to draw the bevel. QStyleOptionButton butOpt; initStyleOption(&butOpt); style()->drawControl( QStyle::CE_PushButtonBevel, &butOpt, &painter, this ); // OK, now we can muck around with drawing out pretty little color box // First, sort out where it goes QRect labelRect = style()->subElementRect( QStyle::SE_PushButtonContents, &butOpt, this ); int shift = style()->pixelMetric( QStyle::PM_ButtonMargin ); labelRect.adjust(shift, shift, -shift, -shift); int x, y, w, h; labelRect.getRect(&x, &y, &w, &h); if (isChecked() || isDown()) { x += style()->pixelMetric( QStyle::PM_ButtonShiftHorizontal ); y += style()->pixelMetric( QStyle::PM_ButtonShiftVertical ); } qDrawShadePanel( &painter, x, y, w, h, palette(), true, 1, NULL); if ( isEnabled() ) { QLinearGradient lg( x+1, 0, x+w-1, 0 ); lg.setStops( m_gradient.stops() ); painter.setBrush( lg ); } else painter.setBrush( palette().color(backgroundRole()) ); painter.drawRect( x+1, y+1, w-2, h-2 ); if ( hasFocus() ) { QRect focusRect = style()->subElementRect( QStyle::SE_PushButtonFocusRect, &butOpt, this ); QStyleOptionFocusRect focusOpt; focusOpt.init(this); focusOpt.rect = focusRect; focusOpt.backgroundColor = palette().background().color(); style()->drawPrimitive( QStyle::PE_FrameFocusRect, &focusOpt, &painter, this ); } } //END class KGradientButton diff --git a/kmplot/ksliderwindow.cpp b/kmplot/ksliderwindow.cpp index b6eaf84..48def16 100644 --- a/kmplot/ksliderwindow.cpp +++ b/kmplot/ksliderwindow.cpp @@ -1,136 +1,134 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2005 Fredrik Edemar * 2007 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ // local includes #include "ksliderwindow.h" #include "view.h" #include "xparser.h" #include #include #include #include #include #include //BEGIN class SliderWidget SliderWidget::SliderWidget( QWidget *parent, int number ) : QGroupBox( i18n( "Slider %1", number+1 ), parent ) { m_number = number; setupUi( this ); slider->setToolTip( i18n( "Move slider to change the parameter of the function plot connected to this slider." ) ); KConfig config( "kmplotrc" ); KConfigGroup group = config.group( "slider" + QString::number(m_number) ); min->setText( group.readEntry( "min", "0" ) ); max->setText( group.readEntry( "max", "10" ) ); slider->setValue( group.readEntry( "value", 500 ) ); connect(slider, &QSlider::valueChanged, this, &SliderWidget::updateValue); connect(min, &EquationEdit::editingFinished, this, &SliderWidget::updateValue); connect(max, &EquationEdit::editingFinished, this, &SliderWidget::updateValue); updateValue(); } SliderWidget::~SliderWidget() { KConfig config( "kmplotrc" ); KConfigGroup group = config.group( "slider" + QString::number(m_number) ); group.writeEntry( "min", min->text() ); group.writeEntry( "max", max->text() ); group.writeEntry( "value", slider->value() ); } void SliderWidget::updateValue() { valueLabel->setText( View::self()->posToString( value(), 0.001*(max->value() - min->value()), View::DecimalFormat ) ); emit valueChanged(); } double SliderWidget::value() { double prop = double(slider->value() - slider->minimum()) / double(slider->maximum() - slider->minimum()); return prop * (max->value() - min->value()) + min->value(); } //END class SliderWidget //BEGIN class KSliderWindow KSliderWindow::KSliderWindow( QWidget * parent ) : QDialog( parent ) { setModal( false ); QWidget * widget = new QWidget( this ); setWindowTitle( i18n("Sliders") ); - QVBoxLayout *layout = new QVBoxLayout( widget ); - setLayout(layout); + + QVBoxLayout *layout = new QVBoxLayout( this ); layout->addWidget(widget); Q_ASSERT( SLIDER_COUNT == 4 ); // safety check, in case SLIDER_COUNT is increased but not this code - - layout->setMargin( 0 ); - + for ( int i = 0; i < SLIDER_COUNT; ++i ) { m_sliders[i] = new SliderWidget( widget, i ); connect( m_sliders[i], &SliderWidget::valueChanged, this, &KSliderWindow::valueChanged ); layout->addWidget( m_sliders[i] ); } QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::rejected, this, &KSliderWindow::reject); layout->addWidget(buttonBox); resize( layout->minimumSize() ); } KSliderWindow::~KSliderWindow() { } double KSliderWindow::value( int slider ) { Q_ASSERT( (slider>=0) && (slider < SLIDER_COUNT) ); return m_sliders[slider]->value(); } void KSliderWindow::closeEvent( QCloseEvent * e) { emit windowClosed(); e->accept(); } //END class KSliderWindow diff --git a/kmplot/parameteranimator.cpp b/kmplot/parameteranimator.cpp index d3940d7..26abcb0 100644 --- a/kmplot/parameteranimator.cpp +++ b/kmplot/parameteranimator.cpp @@ -1,252 +1,255 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2006 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "parameteranimator.h" #include "ui_parameteranimator.h" #include "view.h" #include #include #include #include #include #include using namespace std; #ifndef KDEWIN_MATH_H double inline log(int n) { return log(double(n)); } #endif class ParameterAnimatorWidget : public QWidget, public Ui::ParameterAnimator { public: ParameterAnimatorWidget( QWidget * parent = 0 ) : QWidget( parent ) { setupUi(this); } }; //BEGIN class ParameterAnimator ParameterAnimator::ParameterAnimator( QWidget * parent, Function * function ) : QDialog( parent ), m_function( function ) { m_widget = new ParameterAnimatorWidget( this ); setWindowTitle( i18n("Parameter Animator") ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::rejected, this, &ParameterAnimator::reject); - m_widget->layout()->addWidget(buttonBox); + + QVBoxLayout *dialogLayout = new QVBoxLayout( this ); + dialogLayout->addWidget(m_widget); + dialogLayout->addWidget(buttonBox); m_mode = Paused; m_currentValue = 0; m_function->m_parameters.animating = true; m_function->k = m_currentValue; if ( function->eq[0]->usesParameter() ) m_widget->warningLabel->hide(); m_timer = new QTimer( this ); connect(m_timer, &QTimer::timeout, this, &ParameterAnimator::step); m_widget->gotoInitial->setIcon( QIcon::fromTheme( "go-first" ) ); m_widget->gotoFinal->setIcon( QIcon::fromTheme( "go-last" ) ); m_widget->stepBackwards->setIcon( QIcon::fromTheme( "go-previous" ) ); m_widget->stepForwards->setIcon( QIcon::fromTheme( "go-next" ) ); m_widget->pause->setIcon( QIcon::fromTheme( "media-playback-pause" ) ); connect(m_widget->gotoInitial, &QToolButton::clicked, this, &ParameterAnimator::gotoInitial); connect(m_widget->gotoFinal, &QToolButton::clicked, this, &ParameterAnimator::gotoFinal); connect(m_widget->stepBackwards, &QToolButton::toggled, this, &ParameterAnimator::stepBackwards); connect(m_widget->stepForwards, &QToolButton::toggled, this, &ParameterAnimator::stepForwards); connect(m_widget->pause, &QToolButton::clicked, this, &ParameterAnimator::pause); connect(m_widget->speed, &QSlider::valueChanged, this, &ParameterAnimator::updateSpeed); updateUI(); updateFunctionParameter(); connect(this, &ParameterAnimator::finished, this, &ParameterAnimator::deleteLater); } ParameterAnimator::~ ParameterAnimator() { qDebug() ; m_function->m_parameters.animating = false; View::self()->drawPlot(); } void ParameterAnimator::step() { // This function shouldn't get called when we aren't actually stepping assert( m_mode != Paused ); double dx = m_widget->step->value(); bool increasing = ( (m_mode == StepBackwards && (dx < 0)) || (m_mode == StepForwards && (dx > 0)) ); bool decreasing = ( (m_mode == StepBackwards && (dx > 0)) || (m_mode == StepForwards && (dx < 0)) ); double upper = m_widget->final->value(); double lower = m_widget->initial->value(); if ( lower > upper ) qSwap( lower, upper ); if ( (increasing && (m_currentValue >= upper)) || (decreasing && (m_currentValue <= lower)) ) { stopStepping(); return; } if ( m_mode == StepForwards ) m_currentValue += dx; else m_currentValue -= dx; updateUI(); updateFunctionParameter(); } void ParameterAnimator::updateFunctionParameter() { m_function->k = m_currentValue; View::self()->drawPlot(); } void ParameterAnimator::gotoInitial() { m_currentValue = m_widget->initial->value(); updateUI(); updateFunctionParameter(); } void ParameterAnimator::gotoFinal() { m_currentValue = m_widget->final->value(); updateUI(); updateFunctionParameter(); } void ParameterAnimator::stepBackwards( bool step ) { if ( !step ) { pause(); return; } m_mode = StepBackwards; startStepping(); updateUI(); } void ParameterAnimator::stepForwards( bool step ) { if ( !step ) { pause(); return; } m_mode = StepForwards; startStepping(); updateUI(); } void ParameterAnimator::pause() { m_mode = Paused; m_timer->stop(); updateUI(); } void ParameterAnimator::updateUI() { switch ( m_mode ) { case StepBackwards: m_widget->stepBackwards->setChecked( true ); m_widget->stepForwards->setChecked( false ); break; case StepForwards: m_widget->stepBackwards->setChecked( false ); m_widget->stepForwards->setChecked( true ); break; case Paused: m_widget->stepBackwards->setChecked( false ); m_widget->stepForwards->setChecked( false ); break; } m_widget->currentValue->setText( View::self()->posToString( m_currentValue, m_widget->step->value() * 1e-2, View::DecimalFormat ) ); } void ParameterAnimator::updateSpeed() { if ( m_mode != Paused ) startStepping(); } void ParameterAnimator::startStepping() const { double prop = (log( m_widget->speed->value() ) - log( m_widget->speed->minimum() )) / (log( m_widget->speed->maximum()) - log( m_widget->speed->minimum())); // prop = 0 ~ slowest // prop = 1 ~ fastest int min_ms = 40; int max_ms = 1000; int ms = int( prop*min_ms + (1-prop)*max_ms ); m_timer->start( ms ); } void ParameterAnimator::stopStepping() { m_timer->stop(); m_mode = Paused; updateUI(); } //END class ParameterAnimator