Blog

Debut on Medium and announcement of Frienzzle

Submitted by mimec on

A few days ago I published my first article on Medium: A brief history of Frienzzle. I announced the plans to publish Frienzzle, an innovative multi-player jigsaw puzzle, by the end of May, and also to publish regular updates on the progress on making this game. If you’re curious about the game and you don’t want to miss the launch date, you can go to frienzzle.com and subscribe today. We will send you an invitation as soon as the game is ready for public beta testing.

Also jut a few days ago I released the long awaited version 1.0 of Saladin, my open-source dual pane file manager for Windows. Currently I'm working on a minor release of WebIssues which will also be published very soon. It's a very busy period for me personally and for the Bulletcode company that I co-founded; challenging but also very creative and exciting. To get the latest updates, make sure that you follow me on Twitter: @MichalMecinski.

The future of mimec.org

Submitted by mimec on

The main focus of all my recent work is Bulletcode and this will remain my top priority in the coming months and (hopefully) years. There's a lot going on at the moment, so if you want to get the latest updates, please make sure that you follow my official Twitter channel: @MichalMecinski.

I'm not planning to update my blog dedicated to Qt development, mostly because I'm moving away from this technology and learning something new. However, I'm planning to start writing a new series of technical blog posts about JavaScript and Node.js. Most likely I will switch to some new, more community-oriented blogging platform, but I will post a link here so you don't miss it. Also, soon a new, very cool project using Node.js will be released. Those who follow me on Twitter could already see some early previews. Hint: it will be a multi-player online game :).

The amount of time that I can dedicate to my numerous open-source projects is much smaller than before, but it doesn't mean that nothing's happening in that area. Very soon I will publish the long-awaited version 1.0 of Saladin with a ton of visual and functional improvements. Later this year a bug fix release of WebIssues will be published as well.

Life goes on pt. 2

Submitted by mimec on

Wow... I just realized that the last time I wrote anything here was nine months ago, and what's worse, almost every word that I wrote is no longer true. The only thing that remains pretty much the same is my job, which is still the same as 11 years ago. I found that at this moment I'm much closer to what I wrote in April 2014, in the previous Life goes on post. So who knows, maybe it will become a new series?

First of all, I'm officially divorced, once and for all. I tried to fight against it, but when your life becomes an endless war, it means that something went terribly wrong. So in the end it's a big step forward after all the turbulences from the past three years. Still, much time has to pass before I can even start thinking about being with someone again, and I must admit that's something that I really miss. It's really ironic that in 2014 I wrote that I'd already gone through all the denial-anger-regret stages, because so much has happened since that time that now I'm in yet another stage of profound sadness.

Also, the project that my company has been working on for almost a year, failed miserably for reasons beyond our control, just like the previous one. Ironically, the reasons were pretty much the same in both cases - the people that we relied on exhibited a very harmful mixture of greed and utter ignorance. We still have to decide what to do next, but honestly, none of us is willing to go through this once again. It surely wasn't a waste of time, working on this project was a great experience and I'm extremely proud of what we have accomplished as a team. However, seeing things that you've created burn and fall because of someone's bad will doesn't feel so great.

So what remains? Not much for now, I must admit. Obviously I have to start working on something again just to remain sane. The most logical thing would be to return to one of my open source projects. For example, there's a pile of feature requests for WebIssues. I don't rule it out, perhaps I will do that next year. However, at this moment I need to start something new and a bit more creative. In my case typically that means creating a game. I still remember the lessons I drew from Mister Tins, so this time I will take a slightly different approach. It will be a simple 2D browser game. There will be stronger focus on graphics and level design, and the game engine will be as simple as possible. Generally the goal is to create a nice looking and fun game with reasonable effort. Recently any plans I make tend to backfire, but on the other hand it's always important to keep trying, so time will show how it goes this time.

Tags

Happy 10th anniversary, mimec.org!

Submitted by mimec on

Today is a very special day. Excactly ten years ago, on December 15th 2005, I wrote the first post on the mimec.org website. It's become a tradition that I write a short summary of the past year on each anniversary, and I will do it again today, because it was also a very special year for me.

First of all, there were a lot of round anniversaries this year. Almost exactly 10 years ago I graduated from college. WebIssues turned 10 years old in November, although technically it wasn't officially released until September 2006. Fraqtive turned 10 years old in January. And in March it was 10 years since I started my first job - and after those 10 years I still work for the same company, although it grew in size from a few developers to a few hundred, changed its name and relocated its headquarters. Even my primary day job project is still the same after 10 years. So, looking at those numbers, one might think that my life is very stagnant, and I will most likely spend the rest of it in the same place, doing the same things…

But even though a lot of things remained the same for such a long time, the last year also brought a lot of substantial changes. I overcame a serious crisis in my family, and we are back together, although a year ago nothing indicated that this would ever be possible. I think that this is my greatest personal accomplishment, and I simply owed this to my son. Obviously it doesn't mean that it's all a bed of roses now, quite on the contrary, but it was a very valuable lesson for all of us, and I will definitely not let the most important things get out of control again.

Today is also the first anniversary of Bulletcode, a software company founded by me and two of my friends. At the moment it's still more of a hobby than a real business, we put more money into it than we make, and we try to put as much work into it as our day jobs allow. But the whole year was a huge, invaluable experience for us all. We started the company to work on a very promising project, which unfortunately failed miserably for reasons that were beyond our control. So we ended up with a company which generated costs, without any projects, with no business partners, and with no idea what to do next. But instead of shutting it down, we took the challenge and started looking for new ideas and opportunities. I cannot reveal yet what we are working on, it's all a bit of a mistery and conspiracy, but it's definitely the most interesting project I've ever participated in, and we're all waiting impatiently to release our first product.

Model-View-Presenter in QtQuick pt. 2

Submitted by mimec on

In the previous article I explained the basics of a simple Model-View-Presenter architecture in QtQuick. Now it's time to explain the implementation details. I will start with the Presenter QML component which is the base component of all presenters:

FocusScope {
    id: root

    property Item view
    property QtObject model

    property var modelToViewBindings: []
    property var viewToModelBindings: []

    Component.onCompleted: {
        root.view.anchors.fill = root;
        root.view.focus = true;

        for ( i in root.modelToViewBindings ) {
            name = root.modelToViewBindings[ i ];
            dynamicBinding.createObject( root, {
                target: root.view, property: name, source: root.model, sourceProperty: name
            } );
        }

        for ( var i in root.viewToModelBindings ) {
            var name = root.viewToModelBindings[ i ];
            dynamicBinding.createObject( root, {
                target: root.model, property: name, source: root.view, sourceProperty: name
            } );
        }
    }

    Component {
        id: dynamicBinding

        Binding {
            id: binding

            property var source
            property string sourceProperty

            value: binding.source[ binding.sourceProperty ]
        }
    }
}

As you can see, the presenter is a FocusScope, so that it can be used as a top-level visual component of a window or can be embedded in some more complex layout. The presenter contains a view property which holds a reference to the embedded view component and a model property which holds a reference to the model object. The Component.onCompleted function makes sure that the view fills the entire presenter and that it has keyboard focus enabled.

The remaining code is related to binding properties between the model and the view and vice versa in a simplified way. The modelToViewBindings property contains an array of names of properties that should be bound from the model to the view. The first loop in the Component.onCompleted function creates a Binding object for each property binding. The target of the binding is a property of the view. The value of that property is bound to the corresponding source property in the model. Note that JavaScript makes it possible to access a property of an object with a given name using the [] operator, because an object is essentially an associative array. The binding from the view to the model works in exactly the same way. As demonstrated in the example in the previous article, it's even possible to create bi-directional bindings.

The view and model objects are created in the actual presenter component which inherits Presenter. As I explained in the previous article, we want to be able to switch both the view and the model as easily as possible. In order to do that, I implemented a simple factory, which is basically a shared library implemented in JavaScript:

.pragma library

var config = {
    modules: {},
    urls: { views: "views/", models: "models/" }
};

function createObject( type, name, parent ) {
    var module = config.modules[ type ];
    if ( module !== undefined ) {
        var qml = "import " + module + "; " + name + " {}";
        return Qt.createQmlObject( qml, parent );
    } else {
        var url = config.urls[ type ];
        if ( url !== undefined ) {
            var component = Qt.createComponent( url + name + ".qml", parent );
            var object = component.createObject( parent );
            if ( object === null )
                console.log( "Could not create " + name + ":\n" + component.errorString() );
            return object;
        } else {
            console.log( "Factory is not configured for " + type );
            return null;
        }
    }
}

function createView( name, parent ) {
    return createObject( "views", name, parent );
}

function createModel( name, parent ) {
    return createObject( "models", name, parent );
}

The config variable specifies the names of C++ modules and/or URLs of directories that contain QML files with the implementation of views and models. By default, the models can be simple mock-ups written in QML, which makes it possible to run the whole application directly using the qmlscene tool without writing a single line of code in C++.

The createObject() function first looks for a registered C++ module of the given type. If present, it creates a simple component declaration in QML and calls Qt.createQmlObject() to create the instance of the component. When there is no C++ module registered, the function tries to load the component from the QML file in the given location. The createView() and createModel() functions are wrappers that can be used for simplicity.

By changing the default configuration of the factory at run-time, you can not only switch between mock-up models and real models implemented in C++, but also, for example, to use different views in mobile and desktop versions of the application. For example, the Component.onCompleted function of your top-level QML component could contain the following code to override the default configuration:

if ( typeof models !== 'undefined' )
    Factory.config.modules.models = models;

The C++ application can register the classes which implement the models in a module and pass the name of that module to the QML engine as a property of the root context, like this:

qmlEngine->rootContext()->setContextProperty( "models", "MyApp.Models 1.0" );

Unfortunately, it's not possible to pass variables from C++ code directly to shared JavaScript libraries which use the ".pragma library" directive (according to this thread, this is done this way on purpose). The method shown above can be used to work around this limitation; just keep in mind that the factory needs to be configured before any objects are actually created.