Cumulative Undo/Redo :More than one stroke at a time

The last feature I did for Krita was to implement a Cumulative Undo/Redo feature. Since its been almost 3 months since my last contribution to Krita — I thought this was the one of the very first things I had to do from a rather clogged pipeline.

ALPHA 1: unnamed - test.kra [modified] – Krita_002

The Cumulative Undo/Redo feature basically enables the artist to undo/redo several strokes in one go. How it works is that it groups several of the strokes together as one Undo Command based on the time-stamp on it. The grouping parameters are configurable by the artist and define as to how many strokes should be kept individual (undoable) before the grouping starts taking place. Further more, the user can also define how much time-gap should be between each individual stroke and the time-span across the first and last stroke of the group for the commands to be merged.

Selection_001

As shown in the screenshot — several commands have been merged into the top few commands ( You can view this by going to Settings -> Dockers -> Undo History ). The last commands however will remain unmerged as the last N strokes are supposed to remain individual. The parameters can be set by right-clicking on the docker.

The use for such a feature is when the artist is making something as deft as grass and then realizes that the brush size is wrong or the color is a shade lighter. So, instead of undoing every blade of grass — he or she can use this feature and get rid of the grass entirely.

Now, for the details. We implemented this by putting an empty linked list structures in each of the KUndo2Command objects used in the Undo Stacks. These linked lists worked like mini-undo stacks themselves. So whenever merging occurred based on the timestamp – the KUndo2Command objects are appended to the Head command (chronologically first command in the group) and removed from the main Undo-Stack itself. So whenever somebody wants to undo the entire set of commands in the merged commands — the undo starts happening from the last command itself ( Tail of the List ) and works its way upto the Head of the List. The Redo command works exactly the opposite. It starts from the Head and works its way down the list to the chronologically last command in the group.

So that was one thing out of the pipeline. Hopefully, I’ll start contributing to Krita again and keep the pipe clean  or for a need of a better phrase — manage my time better.

Cumulative Undo/Redo :More than one stroke at a time

Locked Settings : A Proxy Pattern Based Design

Locked Settings is actually a misnomer to what this feature does. Contrary to the common sense notion that it may make an option or setting non editable, it actually shares that particular option across all presets.

After that rather foggy opening statement, here is what it actually does.

Image

Right Clicking on any of the options with the Link Icon in front of them brings up the menu to “Lock” the option. Once the option is locked, the option will remain constant across all presets.

Image

For example : we locked Brush Tip for the Basic_Circle_Wet preset. Now, even when we are in the Bristles_Wet preset, the Brush Tip is the same. However, the Brush Tip is still editable as before. If we change the Diameter or any other parameter, it will reflect across all presets — even the original one. So we are not really locking the setting, we are sharing it.

Right Clicking on a Locked Option brings up the following menu :

Image

Selecting the “Load Last Selected” option will revert the current preset back to the configuration it had before it got overriden by the Locked/Shared Setting. Whereas “Load Current Setting” will unlock the option, but keep the current configuration with the preset.

This feature is ( or will be?) particularly useful when the user likes a particular configuration for an option, but wants to explore different presets with the same option. So, he/she doesn’t always have to change the Brush Tip or Size Option to his/her preferred configuration — Just Lock it and continue exploring more options 🙂

Now, for how the feature was implemented.

DmitryK introduced me to a new (for me :P) type of design called Proxy Pattern Based Design. The logic was simple — keep a central list of the Options being Locked with their configuration values. This List is accessible via a Global Static Server Class that keeps an object of the List. Now, whenever the paintop widget is required to set the configuration from the Preset Settings to the widget or required to write the configuration from the widget to the Preset Settings, a Proxy object ,generated by the LockedSettings Server, is passed into these functions rather than the original Settings object. The job of the Proxy Object is to make a detour to the Locked Settings Server and check whether any of the Options to be Read/Written from/onto the Widget are saved in the Locked Settings List. For all the Options in that List, the values are borrowed from the List rather than the Preset and passed on to the Widget.

So using this design, I was able to circumvent a lot of problems that I would have had to face if I had kept the Preset and the Widget object in the loop to obtain the Locked Setting Values. I just modified the path between the two by putting a Locked Settings Server in between. So technically, the Preset Object and the Widget don’t even know that there is any such thing known as Locked Settings !!

 I am currently working on Cumulative Undo/Redo that will free up Undo Slots in Krita by merging strokes together. More on that in the next post. For now, <lame attempt at humour>since my eye lids are fighting a losing battle against gravity, I may as well log out or work upside down</lame attempt at humour>. Ciao !!

 

Locked Settings : A Proxy Pattern Based Design

Dirty Presets : Why Design is Important

Well I haven’t blogged in a while (read ever since I started coding for GSoC), but then it has been an eventful month with myths being debunked. Before this, I believed that if you just sit down and and start writing lines of code, you will get somewhere and there will be some order out of chaos. Guess what didn’t happen while I was putting my half-baked ideas to code ?

But my mentor came to my rescue and I am a wiser man now 🙂

So, what have I been working on ? Well, as in the first post, I mentioned Dirty Presets. So basically, a user can temporarily save his tweaks to a preset during a session without actually overwriting it.The tweaks stay till the user reloads the original preset from the file.

That was about the usability of the feature. But more importantly, I wanted to write about the design that is behind it and why it is important to get it right before the actual coding.

Initially, I was going with the idea that I can create a temporary file for each loaded preset and using the load and save methods would get the temporary tweaks. But soon I realized that that particular way of doing things  required unnecessary massive refactoring of existing classes. Also, I realized that it wasn’t as if the tweaks were already not saved. they were just overwritten by the original settings somewhere in the workflow.

So, the next obvious solution that came to mind was to skip that portion in the workflow. Once I did that — Dirty Presets came to life. Just with about 10 lines of code — I was able to keep all tweaks made in a session till the end. However – now came the two more important parts — adding a Reload functionality( making the presets clean again) and marking a preset when it is dirty.

Hence began a week full of qDebugs and git resets. While DmitryK, my mentor, kept advising me against it — I kept working on a model based on UI signals. Using these signals, I developed a way to detect when a preset is dirty and when it is made clean again by reloading.

However, the thing with UI signals is that — they are completely unreliable and there is no predefined order by which they are executed. So while I got the code working on my system, it just crashed on DmitryK’s system.

Here is where Object Oriented Programming concepts come into play and all those long hours in the lecture hall come in use. DmitryK explained to me — that at a logical level, the fact that a preset is dirty or not should remain within the Preset object itself : Basic rule of Encapsulation. So that logic should pervade through to the code and that is where design of the code is as important as the code itself. Hence — the opening paragraph of this post.

So I started again. With parts from the previous implementation and a firm design, in another two days, the feature was completed.We also refactored the code so as to remove all clones of preset objects. It was a days work with DmitryK providing the template by using a policy based design to handle both shared pointers and normal pointers. Another new thing learnt 🙂

The feature is available in the git repository under the branch “krita-mohit-testing” for all of you who are active in the development and testing of Krita 2.9.

That’s all for now. Will post something new about Locked/Shared Settings really soon. That feature is also almost complete and this time — we started with a Proxy Pattern Based Design. More on that in the next post 🙂

Dirty Presets : Why Design is Important

To Smudge or Not To Smudge

Despite being quite capable of losing to five-year olds at art competitions, I know, even in my painfully limited knowledge about painting that Smudging is a pretty essential tool that all artists use. Krita has an excellent Color-smudge brush module which is again at the core of the brush module.

Image

Now, there are mainly three properties that are usually associated with Smudging :

  • Smudge Length : This decides that how long ( in terms of pixels relative to brush size ) do you want the smudging to have effect
  • Color Rate : How much the brush’s selected color should affect the whole smudging and how much the background color should affect the smudging
  • Smudge Radius : How much radius around the brush ( relative to brush size ) should be considered while calculating the color of the smudging

Now while Krita had the former two properties implemented and well used, the third property “Smudge Radius” was not implemented till now. So after going through this wish

 

 

 

To Smudge or Not To Smudge

Starting Off : GSoC 2014 with Krita

Hi, I am Mohit Goyal from BITS Pilani K.K. Birla Goa Campus and I am participating in GSoC’14 with KDE or to be more specific – Krita.

Krita is an established Digital Painting Software developed in the Calligra Suite of Desktop Applications under KDE. Its the product of a massive open source community of developers and painters alike – everybody trying to make it better each day. Here is a glimpse of some art developed by David Revoy( http://www.davidrevoy.com) in Krita.

My Tryst with Krita began in mid January through another developer for Krita. It took me days to set up Calligra and Krita partially because I was somewhat lazy and because the concept of compiling from source code was new. Usually sudo apt-get was all I did.

I got some excellent help from the community from people like Paul (mifth), Boud, DmitryK to get QtCreator rightly configured and to start off with my first contribution to open source – Fuzzy Parameter rotates in one direction. Despite all the help I got — It took me more than 20 days to make any headway.

All in all, after 3 months, several patches, several screenshots and several patches to fix the previous patches – my proposal to work with Krita in GSoC’14 got accepted. The proposal also was a product of some thought from my side and heavy correction from my mentors DmitryK and Boud.

About my Project :

I will primarily be working to improve the Brush Module in Krita. There are three features I will be implementing :

  1. Whenever the settings of a brush are changed from its preset, then after the brush is changed – the tweaked settings are lost. To counter this, the tweaked settings can be saved temporarily till the end of the session in a “Dirty Preset”. This Dirty Preset will work on top of the selected Paintop’s default preset. So, the user will not have to tweak his settings every time he changes a brush.

  2. An artist in Krita often uses short consecutive strokes while using brush-based tools.Since, each stroke is considered separate, to undo the strokes, the user has to call the Undo Command several times which is quite cumbersome. Using Cumulative Undo/Redo when drawing consecutive strokes with a brush-based tool, such strokes will be regarded as a single one for the undo system. Therefore when calling the Undo/Redo command, they will be undone/redone at the same time.

  3. Whenever an artist switches from one brush to another, he has to start making the brush all over again to include his own tweaks that he had made in the previous brush. Also, he may like to have certain capabilities from the other brush as well. Hence, a Master Brush Engine can solve this issue by incorporating all compatible capabilities in one brush engine. This brush engine can also import certain settings from different brushes and put them all together.

Continue reading “Starting Off : GSoC 2014 with Krita”

Link