diff --git a/declarativeimports/core/CMakeLists.txt b/declarativeimports/core/CMakeLists.txt index 64254ac8d..3626816a4 100644 --- a/declarativeimports/core/CMakeLists.txt +++ b/declarativeimports/core/CMakeLists.txt @@ -11,6 +11,7 @@ set(corebindings_SRCS framesvgitem.cpp dialog.cpp tooltip.cpp + dataenginebindings.cpp ) INCLUDE_DIRECTORIES( @@ -23,7 +24,7 @@ qt4_automoc(${corebindings_SRCS}) add_library(corebindingsplugin SHARED ${corebindings_SRCS}) -target_link_libraries(corebindingsplugin ${KDE4_PLASMA_LIBS} ${QT_QTSCRIPT_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY}) +target_link_libraries(corebindingsplugin ${KDE4_PLASMA_LIBS} ${QT_QTSCRIPT_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} kdeclarative) install(TARGETS corebindingsplugin DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/plasma/core) install(FILES qmldir DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/plasma/core) diff --git a/declarativeimports/core/corebindingsplugin.cpp b/declarativeimports/core/corebindingsplugin.cpp index 6e06c2e6c..f08d8b36d 100644 --- a/declarativeimports/core/corebindingsplugin.cpp +++ b/declarativeimports/core/corebindingsplugin.cpp @@ -23,17 +23,21 @@ #include #include +#include + +#include #include #include -#include "datasource_p.h" +#include "datasource.h" #include "datamodel.h" -#include "framesvgitem_p.h" -#include "svgitem_p.h" -#include "theme_p.h" +#include "framesvgitem.h" +#include "svgitem.h" +#include "theme.h" #include "dialog.h" #include "tooltip.h" +#include "dataenginebindings_p.h" void CoreBindingsPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) { @@ -43,6 +47,19 @@ void CoreBindingsPlugin::initializeEngine(QDeclarativeEngine *engine, const char ThemeProxy *theme = new ThemeProxy(context); context->setContextProperty("theme", theme); + + KDeclarative kdeclarative; + kdeclarative.setDeclarativeEngine(engine); + kdeclarative.initialize(); + QScriptEngine *scriptEngine = kdeclarative.scriptEngine(); + + //inject the hack only if wasn't injected already + if (!scriptEngine->globalObject().property("i18n").isValid()) { + //binds things like kconfig and icons + kdeclarative.setupBindings(); + } + + registerDataEngineMetaTypes(scriptEngine); } void CoreBindingsPlugin::registerTypes(const char *uri) diff --git a/declarativeimports/core/dataenginebindings.cpp b/declarativeimports/core/dataenginebindings.cpp new file mode 100644 index 000000000..8fb608028 --- /dev/null +++ b/declarativeimports/core/dataenginebindings.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2007 Richard J. Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * 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 program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "dataenginebindings_p.h" + +typedef Plasma::Service *ServicePtr; +QScriptValue qScriptValueFromService(QScriptEngine *engine, const ServicePtr &service) +{ + return engine->newQObject(const_cast(service), QScriptEngine::AutoOwnership, QScriptEngine::PreferExistingWrapperObject); +} + +void serviceFromQScriptValue(const QScriptValue &scriptValue, ServicePtr &service) +{ + QObject *obj = scriptValue.toQObject(); + service = static_cast(obj); +} + +typedef Plasma::DataEngine *DataEnginePtr; +QScriptValue qScriptValueFromDataEngine(QScriptEngine *engine, const DataEnginePtr &dataEngine) +{ + return engine->newQObject(const_cast(dataEngine), QScriptEngine::AutoOwnership, QScriptEngine::PreferExistingWrapperObject); +} + +void dataEngineFromQScriptValue(const QScriptValue &scriptValue, DataEnginePtr &dataEngine) +{ + QObject *obj = scriptValue.toQObject(); + dataEngine = static_cast(obj); +} + +typedef Plasma::ServiceJob *ServiceJobPtr; +QScriptValue qScriptValueFromServiceJob(QScriptEngine *engine, const ServiceJobPtr &serviceJob) +{ + return engine->newQObject(const_cast(serviceJob), QScriptEngine::AutoOwnership, QScriptEngine::PreferExistingWrapperObject); +} + +void serviceJobFromQScriptValue(const QScriptValue &scriptValue, ServiceJobPtr &serviceJob) +{ + QObject *obj = scriptValue.toQObject(); + serviceJob = static_cast(obj); +} + +void registerDataEngineMetaTypes(QScriptEngine *engine) +{ + qRegisterMetaType("Plasma::DataEngine::Data"); + qRegisterMetaType("DataEngine::Data"); + qScriptRegisterMapMetaType(engine); + qScriptRegisterMetaType(engine, qScriptValueFromService, serviceFromQScriptValue); + qScriptRegisterMetaType(engine, qScriptValueFromDataEngine, dataEngineFromQScriptValue); + qScriptRegisterMetaType(engine, qScriptValueFromServiceJob, serviceJobFromQScriptValue); +} + diff --git a/declarativeimports/core/dataenginebindings_p.h b/declarativeimports/core/dataenginebindings_p.h new file mode 100644 index 000000000..17193c1ee --- /dev/null +++ b/declarativeimports/core/dataenginebindings_p.h @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Richard J. Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * 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 program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DATAENGINEBIND_H +#define DATAENGINEBIND_H + +#include +#include +#include +#include + +#include +#include +#include + +using namespace Plasma; + +Q_DECLARE_METATYPE(DataEngine::Dict) +Q_DECLARE_METATYPE(DataEngine::Data) + +template +QScriptValue qScriptValueFromMap(QScriptEngine *eng, const M &map) +{ + //kDebug() << "qScriptValueFromMap called"; + QScriptValue obj = eng->newObject(); + typename M::const_iterator begin = map.constBegin(); + typename M::const_iterator end = map.constEnd(); + typename M::const_iterator it; + for (it = begin; it != end; ++it) { + if (it.value().type() == QVariant::Hash) { + obj.setProperty(it.key(), qScriptValueFromMap(eng, it.value().toHash())); + } else if (it.value().type() == QVariant::Map) { + obj.setProperty(it.key(), qScriptValueFromMap(eng, it.value().toMap())); + } else { + obj.setProperty(it.key(), qScriptValueFromValue(eng, it.value())); + } + } + + return obj; +} + +template +void qScriptValueToMap(const QScriptValue &value, M &map) +{ + //kDebug() << "qScriptValueToMap called"; + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + map[it.name()] = qscriptvalue_cast(it.value()); + } +} + +template +int qScriptRegisterMapMetaType( + QScriptEngine *engine, + const QScriptValue &prototype = QScriptValue() +#ifndef qdoc + , T * /* dummy */ = 0 +#endif +) +{ + return qScriptRegisterMetaType(engine, qScriptValueFromMap, qScriptValueToMap, prototype); +} + +void registerDataEngineMetaTypes(QScriptEngine *engine); + +#endif // DATAENGINE_H + diff --git a/declarativeimports/core/datamodel.cpp b/declarativeimports/core/datamodel.cpp index 29da9e13c..0b260af4f 100644 --- a/declarativeimports/core/datamodel.cpp +++ b/declarativeimports/core/datamodel.cpp @@ -18,7 +18,7 @@ */ #include "datamodel.h" -#include "datasource_p.h" +#include "datasource.h" #include diff --git a/declarativeimports/core/datasource.cpp b/declarativeimports/core/datasource.cpp index b33a38728..b29158809 100644 --- a/declarativeimports/core/datasource.cpp +++ b/declarativeimports/core/datasource.cpp @@ -19,7 +19,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "datasource_p.h" +#include "datasource.h" #include "qdeclarativeengine.h" #include "qdeclarativecontext.h" @@ -196,4 +196,4 @@ void DataSource::disconnectSource(const QString &source) } } -#include "datasource_p.moc" +#include "datasource.moc" diff --git a/declarativeimports/core/datasource_p.h b/declarativeimports/core/datasource.h similarity index 100% rename from declarativeimports/core/datasource_p.h rename to declarativeimports/core/datasource.h diff --git a/declarativeimports/core/dialog.cpp b/declarativeimports/core/dialog.cpp index 3b063f36e..57e9adecd 100644 --- a/declarativeimports/core/dialog.cpp +++ b/declarativeimports/core/dialog.cpp @@ -20,7 +20,9 @@ #include "dialog.h" #include "declarativeitemcontainer_p.h" +#include #include +#include #include #include #include @@ -31,6 +33,9 @@ #include +int DialogProxy::offscreenX = 0; +int DialogProxy::offscreenY = 0; + DialogMargins::DialogMargins(Plasma::Dialog *dialog, QObject *parent) : QObject(parent), m_dialog(dialog) @@ -95,8 +100,8 @@ DialogProxy::DialogProxy(QObject *parent) DialogProxy::~DialogProxy() { - delete m_dialog; delete m_declarativeItemContainer; + delete m_dialog; } QGraphicsObject *DialogProxy::mainItem() const @@ -171,6 +176,12 @@ void DialogProxy::syncMainItem() } } m_dialog->setGraphicsWidget(widget); + + if (!qobject_cast(scene)) { + offscreenX -= 1024; + offscreenY -= 1024; + widget->setPos(offscreenX, offscreenY); + } } bool DialogProxy::isVisible() const @@ -190,16 +201,98 @@ void DialogProxy::setVisible(const bool visible) } } -QPoint DialogProxy::popupPosition(QGraphicsObject *item, int alignment) const +QPoint DialogProxy::popupPosition(QGraphicsObject *item, int alignment) { - if (!item) { - return QPoint(); + QGraphicsObject *actualItem = item; + + //if no item is passed search the root item in order to figure out the view + if (!actualItem) { + actualItem = qobject_cast(parent()); + + //search the root object + while (true) { + QGraphicsObject *ancestor = qobject_cast(actualItem->parent()); + + if (ancestor) { + actualItem = ancestor; + } else { + break; + } + } + if (!actualItem) { + return QPoint(); + } } - Plasma::Corona *corona = qobject_cast(item->scene()); - if (corona) { - return corona->popupPosition(item, m_dialog->size(), (Qt::AlignmentFlag)alignment); + + //ensure the dialog has the proper size + syncMainItem(); + m_dialog->syncToGraphicsWidget(); + + Plasma::Corona *corona = qobject_cast(actualItem->scene()); + if (corona && item) { + return corona->popupPosition(actualItem, m_dialog->size(), (Qt::AlignmentFlag)alignment); } else { - return QPoint(); + + QList views = actualItem->scene()->views(); + + + if (views.size() < 1) { + return QPoint(); + } + + QGraphicsView *view = 0; + if (views.size() == 1) { + view = views[0]; + } else { + QGraphicsView *found = 0; + QGraphicsView *possibleFind = 0; + + foreach (QGraphicsView *v, views) { + if (v->sceneRect().intersects(actualItem->sceneBoundingRect()) || + v->sceneRect().contains(actualItem->scenePos())) { + if (v->isActiveWindow()) { + found = v; + } else { + possibleFind = v; + } + } + } + view = found ? found : possibleFind; + } + + if (!view) { + return QPoint(); + } + + //if no item was explicitly specified, align the dialog in the center of the parent view + if (!item) { + return view->geometry().center() - QPoint(m_dialog->width()/2, m_dialog->height()/2); + } + + //swap direction if necessary + if (QApplication::isRightToLeft() && alignment != Qt::AlignCenter) { + if (alignment == Qt::AlignRight) { + alignment = Qt::AlignLeft; + } else { + alignment = Qt::AlignRight; + } + } + + int xOffset = 0; + + if (alignment == Qt::AlignCenter) { + xOffset = actualItem->boundingRect().width()/2 - m_dialog->width()/2; + } else if (alignment == Qt::AlignRight) { + xOffset = actualItem->boundingRect().width() - m_dialog->width(); + } + + const QRect avail = QApplication::desktop()->availableGeometry(view); + QPoint menuPos = view->mapToGlobal(view->mapFromScene(actualItem->scenePos()+QPoint(xOffset, actualItem->boundingRect().height()))); + + if (menuPos.y() + m_dialog->height() > avail.bottom()) { + menuPos = view->mapToGlobal(view->mapFromScene(actualItem->scenePos() - QPoint(-xOffset, m_dialog->height()))); + } + return menuPos; } } diff --git a/declarativeimports/core/dialog.h b/declarativeimports/core/dialog.h index a871a80d1..5e307bea3 100644 --- a/declarativeimports/core/dialog.h +++ b/declarativeimports/core/dialog.h @@ -119,8 +119,13 @@ public: QObject *margins() const; + /** + * @returns The suggested screen position for the popup + * @arg item the item the popup has to be positioned relatively to. if null, the popup will be positioned in the center of the window + * @arg alignment alignment of the popup compared to the item + */ //FIXME: alignment should be Qt::AlignmentFlag - Q_INVOKABLE QPoint popupPosition(QGraphicsObject *item, int alignment=Qt::AlignLeft) const; + Q_INVOKABLE QPoint popupPosition(QGraphicsObject *item, int alignment=Qt::AlignLeft) ; //FIXME:: Qt::WidgetAttribute should be already Q_INVOKABLE void setAttribute(int attribute, bool on); @@ -148,6 +153,8 @@ private: DialogMargins *m_margins; bool m_activeWindow; Plasma::Location m_location; + static int offscreenX; + static int offscreenY; }; #endif diff --git a/declarativeimports/core/framesvgitem.cpp b/declarativeimports/core/framesvgitem.cpp index 4c030f356..edfcbc934 100644 --- a/declarativeimports/core/framesvgitem.cpp +++ b/declarativeimports/core/framesvgitem.cpp @@ -17,7 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "framesvgitem_p.h" +#include "framesvgitem.h" #include @@ -130,4 +130,4 @@ void FrameSvgItem::doUpdate() } // Plasma namespace -#include "framesvgitem_p.moc" +#include "framesvgitem.moc" diff --git a/declarativeimports/core/framesvgitem_p.h b/declarativeimports/core/framesvgitem.h similarity index 100% rename from declarativeimports/core/framesvgitem_p.h rename to declarativeimports/core/framesvgitem.h diff --git a/declarativeimports/core/svgitem.cpp b/declarativeimports/core/svgitem.cpp index ae246e717..00e6d2a84 100644 --- a/declarativeimports/core/svgitem.cpp +++ b/declarativeimports/core/svgitem.cpp @@ -17,7 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "svgitem_p.h" +#include "svgitem.h" #include @@ -124,4 +124,4 @@ void SvgItem::updateNeeded() } // Plasma namespace -#include "svgitem_p.moc" +#include "svgitem.moc" diff --git a/declarativeimports/core/svgitem_p.h b/declarativeimports/core/svgitem.h similarity index 100% rename from declarativeimports/core/svgitem_p.h rename to declarativeimports/core/svgitem.h diff --git a/declarativeimports/core/theme.cpp b/declarativeimports/core/theme.cpp index 262afff59..702503d1f 100644 --- a/declarativeimports/core/theme.cpp +++ b/declarativeimports/core/theme.cpp @@ -17,7 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ -#include "theme_p.h" +#include "theme.h" #include @@ -64,6 +64,8 @@ FontProxy::FontProxy(Plasma::Theme::FontRole role, QObject *parent) this, SIGNAL(weightChanged())); connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SIGNAL(wordSpacingChanged())); + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), + this, SIGNAL(mSizeChanged())); } FontProxy::~FontProxy() @@ -140,6 +142,10 @@ qreal FontProxy::wordSpacing() const return Plasma::Theme::defaultTheme()->font(m_fontRole).wordSpacing(); } +QSize FontProxy::mSize() const +{ + return QFontMetrics(Plasma::Theme::defaultTheme()->font(m_fontRole)).boundingRect("M").size(); +} //********** Theme ************* @@ -299,5 +305,5 @@ int ThemeProxy::enormousIconSize() const return KIconLoader::SizeEnormous; } -#include "theme_p.moc" +#include "theme.moc" diff --git a/declarativeimports/core/theme_p.h b/declarativeimports/core/theme.h similarity index 97% rename from declarativeimports/core/theme_p.h rename to declarativeimports/core/theme.h index e83e492e2..389cfb5cb 100644 --- a/declarativeimports/core/theme_p.h +++ b/declarativeimports/core/theme.h @@ -41,6 +41,7 @@ class FontProxy : public QObject Q_PROPERTY(bool underline READ underline NOTIFY underlineChanged ) Q_PROPERTY(Weight weight READ weight NOTIFY weightChanged ) Q_PROPERTY(qreal wordSpacing READ wordSpacing NOTIFY wordSpacingChanged ) + Q_PROPERTY(QSize mSize READ mSize NOTIFY mSizeChanged ) Q_ENUMS(Capitalization) Q_ENUMS(Weight) @@ -80,6 +81,11 @@ public: Weight weight() const; qreal wordSpacing() const; + /** + * @return The size of an uppercase M in this font + */ + QSize mSize() const; + Q_SIGNALS: void boldChanged(); void capitalizationChanged(); @@ -92,6 +98,7 @@ Q_SIGNALS: void underlineChanged(); void weightChanged(); void wordSpacingChanged(); + void mSizeChanged(); private: Plasma::Theme::FontRole m_fontRole; diff --git a/declarativeimports/core/tooltip.cpp b/declarativeimports/core/tooltip.cpp index 966450ce5..4eaa5b8fc 100644 --- a/declarativeimports/core/tooltip.cpp +++ b/declarativeimports/core/tooltip.cpp @@ -70,13 +70,16 @@ void ToolTipProxy::setTarget(QGraphicsObject *target) void ToolTipProxy::syncTarget() { + if (!m_target) { + return; + } // find the scene QGraphicsScene *scene = m_target.data()->scene(); if (!scene) { QObject *parent = m_target.data(); while ((parent = parent->parent())) { QGraphicsObject *qo = qobject_cast(parent); - if (qo) { + if (qo && qo->scene()) { scene = qo->scene(); scene->addItem(m_target.data()); break; diff --git a/declarativeimports/plasmacomponents/CMakeLists.txt b/declarativeimports/plasmacomponents/CMakeLists.txt index e60727554..f855e3b3e 100644 --- a/declarativeimports/plasmacomponents/CMakeLists.txt +++ b/declarativeimports/plasmacomponents/CMakeLists.txt @@ -6,6 +6,7 @@ set(plasmacomponents_SRCS enums.cpp qmenu.cpp qmenuitem.cpp + kdialogproxy.cpp ) INCLUDE_DIRECTORIES( @@ -18,8 +19,17 @@ qt4_automoc(${plasmacomponents_SRCS}) add_library(plasmacomponentsplugin SHARED ${plasmacomponents_SRCS}) -target_link_libraries(plasmacomponentsplugin ${QT_QTCORE_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} ${QT_QTGUI_LIBRARY}) +target_link_libraries(plasmacomponentsplugin ${QT_QTCORE_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDEUI_LIBRARY}) install(TARGETS plasmacomponentsplugin DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/plasma/components) install(DIRECTORY qml/ DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/plasma/components) + + + +#The platform specific stuff, overwrites a copy of the desktop one +#it does install some files on top of the old ones, it's pretty hackyu but it's intended since there are no more elegant ways to produce a fallback during a qml import from the most specific files to the general ones if specific were not found + +install(TARGETS plasmacomponentsplugin DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) +install(DIRECTORY qml/ DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) +install(DIRECTORY platformcomponents/touch/ DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) diff --git a/declarativeimports/plasmacomponents/kdialogproxy.cpp b/declarativeimports/plasmacomponents/kdialogproxy.cpp new file mode 100644 index 000000000..9e98d35f2 --- /dev/null +++ b/declarativeimports/plasmacomponents/kdialogproxy.cpp @@ -0,0 +1,151 @@ +/* +* Copyright (C) 2011 by Marco MArtin +* +* 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, 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 "kdialogproxy.h" + +#include + +#include + +KDialogProxy::KDialogProxy (QObject *parent) + : QObject(parent), + m_status(DialogStatus::Closed) +{ + m_dialog = new KDialog(0); + m_label = new QLabel(m_dialog); + m_label->setWordWrap(true); + m_dialog->setMainWidget(m_label); + m_dialog->setButtons( KDialog::Ok | KDialog::Cancel); + connect(m_dialog, SIGNAL(okClicked()), this, SIGNAL(accepted())); + connect(m_dialog, SIGNAL(cancelClicked()), this, SIGNAL(rejected())); + connect(m_dialog, SIGNAL(closeClicked()), this, SIGNAL(rejected())); +} + +KDialogProxy::~KDialogProxy() +{ + delete m_dialog; +} + + +void KDialogProxy::setTitleText(const QString &text) +{ + if (text == m_titleText) { + return; + } + + m_dialog->setCaption(text); + m_titleText = text; + emit titleTextChanged(); +} + +QString KDialogProxy::titleText() const +{ + return m_titleText; +} + + +void KDialogProxy::setTitleIcon(const QString &icon) +{ + if (icon == m_titleIcon) { + return; + } + + m_dialog->setWindowIcon(KIcon(icon)); + m_titleIcon = icon; + emit titleIconChanged(); +} + +QString KDialogProxy::titleIcon() const +{ + return m_titleIcon; +} + + +void KDialogProxy::setMessage(const QString &message) +{ + if (message == m_message) { + return; + } + + m_label->setText(message); + m_message = message; + emit messageChanged(); +} + +QString KDialogProxy::message() const +{ + return m_message; +} + + +void KDialogProxy::setAcceptButtonText(const QString &text) +{ + if (text == m_acceptButtonText) { + return; + } + + m_dialog->setButtonText(KDialog::Ok, text); + m_acceptButtonText = text; + emit acceptButtonTextChanged(); +} + +QString KDialogProxy::acceptButtonText() const +{ + return m_acceptButtonText; +} + + +void KDialogProxy::setRejectButtonText(const QString &text) +{ + if (text == m_rejectButtonText) { + return; + } + + m_dialog->setButtonText(KDialog::Cancel, text); + m_rejectButtonText = text; + emit rejectButtonTextChanged(); +} + +QString KDialogProxy::rejectButtonText() const +{ + return m_rejectButtonText; +} + + +DialogStatus::Status KDialogProxy::status() const +{ + return m_status; +} + +void KDialogProxy::open() +{ + m_dialog->show(); + m_status = DialogStatus::Open; + emit statusChanged(); +} + +void KDialogProxy::close() +{ + m_dialog->hide(); + m_status = DialogStatus::Closed; + emit statusChanged(); +} + +#include "kdialogproxy.moc" + diff --git a/declarativeimports/plasmacomponents/kdialogproxy.h b/declarativeimports/plasmacomponents/kdialogproxy.h new file mode 100644 index 000000000..19e4ffa8f --- /dev/null +++ b/declarativeimports/plasmacomponents/kdialogproxy.h @@ -0,0 +1,88 @@ +/* +* Copyright (C) 2011 by Marco MArtin +* +* 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, 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 KDIALOG_PROXY_H +#define KDIALOG_PROXY_H + +#include +#include +#include "kdialogproxy.h" +#include "enums.h" + +class QLabel; + +class KDialogProxy : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString titleText READ titleText WRITE setTitleText NOTIFY titleTextChanged) + Q_PROPERTY(QString titleIcon READ titleIcon WRITE setTitleIcon NOTIFY titleIconChanged) + Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged) + Q_PROPERTY(QString acceptButtonText READ acceptButtonText WRITE setAcceptButtonText NOTIFY acceptButtonTextChanged) + Q_PROPERTY(QString rejectButtonText READ rejectButtonText WRITE setRejectButtonText NOTIFY rejectButtonTextChanged) + Q_PROPERTY(DialogStatus::Status status READ status NOTIFY statusChanged) + +public: + KDialogProxy(QObject *parent = 0); + ~KDialogProxy(); + + void setTitleText(const QString &text); + QString titleText() const; + + void setTitleIcon(const QString &icon); + QString titleIcon() const; + + void setMessage(const QString &message); + QString message() const; + + void setAcceptButtonText(const QString &text); + QString acceptButtonText() const; + + void setRejectButtonText(const QString &text); + QString rejectButtonText() const; + + void setStatus(DialogStatus::Status status); + DialogStatus::Status status() const; + + Q_INVOKABLE void open(); + Q_INVOKABLE void close(); + +Q_SIGNALS: + void titleTextChanged(); + void titleIconChanged(); + void messageChanged(); + void acceptButtonTextChanged(); + void rejectButtonTextChanged(); + void statusChanged(); + void accepted(); + void rejected(); + +private: + KDialog *m_dialog; + QLabel *m_label; + QString m_titleText; + QString m_titleIcon; + QString m_message; + QString m_acceptButtonText; + QString m_rejectButtonText; + DialogStatus::Status m_status; +}; + +#endif //KDIALOG_PROXY_H + diff --git a/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp b/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp index 0ee5a0a98..b1bee475e 100644 --- a/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp +++ b/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp @@ -20,22 +20,34 @@ #include "plasmacomponentsplugin.h" #include +#include #include "qrangemodel.h" +#include + #include "enums.h" #include "qmenu.h" #include "qmenuitem.h" - +#include "kdialogproxy.h" void PlasmaComponentsPlugin::registerTypes(const char *uri) { Q_ASSERT(uri == QLatin1String("org.kde.plasma.components")); + QString componentsPlatform = getenv("KDE_PLASMA_COMPONENTS_PLATFORM"); + if (componentsPlatform.isEmpty()) { + KConfigGroup cg(KSharedConfig::openConfig("kdeclarativerc"), "Components-platform"); + componentsPlatform = cg.readEntry("name", "desktop"); + } - qmlRegisterType(uri, 0, 1, "Menu"); - qmlRegisterType(uri, 0, 1, "ContextMenu"); - qmlRegisterType(uri, 0, 1, "MenuItem"); + if (componentsPlatform == "desktop") { + qmlRegisterType(uri, 0, 1, "QueryDialog"); + + qmlRegisterType(uri, 0, 1, "Menu"); + qmlRegisterType(uri, 0, 1, "ContextMenu"); + qmlRegisterType(uri, 0, 1, "MenuItem"); + } qmlRegisterType(uri, 0, 1, "RangeModel"); diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/ButtonShadow.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/ButtonShadow.qml new file mode 100644 index 000000000..09a0a5250 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/ButtonShadow.qml @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 by Daker Fernandes Pinheiro + * Copyright (C) 2011 by Marco Martin + * + * 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, 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. + */ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore + +Item { + id: main + state: parent.state + property bool hasOverState: false + + PlasmaCore.FrameSvgItem { + id: shadow + + anchors { + fill: parent + leftMargin: -margins.left + topMargin: -margins.top + rightMargin: -margins.right + bottomMargin: -margins.bottom + } + imagePath: "widgets/button" + prefix: "shadow" + } + + states: [ + State { + name: "shadow" + PropertyChanges { + target: shadow + opacity: 1 + } + }, + State { + name: "hidden" + PropertyChanges { + target: shadow + opacity: 0 + } + } + ] + + transitions: [ + Transition { + PropertyAnimation { + properties: "opacity" + duration: 250 + easing.type: Easing.OutQuad + } + } + ] +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/Menu.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/Menu.qml new file mode 100644 index 000000000..b60c7c037 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/Menu.qml @@ -0,0 +1,109 @@ +/* +* Copyright (C) 2011 by Marco Martin +* +* 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, 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. +*/ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore +import "." 0.1 + +Item { + id: root + + default property alias content: visualModel.children + property Item visualParent + property int status: DialogStatus.Closed + + function open() + { + var parent = root.visualParent ? root.visualParent : root.parent + var pos = dialog.popupPosition(parent, Qt.alignCenter) + dialog.x = pos.x + dialog.y = pos.y + + dialog.visible = true + dialog.focus = true + } + + function close() + { + dialog.visible = false + } + + visible: false + + PlasmaCore.Dialog { + id: dialog + visible: false + windowFlags: Qt.Popup + onVisibleChanged: { + if (visible) { + status = DialogStatus.Open + } else { + status = DialogStatus.Closed + } + } + + mainItem: Item { + id: contentItem + + width: theme.defaultFont.mSize.width * 12 + height: Math.min(listView.contentHeight, theme.defaultFont.mSize.height * 25) + + + ListView { + id: listView + anchors.fill: parent + + currentIndex : -1 + clip: true + + model: VisualItemModel { + id: visualModel + onChildrenChanged: { + for (var i = 0; i < children.length; ++i) { + if (children[i].clicked != undefined) + children[i].clicked.connect(root.close) + } + } + } + } + + ScrollBar { + id: scrollBar + flickableItem: listView + visible: listView.contentHeight > contentItem.height + //platformInverted: root.platformInverted + anchors { top: listView.top; right: listView.right } + } + } + } + + + onStatusChanged: { + if (status == DialogStatus.Opening) { + if (listView.currentItem != null) { + listView.currentItem.focus = false + } + listView.currentIndex = -1 + listView.positionViewAtIndex(0, ListView.Beginning) + } + else if (status == DialogStatus.Open) { + listView.focus = true + } + } +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/MenuItem.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/MenuItem.qml new file mode 100644 index 000000000..9ef171d5c --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/MenuItem.qml @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore + +Item { + id: root + + property alias text: textArea.text + + signal clicked + + property int implicitWidth: textArea.paintedWidth + 6 + width: parent.width + height: textArea.paintedHeight + 6 + + Label { + id: textArea + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + } + + + MouseArea { + id: mouseArea + + property bool canceled: false + + anchors.fill: parent + + onPressed: { + canceled = false + } + onClicked: { + if (!canceled) + root.clicked() + } + onExited: canceled = true + } + + Keys.onPressed: { + event.accepted = true + switch (event.key) { + case Qt.Key_Select: + case Qt.Key_Enter: + case Qt.Key_Return: { + if (!event.isAutoRepeat) { + root.clicked() + } + break + } + + case Qt.Key_Up: { + if (ListView.view != null) + ListView.view.decrementCurrentIndex() + else + event.accepted = false + break + } + + case Qt.Key_Down: { + if (ListView.view != null) + ListView.view.incrementCurrentIndex() + else + event.accepted = false + break + } + default: { + event.accepted = false + break + } + } + } +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/QueryDialog.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/QueryDialog.qml new file mode 100644 index 000000000..75126dc91 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/QueryDialog.qml @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Marco Martin +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.1 + +import "." 0.1 + +CommonDialog { + id: root + objectName: "root" + + property string message + property string acceptButtonText + property string rejectButtonText + + onAcceptButtonTextChanged: internal.updateButtonTexts() + onRejectButtonTextChanged: internal.updateButtonTexts() + + onButtonClicked: { + if (acceptButtonText && index == 0) + accepted() + else + rejected() + } + + content: Item { + implicitHeight: Math.min(theme.defaultFont.mSize.height*12, label.paintedHeight+12) + width: parent.width + + Item { + anchors { + top: parent.top; topMargin: 6 + bottom: parent.bottom; bottomMargin: 6 + left: parent.left; leftMargin: 6 + right: parent.right + } + + Flickable { + id: flickable + width: parent.width + height: parent.height + anchors { left: parent.left; top: parent.top } + contentHeight: label.paintedHeight + flickableDirection: Flickable.VerticalFlick + clip: true + interactive: contentHeight > height + + Label { + id: label + anchors { right: parent.right } + width: flickable.width + wrapMode: Text.WordWrap + text: root.message + horizontalAlignment: Text.AlignLeft + } + } + + ScrollBar { + id: scrollBar + height: parent.height + anchors { top: flickable.top; right: flickable.right } + flickableItem: flickable + interactive: false + orientation: Qt.Vertical + //platformInverted: root.platformInverted + } + } + } + + QtObject { + id: internal + + function updateButtonTexts() { + var newButtonTexts = [] + if (acceptButtonText) + newButtonTexts.push(acceptButtonText) + if (rejectButtonText) + newButtonTexts.push(rejectButtonText) + root.buttonTexts = newButtonTexts + } + } +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/RoundShadow.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/RoundShadow.qml new file mode 100644 index 000000000..1ea1465ec --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/RoundShadow.qml @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011 by Daker Fernandes Pinheiro + * Copyright (C) 2011 by Marco Martin + * + * 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, 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. + */ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore + +Item { + id: main + state: parent.state + property alias imagePath: shadowSvg.imagePath + property string hoverElement: "hover" + property string focusElement: "focus" + property alias shadowElement: shadow.elementId + + PlasmaCore.Svg { + id: shadowSvg + imagePath: "widgets/actionbutton" + } + + PlasmaCore.SvgItem { + id: hover + svg: shadowSvg + elementId: "hover" + + anchors.fill: parent + + opacity: 0 + } + + PlasmaCore.SvgItem { + id: shadow + svg: shadowSvg + elementId: "shadow" + + anchors.fill: parent + } + + states: [ + State { + name: "shadow" + PropertyChanges { + target: shadow + opacity: 1 + } + PropertyChanges { + target: hover + opacity: 0 + elementId: hoverElement + } + }, + State { + name: "focus" + PropertyChanges { + target: shadow + opacity: 0 + } + PropertyChanges { + target: hover + opacity: 1 + elementId: focusElement + } + }, + State { + name: "hidden" + PropertyChanges { + target: shadow + opacity: 0 + } + PropertyChanges { + target: hover + opacity: 0 + elementId: hoverElement + } + } + ] + + transitions: [ + Transition { + PropertyAnimation { + properties: "opacity" + duration: 250 + easing.type: Easing.OutQuad + } + } + ] +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollBar.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollBar.qml new file mode 100644 index 000000000..ccb8ac494 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollBar.qml @@ -0,0 +1,136 @@ +/* +* Copyright (C) 2011 by Daker Fernandes Pinheiro +* Copyright (C) 2011 Marco Martin +* +* 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, 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 program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore + + +/** + * A generic ScrollBar/ScrollDecorator component: + * Qlways prefer this to ScrollDecorator that is not available on desktop. + * By default, this component will look and behave like a scroll decorator on touchscreens + */ +// TODO: add support mouse wheel events +Item { + id: scrollbar + + // Common API + property Flickable flickableItem: null + property int orientation: Qt.Vertical + property bool interactive: false + + // Plasma API + property bool inverted: false + property alias stepSize: range.stepSize + property bool pressed: internalLoader.item.mouseArea?internalLoader.item.mouseArea.pressed:false + property real scrollButtonInterval: 50 + + implicitWidth: internalLoader.isVertical ? (interactive ? 22 : 12) : 200 + implicitHeight: internalLoader.isVertical ? 200 : (interactive ? 22 : 12) + // TODO: needs to define if there will be specific graphics for + // disabled scroll bars + opacity: enabled ? 1.0 : 0.5 + + visible: flickableItem && internalLoader.handleEnabled + + anchors { + right: flickableItem.right + left: (orientation == Qt.Vertical) ? undefined : flickableItem.left + top: (orientation == Qt.Vertical) ? flickableItem.top : undefined + bottom: flickableItem.bottom + } + + Loader { + id: internalLoader + anchors.fill: parent + //property bool handleEnabled: internalLoader.isVertical ? item.handle.height < item.contents.height : item.handle.width < item.contents.width + property bool handleEnabled: internalLoader.isVertical ? flickableItem.contentHeight > flickableItem.height : flickableItem.contentWidth > flickableItem.width + property bool isVertical: orientation == Qt.Vertical + + function incrementValue(increment) + { + if (!flickableItem) + return; + + if (internalLoader.isVertical) { + flickableItem.contentY = Math.max(0, Math.min(flickableItem.contentHeight, + flickableItem.contentY + increment)) + } else { + flickableItem.contentX = Math.max(0, Math.min(flickableItem.contentWidth, + flickableItem.contentX + increment)) + } + } + + RangeModel { + id: range + + minimumValue: 0 + maximumValue: { + var diff; + if (internalLoader.isVertical) { + diff = flickableItem.contentHeight - flickableItem.height + } else { + diff = flickableItem.contentWidth - flickableItem.width + } + + return Math.max(0, diff) + } + + stepSize: 10 + inverted: scrollbar.inverted + positionAtMinimum: 0 + positionAtMaximum: { + if (internalLoader.isVertical) { + internalLoader.item.contents.height - internalLoader.item.handle.height + } else { + internalLoader.item.contents.width - internalLoader.item.handle.width + } + } + value: internalLoader.isVertical ? flickableItem.contentY : flickableItem.contentX + onValueChanged: { + if (flickableItem.moving) { + return + } + + if (internalLoader.isVertical) { + flickableItem.contentY = value + } else { + flickableItem.contentX = value + } + } + + position: internalLoader.isVertical ? internalLoader.item.handle.y : internalLoader.item.handle.x + + onPositionChanged: { + if (internalLoader.item.mouseArea && internalLoader.item.mouseArea.pressed) { + return + } + + if (internalLoader.isVertical) { + internalLoader.item.handle.y = position + } else { + internalLoader.item.handle.x = position + } + } + } + + source: interactive ? "ScrollBarDelegate.qml" : "ScrollDecoratorDelegate.qml" + } +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollDecorator.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollDecorator.qml new file mode 100644 index 000000000..b3b11eb7a --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/ScrollDecorator.qml @@ -0,0 +1,28 @@ +/* +* Copyright (C) 2011 Marco Martin +* +* 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, 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 program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.0 + +/** + * Just provided for compatibility + * Use ScrollBar instead. will behave like a ScrollDecorator on touchscreens + */ +ScrollBar { + interactive: false +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/SectionScroller.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/SectionScroller.qml new file mode 100644 index 000000000..0db1406f7 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/SectionScroller.qml @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.1 +import "SectionScroller.js" as Sections +import org.kde.plasma.core 0.1 as PlasmaCore + +/** + * It's similar to a ScrollBar or a ScrollDecorator. + * It's interactive and works on ListViews that have section.property set, + * so its contents are categorized. + * An indicator will say to what category the user scrolled to. + * + * Useful for things like address books or things sorted by date. + * Don't use with models too big (thousands of items) because implies + * loading all the items to memory, as well loses precision. + */ +Item { + id: root + + /** + * The listview this scroll indicator will work on + */ + property ListView listView + + onListViewChanged: { + if (listView && listView.model) + internal.initDirtyObserver(); + } + + Connections { + target: listView + onModelChanged: { + if (listView && listView.model) { + internal.initDirtyObserver() + } + } + onMovementStarted: root.opacity = 1 + onMovementEnded: { + if (!dragArea.pressed) { + fadeTimer.restart() + } + } + } + + width: 48 + opacity: 0 + Behavior on opacity { + NumberAnimation { + duration: 250 + } + } + + anchors { + right: listView.right + top: listView.top + bottom: listView.bottom + } + + Timer { + id: fadeTimer + interval: 4000 + repeat: false + running: false + onTriggered: { + root.opacity = 0 + } + } + + RangeModel { + id: range + + minimumValue: 0 + maximumValue: Math.max(0, listView.contentHeight - listView.height) + stepSize: 0 + //inverted: true + positionAtMinimum: handle.height / 2 + positionAtMaximum: root.height - handle.height - handle.height / 2 + value: listView.contentY + onValueChanged: { + if (listView.moving) { + return + } else { + listView.contentY = value + } + } + //position: handle.y + onPositionChanged: { + if (!dragArea.pressed) { + handle.y = position + } + } + } + + Rectangle { + anchors.fill: parent + color: Qt.rgba(0,0,0,0.3) + } + + Rectangle { + id: handle + width: 6 + height: 6 + color: theme.textColor + opacity: 0.7 + anchors.horizontalCenter: parent.horizontalCenter + border { + width: 1 + color: theme.backgroundColor + } + onYChanged: { + if (dragArea.pressed) { + range.position = y + } + sectionLabel.text = Sections.closestSection(y/listView.height) + } + Behavior on y { + NumberAnimation { + duration: 150 + } + } + } + PlasmaCore.FrameSvgItem { + imagePath: "widgets/tooltip" + width: sectionLabel.paintedWidth + margins.left + margins.right + height: sectionLabel.paintedHeight + margins.top + margins.bottom + Label { + id: sectionLabel + font.pointSize: theme.defaultFont.pointSize*3 + x: parent.margins.left + y: parent.margins.top + } + y: Math.min(root.height-height, Math.max(0, handle.y - height/2)) + anchors { + //verticalCenter: handle.verticalCenter + right: parent.left + } + opacity: dragArea.pressed?1:0 + Behavior on opacity { + NumberAnimation { + duration: 250 + } + } + } + /*Repeater { + id: sectionsRepeater + delegate: Label { + anchors.horizontalCenter: parent.horizontalCenter + text: Sections._sections[modelData] + y: Sections._sectionData[modelData].index*(listView.height/listView.model.count) + } + }*/ + MouseArea { + id: dragArea + anchors.fill: parent + enabled: scrollbar.enabled + drag { + target: handle + axis: Drag.YAxis + minimumY: range.positionAtMinimum + maximumY: range.positionAtMaximum + } + onPressed: { + mouse.accepted = true + handle.y = mouse.y + } + onReleased: fadeTimer.restart() + + } + + QtObject { + id: internal + + function initDirtyObserver() { + Sections.initSectionData(listView); + function dirtyObserver() { + if (!internal.modelDirty) { + internal.modelDirty = true; + dirtyTimer.running = true; + } + } + + if (listView.model.countChanged) + listView.model.countChanged.connect(dirtyObserver); + + if (listView.model.itemsChanged) + listView.model.itemsChanged.connect(dirtyObserver); + + if (listView.model.itemsInserted) + listView.model.itemsInserted.connect(dirtyObserver); + + if (listView.model.itemsMoved) + listView.model.itemsMoved.connect(dirtyObserver); + + if (listView.model.itemsRemoved) + listView.model.itemsRemoved.connect(dirtyObserver); + + sectionsRepeater.model = Sections._sections.length + } + } +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/TextFieldFocus.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/TextFieldFocus.qml new file mode 100644 index 000000000..a8b031c13 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/TextFieldFocus.qml @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2011 by Daker Fernandes Pinheiro + * Copyright (C) 2011 by Marco Martin + * + * 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, 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. + */ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore + +Item { + id: main + state: parent.state + + PlasmaCore.Svg { + id: lineEditSvg + imagePath: "widgets/lineedit" + onRepaintNeeded: { + if (lineEditSvg.hasElement("hint-focus-over-base")) { + main.z = 800 + } else { + main.z = 0 + } + } + Component.onCompleted: { + if (lineEditSvg.hasElement("hint-focus-over-base")) { + main.z = 800 + } else { + main.z = 0 + } + } + } + + PlasmaCore.FrameSvgItem { + id: hover + + anchors { + fill: parent + leftMargin: -margins.left + topMargin: -margins.top + rightMargin: -margins.right + bottomMargin: -margins.bottom + } + opacity: 0 + imagePath: "widgets/lineedit" + prefix: "hover" + } + + states: [ + State { + name: "focus" + PropertyChanges { + target: hover + opacity: 1 + prefix: "focus" + } + }, + State { + name: "hidden" + PropertyChanges { + target: hover + opacity: 0 + prefix: "hover" + } + } + ] + + transitions: [ + Transition { + PropertyAnimation { + properties: "opacity" + duration: 250 + easing.type: Easing.OutQuad + } + } + ] +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/Window.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/Window.qml new file mode 100644 index 000000000..2f436a932 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/Window.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.0 + +Item { + id: root + + property bool inPortrait: height > width + signal orientationChangeAboutToStart + signal orientationChangeStarted + signal orientationChangeFinished + + width: 800 + height: 480 + + Connections { + target: root + onInPortraitChanged: { + root.orientationChangeFinished() + } + } +} diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/qmldir b/declarativeimports/plasmacomponents/platformcomponents/touch/qmldir new file mode 100644 index 000000000..27cf61792 --- /dev/null +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/qmldir @@ -0,0 +1,42 @@ +plugin plasmacomponentsplugin + +BusyIndicator 0.1 BusyIndicator.qml +Button 0.1 Button.qml +ButtonColumn 0.1 ButtonColumn.qml +ButtonGroup 0.1 ButtonGroup.js +ButtonRow 0.1 ButtonRow.qml +CheckBox 0.1 CheckBox.qml +FlashingLabel 0.1 FlashingLabel.qml +Frame 0.1 Frame.qml +Highlight 0.1 Highlight.qml +IconWidget 0.1 IconWidget.qml +Label 0.1 Label.qml +ProgressBar 0.1 ProgressBar.qml +PushButton 0.1 PushButton.qml +RadioButton 0.1 RadioButton.qml +ScrollBar 0.1 ScrollBar.qml +ScrollDecorator 0.1 ScrollDecorator.qml +Slider 0.1 Slider.qml +Switch 0.1 Switch.qml +TextArea 0.1 TextArea.qml +TextField 0.1 TextField.qml +ToolBar 0.1 ToolBar.qml +ToolButton 0.1 ToolButton.qml +ListItem 0.1 ListItem.qml + +CommonDialog 0.1 CommonDialog.qml +QueryDialog 0.1 QueryDialog.qml +SelectionDialog 0.1 SelectionDialog.qml +Window 0.1 Window.qml +ToolBarLayout 0.1 ToolBarLayout.qml +Menu 0.1 Menu.qml +ContextMenu 0.1 Menu.qml +MenuItem 0.1 MenuItem.qml + +Page 0.1 Page.qml +PageStack 0.1 PageStack.qml + +TabBar 0.1 TabBar.qml +TabButton 0.1 TabButton.qml +TabGroup 0.1 TabGroup.qml +SectionScroller 0.1 SectionScroller.qml diff --git a/declarativeimports/plasmacomponents/qmenu.cpp b/declarativeimports/plasmacomponents/qmenu.cpp index 36d6e18da..db613ee7b 100644 --- a/declarativeimports/plasmacomponents/qmenu.cpp +++ b/declarativeimports/plasmacomponents/qmenu.cpp @@ -24,6 +24,7 @@ #include #include #include +#include QMenuProxy::QMenuProxy (QObject *parent) : QObject(parent), @@ -57,6 +58,21 @@ DialogStatus::Status QMenuProxy::status() const return m_status; } +QDeclarativeItem *QMenuProxy::visualParent() const +{ + return m_visualParent.data(); +} + +void QMenuProxy::setVisualParent(QDeclarativeItem *parent) +{ + if (m_visualParent.data() == parent) { + return; + } + + m_visualParent = parent; + emit visualParentChanged(); +} + void QMenuProxy::showMenu(int x, int y) { m_menu->clear(); @@ -79,7 +95,12 @@ void QMenuProxy::open() } m_menu->updateGeometry(); - QGraphicsObject *parentItem = qobject_cast(parent()); + QGraphicsObject *parentItem; + if (m_visualParent) { + parentItem = qobject_cast(parent()); + } else { + parentItem = m_visualParent.data(); + } if (!parentItem || !parentItem->scene()) { showMenu(0, 0); diff --git a/declarativeimports/plasmacomponents/qmenu.h b/declarativeimports/plasmacomponents/qmenu.h index 83c15a61f..0f503efaf 100644 --- a/declarativeimports/plasmacomponents/qmenu.h +++ b/declarativeimports/plasmacomponents/qmenu.h @@ -26,12 +26,15 @@ #include "qmenuitem.h" #include "enums.h" +class QDeclarativeItem; + class QMenuProxy : public QObject { Q_OBJECT Q_PROPERTY(QDeclarativeListProperty items READ items CONSTANT) Q_CLASSINFO("DefaultProperty", "items") + Q_PROPERTY(QDeclarativeItem *visualParent READ visualParent WRITE setVisualParent NOTIFY visualParentChanged()) Q_PROPERTY(DialogStatus::Status status READ status NOTIFY statusChanged) public: @@ -43,17 +46,22 @@ public: QMenuItem *action(int) const; DialogStatus::Status status() const; + QDeclarativeItem *visualParent() const; + void setVisualParent(QDeclarativeItem *parent); + void showMenu(int x, int y); Q_INVOKABLE void open(); Q_INVOKABLE void close(); Q_SIGNALS: void statusChanged(); + void visualParentChanged(); private: QList m_items; QMenu *m_menu; DialogStatus::Status m_status; + QWeakPointer m_visualParent; }; #endif //QMENU_PROXY_H diff --git a/declarativeimports/plasmacomponents/qml/AppManager.js b/declarativeimports/plasmacomponents/qml/AppManager.js new file mode 100644 index 000000000..daed77a05 --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/AppManager.js @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +function rootObject() { + var next = parent + while (next && next.parent) + next = next.parent + return next +} + +function findParent(child, propertyName) { + if (!child) + return null + var next = child.parent + while (next && !next.hasOwnProperty(propertyName)) + next = next.parent + return next +} + +function sceneX(item) { + // Binding may cause that this function is evaluated even when item is undefined, + // but in that case the Binding isn't active however so we can safely return 0 + var x = 0 + if (item) { + x = item.x + var p = item.parent + while (p) { + x += p.x + p = p.parent + } + } + return x +} + +function sceneY(item) { + // Binding may cause that this function is evaluated even when item is undefined, + // but in that case the Binding isn't active however so we can safely return 0 + var y = 0 + if (item) { + y = item.y + var p = item.parent + while (p) { + y += p.y + p = p.parent + } + } + return y +} diff --git a/declarativeimports/plasmacomponents/qml/BusyIndicator.qml b/declarativeimports/plasmacomponents/qml/BusyIndicator.qml index 1e4f4e901..96ace52d5 100644 --- a/declarativeimports/plasmacomponents/qml/BusyIndicator.qml +++ b/declarativeimports/plasmacomponents/qml/BusyIndicator.qml @@ -75,11 +75,12 @@ Item { PlasmaCore.SvgItem { id: widget + svg: PlasmaCore.Svg { imagePath: "widgets/busywidget" } + elementId: "busywidget" anchors.centerIn: parent width: busy.width height: busy.height smooth: !running || smoothAnimation - svg: PlasmaCore.Svg { imagePath: "widgets/busywidget" } } } diff --git a/declarativeimports/plasmacomponents/qml/Button.qml b/declarativeimports/plasmacomponents/qml/Button.qml index f62c6def3..b90f824a2 100644 --- a/declarativeimports/plasmacomponents/qml/Button.qml +++ b/declarativeimports/plasmacomponents/qml/Button.qml @@ -1,5 +1,7 @@ /* * Copyright (C) 2011 by Daker Fernandes Pinheiro +* Copyright (C) 2011 by Mark Gaiser +* Copyright (C) 2011 by Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as @@ -71,73 +73,127 @@ Item { signal clicked() - - function pressButton() { - if (button.enabled) - surface.prefix = "pressed"; + width: { + if (label.paintedWidth == 0) { + return height + } else { + return Math.max(theme.defaultFont.mSize.width*12, icon.width + label.paintedWidth + surfaceNormal.margins.left + surfaceNormal.margins.right) + ((icon.valid) ? surfaceNormal.margins.left : 0) + } } + height: Math.max(theme.defaultFont.mSize.height*1.8, Math.max(icon.height, label.paintedHeight) + surfaceNormal.margins.top + surfaceNormal.margins.bottom) - function releaseButton() { - if (!button.enabled) - return; - - if (button.checkable) - button.checked = !button.checked; - - // TODO: "checked" state must have special graphics? - if (button.checked) - surface.prefix = "pressed"; - else - surface.prefix = "normal"; - - button.clicked(); - button.forceActiveFocus(); - } - - width: Math.max(50, icon.width + label.paintedWidth + surface.margins.left + surface.margins.right) - height: Math.max(20, Math.max(icon.height, label.paintedHeight) + surface.margins.top + surface.margins.bottom) // TODO: needs to define if there will be specific graphics for // disabled buttons opacity: enabled ? 1.0 : 0.5 - Keys.onSpacePressed: pressButton(); - Keys.onReturnPressed: pressButton(); + QtObject { + id: internal + property bool userPressed: false + + function belongsToButtonGroup() + { + return button.parent + && button.parent.hasOwnProperty("checkedButton") + && button.parent.exclusive + } + + function pressButton() + { + userPressed = true + } + + function releaseButton() + { + userPressed = false + if (!button.enabled) { + return + } + + if ((!belongsToButtonGroup() || !button.checked) && button.checkable) { + button.checked = !button.checked + } + + button.clicked() + button.forceActiveFocus() + } + } + + Keys.onSpacePressed: internal.pressButton() + Keys.onReturnPressed: internal.pressButton() Keys.onReleased: { if (event.key == Qt.Key_Space || event.key == Qt.Key_Return) - releaseButton(); - } - - onActiveFocusChanged: { - if (activeFocus) { - shadow.state = "focus" - } else if (checked) { - shadow.state = "hidden" - } else { - shadow.state = "shadow" - } + internal.releaseButton(); } ButtonShadow { id: shadow anchors.fill: parent + state: { + if (internal.userPressed || checked) { + return "hidden" + } else if (mouse.containsMouse) { + return "hover" + } else if (button.activeFocus) { + return "focus" + } else { + return "shadow" + } + } } + // The normal button state PlasmaCore.FrameSvgItem { - id: surface + id: surfaceNormal anchors.fill: parent imagePath: "widgets/button" prefix: "normal" } + // The pressed state + PlasmaCore.FrameSvgItem { + id: surfacePressed + + anchors.fill: parent + imagePath: "widgets/button" + prefix: "pressed" + opacity: 0 + } + Item { + id: buttonContent + state: (internal.userPressed || checked) ? "pressed" : "normal" + + states: [ + State { name: "normal" }, + State { name: "pressed" } + ] + transitions: [ + Transition { + to: "normal" + // Cross fade from pressed to normal + ParallelAnimation { + NumberAnimation { target: surfaceNormal; property: "opacity"; to: 1; duration: 100 } + NumberAnimation { target: surfacePressed; property: "opacity"; to: 0; duration: 100 } + } + }, + Transition { + to: "pressed" + // Cross fade from normal to pressed + ParallelAnimation { + NumberAnimation { target: surfaceNormal; property: "opacity"; to: 0; duration: 100 } + NumberAnimation { target: surfacePressed; property: "opacity"; to: 1; duration: 100 } + } + } + ] + anchors { fill: parent - leftMargin: surface.margins.left - topMargin: surface.margins.top - rightMargin: surface.margins.right - bottomMargin: surface.margins.bottom + leftMargin: surfaceNormal.margins.left + topMargin: surfaceNormal.margins.top + rightMargin: surfaceNormal.margins.right + bottomMargin: surfaceNormal.margins.bottom } IconLoader { @@ -156,9 +212,11 @@ Item { anchors { top: parent.top bottom: parent.bottom - left: icon.valid ? icon.right : parent.left right: parent.right + left: icon.valid ? icon.right : parent.left + leftMargin: icon.valid ? parent.anchors.leftMargin : 0 } + font.capitalization: theme.defaultFont.capitalization font.family: theme.defaultFont.family font.italic: theme.defaultFont.italic @@ -169,7 +227,7 @@ Item { font.weight: theme.defaultFont.weight font.wordSpacing: theme.defaultFont.wordSpacing color: theme.buttonTextColor - horizontalAlignment: Text.AlignHCenter + horizontalAlignment: icon.valid ? Text.AlignLeft : Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } @@ -179,25 +237,8 @@ Item { anchors.fill: parent hoverEnabled: true - - onPressed: { - pressButton(); - } - onReleased: { - releaseButton(); - } - onEntered: { - shadow.state = "hover" - } - onExited: { - if (button.activeFocus) { - shadow.state = "focus" - } else if (checked) { - shadow.state = "hidden" - } else { - shadow.state = "shadow" - } - } + onPressed: internal.pressButton() + onReleased: internal.releaseButton() + onCanceled: internal.releaseButton() } } - diff --git a/declarativeimports/plasmacomponents/qml/ButtonShadow.qml b/declarativeimports/plasmacomponents/qml/ButtonShadow.qml index 0200e5032..c32b0ade6 100644 --- a/declarativeimports/plasmacomponents/qml/ButtonShadow.qml +++ b/declarativeimports/plasmacomponents/qml/ButtonShadow.qml @@ -39,6 +39,7 @@ import org.kde.plasma.core 0.1 as PlasmaCore Item { id: main state: parent.state + property bool hasOverState: true PlasmaCore.FrameSvgItem { id: hover diff --git a/declarativeimports/plasmacomponents/qml/CheckBox.qml b/declarativeimports/plasmacomponents/qml/CheckBox.qml index 636deb8f0..f077ae094 100644 --- a/declarativeimports/plasmacomponents/qml/CheckBox.qml +++ b/declarativeimports/plasmacomponents/qml/CheckBox.qml @@ -38,24 +38,9 @@ DualStateButton { view: PlasmaCore.FrameSvgItem { imagePath: "widgets/button" prefix: "normal" - width: fontMetricText.height + margins.left - height: fontMetricText.height + margins.top - //FIXME: an hack to have font metrics: can we have a proper binding? - Text { - id: fontMetricText - text: "M" - visible: false - font.capitalization: theme.defaultFont.capitalization - font.family: theme.defaultFont.family - font.italic: theme.defaultFont.italic - font.letterSpacing: theme.defaultFont.letterSpacing - font.pointSize: theme.defaultFont.pointSize - font.strikeout: theme.defaultFont.strikeout - font.underline: theme.defaultFont.underline - font.weight: theme.defaultFont.weight - font.wordSpacing: theme.defaultFont.wordSpacing - color: theme.textColor - } + width: theme.defaultFont.mSize.height + margins.left + height: theme.defaultFont.mSize.height + margins.top + PlasmaCore.SvgItem { svg: PlasmaCore.Svg { id: checkmarkSvg diff --git a/declarativeimports/plasmacomponents/qml/CommonDialog.qml b/declarativeimports/plasmacomponents/qml/CommonDialog.qml new file mode 100644 index 000000000..3aeb5724e --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/CommonDialog.qml @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Marco Martin +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore +import "." 0.1 + +Dialog { + id: root + + property alias titleText: titleAreaText.text + property string titleIcon + property variant buttonTexts: [] + property bool privateCloseIcon: false + + signal buttonClicked(int index) + + onButtonTextsChanged: { + for (var i = buttonRow.children.length; i > 0; --i) { + buttonRow.children[i - 1].destroy() + } + for (var j = 0; j < buttonTexts.length; ++j) { + var button = buttonComponent.createObject(buttonRow) + button.text = buttonTexts[j] + button.index = j + } + } + + Component { + id: buttonComponent + Button { + property int index + + onClicked: { + if (root.status == DialogStatus.Open) { + root.buttonClicked(index) + root.close() + } + } + } + } + + QtObject { + id: internal + + function buttonWidth() { + switch (buttonTexts.length) { + case 0: return 0 + case 1: return Math.round((800 - 3 * 4) / 2) + default: return (buttonContainer.width - (buttonTexts.length + 1) * + 4) / buttonTexts.length + } + } + + function iconSource() { + return root.titleIcon + } + } + + title: PlasmaCore.FrameSvgItem { + imagePath: "widgets/extender-dragger" + prefix: "root" + anchors.left: parent.left + anchors.right: parent.right + //FIXME: +5 because of Plasma::Dialog margins + height: titleAreaText.paintedHeight + margins.top + margins.bottom + + LayoutMirroring.enabled: privateCloseIcon ? false : undefined + LayoutMirroring.childrenInherit: true + + Item { + id: titleLayoutHelper // needed to make the text mirror correctly + + anchors { + right: parent.right + left: titleAreaIcon.source == "" ? parent.left : titleAreaIcon.right + top: parent.top + bottom: parent.bottom + leftMargin: parent.margins.left + rightMargin: parent.margins.right + topMargin: parent.margins.top + bottomMargin: parent.margins.bottom + } + + Label { + id: titleAreaText + + LayoutMirroring.enabled: root.LayoutMirroring.enabled + + anchors.fill: parent + + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + IconLoader { + id: titleAreaIcon + width: theme.iconSizeSmall + height: theme.iconSizeSmall + source: titleIcon + anchors.left: parent.left + anchors.rightMargin: 4 + anchors.verticalCenter: parent.verticalCenter + } + } + + buttons: Item { + id: buttonContainer + + LayoutMirroring.enabled: false + LayoutMirroring.childrenInherit: true + + width: parent.width + height: buttonTexts.length ? 48 + 2 * 2 : 0 + + Row { + id: buttonRow + objectName: "buttonRow" + anchors.centerIn: parent + spacing: 4 + } + } +} diff --git a/declarativeimports/plasmacomponents/qml/Dialog.qml b/declarativeimports/plasmacomponents/qml/Dialog.qml new file mode 100644 index 000000000..c5696594c --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/Dialog.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Marco Martin +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore +import "AppManager.js" as Utils +import "." 0.1 + +Item { + id: root + + property alias title: titleBar.children + property alias content: contentItem.children + property alias buttons: buttonItem.children +// property alias visualParent: dialog.visualParent + property int status: DialogStatus.Closed + + + property alias privateTitleHeight: titleBar.height + property alias privateButtonsHeight: buttonItem.height + + signal accepted + signal rejected + signal clickedOutside + + function open() + { + var pos = dialog.popupPosition(null, Qt.alignCenter) + dialog.x = pos.x + dialog.y = pos.y + + dialog.visible = true + dialog.focus = true + } + + function accept() + { + if (status == DialogStatus.Open) { + dialog.visible = false + accepted() + } + } + + function reject() { + if (status == DialogStatus.Open) { + dialog.visible = false + rejected() + } + } + + function close() { + dialog.visible = false + } + + visible: false + + PlasmaCore.Dialog { + id: dialog + + + //onFaderClicked: root.clickedOutside() + property Item rootItem + + //state: "Hidden" + visible: false + onVisibleChanged: { + if (visible) { + status = DialogStatus.Open + } else { + status = DialogStatus.Closed + } + } + + mainItem: Item { + width: theme.defaultFont.mSize.width * 40 + height: titleBar.childrenRect.height + contentItem.childrenRect.height + buttonItem.childrenRect.height + + // Consume all key events that are not processed by children + Keys.onPressed: event.accepted = true + Keys.onReleased: event.accepted = true + + Item { + id: titleBar + + height: childrenRect.height + anchors { + top: parent.top + left: parent.left + right: parent.right + } + } + + Item { + id: contentItem + + clip: true + anchors { + top: titleBar.bottom + left: parent.left + right: parent.right + bottom: buttonItem.top + } + } + + Item { + id: buttonItem + + height: childrenRect.height + clip: true + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + } + } + + Component.onCompleted: { + rootItem = Utils.rootObject() + } + } +} diff --git a/declarativeimports/plasmacomponents/qml/DualStateButton.qml b/declarativeimports/plasmacomponents/qml/DualStateButton.qml index e244808cb..588857f45 100644 --- a/declarativeimports/plasmacomponents/qml/DualStateButton.qml +++ b/declarativeimports/plasmacomponents/qml/DualStateButton.qml @@ -69,7 +69,7 @@ Item { property alias shadow: shadowLoader.sourceComponent width: surfaceLoader.width + label.paintedWidth - height: surfaceLoader.height + height: theme.defaultFont.mSize.height*1.8 // TODO: needs to define if there will be specific graphics for // disabled buttons opacity: dualButton.enabled ? 1.0 : 0.5 diff --git a/declarativeimports/plasmacomponents/qml/Label.qml b/declarativeimports/plasmacomponents/qml/Label.qml index 42d18e55a..07818e4fb 100644 --- a/declarativeimports/plasmacomponents/qml/Label.qml +++ b/declarativeimports/plasmacomponents/qml/Label.qml @@ -35,6 +35,10 @@ import org.kde.plasma.core 0.1 as PlasmaCore Text { id: root + height: theme.defaultFont.mSize.height*1.8 + //FIXME: wait to rely on 1.1 for lineCount > 1 + verticalAlignment: paintedHeight > theme.defaultFont.mSize.height*1.5 ? Text.AlignTop : Text.AlignVCenter + font.capitalization: theme.defaultFont.capitalization font.family: theme.defaultFont.family font.italic: theme.defaultFont.italic diff --git a/declarativeimports/plasmacomponents/qml/ListItem.qml b/declarativeimports/plasmacomponents/qml/ListItem.qml new file mode 100644 index 000000000..45c1e6e2c --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/ListItem.qml @@ -0,0 +1,95 @@ +/* + * Copyright 2010 Marco Martin + * + * 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, 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. + */ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore + +Item { + id: listItem + default property alias content: paddingItem.data + + //this defines if the item will emit clicked and look pressed on mouse down + property bool enabled: false + //item has been clicked or pressed+hold + signal clicked + signal pressAndHold + + //plasma extension + //always look pressed? + property bool checked: false + //is this to be used as section delegate? + property bool sectionDelegate: false + + width: parent.width + height: paddingItem.childrenRect.height + background.margins.top + background.margins.bottom + + property int implicitHeight: paddingItem.childrenRect.height + background.margins.top + background.margins.bottom + + + Connections { + target: listItem + onCheckedChanged: background.prefix = (listItem.checked ? "pressed" : "normal") + onSectionDelegateChanged: background.prefix = (listItem.sectionDelegate ? "section" : "normal") + } + PlasmaCore.FrameSvgItem { + id : background + imagePath: "widgets/listitem" + prefix: "normal" + + anchors.fill: parent + Component.onCompleted: { + prefix = (listItem.sectionDelegate ? "section" : (listItem.checked ? "pressed" : "normal")) + } + } + PlasmaCore.SvgItem { + svg: PlasmaCore.Svg {imagePath: "widgets/listitem"} + elementId: "separator" + anchors { + left: parent.left + right: parent.right + top: parent.top + } + height: naturalSize.height + visible: listItem.sectionDelegate || (index != undefined && index > 0 && !listItem.checked && !itemMouse.pressed) + } + + MouseArea { + id: itemMouse + property bool changeBackgroundOnPress: !listItem.checked && !listItem.sectionDelegate + anchors.fill: background + enabled: listItem.enabled + + onClicked: listItem.clicked() + onPressAndHold: listItem.pressAndHold() + onPressed: if (changeBackgroundOnPress) background.prefix = "pressed" + onReleased: if (changeBackgroundOnPress) background.prefix = "normal" + onCanceled: if (changeBackgroundOnPress) background.prefix = "normal" + } + + Item { + id: paddingItem + anchors { + fill: background + leftMargin: background.margins.left + topMargin: background.margins.top + rightMargin: background.margins.right + bottomMargin: background.margins.bottom + } + } +} diff --git a/declarativeimports/plasmacomponents/qml/Page.qml b/declarativeimports/plasmacomponents/qml/Page.qml index c5fecc320..a720d99a1 100644 --- a/declarativeimports/plasmacomponents/qml/Page.qml +++ b/declarativeimports/plasmacomponents/qml/Page.qml @@ -77,7 +77,7 @@ Item { // PageStatus.Deactivating - the page is transitioning into becoming inactive property int status: PageStatus.Inactive - property PageStack pageStack + property Item pageStack // Defines orientation lock for a page property int orientationLock: PageOrientation.Automatic @@ -89,18 +89,8 @@ Item { width: visible && parent ? parent.width : internal.previousWidth height: visible && parent ? parent.height : internal.previousHeight - onWidthChanged: internal.previousWidth = visible ? width : internal.previousWidth - onHeightChanged: internal.previousHeight = visible ? height : internal.previousHeight - - onStatusChanged: { - if (status == PageStatus.Activating) - internal.orientationLockCheck(); - } - - onOrientationLockChanged: { - if (status == PageStatus.Activating || status == PageStatus.Active) - internal.orientationLockCheck(); - } + onWidthChanged: internal.previousWidth = (visible ? width : internal.previousWidth) + onHeightChanged: internal.previousHeight = (visible ? height : internal.previousHeight) // This is needed to make a parentless Page component visible in the Designer of QtCreator. // It's done here instead of binding the visible property because binding it to a script @@ -113,36 +103,5 @@ Item { id: internal property int previousWidth: 0 property int previousHeight: 0 - - function isScreenInPortrait() { - return screen.currentOrientation == Screen.Portrait || screen.currentOrientation == Screen.PortraitInverted; - } - - function isScreenInLandscape() { - return screen.currentOrientation == Screen.Landscape || screen.currentOrientation == Screen.LandscapeInverted; - } - - function orientationLockCheck() { - switch (orientationLock) { - case PageOrientation.Automatic: - screen.allowedOrientations = Screen.Default - break - case PageOrientation.LockPortrait: - screen.allowedOrientations = Screen.Portrait - break - case PageOrientation.LockLandscape: - screen.allowedOrientations = Screen.Landscape - break - case PageOrientation.LockPrevious: - screen.allowedOrientations = screen.currentOrientation - break - case PageOrientation.Manual: - default: - // Do nothing - // In manual mode it is expected that orientation is set - // explicitly to "screen.allowedOrientations" by the user. - break - } - } } } diff --git a/declarativeimports/plasmacomponents/qml/PageStack.js b/declarativeimports/plasmacomponents/qml/PageStack.js index 5e6db40f7..eaac5ff8f 100644 --- a/declarativeimports/plasmacomponents/qml/PageStack.js +++ b/declarativeimports/plasmacomponents/qml/PageStack.js @@ -150,7 +150,11 @@ function initPage(page, properties) { } container.page = page; - container.owner = page.parent; + if (page.parent == null) { + container.owner = container; + } else { + container.owner = page.parent; + } // the page has to be reparented if if (page.parent != container) { @@ -161,6 +165,8 @@ function initPage(page, properties) { page.pageStack = root; } + page.anchors.fill = container + return container; } diff --git a/declarativeimports/plasmacomponents/qml/PageStack.qml b/declarativeimports/plasmacomponents/qml/PageStack.qml index 541193438..caa95a1e9 100644 --- a/declarativeimports/plasmacomponents/qml/PageStack.qml +++ b/declarativeimports/plasmacomponents/qml/PageStack.qml @@ -204,8 +204,8 @@ Item { // The owner of the page. property Item owner: null - // The width of the longer screen dimension - property int screenWidth: Math.max(screen.width, screen.height) + // The width of the longer stack dimension + property int stackWidth: Math.max(root.width, root.height) // Duration of transition animation (in ms) property int transitionDuration: 250 @@ -308,8 +308,9 @@ Item { { transitionAnimationRunning = true; internal.ongoingTransitionCount++; - if (root.visible) + if (root.visible) { internal.setPageStatus(page, (state == "") ? PageStatus.Activating : PageStatus.Deactivating); + } } // Called when a transition has ended. @@ -341,7 +342,7 @@ Item { // when exiting portrait and entering landscape. State { name: "LandscapeLeft" - PropertyChanges { target: container; x: -screenWidth / 2; opacity: 0 } + PropertyChanges { target: container; x: -stackWidth / 2; opacity: 0 } }, // Start state for push entry, end state for pop exit. State { @@ -352,7 +353,7 @@ Item { // when exiting portrait and entering landscape. State { name: "LandscapeRight" - PropertyChanges { target: container; x: screenWidth / 2; opacity: 0 } + PropertyChanges { target: container; x: stackWidth / 2; opacity: 0 } }, // Inactive state. State { @@ -470,14 +471,17 @@ Item { function cleanup() { if (page != null) { - if (page.status == PageStatus.Active) - internal.setPageStatus(page, PageStatus.Inactive); + if (page.status == PageStatus.Active) { + internal.setPageStatus(page, PageStatus.Inactive) + } if (owner != container) { // container is not the owner of the page - re-parent back to original owner page.visible = false; + page.anchors.fill = undefined page.parent = owner; } } + container.destroy(); } } diff --git a/declarativeimports/plasmacomponents/qml/ProgressBar.qml b/declarativeimports/plasmacomponents/qml/ProgressBar.qml index 090688fd0..9f958b66a 100644 --- a/declarativeimports/plasmacomponents/qml/ProgressBar.qml +++ b/declarativeimports/plasmacomponents/qml/ProgressBar.qml @@ -51,6 +51,7 @@ Properties: import QtQuick 1.0 import org.kde.plasma.core 0.1 as PlasmaCore +import org.kde.qtextracomponents 0.1 Item { id: progressBar @@ -64,9 +65,6 @@ Item { // Plasma API property int orientation: Qt.Horizontal - // Convinience API - property bool _isVertical: orientation == Qt.Vertical - width: 100 height: 20 opacity: enabled ? 1.0 : 0.5 @@ -86,26 +84,57 @@ Item { Item { id: contents + property bool _isVertical: orientation == Qt.Vertical + width: _isVertical ? progressBar.height : progressBar.width height: _isVertical ? progressBar.width : progressBar.height rotation: _isVertical ? 90 : 0 anchors.centerIn: parent - PlasmaCore.FrameSvgItem { - id: background - - anchors.fill: parent - imagePath: "widgets/bar_meter_horizontal" - prefix: "bar-inactive" + Timer { + id: resizeTimer + repeat: false + interval: 0 + running: false + onTriggered: { + barFrameSvg.resizeFrame(Qt.size(Math.floor(contents.height/1.6), contents.height)) + barPixmapItem.pixmap = barFrameSvg.framePixmap() + backgroundFrameSvg.resizeFrame(Qt.size(Math.floor(contents.height/1.6), contents.height)) + backgroundPixmapItem.pixmap = backgroundFrameSvg.framePixmap() + } + } + PlasmaCore.FrameSvg { + id: barFrameSvg + Component.onCompleted: { + barFrameSvg.setImagePath("widgets/bar_meter_horizontal") + barFrameSvg.setElementPrefix("bar-active") + resizeTimer.restart() + } + } + PlasmaCore.FrameSvg { + id: backgroundFrameSvg + Component.onCompleted: { + backgroundFrameSvg.setImagePath("widgets/bar_meter_horizontal") + backgroundFrameSvg.setElementPrefix("bar-inactive") + resizeTimer.restart() + } + } + QPixmapItem { + id: backgroundPixmapItem + fillMode: QPixmapItem.Tile + width: Math.floor(parent.width/(height/1.6))*Math.floor(height/1.6) + height: parent.height + onWidthChanged: resizeTimer.restart() + onHeightChanged: resizeTimer.restart() } - PlasmaCore.FrameSvgItem { - id: bar - width: indeterminate ? contents.width / 4 : range.position + QPixmapItem { + id: barPixmapItem + fillMode: QPixmapItem.Tile + width: indeterminate ? Math.floor(height/1.6)*2 : range.position height: contents.height - imagePath: "widgets/bar_meter_horizontal" - prefix: "bar-active" + visible: indeterminate || value > 0 SequentialAnimation { @@ -114,16 +143,16 @@ Item { loops: Animation.Infinite PropertyAnimation { - target: bar; + target: barPixmapItem property: "x" duration: 800 to: 0 } PropertyAnimation { - target: bar; + target: barPixmapItem property: "x" duration: 800 - to: background.width - bar.width + to: backgroundPixmapItem.width - barPixmapItem.width } } } diff --git a/declarativeimports/plasmacomponents/qml/RadioButton.qml b/declarativeimports/plasmacomponents/qml/RadioButton.qml index ee9c0bb01..bd80b83e6 100644 --- a/declarativeimports/plasmacomponents/qml/RadioButton.qml +++ b/declarativeimports/plasmacomponents/qml/RadioButton.qml @@ -44,24 +44,9 @@ DualStateButton { imagePath: "widgets/actionbutton" } elementId: "normal" - width: fontMetricText.height + 6 + width: theme.defaultFont.mSize.height + 6 height: width - //FIXME: an hack to have font metrics: can we have a proper binding? - Text { - id: fontMetricText - text: "M" - visible: false - font.capitalization: theme.defaultFont.capitalization - font.family: theme.defaultFont.family - font.italic: theme.defaultFont.italic - font.letterSpacing: theme.defaultFont.letterSpacing - font.pointSize: theme.defaultFont.pointSize - font.strikeout: theme.defaultFont.strikeout - font.underline: theme.defaultFont.underline - font.weight: theme.defaultFont.weight - font.wordSpacing: theme.defaultFont.wordSpacing - color: theme.textColor - } + PlasmaCore.SvgItem { svg: PlasmaCore.Svg { id: checkmarkSvg diff --git a/declarativeimports/plasmacomponents/qml/RoundShadow.qml b/declarativeimports/plasmacomponents/qml/RoundShadow.qml index 4b825c7ff..07343dc4d 100644 --- a/declarativeimports/plasmacomponents/qml/RoundShadow.qml +++ b/declarativeimports/plasmacomponents/qml/RoundShadow.qml @@ -40,13 +40,19 @@ import org.kde.plasma.core 0.1 as PlasmaCore Item { id: main state: parent.state + property alias imagePath: shadowSvg.imagePath + property string hoverElement: "hover" + property string focusElement: "focus" + property alias shadowElement: shadow.elementId + + PlasmaCore.Svg { + id: shadowSvg + imagePath: "widgets/actionbutton" + } PlasmaCore.SvgItem { id: hover - svg: PlasmaCore.Svg { - id: hoverSvg - imagePath: "widgets/actionbutton" - } + svg: shadowSvg elementId: "hover" anchors.fill: parent @@ -56,10 +62,7 @@ Item { PlasmaCore.SvgItem { id: shadow - svg: PlasmaCore.Svg { - id: shadowSvg - imagePath: "widgets/actionbutton" - } + svg: shadowSvg elementId: "shadow" anchors.fill: parent @@ -75,7 +78,7 @@ Item { PropertyChanges { target: hover opacity: 0 - elementId: "hover" + elementId: hoverElement } }, State { @@ -87,7 +90,7 @@ Item { PropertyChanges { target: hover opacity: 1 - elementId: "hover" + elementId: hoverElement } }, State { @@ -99,11 +102,11 @@ Item { PropertyChanges { target: hover opacity: 1 - elementId: "focus" + elementId: focusElement } }, State { - name: "hover" + name: "hidden" PropertyChanges { target: shadow opacity: 0 @@ -111,7 +114,7 @@ Item { PropertyChanges { target: hover opacity: 0 - elementId: "hover" + elementId: hoverElement } } ] diff --git a/declarativeimports/plasmacomponents/qml/ScrollBar.qml b/declarativeimports/plasmacomponents/qml/ScrollBar.qml index 6a6f81410..4e7742cbf 100644 --- a/declarativeimports/plasmacomponents/qml/ScrollBar.qml +++ b/declarativeimports/plasmacomponents/qml/ScrollBar.qml @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 by Daker Fernandes Pinheiro +* Copyright (C) 2011 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as @@ -61,36 +62,34 @@ Properties: import QtQuick 1.1 import org.kde.plasma.core 0.1 as PlasmaCore -// TODO: add support mouse wheel and key events + +/** + * A generic ScrollBar/ScrollDecorator component: + * Qlways prefer this to ScrollDecorator that is not available on desktop. + * By default, this component will look and behave like a scroll decorator on touchscreens + */ +// TODO: add support mouse wheel events Item { id: scrollbar // Common API property Flickable flickableItem: null - property bool interactive + property int orientation: Qt.Vertical + property bool interactive: true // Plasma API - property int orientation: Qt.Vertical - property bool animated: true property bool inverted: false - property bool updateValueWhileDragging: true property alias stepSize: range.stepSize - property alias pressed: mouseArea.pressed + property bool pressed: internalLoader.item.mouseArea?internalLoader.item.mouseArea.pressed:false property real scrollButtonInterval: 50 - // Convinience API - property bool _isVertical: orientation == Qt.Vertical - property bool _showButtons: stepSize != 0 - property bool _inverted: _isVertical ? - !scrollbar.inverted : scrollbar.inverted - - implicitWidth: _isVertical ? 22 : 200 - implicitHeight: _isVertical ? 200 : 22 + implicitWidth: internalLoader.isVertical ? (interactive ? 22 : 12) : 200 + implicitHeight: internalLoader.isVertical ? 200 : (interactive ? 22 : 12) // TODO: needs to define if there will be specific graphics for // disabled scroll bars opacity: enabled ? 1.0 : 0.5 - visible: flickableItem && handle.width < contents.width + visible: flickableItem && internalLoader.handleEnabled anchors { right: flickableItem.right @@ -99,300 +98,80 @@ Item { bottom: flickableItem.bottom } - function incrementValue(increment) { - if (!flickableItem) - return; + Loader { + id: internalLoader + anchors.fill: parent + //property bool handleEnabled: internalLoader.isVertical ? item.handle.height < item.contents.height : item.handle.width < item.contents.width + property bool handleEnabled: internalLoader.isVertical ? flickableItem.contentHeight > flickableItem.height : flickableItem.contentWidth > flickableItem.width + property bool isVertical: orientation == Qt.Vertical - if (_isVertical) { - flickableItem.contentY = Math.min(flickableItem.contentHeight, - flickableItem.contentY + increment); - } else { - flickableItem.contentX = Math.min(flickableItem.contentWidth, - flickableItem.contentX + increment); - } - } + function incrementValue(increment) + { + if (!flickableItem) + return; - Keys.onUpPressed: { - if (!enabled || !_isVertical) - return; - - if (_inverted) - incrementValue(-stepSize); - else - incrementValue(stepSize); - } - - Keys.onDownPressed: { - if (!enabled || !_isVertical) - return; - - if (_inverted) - incrementValue(stepSize); - else - incrementValue(-stepSize); - } - - Keys.onLeftPressed: { - if (!enabled || _isVertical) - return; - - if (_inverted) - incrementValue(stepSize); - else - incrementValue(-stepSize); - } - - Keys.onRightPressed: { - if (!enabled || _isVertical) - return; - - if (_inverted) - incrementValue(-stepSize); - else - incrementValue(stepSize); - } - - - Item { - - width: _isVertical ? scrollbar.height : scrollbar.width - height: _isVertical ? scrollbar.width : scrollbar.height - rotation: _isVertical ? -90 : 0 - - anchors.centerIn: parent - PlasmaCore.Svg { - id: scrollbarSvg - imagePath: "widgets/scrollbar" + if (internalLoader.isVertical) { + flickableItem.contentY = Math.max(0, Math.min(flickableItem.contentHeight, + flickableItem.contentY + increment)) + } else { + flickableItem.contentX = Math.max(0, Math.min(flickableItem.contentWidth, + flickableItem.contentX + increment)) + } } - PlasmaCore.SvgItem { - id: leftButton + RangeModel { + id: range - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - height: 18 - width: _showButtons ? 18 : 0 - svg: scrollbarSvg - elementId: { - if (leftMousArea.pressed) - return "sunken-arrow-left"; + minimumValue: 0 + maximumValue: { + var diff; + if (internalLoader.isVertical) { + diff = flickableItem.contentHeight - flickableItem.height + } else { + diff = flickableItem.contentWidth - flickableItem.width + } - if (scrollbar.activeFocus || leftMousArea.containsMouse) - return "mouseover-arrow-left"; - else - return "arrow-left"; + return Math.max(0, diff) } - MouseArea { - id: leftMousArea + stepSize: 10 + inverted: scrollbar.inverted + positionAtMinimum: 0 + positionAtMaximum: { + if (internalLoader.isVertical) { + internalLoader.item.contents.height - internalLoader.item.handle.height + } else { + internalLoader.item.contents.width - internalLoader.item.handle.width + } + } + value: internalLoader.isVertical ? flickableItem.contentY : flickableItem.contentX + onValueChanged: { + if (flickableItem.moving) { + return + } - anchors.fill: parent - enabled: scrollbar.enabled - Timer { - id: leftTimer - interval: scrollbar.scrollButtonInterval; - running: parent.pressed - repeat: true - onTriggered: { - scrollbar.forceActiveFocus(); - if (_inverted) - incrementValue(stepSize); - else - incrementValue(-stepSize); - } + if (internalLoader.isVertical) { + flickableItem.contentY = value + } else { + flickableItem.contentX = value + } + } + + position: internalLoader.isVertical ? internalLoader.item.handle.y : internalLoader.item.handle.x + + onPositionChanged: { + if (internalLoader.item.mouseArea && internalLoader.item.mouseArea.pressed) { + return + } + + if (internalLoader.isVertical) { + internalLoader.item.handle.y = position + } else { + internalLoader.item.handle.x = position } } } - PlasmaCore.SvgItem { - id: rightButton - - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - height: 18 - width: _showButtons ? 18 : 0 - svg: scrollbarSvg - elementId: { - if (rightMousArea.pressed) - return "sunken-arrow-right"; - - if (scrollbar.activeFocus || rightMousArea.containsMouse) - return "mouseover-arrow-right"; - else - return "arrow-right"; - } - - MouseArea { - id: rightMousArea - - anchors.fill: parent - enabled: scrollbar.enabled - Timer { - id: rightTimer - interval: scrollbar.scrollButtonInterval; - running: parent.pressed; - repeat: true - onTriggered: { - scrollbar.forceActiveFocus(); - if (_inverted) - incrementValue(-stepSize); - else - incrementValue(stepSize); - } - } - } - } - - Item { - id: contents - - anchors { - left: leftButton.right - top: parent.top - bottom: parent.bottom - right: rightButton.left - } - - RangeModel { - id: range - - minimumValue: 0 - maximumValue: { - var diff; - if (_isVertical) - diff = flickableItem.contentHeight - flickableItem.height; - else - diff = flickableItem.contentWidth - flickableItem.width; - - return Math.max(0, diff); - } - stepSize: 10 - inverted: _inverted - positionAtMinimum: 0 + handle.width / 2 - positionAtMaximum: contents.width - handle.width / 2 - value: _isVertical ? flickableItem.contentY : flickableItem.contentX - onValueChanged: { - if (flickableItem.flicking) - return; - - if (_isVertical) - flickableItem.contentY = value; - else - flickableItem.contentX = value; - } - position: handle.x - onPositionChanged: { handle.x = position; } - } - - PlasmaCore.FrameSvgItem { - id: groove - - anchors.fill: parent - imagePath: "widgets/scrollbar" - prefix: "background-horizontal" - } - - PlasmaCore.FrameSvgItem { - id: handle - - transform: Translate { x: - handle.width / 2 } - x: fakeHandle.x - anchors.verticalCenter: groove.verticalCenter - width: { - var ratio; - if (_isVertical) - ratio = flickableItem.visibleArea.heightRatio; - else - ratio = flickableItem.visibleArea.widthRatio; - - return ratio * parent.width; - } - height: parent.height - margins.top // TODO: check mergin - imagePath: "widgets/scrollbar" - prefix: { - if (scrollbar.pressed) - return "sunken-slider"; - - if (scrollbar.activeFocus || mouseArea.containsMouse) - return "mouseover-slider"; - else - return "slider"; - } - - Behavior on x { - id: behavior - enabled: !mouseArea.drag.active && scrollbar.animated && - !flickableItem.flicking - - PropertyAnimation { - duration: behavior.enabled ? 150 : 0 - easing.type: Easing.OutSine - } - } - } - - Item { - id: fakeHandle - width: handle.width - height: handle.height - transform: Translate { x: - handle.width / 2 } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - enabled: scrollbar.enabled - drag { - target: fakeHandle - axis: Drag.XAxis - minimumX: range.positionAtMinimum - maximumX: range.positionAtMaximum - } - - onPressed: { - // Clamp the value - var newX = Math.max(mouse.x, drag.minimumX); - newX = Math.min(newX, drag.maximumX); - - // Debounce the press: a press event inside the handler will not - // change its position, the user needs to drag it. - if (Math.abs(newX - fakeHandle.x) > handle.width / 2) - range.position = newX; - - scrollbar.forceActiveFocus(); - } - onReleased: { - // If we don't update while dragging, this is the only - // moment that the range is updated. - if (!scrollbar.updateValueWhileDragging) - range.position = fakeHandle.x; - } - } - } - - // Range position normally follow fakeHandle, except when - // 'updateValueWhileDragging' is false. In this case it will only follow - // if the user is not pressing the handle. - Binding { - when: updateValueWhileDragging || !mouseArea.pressed - target: range - property: "position" - value: fakeHandle.x - } - - // During the drag, we simply ignore position set from the range, this - // means that setting a value while dragging will not "interrupt" the - // dragging activity. - Binding { - when: !mouseArea.drag.active - target: fakeHandle - property: "x" - value: range.position - } + source: interactive ? "ScrollBarDelegate.qml" : "ScrollDecoratorDelegate.qml" } } diff --git a/declarativeimports/plasmacomponents/qml/ScrollBarDelegate.qml b/declarativeimports/plasmacomponents/qml/ScrollBarDelegate.qml new file mode 100644 index 000000000..15ee7aa68 --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/ScrollBarDelegate.qml @@ -0,0 +1,251 @@ +/* +* Copyright (C) 2011 by Daker Fernandes Pinheiro +* Copyright (C) 2011 Marco Martin +* +* 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, 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 program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore + + +PlasmaCore.FrameSvgItem { + id: background + anchors.fill: parent + imagePath:"widgets/scrollbar" + prefix: internalLoader.isVertical ? "background-vertical" : "background-horizontal" + + Keys.onUpPressed: { + if (!enabled || !internalLoader.isVertical) + return; + + if (inverted) + internalLoader.incrementValue(stepSize); + else + internalLoader.incrementValue(-stepSize); + } + + Keys.onDownPressed: { + if (!enabled || !internalLoader.isVertical) + return; + + if (inverted) + internalLoader.incrementValue(-stepSize); + else + internalLoader.incrementValue(stepSize); + } + + Keys.onLeftPressed: { + if (!enabled || internalLoader.isVertical) + return; + + if (inverted) + internalLoader.incrementValue(stepSize); + else + internalLoader.incrementValue(-stepSize); + } + + Keys.onRightPressed: { + if (!enabled || internalLoader.isVertical) + return; + + if (inverted) + internalLoader.incrementValue(-stepSize); + else + internalLoader.incrementValue(stepSize); + } + + property Item handle: handle + + property Item contents: contents + Item { + id: contents + anchors { + fill: parent + leftMargin: internalLoader.isVertical || stepSize <= 0 ? 0 : leftButton.width + rightMargin: internalLoader.isVertical || stepSize <= 0 ? 0 : rightButton.width + topMargin: internalLoader.isVertical && stepSize > 0 ? leftButton.height : 0 + bottomMargin: internalLoader.isVertical && stepSize > 0 ? rightButton.height : 0 + } + + PlasmaCore.FrameSvgItem { + id: handle + imagePath:"widgets/scrollbar" + prefix: { + if (mouseArea.pressed) { + return "sunken-slider" + } + + if (scrollbar.activeFocus || mouseArea.containsMouse) { + return "mouseover-slider" + } else { + return "slider" + } + } + + property int length: internalLoader.isVertical? flickableItem.visibleArea.heightRatio * parent.height : flickableItem.visibleArea.widthRatio * parent.width + + width: internalLoader.isVertical ? parent.width : length + height: internalLoader.isVertical ? length : parent.height + } + } + + PlasmaCore.Svg { + id: scrollbarSvg + imagePath: "widgets/scrollbar" + } + + PlasmaCore.SvgItem { + id: leftButton + visible: stepSize > 0 + + anchors { + left: internalLoader.isVertical ? undefined : parent.left + verticalCenter: internalLoader.isVertical ? undefined : parent.verticalCenter + top: internalLoader.isVertical ? parent.top : undefined + horizontalCenter: internalLoader.isVertical ? parent.horizontalCenter : undefined + } + width: 18 + height: 18 + svg: scrollbarSvg + elementId: { + if (leftMouseArea.pressed) { + return internalLoader.isVertical ? "sunken-arrow-up" : "sunken-arrow-left" + } + + if (scrollbar.activeFocus || leftMouseArea.containsMouse) { + return internalLoader.isVertical ? "mouseover-arrow-up" : "mouseover-arrow-left" + } else { + return internalLoader.isVertical ? "mouseover-arrow-up" : "arrow-left" + } + } + + MouseArea { + id: leftMouseArea + + anchors.fill: parent + enabled: scrollbar.enabled + Timer { + id: leftTimer + interval: scrollbar.scrollButtonInterval; + running: parent.pressed + repeat: true + onTriggered: { + background.forceActiveFocus() + if (inverted) { + internalLoader.incrementValue(stepSize); + } else { + internalLoader.incrementValue(-stepSize); + } + } + } + } + } + + PlasmaCore.SvgItem { + id: rightButton + visible: stepSize > 0 + + anchors { + right: internalLoader.isVertical ? undefined : parent.right + verticalCenter: internalLoader.isVertical ? undefined : parent.verticalCenter + bottom: internalLoader.isVertical ? parent.bottom : undefined + horizontalCenter: internalLoader.isVertical ? parent.horizontalCenter : undefined + } + width: 18 + height: 18 + svg: scrollbarSvg + elementId: { + if (leftMouseArea.pressed) { + return internalLoader.isVertical ? "sunken-arrow-down" : "sunken-arrow-right" + } + + if (scrollbar.activeFocus || leftMouseArea.containsMouse) { + return internalLoader.isVertical ? "mouseover-arrow-down" : "mouseover-arrow-right" + } else { + return internalLoader.isVertical ? "mouseover-arrow-down" : "arrow-right" + } + } + + MouseArea { + id: rightMouseArea + + anchors.fill: parent + enabled: scrollbar.enabled + Timer { + id: rightTimer + interval: scrollbar.scrollButtonInterval; + running: parent.pressed; + repeat: true + onTriggered: { + background.forceActiveFocus(); + if (inverted) + internalLoader.incrementValue(-stepSize); + else + internalLoader.incrementValue(stepSize); + } + } + } + } + + property MouseArea mouseArea: mouseArea + MouseArea { + id: mouseArea + + anchors.fill: contents + enabled: scrollbar.enabled + hoverEnabled: true + drag { + target: handle + axis: internalLoader.isVertical ? Drag.YAxis : Drag.XAxis + minimumX: range.positionAtMinimum + maximumX: range.positionAtMaximum + minimumY: range.positionAtMinimum + maximumY: range.positionAtMaximum + } + + onPressed: { + if (internalLoader.isVertical) { + // Clamp the value + var newY = Math.max(mouse.y, drag.minimumY); + newY = Math.min(newY, drag.maximumY); + + // Debounce the press: a press event inside the handler will not + // change its position, the user needs to drag it. + if (newY > handle.y + handle.height) { + handle.y = mouse.y - handle.height + } else if (newY < handle.y) { + handle.y = mouse.y + } + } else { + // Clamp the value + var newX = Math.max(mouse.x, drag.minimumX); + newX = Math.min(newX, drag.maximumX); + + // Debounce the press: a press event inside the handler will not + // change its position, the user needs to drag it. + if (newX > handle.x + handle.width) { + handle.x = mouse.x - handle.width + } else if (newX < handle.x) { + handle.x = mouse.x + } + } + + background.forceActiveFocus(); + } + } +} + diff --git a/declarativeimports/plasmacomponents/qml/ScrollDecoratorDelegate.qml b/declarativeimports/plasmacomponents/qml/ScrollDecoratorDelegate.qml new file mode 100644 index 000000000..2e9422bb0 --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/ScrollDecoratorDelegate.qml @@ -0,0 +1,95 @@ +/* +* Copyright (C) 2011 by Daker Fernandes Pinheiro +* Copyright (C) 2011 Marco Martin +* +* 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, 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 program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore + + +PlasmaCore.FrameSvgItem { + id: background + anchors.fill: parent + imagePath:"widgets/scrollbar" + prefix: internalLoader.isVertical ? "background-vertical" : "background-horizontal" + + opacity: 0 + Behavior on opacity { + NumberAnimation { + duration: 250 + easing.type: Easing.OutQuad + } + } + + property Item handle: handle + + property Item contents: contents + Item { + id: contents + anchors.fill: parent + + PlasmaCore.FrameSvgItem { + id: handle + imagePath:"widgets/scrollbar" + prefix: "slider" + + function length() { + if (internalLoader.isVertical) { + var overshoot = 0 + if (flickableItem.atYBeginning || flickableItem.atYEnd) { + overshoot = Math.abs(flickableItem.visibleArea.yPosition * parent.height) + } + return (flickableItem.visibleArea.heightRatio * parent.height) - overshoot + } else { + var overshoot = 0 + if (flickableItem.atXBeginning || flickableItem.atXEnd) { + overshoot = Math.abs(flickableItem.visibleArea.xPosition * parent.width) + } + return (flickableItem.visibleArea.widthRatio * parent.width) - overshoot + } + } + + width: internalLoader.isVertical ? parent.width : length() + height: internalLoader.isVertical ? length() : parent.height + } + } + + property MouseArea mouseArea: null + + Connections { + target: flickableItem + onMovingChanged: { + if (flickableItem.moving) { + opacityTimer.running = false + background.opacity = 1 + } else { + opacityTimer.restart() + } + } + } + Timer { + id: opacityTimer + interval: 500 + repeat: false + running: false + onTriggered: { + background.opacity = 0 + } + } +} + diff --git a/declarativeimports/plasmacomponents/qml/SectionScroller.qml b/declarativeimports/plasmacomponents/qml/SectionScroller.qml index fda5537a9..c81b7350d 100644 --- a/declarativeimports/plasmacomponents/qml/SectionScroller.qml +++ b/declarativeimports/plasmacomponents/qml/SectionScroller.qml @@ -85,16 +85,9 @@ Item { internal.initDirtyObserver() } } - onMovementStarted: root.opacity = 1 - onMovementEnded: { - if (!dragArea.pressed) { - fadeTimer.restart() - } - } } - width: 48 - opacity: 0 + width: 22 Behavior on opacity { NumberAnimation { duration: 250 @@ -107,15 +100,6 @@ Item { bottom: listView.bottom } - Timer { - id: fadeTimer - interval: 4000 - repeat: false - running: false - onTriggered: { - root.opacity = 0 - } - } RangeModel { id: range @@ -124,99 +108,42 @@ Item { maximumValue: Math.max(0, listView.contentHeight - listView.height) stepSize: 0 //inverted: true - positionAtMinimum: handle.height / 2 - positionAtMaximum: root.height - handle.height - handle.height / 2 + positionAtMinimum: root.width*2 + positionAtMaximum: root.height - root.width*2 value: listView.contentY - onValueChanged: { - if (listView.moving) { - return - } else { - listView.contentY = value - } - } - //position: handle.y - onPositionChanged: { - if (!dragArea.pressed) { - handle.y = position - } - } + onPositionChanged: sectionLabel.text = Sections.closestSection(position/listView.height) + } - Rectangle { + ScrollBar { + id: scrollBar + flickableItem: listView anchors.fill: parent - color: Qt.rgba(0,0,0,0.3) - } - - Rectangle { - id: handle - width: 6 - height: 6 - color: theme.textColor - opacity: 0.7 - anchors.horizontalCenter: parent.horizontalCenter - border { - width: 1 - color: theme.backgroundColor - } - onYChanged: { - if (dragArea.pressed) { - range.position = y - } - sectionLabel.text = Sections.closestSection(y/listView.height) - } - Behavior on y { - NumberAnimation { - duration: 150 - } - } + interactive: true } PlasmaCore.FrameSvgItem { imagePath: "widgets/tooltip" - width: childrenRect.width + margins.left + margins.right - height: childrenRect.height + margins.top + margins.bottom + width: sectionLabel.paintedWidth + margins.left + margins.right + height: sectionLabel.paintedHeight + margins.top + margins.bottom Label { id: sectionLabel font.pointSize: theme.defaultFont.pointSize*3 x: parent.margins.left y: parent.margins.top } - y: Math.min(root.height-height, Math.max(0, handle.y - height/2)) + y: Math.min(root.height-height-scrollBar.width, Math.max(scrollBar.width, range.position - height/2)) anchors { //verticalCenter: handle.verticalCenter right: parent.left } - opacity: dragArea.pressed?1:0 + opacity: sectionLabel.text && scrollBar.pressed?1:0 Behavior on opacity { NumberAnimation { duration: 250 } } } - /*Repeater { - id: sectionsRepeater - delegate: Label { - anchors.horizontalCenter: parent.horizontalCenter - text: Sections._sections[modelData] - y: Sections._sectionData[modelData].index*(listView.height/listView.model.count) - } - }*/ - MouseArea { - id: dragArea - anchors.fill: parent - enabled: scrollbar.enabled - drag { - target: handle - axis: Drag.YAxis - minimumY: range.positionAtMinimum - maximumY: range.positionAtMaximum - } - onPressed: { - mouse.accepted = true - handle.y = mouse.y - } - onReleased: fadeTimer.restart() - } QtObject { id: internal diff --git a/declarativeimports/plasmacomponents/qml/SelectionDialog.qml b/declarativeimports/plasmacomponents/qml/SelectionDialog.qml new file mode 100644 index 000000000..8c493b76f --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/SelectionDialog.qml @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Marco Martin +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.1 + +import "." 0.1 + +CommonDialog { + id: root + + // Common API + property alias model: listView.model + property int selectedIndex: -1 + property Component delegate: defaultDelegate + + privateCloseIcon: true + + Component { + id: defaultDelegate + + Label { + //platformInverted: root.platformInverted + text: modelData + MouseArea { + anchors.fill: parent + onClicked: { + selectedIndex = index + root.accept() + } + } + + Keys.onPressed: { + if (event.key == Qt.Key_Up || event.key == Qt.Key_Down) + scrollBar.flash() + } + } + } + + content: Item { + id: contentItem + + width: theme.defaultFont.mSize.width * 40 + height: theme.defaultFont.mSize.height * 12 + + Item { + // Clipping item with bottom margin added to align content with rounded background graphics + id: clipItem + anchors.fill: parent + anchors.bottomMargin: 4 + clip: true + ListView { + id: listView + + currentIndex : -1 + width: contentItem.width + height: contentItem.height + delegate: root.delegate + clip: true + + Keys.onPressed: { + if (event.key == Qt.Key_Up || event.key == Qt.Key_Down + || event.key == Qt.Key_Left || event.key == Qt.Key_Right + || event.key == Qt.Key_Select || event.key == Qt.Key_Enter + || event.key == Qt.Key_Return) { + listView.currentIndex = 0 + event.accepted = true + } + } + } + } + ScrollBar { + id: scrollBar + flickableItem: listView + visible: listView.contentHeight > contentItem.height + //platformInverted: root.platformInverted + anchors { top: clipItem.top; right: clipItem.right } + } + } + + onClickedOutside: { + reject() + } + + onStatusChanged: { + if (status == DialogStatus.Opening) { + if (listView.currentItem != null) { + listView.currentItem.focus = false + } + listView.currentIndex = -1 + listView.positionViewAtIndex(0, ListView.Beginning) + } + else if (status == DialogStatus.Open) { + listView.focus = true + } + } +} diff --git a/declarativeimports/plasmacomponents/qml/Slider.qml b/declarativeimports/plasmacomponents/qml/Slider.qml index c51b0c561..3b535bd66 100644 --- a/declarativeimports/plasmacomponents/qml/Slider.qml +++ b/declarativeimports/plasmacomponents/qml/Slider.qml @@ -82,11 +82,11 @@ Item { property bool updateValueWhileDragging: true property real handleSize: 22 - // Convinience API + // Convenience API property bool _isVertical: orientation == Qt.Vertical - width: _isVertical ? 22 : 200 - height: _isVertical ? 200 : 22 + width: _isVertical ? theme.defaultFont.mSize.height*1.8 : 200 + height: _isVertical ? 200 : theme.defaultFont.mSize.height*1.8 // TODO: needs to define if there will be specific graphics for // disabled sliders opacity: enabled ? 1.0 : 0.5 @@ -151,8 +151,8 @@ Item { value: 0 stepSize: 0.0 inverted: false - positionAtMinimum: 0 + handle.width / 2 - positionAtMaximum: contents.width - handle.width / 2 + positionAtMinimum: 0 + positionAtMaximum: contents.width - handle.width } PlasmaCore.Svg { @@ -176,51 +176,26 @@ Item { imagePath: "widgets/slider" prefix: "groove-highlight" height: groove.height - width: inverted ? groove.width - handle.x : fakeHandle.x + width: inverted ? groove.width - handle.x : fakeHandle.x + handle.width/2 x: inverted ? handle.x : 0 anchors.verticalCenter: parent.verticalCenter visible: range.position > 0 && slider.enabled } - PlasmaCore.SvgItem { - id: focus - - transform: Translate { x: - handle.width / 2 } - anchors { - fill: handle - margins: -1 // Hardcoded - } - opacity: slider.activeFocus ? 1 : 0 - svg: PlasmaCore.Svg { imagePath: "widgets/slider" } - elementId: "horizontal-slider-hover" - - Behavior on opacity { - PropertyAnimation { duration: 250 } - } - } - - PlasmaCore.SvgItem { - id: hover - - transform: Translate { x: - handle.width / 2 } - anchors { - fill: handle - margins: -2 // Hardcoded - } - opacity: 0 - svg: PlasmaCore.Svg { imagePath: "widgets/slider" } - elementId: "horizontal-slider-hover" - - Behavior on opacity { - PropertyAnimation { duration: 250 } - } + RoundShadow { + id: shadow + imagePath: "widgets/slider" + focusElement: "horizontal-slider-focus" + hoverElement: "horizontal-slider-hover" + shadowElement: "horizontal-slider-shadow" + state: slider.activeFocus ? "focus" : (mouseArea.containsMouse ? "hover" : "shadow") + anchors.fill: handle } PlasmaCore.SvgItem { id: handle - transform: Translate { x: - handle.width / 2 } x: fakeHandle.x anchors { verticalCenter: groove.verticalCenter @@ -245,7 +220,6 @@ Item { id: fakeHandle width: handle.width height: handle.height - transform: Translate { x: - handle.width / 2 } } MouseArea { @@ -261,33 +235,25 @@ Item { } hoverEnabled: true - onEntered: { - hover.opacity = 1; - } - onExited: { - if (!pressed) - hover.opacity = 0; - } onPressed: { // Clamp the value - var newX = Math.max(mouse.x, drag.minimumX); - newX = Math.min(newX, drag.maximumX); + var newX = Math.max(mouse.x, drag.minimumX) + newX = Math.min(newX, drag.maximumX) // Debounce the press: a press event inside the handler will not // change its position, the user needs to drag it. - if (Math.abs(newX - fakeHandle.x) > handle.width / 2) - range.position = newX; + if (Math.abs(newX - fakeHandle.x) > handle.width / 2) { + range.position = newX + } - slider.forceActiveFocus(); + slider.forceActiveFocus() } onReleased: { // If we don't update while dragging, this is the only // moment that the range is updated. - if (!slider.updateValueWhileDragging) - range.position = fakeHandle.x; - - if (!containsMouse) - hover.opacity = 0; + if (!slider.updateValueWhileDragging) { + range.position = fakeHandle.x + } } } } diff --git a/declarativeimports/plasmacomponents/qml/Switch.qml b/declarativeimports/plasmacomponents/qml/Switch.qml index ecb7f4078..60bf28599 100644 --- a/declarativeimports/plasmacomponents/qml/Switch.qml +++ b/declarativeimports/plasmacomponents/qml/Switch.qml @@ -40,13 +40,7 @@ DualStateButton { imagePath: "widgets/slider" prefix: "groove" width: height * 2 - height: fontMetricText.height + margins.top - //FIXME: an hack to have font metrics: can we have a proper binding? - Text { - id: fontMetricText - text: "M" - visible: false - } + height: theme.defaultFont.mSize.height + margins.top PlasmaCore.FrameSvgItem { id: highlight diff --git a/declarativeimports/plasmacomponents/qml/TabBar.qml b/declarativeimports/plasmacomponents/qml/TabBar.qml index be3f07305..66ac34ac7 100644 --- a/declarativeimports/plasmacomponents/qml/TabBar.qml +++ b/declarativeimports/plasmacomponents/qml/TabBar.qml @@ -69,9 +69,9 @@ Item { property alias layout: tabBarLayout //Plasma extension - property Item currentItem + property Item currentTab - implicitWidth: tabBarLayout.implicitWidth + backgroundFrame.margins.left + backgroundFrame.margins.right + buttonFrame.margins.left + buttonFrame.margins.right + implicitWidth: tabBarLayout.implicitWidth + backgroundFrame.margins.left + backgroundFrame.margins.right + (buttonFrame.margins.left + buttonFrame.margins.right)*tabBarLayout.children.length implicitHeight: tabBarLayout.implicitHeight + backgroundFrame.margins.top + backgroundFrame.margins.bottom + buttonFrame.margins.top + buttonFrame.margins.bottom PlasmaCore.FrameSvgItem { @@ -85,10 +85,10 @@ Item { PlasmaCore.FrameSvgItem { id: buttonFrame - x: currentItem.x + backgroundFrame.margins.left + x: currentTab.x + backgroundFrame.margins.left y: backgroundFrame.margins.top - width: currentItem.width + buttonFrame.margins.left + buttonFrame.margins.right - height: currentItem.height + buttonFrame.margins.top + buttonFrame.margins.bottom + width: currentTab.width + buttonFrame.margins.left + buttonFrame.margins.right + height: currentTab.height + buttonFrame.margins.top + buttonFrame.margins.bottom imagePath: "widgets/button" prefix: "normal" Behavior on x { diff --git a/declarativeimports/plasmacomponents/qml/TabBarLayout.qml b/declarativeimports/plasmacomponents/qml/TabBarLayout.qml index 1985d9a75..f3aa2951f 100644 --- a/declarativeimports/plasmacomponents/qml/TabBarLayout.qml +++ b/declarativeimports/plasmacomponents/qml/TabBarLayout.qml @@ -67,15 +67,18 @@ Item { Keys.onPressed: { if (event.key == Qt.Key_Right || event.key == Qt.Key_Left) { if (event.key == Qt.Key_Right || priv.mirrored) { - var oldIndex = priv.currentButtonIndex() + var oldIndex = priv.currentButtonIndex(); + if (oldIndex != root.children.length - 1) { priv.tabGroup.currentTab = root.children[oldIndex + 1].tab + root.parent.currentTab = root.children[oldIndex + 1] event.accepted = true } } else if (event.key == Qt.Key_Left || priv.mirrored) { var oldIndex = priv.currentButtonIndex() if (oldIndex != 0) { priv.tabGroup.currentTab = root.children[oldIndex - 1].tab + root.parent.currentTab = root.children[oldIndex - 1] event.accepted = true } } @@ -88,7 +91,7 @@ Item { id: priv property Item firstButton: root.children.length > 0 ? root.children[0] : null property Item firstTab: firstButton ? (firstButton.tab != null ? firstButton.tab : null) : null - property Item tabGroup: firstTab ? (firstTab.parent ? firstTab.parent.parent : null) : null + property Item tabGroup: firstTab ? (firstTab.parent ? firstTab.parent.parent.parent : null) : null property bool mirrored: root.LayoutMirroring.enabled onMirroredChanged: layoutChildren() @@ -106,19 +109,19 @@ Item { var contentWidth = 0 var contentHeight = 0 if (childCount != 0) { - var itemWidth = root.width / childCount + var itemWidth = (root.width - (childCount-1)*10) / childCount var itemIndex = mirrored ? childCount - 1 : 0 var increment = mirrored ? - 1 : 1 for (var i = 0; i < childCount; ++i, itemIndex += increment) { var child = root.children[itemIndex] - child.x = i * itemWidth + child.x = i * itemWidth + i*10 child.y = 0 child.width = itemWidth child.height = root.height if (child.implicitWidth != undefined) { - contentWidth = Math.max(contentWidth, (child.implicitWidth + buttonFrame.margins.left*2 + buttonFrame.margins.right*2) * childCount) + contentWidth = Math.max(contentWidth + i*10, (child.implicitWidth + buttonFrame.margins.left*2 + buttonFrame.margins.right*2) * childCount) contentHeight = Math.max(contentHeight, (child.implicitHeight + buttonFrame.margins.top + buttonFrame.margins.bottom)) } } diff --git a/declarativeimports/plasmacomponents/qml/TabButton.qml b/declarativeimports/plasmacomponents/qml/TabButton.qml index c0dbb2f44..ff7ab8671 100644 --- a/declarativeimports/plasmacomponents/qml/TabButton.qml +++ b/declarativeimports/plasmacomponents/qml/TabButton.qml @@ -94,7 +94,7 @@ Item { target: root onPressedChanged: { //TabBar is the granparent - root.parent.parent.currentItem = root + root.parent.parent.currentTab = root } } @@ -113,7 +113,7 @@ Item { Component.onCompleted: { if (internal.tabGroup.currentTab == tab) { - parent.parent.currentItem = root + parent.parent.currentTab = root } } } @@ -157,7 +157,7 @@ Item { internal.tabGroup.currentTab = tab } //TabBar is the granparent, done here too in case of no tabgroup - root.parent.parent.currentItem = root + root.parent.parent.currentTab = root } anchors.fill: parent diff --git a/declarativeimports/plasmacomponents/qml/TextArea.qml b/declarativeimports/plasmacomponents/qml/TextArea.qml index 4439889ed..c5de1e2aa 100644 --- a/declarativeimports/plasmacomponents/qml/TextArea.qml +++ b/declarativeimports/plasmacomponents/qml/TextArea.qml @@ -165,7 +165,6 @@ Item { property alias interactive: flickArea.interactive property alias contentMaxWidth: textEdit.width property alias contentMaxHeight: textEdit.height - property real scrollWidth: 22 // Set active focus to it's internal textInput. // Overriding QtQuick.Item forceActiveFocus function. @@ -178,32 +177,12 @@ Item { opacity: enabled ? 1.0 : 0.5 - PlasmaCore.FrameSvgItem { + TextFieldFocus { id: hover - - anchors { - fill: base - leftMargin: -margins.left - topMargin: -margins.top - rightMargin: -margins.right - bottomMargin: -margins.bottom - } - imagePath: "widgets/lineedit" - prefix: { - if (textEdit.activeFocus) - return "focus"; - else - return "hover"; - } - - opacity: (mouseWatcher.containsMouse||textArea.activeFocus) ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: 250 - easing.type: Easing.InOutQuad - } - } + state: textArea.activeFocus ? "focus" : (mouseWatcher.containsMouse ? "hover" : "hidden") + anchors.fill: base } + MouseArea { id: mouseWatcher anchors.fill: hover @@ -215,11 +194,7 @@ Item { // TODO: see what is the best policy for margins anchors { - fill: flickArea - leftMargin: -2 * base.margins.left - rightMargin: -2 * base.margins.right - topMargin: -2 * base.margins.top - bottomMargin: -2 * base.margins.bottom + fill: parent } imagePath: "widgets/lineedit" prefix: "base" @@ -229,10 +204,12 @@ Item { id: flickArea anchors { fill: parent - rightMargin: scrollWidth - bottomMargin: scrollWidth + leftMargin: 2 * base.margins.left + rightMargin: 2 * base.margins.right + (verticalScroll.visible ? verticalScroll.width : 0) + topMargin: 2 * base.margins.top + bottomMargin: 2 * base.margins.bottom + (horizontalScroll.visible ? verticalScroll.width : 0) } - interactive: false //textArea.activeFocus + interactive: !verticalScroll.interactive //textArea.activeFocus contentWidth: { if (textEdit.wrapMode == TextEdit.NoWrap) return textEdit.paintedWidth; @@ -260,6 +237,7 @@ Item { font.weight: theme.defaultFont.weight font.wordSpacing: theme.defaultFont.wordSpacing color: theme.viewTextColor + selectByMouse: verticalScroll.interactive onCursorPositionChanged: { if (cursorRectangle.x < flickArea.contentX) { @@ -310,7 +288,6 @@ Item { } enabled: parent.enabled flickableItem: flickArea - height: visible ? scrollWidth : 0 orientation: Qt.Horizontal stepSize: textEdit.font.pixelSize } @@ -324,7 +301,6 @@ Item { } enabled: parent.enabled flickableItem: flickArea - width: visible ? scrollWidth : 0 orientation: Qt.Vertical stepSize: textEdit.font.pixelSize } diff --git a/declarativeimports/plasmacomponents/qml/TextField.qml b/declarativeimports/plasmacomponents/qml/TextField.qml index 9b71157c4..d092c4486 100644 --- a/declarativeimports/plasmacomponents/qml/TextField.qml +++ b/declarativeimports/plasmacomponents/qml/TextField.qml @@ -119,6 +119,9 @@ Item { property alias text: textInput.text property alias maximumLength: textInput.maximumLength + //Plasma api + property bool clearButtonShown: false + function copy() { textInput.copy(); } @@ -162,12 +165,18 @@ Item { property alias activeFocus: textInput.activeFocus // TODO: fix default size - implicitWidth: 100 - implicitHeight: 26 + implicitWidth: theme.defaultFont.mSize.width*12 + implicitHeight: theme.defaultFont.mSize.height*1.8 // TODO: needs to define if there will be specific graphics for // disabled text fields opacity: enabled ? 1.0 : 0.5 + TextFieldFocus { + id: hover + state: textInput.activeFocus ? "focus" : (mouseWatcher.containsMouse ? "hover" : "hidden") + anchors.fill: base + } + PlasmaCore.FrameSvgItem { id: base @@ -177,32 +186,6 @@ Item { prefix: "base" } - PlasmaCore.FrameSvgItem { - id: hover - - anchors { - fill: parent - leftMargin: -margins.left - topMargin: -margins.top - rightMargin: -margins.right - bottomMargin: -margins.bottom - } - imagePath: "widgets/lineedit" - prefix: { - if (textField.activeFocus) { - return "focus" - } else { - return "hover" - } - } - opacity: (mouseWatcher.containsMouse||textField.activeFocus) ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: 250 - easing.type: Easing.InOutQuad - } - } - } MouseArea { id: mouseWatcher anchors.fill: hover @@ -210,7 +193,13 @@ Item { } Text { - anchors.fill: textInput + anchors { + left: parent.left + right: parent.right + verticalCenter: parent.verticalCenter + leftMargin: 2 * base.margins.left + rightMargin: 2 * base.margins.right + } text: placeholderText visible: textInput.text == "" && !textField.activeFocus // XXX: using textColor and low opacity for theming placeholderText @@ -235,12 +224,12 @@ Item { anchors { left: parent.left right: parent.right + verticalCenter: parent.verticalCenter // TODO: see what is the correct policy for margins leftMargin: 2 * base.margins.left rightMargin: 2 * base.margins.right } - y: (height - font.pixelSize) * 0.4 // XXX: verticalCenter anchor is not centering the text - height: Math.min(2 * font.pixelSize, parent.height) + selectByMouse: true color: theme.textColor enabled: textField.enabled clip: true @@ -250,4 +239,30 @@ Item { Keys.onPressed: textField.Keys.pressed(event); Keys.onReleased: textField.Keys.released(event); } + + PlasmaCore.SvgItem { + svg: PlasmaCore.Svg {imagePath: "widgets/lineedit"} + elementId: "clearbutton" + width: textInput.height + height: textInput.height + opacity: (textInput.text != "" && clearButtonShown) ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: 250 + easing.type: Easing.InOutQuad + } + } + anchors { + right: parent.right + rightMargin: y + verticalCenter: textInput.verticalCenter + } + MouseArea { + anchors.fill: parent + onClicked: { + textInput.text = "" + textInput.forceActiveFocus() + } + } + } } \ No newline at end of file diff --git a/declarativeimports/plasmacomponents/qml/TextFieldFocus.qml b/declarativeimports/plasmacomponents/qml/TextFieldFocus.qml new file mode 100644 index 000000000..3bc24ffcc --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/TextFieldFocus.qml @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2011 by Daker Fernandes Pinheiro + * Copyright (C) 2011 by Marco Martin + * + * 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, 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. + */ + +import QtQuick 1.0 +import org.kde.plasma.core 0.1 as PlasmaCore + +Item { + id: main + state: parent.state + + PlasmaCore.Svg { + id: lineEditSvg + imagePath: "widgets/lineedit" + onRepaintNeeded: { + if (lineEditSvg.hasElement("hint-focus-over-base")) { + main.z = 800 + } else { + main.z = 0 + } + } + Component.onCompleted: { + if (lineEditSvg.hasElement("hint-focus-over-base")) { + main.z = 800 + } else { + main.z = 0 + } + } + } + + PlasmaCore.FrameSvgItem { + id: hover + + anchors { + fill: parent + leftMargin: -margins.left + topMargin: -margins.top + rightMargin: -margins.right + bottomMargin: -margins.bottom + } + opacity: 0 + imagePath: "widgets/lineedit" + prefix: "hover" + } + + states: [ + State { + name: "hover" + PropertyChanges { + target: hover + opacity: 1 + prefix: "hover" + } + }, + State { + name: "focus" + PropertyChanges { + target: hover + opacity: 1 + prefix: "focus" + } + }, + State { + name: "hidden" + PropertyChanges { + target: hover + opacity: 0 + prefix: "hover" + } + } + ] + + transitions: [ + Transition { + PropertyAnimation { + properties: "opacity" + duration: 250 + easing.type: Easing.OutQuad + } + } + ] +} diff --git a/declarativeimports/plasmacomponents/qml/ToolBar.qml b/declarativeimports/plasmacomponents/qml/ToolBar.qml index ea4729bb9..c3600d6b7 100644 --- a/declarativeimports/plasmacomponents/qml/ToolBar.qml +++ b/declarativeimports/plasmacomponents/qml/ToolBar.qml @@ -44,12 +44,18 @@ Properties: import QtQuick 1.1 import org.kde.plasma.core 0.1 as PlasmaCore -PlasmaCore.FrameSvgItem { +Item{ id: toolBar - imagePath: "widgets/frame" - prefix: "raised" width: parent.width - height: 48 + margins.top + margins.bottom + height: (tools && enabled) ? theme.defaultFont.mSize.height*2 + frameSvg.margins.top + frameSvg.margins.bottom : 0 + visible: height > 0 + Behavior on height { + PropertyAnimation { + id: heightAnimation + duration: 250 + } + } + z: 1000 // The current set of tools; null if none. property Item tools @@ -71,75 +77,97 @@ PlasmaCore.FrameSvgItem { toolBar.transition = transition toolBar.tools = tools } - onToolsChanged: { - var newContainer - var oldContainer - if (containerA.current) { - newContainer = containerB - oldContainer = containerA - } else { - newContainer = containerA - oldContainer = containerB + Connections { + id: connection + target: toolBar + function internalToolsChanged() + { + var newContainer + var oldContainer + if (containerA.current) { + newContainer = containerB + oldContainer = containerA + } else { + newContainer = containerA + oldContainer = containerB + } + containerA.current = !containerA.current + + tools.parent = newContainer + tools.visible = true + tools.anchors.left = newContainer.left + tools.anchors.right = newContainer.right + tools.anchors.verticalCenter = newContainer.verticalCenter + + switch (transition) { + case "push": + containerA.animationsEnabled = true + oldContainer.x = -oldContainer.width/2 + + containerA.animationsEnabled = false + newContainer.x = newContainer.width/2 + newContainer.y = 0 + containerA.animationsEnabled = true + newContainer.x = 0 + break + case "pop": + containerA.animationsEnabled = true + oldContainer.x = oldContainer.width/2 + + containerA.animationsEnabled = false + newContainer.x = -newContainer.width/2 + newContainer.y = 0 + containerA.animationsEnabled = true + newContainer.x = 0 + break + case "replace": + containerA.animationsEnabled = true + oldContainer.y = oldContainer.height + + containerA.animationsEnabled = false + newContainer.x = 0 + newContainer.y = -newContainer.height + containerA.animationsEnabled = true + newContainer.y = 0 + break + case "set": + default: + containerA.animationsEnabled = false + containerA.animationsEnabled = false + oldContainer.x = -oldContainer.width/2 + newContainer.x = 0 + break + } + + newContainer.opacity = 1 + oldContainer.opacity = 0 } - containerA.current = !containerA.current + onToolsChanged: connection.internalToolsChanged() + Component.onCompleted: connection.internalToolsChanged() + } - tools.parent = newContainer - tools.visible = true - tools.anchors.left = newContainer.left - tools.anchors.right = newContainer.right - tools.anchors.verticalCenter = newContainer.verticalCenter - - switch (transition) { - case "push": - containerA.animationsEnabled = true - oldContainer.x = -oldContainer.width - - containerA.animationsEnabled = false - newContainer.x = newContainer.width - newContainer.y = 0 - containerA.animationsEnabled = true - newContainer.x = 0 - break - case "pop": - containerA.animationsEnabled = true - oldContainer.x = oldContainer.width - - containerA.animationsEnabled = false - newContainer.x = -newContainer.width - newContainer.y = 0 - containerA.animationsEnabled = true - newContainer.x = 0 - break - case "replace": - containerA.animationsEnabled = true - oldContainer.y = oldContainer.height - - containerA.animationsEnabled = false - newContainer.x = 0 - newContainer.y = -newContainer.height - containerA.animationsEnabled = true - newContainer.y = 0 - break - case "set": - default: - containerA.animationsEnabled = false - containerA.animationsEnabled = false - oldContainer.x = -oldContainer.width - newContainer.x = 0 - break + PlasmaCore.FrameSvgItem { + id: frameSvg + imagePath: "widgets/frame" + prefix: "raised" + anchors { + fill: parent + leftMargin: -margins.left + rightMargin: -margins.right + //FIXME: difference between actial border and shadow + topMargin: toolBar.y <= 0 ? -margins.top : -margins.top/2 + bottomMargin: toolBar.y >= toolBar.parent.height - toolBar.height ? -margins.bottom : -margins.bottom/2 } - - newContainer.opacity = 1 - oldContainer.opacity = 0 } Item { + clip: containerAOpacityAnimation.running || heightAnimation.running anchors { fill: parent - leftMargin: parent.margins.left - topMargin: parent.margins.top - rightMargin: parent.margins.right - bottomMargin: parent.margins.bottom + leftMargin: frameSvg.margins.left/2 + topMargin: frameSvg.margins.top/2 + rightMargin: frameSvg.margins.right/2 + bottomMargin: frameSvg.margins.bottom/2 } Item { @@ -151,7 +179,10 @@ PlasmaCore.FrameSvgItem { //this asymmetry just to not export a property property bool current: false Behavior on opacity { - PropertyAnimation { duration: 250 } + PropertyAnimation { + id: containerAOpacityAnimation + duration: 250 + } } Behavior on x { enabled: containerA.animationsEnabled diff --git a/declarativeimports/plasmacomponents/qml/ToolBarLayout.qml b/declarativeimports/plasmacomponents/qml/ToolBarLayout.qml new file mode 100644 index 000000000..47bf2e9f2 --- /dev/null +++ b/declarativeimports/plasmacomponents/qml/ToolBarLayout.qml @@ -0,0 +1,66 @@ +/* +* Copyright (C) 2011 by Marco Martin +* +* 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, 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. +*/ + + +// ToolBarLayout is a container for items on a toolbar that automatically +// implements an appropriate layout for its children. + +import QtQuick 1.1 +import "." 0.1 + + +Row { + id: root + + visible: false + + Item { + id: spacer + width: 10 + height: 10 + } + + QtObject { + id: internal + property bool layouting: false + function layoutChildren() + { + var numChildren = root.children.length + if (layouting || parent == null || + root.width == 0 || numChildren < 2) { + return + } + + layouting = true + spacer.parent = null + + spacer.width = root.parent.width - root.childrenRect.width -10 + + var last = root.children[numChildren-2] + last.parent = null + spacer.parent = root + last.parent = root + layouting = false + } + } + + Component.onCompleted: internal.layoutChildren() + onChildrenChanged: internal.layoutChildren() + onWidthChanged: internal.layoutChildren() +} diff --git a/declarativeimports/plasmacomponents/qml/ToolButton.qml b/declarativeimports/plasmacomponents/qml/ToolButton.qml index 10bf8bfd5..7e02255c7 100644 --- a/declarativeimports/plasmacomponents/qml/ToolButton.qml +++ b/declarativeimports/plasmacomponents/qml/ToolButton.qml @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 by Daker Fernandes Pinheiro +* Copyright (C) 2011 by Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as @@ -76,41 +77,26 @@ Item { surface.opacity = 1 } - function pressButton() { - if (button.enabled) - surface.prefix = "pressed"; + + implicitWidth: { + if (label.paintedWidth == 0) { + return implicitHeight + } else { + return Math.max(theme.defaultFont.mSize.width*12, icon.width + label.paintedWidth + surface.margins.left + surface.margins.right) + ((icon.valid) ? surface.margins.left : 0) + } } - - function releaseButton() { - if (!button.enabled) - return; - - if (button.checkable) - button.checked = !button.checked; - - // TODO: "checked" state must have special graphics? - if (button.checked) - surface.prefix = "pressed"; - else - surface.prefix = "normal"; - - button.clicked(); - button.forceActiveFocus(); - } - - implicitWidth: Math.max(50, icon.width + label.paintedWidth + surface.margins.left + surface.margins.right) - implicitHeight: Math.max(20, Math.max(icon.height, label.paintedHeight) + surface.margins.top + surface.margins.bottom) + implicitHeight: Math.max(theme.defaultFont.mSize.height*1.8, Math.max(icon.height, label.paintedHeight) + surface.margins.top + surface.margins.bottom) // TODO: needs to define if there will be specific graphics for // disabled buttons opacity: enabled ? 1.0 : 0.5 - Keys.onSpacePressed: pressButton(); - Keys.onReturnPressed: pressButton(); + Keys.onSpacePressed: internal.pressButton() + Keys.onReturnPressed: internal.pressButton() Keys.onReleased: { if (event.key == Qt.Key_Space || event.key == Qt.Key_Return) - releaseButton(); + internal.releaseButton() } onActiveFocusChanged: { @@ -123,6 +109,31 @@ Item { } } + QtObject { + id: internal + property bool userPressed: false + + function pressButton() + { + userPressed = true + } + + function releaseButton() + { + userPressed = false + if (!button.enabled) { + return + } + + if (button.checkable) { + button.checked = !button.checked + } + + button.clicked() + button.forceActiveFocus() + } + } + ButtonShadow { id: shadow anchors.fill: parent @@ -134,8 +145,9 @@ Item { anchors.fill: parent imagePath: "widgets/button" - prefix: "normal" - opacity: 0 + prefix: (internal.userPressed || checked) ? "pressed" : "normal" + //internal: if there is no hover status, don't paint on mouse over in touchscreens + opacity: (internal.userPressed || checked || !flat || (shadow.hasOverState && mouse.containsMouse)) ? 1 : 0 Behavior on opacity { PropertyAnimation { duration: 250 } } @@ -179,7 +191,7 @@ Item { font.weight: theme.defaultFont.weight font.wordSpacing: theme.defaultFont.wordSpacing color: theme.buttonTextColor - horizontalAlignment: Text.AlignHCenter + horizontalAlignment: icon.valid ? Text.AlignLeft : Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } @@ -190,23 +202,17 @@ Item { anchors.fill: parent hoverEnabled: true - onPressed: { - pressButton(); - } - onReleased: { - releaseButton(); - } + onPressed: internal.pressButton(); + + onReleased: internal.releaseButton(); + onEntered: { - if (flat) { - surface.opacity = 1 - } else { + if (!flat) { shadow.state = "hover" } } onExited: { - if (flat) { - surface.opacity = 0 - } else { + if (!flat) { if (button.activeFocus) { shadow.state = "focus" } else if (checked) { diff --git a/declarativeimports/plasmacomponents/qml/qmldir b/declarativeimports/plasmacomponents/qml/qmldir index 6ac3c235b..33220fa2e 100644 --- a/declarativeimports/plasmacomponents/qml/qmldir +++ b/declarativeimports/plasmacomponents/qml/qmldir @@ -15,19 +15,20 @@ ProgressBar 0.1 ProgressBar.qml PushButton 0.1 PushButton.qml RadioButton 0.1 RadioButton.qml ScrollBar 0.1 ScrollBar.qml -ScrollDecorator 0.1 ScrollDecorator.qml Slider 0.1 Slider.qml Switch 0.1 Switch.qml TextArea 0.1 TextArea.qml TextField 0.1 TextField.qml ToolBar 0.1 ToolBar.qml ToolButton 0.1 ToolButton.qml -ListItem 0.1 ToolButton.qml +ListItem 0.1 ListItem.qml + +CommonDialog 0.1 CommonDialog.qml +SelectionDialog 0.1 SelectionDialog.qml +ToolBarLayout 0.1 ToolBarLayout.qml Page 0.1 Page.qml PageStack 0.1 PageStack.qml -Window 0.1 Window.qml - TabBar 0.1 TabBar.qml TabButton 0.1 TabButton.qml diff --git a/declarativeimports/qtextracomponents/CMakeLists.txt b/declarativeimports/qtextracomponents/CMakeLists.txt index 3264ae8e2..a78644ff2 100644 --- a/declarativeimports/qtextracomponents/CMakeLists.txt +++ b/declarativeimports/qtextracomponents/CMakeLists.txt @@ -19,7 +19,7 @@ qt4_automoc(${qtextracomponents_SRCS}) add_library(qtextracomponentsplugin SHARED ${qtextracomponents_SRCS}) -target_link_libraries(qtextracomponentsplugin ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY}) +target_link_libraries(qtextracomponentsplugin ${KDE4_KDEUI_LIBS} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY}) install(TARGETS qtextracomponentsplugin DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/qtextracomponents) diff --git a/declarativeimports/qtextracomponents/qiconitem.cpp b/declarativeimports/qtextracomponents/qiconitem.cpp index d72381e47..378a0eac7 100644 --- a/declarativeimports/qtextracomponents/qiconitem.cpp +++ b/declarativeimports/qtextracomponents/qiconitem.cpp @@ -19,6 +19,7 @@ #include "qiconitem.h" +#include #include @@ -34,9 +35,14 @@ QIconItem::~QIconItem() { } -void QIconItem::setIcon(const QIcon &icon) +void QIconItem::setIcon(const QVariant &icon) { - m_icon = icon; + if(icon.canConvert()) { + m_icon = icon.value(); + } + else if(icon.canConvert()) { + m_icon = KIcon(icon.toString()); + } update(); } diff --git a/declarativeimports/qtextracomponents/qiconitem.h b/declarativeimports/qtextracomponents/qiconitem.h index 9972a98fe..fa89057e8 100644 --- a/declarativeimports/qtextracomponents/qiconitem.h +++ b/declarativeimports/qtextracomponents/qiconitem.h @@ -21,19 +21,20 @@ #include #include +#include class QIconItem : public QDeclarativeItem { Q_OBJECT - Q_PROPERTY(QIcon icon READ icon WRITE setIcon) + Q_PROPERTY(QVariant icon READ icon WRITE setIcon) Q_PROPERTY(bool smooth READ smooth WRITE setSmooth) public: QIconItem(QDeclarativeItem *parent=0); ~QIconItem(); - void setIcon(const QIcon &icon); + void setIcon(const QVariant &icon); QIcon icon() const; void setSmooth(const bool smooth); diff --git a/declarativeimports/qtextracomponents/qimageitem.cpp b/declarativeimports/qtextracomponents/qimageitem.cpp index 086449d19..97eaec4c8 100644 --- a/declarativeimports/qtextracomponents/qimageitem.cpp +++ b/declarativeimports/qtextracomponents/qimageitem.cpp @@ -24,7 +24,8 @@ QImageItem::QImageItem(QDeclarativeItem *parent) : QDeclarativeItem(parent), - m_smooth(false) + m_smooth(false), + m_fillMode(QImageItem::Stretch) { setFlag(QGraphicsItem::ItemHasNoContents, false); } @@ -71,6 +72,22 @@ int QImageItem::nativeHeight() const return m_image.size().height(); } +QImageItem::FillMode QImageItem::fillMode() const +{ + return m_fillMode; +} + +void QImageItem::setFillMode(QImageItem::FillMode mode) +{ + if (mode == m_fillMode) { + return; + } + + m_fillMode = mode; + update(); + emit fillModeChanged(); +} + void QImageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); @@ -79,15 +96,51 @@ void QImageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option if (m_image.isNull()) { return; } - //do without painter save, faster and the support can be compiled out - const bool wasAntiAlias = painter->testRenderHint(QPainter::Antialiasing); - const bool wasSmoothTransform = painter->testRenderHint(QPainter::SmoothPixmapTransform); + painter->save(); painter->setRenderHint(QPainter::Antialiasing, m_smooth); painter->setRenderHint(QPainter::SmoothPixmapTransform, m_smooth); - painter->drawImage(boundingRect(), m_image, m_image.rect()); - painter->setRenderHint(QPainter::Antialiasing, wasAntiAlias); - painter->setRenderHint(QPainter::SmoothPixmapTransform, wasSmoothTransform); + QRect destRect; + switch (m_fillMode) { + case PreserveAspectFit: { + QSize scaled = m_image.size(); + + scaled.scale(boundingRect().size().toSize(), Qt::KeepAspectRatio); + destRect = QRect(QPoint(0, 0), scaled); + break; + } + case PreserveAspectCrop: { + painter->setClipRect(boundingRect(), Qt::IntersectClip); + QSize scaled = m_image.size(); + scaled.scale(boundingRect().size().toSize(), Qt::KeepAspectRatioByExpanding); + destRect = QRect(QPoint(0, 0), scaled); + break; + } + case TileVertically: { + painter->scale(width()/(qreal)m_image.width(), 1); + destRect = boundingRect().toRect(); + destRect.setWidth(destRect.width() / (width()/(qreal)m_image.width())); + break; + } + case TileHorizontally: { + painter->scale(1, height()/(qreal)m_image.height()); + destRect = boundingRect().toRect(); + destRect.setHeight(destRect.height() / (height()/(qreal)m_image.height())); + break; + } + case Stretch: + case Tile: + default: + destRect = boundingRect().toRect(); + } + + if (m_fillMode >= Tile) { + painter->drawTiledPixmap(destRect, QPixmap::fromImage(m_image)); + } else { + painter->drawImage(destRect, m_image, m_image.rect()); + } + + painter->restore(); } diff --git a/declarativeimports/qtextracomponents/qimageitem.h b/declarativeimports/qtextracomponents/qimageitem.h index a4365b5dc..0c358ec71 100644 --- a/declarativeimports/qtextracomponents/qimageitem.h +++ b/declarativeimports/qtextracomponents/qimageitem.h @@ -30,8 +30,19 @@ class QImageItem : public QDeclarativeItem Q_PROPERTY(bool smooth READ smooth WRITE setSmooth) Q_PROPERTY(int nativeWidth READ nativeWidth NOTIFY nativeWidthChanged) Q_PROPERTY(int nativeHeight READ nativeHeight NOTIFY nativeHeightChanged) + Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) + Q_ENUMS(FillMode) public: + enum FillMode { + Stretch, // the image is scaled to fit + PreserveAspectFit, // the image is scaled uniformly to fit without cropping + PreserveAspectCrop, // the image is scaled uniformly to fill, cropping if necessary + Tile, // the image is duplicated horizontally and vertically + TileVertically, // the image is stretched horizontally and tiled vertically + TileHorizontally //the image is stretched vertically and tiled horizontally + }; + QImageItem(QDeclarativeItem *parent=0); ~QImageItem(); @@ -44,15 +55,20 @@ public: int nativeWidth() const; int nativeHeight() const; + FillMode fillMode() const; + void setFillMode(FillMode mode); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); Q_SIGNALS: void nativeWidthChanged(); void nativeHeightChanged(); + void fillModeChanged(); private: QImage m_image; bool m_smooth; + FillMode m_fillMode; }; #endif diff --git a/declarativeimports/qtextracomponents/qpixmapitem.cpp b/declarativeimports/qtextracomponents/qpixmapitem.cpp index 3c09efec1..690ed0f00 100644 --- a/declarativeimports/qtextracomponents/qpixmapitem.cpp +++ b/declarativeimports/qtextracomponents/qpixmapitem.cpp @@ -24,7 +24,8 @@ QPixmapItem::QPixmapItem(QDeclarativeItem *parent) : QDeclarativeItem(parent), - m_smooth(false) + m_smooth(false), + m_fillMode(QPixmapItem::Stretch) { setFlag(QGraphicsItem::ItemHasNoContents, false); } @@ -71,6 +72,22 @@ int QPixmapItem::nativeHeight() const return m_pixmap.size().height(); } +QPixmapItem::FillMode QPixmapItem::fillMode() const +{ + return m_fillMode; +} + +void QPixmapItem::setFillMode(QPixmapItem::FillMode mode) +{ + if (mode == m_fillMode) { + return; + } + + m_fillMode = mode; + update(); + emit fillModeChanged(); +} + void QPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); @@ -79,15 +96,51 @@ void QPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio if (m_pixmap.isNull()) { return; } - //do without painter save, faster and the support can be compiled out - const bool wasAntiAlias = painter->testRenderHint(QPainter::Antialiasing); - const bool wasSmoothTransform = painter->testRenderHint(QPainter::SmoothPixmapTransform); + painter->save(); painter->setRenderHint(QPainter::Antialiasing, m_smooth); painter->setRenderHint(QPainter::SmoothPixmapTransform, m_smooth); - painter->drawPixmap(boundingRect(), m_pixmap, m_pixmap.rect()); - painter->setRenderHint(QPainter::Antialiasing, wasAntiAlias); - painter->setRenderHint(QPainter::SmoothPixmapTransform, wasSmoothTransform); + QRect destRect; + switch (m_fillMode) { + case PreserveAspectFit: { + QSize scaled = m_pixmap.size(); + + scaled.scale(boundingRect().size().toSize(), Qt::KeepAspectRatio); + destRect = QRect(QPoint(0, 0), scaled); + break; + } + case PreserveAspectCrop: { + painter->setClipRect(boundingRect(), Qt::IntersectClip); + QSize scaled = m_pixmap.size(); + scaled.scale(boundingRect().size().toSize(), Qt::KeepAspectRatioByExpanding); + destRect = QRect(QPoint(0, 0), scaled); + break; + } + case TileVertically: { + painter->scale(width()/(qreal)m_pixmap.width(), 1); + destRect = boundingRect().toRect(); + destRect.setWidth(destRect.width() / (width()/(qreal)m_pixmap.width())); + break; + } + case TileHorizontally: { + painter->scale(1, height()/(qreal)m_pixmap.height()); + destRect = boundingRect().toRect(); + destRect.setHeight(destRect.height() / (height()/(qreal)m_pixmap.height())); + break; + } + case Stretch: + case Tile: + default: + destRect = boundingRect().toRect(); + } + + if (m_fillMode >= Tile) { + painter->drawTiledPixmap(destRect, m_pixmap); + } else { + painter->drawPixmap(destRect, m_pixmap, m_pixmap.rect()); + } + + painter->restore(); } diff --git a/declarativeimports/qtextracomponents/qpixmapitem.h b/declarativeimports/qtextracomponents/qpixmapitem.h index af2cc9ef0..ea91ac814 100644 --- a/declarativeimports/qtextracomponents/qpixmapitem.h +++ b/declarativeimports/qtextracomponents/qpixmapitem.h @@ -30,8 +30,19 @@ class QPixmapItem : public QDeclarativeItem Q_PROPERTY(bool smooth READ smooth WRITE setSmooth) Q_PROPERTY(int nativeWidth READ nativeWidth NOTIFY nativeWidthChanged) Q_PROPERTY(int nativeHeight READ nativeHeight NOTIFY nativeHeightChanged) + Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) + Q_ENUMS(FillMode) public: + enum FillMode { + Stretch, // the image is scaled to fit + PreserveAspectFit, // the image is scaled uniformly to fit without cropping + PreserveAspectCrop, // the image is scaled uniformly to fill, cropping if necessary + Tile, // the image is duplicated horizontally and vertically + TileVertically, // the image is stretched horizontally and tiled vertically + TileHorizontally //the image is stretched vertically and tiled horizontally + }; + QPixmapItem(QDeclarativeItem *parent=0); ~QPixmapItem(); @@ -44,15 +55,20 @@ public: int nativeWidth() const; int nativeHeight() const; + FillMode fillMode() const; + void setFillMode(FillMode mode); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); Q_SIGNALS: void nativeWidthChanged(); void nativeHeightChanged(); + void fillModeChanged(); private: QPixmap m_pixmap; bool m_smooth; + FillMode m_fillMode; }; #endif diff --git a/declarativeimports/test/gallery/Busy.qml b/declarativeimports/test/gallery/Busy.qml index 8e77db1ec..55ffe20f5 100644 --- a/declarativeimports/test/gallery/Busy.qml +++ b/declarativeimports/test/gallery/Busy.qml @@ -20,59 +20,76 @@ import QtQuick 1.0 import org.kde.plasma.components 0.1 as PlasmaComponents -Column { - spacing: 20 +PlasmaComponents.Page { + height: childrenRect.height + property int implicitHeight: childrenRect.height - Text { - font.pixelSize: 20 - text: "Busy Indicator" - } - - PlasmaComponents.BusyIndicator { } - - PlasmaComponents.BusyIndicator { running: true } - - Text { - font.pixelSize: 20 - text: "Progress Bar" - } - - Text { text: "Horizontal" } - - PlasmaComponents.ProgressBar { - value: 0.3 - } - - PlasmaComponents.ProgressBar { - indeterminate: true - } - - PlasmaComponents.ProgressBar { - minimumValue: 0 - maximumValue: 100 - value: 30 - } - - Text { text: "Vertical" } - Row { - spacing: 20 + tools: PlasmaComponents.ToolBarLayout { + spacing: 5 + PlasmaComponents.ToolButton { + text: "ToolButton" + } PlasmaComponents.ProgressBar { value: 0.3 - orientation: Qt.Vertical - width: 20 - height: 100 } - PlasmaComponents.ProgressBar { - value: 0.4 - orientation: Qt.Vertical - width: 20 - height: 120 + PlasmaComponents.TextField { + text: "Busy widgets" } + } + Column { + spacing: 20 + + Text { + font.pixelSize: 20 + text: "Busy Indicator" + } + + PlasmaComponents.BusyIndicator { } + + PlasmaComponents.BusyIndicator { running: true } + + Text { + font.pixelSize: 20 + text: "Progress Bar" + } + + Text { text: "Horizontal" } + + PlasmaComponents.ProgressBar { + value: 0.3 + } + PlasmaComponents.ProgressBar { - orientation: Qt.Vertical - width: 20 - height: 100 indeterminate: true } + + PlasmaComponents.ProgressBar { + minimumValue: 0 + maximumValue: 100 + value: 30 + } + + Text { text: "Vertical" } + Row { + spacing: 20 + PlasmaComponents.ProgressBar { + value: 0.3 + orientation: Qt.Vertical + width: 20 + height: 100 + } + PlasmaComponents.ProgressBar { + value: 0.4 + orientation: Qt.Vertical + width: 20 + height: 120 + } + PlasmaComponents.ProgressBar { + orientation: Qt.Vertical + width: 20 + height: 100 + indeterminate: true + } + } } } diff --git a/declarativeimports/test/gallery/Buttons.qml b/declarativeimports/test/gallery/Buttons.qml index b1d9ecf7b..39dd2c6d9 100644 --- a/declarativeimports/test/gallery/Buttons.qml +++ b/declarativeimports/test/gallery/Buttons.qml @@ -20,80 +20,94 @@ import QtQuick 1.0 import org.kde.plasma.components 0.1 as PlasmaComponents -Column { - spacing: 20 - - Text { - font.pixelSize: 20 - text: "Buttons" +PlasmaComponents.Page { + height: childrenRect.height + tools: PlasmaComponents.ToolBarLayout { + spacing: 5 + PlasmaComponents.Button { + text: "Button" + } + PlasmaComponents.Button { + text: "toolbar of the Buttons page" + } + PlasmaComponents.TextField {} } - PlasmaComponents.Button { - id: bt1 - width: 140 - height: 30 - text: "Button" + Column { + spacing: 20 - onClicked: { - console.log("Clicked"); + Text { + font.pixelSize: 20 + text: "Buttons" } - Keys.onTabPressed: bt2.forceActiveFocus(); - } + PlasmaComponents.Button { + id: bt1 + width: 140 + height: 30 + text: "Button" - PlasmaComponents.Button { - id: bt2 - width: 140 - height: 30 - text: "Checkable Button" - checkable: true + onClicked: { + console.log("Clicked"); + } - onCheckedChanged: { - if (checked) - console.log("Button Checked"); - else - console.log("Button Unchecked"); + Keys.onTabPressed: bt2.forceActiveFocus(); } - Keys.onTabPressed: bt3.forceActiveFocus(); - } + PlasmaComponents.Button { + id: bt2 + width: 140 + height: 30 + text: "Checkable Button" + checkable: true - PlasmaComponents.Button { - id: bt3 - width: 140 - height: 30 - text: "Different Font" - font { - pixelSize: 20 - family: "Helvetica" + onCheckedChanged: { + if (checked) + console.log("Button Checked"); + else + console.log("Button Unchecked"); + } + + Keys.onTabPressed: bt3.forceActiveFocus(); } - Keys.onTabPressed: bt4.forceActiveFocus(); - } + PlasmaComponents.Button { + id: bt3 + width: 140 + height: 30 + text: "Different Font" + font { + pixelSize: 20 + family: "Helvetica" + } - PlasmaComponents.Button { - id: bt4 - width: 140 - height: 30 - text: "Icon Button" - iconSource: "/home/dakerfp/work/comics-reader/ui/images/random.png" + Keys.onTabPressed: bt4.forceActiveFocus(); + } - Keys.onTabPressed: bt5.forceActiveFocus(); - } + PlasmaComponents.Button { + id: bt4 + width: 140 + height: 30 + text: "Icon Button" + iconSource: "/home/dakerfp/work/comics-reader/ui/images/random.png" - PlasmaComponents.Button { - id: bt5 - width: 140 - height: 30 - iconSource: "/home/dakerfp/work/comics-reader/ui/images/random.png" + Keys.onTabPressed: bt5.forceActiveFocus(); + } - Keys.onTabPressed: bt1.forceActiveFocus(); - } + PlasmaComponents.Button { + id: bt5 + width: 140 + height: 30 + iconSource: "/home/dakerfp/work/comics-reader/ui/images/random.png" - PlasmaComponents.Button { - width: 140 - height: 30 - text: "Disabled Button" - enabled: false + Keys.onTabPressed: bt1.forceActiveFocus(); + } + + PlasmaComponents.Button { + width: 140 + height: 30 + text: "Disabled Button" + enabled: false + } } } diff --git a/declarativeimports/test/gallery/CheckableButtons.qml b/declarativeimports/test/gallery/CheckableButtons.qml index fee6032b4..66223760f 100644 --- a/declarativeimports/test/gallery/CheckableButtons.qml +++ b/declarativeimports/test/gallery/CheckableButtons.qml @@ -20,88 +20,106 @@ import QtQuick 1.0 import org.kde.plasma.components 0.1 as PlasmaComponents -Column { - spacing: 20 - Text { - font.pixelSize: 20 - text: "Check Box" - } +PlasmaComponents.Page { + height: childrenRect.height + property int implicitHeight: childrenRect.height - PlasmaComponents.CheckBox { - width: 140 - height: 30 - text: "Check Box 1" - - onCheckedChanged: { - if (checked) - console.log("CheckBox checked"); - else - console.log("CheckBox unchecked"); + tools: PlasmaComponents.ToolBarLayout { + spacing: 5 + PlasmaComponents.ToolButton { + text: "ToolButton" } - onClicked: { - console.log("CheckBox clicked"); + PlasmaComponents.CheckBox { + text: "Checkbox in the toolbar" + } + PlasmaComponents.TextField { + text: "hello" } } - - PlasmaComponents.CheckBox { - height: 30 - text: "Disabled" - enabled: false - } - - PlasmaComponents.CheckBox { - height: 30 - text: "" - } - - PlasmaComponents.CheckBox { - height: 30 - text: "A loooooooooooooong text" - } - - Text { - font.pixelSize: 20 - text: "Radio Button" - } - - PlasmaComponents.RadioButton { - width: 140 - height: 30 - text: "RadioButton" - - onCheckedChanged: { - if (checked) - console.log("RadioButton Checked"); - else - console.log("RadioButton Unchecked"); - } - } - - PlasmaComponents.Switch { } - - Text { - font.pixelSize: 20 - text: "Button Row" - } - - PlasmaComponents.ButtonRow { + Column { spacing: 20 - PlasmaComponents.RadioButton { text: "A" } - PlasmaComponents.RadioButton { text: "B" } - PlasmaComponents.RadioButton { text: "C" } - } - Text { - font.pixelSize: 20 - text: "Button Column" - } + Text { + font.pixelSize: 20 + text: "Check Box" + } - PlasmaComponents.ButtonColumn { - spacing: 20 - PlasmaComponents.RadioButton { text: "Alice" } - PlasmaComponents.RadioButton { text: "Bob" } - PlasmaComponents.RadioButton { text: "Charles" } - } + PlasmaComponents.CheckBox { + width: 140 + height: 30 + text: "Check Box 1" + onCheckedChanged: { + if (checked) + console.log("CheckBox checked"); + else + console.log("CheckBox unchecked"); + } + onClicked: { + console.log("CheckBox clicked"); + } + } + + PlasmaComponents.CheckBox { + height: 30 + text: "Disabled" + enabled: false + } + + PlasmaComponents.CheckBox { + height: 30 + text: "" + } + + PlasmaComponents.CheckBox { + height: 30 + text: "A loooooooooooooong text" + } + + Text { + font.pixelSize: 20 + text: "Radio Button" + } + + PlasmaComponents.RadioButton { + width: 140 + height: 30 + text: "RadioButton" + + onCheckedChanged: { + if (checked) + console.log("RadioButton Checked"); + else + console.log("RadioButton Unchecked"); + } + } + + PlasmaComponents.Switch { } + + Text { + font.pixelSize: 20 + text: "Button Row" + } + + PlasmaComponents.ButtonRow { + spacing: 20 + PlasmaComponents.RadioButton { text: "A" } + PlasmaComponents.RadioButton { text: "B" } + PlasmaComponents.RadioButton { text: "C" } + } + + Text { + font.pixelSize: 20 + text: "Button Column" + } + + PlasmaComponents.ButtonColumn { + spacing: 20 + PlasmaComponents.RadioButton { text: "Alice" } + PlasmaComponents.RadioButton { text: "Bob" } + PlasmaComponents.RadioButton { text: "Charles" } + } + + } } diff --git a/declarativeimports/test/gallery/Gallery.qml b/declarativeimports/test/gallery/Gallery.qml index bae3ada49..515b3db4b 100644 --- a/declarativeimports/test/gallery/Gallery.qml +++ b/declarativeimports/test/gallery/Gallery.qml @@ -18,14 +18,14 @@ */ import QtQuick 1.0 -import org.kde.plasma.components 0.1 as PlasmaComponents +import org.kde.plasma.components 0.1 Rectangle { width: 1000 height: 800 color: "lightgrey" - PlasmaComponents.ToolBar { + ToolBar { id: toolBar z: 10 anchors { @@ -33,76 +33,88 @@ Rectangle { left: parent.left right: parent.right } - tools: toolbarA } - Row { - id: toolbarA - visible: false - spacing: 5 - PlasmaComponents.ToolButton { - text: "Switch toolbar" - onClicked: toolBar.setTools(toolbarB, "push") + + + ListView { + id: pageSelector + width: 200 + anchors { + top: toolBar.bottom + bottom: parent.bottom } - PlasmaComponents.ToolButton { - text: "button on first toolbar" + model: ListModel { + id: pagesModel + ListElement { + page: "Buttons.qml" + title: "Buttons" + } + ListElement { + page: "CheckableButtons.qml" + title: "Checkable buttons" + } + ListElement { + page: "Busy.qml" + title: "Busy indicators" + } + ListElement { + page: "Sliders.qml" + title: "Sliders" + } + ListElement { + page: "Scrollers.qml" + title: "Scrollers" + } + ListElement { + page: "Texts.qml" + title: "Text elements" + } + ListElement { + page: "Misc.qml" + title: "Misc stuff" + } + } + delegate: ListItem { + enabled: true + Column { + Label { + text: title + } + } + onClicked: pageStack.replace(Qt.createComponent(page)) } } - Row { - id: toolbarB - visible: false - spacing: 5 - PlasmaComponents.ToolButton { - text: "Switch toolbar" - onClicked: toolBar.setTools(toolbarA, "pop") - } - PlasmaComponents.ToolButton { - flat: false - text: "button on second toolbar" - } - PlasmaComponents.TextField {} - } + + Flickable { id: page anchors { top: toolBar.bottom - left: parent.left + left: pageSelector.right right: parent.right bottom: parent.bottom } - contentWidth: 2200 - contentHeight: 1000 + contentWidth: pageStack.currentPage.implicitWidth + contentHeight: pageStack.currentPage.implicitHeight - Row { - x: 30 - anchors { - top: parent.top - bottom: parent.bottom - margins: 20 - } - spacing: 30 - - Buttons{ } - - CheckableButtons { } - - Busy { } - - Sliders { } - - Scrollers { } - - Texts { } + PageStack { + id: pageStack + toolBar: toolBar + width: page.width + height: currentPage.implicitHeight + initialPage: Qt.createComponent("Buttons.qml") } + } - PlasmaComponents.ScrollBar { + ScrollBar { id: horizontalScrollBar stepSize: 30 flickableItem: page - animated: true + orientation: Qt.Horizontal anchors { left: parent.left right: verticalScrollBar.left @@ -110,14 +122,13 @@ Rectangle { } } - PlasmaComponents.ScrollBar { + ScrollBar { id: verticalScrollBar stepSize: 30 orientation: Qt.Vertical flickableItem: page - animated: true anchors { top: toolBar.bottom right: parent.right diff --git a/declarativeimports/test/gallery/Misc.qml b/declarativeimports/test/gallery/Misc.qml new file mode 100644 index 000000000..aebdd733f --- /dev/null +++ b/declarativeimports/test/gallery/Misc.qml @@ -0,0 +1,636 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.1 +import org.kde.plasma.components 0.1 + + +Column { + id: column + + // for demonstration and testing purposes each component needs to + // set its inverted state explicitly + property bool childrenInverted: false + property bool windowInverted: false + + spacing: 14 + + Label { + anchors.horizontalCenter: parent.horizontalCenter + text: "Qt Components " + (enabled ? "(enabled)" : "(disabled)") + } + + Button { + anchors.horizontalCenter: parent.horizontalCenter + text: "Push me" + width: parent.width - parent.spacing + } + + TextField { + anchors.horizontalCenter: parent.horizontalCenter + placeholderText: "TextField" + width: parent.width - parent.spacing + } + + TextField { + id: clearable + anchors.horizontalCenter: parent.horizontalCenter + placeholderText: "Clearable TextField" + text: "Clearable TextField" + width: parent.width - parent.spacing + + Image { + id: clearText + anchors { top: parent.top; right: parent.right; margins: 6 } + fillMode: Image.PreserveAspectFit + smooth: true; visible: parent.text + source: "qrc:close_stop.svg" + height: parent.height - 6 + width: parent.height - 6 + + MouseArea { + id: clear + anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } + height: clearable.height; width: clearable.height + onClicked: clearable.text = "" + } + } + } + + TextField { + id: customOperation + anchors.horizontalCenter: parent.horizontalCenter + placeholderText: "Custom operation" + width: parent.width - parent.spacing + + Image { + id: addText + anchors { top: parent.top; right: parent.right } + smooth: true + fillMode: Image.PreserveAspectFit + source: "qrc:ok.svg" + height: parent.height; width: parent.height + scale: LayoutMirroring.enabled ? -1 : 1 + + MouseArea { + id: add + anchors.fill: parent + onClicked: textSelection.open() + } + + SelectionDialog { + id: textSelection + titleText: "Preset Texts" + selectedIndex: -1 + model: ListModel { + ListElement { name: "Lorem ipsum." } + ListElement { name: "Lorem ipsum dolor sit amet." } + ListElement { name: "Lorem ipsum dolor sit amet ipsum." } + } + + onAccepted: { + customOperation.text = textSelection.model.get(textSelection.selectedIndex).name + customOperation.forceActiveFocus() + } + + onRejected: selectedIndex = -1 + } + } + } + + TextArea { + anchors.horizontalCenter: parent.horizontalCenter + placeholderText: "This is a\n multiline control." + width: parent.width - parent.spacing; height: 280 + } + + Slider { + anchors.horizontalCenter: parent.horizontalCenter + value: 50 + } + + ButtonRow { + anchors.horizontalCenter: parent.horizontalCenter + spacing: parent.spacing + + exclusive: true + + RadioButton { + } + + RadioButton { + } + } + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: parent.spacing + + CheckBox { + } + + CheckBox { + checked: true + } + } + + Switch { + anchors.horizontalCenter: parent.horizontalCenter + } + + ProgressBar { + anchors.horizontalCenter: parent.horizontalCenter + + Timer { + running: true + repeat: true + interval: 25 + onTriggered: parent.value = (parent.value + 1) % 1.1 + } + } + + ProgressBar { + anchors.horizontalCenter: parent.horizontalCenter + indeterminate: true + } + + Component { + id: dialogComponent + CommonDialog { + id: dialog + titleText: "CommonDialog" + buttonTexts: ["Ok", "Cancel"] + + content: Text { + text: "This is the content" + font { bold: true; pixelSize: 16 } + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + } + + Button { + property CommonDialog dialog + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - parent.spacing + text: "CommonDialog" + onClicked: { + if (!dialog) + dialog = dialogComponent.createObject(column) + dialog.open() + } + } + + Component { + id: singleSelectionDialogComponent + SelectionDialog { + titleText: "Select background color" + selectedIndex: 1 + + model: ListModel { + id: colorModel + + ListElement { name: "Red" } + ListElement { name: "Blue" } + ListElement { name: "Green" } + ListElement { name: "Yellow" } + ListElement { name: "Black" } + ListElement { name: "White" } + ListElement { name: "Grey" } + ListElement { name: "Orange" } + ListElement { name: "Pink" } + } + + onAccepted: { selectionDialogButton.parent.color = colorModel.get(selectedIndex).name } + } + } + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + height: selectionDialogButton.height + width: parent.width - parent.spacing + radius: 10 + + Button { + id: selectionDialogButton + property SelectionDialog singleSelectionDialog + anchors.centerIn: parent + text: "Selection Dialog" + onClicked: { + if (!singleSelectionDialog) + singleSelectionDialog = singleSelectionDialogComponent.createObject(column) + singleSelectionDialog.open() + } + } + } + + Button { + property QueryDialog queryDialog + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - parent.spacing + text: "QueryDialog" + onClicked: { + if (!queryDialog) + queryDialog = queryDialogComponent.createObject(column) + queryDialog.open() + } + } + + Component { + id: queryDialogComponent + QueryDialog { + titleText: "Query Dialog" + // Arabic character in the beginning to test right-to-left UI alignment + message: (LayoutMirroring.enabled ? "\u062a" : "") + "Lorem ipsum dolor sit amet, consectetur adipisici elit," + + "sed eiusmod tempor incidunt ut labore et dolore magna aliqua." + + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris" + + "nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit" + + "in voluptate velit esse cillum dolore eu fugiat nulla pariatur." + + "Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui" + + "officia deserunt mollit anim id est laborum." + + acceptButtonText: "Ok" + rejectButtonText: "Cancel" + + titleIcon: "kmail" + } + } + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + height: contentMenuButton.height + width: parent.width - parent.spacing + radius: 10 + + Button { + id: contentMenuButton + property ContextMenu contextMenu + anchors.horizontalCenter: parent.horizontalCenter + text: "ContextMenu" + onClicked: { + if (!contextMenu) + contextMenu = contextMenuComponent.createObject(contentMenuButton) + contextMenu.open() + } + } + } + + Component { + id: contextMenuComponent + ContextMenu { + MenuItem { + text: "White" + onClicked: contentMenuButton.parent.color = "White" + } + MenuItem { + text: "Red" + onClicked: contentMenuButton.parent.color = "Red" + } + MenuItem { + text: "LightBlue" + onClicked: contentMenuButton.parent.color = "LightBlue" + } + MenuItem { + text: "LightGreen" + onClicked: contentMenuButton.parent.color = "LightGreen" + } + } + } + + ListView { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - parent.spacing; height: 120 + clip: true + delegate: listDelegate + model: listModel + header: listHeading + } + + ListModel { + id: listModel + + ListElement { + titleText: "Title" + subTitleText: "SubTitle" + } + ListElement { + titleText: "Title2" + subTitleText: "SubTitle" + } + ListElement { + titleText: "Title3" + subTitleText: "SubTitle" + } + } + + Component { + id: listHeading + Label { + text: "Heading" + } + } + + Component { + id: listDelegate + ListItem { + id: listItem + Column { + + Label { + text: titleText + } + Label { + text: subTitleText + } + } + } + } + + Label { + property SelectionDialog selectionDialog + text: { + if (selectionDialog) { + if (selectionDialog.selectedIndex >= 0) + return selectionDialog.model.get(selectionDialog.selectedIndex).name + } + return "Three" + } + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - parent.spacing + + MouseArea { + anchors.fill: parent + onClicked: { + if (!selectionDialog) + selectionDialog = selectionDialogComponent.createObject(column) + selectionDialog.open() + } + } + + Component { + id: selectionDialogComponent + SelectionDialog { + titleText: "Select" + selectedIndex: 2 + model: ListModel { + ListElement { name: "One" } + ListElement { name: "Two" } + ListElement { name: "Three" } + ListElement { name: "Four" } + ListElement { name: "Five" } + ListElement { name: "Six" } + ListElement { name: "Seven" } + ListElement { name: "Eight" } + ListElement { name: "Nine" } + } + } + } + } + + + TabBar { + //width: parent.width - parent.spacing + //height: 50 + anchors.horizontalCenter: parent.horizontalCenter + TabButton { tab: tab1content; text: "1"; iconSource: "qrc:close_stop.svg"} + TabButton { tab: tab2content; text: "2"; iconSource: "konqueror"} + TabButton { tab: tab3content; text: "3"} + } + + TabGroup { + height: 100 + width: parent.width - parent.spacing + Button { id: tab1content; text: "tab1" } + Text { + id: tab2content + text: "tab2" + horizontalAlignment: "AlignHCenter" + verticalAlignment: "AlignVCenter" + } + Page { + id: tab3content + width: 50 + height: 32 + CheckBox { anchors.fill: parent; text: "tab3"} + } + } + + ToolButton { + id: toolButton + text: "ToolButton" + iconSource: "konqueror" + } + + ToolButton { + id: toolButton2 + flat: true + iconSource: "qrc:ok.svg" + } + + ToolButton { + id: toolButton3 + text: "ToolButton" + iconSource: "qrc:close_stop.svg" + } + + Row { + spacing: 5 + + BusyIndicator { + id: busyInd1 + width: 20 + height: 20 + running: true + } + + BusyIndicator { + // default width/height is 40 + id: busyInd2 + running: true + } + + BusyIndicator { + id: busyInd3 + width: 60 + height: 60 + running: true + } + + Button { + text: "Toggle" + onClicked: { + busyInd1.running = !busyInd1.running + busyInd2.running = !busyInd2.running + busyInd3.running = !busyInd3.running + } + } + } + + Button { + property CommonDialog sectionScroll + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - parent.spacing + text: "SectionScroller" + iconSource: "konqueror" + onClicked: { + if (!sectionScroll) + sectionScroll = sectionScrollComponent.createObject(column) + sectionScroll.open() + } + } + + Component { + id: sectionScrollComponent + CommonDialog { + id: sectionScroll + titleText: "Section Scroller" + buttonTexts: ["Close"] + onButtonClicked: close() + + content: Rectangle { + color: Qr.rgba(1,1,1,0.8) + width: parent.width + implicitHeight: 300 + + ListModel { + id: testModel + ListElement { name: "A Cat 1"; alphabet: "A" } + ListElement { name: "A Cat 2"; alphabet: "A" } + ListElement { name: "Boo 1"; alphabet: "B" } + ListElement { name: "Boo 2"; alphabet: "B" } + ListElement { name: "Cat 1"; alphabet: "C" } + ListElement { name: "Cat 2"; alphabet: "C" } + ListElement { name: "Dog 1"; alphabet: "D" } + ListElement { name: "Dog 2"; alphabet: "D" } + ListElement { name: "Dog 3"; alphabet: "D" } + ListElement { name: "Dog 4"; alphabet: "D" } + ListElement { name: "Dog 5"; alphabet: "D" } + ListElement { name: "Dog 6"; alphabet: "D" } + ListElement { name: "Dog 7"; alphabet: "D" } + ListElement { name: "Dog 8"; alphabet: "D" } + ListElement { name: "Dog 9"; alphabet: "D" } + ListElement { name: "Dog 10"; alphabet: "D" } + ListElement { name: "Dog 11"; alphabet: "D" } + ListElement { name: "Dog 12"; alphabet: "D" } + ListElement { name: "Elephant 1"; alphabet: "E" } + ListElement { name: "Elephant 2"; alphabet: "E" } + ListElement { name: "FElephant 1"; alphabet: "F" } + ListElement { name: "FElephant 2"; alphabet: "F" } + ListElement { name: "Guinea pig"; alphabet: "G" } + ListElement { name: "Goose"; alphabet: "G" } + ListElement { name: "Horse"; alphabet: "H" } + ListElement { name: "Horse"; alphabet: "H" } + ListElement { name: "Parrot"; alphabet: "P" } + ListElement { name: "Parrot"; alphabet: "P" } + } + + ListView { + id: list + anchors.fill: parent + clip: true + cacheBuffer: contentHeight + delegate: ListItem { + Label { + anchors { + top: parent.top; topMargin: 4 + left: parent.left; leftMargin: 4 + } + text: name + " (index " + index + ")" + horizontalAlignment: Text.AlignLeft + } + } + + model: testModel + section.property: "alphabet" + section.criteria: ViewSection.FullString + section.delegate: ListItem { + sectionDelegate: true + Label { + anchors { + top: parent.top; topMargin: 4 + left: parent.left; leftMargin: 4 + } + text: section + horizontalAlignment: Text.AlignLeft + font { bold: true; } + } + } + } + + SectionScroller { + id: sectionScroller + listView: list + } + } + } + } + + ButtonRow { + id: buttonRow1 + width: parent.width - parent.spacing + exclusive: true + checkedButton: b2 + + Button { text: "b1" } + Button { text: "b2" } + Button { text: "b3" } + } + + ButtonRow { + id: buttonRow2 + width: parent.width - parent.spacing + exclusive: true + + ToolButton { text: "tb1" } + ToolButton { text: "tb2" } + } + + ButtonColumn { + id: buttonColumn + width: parent.width - parent.spacing + exclusive: true + + Button { text: "b4" } + Button { text: "b5" } + Button { text: "b6" } + Button { text: "b7" } + } +} diff --git a/declarativeimports/test/gallery/Scrollers.qml b/declarativeimports/test/gallery/Scrollers.qml index dea2d8c81..25aa47ed8 100644 --- a/declarativeimports/test/gallery/Scrollers.qml +++ b/declarativeimports/test/gallery/Scrollers.qml @@ -20,111 +20,130 @@ import QtQuick 1.0 import org.kde.plasma.components 0.1 as PlasmaComponents -Column { - spacing: 20 +PlasmaComponents.Page { + height: childrenRect.height + property int implicitHeight: childrenRect.height - Text { - font.pixelSize: 20 - text: "Scroll Bar" - } - - ListView { - id: scrollList - - width: 200 - height: 200 - clip: true - model: 20 - delegate: Text { - width: 200 - height: 30 - text: index - font.pixelSize: 18 + tools: PlasmaComponents.ToolBarLayout { + spacing: 5 + PlasmaComponents.ToolButton { + text: "ToolButton" } - - Rectangle { - anchors.fill: parent - color: "grey" - opacity: 0.3 - } - PlasmaComponents.ScrollBar { - id: scrollBar - orientation: Qt.Vertical - flickableItem: scrollList - animated: true - stepSize: 40 - scrollButtonInterval: 50 - anchors { - top: scrollList.top - right: scrollList.right - bottom: scrollList.bottom - } - } - } - - Text { - font.pixelSize: 20 - text: "Scroll Decorator" - } - - Item { - width: 200 - height: 200 - PlasmaComponents.Highlight { anchors.fill: parent } - Flickable { - id: scrollArea - anchors.fill: parent - clip: true - contentWidth: 400 - contentHeight: 400 - - // Flickable Contents - Rectangle { - color: "green" - width: 100 - height: 100 - } - Rectangle { - x: 80 - y: 80 - color: "blue" - width: 200 - height: 200 - } - Rectangle { - x: 200 - y: 200 - color: "red" - width: 150 - height: 150 - } - } - - // Scroll Decorators - PlasmaComponents.ScrollDecorator { - orientation: Qt.Vertical - flickableItem: scrollArea - inverted: true - anchors { - top: scrollArea.top - right: scrollArea.right - bottom: scrollArea.bottom - } - Text { - y: parent.height / 2 - x: 13 - rotation: -90 - text: "inverted" - } - } - PlasmaComponents.ScrollDecorator { orientation: Qt.Horizontal + interactive: true flickableItem: scrollArea - anchors { - left: scrollArea.left - right: scrollArea.right - bottom: scrollArea.bottom + width: 200 + } + PlasmaComponents.TextField { + text: "hello" + } + } + Column { + spacing: 20 + + Text { + font.pixelSize: 20 + text: "Scroll Bar" + } + + ListView { + id: scrollList + + width: 200 + height: 200 + clip: true + model: 20 + delegate: Text { + width: 200 + height: 30 + text: index + font.pixelSize: 18 + } + + Rectangle { + anchors.fill: parent + color: "grey" + opacity: 0.3 + } + + PlasmaComponents.ScrollBar { + id: scrollBar + orientation: Qt.Vertical + flickableItem: scrollList + stepSize: 40 + scrollButtonInterval: 50 + anchors { + top: scrollList.top + right: scrollList.right + bottom: scrollList.bottom + } + } + } + + Text { + font.pixelSize: 20 + text: "Scroll Decorator" + } + + Item { + width: 200 + height: 200 + PlasmaComponents.Highlight { anchors.fill: parent } + Flickable { + id: scrollArea + anchors.fill: parent + clip: true + contentWidth: 400 + contentHeight: 400 + + // Flickable Contents + Rectangle { + color: "green" + width: 100 + height: 100 + } + Rectangle { + x: 80 + y: 80 + color: "blue" + width: 200 + height: 200 + } + Rectangle { + x: 200 + y: 200 + color: "red" + width: 150 + height: 150 + } + } + + // Scroll Decorators + PlasmaComponents.ScrollBar { + orientation: Qt.Vertical + flickableItem: scrollArea + inverted: true + anchors { + top: scrollArea.top + right: scrollArea.right + bottom: scrollArea.bottom + } + Text { + y: parent.height / 2 + x: 13 + rotation: -90 + text: "inverted" + } + } + PlasmaComponents.ScrollBar { + orientation: Qt.Horizontal + flickableItem: scrollArea + anchors { + left: scrollArea.left + right: scrollArea.right + bottom: scrollArea.bottom + } } } } diff --git a/declarativeimports/test/gallery/Sliders.qml b/declarativeimports/test/gallery/Sliders.qml index a87c53a2b..9d37996ad 100644 --- a/declarativeimports/test/gallery/Sliders.qml +++ b/declarativeimports/test/gallery/Sliders.qml @@ -20,113 +20,130 @@ import QtQuick 1.0 import org.kde.plasma.components 0.1 as PlasmaComponents -Column { - spacing: 20 +PlasmaComponents.Page { + height: childrenRect.height + property int implicitHeight: childrenRect.height - PlasmaComponents.Label { - font.pixelSize: 20 - text: "Slider" - } - - PlasmaComponents.Highlight { - width: 300 - height: 400 - Column { - anchors { - fill: parent - } - spacing: 10 - - PlasmaComponents.Label { text: "Color Selector"; font.pixelSize: 20 } - - PlasmaComponents.Label { text: "Red" } - - PlasmaComponents.Slider { - id: redSlider - height: 20 - width: 255 - orientation: Qt.Horizontal - minimumValue: 0 - maximumValue: 255 - stepSize: 10 - animated: true - Keys.onTabPressed: greenSlider.forceActiveFocus() - } - - PlasmaComponents.Label { text: "Green" } - - PlasmaComponents.Slider { - id: greenSlider - height: 20 - width: 255 - orientation: Qt.Horizontal - minimumValue: 0 - maximumValue: 255 - stepSize: 10 - animated: true - Keys.onTabPressed: blueSlider.forceActiveFocus() - } - - PlasmaComponents.Label { text: "Blue" } - - PlasmaComponents.Slider { - id: blueSlider - height: 20 - width: 255 - orientation: Qt.Horizontal - minimumValue: 0 - maximumValue: 255 - stepSize: 10 - animated: true - Keys.onTabPressed: redSlider.forceActiveFocus() - } - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width / 2 - height: width - color: Qt.rgba(redSlider.value / 255, greenSlider.value / 255, blueSlider.value / 255, 1) - } + tools: PlasmaComponents.ToolBarLayout { + spacing: 5 + PlasmaComponents.ToolButton { + text: "ToolButton" + } + PlasmaComponents.Slider { + width: 140 + animated: true + enabled: true + } + PlasmaComponents.TextField { + text: "hello" } } + Column { + spacing: 20 - PlasmaComponents.Label { text: "Disabled Horizontal Slider" } + PlasmaComponents.Label { + font.pixelSize: 20 + text: "Slider" + } - PlasmaComponents.Slider { - id: horizontalSlider - width: 140 - height: 20 - animated: true - enabled: false - } + PlasmaComponents.Highlight { + width: 300 + height: 400 + Column { + anchors { + fill: parent + } + spacing: 10 - PlasmaComponents.Label { text: "Inverted Horizontal Slider" } + PlasmaComponents.Label { text: "Color Selector"; font.pixelSize: 20 } - PlasmaComponents.Slider { - id: invHorizontalSlider - width: 140 - height: 20 - inverted: true - animated: true - enabled: true - } + PlasmaComponents.Label { text: "Red" } - PlasmaComponents.Label { text: "Vertical Slider" } + PlasmaComponents.Slider { + id: redSlider + height: 20 + width: 255 + orientation: Qt.Horizontal + minimumValue: 0 + maximumValue: 255 + stepSize: 10 + Keys.onTabPressed: greenSlider.forceActiveFocus() + } + + PlasmaComponents.Label { text: "Green" } + + PlasmaComponents.Slider { + id: greenSlider + height: 20 + width: 255 + orientation: Qt.Horizontal + minimumValue: 0 + maximumValue: 255 + stepSize: 10 + animated: true + Keys.onTabPressed: blueSlider.forceActiveFocus() + } + + PlasmaComponents.Label { text: "Blue" } + + PlasmaComponents.Slider { + id: blueSlider + height: 20 + width: 255 + orientation: Qt.Horizontal + minimumValue: 0 + maximumValue: 255 + stepSize: 10 + Keys.onTabPressed: redSlider.forceActiveFocus() + } + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width / 2 + height: width + color: Qt.rgba(redSlider.value / 255, greenSlider.value / 255, blueSlider.value / 255, 1) + } + } + } + + PlasmaComponents.Label { text: "Disabled Horizontal Slider" } - Row { - spacing: 30 PlasmaComponents.Slider { - id: verticalSlider - width: 20 - height: 140 - orientation: Qt.Vertical - minimumValue: 10 - maximumValue: 1000 - stepSize: 50 + id: horizontalSlider + width: 140 + height: 20 + animated: true + enabled: false + } + + PlasmaComponents.Label { text: "Inverted Horizontal Slider" } + + PlasmaComponents.Slider { + id: invHorizontalSlider + width: 140 + height: 20 inverted: true animated: true + enabled: true } - PlasmaComponents.Label { text: verticalSlider.value } - } + PlasmaComponents.Label { text: "Vertical Slider" } + + Row { + spacing: 30 + PlasmaComponents.Slider { + id: verticalSlider + width: 20 + height: 140 + orientation: Qt.Vertical + minimumValue: 10 + maximumValue: 1000 + stepSize: 50 + inverted: true + animated: true + } + PlasmaComponents.Label { text: verticalSlider.value } + } + + } } diff --git a/declarativeimports/test/gallery/Texts.qml b/declarativeimports/test/gallery/Texts.qml index ae3d0df48..53c3993a7 100644 --- a/declarativeimports/test/gallery/Texts.qml +++ b/declarativeimports/test/gallery/Texts.qml @@ -20,80 +20,100 @@ import QtQuick 1.1 import org.kde.plasma.components 0.1 as PlasmaComponents -Column { - spacing: 30 - Text { - text: "Text Fields" - font.pixelSize: 20 - } +PlasmaComponents.Page { + height: childrenRect.height + property int implicitHeight: childrenRect.height - PlasmaComponents.Highlight { - width: 200 - height: 100 - Column { - spacing: 10 - Row { - Text { - text: "Username: " - anchors.verticalCenter: tf1.verticalCenter - } - PlasmaComponents.TextField { - id: tf1 - placeholderText: "login" - Keys.onTabPressed: tf2.forceActiveFocus(); - } - } - - Row { - Text { - text: "Password: " - anchors.verticalCenter: tf2.verticalCenter - } - PlasmaComponents.TextField { - id: tf2 - width: 120 - echoMode: TextInput.Password - Keys.onTabPressed: loginButton.forceActiveFocus(); - } - } - - PlasmaComponents.Button { - id: loginButton - text: "Login" - anchors { - right: parent.right - rightMargin: 0 - } - width: 100 - } + tools: PlasmaComponents.ToolBarLayout { + spacing: 5 + PlasmaComponents.Label { + text: "Text label:" + } + PlasmaComponents.ToolButton { + text: "ToolButton" + } + PlasmaComponents.TextField { + placeholderText: "Place holder text" + } + PlasmaComponents.TextField { + text: "Text fields page" } } + Column { + spacing: 30 + Text { + text: "Text Fields" + font.pixelSize: 20 + } - PlasmaComponents.TextField { - width: 120 - placeholderText: "Disabled Text Field" - Keys.onTabPressed: loginButton.forceActiveFocus(); - enabled: false - } + PlasmaComponents.Highlight { + width: 200 + height: 100 + Column { + spacing: 10 + Row { + Text { + text: "Username: " + anchors.verticalCenter: tf1.verticalCenter + } + PlasmaComponents.TextField { + id: tf1 + placeholderText: "login" + Keys.onTabPressed: tf2.forceActiveFocus(); + } + } - Text { - text: "Text Area" - font.pixelSize: 20 - } + Row { + Text { + text: "Password: " + anchors.verticalCenter: tf2.verticalCenter + } + PlasmaComponents.TextField { + id: tf2 + width: 120 + echoMode: TextInput.Password + Keys.onTabPressed: loginButton.forceActiveFocus(); + } + } - PlasmaComponents.TextArea { - width: 200 - height: 200 - placeholderText: "Lorem ipsum et dolor" - wrapMode: TextEdit.WordWrap - contentMaxWidth: 400 - contentMaxHeight: 400 - } + PlasmaComponents.Button { + id: loginButton + text: "Login" + anchors { + right: parent.right + rightMargin: 0 + } + width: 100 + } + } + } - PlasmaComponents.TextArea { - width: 200 - height: 100 - enabled: false - text: "Disabled Text Area" + PlasmaComponents.TextField { + width: 120 + placeholderText: "Disabled Text Field" + Keys.onTabPressed: loginButton.forceActiveFocus(); + enabled: false + } + + Text { + text: "Text Area" + font.pixelSize: 20 + } + + PlasmaComponents.TextArea { + width: 200 + height: 200 + placeholderText: "Lorem ipsum et dolor" + wrapMode: TextEdit.WordWrap + contentMaxWidth: 400 + contentMaxHeight: 400 + } + + PlasmaComponents.TextArea { + width: 200 + height: 100 + enabled: false + text: "Disabled Text Area" + } } } diff --git a/scriptengines/javascript/plasmoid/appletinterface.cpp b/scriptengines/javascript/plasmoid/appletinterface.cpp index 7dcfa8f2a..cc70e8b27 100644 --- a/scriptengines/javascript/plasmoid/appletinterface.cpp +++ b/scriptengines/javascript/plasmoid/appletinterface.cpp @@ -463,6 +463,11 @@ void PopupAppletInterface::showPopup() popupApplet()->showPopup(); } +void PopupAppletInterface::showPopup(int timeout) +{ + popupApplet()->showPopup(timeout); +} + void PopupAppletInterface::setPopupWidget(QGraphicsWidget *widget) { popupApplet()->setGraphicsWidget(widget); diff --git a/scriptengines/javascript/plasmoid/appletinterface.h b/scriptengines/javascript/plasmoid/appletinterface.h index d2cd9a4b5..53d0a2c0a 100644 --- a/scriptengines/javascript/plasmoid/appletinterface.h +++ b/scriptengines/javascript/plasmoid/appletinterface.h @@ -372,6 +372,7 @@ public Q_SLOTS: void togglePopup(); void hidePopup(); void showPopup(); + void showPopup(int timeout); }; diff --git a/scriptengines/javascript/plasmoid/declarativeappletscript.cpp b/scriptengines/javascript/plasmoid/declarativeappletscript.cpp index 249f5e3c0..005894a2f 100644 --- a/scriptengines/javascript/plasmoid/declarativeappletscript.cpp +++ b/scriptengines/javascript/plasmoid/declarativeappletscript.cpp @@ -82,7 +82,7 @@ bool DeclarativeAppletScript::init() { m_declarativeWidget = new Plasma::DeclarativeWidget(applet()); m_declarativeWidget->setInitializationDelayed(true); - KGlobal::locale()->insertCatalog(description().pluginName()); + KGlobal::locale()->insertCatalog("plasma_applet_" % description().pluginName()); //make possible to import extensions from the package //FIXME: probably to be removed, would make possible to use native code from within the package :/ diff --git a/scriptengines/javascript/plasmoid/simplejavascriptapplet.cpp b/scriptengines/javascript/plasmoid/simplejavascriptapplet.cpp index f879ae94b..112c26520 100644 --- a/scriptengines/javascript/plasmoid/simplejavascriptapplet.cpp +++ b/scriptengines/javascript/plasmoid/simplejavascriptapplet.cpp @@ -314,7 +314,7 @@ bool SimpleJavaScriptApplet::init() this, SLOT(extenderItemRestored(Plasma::ExtenderItem*))); connect(applet(), SIGNAL(activate()), this, SLOT(activate())); - KGlobal::locale()->insertCatalog(description().pluginName()); + KGlobal::locale()->insertCatalog("plasma_applet_" % description().pluginName()); setupObjects(); AppletAuthorization auth(this); diff --git a/tools/plasmapkg/main.cpp b/tools/plasmapkg/main.cpp index b4241eceb..dbfd1568a 100644 --- a/tools/plasmapkg/main.cpp +++ b/tools/plasmapkg/main.cpp @@ -39,7 +39,7 @@ #include static const char description[] = I18N_NOOP("Install, list, remove Plasma packages"); -static const char version[] = "0.1"; +static const char version[] = "0.2"; void output(const QString &msg) { @@ -180,6 +180,8 @@ int main(int argc, char **argv) KCmdLineArgs::init( argc, argv, &aboutData ); KCmdLineOptions options; + options.add("h"); + options.add("hash ", ki18nc("Do not translate ", "Generate a SHA1 hash for the package at ")); options.add("g"); options.add("global", ki18n("For install or remove, operates on packages installed for all users.")); options.add("t"); @@ -206,6 +208,26 @@ int main(int argc, char **argv) KApplication app; KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->isSet("hash")) { + const QString path = args->getOption("hash"); + Plasma::PackageStructure::Ptr structure(new Plasma::PackageStructure); + Plasma::Package package(path, structure); + const QString hash = package.contentsHash(); + if (hash.isEmpty()) { + output(i18n("Failed to generate a Package hash for %1", path)); + exit(1); + } + + output(i18n("SHA1 hash for Package at %1: '%2'", path, hash)); + exit(0); + } + + if (args->isSet("list-types")) { + listTypes(); + exit(0); + } + QString type = args->getOption("type"); QString packageRoot = type; QString servicePrefix; @@ -214,11 +236,6 @@ int main(int argc, char **argv) QString package; QString packageFile; - if (args->isSet("list-types")) { - listTypes(); - exit(0); - } - if (args->isSet("remove")) { package = args->getOption("remove"); } else if (args->isSet("upgrade")) {