Friday, January 29, 2010

Tonight's Photobomb Feature(s): More Gwibber Integration

I took a day off from work today. I slept in, I spent some time with my family, and of course, I worked on Photobomb! Specifically, I got a feature working that I actually started yesterday, but it took me a while to figure out.

Since gwibber stores both account information and messages in desktopcouch in the latest and greatest for Lucid, I was able to leverage the account set up and create a social application without the need to write all of the tedious social network protocol connecting code myself.

If you see there is a new tab with the Gwibber icon. If you refresh this tab, it will display all of the images that are in messages in your feeds, and also, all of the photos from the last few days that are tagged with one of your friends in Facebook. So this will pick up all the feeds that you have configured in Gwibber, plus the extra Facebook info.

To get the images from the messages, I just have to look in the couchdatabase and extract what I need. I do it like this:

self.__record_type = "http://gwibber.com/couch/message"
self.__database = CouchDatabase("gwibber_messages", create=False)
if self.__database is None:
return None
results = self.__database.get_records(record_type = self.__record_type, create_view = True)
for result in results:
document = result.value
if "images" in document:
#add the images to the tab
The code for adding the images is rather application specific. However, the rest of it is very applicable to anyone who wants to write apps that use messages from feeds. Essentially, by using desktopcouch, Gwibber now by default has a very straight forward API for reading received messages.

It's pretty easy to see what to query for and such, because of course being in desktopcouch means that you can use futon (a local web page that lets you explore your desktopcouch db):

Currently all of the facebook code is in Photobomb. But this is not a good place for it, because in order to make it work without extra configuration, I have to use the session info and application id for Gwibber. This is probably not a great way to do it. Rather, I will create a patch and ask Segphault to merge it into the Gwibber code base, and then everyone can just make a call like gwibber.get_images() and get back a useful data structure. I will be very happy if Segphault accepts the path, but not too surprised if he doesn't as he probably has a pretty accurate sense of my coding abilities ;) In any case, he'll see what i am trying to do, and perhaps be able to implement the feature better than I can. Otherewise, I'll just go back and try to figure out a better way to do it without using the Gwibber application code.

I ended up using Facebook Query Language to efficiently get just the right set of images. In case you are interested, after creating a facebook object using the python facebook wrapper, you can do stuff like this:
      fql = "select owner, src, src_big,caption from photo where pid in (select pid from photo_tag where subject in (select uid2 from friend where uid1=" + str(uid) + "))"
fql += " and (" + str(int(now)) + "-modified)/86400 < response =" fb.fql.query(fql)" pixbuf =" self.download_to_pixbuf(r[">
This feature of pulling images from your feeds compliments the feature that I implemented a couple of weeks ago that allows you to microblog your images. Together these features show that the Ubuntu Desktop is starting to bear some real fruit from the Social From The Start efforts.

Tuesday, January 26, 2010

Tonight's Photobomb Feature(s): Selectable Directories, Icons

Photobomb has hit a point where adding new features takes a bit longer than it used to because it is now necessary to refactor the code before it is manageable to add new features. In this case, the code for creating the list of images in the Pictures folder at start up was just part of the code for the main window. The fact that it was mixed in with tons of other code made it hard to maintain and enhance.

Last night I wanted to enhance the directory tab by making it so that users can select any directory they want. This is important to me as I wanted some way to get directly to pictures on a camera. By allowing the user to navigate the camera's directory, I could provide access, although in an admittedly cheesy and file centric manner. In the picture above, I am looking at pictures from the memory card from my wife's camera. It would be sweet to have proper camera integration some day.

It took me a couple of hours last night to move the tab into it's own class, as well as to actually implement the functionality for selecting and loading the directory. But now it's easy for me to work on the directory loading function. Note that directory selection is achieved via a new Quidget that I added. quidgets.prompts.choose_directory() yields a path to a directory. There is another refactoring to be done, which is to extract a base class for all of the tabs. However, I am refraining from doing any refactoring, unless it is required to add features.

Anway, after all was said and done, I had a functional tab. However, I was not too happy with how it looked. The folder symbol was next to, but not part of the button. And the tabs are plain with just words, but worse, I named the first tab just "disk", which is descriptive I guess, but just seems awkward.




So tonight I dinked around a bit with icons. I put the folder icon inside the button, and I used theme icons and some border_width to achieve some nicer buttons. There's still room for another button or two.

After a while of working on refactoring last night, I spent some time working on an icon for Photobomb. That's supposed to be camera icon with a bomb instead of a lens. I just created this with Inkscape, and then used glade to set the window icon to my new svg. I don't mean that as an insult to Inkscape. The crappiness of the icon is due to my ineptitude with anything artistic, Inkscape is awesome.

Saturday, January 23, 2010

Tonight's Photobomb Feature(s): Push and Hold Buttons, Simpler Web Tab


Yesterday afternoon I started to implement "Press and Hold" for certain buttons. Like the the "bigger/smaller" buttons, the "less/more opacity" buttons, and the rotation buttons. What I wanted (and now have) is that you can just press down on the button and hold it down. While it is held down the button keeps working, like the selected item keeps getting bigger the longer the hold it down.

Unfortunately, it turns out that gtk.ToolButton don't send pressed and released signals, just "clicked". So I went ahead and reimplemented the buttons for photobomb using regular buttons. Thus it took me a few hours instead of a few minutes to implement that features.

I actually added a Quidget for the press and hold buttons, and is it seemed like useful functionality that I could make a simple API for. To create a PressAndHoldButton, you just create a button as normal, but you pass it an action to perform while depressed. Here's how I created PressAndHoldButtons with an image. "action" is a function passed in to fire repeatedly as the button is held down:
     button = PressAndHoldButton(action)
image_path = getdatapath() + "/media/" + icon
img = gtk.Image()
img.set_from_file(image_path)
button.set_image(img)
button.show()
I suppose that I should really change the API so that you connect a function to a signal that the button fires, for example "tick". This would be more consistent with other PyGtk widgets. It would also developers to tie multiple functions to the button. In any case, the PressAndHoldButton manages a gobject timer internally, as the developer, all you need to do is give it a function.

Anyway, there's one more Quidget, and also while I was at it, I cleaned up the interaction of the clip tool and the pen somewhat, especially in terms of the most cursors they set. I also added buttons for saving a file and micro-blogging. I sniped the Gwibber svg file and sized it down to 20 x 20.

I also modified the web tab somewhat. Now instead of three separate buttons that each bring up a different prompt, there is a single text edit field. The way it works is to first check if the entered text starts with "http:". If it doesn't, the page assumes it's a search, and searches for images matching the keywords. If it does start with "http:" then does it end with the suffix of an image type? If so, it tries to just download that image. Otherwise, it assumes it's a web page, and tries to scrape the page.

Thursday, January 21, 2010

Tonight's Photobomb Feature: Screen Scraping

Today I added another button to the web tab. This button lets users plug in a web url, and then photobomb will try to display all the images on that page. So for example, I've screen scaped cute overload to grab a couple of the pictures.

I was able to do this efficiently despite my complete ineptitude with regular expressions because of strycore. strycore is a fellow Ubuntu community member who took over a silly little program that I started called lolz. I had written a bunch of crappy screen scraping code using split(whatever) to get images from funny sites. strycore wrote some solid regex based code that I was able to snipe and modify for more general screen scraping.

As you can see, I am completely out of ideas for easy ways to make the buttons. I suppose I should create something that looks like a search, something that looks like an image on a page, and something that looks like a web page. Oh well, in the meantime, at least I have tooltips :)

Speaking of tooltips, I haven't been *totally* slacking on photobomb. The other night I added tooltips so you can see the file names (or URLs) of images in the get images tab area.

Monday, January 18, 2010

Today's Photobomb Feature: Layout and PPA Availability

Today is a US holiday, so I spent a bit of it working on Photobomb (of course). Note that I tweaked the layout a bit, creating an attached panel on the side for all of the buttons. Photobomb currently fits pretty precisely into my Dell Mini 10v screen, and I intend to keep it that way. I also want to limit the number of features that are not accessible from the buttons. That means that I have a limited space, and there for limited features. I think that is a good thing. Photobomb should only have the bare necessary number of features to make it easy and fun to use!

Meanwhile, I've uploaded the latest version of quidgets and then photobomb to my PPA. If you want to play with photobomb, you'll need to be running lucid, and you'll need to be update enough to have the latest pygame. So:

1. Add my PPA
2. Install Quidgets
3. Install Photobomb

You'll fine photobomb in the Accessories menu (because I didn't tweak the setup.py file *at all*).

Of course I used Quickly to upload to my PPA! I am getting better and faster at setting my computers with my keys and everything else necessary to use a PPA.

Ubuntu Desktop Alpha 2 and Alpha 3 Work Item Update

As you are probably aware, in Lucid the platform team is working and re-planning in three separate milestones. Last week we passed the first such milestone, Alpha 2. The desktop team then re-planned for the next milestone, Alpha 3. This posting provides a chance to understand those plans. Note that these work items are documented in detail on the relevant blueprints.

Alpha 2 Summary
You can see the full and detailed results of our efforts here:
http://piware.de/workitems/desktop/lucid-alpha2/report.html
Note that the burndown chart is a bit preturbed, as it is in the past, and Martin moved the work item site to a different server.

Alpha 2 Accomplishments
  • Power management tweaks: work to help squeeze a bit more battery life out of a machine
  • Progress on xorg triaging and diagnosis tools: work to make it easier to get debugging information from users encountering issues with graphics
  • Boot Speed: reduced time from from GDM to working desktop from 18+seconds to 11 seconds
  • Jockey Hot plug
  • Latest Likewise Open
  • Change "UNR" to "UNE"
  • Change default applications for the desktop (haven't removed the Gimp or pulled in new f-spot yet, though)
  • Integrate the latest and greatest from the Dx team
  • Change apps to use Udev rather than HAL throughout the desktop, make HAL start on demand rather than at boot time
  • Desktop in the cloud: the server team is creating daily desktop images and hosting them in aws
  • Normal desktop throughput, such as update GNOME packages, updates from Debian, bug triaging, etc...
Alpha 2 Postponed Work
We did not get to everything that we had planned. Specifically:
  • Most of the Social From the Start items. We have re-scoped this work and moved the remaining items to Alpha 3
  • Xorg triaging and diagnosis tools: we only got about half way to this goal and will continue down this path

Alpha 3 goals
you can the full and detailed current plan here:
http://macaroni.ubuntu.com/~pitti/workitems/canonical-desktop-team-lucid-alpha-3.html

Alpha 3 Planned Work
  • Social from the start work focused on supporting the Me Menu
  • UNE session for desktop, desktop session for UNE
  • Finish xorg triaging and diagnosis tools
  • Make the experience for users of proprietary graphics drivers morerobust
  • Switching to -nouveau open source nvidia driver by default to support 3d and KMS (note that this is risky work and will depend on stability and quality of components in xorg and the kernel and will be backed outbefore end of Alpha 3 if necessary)
  • Continue to improve desktop start up speed
  • Tweak compiz effects
  • Continue to change apps to use Udev rather HAL
  • Continual integration of Dx assets as available
  • Continual integration of OLS assets as available
  • Normal desktop throughput, such as update GNOME packages, updatesfrom Debian, bug triaging, etc...
Beta 2 goals
Beta 2 is the final development milestone in Lucid. We are not currently planning for the desktop team to work any of our ownwork items for Beta 2. I want to keep the team's bandwidth open to focus on:
  • Integrate late breaking changes from Dx
  • Integrate late breaking changes from OLS
  • Find and the fix the worst bugs in terms of user impact

Sunday, January 17, 2010

Tonight's Photobomb Feature: Web Searches

Todays' feature allows you to easily import images from the web into photo bomb. You can search for a term, in which case you get back 20 matches which you can add to your photobomb with just a click. If you know a specific image that you want, you can get just that URL. You can choose a web search or just a specific url by clicking on the toolbar in the tab. This puts up a prompt for you to type into.

Yesterday I implemented the Web Cam tab by creating a (poorly named) camera_button Quidget and then adding it to the notebook. I took the OO approach a bit further today and implemented the who search tab as a subclass of gtk.VBox, which interacts with the main program through signals.

I suspect that an OO refactoring may be in the future. I can imagine making classes for each type of object added to the goocanvas, as well as classes for each type of import/export UI.

For the record, the branch is here.

Saturday, January 16, 2010

Tonight's Photobomb Feature: WebCam Support

Last week Seb128 uploaded pygame 1.9.1 to Lucid universe. This was great for me, because pygame 1.9 has fun and easy webcam support.

So today, while lying around recovering from a bit of jet lag, I created a widget that wraps up the pygame webcam support with pygtk. So the contents of the Web Cam tab in the screen shot above is actually from Quidgets, quidgets.widgets.CameraButton. (probably not the best name, but it when I started it, it was just a button that you clicked on, without other controls.

There are a few steps to using CameraButton:

1. Create it and connect to the "picture_taken" event:
     cb = CameraButton()
cb.connect("picture_taken",self.add_image_from_pixbuf)
2. Start it capturing:
 cb.set_capture(True)
3. Respond to picture_taken events and use the supplied pixbuf. So really, it's about 3 lines of code to get web cam support set up with quidgets.

After you have the pixbuf from the camera, you are on your own to do with it what you will. For me, it was easy, as already had code for handling pixbufs read from the disk, so I just needed to do a bit of refactoring and it worked without new code.

It's fresh, barely tested, code. You can get it from the trunk if you want to play with it.

About Quidgets
Quickly + Widgets = Quidgets
There is a Launchpad Project for Quidgets
The most up to date changes are in the Quidgets Trunk Branch

Back from Paris with New Photobomb Features

It was a long couple of flights to Seattle from Paris. Naturally, I passed some of the time working, but I also passed some of the time working on Photobomb ;)

In the above screen shot, you can see three features that I added:
1. First, I added opacity to ink and text objects. Notice the "highlight" effect over "Monkey Attack". I added that by inking over the text, setting the ink color, and then decreasing the opacity until it looked kind of like highlighter. This doesn't work on images (yet), just ink and text so far.

2. I changed the layout of the window a bit. Particularly, I put the Picture directory pictures in a tab, as I plan to add features that include other sources there. While I was at it, I put the loading of the pictures on a thread. Note that I used on my Quidgets for that, AsynchTaskProgressBox. This is a handy widget which you can show or not, but it basically handles setting up thread code for you.
     pic_task = AsynchTaskProgressBox(self.__load_pics)
pic_task.start()
def __load_pics(self, params):
images = []
#lots of slow code that will be run in a thread ....
Those two lines are all it takes to run a function in a thread. AsynchTaskProgressBox has some other features as well, like you can pass parameters to your thread, you can kind of cancel the thread, and you can display it as a widget just by adding it to a Window or Dialog, and calling show().

I saw some postings on planet.ubuntu over the last few days regarding threaded programming in Python. Perhaps Quidgets can help make it a bit more easy and fun.

3. I also added a cropping tool. That thing in the lower right is supposed to look like a scalpel. It's used by drawing a line around a picture, and then the picture gets cropped. Here's what it looks like as I am cropping the wise old monkey:

I also tweaked some interactions with buttons and such here and there.

About Quidgets
Quickly + Widgets = Quidgets
There is a Launchpad Project for Quidgets
The most up to date changes are in the Quidgets Trunk Branch

Thursday, January 14, 2010

Tonight's Photobomb Feature(s): Pictures Dir View (and layout and better ink)

The main feature that I implemented was that your pictures directory gets scanned, and all the pictures get added as buttons ready to be clicked. Clicking the button adds the pictures to the goocanvas.

I spent a few minutes creating an annotations toolbar (though just noticed I did not move the color button to it).

Also, I changed the data string for the ink paths to use bezier curves instead of just being lines. This makes the ink a little nice.

Wednesday, January 13, 2010

Tonight's Photobomb Feature: Microblogging


I took a pause from the opacity feature for items to add the ability to microblogging. After creating your image, you can choose "Microblog" from the File menu.

The way it works is to save the image to a temp file, and upload that to imgur. Then it opens a dialog that allows you to send the created url to your followers through gwibber.

You can add some text too of course, if you want.

I'd be interesting in knowing what the *right* image upload service is. imgur has a good api and good documentation for it, so that's why I chose it to start. Would be sweet if there was a UbuntuOne way to do it.

Welcome Didrocks and UNE Application Selection

The Lucid cycle brought a couple of fun changes to the Ubuntu Platform team. First, the Mobile team renamed the Ubuntu Netbook Remix (UNR) to Ubuntu Netbook Edition (UNE). Then they moved the project to the desktop team.

So this week we welcomed didrocks to the team. He's the first of three folks that we will hire to work on maintaining the high standards for UNE that the mobile team set with UNR.

So I have joined a few folks in Paris this week to get the first real Lucid spin of UNE ready. We just finished with the blueprint for UNE application selection.

We decided that to start, UNE is for computing on the go, it's not going to be a work horse distro out of the box. Of course, users can use Software Center to customize the installed apps as they wish, but by default we are going to start with some very opinionated choices. Based on user feedback, we will continually revisit these choices.
  1. No office applications installed by default. Perhaps we will add links to some web based office apps. Otherwise, users can install Abi Word, etc... as they wish.
  2. No email client by default. We will assume that users will be using web based mail. They can install Thunderbird, Evolution, etc... as they wish.
  3. No photo manager. The assumption being that folks will consume photos but won't be managing them, etc...
  4. Have Cheese and Gwibber available by default, assuming folks will want to do some fun socially stuff with their netbooks.
  5. Hide some of the app menu entries for utilities that are available in the normal stream of use. This includes stuff like print job manager, the screen shot tool, etc...
We are expecting that these choices will bring the size of the ISO way down, making it more accessible to folks who want to try it.

Tuesday, January 12, 2010

Tonight's Photobomb Feature: Transparent Selection


Last night I added selection indication. Tonight I made the selection boxes mostly transparent. This means that I know how to do opacity, so I've started adding the ability to set object transparency as well.

Note that I sniped the code for setting the transparency from Segphault' s GrabberSnap project (same place I got the "save as .png code").

Monday, January 11, 2010

Tonight's Photobomb Feature: Selection





I'm in Paris for a mini-sprint. Right now, I'm Chilling in the lobby of the hotel, as he chair in my room is making my back hurt.

So I added a little gray rectangle to show what item is currently selected in photobomb ...

Friday, January 8, 2010

photobomb can has lolz

Tonight's Photobomb Feature: Text

Tonight I add the ability to add text. You can also change the set the font and color. You can change the size just by growing the size of the object with the size buttons I added initially.

I also added the ability to edit items after you've added them. That is you can change the color of most objects, and the width of your ink strokes. You can't edit the text once you've added it, but I suppose I could add the pretty easily as a feature some night.

Tonight I wrote the first piece of code that suggested extending goocanvas namespace types rather than writing the program in a more procedural style. When changing colors, for most objects, you want to change the fill_color property. But for ink, you want to change the stroke_color property. So I added some code to detect the type and set the right property as needed.

       if type(self.selected_item) == goocanvas.Path:
self.selected_item.set_property("stroke_color",self.__ink_color)
else:
self.selected_item.set_property("fill_color",self.__ink_color)


Typically, when I find myself detecting types and branching, it's not long before I start sub-classing instead. However, when I look at the goocanvas reference it seems that there are limited objects, and perhaps a procedural style will hold out.

More Bug Reporting Tools


My new hero is Brian Murray. I start most mornings taking a look at our team assigned bugs. Typically running the report on demand meant waiting a good 5-10 minutes to get all the bug tasks.

So Brian copied Bryce's JSON format to make a recurring report that is compatible with Bughugger. As a result I instantly get a view appropriate for a manager. Brian is setting the script to run once per day, so it will be a tad out of date, but useful none the less, especially as I can always run the report on demand if needed right from Bughugger.

Also note the "gravity" column.

You can also just play with the JSON if you want.

Thursday, January 7, 2010

Tonight's Photobomb Feature: Ink Properties

Tonight I added ink width and ink color. This means that you can kinda sorta do a lolz with photobomb.

I was a bit bummed to find that there is an Ink Color Button, but there doesn't seem to be a similar control for a toolbar. So I just made a button that pops up the color dialog.
It would be sweet if there was a popup menu connected to a toolbar, so you could kind of pull down and set your color instead of popping the dialog. Perhaps there is a related quidget in the future. Speaking of quidgets, I similarly used a popup to get the integer value from the user for the ink width. It was nice to be able to just pop up the prompt with a one liner and move on. So Quidgets ftw!

I used goocanvases to show the current color and line width on the buttons:
     path_str = "M 5 20 L 25 20" 
self.__ink_width = 5
ink_button_gc = goocanvas.Canvas()
ink_button_gc.set_bounds(0,0,40,40)
ink_button_gc.show()
bttn_root = ink_button_gc.get_root_item()
self.__ink_width_path = goocanvas.Path(data=path_str,
parent=bttn_root, line_width=self.__ink_width,
stroke_color=self.__ink_color)
self.builder.get_object("toolbutton_ink_width").set_icon_widget(ink_button_gc)

It seems to work, but every time the code makes the change, I get a gtk warning:
bin/photobomb:304: Warning: invalid cast from `GooCanvas' to `GtkMisc'
gtk.main()
bin/photobomb:304: GtkWarning: gtk_misc_set_alignment: assertion `GTK_IS_MISC (misc)' failed
gtk.main()

I suppose I'll need to either:
  1. log a bug and hope this gets fixed in gtk
  2. figure out if the bug is in my code and fix it there
  3. use a more tradition gtk way of doing this kind of thing

Wednesday, January 6, 2010

Tonight's Photobomb Feature: Ink


Another night, another photobomb feature. Now you can free hand draw paths on the goocanvas. Sadly, the screenshot utility does not show that the cursor changes to a little pencil while you are in pen mode. I need a better icon than the edit icon for pen mode. Maybe a couple of minutes in inkscape to solve that.

One weird thing about photobomb has been that I have stuck with a fairly functional programming style. I usual start out a programming by extending the various classes that I am using. I'm wondering if I am using goocanvas for specifically what it was designed for, that I haven't needed to extend anything yet? We'll see. It could be that when I add things like selection indication and such, I'll need to refactor toward a more OO approach.

Steering the Release to Alpha 2

As you may be aware, the Ubuntu Platform teams have been tracking their development work with "work items" and "burdown charts", and have been keeping the status up to date hourly, and also public. For example, I have created a page for tracking Desktop related work.

This is really the last week to get our work done for Alpha 2. The burndown chart shows that we were on track for the first half of the milestone, but then when holidays came, work items stopped getting closed out. Finally today, I took some "drastic actions" and changed the scope of the work targeted for the milestone. We are now under the trend line for the milestone. This means, though, that work has been pushed to later milestones.

That big dip in total work items came this morning when I moved all of the Social From the Start work items to alpha 3 by reassigning the blueprint there. Basically saying that we are giving up on social from the start for this milestone. I think we will have to postpone a bunch of that planned work to after Lucid.

It's too bad when you don't meet your goals, but this is the purpose of burndown charts. To help you see the situation for what it is, and to take action to steer the project.

This also gives us a sense of how many work items we can accomplish in a milestone, which will help us plan and prioritize our commitments better for future milestones. Looks like about 60 is a good number to shoot for (depending on the work items of course).

Tuesday, January 5, 2010

One feature a day Photobomb


Last Sunday evening I explored goocanvas enough to know that I wanted to create an app with it. At the same time, my vacation is over, and I am already a bit over committed with coding projects. But I reeaaallly want to work on this. So I decided to just add on feature a day, and see how far I get. See if I can just limit myself to just a little bit each day.

In the meantime, my Photobomb prototype code got a bit out of control and disorganized so I threw it all out and started from scratch. Since I know the API better, I was able to take a much more organized approach. So ...

Day 1 I added:
  • Ability to add images from disk to the surface (thanks Quidgets for making it a one-liner to get the image path from the user)
  • Resize the images
  • Drag around the images (kind of was buggy though)
  • Remove an image
Ok, so that's more than 1 feature, but it was still a bite sized amount of work, and was necessary to get to the juicier features.

Day 2 (tonight) I added:
  • SVG images for the button labels (thank you Inkscape)
  • Ability to rotate images
  • Ability to send an image to the bottom or bring it to the top of the stack
  • Fixed the buggy drag code (had to use convert_to_item_space or the whacky things happened with rotated images).
  • [edit]I cheated a little and added another feature, I sniped some of Segphault's code to implement saving as a png[/edit]
The attached screen shot show three images added, each resized and rotated to look cool.

Next up? I'll probably respond to the feature request to add thought balloons and stuff. But there is also inking.

If you want to join in the fun, I pushed the code to a branch.

Sunday, January 3, 2010

Hooray for goocanvas, tadavinci reborn?


Yesterday I posted about my first little foray into image editing on Ubuntu. I started a little program called "photobomb". I received a comment on that post, suggesting that thought bubbles, and the ability to size and place them, would be a nice feature to add.

I was interested in discovering what it would be like to code that up, so I investigated a bit. It was immidiately apparent that while PIL is great for manipulating images as data, it was not designed to support manipulating images as objects on a screen. As I investigated, I discovered goocanvas. Goocanvas provides a widget like abstraction over SVG, and it is quite well integrated with Gtk, so I was fairly easily able to port photobomb to use goocanvas. It includes classes for images and paths.

I haven't been able to figure out how to write out an image file from the goocanvas, so actually saving the edited file is currently broken. But you can type in a thought and have it appear within a thought balloon, but I you can't size or place it yet.

Goovanvas has support built in for figuring out what item was clicked on, rotating it, scaling it, etc... It's really quite well suited for a photobomb app

While working with the goocanvas API, I realized that I've been here before. About three years ago, when Silverlight was new, and I cared about it, I created "TadaVinci" in Silverlight.

TadaVinci could:
  • Search for images and add them to a canvas
  • Resize, rotate, and place those images
  • "Scalpel" the images, which meant you could kind of carve them up
  • Allow users to draw in different colors and pen thickness
  • Adjust the translucency of any object on the surface
Since I wrote all this functionality once, I think I could write it again with goocanvas. I could also make it a bit more groovy and social:
  • automatically import pictures from Picture directory
  • automatically import pictures for friends via Gwibber
  • automatically import pictures from a web cam
  • publish to facebook, etc... via Gwibber
  • Lots of lolzy stuff, like a "breaking news" frame, etc..., stamps, etc...
I feel very motivated to work on Photobomb, I think it could really add a neat social element to Ubuntu, especially UNR. Mostly, though really fun to write and use. Ah, but alas, vacation time is over.

Tomorrow morning I need to wake up and do my "real job" of managing the Ubuntu Desktop team. I've also got three other projects in the works Bughugger (which is a real work project), Quickly which is like 50% work and 50% person, and Quidets (all personal, but it really helps with Bughugger).

So I don't see myself resurrecting TadaVinci using goocanvas in the near future, but boy would it be cool.

Friday, January 1, 2010

File Prompts ... never write File Selection Code again



Today I wrote two new functions in quidgets.prompts open_image_file, and close_image_file. These prompts allow a user to select and save a file, and include free functionality for the developer:
  • Built in filtering for images (note the "Images" filter set in the open dialog above).
  • Automatically starts in Pictures directory (unless a different default directory is included by the developer).
  • Automatic detection of an existing file in the save dialog and a prompt to replace or cancel.
Currently, these dialogs don't actually handle saving or opening the files, just get paths that the user selects, so the code for opening and saving files in Photobomb looks like this ...

   def open_image(self, widget, data=None):
result, image_path = prompts.open_image_file("Photobomb")
if result == gtk.RESPONSE_OK:
self.__image_path = image_path
self.builder.get_object("image1").set_from_file(self.__image_path)
def save_as(self, widget, data=None):
result, image_target = prompts.save_image_file("Save Photobomb")
if result == gtk.RESPONSE_OK:
image_source = os.path.join(self.__tmp_dir, "img.png")
shutil.copy2(image_source,image_target)
A significant reduction in the amount of code normally required. More open/save prompts to come, in the meantime, I just need to spend some time with the Gimp to make some more progress on Photo bomb before I upload it to my PPA.




About Quidgets
Quickly + Widgets = Quidgets
There is a Launchpad Project for Quidgets
The most up to date changes are in the Quidgets Trunk Branch

Photobomb - I want to make the fun things fun

This morning while doing my normal blog skimming over my morning coffee, I ran across a link for the year's 10 best photo bombs. In the meantime, my son and daughter have been playing with their new Karmic equipped Dell mini 10v's including Cheese, and the pics from our recent vacation. Meanwhile, I've been eyeing PIL, wondering if the solution to our "we need a combination image viewer/very lightweight image editor" problem might be found there. All of this combined in mind into an app that I wanted to write.

This seemed like a great opportunity to make a fun app. Quickly was born for this. And thus, in an hour or two of hacking around while also hanging out with my family, Photobomb was born. the idea is that you load up an image, choose one or more photo bombs to add to it, and then you can save off the photo. It took a bit of learning to figure out how to set up masks and paste and such with PIL. But after that hurdle, I now have code that finds photo-bombs and adds them to the toolbar. So far I have one photobomb in place (the famous squirrel).

So was it fun and easy? I think PIL is a well designed API for the most part, but it was quite hard to find documentation on properly using masks.

In terms of PyGtk, notice that the Open dialog lacks filters and such. This is because code for adding filters and such is repetitive and *not easy and fun*.

See the documentation here. It's not particularly hard, but it is not fun either. As such, I think I may add some quidget.prompt calls, like quidgets.prompts.open_image(some basic stuff), and quidgets.prompts.save_image(some basic stuff). I suppose prompts for text file, music file, video file, etc... would also be good. Some one-liners could make apps like this more fun and easy to write.