/* Copyright (C) 2007 Niels Slot 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 "directiondialog.h" #include using std::atan; #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288419717 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ROUND2INT(x) ( (x) >= 0 ? (int)( (x) + .5 ) : (int)( (x) - .5 ) ) //BEGIN DirectionCanvas widget DirectionCanvas::DirectionCanvas(QWidget* parent) : QWidget(parent) { setFocusPolicy(Qt::ClickFocus); setMinimumSize(230, 200); setBackgroundRole(QPalette::Base); setAutoFillBackground(true); turtle.load(QString(":turtle.svg")); greyTurtle.load(QString(":turtle_grey.svg")); deg = 0; previousDeg = 0; greyTurtleEnabled = true; } void DirectionCanvas::enableGreyTurtle(bool enable) { greyTurtleEnabled = enable; update(); } void DirectionCanvas::paintEvent(QPaintEvent *event) { Q_UNUSED(event); int side = qMin(width(), height()); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.save(); // Place us in the middle of the widget painter.translate(width() / 2, height() / 2); // Scale the widget to a square of 200 by 200 painter.scale(side / 200.0, side / 200.0); // Draw the ellipse. With a nice border of 10 painter.drawEllipse(-80, -80, 160, 160); // Draw the lines in the circle painter.save(); for (int i = 0; i < 4; i++) { painter.drawLine(0, -80, 0, 80); painter.rotate(45); } painter.restore(); painter.drawText(-100, -98, 200, 200, Qt::AlignHCenter|Qt::AlignTop, "0"); painter.drawText(-100, -100, 200, 200, Qt::AlignHCenter|Qt::AlignBottom, "180"); painter.drawText(-100, -100, 203, 200, Qt::AlignRight|Qt::AlignVCenter, "90"); painter.drawText(-109, -100, 200, 200, Qt::AlignLeft|Qt::AlignVCenter, "270"); painter.save(); // the greay turtle if (greyTurtleEnabled) { painter.rotate(previousDeg); painter.setPen(Qt::blue); painter.drawLine(0, -80, 0, 0); QRectF greyTurtleRect(-25, -25, 50, 50); greyTurtle.render(&painter, greyTurtleRect); painter.restore(); painter.save(); } // the more healthy looking one painter.rotate(deg); painter.setPen(Qt::red); painter.drawLine(0, -80, 0, 0); QRectF turtleRect(-25, -25, 50, 50); turtle.render(&painter, turtleRect); painter.restore(); painter.restore(); // Draw the widget's border painter.setPen(palette().dark().color()); painter.setBrush(Qt::NoBrush); painter.drawRect(QRect(0, 0, width() - 1, height() - 1)); } void DirectionCanvas::mouseMoveEvent(QMouseEvent *event) { mousePressEvent(event); } void DirectionCanvas::mousePressEvent(QMouseEvent *event) { // Only act upon left and right mouse button clicks, // then translate the X and Y coordinates so that // (0, 0) is in the middle of the widget, sent the // signals and update the widget. if (event->buttons() & Qt::LeftButton) { deg = translateMouseCoords(event->x() - (width() / 2), event->y() - (height() / 2)); update(); emit degreeChanged(deg); } else if (event->buttons() & Qt::RightButton) { previousDeg = translateMouseCoords(event->x() - (width() / 2), event->y() - (height() / 2)); emit previousDegreeChanged(previousDeg); update(); } } void DirectionCanvas::updateDirections(double previousDeg, double deg) { this->deg = deg; this->previousDeg = previousDeg; update(); } double DirectionCanvas::translateMouseCoords(double trans_x, double trans_y) { // We now have 4 squares. One four every corner. // With a cross in the middle. // For every square we calculate a different tangent // therefore we have to add of substract a number of degrees double result = 0; if (trans_x >= 0 && trans_y >= 0) { // Right down double arc_tan = trans_y / trans_x; result = 90 + (atan(arc_tan)) * (180/M_PI); } else if (trans_x <= 0 && trans_y >= 0) { // Left down trans_x = trans_x * -1; double arc_tan = trans_y / trans_x; result = 270 - (atan(arc_tan)) * (180/M_PI); } else if (trans_x >= 0 && trans_y <= 0) { // Right up trans_y = trans_y * -1; double arc_tan = trans_y / trans_x; result = 90 - (atan(arc_tan)) * (180/M_PI); } else if (trans_x <= 0 && trans_y <= 0) { // Left up trans_x = trans_x * -1; trans_y = trans_y * -1; double arc_tan = trans_y / trans_x; result = 270 + (atan(arc_tan)) * (180/M_PI); } return result; } //END DirectionCanvas widget DirectionDialog::DirectionDialog(double deg, QWidget* parent) : KDialog(parent) { skipValueChangedEvent = false; while (deg < 0 || deg > 359) { if (deg < 0) deg = deg + 360; else if (deg > 359) deg = deg - 360; } translator = Translator::instance(); setCaption(i18n("Direction Chooser")); setModal(false); setButtons(User1); setDefaultButton(User1); setButtonGuiItem(User1, KGuiItem(i18n("&Quit"), "dialog-close")); connect(this, SIGNAL(user1Clicked()), this, SLOT(delayedDestruct())); showButtonSeparator(false); QWidget* baseWidget = new QWidget(this); setMainWidget(baseWidget); QVBoxLayout* baseLayout = new QVBoxLayout; baseWidget->setLayout( baseLayout ); QHBoxLayout* degreeChooserLayout = new QHBoxLayout; baseLayout->addLayout(degreeChooserLayout); canvas = new DirectionCanvas(baseWidget); connect(canvas, SIGNAL(degreeChanged(double)), this, SLOT(updateDegrees(double))); connect(canvas, SIGNAL(previousDegreeChanged(double)), this, SLOT(updatePreviousDegrees(double))); degreeChooserLayout->addWidget(canvas); QWidget* rightWidget = new QWidget(baseWidget); degreeChooserLayout->addWidget(rightWidget); QVBoxLayout* rightLayout = new QVBoxLayout(rightWidget); // command picker QLabel* commandPickerLabel = new QLabel(rightWidget); commandPickerLabel->setText(i18n("Command &type:")); commandPickerLabel->setScaledContents(true); rightLayout->addWidget(commandPickerLabel); commandPicker = new KComboBox(rightWidget); commandPicker->insertItem(Turnleft, translator->default2localized("turnleft")); commandPicker->insertItem(Turnright, translator->default2localized("turnright")); commandPicker->insertItem(Direction, translator->default2localized("direction")); rightLayout->addWidget(commandPicker); commandPickerLabel->setBuddy(commandPicker); connect(commandPicker, SIGNAL(currentIndexChanged(int)), this, SLOT(changeCommand(int))); rightLayout->addStretch(); // direction QLabel* previousDirectionLabel = new QLabel(rightWidget); previousDirectionLabel->setText(i18n("&Previous direction:")); previousDirectionLabel->setScaledContents(true); rightLayout->addWidget(previousDirectionLabel); previousDirectionSpin = new KIntSpinBox(rightWidget); // Use -360 to 720 instead of 0 to 360 // If 0 to 360 is used, then wrap-around goes from 360 to 0 (which isn't really a step at all) // Instead use larger range and then convert it into the 0 to 359 range whenever it is changed. previousDirectionSpin->setRange(-360, 720); previousDirectionSpin->setWrapping(true); previousDirectionSpin->setSingleStep(10); previousDirectionSpin->setValue((int)deg); rightLayout->addWidget(previousDirectionSpin); previousDirectionLabel->setBuddy(previousDirectionSpin); connect(previousDirectionSpin, SIGNAL(valueChanged(int)), this, SLOT(directionChanged(int))); // previous direction QLabel* directionLabel = new QLabel(rightWidget); directionLabel->setText(i18n("&New direction:")); rightLayout->addWidget(directionLabel); directionSpin = new KIntSpinBox(rightWidget); // Use -360 to 720 instead of 0 to 360 // If 0 to 360 is used, then wrap-around goes from 360 to 0 (which isn't really a step at all) // Instead use larger range and then convert it into the 0 to 359 range whenever it is changed. directionSpin->setRange(-360, 720); directionSpin->setWrapping(true); directionSpin->setSingleStep(10); directionSpin->setValue((int)deg); rightLayout->addWidget(directionSpin); directionLabel->setBuddy(directionSpin); connect(directionSpin, SIGNAL(valueChanged(int)), this, SLOT(directionChanged(int))); baseLayout->addSpacing(20); // commandBox and copy/paste buttons QHBoxLayout *pasteRowLayout = new QHBoxLayout; baseLayout->addLayout(pasteRowLayout); pasteRowLayout->addStretch(); commandBox = new KLineEdit(rightWidget); commandBox->setReadOnly(true); commandBox->setFont(KGlobalSettings::fixedFont()); commandBox->setMinimumWidth(commandBox->fontMetrics().width("000000000_360")); pasteRowLayout->addWidget(commandBox); KPushButton* copyButton = new KPushButton(KIcon("edit-copy"), i18n("&Copy to clipboard"), baseWidget); pasteRowLayout->addWidget(copyButton); connect(copyButton, SIGNAL(clicked()), this, SLOT(copyProxy())); KPushButton* pasteButton = new KPushButton(KIcon("edit-paste"), i18n("&Paste to editor"), baseWidget); pasteRowLayout->addWidget(pasteButton); connect(pasteButton, SIGNAL(clicked()), this, SLOT(pasteProxy())); pasteRowLayout->addStretch(); baseLayout->addSpacing(10); changeCommand(0); show(); } void DirectionDialog::directionChanged(int value) { Q_UNUSED(value); // if value is outside of the 0 to 359 range, then move it into that range if (previousDirectionSpin->value() < 0) { previousDirectionSpin->setValue(previousDirectionSpin->value() + 360); } else if (previousDirectionSpin->value() >= 360) { previousDirectionSpin->setValue(previousDirectionSpin->value() - 360); } // if value is outside of the 0 to 359 range, then move it into that range if (directionSpin->value() < 0) { directionSpin->setValue(directionSpin->value() + 360); } else if (directionSpin->value() >= 360) { directionSpin->setValue(directionSpin->value() - 360); } // Don't update the canvas when we just updated the direction spinbox. // (only update when the users changes the spinbox) if (skipValueChangedEvent) { skipValueChangedEvent = false; return; } updateCanvas(); updateCommandBox(); } void DirectionDialog::updateCanvas() { // Get the things we need, then update the canvas. int previousDir = previousDirectionSpin->value(); int dir = directionSpin->value(); canvas->updateDirections(previousDir, dir); } void DirectionDialog::changeCommand(int command) { currentCommand = command; if (currentCommand == Direction) { previousDirectionSpin->setEnabled(false); canvas->enableGreyTurtle(false); } else { previousDirectionSpin->setEnabled(true); canvas->enableGreyTurtle(true); } updateCanvas(); updateCommandBox(); } void DirectionDialog::updateDegrees(double deg) { // The canvas has changed, update the spinbox and command-LineEdit skipValueChangedEvent = true; directionSpin->setValue(ROUND2INT(deg)); updateCommandBox(); } void DirectionDialog::updatePreviousDegrees(double deg) { // The canvas has changed, update the spinbox and commandBox skipValueChangedEvent = true; previousDirectionSpin->setValue(ROUND2INT(deg)); updateCommandBox(); } void DirectionDialog::updateCommandBox() { // Generate a new value for the commandBox. QString output; int degree = 0; switch (currentCommand) { case Turnleft: output.append(translator->default2localized("turnleft")); degree = 360 - (directionSpin->value() - previousDirectionSpin->value()); break; case Turnright: output.append(translator->default2localized("turnright")); degree = directionSpin->value() - previousDirectionSpin->value(); break; case Direction: output.append(translator->default2localized("direction")); degree = directionSpin->value(); break; } if (degree < 0) { degree += 360; } else if (degree >= 360) { degree -= 360; } output.append(QString(" %1\n").arg(degree)); commandBox->setText(output); } void DirectionDialog::copyProxy() { KApplication::clipboard()->setText(commandBox->text()); } void DirectionDialog::pasteProxy() { emit pasteText(commandBox->text()); } #include "directiondialog.moc"