• May 02, 2024, 04:54:32 am

Author Topic: [TUT] Homescreen Widget in QML, because - why not?  (Read 5202 times)

0 Members and 1 Guest are viewing this topic.

Offline pisarz1958

  • Developer
  • New Member
  • ****
  • Posts: 26
  • Reputation: 27
  • Oh, I have this little field in my profile!
  • Current Phone: : Nokia 500
[TUT] Homescreen Widget in QML, because - why not?
« on: August 19, 2013, 09:31:34 pm »
Hi everyone! I promised Allstar that I'll write this tutorial. In past few days, I was resting a bit, and now, let's get to work, shall we? :) So, in this tutorial, I'm going to show you, how to implement homescreen widget in Qt and make necessary QML bindings. I hope you find it useful.

Beginning: What's the problem?
So, why this stuff isn't exactly simple? The problem is, there are no up to date APIs for homescreen publishing in Belle. We're going to use N97 Homescreen Publishing API (Symbian s60v5). But don't worry, it's fairy simple :)

PREPARE YOURSELF!
Before we get started, let's get required files. There is QHSWidget example somewhere, but it required copying files to SDK folder and compiling with s60v5 SDK. Fortunately, someone provided precompiled dll files, which we can simply use without doing all this stuff. You can get them here. There are two DLL files, urel and udeb. You need to choose one, which suits your compilation method. If you're building your app with debug option, choose "udeb". If you're building your app with release option, choose "urel".

Then, you need qhswidget.h from the example. You can get it from linked website, or you can also find it in my GitHub repository for Lightbulb, here. After adding it to your project and copying .dll into projects folder, let's do something fun, finally :D

Preparing project
First, let's rename dll file. It has to be done to avoid name clashing. Good idea would be to put UID there. Then, open qhswidget.h and change line containing DLL name, like this:
Code: [Select]
const QString DLLName("[your DLL name]");Also, you need to update your .pro file, so the DLL would be a part of SIS file. This is, how I did it in Lightbulb.
Code: [Select]
addFiles.pkg_postrules += "\"C:\\Projekty\\Lightbulb\\HSWidgetPlugin0xE22AC278.dll\" - \"!:\\sys\\bin\\HSWidgetPlugin0xE22AC278.dll\""
DEPLOYMENT += addFiles
Replace "C:\Projekty\Lightbulb\HSWidgetPlugin0xE22AC278.dll" with path to your .dll file. Don't forget about double slashes :)
This way, our dll file will be put in !:\sys\bin, where ! is destination drive. You could also want to do last part of the original instruction here if you want to prepare your app for publishing. As I haven't done it yet, I'm not explaining this.

You will also need some libraries, so put this stuff in .pro file:
Code: [Select]
#that library should be copied to SDK folder
#LIBS += -lhswidgetpublisher
#Libs for appswitcher
LIBS += -lapgrfx -lcone -lws32
#Libs for CFbsBimap
LIBS += -lbitgdi -lfbscli -laknskins -laknskinsrv -leikcore
Not sure, if all of these is even needed, but nevermind. :D

I hope you added qhswidget.h to project tree in this file. Just add it's name in "headers" section of the project file if you haven't done it yet.

Widget class
Now, let's add new C++ class, the same way it was done in previous tutorial. If you don't remember, how it was done, or haven't read it, a simple reminder:

This time, use different name, for example "hswidget". Make sure class is derived from QObject, it's somehow important. If you're ready, let's go to cpp file. Add required includes first:
Code: [Select]
#include "hswidget.h"
#include <QDebug>
#include <apgtask.h>
#include <eikenv.h>
QDebug itself isn't required, but if you want to add debug stuff here, you would need it. Then, you have to choose proper type of widget, for example:
Code: [Select]
const QString sw_type = "threerows";There are five layouts available.


First one, "wideimage". In this widget, image fills the space. You can use it as a template for your own layout, put text there etc. I guess that it can be transparent with svg or png file of your choice, though I've never explored this option.


Second one is "onerow". It contains one row of text and an icon. Really basic layout.


Need more space for your text? What about "tworows"? What is important, you need to set text in every row by yourself. So, they can contain different informations.


"threerows". Holds three rows of text and an icon.


You don't like icons anyway, do you? So, for people like you, there is also "threetextrows" layout, which contains only images.

If you have chosen right layout for your project, we can go further. You need a line that defines widgets name.
Code: [Select]
const QString sw_name = "Amazing and awesome widget";
Also, you should put your UID in the next line. Though, it can be any unique string. Even "ILoveSlicedBread", or whatever. But UID is the best solution against name clashing. :)
Code: [Select]
const QString sw_id = "0xE22AC278"; //can be any unique string
Now, let's specify some rows.
Code: [Select]
const QString sw_image ("image1");
const QString row1 ("text1");
I did it this way. Name of QString doesn't really matter though. This other stuff does. For more rows, just use "text2" and "text3".

We need to add some functions now.
Code: [Select]
HSWidget::HSWidget(QObject *parent) :
    QObject(parent)
{

    widget = QHSWidget::create(sw_type, sw_name, sw_id, this);
    connect(widget, SIGNAL(handleEvent(QHSWidget*, QHSEvent)), this, SLOT(handleEvent(QHSWidget*, QHSEvent) ));
    connect(widget, SIGNAL(handleItemEvent(QHSWidget*, QString, QHSItemEvent)), this, SLOT(handleItemEvent(QHSWidget*, QString, QHSItemEvent)));
}
This way, we're creating QHSWidget and doing necessary connections, so we could handle all the events.

Code: [Select]
void HSWidget::registerWidget()
{
    widget->RegisterWidget();

}
This function will allow us to register widget directly from QML file. This makes widget available for the user and should be done in first run.

Code: [Select]
void HSWidget::publishWidget()
{
    try {
        widget->PublishWidget();
    }
    catch (...) {
    }
}
This function updates widget. Also, I added this "try" stuff, so my app wouldn't crash when widget is not on the screen. I guess I could do it in much better way, but nevermind.

Code: [Select]
void HSWidget::removeWidget()
{
    widget->RemoveWidget();
}
Unregisters the widget, which makes it unavailable, like uninstalling or something.

Code: [Select]
void HSWidget::handleEvent( QHSWidget* /*aSender*/, QHSEvent aEvent )
{
    switch(aEvent)
                    {
                    case EActivate:
                    case EResume:
                            {
                            publishWidget();
                            }
                            break;
                    default:
                            break;
                    }

}
Let's handle some events, ok? In case widget was activated (EActivate) or resumed from suspension (EResume), it would be automatically updated. How it works? When widget is not on currently active homescreen, simply gets suspended, so we can't update it in this time. Also, activation event means that someone added our widget to homescreen. There is also "ESuspend" which let's you know that widget was suspended. For more details, just refer to "Home Screen Publishing API" documentation.

Code: [Select]
void HSWidget::handleItemEvent( QHSWidget* /*aSender*/, QString aTemplateItemName,
    QHSItemEvent aEvent)
{
    if(aTemplateItemName.compare(sw_image)==0)
                    {
                    publishWidget();
                    }
            else
                    {
                        this->bringToFront();
                    }
}
This code is required to bring our app to front if someone tapped it's icon in widget. Every element can have different actions. You can also use signals etc. I haven't tried it yet though, so I won't explain it unfortunately.

Code: [Select]
void HSWidget::bringToFront()
{
    TApaTask task( CEikonEnv::Static()->WsSession() );
    task.SetWgId(CEikonEnv::Static()->RootWin().Identifier());
    task.BringToForeground();
}
And this is a simple function that brings our app to front and automatically founds out, which is our UID. Nice stuff.

Finally, we would like to make a function which would allow us to change displayed data right from QML. This is my, extremely basic approach:

Code: [Select]
void HSWidget::updateWidget( QString icon, QString nRow1 )
{
    widget->SetItem(sw_image, icon);
    widget->SetItem(row1, nRow1);
    publishWidget();
}

I guess this is quite simple, isn't it? :) So... let's get to header file! Just copy it, I guess it doesn't require any explanations.
Code: [Select]
#ifndef HSWIDGET_H
#define HSWIDGET_H

#include <QObject>
#include "qhswidget.h"

class HSWidget : public QObject
{
    Q_OBJECT
public:
    explicit HSWidget(QObject *parent = 0);
    Q_INVOKABLE void registerWidget();
    Q_INVOKABLE void publishWidget();
    Q_INVOKABLE void removeWidget();
    Q_INVOKABLE void updateWidget( QString icon, nRow1 );
    void bringToFront();
public slots:
    void handleEvent(QHSWidget*, QHSEvent aEvent );
    void handleItemEvent(QHSWidget*, QString aTemplateItemName,
                         QHSItemEvent aEvent);
private:
    QHSWidget* widget;
};

#endif // HSWIDGET_H

Super simple stuff :)

QML bindings!
Now, let's go back to main.cpp. Remember, what we did previously? We're going to do the same again! First, include header file of our new class.
Code: [Select]
#include "hswidget.h"
Then, register it as QML object:
Code: [Select]
qmlRegisterType<hswidget>("someVeryAwesomeStuff", 1, 0, "HSWidget");And some explanations, if you haven't read previous tutorial:
Quote
Feel free to replace "someVeryAwesomeStuff" with anything you want. You will use this name later in QML file. Those numbers is version. "GlobalNote" is the name of our new QML object.

Now, just create an object in QML of "HSWidget" type, for example in main.qml, and you can use it, just like that:
Code: [Select]
hswidget.registerWidget()
Code: [Select]
hswidget.publishWidget()
Code: [Select]
hswidget.removeWidget()
Code: [Select]
hswidget.updateWidget(iconPath, "I really love sliced bread")
Thanks for reading, I hope you found it useful.

Sources:
« Last Edit: December 25, 2013, 02:34:57 am by Allstar12345 »

Offline huellif

  • Developer
  • Christmas Santa
  • ****
  • Posts: 402
  • Reputation: 212
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #1 on: August 19, 2013, 11:54:44 pm »
before I used it from pure Qt, but QtQuick is really nice.
Cool tutorial :)

Offline Allstar12345

  • Allstar Software Founder
  • Administrator
  • Forum Genius
  • ******
  • Posts: 5,235
  • Reputation: 812
    • Allstar Software
  • Current Phone: : OnePlus 8 Pro, Xperia 10, Nexus 6p, Jolla Phone, Nokia N8, Nokia 808 PureView, BlackBerry Z30
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #2 on: August 31, 2013, 06:47:50 pm »
I get compile errors everytime :(
Code: [Select]
In file included from C:/Users/me/FacebookTouchQt/main.cpp:26:
   C:/Users/me/FacebookTouchQt/hswidget.h: At global scope:
   C:/Users/me/FacebookTouchQt/hswidget.h:15: error: 'nRow1' has not been declared
   C:/Users/me/FacebookTouchQt/main.cpp: In function 'int main(int, char**)':
   C:/Users/me/FacebookTouchQt/main.cpp:135: error: 'hswidget' was not declared in this scope
   C:/Users/me/FacebookTouchQt/main.cpp:135: error: no matching function for call to 'qmlRegisterType(const char [9], int, int, const char [9])'

Offline pisarz1958

  • Developer
  • New Member
  • ****
  • Posts: 26
  • Reputation: 27
  • Oh, I have this little field in my profile!
  • Current Phone: : Nokia 500
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #3 on: August 31, 2013, 07:32:27 pm »
PM me your hswidget (cpp and header), I guess you've forgot to include something.

Offline Allstar12345

  • Allstar Software Founder
  • Administrator
  • Forum Genius
  • ******
  • Posts: 5,235
  • Reputation: 812
    • Allstar Software
  • Current Phone: : OnePlus 8 Pro, Xperia 10, Nexus 6p, Jolla Phone, Nokia N8, Nokia 808 PureView, BlackBerry Z30
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #4 on: December 22, 2013, 05:50:50 pm »
Still get the same errrors on another project :-/

Edit: fixed
« Last Edit: December 24, 2013, 03:36:40 am by Allstar12345 »

Offline matthew

  • Mass Poster
  • ****
  • Posts: 1,315
  • Reputation: 13
  • SymphonyOS
  • Current Phone: :
    N8-00 (25.007)
    808 (113.010.1508)
    Retired E72, E6-00
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #5 on: December 23, 2013, 12:08:10 am »
Whoa! Thanks for this tutorial, pisarz ;)

Add: This has shed a lot of light on what i have been staring at and wondering about in the HS widget framework for a while. Thanks again :)
« Last Edit: December 25, 2013, 10:35:52 pm by matthew »

Offline Allstar12345

  • Allstar Software Founder
  • Administrator
  • Forum Genius
  • ******
  • Posts: 5,235
  • Reputation: 812
    • Allstar Software
  • Current Phone: : OnePlus 8 Pro, Xperia 10, Nexus 6p, Jolla Phone, Nokia N8, Nokia 808 PureView, BlackBerry Z30
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #6 on: December 24, 2013, 03:37:15 am »
Topic Stickied.

Also you don't need to register it then import it, this seems to be working for me:
Code: [Select]
HSWidget hsWidget(&view);
            view.rootContext()->setContextProperty("HSWIDGET", &hsWidget);

« Last Edit: December 24, 2013, 03:46:25 am by Allstar12345 »

Offline pisarz1958

  • Developer
  • New Member
  • ****
  • Posts: 26
  • Reputation: 27
  • Oh, I have this little field in my profile!
  • Current Phone: : Nokia 500
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #7 on: December 24, 2013, 11:50:06 pm »
Sure, I just prefer registering because my app is already using it everywhere.

Offline Motaz

  • Developer
  • Forum User
  • ****
  • Posts: 62
  • Reputation: 72
  • Symbian Power User
  • Current Phone: : Nokia 700
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #8 on: December 25, 2013, 02:11:58 am »
Thank you pisarz1958 :)

I make some adjustments to HSWidget Plugin and I added this options:
 - Add widget icon
 - Add widget description

Just download the plugin for attachment and change the UID for it. (Use EpocID by CODeRUS)

and I make a example that update the widget from QML ;)

Offline Allstar12345

  • Allstar Software Founder
  • Administrator
  • Forum Genius
  • ******
  • Posts: 5,235
  • Reputation: 812
    • Allstar Software
  • Current Phone: : OnePlus 8 Pro, Xperia 10, Nexus 6p, Jolla Phone, Nokia N8, Nokia 808 PureView, BlackBerry Z30
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #9 on: December 25, 2013, 02:19:48 am »
Thank you pisarz1958 :)

I make some adjustments to HSWidget Plugin and I added this options:
 - Add widget icon
 - Add widget description

Just download the plugin for attachment and change the UID for it. (Use EpocID by CODeRUS)

and I make a example that update the widget from QML ;)

Excellent mate :)
+rep going your way

Offline pisarz1958

  • Developer
  • New Member
  • ****
  • Posts: 26
  • Reputation: 27
  • Oh, I have this little field in my profile!
  • Current Phone: : Nokia 500
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #10 on: December 25, 2013, 03:47:51 am »
Thank you pisarz1958 :)

I make some adjustments to HSWidget Plugin and I added this options:
 - Add widget icon
 - Add widget description

Just download the plugin for attachment and change the UID for it. (Use EpocID by CODeRUS)

and I make a example that update the widget from QML ;)
+1 rep

Really interesting changes you've made :)

Offline huellif

  • Developer
  • Christmas Santa
  • ****
  • Posts: 402
  • Reputation: 212
Re: [TUT] Homescreen Widget in QML, because - why not?
« Reply #11 on: December 26, 2013, 01:10:35 am »
nice work mate :)