Commit 0fee9337 authored by Stefan Majewsky's avatar Stefan Majewsky

Add new mouse configuration UI.

svn path=/trunk/KDE/kdegames/palapeli/; revision=1113451
parent fd089d39
......@@ -3,6 +3,8 @@ set_directory_properties(PROPERTIES COMPILE_DEFINITIONS USE_LOCAL_LIBPALA)
set(palapeli_SRCS
config/mouseinputbutton.cpp
config/triggerconfigwidget.cpp
config/triggerlistview.cpp
creator/propertywidget.cpp
creator/puzzlecreator.cpp
creator/slicerconfwidget.cpp
......
......@@ -73,6 +73,12 @@ Palapeli::MouseInputButton::MouseInputButton(QWidget* parent)
layout->setContentsMargins(marginX, marginY, marginX, marginY);
}
QSize Palapeli::MouseInputButton::sizeHint() const
{
//The layout's size hint is the right one, not the one calculated by QPushButton::sizeHint.
return QWidget::sizeHint();
}
bool Palapeli::MouseInputButton::isNoButtonAllowed() const
{
return m_noButtonAllowed;
......
......@@ -33,6 +33,7 @@ namespace Palapeli
Q_OBJECT
public:
MouseInputButton(QWidget* parent = 0);
virtual QSize sizeHint() const;
bool isNoButtonAllowed() const;
void setNoButtonAllowed(bool noButtonAllowed);
......
/***************************************************************************
* Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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 "triggerconfigwidget.h"
#include "triggerlistview.h"
#include "../engine/interactormanager.h"
#include <KLocalizedString>
Palapeli::TriggerConfigWidget::TriggerConfigWidget(Palapeli::InteractorManager* manager, QWidget* parent)
: QTabWidget(parent)
, m_manager(manager)
{
createTriggerListView(m_mouseView, Palapeli::MouseInteractor);
createTriggerListView(m_wheelView, Palapeli::WheelInteractor);
addTab(m_mouseView, i18n("Mouse buttons"));
addTab(m_wheelView, i18n("Mouse wheel"));
}
void Palapeli::TriggerConfigWidget::createTriggerListView(Palapeli::TriggerListView*& view, Palapeli::InteractorTypes types)
{
//filter interactors
QList<Palapeli::Interactor*> interactors = m_manager->interactors();
QMutableListIterator<Palapeli::Interactor*> it1(interactors);
while (it1.hasNext())
if ((it1.next()->interactorTypes() & types) != types)
it1.remove();
//filter triggers
QList<Palapeli::AssociatedInteractorTrigger> triggers = m_manager->triggers();
QMutableListIterator<Palapeli::AssociatedInteractorTrigger> it2(triggers);
while (it2.hasNext())
if (!interactors.contains(it2.next().second))
it2.remove();
//create view
view = new Palapeli::TriggerListView(interactors, triggers, this);
}
void Palapeli::TriggerConfigWidget::writeConfig()
{
//TODO
}
/***************************************************************************
* Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
***************************************************************************/
#ifndef PALAPELI_TRIGGERCONFIGWIDGET_H
#define PALAPELI_TRIGGERCONFIGWIDGET_H
#include "../engine/interactor.h"
#include <QTabWidget>
namespace Palapeli
{
class InteractorManager;
class TriggerListView;
class TriggerConfigWidget : public QTabWidget
{
public:
//TODO: Provide signal interface for changes (to enable "Apply" button in config dialog.)
TriggerConfigWidget(Palapeli::InteractorManager* manager, QWidget* parent = 0);
void writeConfig();
private:
void createTriggerListView(Palapeli::TriggerListView*& view, Palapeli::InteractorTypes types);
Palapeli::InteractorManager* m_manager;
Palapeli::TriggerListView* m_mouseView;
Palapeli::TriggerListView* m_wheelView;
};
}
#endif // PALAPELI_TRIGGERCONFIGWIDGET_H
/***************************************************************************
* Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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 "triggerlistview.h"
#include "mouseinputbutton.h"
#include "../engine/interactor.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QStandardItemModel>
#include <KCategorizedSortFilterProxyModel>
#include <KCategoryDrawer>
#include <KLocalizedString>
#include <KStringHandler>
#include <KWidgetItemDelegate>
#include <KDebug>
namespace Palapeli
{
class TriggerListProxyModel : public KCategorizedSortFilterProxyModel
{
public:
TriggerListProxyModel(QObject* parent = 0)
: KCategorizedSortFilterProxyModel(parent)
{
setCategorizedModel(true);
}
protected:
virtual int compareCategories(const QModelIndex& left, const QModelIndex& right) const
{
const int categoryLeft = left.data(Palapeli::InteractorRole).value<Palapeli::Interactor*>()->category();
const int categoryRight = right.data(Palapeli::InteractorRole).value<Palapeli::Interactor*>()->category();
return categoryRight - categoryLeft;
}
virtual bool subSortLessThan(const QModelIndex& left, const QModelIndex& right) const
{
const QString textLeft = left.data(Palapeli::InteractorRole).value<Palapeli::Interactor*>()->description();
const QString textRight = right.data(Palapeli::InteractorRole).value<Palapeli::Interactor*>()->description();
return KStringHandler::naturalCompare(textLeft, textRight) < 0;
}
};
class TriggerListDelegateWidget : public QWidget
{
Q_OBJECT
public:
TriggerListDelegateWidget(QWidget* parent = 0) : QWidget(parent)
{
m_iconLabel = new QLabel(this);
m_nameLabel = new QLabel(this);
m_inputButton = new Palapeli::MouseInputButton(this);
connect(m_inputButton, SIGNAL(triggerChanged(const Palapeli::InteractorTrigger&)), SIGNAL(triggerChanged(const Palapeli::InteractorTrigger&)));
//construct layout
QHBoxLayout* layout = new QHBoxLayout;
setLayout(layout);
layout->addWidget(m_iconLabel);
m_iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
layout->addWidget(m_nameLabel);
m_nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
layout->addWidget(m_inputButton);
m_inputButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}
void setIcon(const QIcon& icon)
{
//TODO: respect global icon size configuration
m_iconLabel->setPixmap(icon.pixmap(22));
}
void setText(const QString& text)
{
m_nameLabel->setText(text);
}
void setTrigger(const Palapeli::InteractorTrigger& trigger)
{
m_inputButton->setTrigger(trigger);
}
Q_SIGNALS:
void triggerChanged(const Palapeli::InteractorTrigger& newTrigger);
private:
QLabel* m_iconLabel;
QLabel* m_nameLabel;
Palapeli::MouseInputButton* m_inputButton;
};
class TriggerListDelegate : public KWidgetItemDelegate
{
Q_OBJECT
public:
TriggerListDelegate(QAbstractItemView* view, QObject* parent = 0) : KWidgetItemDelegate(view, parent)
{
m_calculator = new Palapeli::TriggerListDelegateWidget(view);
m_calculator->setVisible(false);
}
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
Q_UNUSED(index)
QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0);
}
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
updateItemWidgets(QList<QWidget*>() << m_calculator, option, index);
return m_calculator->minimumSizeHint();
}
protected:
virtual QList<QWidget*> createItemWidgets() const
{
return QList<QWidget*>() << new Palapeli::TriggerListDelegateWidget(itemView());
}
virtual void updateItemWidgets(QList<QWidget*> widgets, const QStyleOptionViewItem& option, const QPersistentModelIndex& index) const
{
Palapeli::TriggerListDelegateWidget* widget = qobject_cast<Palapeli::TriggerListDelegateWidget*>(widgets[0]);
//adjust widget contents
widget->setIcon(index.data(Qt::DecorationRole).value<QIcon>());
widget->setText(index.data(Qt::DisplayRole).value<QString>());
disconnect(widget, 0, this, 0);
widget->setTrigger(index.data(TriggerRole).value<Palapeli::InteractorTrigger>());
connect(widget, SIGNAL(triggerChanged(const Palapeli::InteractorTrigger&)), SLOT(triggerChanged(const Palapeli::InteractorTrigger&)));
//adjust widget geometry
QRect rect = option.rect;
rect.moveTop(0);
widget->setGeometry(rect);
}
private Q_SLOTS:
void triggerChanged(const Palapeli::InteractorTrigger& newTrigger)
{
const QModelIndex index = focusedIndex();
QAbstractItemModel* model = const_cast<QAbstractItemModel*>(index.model());
model->setData(index, qVariantFromValue(newTrigger), Palapeli::TriggerRole);
}
private:
Palapeli::TriggerListDelegateWidget* m_calculator;
};
}
static QString categoryToString(Palapeli::Interactor::Category category)
{
switch (category)
{
case Palapeli::Interactor::PieceInteraction:
return i18n("Interaction with pieces");
case Palapeli::Interactor::TableInteraction:
return i18n("Interaction with the puzzle table");
case Palapeli::Interactor::ViewportInteraction:
return i18n("Interaction with the viewport");
case Palapeli::Interactor::NoCategory: default:
return QString();
}
}
Palapeli::TriggerListView::TriggerListView(const QList<Palapeli::Interactor*> interactors, const QList<Palapeli::AssociatedInteractorTrigger>& triggers, QWidget* parent)
: KCategorizedView(parent)
, m_categoryDrawer(new KCategoryDrawer)
, m_baseModel(new QStandardItemModel(this))
, m_proxyModel(new Palapeli::TriggerListProxyModel(this))
, m_delegate(new Palapeli::TriggerListDelegate(this))
{
//fill base model with interactors
foreach (Palapeli::Interactor* interactor, interactors)
{
QStandardItem* item = new QStandardItem;
item->setData(interactor->description(), Qt::DisplayRole);
item->setData(interactor->icon(), Qt::DecorationRole);
item->setData(qVariantFromValue(interactor), Palapeli::InteractorRole);
item->setData(qVariantFromValue(Palapeli::InteractorTrigger()), Palapeli::TriggerRole);
item->setData(categoryToString(interactor->category()), KCategorizedSortFilterProxyModel::CategoryDisplayRole);
item->setData(interactor->category(), KCategorizedSortFilterProxyModel::CategorySortRole);
m_baseModel->appendRow(item);
}
//fill base model with triggers
foreach (const Palapeli::AssociatedInteractorTrigger& trigger, triggers)
{
for (int i = 0; i < m_baseModel->rowCount(); ++i)
{
QStandardItem* item = m_baseModel->item(i);
if (item->data(Palapeli::InteractorRole).value<Palapeli::Interactor*>() == trigger.second)
{
item->setData(qVariantFromValue(trigger.first), Palapeli::TriggerRole);
break;
}
}
}
//setup model/view
m_proxyModel->setSourceModel(m_baseModel);
setModel(m_proxyModel);
setItemDelegate(m_delegate);
// setCategoryDrawer(m_categoryDrawer); //FIXME: Why do I crash?
}
Palapeli::TriggerListView::~TriggerListView()
{
delete m_categoryDrawer;
}
QList<Palapeli::AssociatedInteractorTrigger> Palapeli::TriggerListView::triggers() const
{
//read triggers from base model
QList<Palapeli::AssociatedInteractorTrigger> result;
for (int i = 0; i < m_baseModel->rowCount(); ++i)
{
QStandardItem* item = m_baseModel->item(i);
Palapeli::Interactor* interactor = item->data(Palapeli::InteractorRole).value<Palapeli::Interactor*>();
Palapeli::InteractorTrigger trigger = item->data(Palapeli::TriggerRole).value<Palapeli::InteractorTrigger>();
result << qMakePair(trigger, interactor);
}
return result;
}
#include "triggerlistview.moc"
/***************************************************************************
* Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
***************************************************************************/
#ifndef PALAPELI_TRIGGERLISTVIEW_H
#define PALAPELI_TRIGGERLISTVIEW_H
#include "../engine/interactorutils.h"
class QStandardItemModel;
class KCategorizedSortFilterProxyModel;
class KCategoryDrawer;
#include <KCategorizedView>
namespace Palapeli
{
class TriggerListDelegate;
enum TriggerListRoles { TriggerRole = Qt::UserRole + 42, InteractorRole };
class TriggerListView : public KCategorizedView
{
public:
TriggerListView(const QList<Palapeli::Interactor*> interactors, const QList<Palapeli::AssociatedInteractorTrigger>& triggers, QWidget* parent = 0);
virtual ~TriggerListView();
QList<Palapeli::AssociatedInteractorTrigger> triggers() const;
private:
KCategoryDrawer* m_categoryDrawer;
QStandardItemModel* m_baseModel;
KCategorizedSortFilterProxyModel* m_proxyModel;
Palapeli::TriggerListDelegate* m_delegate;
};
}
#endif // PALAPELI_TRIGGERLISTVIEW_H
......@@ -24,7 +24,7 @@
Palapeli::ConstraintInteractor::ConstraintInteractor(QGraphicsView* view)
: Palapeli::Interactor(Palapeli::MouseInteractor, view)
{
setMetadata(i18n("Change size of puzzle table by dragging its edges"), QIcon());
setMetadata(TableInteraction, i18n("Change size of puzzle table by dragging its edges"), QIcon());
}
QList<Palapeli::ConstraintInteractor::Side> Palapeli::ConstraintInteractor::touchingSides(const QPointF& scenePos) const
......
......@@ -22,6 +22,7 @@ Palapeli::Interactor::Interactor(Palapeli::InteractorTypes types, QGraphicsView*
: m_types(types)
, m_view(view)
, m_scene(view->scene())
, m_category(NoCategory)
{
}
......@@ -44,6 +45,11 @@ Palapeli::InteractorTypes Palapeli::Interactor::interactorTypes() const
return m_types;
}
Palapeli::Interactor::Category Palapeli::Interactor::category() const
{
return m_category;
}
QString Palapeli::Interactor::description() const
{
return m_description;
......@@ -54,13 +60,14 @@ QIcon Palapeli::Interactor::icon() const
return m_icon;
}
void Palapeli::Interactor::setMetadata(const QString& description, const QIcon& icon)
void Palapeli::Interactor::setMetadata(Palapeli::Interactor::Category category, const QString& description, const QIcon& icon)
{
m_category = category;
m_description = description;
m_icon = icon;
}
void Palapeli::Interactor::updateScene() //NOTE: Read the scene of the view, and when it has changed, fire a sceneChangeEvent.
void Palapeli::Interactor::updateScene()
{
QGraphicsScene* oldScene = m_scene;
QGraphicsScene* newScene = m_view->scene();
......
......@@ -30,8 +30,8 @@ namespace Palapeli
{
enum InteractorType
{
MouseInteractor,
WheelInteractor
MouseInteractor = 0x1,
WheelInteractor = 0x2
};
Q_DECLARE_FLAGS(InteractorTypes, InteractorType)
......@@ -42,6 +42,8 @@ namespace Palapeli
public:
virtual ~Interactor();
enum Category { NoCategory, PieceInteraction, TableInteraction, ViewportInteraction };
Category category() const;
QString description() const;
QIcon icon() const;
......@@ -55,7 +57,7 @@ namespace Palapeli
void updateScene();
protected:
Interactor(Palapeli::InteractorTypes types, QGraphicsView* view);
void setMetadata(const QString& description, const QIcon& icon);
void setMetadata(Category category, const QString& description, const QIcon& icon);
QGraphicsView* view() const;
QGraphicsScene* scene() const;
......@@ -74,6 +76,7 @@ namespace Palapeli
QGraphicsView* m_view;
QGraphicsScene* m_scene;
//metadata
Category m_category;
QString m_description;
QIcon m_icon;
};
......
......@@ -27,9 +27,6 @@
namespace Palapeli
{
class Interactor;
typedef QPair<Palapeli::InteractorTrigger, Palapeli::Interactor*> AssociatedInteractorTrigger;
class InteractorManager : public QObject
{
public:
......
......@@ -30,7 +30,7 @@
Palapeli::MovePieceInteractor::MovePieceInteractor(QGraphicsView* view)
: Palapeli::Interactor(Palapeli::MouseInteractor, view)
{
setMetadata(i18nc("Description (used like a name) for a mouse interaction method", "Move pieces by dragging"), QIcon());
setMetadata(PieceInteraction, i18nc("Description (used like a name) for a mouse interaction method", "Move pieces by dragging"), QIcon());
}
static QGraphicsItem* findSelectableItemAt(const QPointF& scenePos, QGraphicsScene* scene)
......@@ -128,7 +128,7 @@ void Palapeli::MovePieceInteractor::mouseReleaseEvent(const Palapeli::MouseEvent
Palapeli::SelectPieceInteractor::SelectPieceInteractor(QGraphicsView* view)
: Palapeli::Interactor(Palapeli::MouseInteractor, view)
{
setMetadata(i18nc("Description (used like a name) for a mouse interaction method", "Select pieces by clicking"), QIcon());
setMetadata(PieceInteraction, i18nc("Description (used like a name) for a mouse interaction method", "Select pieces by clicking"), QIcon());
}
bool Palapeli::SelectPieceInteractor::acceptMousePosition(const QPoint& pos)
......@@ -157,7 +157,7 @@ void Palapeli::SelectPieceInteractor::mousePressEvent(const Palapeli::MouseEvent
Palapeli::MoveViewportInteractor::MoveViewportInteractor(QGraphicsView* view)
: Palapeli::Interactor(Palapeli::MouseInteractor, view)
{
setMetadata(i18nc("Description (used like a name) for a mouse interaction method", "Move viewport by dragging"), QIcon());
setMetadata(ViewportInteraction, i18nc("Description (used like a name) for a mouse interaction method", "Move viewport by dragging"), QIcon());
}
void Palapeli::MoveViewportInteractor::mousePressEvent(const Palapeli::MouseEvent& event)
......@@ -180,7 +180,7 @@ void Palapeli::MoveViewportInteractor::mouseMoveEvent(const Palapeli::MouseEvent
Palapeli::ZoomViewportInteractor::ZoomViewportInteractor(QGraphicsView* view)
: Palapeli::Interactor(Palapeli::WheelInteractor, view)
{
setMetadata(i18nc("Description (used like a name) for a mouse interaction method", "Zoom viewport"), QIcon());
setMetadata(ViewportInteraction, i18nc("Description (used like a name) for a mouse interaction method", "Zoom viewport"), QIcon());
}
void Palapeli::ZoomViewportInteractor::wheelEvent(const Palapeli::WheelEvent& event)
......@@ -257,7 +257,7 @@ Palapeli::RubberBandInteractor::RubberBandInteractor(QGraphicsView* view)
: Palapeli::Interactor(Palapeli::MouseInteractor, view)
, m_item(new Palapeli::RubberBandItem)
{
setMetadata(i18nc("Description (used like a name) for a mouse interaction method", "Select multiple pieces at once"), QIcon());
setMetadata(PieceInteraction, i18nc("Description (used like a name) for a mouse interaction method", "Select multiple pieces at once"), QIcon());
if (scene())
scene()->addItem(m_item);
m_item->hide(); //NOTE: This is not necessary for the painting, but we use m_item->isVisible() to determine whether we are rubberbanding at the moment.
......
......@@ -82,6 +82,9 @@ namespace Palapeli
Qt::MouseButton m_button;
Qt::Orientation m_wheelDirection;
};
class Interactor;
typedef QPair<Palapeli::InteractorTrigger, Palapeli::Interactor*> AssociatedInteractorTrigger;
}
bool Palapeli::InteractorTrigger::operator!=(const Palapeli::InteractorTrigger& other) const
......
......@@ -17,7 +17,9 @@
***************************************************************************/
#include "mainwindow.h"
#include "../config/triggerconfigwidget.h"
#include "../creator/puzzlecreator.h"
#include "../engine/interactormanager.h"
#include "../engine/scene.h"
#include "../engine/texturehelper.h"
#include "../engine/view.h"
......@@ -190,7 +192,7 @@ void Palapeli::MainWindow::configurePalapeli()
//setup dialog
KConfigDialog settingsDialog(this, QString(), Settings::self());
settingsDialog.addPage(settingsWidget, i18n("General settings"))->setIcon(KIcon("configure"));
// settingsDialog.addPage(new Palapeli::InteractorManagerWidget(m_puzzleTable->view()->interactorManager()), i18n("Mouse interaction"))->setIcon(KIcon("input-mouse"));
settingsDialog.addPage(new Palapeli::TriggerConfigWidget(m_puzzleTable->view()->interactorManager()), i18n("Mouse interaction"))->setIcon(KIcon("input-mouse"));
// connect(&settingsDialog, SIGNAL(settingsChanged(const QString&)), this, SLOT(configureFinished())); //NOTE: unused ATM (settings are read on demand)
settingsDialog.exec();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment