The diary of a dedicated Ubuntu user that lucked into his dream job working on the Ubuntu team.

Monday, December 27, 2010

New Personal Goal: Photobomb for Natty

I'm on holiday for the next week, yeah! I've started filling some of my free time by resurrecting Photobomb (again). There have been some technical improvements to the APIs I've been using, and also, I've learned some ways to do a few things better. I'm hoping that by spending a few hours a day, I can pretty much complete Photobomb by the end of this week, and then work on getting it into Universe for Natty.

Things I accomplished so far:

I fixed the WebcamBox quidget so that it doesn't hang if you try to tell it play when it hasn't been realized. The effect of this is that I can put the webcam tab on the end of the tabs, much nicer.

Then I went on to complete how the UI is organized. I want Photobomb to work really well on netbooks running Unity in Natty. Since I started Photobomb on Lucid, apps have gotten slightly less horizontal space but more vertical space. I moved the toolbar from the right, and added it as a tab on the left. Even when making the tabs wider, this reclaimed lots of vertical space.

I added delete and duplicate! So now you can delete or duplicate the selected item. I was going to add cut, copy, and paste, but I think delete and duplicate works better for this app.

When I started Photobomb, I simply created GooCanvas items like goocanvas.Imate, goocanvas.Path, and goocanvas.Text. Each of these types of items interact with different parts of the toolbar slightly differently, so there were lots of places in the code where I had to use code like "if type(self.selected_item) == goocanvas.Path:". Whenever I find myself type checking, I know that subclassing is in my future. Also, goocanvas.Items only let you write to their opacity properties, so for the increase and decrease opacity functions, I've been tracking opacity externally, in a dictionary, rather than as a property on the items. Refactoring was clearly in order before I continued to add features, so I created photobomb_item.py, and added PhotobombImage, PhotobombPath, and PhotobombText, then implemented common properties on each. It was only after doing this that it was reasonable code factoring to create the duplicate function. I'm not quite done this part, though.

Here's a quick video showing the new layout and the duplicate function in action:

There's still a lot on my Todo list before I'll consider Photobomb ready for general availability.

Complete the refactoring into PhotobombItems. This will drag me into my first experience with multiple inheritance in Python. I think that it will be simple for this particular application. Every PhotobombItem will derive from PhotobombItem to pick up common properties and functions, but also from the appropriate goocanvas.Item (Image, Path, or Text for now). I'll probably do this one next, as I will use that to fix the opacity controls.

I want to move common editing commands into their own toolbar which is always available. The new found vertical space from Unity provides this luxury.

I use Python threading code in directory tab, and also the web tab. Python Thread code is notoriously difficult, and indeed, there are a number of hangs or situations where Photobomb doesn't quite quit all the way due to threads running and colliding. I will replace threads with a combination of UrlFetchProgressbox, and gobject.timeout_add. In fact, I am considering creating quidgets to handle common asynchronous activities that I have mistakenly used Threads for in the past. Depending on how it goes, I may create DirectoryScannerProgressBox, DictionaryScannerProgressBox, XMLScannerProgressBox, and JSONScannerProgressBox. I would intend for these to work in very similar ways, but make it super simple to perform long running tasks without blocking the UI or resorting the Threads.

I will change the Gwibber page to use libgwibber, and also the poster button to use libgwibber.

I'll make the webcam tab present the webcam image on a button instead of using a separate button. This will be more consistent with the other tabs.

I want to add an undo/redo stack (which should be lots easier after I'm done with the PhotobombItem refactoring).

For the toolbar tab, I didn't really do any code refactoring, I just grabbed the table of buttons, removed them from the main window, and packed them into the tab. I should really do a proper job of making the toolbox into a proper widget that rips signals. In this way, the UI will become much easier to modify in the future, and generally the photobomb code will become reusable.

Since Photobomb has no preferences, I may as well remove the preferences code. All it does it start up desktopcouch and then not use it.

Finally, the global menu means I can add in a menu bar without sacrificing any vertical space. This will have a few benefits. It will mean users can access the toolbar functions without changing to the toolbar tab, it will be way easier for me to add key commands for the functions, and I can add certain functions only to the menu. For example, the export and microblog commands may be better hanging out on the file menu, rather than be part of the toolbar.