Tumblelog by Soup.io
Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

May 17 2017

19:41

The rules of scuba diving

  • First rule. You must understand the rules of scuba diving. If you don’t know or understand the rules of scuba diving, go to the second rule.
  • The second rule is that you never dive alone.
  • The third rule is that you always keep close enough to each other to perform a rescue of any kind.
  • The forth rule is that you signal each other and therefor know each other’s signals. Underwater, communication is key.
  • The fifth rule is that you tell the others, for example, when you don’t feel well. The others want to know when you emotionally don’t feel well. Whenever you are insecure, you tell them. This is hard.
  • The sixth rule is that you don’t violate earlier agreed upon rules.
  • The seventh rule is that given rules will be eclipsed the moment any form of panic occurs, you will restore the rules using rationalism first, pragmatism next but emotional feelings last. No matter what.
  • The eighth rule is that the seventh rule is key to survival.

These rules make scuba diving an excellent learning school for software development project managers.

0 Add to favourites0 Bury

May 11 2017

20:09

How do they do it? Asynchronous undo and redo editors

Imagine we want an editor that has undo and redo capability. But the operations on the editor are all asynchronous. This implies that also undo and redo are asynchronous operations.

We want all this to be available in QML, we want to use QFuture for the asynchronous stuff and we want to use QUndoCommand for the undo and redo capability.

But how do they do it?

First of all we will make a status object, to put the status of the asynchronous operations in (asyncundoable.h).

class AbstractAsyncStatus: public QObject
{
    Q_OBJECT

    Q_PROPERTY(bool success READ success CONSTANT)
    Q_PROPERTY(int extra READ extra CONSTANT)
public:
    AbstractAsyncStatus(QObject *parent):QObject (parent) {}
    virtual bool success() = 0;
    virtual int extra() = 0;
};

We will be passing it around as a QSharedPointer, so that lifetime management becomes easy. But typing that out is going to give us long APIs. So let’s make a typedef for that (asyncundoable.h).

typedef QSharedPointer<AbstractAsyncStatus> AsyncStatusInstance;

Now let’s make ourselves a undo command that allows us to wait for asynchronous undo and asynchronous redo. We’re combining QUndoCommand and QFutureInterface here (asyncundoable.h).

class AbstractAsyncUndoable: public QUndoCommand
{
public:
    AbstractAsyncUndoable( QUndoCommand *parent = nullptr )
        : QUndoCommand ( parent )
        , m_undoFuture ( new QFutureInterface<AsyncStatusInstance>() )
        , m_redoFuture ( new QFutureInterface<AsyncStatusInstance>() ) {}
    QFuture<AsyncStatusInstance> undoFuture()
        { return m_undoFuture->future(); }
    QFuture<AsyncStatusInstance> redoFuture()
        { return m_redoFuture->future(); }

protected:
    QScopedPointer<QFutureInterface<AsyncStatusInstance> > m_undoFuture;
    QScopedPointer<QFutureInterface<AsyncStatusInstance> > m_redoFuture;

};

Okay, let’s implement these with an example operation. First the concrete status object (asyncexample1command.h).

class AsyncExample1Status: public AbstractAsyncStatus
{
    Q_OBJECT
    Q_PROPERTY(bool example1 READ example1 CONSTANT)
public:
    AsyncExample1Status ( bool success, int extra, bool example1,
                          QObject *parent = nullptr )
        : AbstractAsyncStatus(parent)
        , m_example1 ( example1 )
        , m_success ( success )
        , m_extra ( extra ) {}
    bool example1() { return m_example1; }
    bool success() Q_DECL_OVERRIDE { return m_success; }
    int extra() Q_DECL_OVERRIDE { return m_extra; }
private:
    bool m_example1 = false;
    bool m_success = false;
    int m_extra = -1;
};

Let’s make a QUndoCommand that uses a timer to simulate asynchronous behavior. We could also use QtConcurrent’s run function to use a QThreadPool and QRunnable instances that also implement QFutureInterface, of course. Seasoned Qt developers know what I mean. For the sake of example, I wanted to illustrate that QFuture can also be used for asynchronous things that aren’t threads. We’ll use the lambda because QUndoCommand isn’t a QObject, so no easy slots. That’s the only reason (asyncexample1command.h).

class AsyncExample1Command: public AbstractAsyncUndoable
{
public:
    AsyncExample1Command(bool example1, QUndoCommand *parent = nullptr)
        : AbstractAsyncUndoable ( parent ), m_example1(example1) {}
    void undo() Q_DECL_OVERRIDE {
        m_undoFuture->reportStarted();
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        QObject::connect(timer, &QTimer::timeout, [=]() {
            QSharedPointer<AbstractAsyncStatus> result;
            result.reset(new AsyncExample1Status ( true, 1, m_example1 ));
            m_undoFuture->reportFinished(&result);
            timer->deleteLater();
        } );
        timer->start(1000);
    }
    void redo() Q_DECL_OVERRIDE {
        m_redoFuture->reportStarted();
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        QObject::connect(timer, &QTimer::timeout, [=]() {
            QSharedPointer<AbstractAsyncStatus> result;
            result.reset(new AsyncExample1Status ( true, 2, m_example1 ));
            m_redoFuture->reportFinished(&result);
            timer->deleteLater();
        } );
        timer->start(1000);
    }
private:
    QTimer m_timer;
    bool m_example1;
};

Let’s now define something we get from the strategy design pattern; a editor behavior. Implementations provide an editor all its editing behaviors (abtracteditorbehavior.h).

class AbstractEditorBehavior : public QObject
{
    Q_OBJECT
public:
    AbstractEditorBehavior( QObject *parent) : QObject (parent) {}

    virtual QFuture<AsyncStatusInstance> performExample1( bool example1 ) = 0;
    virtual QFuture<AsyncStatusInstance> performUndo() = 0;
    virtual QFuture<AsyncStatusInstance> performRedo() = 0;
    virtual bool canRedo() = 0;
    virtual bool canUndo() = 0;
};

So far so good, so let’s make an implementation that has a QUndoStack and that therefor is undoable (undoableeditorbehavior.h).

class UndoableEditorBehavior: public AbstractEditorBehavior
{
public:
    UndoableEditorBehavior(QObject *parent = nullptr)
        : AbstractEditorBehavior (parent)
        , m_undoStack ( new QUndoStack ){}

    QFuture<AsyncStatusInstance> performExample1( bool example1 ) Q_DECL_OVERRIDE {
        AsyncExample1Command *command = new AsyncExample1Command ( example1 );
        m_undoStack->push(command);
        return command->redoFuture();
    }
    QFuture<AsyncStatusInstance> performUndo() {
        const AbstractAsyncUndoable *undoable =
            dynamic_cast<const AbstractAsyncUndoable *>(
                    m_undoStack->command( m_undoStack->index() - 1));
        m_undoStack->undo();
        return const_cast<AbstractAsyncUndoable*>(undoable)->undoFuture();
    }
    QFuture<AsyncStatusInstance> performRedo() {
        const AbstractAsyncUndoable *undoable =
            dynamic_cast<const AbstractAsyncUndoable *>(
                    m_undoStack->command( m_undoStack->index() ));
        m_undoStack->redo();
        return const_cast<AbstractAsyncUndoable*>(undoable)->redoFuture();
    }
    bool canRedo() Q_DECL_OVERRIDE { return m_undoStack->canRedo(); }
    bool canUndo() Q_DECL_OVERRIDE { return m_undoStack->canUndo(); }
private:
    QScopedPointer<QUndoStack> m_undoStack;
};

Now we only need an editor, right (editor.h)?

class Editor: public QObject
{
    Q_OBJECT
    Q_PROPERTY(AbstractEditorBehavior* editorBehavior READ editorBehavior CONSTANT)
public:
    Editor(QObject *parent=nullptr) : QObject(parent)
        , m_editorBehavior ( new UndoableEditorBehavior ) { }
    AbstractEditorBehavior* editorBehavior() { return m_editorBehavior.data(); }
    Q_INVOKABLE void example1Async(bool example1) {
        QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
        connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                this, &Editor::onExample1Finished);
        watcher->setFuture ( m_editorBehavior->performExample1(example1) );
    }
    Q_INVOKABLE void undoAsync() {
        if (m_editorBehavior->canUndo()) {
            QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
            connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                    this, &Editor::onUndoFinished);
            watcher->setFuture ( m_editorBehavior->performUndo() );
        }
    }
    Q_INVOKABLE void redoAsync() {
        if (m_editorBehavior->canRedo()) {
            QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
            connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                    this, &Editor::onRedoFinished);
            watcher->setFuture ( m_editorBehavior->performRedo() );
        }
    }
signals:
    void example1Finished( AsyncExample1Status *status );
    void undoFinished( AbstractAsyncStatus *status );
    void redoFinished( AbstractAsyncStatus *status );
private slots:
    void onExample1Finished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit example1Finished( watcher->result().objectCast<AsyncExample1Status>().data() );
        watcher->deleteLater();
    }
    void onUndoFinished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit undoFinished( watcher->result().objectCast<AbstractAsyncStatus>().data() );
        watcher->deleteLater();
    }
    void onRedoFinished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit redoFinished( watcher->result().objectCast<AbstractAsyncStatus>().data() );
        watcher->deleteLater();
    }
private:
    QScopedPointer<AbstractEditorBehavior> m_editorBehavior;
};

Okay, let’s register this up to make it known in QML and make ourselves a main function (main.cpp).

#include <QtQml>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <editor.h>
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    qmlRegisterType<Editor>("be.codeminded.asyncundo", 1, 0, "Editor");
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

Now, let’s make ourselves a simple QML UI to use this with (main.qml).

import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
import be.codeminded.asyncundo 1.0
Window {
    visible: true
    width: 360
    height: 360
    Editor {
        id: editor
        onUndoFinished: text.text = "undo"
        onRedoFinished: text.text = "redo"
        onExample1Finished: text.text = "whoohoo " + status.example1
    }
    Text {
        id: text
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
    Action {
        shortcut: "Ctrl+z"
        onTriggered: editor.undoAsync()
    }
    Action {
        shortcut: "Ctrl+y"
        onTriggered: editor.redoAsync()
    }
    Button  {
        onClicked: editor.example1Async(99);
    }
}

You can find the sources of this complete example at github. Enjoy!

0 Add to favourites0 Bury

April 30 2017

10:16

Q2 2017 Community Council Election Announcement

Dear friends and Maemoans. It is again the time for us to elect the new Community Council.

The schedule for the voting process is as follows:

  • The nomination period starts next Monday, on the 1st of May 2017 and will continue until the 23rd of May 2017.
  • The election starts on Thursday, on the 1st of June 2017 and will continue until the 7th of June 2017. In order for us to keep the community strong, we need to have new people with fresh ideas to carry on the torch. So, please consider volunteering for the position of Maemo Council.

    On behalf of the outgoing Community Council,

    eekkelund

0 Add to favourites0 Bury

April 20 2017

00:00

Atreus: Building a custom ergonomic keyboard

As mentioned in my Working on Android post, I’ve been using a mechanical keyboard for a couple of years now. Now that I work on Flowhub from home, it was a good time to re-evaluate the whole work setup. As far as regular keyboards go, the MiniLa was nice, but I wanted something more compact and ergonomic.

The Atreus keyboard

My new Atreus

Atreus is a 40% ergonomic mechanical keyboard designed by Phil Hagelberg. It is an open hardware design, but he also sells kits for easier construction. From the kit introduction:

The Atreus is a small mechanical keyboard that is based around the shape of the human hand. It combines the comfort of a split ergonomic keyboard with the crisp key action of mechanical switches, all while fitting into a tiny profile.

My use case was also quite travel-oriented. I wanted a small keyboard that would enable me to work with it also on the road. There are many other small-ish DIY keyboard designs like Planck and Gherkin available, but Atreus had the advantage of better ergonomics. I really liked the design of the Ergodox keyboard, and Atreus essentially is that made mobile:

I found the split halves and relatively large size (which are fantastic for stationary use at a desk) make me reluctant to use it on the lap, at a coffee shop, or on the couch, so that’s the primary use case I’ve targeted with the Atreus. It still has most of the other characteristics that make the Ergodox stand out, like mechanical Cherry switches, staggered columns instead of rows, heavy usage of the thumbs, and a hackable microcontroller with flexible firmware, but it’s dramatically smaller and lighter

I had the opportunity to try a kit-built Atreus in the Berlin Mechanical Keyboard meetup, and it felt nice. It was time to start the project.

Sourcing the parts

When building an Atreus the first decision is whether to go with the kit or hand-wire it yourself. Building from a kit is certainly easier, but since I’m a member of a hackerspace, doing a hand-wired build seemed like the way to go.

To build a custom keyboard, you need:

  • Switches: in my case 37 Cherry MX blues and 5 Cherry MX blacks
  • Diodes: one 1N4148 per switch
  • Microcontroller: a Arduino Pro Micro on my keyboard
  • Keycaps: started with recycled ones and later upgraded to DSA blanks
  • Case: got a set of laset-cut steel plates

Even though Cherry — the maker of the most common mechanical key switches — is a German company, it is quite difficult to get switches in retail here. Luckily a fellow hackerspace member had just dismantled some old mechanical keyboards, and so I was able to get the switches I needed via barter.

Keyswitches

The Cherry MX blues are tactile clicky switches that feel super-nice to type on, but are quite loud. For modifiers I went with Cherry MX blacks that are linear. This way there is quite a clear difference in feel between keys you typically hold down compared to the ones you just press.

The diodes and the microcontroller I ordered from Amazon for about 20€ total.

Arduino Pro Micro

At first I used a set of old keycaps that I got with the switches, but once the keyboard was up and running I upgraded to a very nice set of blank DSA-profile keycaps that I ordered from AliExpress for 30€. That set came with enough keycaps that I’ll have myself covered if I ever build a second Atreus.

All put together, I think the parts ended up costing me around 100€ total.

Preparations

When I received all the parts, there were some preparation steps to be made. Since the key switches were 2nd hand, I had to start by dismantling them and removing old diodes that had been left inside some of them.

Opening the key switches

The keycaps I had gotten with the switches were super grimy, and so I ended up sending them to the washing machine. After that you could see that they were not new, but at least they were clean.

With the steel mounting plate there had been a slight misunderstading, and the plates I received were a few millimeters thicker than needed, so the switches wouldn’t “click” in place. While this could’ve been worked around with hot glue, we ended up filing the mounting holes down to the right thickness.

Filing the plate

Little bit of help

Wiring the keyboard

Once the mounting plate was in the right shape, I clicked the switches in and it was time to solder.

All switches in place

Hand-wiring keyboards is not that tricky. You have to attach a diode to each keyswitch, and then connect each row together via the diodes.

Connecting diodes

First row ready

The two thumb keys are wired to be on the same column, but different rows.

All rows ready diodes

Then each column is connected together via the other pin on the switches.

Soldering columns

This is how the matrix looks like:

Completed matrix

After these are done, connect a wire from each column, and each row to a I/O pin on the microcontroller.

Adding column wires

If you haven’t done it earlier, this is a good stage to test all connections with a multimeter!

Connecting the microcontroller

Firmware

After finishing the wiring, I downloaded the QMK firmware, changed the PIN mapping for how my Atreus is wired up, switched the layout to Colemak, and the keyboard was ready to go.

Atreus in use

Don’t mind the key labels in the picture above. These are the second-hand keycaps I started with. Since then I’ve switched to blank ones.

USB-C

The default Atreus design has the USB cable connected directly to the microcontroller, meaning that you’ll have to open the case to change the cable. To mitigate that I wanted to add a USB breakout board to the project, and this being 2017, it felt right to go with USB-C.

USB-C breakouts

I found some cheap USB-C breakout boards from AliExpress. Once they arrived, it was time to figure out how the spec works. Since USB-C is quite new, there are very few resources available on how to use it with microcontrollers. These tutorials were quite helpful:

Here is how we ended up wiring the breakout board. After these you only have four wires to connect to the microcontroller: ground, power, and the positive and negative data pins.

USB-C breakout with wiring

This Atreus build log was useful for figuring out where to connect the USB wires on the Pro Micro. Once all was done, I had a custom, USB-C keyboard!

USB-C keyboard

Next steps

Now I have the Atreus working nicely on my new standing desk. Learning Colemak is a bit painful, but the keyboard itself feels super nice!

New standing desk

However, I’d still like to CNC mill a proper wooden case for the keyboard. I may update this post once that happens.

I’m also considering to order an Atreus kit so I’d have a second, always packed for travel keyboard. The kit comes with a PCB, which might work better at airport security checks than the hand-wired build.

Another thing that is quite tempting is to make a custom firmware with MicroFlo. I have no complaints on how QMK works, but it’d be super-cool to use our visual programming tool to tweak the keyboard live.

Big thanks to Technomancy for the Atreus design, and to XenGi for all the help during the build!

0 Add to favourites0 Bury

April 13 2017

21:32

Asynchronous undoable and redoable APIs

Combining QFuture with QUndoCommand made a lot of sense for us. The undo and the redo methods of the QUndoCommand can also be asynchronous, of course. We wanted to use QFuture without involving threads, because our asynchronosity is done through a process and IPC, and not a thread. It’s the design mistake of QtConcurrent‘s run method, in my opinion. That meant using QFutureInterface instead (which is undocumented, but luckily public – so it’ll remain with us until at least Qt’s 6.y.z releases).

So how do we make a QUndoCommand that has a undo, and that has a redo method that returns a asynchronous QFuture<ResultType>?

We just did that, today. I’m very satisfied with the resulting API and design. It might have helped if QUndoStack would be a QUndoStack<T> and QUndoCommand would have been a QUndoCommand<T> with undo and redo’s return type being T. Just an idea for the Qt 6.y.z developers.

I’m not telling you today, because I want this to settle in our project first. I’m sure we will find problems.

0 Add to favourites0 Bury

April 10 2017

19:07

Looking for new adventures

Yes, I'm looking for a job. :-)

These six years I've spent at Canonical have literally been flying. I enjoyed my work from the very first day, when I was assigned to the Unity 2D team, developing a lightweight desktop environment for Ubuntu, though I stayed in that team just for a few weeks. The next task, which I've been carrying on till today, has been implementing the Online Accounts feature in Ubuntu; this project has been especially dear to me, given that I got to reuse and improve much of the work we developed for the Nokia N9 phone. Seeing it being adopted also by Sailfish OS and KDE has been a major satisfaction, and a proof that we were on the right track. And indeed, porting the UI to Qt/QML for running in Unity 8, plus extending and simplifying the APIs and helping with the development of client applications has been a fantastic ride.
In the times where calm was reigning in the project, I reached out to other teams and offered help, mainly for improving the geolocation service and the webapps project.

Unfortunately, with the decision to terminate the development of Unity8 and to set aside the convergence goals, all of the above is no longer relevant for Canonical's future and I, along many other developers, have left the company.

So, here's my CV.

Given that reading is boring, here's a few pictures (and even a video!) of programs I've done, not as part of my daily work but in my spare time; though, to be honest, I do enjoy middleware and logic development (and even kernel, though I got little chances to work on that so far) more than UI development:
Imaginario on the Ubuntu phone
Imaginario for your desktop (under development)
If you wish to see my code, please have a look at my gitlab, github and launchpad accounts.


0 Add to favourites0 Bury
Reposted byElbenfreund Elbenfreund

March 24 2017

09:42

Making something that is undoable editable with Qt

Among the problems we’ll face is that we want asynchronous APIs that are undoable and that we want to switch to read only, undoable editing, non-undoable editing and that QML doesn’t really work well with QFuture. At least not yet. We want an interface that is easy to talk with from QML. Yet we want to switch between complicated behaviors.

We will also want synchronous mode and asynchronous mode. Because I just invented that requirement out of thin air.

Ok, first the “design”. We see a lot of behaviors, for something that can do something. The behaviors will perform for that something, the actions it can do. That is obviously the strategy design pattern, then. Right? That’s the one about ducks and wing fly behavior and rocket propelled fly behavior and then the ostrich that has a can’t fly behavior. And undo and redo, that certainly sounds like the command pattern. We also have this neat thing in Qt for that. We’ll use it. We don’t reinvent the wheel. Reinventing the wheel is stupid.

Let’s create the duck. I mean, the thing-editor. As I will use “Thing” for the thing that is being edited. We want copy (sync is sufficient), paste (must be aysnc), and edit (must be async). We could also have insert and delete, but those APIs would be just like edit. And that would make the example only longer. Paste would usually be similar to insert, of course. Except that it can be a combined delete and insert when overwriting content. The command pattern allows you to make such combinations. Not the purpose of this example, though.

Enough explanation for a blog. Let’s start! The ThingEditor, is like the flying Duck in strategy. This is going to be more or less the API that we will present to the QML world. It could be your ViewModel, for example (ie. you could let your ThingViewModel subclass ThingEditor).

class ThingEditor : public QObject
{
    Q_OBJECT

    Q_PROPERTY ( ThingEditingBehavior* editingBehavior READ editingBehavior
                 WRITE setEditingBehavior NOTIFY editingBehaviorChanged )
    Q_PROPERTY ( Thing* thing READ thing WRITE setThing NOTIFY thingChanged )

public:
    explicit ThingEditor( QSharedPointer<Thing> &a_thing,
            ThingEditingBehavior *a_editBehavior,
            QObject *a_parent = nullptr );

    explicit ThingEditor( QObject *a_parent = nullptr );

    Thing* thing() const { return m_thing.data(); }
    virtual void setThing( QSharedPointer<Thing> &a_thing );
    virtual void setThing( Thing *a_thing );

    ThingEditingBehavior* editingBehavior() const { return m_editingBehavior.data(); }
    virtual void setEditingBehavior ( ThingEditingBehavior *a_editingBehavior );

    Q_INVOKABLE virtual void copyCurrentToClipboard ( );
    Q_INVOKABLE virtual void editCurrentAsync( const QString &a_value );
    Q_INVOKABLE virtual void pasteCurrentFromClipboardAsync( );

signals:
    void editingBehaviorChanged ();
    void thingChanged();
    void editCurrentFinished( EditCurrentCommand *a_command );
    void pasteCurrentFromClipboardFinished( EditCurrentCommand *a_command );

private slots:
    void onEditCurrentFinished();
    void onPasteCurrentFromClipboardFinished();

private:
    QScopedPointer<ThingEditingBehavior> m_editingBehavior;
    QSharedPointer<Thing> m_thing;
    QList<QFutureWatcher<EditCurrentCommand*> *> m_editCurrentFutureWatchers;
    QList<QFutureWatcher<EditCurrentCommand*> *> m_pasteCurrentFromClipboardFutureWatchers;
};

For the implementation of this class, I’ll only provide the non-obvious pieces. I’m sure you can do that setThing, setEditingBehavior and the constructor yourself. I’m also providing it only once, and also only for the EditCurrentCommand. The one about paste is going to be exactly the same.

void ThingEditor::copyCurrentToClipboard ( )
{
    m_editingBehavior->copyCurrentToClipboard( );
}

void ThingEditor::onEditCurrentFinished( )
{
    QFutureWatcher<EditCurrentCommand*> *resultWatcher
            = static_cast<QFutureWatcher<EditCurrentCommand*>*> ( sender() );
    emit editCurrentFinished ( resultWatcher->result() );
    if (m_editCurrentFutureWatchers.contains( resultWatcher )) {
        m_editCurrentFutureWatchers.removeAll( resultWatcher );
    }
    delete resultWatcher;
}

void ThingEditor::editCurrentAsync( const QString &a_value )
{
    QFutureWatcher<EditCurrentCommand*> *resultWatcher
            = new QFutureWatcher<EditCurrentCommand*>();
    connect ( resultWatcher, &QFutureWatcher<EditCurrentCommand*>::finished,
              this, &ThingEditor::onEditCurrentFinished, Qt::QueuedConnection );
    resultWatcher->setFuture ( m_editingBehavior->editCurrentAsync( a_value ) );
    m_editCurrentFutureWatchers.append ( resultWatcher );
}

For QUndo we’ll need a QUndoCommand. For each undoable action we indeed need to make such a command. No worries, it’s easy. You could add more state and pass it to the constructor. It’s common, for example, to pass Thing, or the ThingEditor or the behavior (this is why I used QSharedPointer for those: as long as your command lives in the stack, you’ll need it to hold a reference to that state).

class EditCurrentCommand: public QUndoCommand
{
public:
    explicit EditCurrentCommand( const QString &a_value,
                                 QUndoCommand *a_parent = nullptr )
        : QUndoCommand ( a_parent )
        , m_value ( a_value ) { }
    void redo() Q_DECL_OVERRIDE {
       // Perform action goes here
    }
    void undo() Q_DECL_OVERRIDE {
      // Undo what got performed goes here
    }
private:
    const QString &m_value;
};

You can (and probably should) also make this one abstract (and/or a so called pure interface), as you’ll usually want many implementations of this one (one for every kind of editing behavior). This is like the fly behavior in the duck that flies -example of strategy. Note that it leaks the QUndoCommand instances unless you handle them (ie. storing them in a QUndoStack). That in itself is a good reason to call the thing abstract.

class ThingEditingBehavior : public QObject
{
    Q_OBJECT

    Q_PROPERTY ( ThingEditor* editor READ editor WRITE setEditor NOTIFY editorChanged )
    Q_PROPERTY ( Thing* thing READ thing NOTIFY thingChanged )

public:
    explicit ThingEditingBehavior( ThingEditor *a_editor,
                                   QObject *a_parent = nullptr )
        : QObject ( a_parent )
        , m_editor ( a_editor ) { }

    explicit ThingEditingBehavior( QObject *a_parent = nullptr )
        : QObject ( a_parent ) { }

    ThingEditor* editor() const { return m_editor.data(); }
    virtual void setEditor( ThingEditor *a_editor );
    Thing* thing() const;

    virtual void copyCurrentToClipboard ( );
    virtual QFuture<EditCurrentCommand*> editCurrentAsync( const QString &a_value, bool a_exec = true );
    virtual QFuture<EditCurrentCommand*> pasteCurrentFromClipboardAsync( bool a_exec = true );

protected:
    virtual EditCurrentCommand* editCurrentSync( const QString &a_value, bool a_exec = true );
    virtual EditCurrentCommand* pasteCurrentFromClipboardSync( bool a_exec = true );

signals:
    void editorChanged();
    void thingChanged();

private:
    QPointer<ThingEditor> m_editor;
    bool m_synchronous = true;
};

That setEditor, the constructor, etc: these are too obvious to write here. You can do that yourself. Right? Here are the non-obvious ones:

void ThingEditingBehavior::copyToClipboard ( )
{
    Q_UNUSED (a_row);
    // TODO: Implementation of copying the current to clipboard. See QClipboard
}

EditCurrentCommand* ThingEditingBehavior::editCurrentSync( const QString &a_value, bool a_exec )
{
    EditCurrentCommand *ret = new EditCurrentCommand ( a_value );
    if ( a_exec )
        ret->redo();
    return ret;
}

QFuture<EditCurrentCommand*> ThingEditingBehavior::editCurrentAsync( const QString &a_value, bool a_exec )
{
    QFuture<EditCurrentCommand*> resultFuture =
            QtConcurrent::run( QThreadPool::globalInstance(), this,
                               &ThingEditingBehavior::editCurrentSync,
                               a_value, a_exec );
    if (m_synchronous)
        resultFuture.waitForFinished();
    return resultFuture;
}

And now we can finally make the whole thing undoable by making a undoable editing behavior. That’s like the fly with wings behavior of the duck that flies -example of strategy. The edit with undoable behavior of the Thing editor. Right? I’ll leave a non-undoable editing behavior as an exercise to the reader (ie. just perform redo() on the QUndoCommand, don’t store it in the QUndoStack and immediately delete or cmd->deleteLater() the instance).

Note that if m_synchronous is false, that (all access to) m_undoStack must be (made) thread-safe. The thread-safety is not the purpose of this example, though.

class UndoableThingEditingBehavior : public ThingEditingBehavior
{
    Q_OBJECT
public:
    explicit UndoableThingEditingBehavior( ThingEditor *a_editor,
                                           QObject *a_parent = nullptr );
protected:
    EditCellCommand* editCurrentSync( const QString &a_value, bool a_exec = true ) Q_DECL_OVERRIDE;
    EditCurrentCommand* pasteCurrentFromClipboardSync( bool a_exec = true ) Q_DECL_OVERRIDE;
private:
    QScopedPointer<QUndoStack> m_undoStack;
};

EditCellCommand* UndoableThingEditingBehavior::editCurrentSync( const QString &a_value, bool a_exec )
{
    Q_UNUSED(a_exec)
    EditCellCommand *undoable = ThingEditingBehavior::editCurrentSync(  a_value, false );
    m_undoStack->push( undoable );
    return undoable;
}

EditCellCommand* UndoableThingEditingBehavior::pasteCurrentFromClipboardSync( bool a_exec )
{
    Q_UNUSED(a_exec)
    EditCellCommand *undoable = ThingEditingBehavior::pasteCurrentFromClipboardSync( false );
    m_undoStack->push( undoable );
    return undoable;
}
0 Add to favourites0 Bury

March 23 2017

00:17

Perfection

Perfection has been reached not when there is nothing left to add, but when there is nothing left to take away.

0 Add to favourites0 Bury

May 17 2017

19:41

The rules of scuba diving

  • First rule. You must understand the rules of scuba diving. If you don’t know or understand the rules of scuba diving, go to the second rule.
  • The second rule is that you never dive alone.
  • The third rule is that you always keep close enough to each other to perform a rescue of any kind.
  • The forth rule is that you signal each other and therefor know each other’s signals. Underwater, communication is key.
  • The fifth rule is that you tell the others, for example, when you don’t feel well. The others want to know when you emotionally don’t feel well. Whenever you are insecure, you tell them. This is hard.
  • The sixth rule is that you don’t violate earlier agreed upon rules.
  • The seventh rule is that given rules will be eclipsed the moment any form of panic occurs, you will restore the rules using rationalism first, pragmatism next but emotional feelings last. No matter what.
  • The eighth rule is that the seventh rule is key to survival.

These rules make scuba diving an excellent learning school for software development project managers.

0 Add to favourites0 Bury

May 11 2017

20:09

How do they do it? Asynchronous undo and redo editors

Imagine we want an editor that has undo and redo capability. But the operations on the editor are all asynchronous. This implies that also undo and redo are asynchronous operations.

We want all this to be available in QML, we want to use QFuture for the asynchronous stuff and we want to use QUndoCommand for the undo and redo capability.

But how do they do it?

First of all we will make a status object, to put the status of the asynchronous operations in (asyncundoable.h).

class AbstractAsyncStatus: public QObject
{
    Q_OBJECT

    Q_PROPERTY(bool success READ success CONSTANT)
    Q_PROPERTY(int extra READ extra CONSTANT)
public:
    AbstractAsyncStatus(QObject *parent):QObject (parent) {}
    virtual bool success() = 0;
    virtual int extra() = 0;
};

We will be passing it around as a QSharedPointer, so that lifetime management becomes easy. But typing that out is going to give us long APIs. So let’s make a typedef for that (asyncundoable.h).

typedef QSharedPointer<AbstractAsyncStatus> AsyncStatusInstance;

Now let’s make ourselves a undo command that allows us to wait for asynchronous undo and asynchronous redo. We’re combining QUndoCommand and QFutureInterface here (asyncundoable.h).

class AbstractAsyncUndoable: public QUndoCommand
{
public:
    AbstractAsyncUndoable( QUndoCommand *parent = nullptr )
        : QUndoCommand ( parent )
        , m_undoFuture ( new QFutureInterface<AsyncStatusInstance>() )
        , m_redoFuture ( new QFutureInterface<AsyncStatusInstance>() ) {}
    QFuture<AsyncStatusInstance> undoFuture()
        { return m_undoFuture->future(); }
    QFuture<AsyncStatusInstance> redoFuture()
        { return m_redoFuture->future(); }

protected:
    QScopedPointer<QFutureInterface<AsyncStatusInstance> > m_undoFuture;
    QScopedPointer<QFutureInterface<AsyncStatusInstance> > m_redoFuture;

};

Okay, let’s implement these with an example operation. First the concrete status object (asyncexample1command.h).

class AsyncExample1Status: public AbstractAsyncStatus
{
    Q_OBJECT
    Q_PROPERTY(bool example1 READ example1 CONSTANT)
public:
    AsyncExample1Status ( bool success, int extra, bool example1,
                          QObject *parent = nullptr )
        : AbstractAsyncStatus(parent)
        , m_example1 ( example1 )
        , m_success ( success )
        , m_extra ( extra ) {}
    bool example1() { return m_example1; }
    bool success() Q_DECL_OVERRIDE { return m_success; }
    int extra() Q_DECL_OVERRIDE { return m_extra; }
private:
    bool m_example1 = false;
    bool m_success = false;
    int m_extra = -1;
};

Let’s make a QUndoCommand that uses a timer to simulate asynchronous behavior. We could also use QtConcurrent’s run function to use a QThreadPool and QRunnable instances that also implement QFutureInterface, of course. Seasoned Qt developers know what I mean. For the sake of example, I wanted to illustrate that QFuture can also be used for asynchronous things that aren’t threads. We’ll use the lambda because QUndoCommand isn’t a QObject, so no easy slots. That’s the only reason (asyncexample1command.h).

class AsyncExample1Command: public AbstractAsyncUndoable
{
public:
    AsyncExample1Command(bool example1, QUndoCommand *parent = nullptr)
        : AbstractAsyncUndoable ( parent ), m_example1(example1) {}
    void undo() Q_DECL_OVERRIDE {
        m_undoFuture->reportStarted();
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        QObject::connect(timer, &QTimer::timeout, [=]() {
            QSharedPointer<AbstractAsyncStatus> result;
            result.reset(new AsyncExample1Status ( true, 1, m_example1 ));
            m_undoFuture->reportFinished(&result);
            timer->deleteLater();
        } );
        timer->start(1000);
    }
    void redo() Q_DECL_OVERRIDE {
        m_redoFuture->reportStarted();
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        QObject::connect(timer, &QTimer::timeout, [=]() {
            QSharedPointer<AbstractAsyncStatus> result;
            result.reset(new AsyncExample1Status ( true, 2, m_example1 ));
            m_redoFuture->reportFinished(&result);
            timer->deleteLater();
        } );
        timer->start(1000);
    }
private:
    QTimer m_timer;
    bool m_example1;
};

Let’s now define something we get from the strategy design pattern; a editor behavior. Implementations provide an editor all its editing behaviors (abtracteditorbehavior.h).

class AbstractEditorBehavior : public QObject
{
    Q_OBJECT
public:
    AbstractEditorBehavior( QObject *parent) : QObject (parent) {}

    virtual QFuture<AsyncStatusInstance> performExample1( bool example1 ) = 0;
    virtual QFuture<AsyncStatusInstance> performUndo() = 0;
    virtual QFuture<AsyncStatusInstance> performRedo() = 0;
    virtual bool canRedo() = 0;
    virtual bool canUndo() = 0;
};

So far so good, so let’s make an implementation that has a QUndoStack and that therefor is undoable (undoableeditorbehavior.h).

class UndoableEditorBehavior: public AbstractEditorBehavior
{
public:
    UndoableEditorBehavior(QObject *parent = nullptr)
        : AbstractEditorBehavior (parent)
        , m_undoStack ( new QUndoStack ){}

    QFuture<AsyncStatusInstance> performExample1( bool example1 ) Q_DECL_OVERRIDE {
        AsyncExample1Command *command = new AsyncExample1Command ( example1 );
        m_undoStack->push(command);
        return command->redoFuture();
    }
    QFuture<AsyncStatusInstance> performUndo() {
        const AbstractAsyncUndoable *undoable =
            dynamic_cast<const AbstractAsyncUndoable *>(
                    m_undoStack->command( m_undoStack->index() - 1));
        m_undoStack->undo();
        return const_cast<AbstractAsyncUndoable*>(undoable)->undoFuture();
    }
    QFuture<AsyncStatusInstance> performRedo() {
        const AbstractAsyncUndoable *undoable =
            dynamic_cast<const AbstractAsyncUndoable *>(
                    m_undoStack->command( m_undoStack->index() ));
        m_undoStack->redo();
        return const_cast<AbstractAsyncUndoable*>(undoable)->redoFuture();
    }
    bool canRedo() Q_DECL_OVERRIDE { return m_undoStack->canRedo(); }
    bool canUndo() Q_DECL_OVERRIDE { return m_undoStack->canUndo(); }
private:
    QScopedPointer<QUndoStack> m_undoStack;
};

Now we only need an editor, right (editor.h)?

class Editor: public QObject
{
    Q_OBJECT
    Q_PROPERTY(AbstractEditorBehavior* editorBehavior READ editorBehavior CONSTANT)
public:
    Editor(QObject *parent=nullptr) : QObject(parent)
        , m_editorBehavior ( new UndoableEditorBehavior ) { }
    AbstractEditorBehavior* editorBehavior() { return m_editorBehavior.data(); }
    Q_INVOKABLE void example1Async(bool example1) {
        QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
        connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                this, &Editor::onExample1Finished);
        watcher->setFuture ( m_editorBehavior->performExample1(example1) );
    }
    Q_INVOKABLE void undoAsync() {
        if (m_editorBehavior->canUndo()) {
            QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
            connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                    this, &Editor::onUndoFinished);
            watcher->setFuture ( m_editorBehavior->performUndo() );
        }
    }
    Q_INVOKABLE void redoAsync() {
        if (m_editorBehavior->canRedo()) {
            QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
            connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                    this, &Editor::onRedoFinished);
            watcher->setFuture ( m_editorBehavior->performRedo() );
        }
    }
signals:
    void example1Finished( AsyncExample1Status *status );
    void undoFinished( AbstractAsyncStatus *status );
    void redoFinished( AbstractAsyncStatus *status );
private slots:
    void onExample1Finished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit example1Finished( watcher->result().objectCast<AsyncExample1Status>().data() );
        watcher->deleteLater();
    }
    void onUndoFinished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit undoFinished( watcher->result().objectCast<AbstractAsyncStatus>().data() );
        watcher->deleteLater();
    }
    void onRedoFinished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit redoFinished( watcher->result().objectCast<AbstractAsyncStatus>().data() );
        watcher->deleteLater();
    }
private:
    QScopedPointer<AbstractEditorBehavior> m_editorBehavior;
};

Okay, let’s register this up to make it known in QML and make ourselves a main function (main.cpp).

#include <QtQml>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <editor.h>
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    qmlRegisterType<Editor>("be.codeminded.asyncundo", 1, 0, "Editor");
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

Now, let’s make ourselves a simple QML UI to use this with (main.qml).

import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
import be.codeminded.asyncundo 1.0
Window {
    visible: true
    width: 360
    height: 360
    Editor {
        id: editor
        onUndoFinished: text.text = "undo"
        onRedoFinished: text.text = "redo"
        onExample1Finished: text.text = "whoohoo " + status.example1
    }
    Text {
        id: text
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
    Action {
        shortcut: "Ctrl+z"
        onTriggered: editor.undoAsync()
    }
    Action {
        shortcut: "Ctrl+y"
        onTriggered: editor.redoAsync()
    }
    Button  {
        onClicked: editor.example1Async(99);
    }
}

You can find the sources of this complete example at github. Enjoy!

0 Add to favourites0 Bury

April 30 2017

10:16

Q2 2017 Community Council Election Announcement

Dear friends and Maemoans. It is again the time for us to elect the new Community Council.

The schedule for the voting process is as follows:

  • The nomination period starts next Monday, on the 1st of May 2017 and will continue until the 23rd of May 2017.
  • The election starts on Thursday, on the 1st of June 2017 and will continue until the 7th of June 2017. In order for us to keep the community strong, we need to have new people with fresh ideas to carry on the torch. So, please consider volunteering for the position of Maemo Council.

    On behalf of the outgoing Community Council,

    eekkelund

0 Add to favourites0 Bury

April 20 2017

00:00

Atreus: Building a custom ergonomic keyboard

As mentioned in my Working on Android post, I’ve been using a mechanical keyboard for a couple of years now. Now that I work on Flowhub from home, it was a good time to re-evaluate the whole work setup. As far as regular keyboards go, the MiniLa was nice, but I wanted something more compact and ergonomic.

The Atreus keyboard

My new Atreus

Atreus is a 40% ergonomic mechanical keyboard designed by Phil Hagelberg. It is an open hardware design, but he also sells kits for easier construction. From the kit introduction:

The Atreus is a small mechanical keyboard that is based around the shape of the human hand. It combines the comfort of a split ergonomic keyboard with the crisp key action of mechanical switches, all while fitting into a tiny profile.

My use case was also quite travel-oriented. I wanted a small keyboard that would enable me to work with it also on the road. There are many other small-ish DIY keyboard designs like Planck and Gherkin available, but Atreus had the advantage of better ergonomics. I really liked the design of the Ergodox keyboard, and Atreus essentially is that made mobile:

I found the split halves and relatively large size (which are fantastic for stationary use at a desk) make me reluctant to use it on the lap, at a coffee shop, or on the couch, so that’s the primary use case I’ve targeted with the Atreus. It still has most of the other characteristics that make the Ergodox stand out, like mechanical Cherry switches, staggered columns instead of rows, heavy usage of the thumbs, and a hackable microcontroller with flexible firmware, but it’s dramatically smaller and lighter

I had the opportunity to try a kit-built Atreus in the Berlin Mechanical Keyboard meetup, and it felt nice. It was time to start the project.

Sourcing the parts

When building an Atreus the first decision is whether to go with the kit or hand-wire it yourself. Building from a kit is certainly easier, but since I’m a member of a hackerspace, doing a hand-wired build seemed like the way to go.

To build a custom keyboard, you need:

  • Switches: in my case 37 Cherry MX blues and 5 Cherry MX blacks
  • Diodes: one 1N4148 per switch
  • Microcontroller: a Arduino Pro Micro on my keyboard
  • Keycaps: started with recycled ones and later upgraded to DSA blanks
  • Case: got a set of laset-cut steel plates

Even though Cherry — the maker of the most common mechanical key switches — is a German company, it is quite difficult to get switches in retail here. Luckily a fellow hackerspace member had just dismantled some old mechanical keyboards, and so I was able to get the switches I needed via barter.

Keyswitches

The Cherry MX blues are tactile clicky switches that feel super-nice to type on, but are quite loud. For modifiers I went with Cherry MX blacks that are linear. This way there is quite a clear difference in feel between keys you typically hold down compared to the ones you just press.

The diodes and the microcontroller I ordered from Amazon for about 20€ total.

Arduino Pro Micro

At first I used a set of old keycaps that I got with the switches, but once the keyboard was up and running I upgraded to a very nice set of blank DSA-profile keycaps that I ordered from AliExpress for 30€. That set came with enough keycaps that I’ll have myself covered if I ever build a second Atreus.

All put together, I think the parts ended up costing me around 100€ total.

Preparations

When I received all the parts, there were some preparation steps to be made. Since the key switches were 2nd hand, I had to start by dismantling them and removing old diodes that had been left inside some of them.

Opening the key switches

The keycaps I had gotten with the switches were super grimy, and so I ended up sending them to the washing machine. After that you could see that they were not new, but at least they were clean.

With the steel mounting plate there had been a slight misunderstading, and the plates I received were a few millimeters thicker than needed, so the switches wouldn’t “click” in place. While this could’ve been worked around with hot glue, we ended up filing the mounting holes down to the right thickness.

Filing the plate

Little bit of help

Wiring the keyboard

Once the mounting plate was in the right shape, I clicked the switches in and it was time to solder.

All switches in place

Hand-wiring keyboards is not that tricky. You have to attach a diode to each keyswitch, and then connect each row together via the diodes.

Connecting diodes

First row ready

The two thumb keys are wired to be on the same column, but different rows.

All rows ready diodes

Then each column is connected together via the other pin on the switches.

Soldering columns

This is how the matrix looks like:

Completed matrix

After these are done, connect a wire from each column, and each row to a I/O pin on the microcontroller.

Adding column wires

If you haven’t done it earlier, this is a good stage to test all connections with a multimeter!

Connecting the microcontroller

Firmware

After finishing the wiring, I downloaded the QMK firmware, changed the PIN mapping for how my Atreus is wired up, switched the layout to Colemak, and the keyboard was ready to go.

Atreus in use

Don’t mind the key labels in the picture above. These are the second-hand keycaps I started with. Since then I’ve switched to blank ones.

USB-C

The default Atreus design has the USB cable connected directly to the microcontroller, meaning that you’ll have to open the case to change the cable. To mitigate that I wanted to add a USB breakout board to the project, and this being 2017, it felt right to go with USB-C.

USB-C breakouts

I found some cheap USB-C breakout boards from AliExpress. Once they arrived, it was time to figure out how the spec works. Since USB-C is quite new, there are very few resources available on how to use it with microcontrollers. These tutorials were quite helpful:

Here is how we ended up wiring the breakout board. After these you only have four wires to connect to the microcontroller: ground, power, and the positive and negative data pins.

USB-C breakout with wiring

This Atreus build log was useful for figuring out where to connect the USB wires on the Pro Micro. Once all was done, I had a custom, USB-C keyboard!

USB-C keyboard

Next steps

Now I have the Atreus working nicely on my new standing desk. Learning Colemak is a bit painful, but the keyboard itself feels super nice!

New standing desk

However, I’d still like to CNC mill a proper wooden case for the keyboard. I may update this post once that happens.

I’m also considering to order an Atreus kit so I’d have a second, always packed for travel keyboard. The kit comes with a PCB, which might work better at airport security checks than the hand-wired build.

Another thing that is quite tempting is to make a custom firmware with MicroFlo. I have no complaints on how QMK works, but it’d be super-cool to use our visual programming tool to tweak the keyboard live.

Big thanks to Technomancy for the Atreus design, and to XenGi for all the help during the build!

0 Add to favourites0 Bury

April 13 2017

21:32

Asynchronous undoable and redoable APIs

Combining QFuture with QUndoCommand made a lot of sense for us. The undo and the redo methods of the QUndoCommand can also be asynchronous, of course. We wanted to use QFuture without involving threads, because our asynchronosity is done through a process and IPC, and not a thread. It’s the design mistake of QtConcurrent‘s run method, in my opinion. That meant using QFutureInterface instead (which is undocumented, but luckily public – so it’ll remain with us until at least Qt’s 6.y.z releases).

So how do we make a QUndoCommand that has a undo, and that has a redo method that returns a asynchronous QFuture<ResultType>?

We just did that, today. I’m very satisfied with the resulting API and design. It might have helped if QUndoStack would be a QUndoStack<T> and QUndoCommand would have been a QUndoCommand<T> with undo and redo’s return type being T. Just an idea for the Qt 6.y.z developers.

I’m not telling you today, because I want this to settle in our project first. I’m sure we will find problems.

0 Add to favourites0 Bury

April 10 2017

19:07

Looking for new adventures

Yes, I'm looking for a job. :-)

These six years I've spent at Canonical have literally been flying. I enjoyed my work from the very first day, when I was assigned to the Unity 2D team, developing a lightweight desktop environment for Ubuntu, though I stayed in that team just for a few weeks. The next task, which I've been carrying on till today, has been implementing the Online Accounts feature in Ubuntu; this project has been especially dear to me, given that I got to reuse and improve much of the work we developed for the Nokia N9 phone. Seeing it being adopted also by Sailfish OS and KDE has been a major satisfaction, and a proof that we were on the right track. And indeed, porting the UI to Qt/QML for running in Unity 8, plus extending and simplifying the APIs and helping with the development of client applications has been a fantastic ride.
In the times where calm was reigning in the project, I reached out to other teams and offered help, mainly for improving the geolocation service and the webapps project.

Unfortunately, with the decision to terminate the development of Unity8 and to set aside the convergence goals, all of the above is no longer relevant for Canonical's future and I, along many other developers, have left the company.

So, here's my CV.

Given that reading is boring, here's a few pictures (and even a video!) of programs I've done, not as part of my daily work but in my spare time; though, to be honest, I do enjoy middleware and logic development (and even kernel, though I got little chances to work on that so far) more than UI development:
Imaginario on the Ubuntu phone
Imaginario for your desktop (under development)
If you wish to see my code, please have a look at my gitlab, github and launchpad accounts.


0 Add to favourites0 Bury
Reposted byElbenfreund Elbenfreund

March 24 2017

09:42

Making something that is undoable editable with Qt

Among the problems we’ll face is that we want asynchronous APIs that are undoable and that we want to switch to read only, undoable editing, non-undoable editing and that QML doesn’t really work well with QFuture. At least not yet. We want an interface that is easy to talk with from QML. Yet we want to switch between complicated behaviors.

We will also want synchronous mode and asynchronous mode. Because I just invented that requirement out of thin air.

Ok, first the “design”. We see a lot of behaviors, for something that can do something. The behaviors will perform for that something, the actions it can do. That is obviously the strategy design pattern, then. Right? That’s the one about ducks and wing fly behavior and rocket propelled fly behavior and then the ostrich that has a can’t fly behavior. And undo and redo, that certainly sounds like the command pattern. We also have this neat thing in Qt for that. We’ll use it. We don’t reinvent the wheel. Reinventing the wheel is stupid.

Let’s create the duck. I mean, the thing-editor. As I will use “Thing” for the thing that is being edited. We want copy (sync is sufficient), paste (must be aysnc), and edit (must be async). We could also have insert and delete, but those APIs would be just like edit. And that would make the example only longer. Paste would usually be similar to insert, of course. Except that it can be a combined delete and insert when overwriting content. The command pattern allows you to make such combinations. Not the purpose of this example, though.

Enough explanation for a blog. Let’s start! The ThingEditor, is like the flying Duck in strategy. This is going to be more or less the API that we will present to the QML world. It could be your ViewModel, for example (ie. you could let your ThingViewModel subclass ThingEditor).

class ThingEditor : public QObject
{
    Q_OBJECT

    Q_PROPERTY ( ThingEditingBehavior* editingBehavior READ editingBehavior
                 WRITE setEditingBehavior NOTIFY editingBehaviorChanged )
    Q_PROPERTY ( Thing* thing READ thing WRITE setThing NOTIFY thingChanged )

public:
    explicit ThingEditor( QSharedPointer<Thing> &a_thing,
            ThingEditingBehavior *a_editBehavior,
            QObject *a_parent = nullptr );

    explicit ThingEditor( QObject *a_parent = nullptr );

    Thing* thing() const { return m_thing.data(); }
    virtual void setThing( QSharedPointer<Thing> &a_thing );
    virtual void setThing( Thing *a_thing );

    ThingEditingBehavior* editingBehavior() const { return m_editingBehavior.data(); }
    virtual void setEditingBehavior ( ThingEditingBehavior *a_editingBehavior );

    Q_INVOKABLE virtual void copyCurrentToClipboard ( );
    Q_INVOKABLE virtual void editCurrentAsync( const QString &a_value );
    Q_INVOKABLE virtual void pasteCurrentFromClipboardAsync( );

signals:
    void editingBehaviorChanged ();
    void thingChanged();
    void editCurrentFinished( EditCurrentCommand *a_command );
    void pasteCurrentFromClipboardFinished( EditCurrentCommand *a_command );

private slots:
    void onEditCurrentFinished();
    void onPasteCurrentFromClipboardFinished();

private:
    QScopedPointer<ThingEditingBehavior> m_editingBehavior;
    QSharedPointer<Thing> m_thing;
    QList<QFutureWatcher<EditCurrentCommand*> *> m_editCurrentFutureWatchers;
    QList<QFutureWatcher<EditCurrentCommand*> *> m_pasteCurrentFromClipboardFutureWatchers;
};

For the implementation of this class, I’ll only provide the non-obvious pieces. I’m sure you can do that setThing, setEditingBehavior and the constructor yourself. I’m also providing it only once, and also only for the EditCurrentCommand. The one about paste is going to be exactly the same.

void ThingEditor::copyCurrentToClipboard ( )
{
    m_editingBehavior->copyCurrentToClipboard( );
}

void ThingEditor::onEditCurrentFinished( )
{
    QFutureWatcher<EditCurrentCommand*> *resultWatcher
            = static_cast<QFutureWatcher<EditCurrentCommand*>*> ( sender() );
    emit editCurrentFinished ( resultWatcher->result() );
    if (m_editCurrentFutureWatchers.contains( resultWatcher )) {
        m_editCurrentFutureWatchers.removeAll( resultWatcher );
    }
    delete resultWatcher;
}

void ThingEditor::editCurrentAsync( const QString &a_value )
{
    QFutureWatcher<EditCurrentCommand*> *resultWatcher
            = new QFutureWatcher<EditCurrentCommand*>();
    connect ( resultWatcher, &QFutureWatcher<EditCurrentCommand*>::finished,
              this, &ThingEditor::onEditCurrentFinished, Qt::QueuedConnection );
    resultWatcher->setFuture ( m_editingBehavior->editCurrentAsync( a_value ) );
    m_editCurrentFutureWatchers.append ( resultWatcher );
}

For QUndo we’ll need a QUndoCommand. For each undoable action we indeed need to make such a command. No worries, it’s easy. You could add more state and pass it to the constructor. It’s common, for example, to pass Thing, or the ThingEditor or the behavior (this is why I used QSharedPointer for those: as long as your command lives in the stack, you’ll need it to hold a reference to that state).

class EditCurrentCommand: public QUndoCommand
{
public:
    explicit EditCurrentCommand( const QString &a_value,
                                 QUndoCommand *a_parent = nullptr )
        : QUndoCommand ( a_parent )
        , m_value ( a_value ) { }
    void redo() Q_DECL_OVERRIDE {
       // Perform action goes here
    }
    void undo() Q_DECL_OVERRIDE {
      // Undo what got performed goes here
    }
private:
    const QString &m_value;
};

You can (and probably should) also make this one abstract (and/or a so called pure interface), as you’ll usually want many implementations of this one (one for every kind of editing behavior). This is like the fly behavior in the duck that flies -example of strategy. Note that it leaks the QUndoCommand instances unless you handle them (ie. storing them in a QUndoStack). That in itself is a good reason to call the thing abstract.

class ThingEditingBehavior : public QObject
{
    Q_OBJECT

    Q_PROPERTY ( ThingEditor* editor READ editor WRITE setEditor NOTIFY editorChanged )
    Q_PROPERTY ( Thing* thing READ thing NOTIFY thingChanged )

public:
    explicit ThingEditingBehavior( ThingEditor *a_editor,
                                   QObject *a_parent = nullptr )
        : QObject ( a_parent )
        , m_editor ( a_editor ) { }

    explicit ThingEditingBehavior( QObject *a_parent = nullptr )
        : QObject ( a_parent ) { }

    ThingEditor* editor() const { return m_editor.data(); }
    virtual void setEditor( ThingEditor *a_editor );
    Thing* thing() const;

    virtual void copyCurrentToClipboard ( );
    virtual QFuture<EditCurrentCommand*> editCurrentAsync( const QString &a_value, bool a_exec = true );
    virtual QFuture<EditCurrentCommand*> pasteCurrentFromClipboardAsync( bool a_exec = true );

protected:
    virtual EditCurrentCommand* editCurrentSync( const QString &a_value, bool a_exec = true );
    virtual EditCurrentCommand* pasteCurrentFromClipboardSync( bool a_exec = true );

signals:
    void editorChanged();
    void thingChanged();

private:
    QPointer<ThingEditor> m_editor;
    bool m_synchronous = true;
};

That setEditor, the constructor, etc: these are too obvious to write here. You can do that yourself. Right? Here are the non-obvious ones:

void ThingEditingBehavior::copyToClipboard ( )
{
    Q_UNUSED (a_row);
    // TODO: Implementation of copying the current to clipboard. See QClipboard
}

EditCurrentCommand* ThingEditingBehavior::editCurrentSync( const QString &a_value, bool a_exec )
{
    EditCurrentCommand *ret = new EditCurrentCommand ( a_value );
    if ( a_exec )
        ret->redo();
    return ret;
}

QFuture<EditCurrentCommand*> ThingEditingBehavior::editCurrentAsync( const QString &a_value, bool a_exec )
{
    QFuture<EditCurrentCommand*> resultFuture =
            QtConcurrent::run( QThreadPool::globalInstance(), this,
                               &ThingEditingBehavior::editCurrentSync,
                               a_value, a_exec );
    if (m_synchronous)
        resultFuture.waitForFinished();
    return resultFuture;
}

And now we can finally make the whole thing undoable by making a undoable editing behavior. That’s like the fly with wings behavior of the duck that flies -example of strategy. The edit with undoable behavior of the Thing editor. Right? I’ll leave a non-undoable editing behavior as an exercise to the reader (ie. just perform redo() on the QUndoCommand, don’t store it in the QUndoStack and immediately delete or cmd->deleteLater() the instance).

Note that if m_synchronous is false, that (all access to) m_undoStack must be (made) thread-safe. The thread-safety is not the purpose of this example, though.

class UndoableThingEditingBehavior : public ThingEditingBehavior
{
    Q_OBJECT
public:
    explicit UndoableThingEditingBehavior( ThingEditor *a_editor,
                                           QObject *a_parent = nullptr );
protected:
    EditCellCommand* editCurrentSync( const QString &a_value, bool a_exec = true ) Q_DECL_OVERRIDE;
    EditCurrentCommand* pasteCurrentFromClipboardSync( bool a_exec = true ) Q_DECL_OVERRIDE;
private:
    QScopedPointer<QUndoStack> m_undoStack;
};

EditCellCommand* UndoableThingEditingBehavior::editCurrentSync( const QString &a_value, bool a_exec )
{
    Q_UNUSED(a_exec)
    EditCellCommand *undoable = ThingEditingBehavior::editCurrentSync(  a_value, false );
    m_undoStack->push( undoable );
    return undoable;
}

EditCellCommand* UndoableThingEditingBehavior::pasteCurrentFromClipboardSync( bool a_exec )
{
    Q_UNUSED(a_exec)
    EditCellCommand *undoable = ThingEditingBehavior::pasteCurrentFromClipboardSync( false );
    m_undoStack->push( undoable );
    return undoable;
}
0 Add to favourites0 Bury

May 11 2017

20:09

How do they do it? Asynchronous undo and redo editors

Imagine we want an editor that has undo and redo capability. But the operations on the editor are all asynchronous. This implies that also undo and redo are asynchronous operations.

We want all this to be available in QML, we want to use QFuture for the asynchronous stuff and we want to use QUndoCommand for the undo and redo capability.

But how do they do it?

First of all we will make a status object, to put the status of the asynchronous operations in (asyncundoable.h).

class AbstractAsyncStatus: public QObject
{
    Q_OBJECT

    Q_PROPERTY(bool success READ success CONSTANT)
    Q_PROPERTY(int extra READ extra CONSTANT)
public:
    AbstractAsyncStatus(QObject *parent):QObject (parent) {}
    virtual bool success() = 0;
    virtual int extra() = 0;
};

We will be passing it around as a QSharedPointer, so that lifetime management becomes easy. But typing that out is going to give us long APIs. So let’s make a typedef for that (asyncundoable.h).

typedef QSharedPointer<AbstractAsyncStatus> AsyncStatusInstance;

Now let’s make ourselves a undo command that allows us to wait for asynchronous undo and asynchronous redo. We’re combining QUndoCommand and QFutureInterface here (asyncundoable.h).

class AbstractAsyncUndoable: public QUndoCommand
{
public:
    AbstractAsyncUndoable( QUndoCommand *parent = nullptr )
        : QUndoCommand ( parent )
        , m_undoFuture ( new QFutureInterface<AsyncStatusInstance>() )
        , m_redoFuture ( new QFutureInterface<AsyncStatusInstance>() ) {}
    QFuture<AsyncStatusInstance> undoFuture()
        { return m_undoFuture->future(); }
    QFuture<AsyncStatusInstance> redoFuture()
        { return m_redoFuture->future(); }

protected:
    QScopedPointer<QFutureInterface<AsyncStatusInstance> > m_undoFuture;
    QScopedPointer<QFutureInterface<AsyncStatusInstance> > m_redoFuture;

};

Okay, let’s implement these with an example operation. First the concrete status object (asyncexample1command.h).

class AsyncExample1Status: public AbstractAsyncStatus
{
    Q_OBJECT
    Q_PROPERTY(bool example1 READ example1 CONSTANT)
public:
    AsyncExample1Status ( bool success, int extra, bool example1,
                          QObject *parent = nullptr )
        : AbstractAsyncStatus(parent)
        , m_example1 ( example1 )
        , m_success ( success )
        , m_extra ( extra ) {}
    bool example1() { return m_example1; }
    bool success() Q_DECL_OVERRIDE { return m_success; }
    int extra() Q_DECL_OVERRIDE { return m_extra; }
private:
    bool m_example1 = false;
    bool m_success = false;
    int m_extra = -1;
};

Let’s make a QUndoCommand that uses a timer to simulate asynchronous behavior. We could also use QtConcurrent’s run function to use a QThreadPool and QRunnable instances that also implement QFutureInterface, of course. Seasoned Qt developers know what I mean. For the sake of example, I wanted to illustrate that QFuture can also be used for asynchronous things that aren’t threads. We’ll use the lambda because QUndoCommand isn’t a QObject, so no easy slots. That’s the only reason (asyncexample1command.h).

class AsyncExample1Command: public AbstractAsyncUndoable
{
public:
    AsyncExample1Command(bool example1, QUndoCommand *parent = nullptr)
        : AbstractAsyncUndoable ( parent ), m_example1(example1) {}
    void undo() Q_DECL_OVERRIDE {
        m_undoFuture->reportStarted();
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        QObject::connect(timer, &QTimer::timeout, [=]() {
            QSharedPointer<AbstractAsyncStatus> result;
            result.reset(new AsyncExample1Status ( true, 1, m_example1 ));
            m_undoFuture->reportFinished(&result);
            timer->deleteLater();
        } );
        timer->start(1000);
    }
    void redo() Q_DECL_OVERRIDE {
        m_redoFuture->reportStarted();
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        QObject::connect(timer, &QTimer::timeout, [=]() {
            QSharedPointer<AbstractAsyncStatus> result;
            result.reset(new AsyncExample1Status ( true, 2, m_example1 ));
            m_redoFuture->reportFinished(&result);
            timer->deleteLater();
        } );
        timer->start(1000);
    }
private:
    QTimer m_timer;
    bool m_example1;
};

Let’s now define something we get from the strategy design pattern; a editor behavior. Implementations provide an editor all its editing behaviors (abtracteditorbehavior.h).

class AbstractEditorBehavior : public QObject
{
    Q_OBJECT
public:
    AbstractEditorBehavior( QObject *parent) : QObject (parent) {}

    virtual QFuture<AsyncStatusInstance> performExample1( bool example1 ) = 0;
    virtual QFuture<AsyncStatusInstance> performUndo() = 0;
    virtual QFuture<AsyncStatusInstance> performRedo() = 0;
    virtual bool canRedo() = 0;
    virtual bool canUndo() = 0;
};

So far so good, so let’s make an implementation that has a QUndoStack and that therefor is undoable (undoableeditorbehavior.h).

class UndoableEditorBehavior: public AbstractEditorBehavior
{
public:
    UndoableEditorBehavior(QObject *parent = nullptr)
        : AbstractEditorBehavior (parent)
        , m_undoStack ( new QUndoStack ){}

    QFuture<AsyncStatusInstance> performExample1( bool example1 ) Q_DECL_OVERRIDE {
        AsyncExample1Command *command = new AsyncExample1Command ( example1 );
        m_undoStack->push(command);
        return command->redoFuture();
    }
    QFuture<AsyncStatusInstance> performUndo() {
        const AbstractAsyncUndoable *undoable =
            dynamic_cast<const AbstractAsyncUndoable *>(
                    m_undoStack->command( m_undoStack->index() - 1));
        m_undoStack->undo();
        return const_cast<AbstractAsyncUndoable*>(undoable)->undoFuture();
    }
    QFuture<AsyncStatusInstance> performRedo() {
        const AbstractAsyncUndoable *undoable =
            dynamic_cast<const AbstractAsyncUndoable *>(
                    m_undoStack->command( m_undoStack->index() ));
        m_undoStack->redo();
        return const_cast<AbstractAsyncUndoable*>(undoable)->redoFuture();
    }
    bool canRedo() Q_DECL_OVERRIDE { return m_undoStack->canRedo(); }
    bool canUndo() Q_DECL_OVERRIDE { return m_undoStack->canUndo(); }
private:
    QScopedPointer<QUndoStack> m_undoStack;
};

Now we only need an editor, right (editor.h)?

class Editor: public QObject
{
    Q_OBJECT
    Q_PROPERTY(AbstractEditorBehavior* editorBehavior READ editorBehavior CONSTANT)
public:
    Editor(QObject *parent=nullptr) : QObject(parent)
        , m_editorBehavior ( new UndoableEditorBehavior ) { }
    AbstractEditorBehavior* editorBehavior() { return m_editorBehavior.data(); }
    Q_INVOKABLE void example1Async(bool example1) {
        QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
        connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                this, &Editor::onExample1Finished);
        watcher->setFuture ( m_editorBehavior->performExample1(example1) );
    }
    Q_INVOKABLE void undoAsync() {
        if (m_editorBehavior->canUndo()) {
            QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
            connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                    this, &Editor::onUndoFinished);
            watcher->setFuture ( m_editorBehavior->performUndo() );
        }
    }
    Q_INVOKABLE void redoAsync() {
        if (m_editorBehavior->canRedo()) {
            QFutureWatcher<AsyncStatusInstance> *watcher = new QFutureWatcher<AsyncStatusInstance>(this);
            connect(watcher, &QFutureWatcher<AsyncStatusInstance>::finished,
                    this, &Editor::onRedoFinished);
            watcher->setFuture ( m_editorBehavior->performRedo() );
        }
    }
signals:
    void example1Finished( AsyncExample1Status *status );
    void undoFinished( AbstractAsyncStatus *status );
    void redoFinished( AbstractAsyncStatus *status );
private slots:
    void onExample1Finished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit example1Finished( watcher->result().objectCast<AsyncExample1Status>().data() );
        watcher->deleteLater();
    }
    void onUndoFinished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit undoFinished( watcher->result().objectCast<AbstractAsyncStatus>().data() );
        watcher->deleteLater();
    }
    void onRedoFinished() {
        QFutureWatcher<AsyncStatusInstance> *watcher =
                dynamic_cast<QFutureWatcher<AsyncStatusInstance>*> (sender());
        emit redoFinished( watcher->result().objectCast<AbstractAsyncStatus>().data() );
        watcher->deleteLater();
    }
private:
    QScopedPointer<AbstractEditorBehavior> m_editorBehavior;
};

Okay, let’s register this up to make it known in QML and make ourselves a main function (main.cpp).

#include <QtQml>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <editor.h>
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    qmlRegisterType<Editor>("be.codeminded.asyncundo", 1, 0, "Editor");
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

Now, let’s make ourselves a simple QML UI to use this with (main.qml).

import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
import be.codeminded.asyncundo 1.0
Window {
    visible: true
    width: 360
    height: 360
    Editor {
        id: editor
        onUndoFinished: text.text = "undo"
        onRedoFinished: text.text = "redo"
        onExample1Finished: text.text = "whoohoo " + status.example1
    }
    Text {
        id: text
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
    Action {
        shortcut: "Ctrl+z"
        onTriggered: editor.undoAsync()
    }
    Action {
        shortcut: "Ctrl+y"
        onTriggered: editor.redoAsync()
    }
    Button  {
        onClicked: editor.example1Async(99);
    }
}

You can find the sources of this complete example at github. Enjoy!

0 Add to favourites0 Bury

April 30 2017

10:16

Q2 2017 Community Council Election Announcement

Dear friends and Maemoans. It is again the time for us to elect the new Community Council.

The schedule for the voting process is as follows:

  • The nomination period starts next Monday, on the 1st of May 2017 and will continue until the 23rd of May 2017.
  • The election starts on Thursday, on the 1st of June 2017 and will continue until the 7th of June 2017. In order for us to keep the community strong, we need to have new people with fresh ideas to carry on the torch. So, please consider volunteering for the position of Maemo Council.

    On behalf of the outgoing Community Council,

    eekkelund

0 Add to favourites0 Bury

April 20 2017

00:00

Atreus: Building a custom ergonomic keyboard

As mentioned in my Working on Android post, I’ve been using a mechanical keyboard for a couple of years now. Now that I work on Flowhub from home, it was a good time to re-evaluate the whole work setup. As far as regular keyboards go, the MiniLa was nice, but I wanted something more compact and ergonomic.

The Atreus keyboard

My new Atreus

Atreus is a 40% ergonomic mechanical keyboard designed by Phil Hagelberg. It is an open hardware design, but he also sells kits for easier construction. From the kit introduction:

The Atreus is a small mechanical keyboard that is based around the shape of the human hand. It combines the comfort of a split ergonomic keyboard with the crisp key action of mechanical switches, all while fitting into a tiny profile.

My use case was also quite travel-oriented. I wanted a small keyboard that would enable me to work with it also on the road. There are many other small-ish DIY keyboard designs like Planck and Gherkin available, but Atreus had the advantage of better ergonomics. I really liked the design of the Ergodox keyboard, and Atreus essentially is that made mobile:

I found the split halves and relatively large size (which are fantastic for stationary use at a desk) make me reluctant to use it on the lap, at a coffee shop, or on the couch, so that’s the primary use case I’ve targeted with the Atreus. It still has most of the other characteristics that make the Ergodox stand out, like mechanical Cherry switches, staggered columns instead of rows, heavy usage of the thumbs, and a hackable microcontroller with flexible firmware, but it’s dramatically smaller and lighter

I had the opportunity to try a kit-built Atreus in the Berlin Mechanical Keyboard meetup, and it felt nice. It was time to start the project.

Sourcing the parts

When building an Atreus the first decision is whether to go with the kit or hand-wire it yourself. Building from a kit is certainly easier, but since I’m a member of a hackerspace, doing a hand-wired build seemed like the way to go.

To build a custom keyboard, you need:

  • Switches: in my case 37 Cherry MX blues and 5 Cherry MX blacks
  • Diodes: one 1N4148 per switch
  • Microcontroller: a Arduino Pro Micro on my keyboard
  • Keycaps: started with recycled ones and later upgraded to DSA blanks
  • Case: got a set of laset-cut steel plates

Even though Cherry — the maker of the most common mechanical key switches — is a German company, it is quite difficult to get switches in retail here. Luckily a fellow hackerspace member had just dismantled some old mechanical keyboards, and so I was able to get the switches I needed via barter.

Keyswitches

The Cherry MX blues are tactile clicky switches that feel super-nice to type on, but are quite loud. For modifiers I went with Cherry MX blacks that are linear. This way there is quite a clear difference in feel between keys you typically hold down compared to the ones you just press.

The diodes and the microcontroller I ordered from Amazon for about 20€ total.

Arduino Pro Micro

At first I used a set of old keycaps that I got with the switches, but once the keyboard was up and running I upgraded to a very nice set of blank DSA-profile keycaps that I ordered from AliExpress for 30€. That set came with enough keycaps that I’ll have myself covered if I ever build a second Atreus.

All put together, I think the parts ended up costing me around 100€ total.

Preparations

When I received all the parts, there were some preparation steps to be made. Since the key switches were 2nd hand, I had to start by dismantling them and removing old diodes that had been left inside some of them.

Opening the key switches

The keycaps I had gotten with the switches were super grimy, and so I ended up sending them to the washing machine. After that you could see that they were not new, but at least they were clean.

With the steel mounting plate there had been a slight misunderstading, and the plates I received were a few millimeters thicker than needed, so the switches wouldn’t “click” in place. While this could’ve been worked around with hot glue, we ended up filing the mounting holes down to the right thickness.

Filing the plate

Little bit of help

Wiring the keyboard

Once the mounting plate was in the right shape, I clicked the switches in and it was time to solder.

All switches in place

Hand-wiring keyboards is not that tricky. You have to attach a diode to each keyswitch, and then connect each row together via the diodes.

Connecting diodes

First row ready

The two thumb keys are wired to be on the same column, but different rows.

All rows ready diodes

Then each column is connected together via the other pin on the switches.

Soldering columns

This is how the matrix looks like:

Completed matrix

After these are done, connect a wire from each column, and each row to a I/O pin on the microcontroller.

Adding column wires

If you haven’t done it earlier, this is a good stage to test all connections with a multimeter!

Connecting the microcontroller

Firmware

After finishing the wiring, I downloaded the QMK firmware, changed the PIN mapping for how my Atreus is wired up, switched the layout to Colemak, and the keyboard was ready to go.

Atreus in use

Don’t mind the key labels in the picture above. These are the second-hand keycaps I started with. Since then I’ve switched to blank ones.

USB-C

The default Atreus design has the USB cable connected directly to the microcontroller, meaning that you’ll have to open the case to change the cable. To mitigate that I wanted to add a USB breakout board to the project, and this being 2017, it felt right to go with USB-C.

USB-C breakouts

I found some cheap USB-C breakout boards from AliExpress. Once they arrived, it was time to figure out how the spec works. Since USB-C is quite new, there are very few resources available on how to use it with microcontrollers. These tutorials were quite helpful:

Here is how we ended up wiring the breakout board. After these you only have four wires to connect to the microcontroller: ground, power, and the positive and negative data pins.

USB-C breakout with wiring

This Atreus build log was useful for figuring out where to connect the USB wires on the Pro Micro. Once all was done, I had a custom, USB-C keyboard!

USB-C keyboard

Next steps

Now I have the Atreus working nicely on my new standing desk. Learning Colemak is a bit painful, but the keyboard itself feels super nice!

New standing desk

However, I’d still like to CNC mill a proper wooden case for the keyboard. I may update this post once that happens.

I’m also considering to order an Atreus kit so I’d have a second, always packed for travel keyboard. The kit comes with a PCB, which might work better at airport security checks than the hand-wired build.

Another thing that is quite tempting is to make a custom firmware with MicroFlo. I have no complaints on how QMK works, but it’d be super-cool to use our visual programming tool to tweak the keyboard live.

Big thanks to Technomancy for the Atreus design, and to XenGi for all the help during the build!

0 Add to favourites0 Bury

April 13 2017

21:32

Asynchronous undoable and redoable APIs

Combining QFuture with QUndoCommand made a lot of sense for us. The undo and the redo methods of the QUndoCommand can also be asynchronous, of course. We wanted to use QFuture without involving threads, because our asynchronosity is done through a process and IPC, and not a thread. It’s the design mistake of QtConcurrent‘s run method, in my opinion. That meant using QFutureInterface instead (which is undocumented, but luckily public – so it’ll remain with us until at least Qt’s 6.y.z releases).

So how do we make a QUndoCommand that has a undo, and that has a redo method that returns a asynchronous QFuture<ResultType>?

We just did that, today. I’m very satisfied with the resulting API and design. It might have helped if QUndoStack would be a QUndoStack<T> and QUndoCommand would have been a QUndoCommand<T> with undo and redo’s return type being T. Just an idea for the Qt 6.y.z developers.

I’m not telling you today, because I want this to settle in our project first. I’m sure we will find problems.

0 Add to favourites0 Bury

April 10 2017

19:07

Looking for new adventures

Yes, I'm looking for a job. :-)

These six years I've spent at Canonical have literally been flying. I enjoyed my work from the very first day, when I was assigned to the Unity 2D team, developing a lightweight desktop environment for Ubuntu, though I stayed in that team just for a few weeks. The next task, which I've been carrying on till today, has been implementing the Online Accounts feature in Ubuntu; this project has been especially dear to me, given that I got to reuse and improve much of the work we developed for the Nokia N9 phone. Seeing it being adopted also by Sailfish OS and KDE has been a major satisfaction, and a proof that we were on the right track. And indeed, porting the UI to Qt/QML for running in Unity 8, plus extending and simplifying the APIs and helping with the development of client applications has been a fantastic ride.
In the times where calm was reigning in the project, I reached out to other teams and offered help, mainly for improving the geolocation service and the webapps project.

Unfortunately, with the decision to terminate the development of Unity8 and to set aside the convergence goals, all of the above is no longer relevant for Canonical's future and I, along many other developers, have left the company.

So, here's my CV.

Given that reading is boring, here's a few pictures (and even a video!) of programs I've done, not as part of my daily work but in my spare time; though, to be honest, I do enjoy middleware and logic development (and even kernel, though I got little chances to work on that so far) more than UI development:
Imaginario on the Ubuntu phone
Imaginario for your desktop (under development)
If you wish to see my code, please have a look at my gitlab, github and launchpad accounts.


0 Add to favourites0 Bury
Reposted byElbenfreund Elbenfreund
Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.

Don't be the product, buy the product!

Schweinderl