Logo Search packages:      
Sourcecode: kbruch version File versions  Download package

FractionRingWidget.cpp

/***************************************************************************
                              fractionringwidget.cpp
                             -------------------
    begin                : 2008/09/16
    copyright            : (C) 2008 by Danilo Balzaque
    email                : danilo.balzaque@ltia.fc.unesp.br

    copyright            : (C) 2008 by Tadeu Araujo, tadeu.araujo@ltia.fc.unesp.br
    copyright            : (C) 2008 by Tiago Porangaba, tiago.porangaba@ltia.fc.unesp.br
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#include "FractionRingWidget.h"
#include "FractionRingWidget.moc"

/* these includes are needed for KDE support */
#include <KAction>
#include <kactioncollection.h>
#include <kconfigdialog.h>
#include <klocale.h>
#include <KNumInput>
#include <kstandardaction.h>
#include <KStandardShortcut>
#include <KTextEdit>

/* these includes are needed for Qt support */
#include <qapplication.h>

//Added by qt3to4:
#include <QGridLayout>
#include <QLabel>
#include <QPainter>
#include <QRectF>
#include <QString>
#include <QPushButton>

#include "ratio.h"
#include "FractionPainter.h"
#include "ui_taskfontsbase.h"
#include "settingsclass.h"
#include "TaskColors.h"

#define MARG_LEFT 10
#define MARG_TOP 70

/* constructor */
00054 FractionRingWidget::FractionRingWidget()
{
#ifdef DEBUG
    kDebug() << "constructor FractionRingWidget()";
#endif
    // creating KActions, used by the kbruchui.rc file
    setupActions();
    createGUI ("FractionRingWidgetui.rc");

    setCaption (i18n ("Learning"));

    layout1 = new QGridLayout();
    layout1->setObjectName ("layout1");

    baseWidget = new QWidget();
    baseWidget->setObjectName ("baseWidget");

    setCentralWidget (baseWidget);

    interfaceWidget = new QWidget (this);
    interfaceWidget->setObjectName ("interfaceWidget");
    interfaceWidget->setFixedSize (QSize (270, 300));

    gridLayout = new QGridLayout();
    gridLayout->setObjectName ("gridLayout");

    // setup colors ---------------------------------------
    bgOutsideRing = QColor (242, 242, 242);
    bgOutsideMold = QColor (51, 51, 153);
    bgInsideRing = QColor (242, 242, 242);
    bgInsideMold = QColor (184, 18, 0);
    bgColor = QColor (240, 240, 250);

    colorListLeft[0] = QColor (0, 122, 209);
    colorListLeft[1] = QColor (70, 156, 207);
    colorListLeft[2] = QColor (121, 205, 241);
    colorListLeft[3] = QColor (174, 231, 255);
    colorListLeft[4] = QColor (117, 241, 255);

    colorListRight[0] = QColor (186, 18, 24);
    colorListRight[1] = QColor (217, 74, 81);
    colorListRight[2] = QColor (255, 114, 122);
    colorListRight[3] = QColor (230, 147, 152);
    colorListRight[4] = QColor (255, 186, 190);

    // 742, 520
    setFixedSize (QSize (742, 520));

    setPalette (QPalette (bgColor));
    setAutoFillBackground (true);

    move (50, 50);

    fractionWidget = new FractionPainter (this);
    fractionWidget->setObjectName ("fractionWidget");

    gridLayout->addWidget (fractionWidget, 0, 0, 1, 2, Qt::AlignBottom | Qt::AlignHCenter);

    // Info Labels -------------------------------------
    leftInfoLabel = new QLabel (this);
    leftInfoLabel->setObjectName ("leftInfoLabel");
    leftInfoLabel->setText (i18nc ("Expands the ratio shown on the left by the given factor. Please note, expanding is not the same as multiplying. For example, expanding a ratio by 2 basically means multiplying the ratio with 2/2 and not with 2/1!", "Expand"));
    gridLayout->addWidget (leftInfoLabel, 1, 0, Qt::AlignCenter);

    rightInfoLabel = new QLabel (this);
    rightInfoLabel->setObjectName ("rightInfoLabel");
    rightInfoLabel->setText (i18nc ("Expands the ratio shown on the left by the given factor. Please note, expanding is not the same as multiplying. For example, expanding a ratio by 2 basically means multiplying the ratio with 2/2 and not with 2/1!", "Expand"));
    gridLayout->addWidget (rightInfoLabel, 1, 1, Qt::AlignCenter);

    // SpinBox -----------------------------------------
    leftSpinBox = new KIntSpinBox (this);
    leftSpinBox->setObjectName ("leftSpinBox");
    leftSpinBox->setRange (1, 6);
    leftSpinBox->setMaximumWidth (50);
    leftSpinBox->setMinimumWidth (50);
    gridLayout->addWidget (leftSpinBox, 2, 0, Qt::AlignTop | Qt::AlignHCenter);

    rightSpinBox = new KIntSpinBox (this);
    rightSpinBox->setObjectName ("rightSpinBox");
    rightSpinBox->setRange (1, 6);
    rightSpinBox->setMaximumWidth (50);
    rightSpinBox->setMinimumWidth (50);
    gridLayout->addWidget (rightSpinBox, 2, 1, Qt::AlignTop | Qt::AlignHCenter);

    QObject::connect (leftSpinBox, SIGNAL (valueChanged (int)), this,
                      SLOT (slotLeftSpinBoxValueChanged (int)));
    QObject::connect (rightSpinBox, SIGNAL (valueChanged (int)), this,
                      SLOT (slotRightSpinBoxValueChanged (int)));

    // Reset Button ------------------------------------
    resetButton = new QPushButton (this);
    resetButton->setObjectName ("resetButton");
    resetButton->setText (i18n ("New"));
    resetButton->setMaximumWidth (70);
    gridLayout->addWidget (resetButton, 3, 0, 1, 2, Qt::AlignCenter);

    QObject::connect (resetButton, SIGNAL (clicked()), this,
                      SLOT (NewTask()));

    // grid row settings --------------------------------
    gridLayout->setRowMinimumHeight (0, 185);
    gridLayout->setRowMinimumHeight (1, 10);
    gridLayout->setRowMinimumHeight (2, 15);
    gridLayout->setRowMinimumHeight (3, 85);

    interfaceWidget->setLayout (gridLayout);
    layout1->addWidget (interfaceWidget, 1, 0, Qt::AlignTop | Qt::AlignHCenter);

    // textedit -----------------------------------------
    textMsg = new KTextEdit (this);
    textMsg->setObjectName ("textMsg");
    textMsg->setFixedSize (QSize (250 - MARG_LEFT, 300));
    textMsg->setReadOnly (true);
    textMsg->setPalette (QPalette (QColor (255, 255, 255)));
    textMsg->setAutoFillBackground (true);
    layout1->addWidget (textMsg, 0, 1, 2, 1, Qt::AlignCenter);

    // grid row settings --------------------------------
    layout1->setRowMinimumHeight (0, MARG_TOP - 20);
    layout1->setRowMinimumHeight (1, 370 - MARG_TOP);

    // grid column settings -----------------------------
    layout1->setColumnMinimumWidth (0, 460 + MARG_LEFT);
    layout1->setColumnMinimumWidth (1, 282 - MARG_LEFT);

    baseWidget->setLayout (layout1);

    // Ratio ----------------------------------------------
    resetFraction (true);
}

/* destructor */
00186 FractionRingWidget::~FractionRingWidget()
{
#ifdef DEBUG
    kDebug() << "destructor StatisticsBarWidget()";
#endif
}

void FractionRingWidget::setupActions()
{
#ifdef DEBUG
    kDebug() << "setupActions FractionRingWidget";
#endif
    // new task action
    m_NewTaskAction  = new KAction (KIcon ("document-new"), i18nc ("@action opens a new question", "&New"), this);
    actionCollection()->addAction ("NewTask", m_NewTaskAction);
    connect (m_NewTaskAction, SIGNAL (triggered (bool)), SLOT (NewTask()));
    m_NewTaskAction->setShortcut (KStandardShortcut::shortcut (KStandardShortcut::New));

    // back action
    m_BackAction  = new KAction (KIcon ("go-previous"), i18nc ("@action go to the main screen", "Back"), this);
    actionCollection()->addAction ("Back", m_BackAction);
    connect (m_BackAction, SIGNAL (triggered (bool)), SLOT (GoBack()));

    // hint action (hide it as it doesn't exist here)
    m_HintAction  = new KAction (KIcon ("games-hint"), i18nc ("@action opens hint", "Hint"), this);
    actionCollection()->addAction ("Hint", m_HintAction);
    connect (m_HintAction, SIGNAL (triggered (bool)), SLOT (Hint()));

    // quit action
    KStandardAction::quit (kapp, SLOT (quit()), actionCollection());

    KStandardAction::preferences (this,  SLOT (slotPrefs()), actionCollection());

    if (!initialGeometrySet())
        resize (QSize (725, 330).expandedTo (minimumSizeHint()));
    setupGUI (ToolBar | Keys | StatusBar | Create);
    setAutoSaveSettings();
}

00225 void FractionRingWidget::slotPrefs()
{
#ifdef DEBUG
    kDebug() << "slotPrefs FractionRingWidget";
#endif
    // do not show dialog twice
    if (KConfigDialog::showDialog ("settings"))
        return;

    //KConfigDialog didn't find an instance of this dialog, so lets create it :
    KConfigDialog* configDialog = new KConfigDialog (this, "settings", SettingsClass::self());

    TaskColors * taskColors = new TaskColors (0);
    configDialog->addPage (taskColors, i18n ("Colors"), "preferences-desktop-color");

    // User edited the configuration - update your local copies of the
    // configuration data
    connect (configDialog, SIGNAL (settingsChanged (const QString &)), this, SLOT (slotApplySettings()));
    configDialog->setHelp ("kbruch/index.html");
    configDialog->show();

    return;
}

00249 void FractionRingWidget::slotApplySettings()
{
#ifdef DEBUG
    kDebug() << "slotApplySettings FractionRingWidget";
#endif
    fractionWidget->update();
    return;
}

00258 void FractionRingWidget::paintEvent (QPaintEvent *)
{
    QPainter painter (this);
    painter.setRenderHint (QPainter::Antialiasing);

    QPen penBorder = QPen (Qt::white);
    penBorder.setWidth (2);

    painter.setPen (penBorder);
    painter.setBrush (bgOutsideRing);

    QRectF rect (MARG_LEFT, MARG_TOP, 440, 440);

    int startAngle = 90 * 16;
    int spanAngle = 0;

    // Outside Ring -------------------------------
    painter.drawEllipse (rect);

    painter.setPen (Qt::NoPen);

    int div = 255 / (rLeft.denominator() + 1);
    for (int i = 0; i < rLeft.numerator(); i++) {
        painter.setBrush (colorListLeft[i]);
        spanAngle = ( (16 * 360) << 8) / rLeft.denominator();
        painter.drawPie (rect, startAngle + ( (i * spanAngle) >> 8), (spanAngle >> 8));
    }

    painter.setPen (penBorder);
    painter.setBrush (Qt::transparent);
    for (int i = 0; i < rLeft.denominator() * multLeft; i++) {
        spanAngle = ( (16 * 360) << 8) / (rLeft.denominator() * multLeft);
        painter.drawPie (rect, startAngle + ( (i * spanAngle) >> 8), (spanAngle >> 8));
    }

    // Spacer Ring -------------------------------
    painter.setPen (penBorder);
    painter.setBrush (bgColor);
    rect.setRect (MARG_LEFT + 27, MARG_TOP + 27, 386, 386);
    painter.drawEllipse (rect);

    // Inside Ring -------------------------------
    painter.setPen (penBorder);
    painter.setBrush (bgInsideRing);
    rect.setRect (MARG_LEFT + 33, MARG_TOP + 33, 374, 374);
    painter.drawEllipse (rect);

    painter.setPen (penBorder);

    div = 255 / (rRight.denominator() + 1);
    for (int i = 0; i < rRight.numerator(); i++) {
        painter.setBrush (colorListRight[i]);
        spanAngle = ( (16 * 360) << 8) / rRight.denominator();
        painter.drawPie (rect, startAngle + ( (i * spanAngle) >> 8), (spanAngle >> 8));
    }

    painter.setPen (penBorder);
    painter.setBrush (Qt::transparent);
    for (int i = 0; i < rRight.denominator() * multRight; i++) {
        spanAngle = ( (16 * 360) << 8) / ( (rRight.denominator() * multRight));
        painter.drawPie (rect, startAngle + ( (i * spanAngle) >> 8), (spanAngle >> 8));
    }

    // Inside Area -------------------------------
    painter.setPen (penBorder);
    painter.setBrush (QColor (230, 230, 240));
    rect.setRect (MARG_LEFT + 60, MARG_TOP + 60, 320, 320);
    painter.drawEllipse (rect);

    // left mold ---------------------------------
    QPen pen = QPen (bgOutsideMold);
    pen.setWidth (2);
    painter.setPen (pen);
    painter.setBrush (QColor (205, 225, 240, 150));
    rect.setRect (MARG_LEFT + 118, MARG_TOP + 120, 80, 160);
    painter.drawRect (rect);

    // right mold --------------------------------
    pen.setColor (bgInsideMold);
    painter.setPen (pen);
    painter.setBrush (QColor (240, 210, 160));
    rect.setRect (MARG_LEFT + 252, MARG_TOP + 120, 80, 160);
    painter.drawRect (rect);
}

void FractionRingWidget::GoBack()
{
    kbruchApp = new AppMenuWidget();
    kbruchApp->show();
    close();
}

void FractionRingWidget::Hint()
{
    textMsg->setVisible (!textMsg->isVisible());
}

void FractionRingWidget::slotLeftSpinBoxValueChanged (int value)
{
    multLeft = value;

    QString msg;
    if (checkTask()) {
        msg = i18n ("Now the parts of the inside ring and outside ring have "
                    "the same size, and we can add the fractions!\n\n"
                    "This is called finding the main denominator. "
                    "The main denominator divides the rings into equal parts.");
        if (rLeft.denominator() * value != MCM (rLeft.denominator(), rRight.denominator())) {
            msg += QString ("\n\n");
            msg += i18n ("There is a smaller main denominator. Can you find it?");
        }

        textMsg->setText (msg);
    } else {
        msg = i18n ("You have just expanded the first fraction by %1. "
                    "Our main goal is to make all parts be the same size. "
                    "Try expanding the first fraction by %2 and the second fraction by %3.",
                    value, rRight.denominator(), rLeft.denominator());
        textMsg->setText (msg);
    }

    update();
    fractionWidget->paintFraction ("+", rLeft, multLeft, rRight, multRight);
}

void FractionRingWidget::slotRightSpinBoxValueChanged (int value)
{
    multRight = value;

    QString msg;
    if (checkTask()) {
        msg = i18n ("Now the parts of the inside ring and outside ring have "
                    "the same size, and we can add the fractions!\n\n"
                    "This is called finding the main denominator. "
                    "The main denominator divides the rings into equal parts.");
        if (rRight.denominator() * value != MCM (rLeft.denominator(), rRight.denominator())) {
            msg += QString ("\n\n");
            msg += i18n ("There is a smaller main denominator. Can you find it?");
        }

        textMsg->setText (msg);
    } else {
        msg = i18n ("You have just expanded the second fraction by %1. "
                    "Our main goal is to make all parts be the same size. "
                    "Try expanding the first fraction by %2 and the second fraction by %3.",
                    value, rRight.denominator(), rLeft.denominator());
        textMsg->setText (msg);
    }

    update();
    fractionWidget->paintFraction ("+", rLeft, multLeft, rRight, multRight);
}

void FractionRingWidget::NewTask()
{
    resetFraction (true);
}

void FractionRingWidget::resetFraction (bool flag = true)
{
    int denominator = int ( (double (rand()) / RAND_MAX) * 5) + 2;
    int numerator = int ( (double (rand()) / RAND_MAX) * (denominator - 1)) + 1;

    rLeft = ratio (numerator, denominator, false);

    int denominator2 = int ( (double (rand()) / RAND_MAX) * 5) + 2;
    while (denominator2 == denominator) {
        denominator2 = int ( (double (rand()) / RAND_MAX) * 5) + 2;
    }
    int numerator2 = int ( (double (rand()) / RAND_MAX) * (denominator2 - 1)) + 1;
    rRight = ratio (numerator2, denominator2, false);

    multLeft = 1;
    multRight = 1;
    leftSpinBox->setValue (1);
    rightSpinBox->setValue (1);

    // NOTE: Inserting denominator as %1, as first number is used to determine plural form,
    // and in these messages that should be the number next to "...painted parts".
    QString insert1 = i18ncp ("Inserted as %1 in the message below.",
                              "%2 of 1 painted part.", "%2 of %1 painted parts.",
                              rLeft.denominator(), rLeft.numerator());
    QString insert2 = i18ncp ("Inserted as %2 in the message below.",
                              "%2 of 1 painted part.", "%2 of %1 painted parts.",
                              rRight.denominator(), rRight.numerator());
    QString msg = i18nc ("%1 and %2 are the two messages translated above.",
                         "The outside ring represents the left fraction. %1\n\n"
                         "The inside ring represents the right fraction. %2\n\n"
                         "The 'Expand' spinboxes expand each fraction. Try to change one of the spinbox values!",
                         insert1, insert2);

    textMsg->setText (msg);

    if (flag) {
        update();
        fractionWidget->paintFraction ("+", rLeft, multLeft, rRight, multRight);
    }
}

int FractionRingWidget::MCM (int a, int b)
{
    return a * b / GCF (a, b);
}

int FractionRingWidget::GCF (int a, int b)
{
    int tmp;
    if (a < b) {
        tmp = b;
        b = a;
        a = tmp;
    }
    tmp = a % b;
    while (tmp != 0) {
        a = b;
        b = tmp;
        tmp = a % b;
    }
    return b;
}

bool FractionRingWidget::checkTask()
{
    return (rLeft.denominator() * multLeft == rRight.denominator() * multRight);
}

Generated by  Doxygen 1.6.0   Back to index