diff options
-rw-r--r-- | qml/pages/AddWidget.qml | 5 | ||||
-rw-r--r-- | qml/pages/MainPage.qml | 2 | ||||
-rw-r--r-- | qml/watch/faces/builtinface0.qml | 11 | ||||
-rw-r--r-- | qml/watch/faces/builtinface1.qml | 11 | ||||
-rw-r--r-- | qml/watch/faces/builtinface2.png (renamed from qml/watch/faces/builtinface_what.png) | bin | 906 -> 906 bytes | |||
-rw-r--r-- | qml/watch/faces/builtinface2.qml | 11 | ||||
-rw-r--r-- | qml/watch/faces/builtinface4.qml | 2 | ||||
-rw-r--r-- | qml/watch/faces/builtinface5.png | bin | 0 -> 1663 bytes | |||
-rw-r--r-- | qml/watch/faces/builtinface5.qml | 11 | ||||
-rw-r--r-- | salmeta.pro | 3 | ||||
-rw-r--r-- | src/availablewidgetsmodel.cpp | 31 | ||||
-rw-r--r-- | src/widgetinfomodel.cpp | 125 | ||||
-rw-r--r-- | src/widgetinfomodel.h | 7 | ||||
-rw-r--r-- | translations/salmeta.ts | 34 |
14 files changed, 231 insertions, 22 deletions
diff --git a/qml/pages/AddWidget.qml b/qml/pages/AddWidget.qml index 5c3086e..c854c7c 100644 --- a/qml/pages/AddWidget.qml +++ b/qml/pages/AddWidget.qml @@ -19,13 +19,14 @@ Page { } delegate : BackgroundItem { + id: widgetDelegate contentHeight: Theme.itemSizeSmall Label { anchors.left: parent.left anchors.margins: Theme.paddingLarge anchors.verticalCenter: parent.verticalCenter - text: model.description + text: model.description + (!widgetDelegate.enabled ? qsTr(" (does not fit)") : "") truncationMode: TruncationMode.Elide color: highlighted ? Theme.highlightColor : Theme.primaryColor } @@ -34,6 +35,8 @@ Page { curWidgets.addWidget(model.url, addToPage, addToPos, model.size); pageStack.pop(); } + + enabled: !curWidgets.widgetOverlaps(addToPage, addToPos, model.size); } } } diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml index b25ff06..20d602f 100644 --- a/qml/pages/MainPage.qml +++ b/qml/pages/MainPage.qml @@ -227,7 +227,7 @@ Page { Label { x: Theme.paddingLarge - text: "TODO" + text: "TODO: List of notification types" } } } diff --git a/qml/watch/faces/builtinface0.qml b/qml/watch/faces/builtinface0.qml new file mode 100644 index 0000000..a8df091 --- /dev/null +++ b/qml/watch/faces/builtinface0.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 96/2 + height: 96/2 + + Image { + anchors.fill: parent + source: "builtinface0.png" + } +} diff --git a/qml/watch/faces/builtinface1.qml b/qml/watch/faces/builtinface1.qml new file mode 100644 index 0000000..3d4bb57 --- /dev/null +++ b/qml/watch/faces/builtinface1.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 96 + height: 96/2 + + Image { + anchors.fill: parent + source: "builtinface3.png" + } +} diff --git a/qml/watch/faces/builtinface_what.png b/qml/watch/faces/builtinface2.png Binary files differindex 3ade62b..3ade62b 100644 --- a/qml/watch/faces/builtinface_what.png +++ b/qml/watch/faces/builtinface2.png diff --git a/qml/watch/faces/builtinface2.qml b/qml/watch/faces/builtinface2.qml new file mode 100644 index 0000000..7c4542a --- /dev/null +++ b/qml/watch/faces/builtinface2.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 96 + height: 96 + + Image { + anchors.fill: parent + source: "builtinface2.png" + } +} diff --git a/qml/watch/faces/builtinface4.qml b/qml/watch/faces/builtinface4.qml index f9eff50..ca542d4 100644 --- a/qml/watch/faces/builtinface4.qml +++ b/qml/watch/faces/builtinface4.qml @@ -6,6 +6,6 @@ Rectangle { Image { anchors.fill: parent - source: "builtinface4.png" + source: "builtinface3.png" } } diff --git a/qml/watch/faces/builtinface5.png b/qml/watch/faces/builtinface5.png Binary files differnew file mode 100644 index 0000000..d084bb0 --- /dev/null +++ b/qml/watch/faces/builtinface5.png diff --git a/qml/watch/faces/builtinface5.qml b/qml/watch/faces/builtinface5.qml new file mode 100644 index 0000000..e64703c --- /dev/null +++ b/qml/watch/faces/builtinface5.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 96 + height: 96 + + Image { + anchors.fill: parent + source: "builtinface5.png" + } +} diff --git a/salmeta.pro b/salmeta.pro index 550925f..86ccf52 100644 --- a/salmeta.pro +++ b/salmeta.pro @@ -45,8 +45,7 @@ OTHER_FILES += qml/salmeta.qml \ qml/pages/MainPage.qml \ qml/watch/WidgetView.qml \ qml/watch/WatchView.qml qml/watch/add_widget.png \ - qml/watch/faces/builtinface3.qml qml/watch/faces/builtinface3.png \ - qml/watch/faces/builtinface4.qml qml/watch/faces/builtinface4.png \ + qml/watch/faces/*.qml qml/watch/faces/*.png \ qml/watch/icons/*.png \ qml/pages/AddWidget.qml \ qml/watch/notification.png diff --git a/src/availablewidgetsmodel.cpp b/src/availablewidgetsmodel.cpp index 37232dc..77304b9 100644 --- a/src/availablewidgetsmodel.cpp +++ b/src/availablewidgetsmodel.cpp @@ -53,17 +53,42 @@ void AvailableWidgetsModel::reload() // Load builtin widgets WidgetInfo info; + info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface0.qml")); + info.setDescription(tr("Watchface: 1x1 Small")); + info.setSize(WidgetInfo::Size1Q); + Q_ASSERT(info.builtinClockfaceId() == 0); // Ensure face ID is autodetected from passed URL + _widgets.append(info); + + + info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface1.qml")); + info.setDescription(tr("Watchface: 2x1 Horizontal")); + info.setSize(WidgetInfo::Size2QHorizontal); + Q_ASSERT(info.builtinClockfaceId() == 1); + _widgets.append(info); + + info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface2.qml")); + info.setDescription(tr("Watchface: 2x2 MetaWatch logo")); + info.setSize(WidgetInfo::Size4Q); + Q_ASSERT(info.builtinClockfaceId() == 2); + _widgets.append(info); + info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface3.qml")); - info.setDescription("Builtin watchface #3"); + info.setDescription(tr("Watchface: 2x2 Big numbers")); info.setSize(WidgetInfo::Size4Q); - Q_ASSERT(info.builtinClockfaceId() == 3); // Autodetected from passed URL + Q_ASSERT(info.builtinClockfaceId() == 3); _widgets.append(info); info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface4.qml")); - info.setDescription("Builtin watchface #4"); + info.setDescription(tr("Watchface: 2x2 Fish")); info.setSize(WidgetInfo::Size4Q); Q_ASSERT(info.builtinClockfaceId() == 4); _widgets.append(info); + info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface5.qml")); + info.setDescription(tr("Watchface: 2x2 Hanzi")); + info.setSize(WidgetInfo::Size4Q); + Q_ASSERT(info.builtinClockfaceId() == 5); + _widgets.append(info); + endResetModel(); } diff --git a/src/widgetinfomodel.cpp b/src/widgetinfomodel.cpp index e2f145f..9bb53e4 100644 --- a/src/widgetinfomodel.cpp +++ b/src/widgetinfomodel.cpp @@ -1,4 +1,5 @@ #include <QtCore/QDebug> +#include <QtCore/QBitArray> #include <QtCore/QStringList> #include "widgetinfomodel.h" @@ -10,6 +11,82 @@ inline QString get_widget_dconf_base(int index) return QString("widget%1_").arg(index); } +WidgetInfo::WidgetPosition canonicalize_widget_pos(WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size) +{ + switch (size) { + case WidgetInfo::Size1Q: + return pos; // Any position is valid + case WidgetInfo::Size2QHorizontal: + switch (pos) { + case WidgetInfo::PosNW: + case WidgetInfo::PosNE: + return WidgetInfo::PosNW; + case WidgetInfo::PosSW: + case WidgetInfo::PosSE: + return WidgetInfo::PosSW; + } + break; + case WidgetInfo::Size2QVertical: + switch (pos) { + case WidgetInfo::PosNW: + case WidgetInfo::PosSW: + return WidgetInfo::PosNW; + case WidgetInfo::PosNE: + case WidgetInfo::PosSE: + return WidgetInfo::PosNE; + } + break; + case WidgetInfo::Size4Q: + return WidgetInfo::PosNW; // 4Q widgets use entire screen + } + + return pos; +} + +QBitArray used_positions(WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size) +{ + QBitArray used(4, false); + + switch (size) { + case WidgetInfo::Size1Q: + used[pos] = true; + break; + case WidgetInfo::Size2QHorizontal: + switch (pos) { + case WidgetInfo::PosNW: + case WidgetInfo::PosNE: + used[WidgetInfo::PosNW] = true; + used[WidgetInfo::PosNE] = true; + break; + case WidgetInfo::PosSW: + case WidgetInfo::PosSE: + used[WidgetInfo::PosNW] = true; + used[WidgetInfo::PosNE] = true; + break; + } + break; + case WidgetInfo::Size2QVertical: + switch (pos) { + case WidgetInfo::PosNW: + case WidgetInfo::PosSW: + used[WidgetInfo::PosNW] = true; + used[WidgetInfo::PosSW] = true; + break; + case WidgetInfo::PosNE: + case WidgetInfo::PosSE: + used[WidgetInfo::PosNE] = true; + used[WidgetInfo::PosSE] = true; + break; + } + break; + case WidgetInfo::Size4Q: + used.fill(true); + break; + } + + return used; +} + } WidgetInfoModel::WidgetInfoModel(const QString &settingsPrefix, QObject *parent) : @@ -69,23 +146,21 @@ QList<WidgetInfo> WidgetInfoModel::toList() const return _widgets.toList(); } -void WidgetInfoModel::reload() +bool WidgetInfoModel::widgetOverlaps(int page, WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size) const { - beginResetModel(); - _widgets.resize(16); + QBitArray usedPos = used_positions(pos, size); for (int i = 0; i < _widgets.size(); i++) { - WidgetInfo &info = _widgets[i]; - const QString base = get_widget_dconf_base(i); + if (_widgets[i].url().isEmpty()) continue; + if (_widgets[i].page() != page) continue; - info.setInvert(_settings->value(base + "invert").toBool()); - info.setPage(_settings->value(base + "page").toInt()); - info.setSize(static_cast<WidgetInfo::WidgetSize>(_settings->value(base + "size").toInt())); - info.setPosition(static_cast<WidgetInfo::WidgetPosition>(_settings->value(base + "position").toInt())); - info.setUrl(_settings->value(base + "url").toUrl()); + QBitArray intersection = usedPos & used_positions(_widgets[i].position(), _widgets[i].size()); + if (intersection.count(true) > 0) { + return true; + } } - endResetModel(); + return false; } int WidgetInfoModel::addWidget(const QUrl &url, int page, WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size) @@ -93,11 +168,18 @@ int WidgetInfoModel::addWidget(const QUrl &url, int page, WidgetInfo::WidgetPosi int slot = findEmptySlot(); if (slot == -1) { qWarning() << "No empty slots!"; // This shouldn't happen - return slot; + return -1; } + pos = canonicalize_widget_pos(pos, size); + qDebug() << "Adding widget" << url << page << pos << size; + if (widgetOverlaps(page, pos, size)) { + qWarning() << "Can't add the widget: it overlaps with an existing one!"; + return -1; + } + const QString base = get_widget_dconf_base(slot); _settings->setValue(base + "invert", QVariant::fromValue<bool>(false)); @@ -122,6 +204,25 @@ void WidgetInfoModel::removeWidget(int widgetId) _settings->setValue(base + "position", QVariant()); } +void WidgetInfoModel::reload() +{ + beginResetModel(); + _widgets.resize(16); + + for (int i = 0; i < _widgets.size(); i++) { + WidgetInfo &info = _widgets[i]; + const QString base = get_widget_dconf_base(i); + + info.setInvert(_settings->value(base + "invert").toBool()); + info.setPage(_settings->value(base + "page").toInt()); + info.setSize(static_cast<WidgetInfo::WidgetSize>(_settings->value(base + "size").toInt())); + info.setPosition(static_cast<WidgetInfo::WidgetPosition>(_settings->value(base + "position").toInt())); + info.setUrl(_settings->value(base + "url").toUrl()); + } + + endResetModel(); +} + int WidgetInfoModel::findEmptySlot() { for (int i = 0; i < _widgets.size(); i++) { diff --git a/src/widgetinfomodel.h b/src/widgetinfomodel.h index 4b2a700..bc3cd67 100644 --- a/src/widgetinfomodel.h +++ b/src/widgetinfomodel.h @@ -27,12 +27,15 @@ public: QList<WidgetInfo> toList() const; + Q_INVOKABLE bool widgetOverlaps(int page, WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size) const; + + Q_INVOKABLE int addWidget(const QUrl &url, int page, WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size); + Q_INVOKABLE void removeWidget(int widgetId); + signals: public slots: void reload(); - int addWidget(const QUrl &url, int page, WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size); - void removeWidget(int widgetId); private: int findEmptySlot(); diff --git a/translations/salmeta.ts b/translations/salmeta.ts index 786af13..605d20c 100644 --- a/translations/salmeta.ts +++ b/translations/salmeta.ts @@ -2,6 +2,40 @@ <!DOCTYPE TS> <TS version="2.0"> <context> + <name>AddWidget</name> + <message> + <source> (does not fit)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>AvailableWidgetsModel</name> + <message> + <source>Watchface: 1x1 Small</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Watchface: 2x1 Horizontal</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Watchface: 2x2 MetaWatch logo</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Watchface: 2x2 Big numbers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Watchface: 2x2 Fish</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Watchface: 2x2 Hanzi</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>MainPage</name> <message> <source>Not done yet</source> |