/*
    Copyright (C) 2006 Oswald Buddenhagen <ossi@kde.org>

    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 Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "positioner.h"

#include <klocale.h>
#include <kstandarddirs.h>

#include <QFrame>
#include <QLabel>
#include <QMouseEvent>
#include <QDesktopWidget>
#include <QApplication>

#define TOTAL_WIDTH 200
#define TOTAL_HEIGHT 186
#define ACTIVE_X 23
#define ACTIVE_Y 14
#define ACTIVE_WIDTH 151
#define ACTIVE_HEIGHT 115
#define MARGIN 10

#define SNAP 10
#define STEP 5

static void
fit(int &p)
{
    if (p < SNAP)
        p = 0;
    else if (p > 100 - SNAP)
        p = 100;
    else if (p > 50 - SNAP / 2 && p < 50 + SNAP / 2)
        p = 50;
}

static void
step(int &p, int d)
{
    if (p < SNAP)
        p = 0 + (d + 1) * SNAP / 2;
    else if (p > 100 - SNAP)
        p = 100 + (d - 1) * SNAP / 2;
    else if (p > 50 - SNAP / 2 && p < 50 + SNAP / 2)
        p = 50 + d * SNAP / 2;
    else {
        p += d * STEP;
        fit(p);
    }
}

Positioner::Positioner(QWidget *parent)
    : ScreenPreviewWidget(parent)
    , m_x(50)
    , m_y(50)
{
    QDesktopWidget *desktop = QApplication::desktop();
    setRatio((qreal)desktop->width() / (qreal)desktop->height());
    m_anchor = QPixmap(KStandardDirs::locate("data", "kcontrol/pics/anchor.png"));
    setFocusPolicy(Qt::StrongFocus);
    const int fw = MARGIN * 2;
    setMinimumSize(TOTAL_WIDTH + fw, TOTAL_HEIGHT + fw);
    setMaximumWidth(400);
    QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Expanding);
    sp.setHeightForWidth(true);
    setSizePolicy(sp);
    m_frame = new QFrame(this);
    m_screen = new QWidget(m_frame);
    m_screen->setAutoFillBackground(true);
    QPalette pal;
    pal.setColor(QPalette::Background, QColor(255, 255, 255, 128));
    m_screen->setPalette(pal);
    m_dlg = new QFrame(m_screen);
    m_dlg->setFrameStyle(QFrame::Panel | QFrame::Raised);
    m_dlg->setAutoFillBackground(true);
    QPalette pal2;
    pal2.setBrush(QPalette::Background, pal2.brush(QPalette::Normal, QPalette::Background));
    m_dlg->setPalette(pal2);
    m_ptr = new QLabel(m_screen);
    m_ptr->setPixmap(m_anchor);
    QString wts(i18n(
        "Drag the anchor to move the center of the dialog to the desired position. "
        "Keyboard control is possible as well: Use the arrow keys or Home to center. "
        "Note that the actual proportions of the dialog are probably different."));
    m_frame->setWhatsThis(wts);
    m_screen->setWhatsThis(wts);
    m_ptr->setWhatsThis(wts);
}

void
Positioner::setPosition(int x, int y)
{
    m_x = x;
    m_y = y;
    updateHandle();
}

int
Positioner::heightForWidth(int w) const
{
    const int fw = MARGIN * 2;
    return ((w - fw) * TOTAL_HEIGHT + (TOTAL_WIDTH / 2)) / TOTAL_WIDTH + fw;
}

void
Positioner::updateHandle()
{
    int px = m_screen->size().width() * m_x / 100;
    int py = m_screen->size().height() * m_y / 100;
    m_ptr->setGeometry(px - m_anchor.width() / 2, py - m_anchor.height() / 2,
                       m_anchor.width(), m_anchor.height());
    int sw = m_screen->width() * 2 / 5;
    int sh = m_screen->height() * 2 / 5;
    QRect grt(px - sw / 2, py - sh / 2, sw, sh);
    int di;
    if ((di = m_screen->size().width() - grt.right()) < 0)
        grt.translate(di, 0);
    if ((di = - grt.left()) > 0)
        grt.translate(di, 0);
    if ((di = m_screen->size().height() - grt.bottom()) < 0)
        grt.translate(0, di);
    if ((di = - grt.top()) > 0)
        grt.translate(0, di);
    m_dlg->setGeometry(grt);
}

void
Positioner::resizeEvent(QResizeEvent *event)
{
    ScreenPreviewWidget::resizeEvent(event);
    const int fw = MARGIN * 2;
    QSize rs(TOTAL_WIDTH, TOTAL_HEIGHT);
    rs.scale(size() - QSize(fw, fw), Qt::KeepAspectRatio);

    m_frame->setGeometry(0, 0, rs.width() + fw, rs.height() + fw);
    m_frame->resize(size());
    m_screen->setGeometry(previewRect());

    updateHandle();
}

void
Positioner::focusInEvent(QFocusEvent *)
{
    m_frame->setFrameStyle(QFrame::Panel | QFrame::Sunken);
}

void
Positioner::focusOutEvent(QFocusEvent *)
{
    m_frame->setFrameStyle(QFrame::NoFrame);
}

void
Positioner::mousePressEvent(QMouseEvent *event)
{
    QPoint cp = event->pos() - m_screen->pos();
    if (m_ptr->geometry().contains(cp))
        m_delta = m_ptr->geometry().center() - cp;
    else
        m_delta.setX(-1);
}

void
Positioner::mouseMoveEvent(QMouseEvent *event)
{
    if (m_delta.x() != -1) {
        QPoint cp = event->pos() - m_screen->pos() + m_delta;
        m_x = cp.x() * 100 / m_screen->size().width();
        m_y = cp.y() * 100 / m_screen->size().height();
        fit(m_x);
        fit(m_y);
        updateHandle();
        emit positionChanged();
    }
}

void
Positioner::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Home:
        m_x = m_y = 50;
        break;
    case Qt::Key_Left:
        step(m_x, -1);
        break;
    case Qt::Key_Right:
        step(m_x, 1);
        break;
    case Qt::Key_Up:
        step(m_y, -1);
        break;
    case Qt::Key_Down:
        step(m_y, 1);
        break;
    default:
        event->ignore();
        return;
    }
    updateHandle();
    emit positionChanged();
    event->accept();
}

#include "positioner.moc"
