Sunday, September 26, 2010

$quickly create ubuntu-pygame targets


I hit a kind of hard part in photobomb, basically, creating copies of objects and applying clippings turns out to be a bit challenging. Sometimes when I'm feeling stymied, I switch to something new for a while to keep the programming fun. Of course, this results in having a few programs, like Photobomb, that are in a perpetual state of being incomplete. However, since I write FOSS software for the fun of it, I figure ... meh ... might well keep it fun.

Anyway, I recalled a really simple and fun game we used to play in college. I decided to build some similar game play, using the Quickly PyGame template. I created this template for Lucid, but it didn't really get any attention from me since then.

Here's some game play video, I mercifully left out the sounds:



The goal is to get points by touching the target, which moves after it is touched. The player controls the green smiley faced guy. By default, the PyGame template assumes that the player will control "the guy" using the keyboard. So, I had to change this by mapping the guy's location to the mouse. The place to update the guy's location is in the main files "controller_tick" function. This function fires each clock tick, and you use it to update the models of all the sprites and such. Checking out the PyGame docs, this turned out to be a simple one-liner:
    g.x, g.y = pygame.mouse.get_pos()

g is the variable name for the instance of the guy, and it's easy to set with the tuple returned from mouse position function. So that was all it took to make the guy follow the mouse (and deleted the code that used the keyboard of course). But then, I wanted to enemies to bounce around and be a bit hard to avoid, by by default, enemies wrap around the screen. Since I wanted all the sprites in the game to bounce off of wall, I edited the base_sprite.py file to change the wrapping to bouncing:
        #make the sprite bounce off of walls
if self.x + self.rect.width > sw:
self.x = sw - self.rect.width
self.velocity_x = -self.velocity_x
if self.y + self.rect.height > sh:
self.y = sh - self.rect.height
self.velocity_y = -self.velocity_y

if self.x <= 0: self.x = 0 self.velocity_x = -self.velocity_x if self.y <= 0: self.y = 0 self.velocity_y = -self.velocity_y
This code simply changes the direction that the sprite is traveling so it is reflected at the opposite angle that it hit. There's probably a more elegant way of doing it, but this turned out to be readable and reliable for me once I wrote it.

A bit harder was making enemies bounce off of each other. In previous games I wrote, sprites either did not interact, or killed each other. So this part took me quite a few iterations. I also saw that there were quite a few options for how to program the physics. I chose to make items essentially exchange their velocities, but I added just a touch of randomness. The randomness is designed to keep enemies from getting locked into boring patterns, like moving back and forth in a straight line. Here's the code I eventually ended up with to handle guys bouncing off of each other.
    for enemy in enemies:
e = pygame.sprite.spritecollideany(enemy, enemies)
if enemy is not e:
if enemy.velocity_x * e.velocity_x >= 0:
if enemy.velocity_x >= e.velocity_x:
faster_x = enemy
slower_x = e
else:
faster_x = e
slower_x = enemy

stash = faster_x.velocity_x
faster_x.velocity_x = slower_x.velocity_x
slower_x.velocity_x = stash
else:
stash = e.velocity_x
e.velocity_x = enemy.velocity_x
enemy.velocity_x = stash

if enemy.velocity_y * e.velocity_y >= 0:
if enemy.velocity_y >= e.velocity_y:
faster_y = enemy
slower_y = e
else:
faster_y = e
slower_y = enemy

stash = faster_y.velocity_y
faster_y.velocity_y = slower_y.velocity_y
slower_y.velocity_y = stash
else:
stash = e.velocity_y
e.velocity_y = enemy.velocity_y
enemy.velocity_y = stash

e.velocity_x += random.randint(-5,5)
e.velocity_y += random.randint(-5,5)

enemy.velocity_x += random.randint(-5,5)
enemy.velocity_y += random.randint(-5,5)

Due to horrible variable naming, this code is too hard to read. I should really fix that up. In any case, it is work mostly reliably. The only time it doesn't work is that sprites can get overlapped too much, and they don't travel far enough way to not collide in the next tick, and they look a bit odd weirdly bouncing off of each other.

I added a few game play features, like making the guy a ghost after he gets killed, to give the player a chance to get away and not killed over and over again if the guy is caught in a touch place. I also programmed for the background to update every 20 points.

I used the beloved InkScape to create some new sprites. Of course, I'm a pretty bad programmer, but I'm a worst artist! Any help with graphics would be most welcome :)

I still have some stuff left to do before I consider the game done enough to put in my PPA:
  1. Make and associated some nice sounds.
  2. Make the game increase in difficulty as levels go on. I'll probably increase the number of enemies, make them go faster, and also make the homing missles smarter, laster longer, and maybe faster.
  3. Format the score and levels so they are readable.
  4. Add power ups. I'm thinking ones that make the enemies freeze for a bit, maybe slow them down too. Free lives, and point multipliers of course. I was also thinking that sometimes the power ups could do bad things, like speeding up the enemies and/or changing their velocities unpredictably.
  5. Find a theme and a reasonable name.
If you want to check it out, branch, collaborate, etc... feel free to get the code from launchpad.

Saturday, September 11, 2010

Anything New in Quickly Widgets for Maverick?

Going into Maverick, I had envisioned myself spending a lot of free time on Quickly Widgets throughout the cycle. Sadly, though, due to various factors, I did not make the kind of progress I was hoping to. Then a couple of days ago didrocks pinged me to ask if I was going to update Quickly Widgets for Maverick, because if I was, now is the time. So, today I went through all my changes over the last few months, to make sure tests were passing, and that they were generally working well.

Well, it was a good exercise, because I came to find that I had actually made some decent progress! Here's a quick overview of what is new and improved in Quickly Widgets for Maverick (or will be when it actually gets into Maverick next week). Note that most of the changes were put into place for specific users, so I know that each of these improvements will be useful to at least one person :)

Enhanced DictionaryGrid
In Lucid, when you created a dictionary grid, the keys were used for the titles of the columns. I think this is good, because it's easy and fun. You can get going fast, and a fair amount of the time, this functionality will be more than sufficient. However, sometimes that column title needs to be changed or maybe different than the keys. This was doable, of course, because a DictionaryGrid is just a TreeView, and you can set the titles on a TreeView. You could loop through the columns, and set the titles as desired. Too much code, so I added a helper function. You can create a dictionary of keys to titles, and set them. So an app like PyTask would do this if it wanted different keys and titles:
        titles = {"name":_("Name"),"priority":_("Priority"),
"due":_("Due"),"project":_("Project"),
"complete?":_("Completed")}
self.grid.set_column_titles(titles)

You don't have to do all of the titles, you can just pass in the keys that you want you to change titles for. I also made it a bit easier to access a column. You can just index into the columns by the key. So in the tests, for example, you can see where I used it like this:
        grid.columns["key1_1"].set_title("KEY")

Nice one liner. This is just accessing the gtk.TreeViewColumn, so you can whatever you need to with the column, this just makes it easy to get to the columns you need.

As I previously blogged, there is now a datecolumn with built in editing (thanks to the pygtk faq):


And there is a grid filter to go with it:

So now, any column with a key that ends in "date" will default to be a date column.

DictionaryGrid also has an enriched set of arguments for the cell-edited signal. In addition to the row index and key that were previously reported, it now tells you the new value and also provides the dictionary for the row as well. Makes it easier to decide what to do when a cell is edited without having to probe into the grid.

Enhancemed CouchGrid
The most salient enhancement to CouchGrid, is that it's easy to tell the grid to delete data form desktopcouch now. You do this by passing delete=True to the remove_selected_rows function. So apps like PyTask don't have to do all these crazy contortions to remove data from the underlying store, PyTask just does this:
    def remove_row(self, widget, data=None):
"""Removes the currently selected row from the couchgrid."""

self.grid.remove_selected_rows(delete=True)

I like this because it lets the programmer keep the grid as their mental model of how to interact with the underlying store, and keeping desktopcouch an incidental piece of plumbing.

Enhanced GridFilters
Personally, the ability to apply a filter UI to a grid with just a few lines of code is one of the things about quidgets of which I am the most proud. I still don't know how I managed to pull it off, but I did. I like it because it turns a big chore into something easy and fun. If nothing else, it makes a sweet demo.

So I did make some good progress with this in Maverick. The key thing was that I refactored what a FilterRow contains. The FilterRows were hard coded to use a combo box and TextEntry. This became limiting with data types other than strings. So, I did some open heart surgery on the Filter Code, and after a successful refactoring, can now drop in any set of widgets I would like for a filter row. In addition to a date filter, there's an IntegerFilter now:


New Widgets
Thanks to sil, it's now really trivial to download content from the Internet. Sil wrote the code, and I did a vblog about this a while back. In case you missed that:
This widget works by reusing the common signal handling patterns in PyGtk. From the test app:
    def start_download(self, btn):
prog = UrlFetchProgressBox("http://www.ubuntu.com/desktop/get-ubuntu/download")
prog.connect("downloaded", self.downloaded)
self.vbox.pack_start(prog, expand=False)
prog.show()

def downloaded(self, widget, content):
print "downloaded %s bytes of content" % len(content)

There is also a TextEditor now. This removes all the bookkeeping code that you have to write to keep a TextView, TextBuffer, Markers, etc... all straight.

For example, to tell the TextEditor to highlight a word, just add it to the text editor's list of words to highlight:
        self.editor.add_highlight("some")


Really! That's all you need to highlight the word "some" in a text editor.
It's also got undo and redo built in! So instead of mucking with this yourself, you can hook up an undo command with a one-liner:
        undo_button = gtk.Button("Undo")
undo_button.connect("clicked",self.editor.undo)

If you haven't tried making an undo, redo stack yourself, trust me, this is much easier.

I recently blogged about the new WebCamBox as well. I won't rehash that here.

House Keeping
Finally, I went through this morning to ensure that all of the quidgets were using gettext properly (so bring on the translations if you got 'em), and I've also been adding and improving tests as I've been along.

Anyway
I guess I should write a nice comprehensive tutorial or similar. But in the meantime, there are lots of videos and such on my blog. So, if you want to write an app for Ubuntu, consider using Quickly and Quickly Widgets, because it's getting more fun and more easy with each release!


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

Friday, September 3, 2010

Quidgets < 3 Gstreamer, and the Return of Photobomb

I'm finally settling back into the groove of some of my side projects. I guess I'm handling the new position a bit better as time goes on, and feel that I can spend some free time working on somethings that I want to do, not just things that I feel that I should do.

So, these side projects I do for fun, and they are the most fun when they combine together in sweet ways. During the dead of winter, I spent a bunch of weeks working on Photobomb . On of the features that I added was that you could add an image directly from your web cam. To do this, I used the PyGame Web Cam API, essentially because I saw the API, and knew that I would be able to use it relatively easily, which in fact turned out to be the case.

It also turned out that not everyone had PyGame already installed on their systems. As a result installing Photobomb meant a 25+ Megabyte download, most of which was PyGame. So I was advised to use GStreamer instead. I got started on this conversion back in April, by creating a simple web cam display application using gstreamer. I ran into a series of roadblocks, one such roadblock was removed by Chris Halse Rogers of desktop team fame, who knew why it kept crashing (basically, I was trying to access the xid of a widget that wasn't yet realized).

But I soon had a pipeline together that could display the web cam, but I could not figure out how to modify it so that it could save out a picture whilst still displaying the web cam output. I finally hopped into #gstreamer to see if someone could give me a pointer. Well, it turns out that someone already wrote a pipeline called caemerabin that does everything I need for the web cam, and more.

Well, it turned out that the documentation was out of sync with the current API. This isn't too surprising, as camerabin is still in gstreamer0.01-plugins-bad, and the API is actually improved by the changes. But I was struggling to understand camerabin, so I went back to #gstreamer. Often in IRC, someone will volunteer to spend some time helping you out with a problem. thiagoss (who I think might be this guy) really helped me out. I'm not sure, but I think he may actually be a primary author of camerabin. Anyway, he set me straight on a couple of things, namely:

1. use $gst-inspect camerabin to see what properties and methods the GStreamer elements really support (if they are out of sync with the docs).
2. use GST_DEBUG=2 to run your gstreamer apps, as this puts more warnings in your output.

Well, between these 2 tips, I was quickly able to realize that my WebCamBox widget would not much more than some Gtk/Gstreamer app boiler plate, with a wrapper around camerabin.

So, for example the "take picture" function just creates a time stamp, then tells the camerabin instance to emit a "capture-start" signal.
      stamp = str(datetime.datetime.now())
extension = ".png"
directory = os.environ["HOME"] + _("/Pictures/")
self.filename = directory + self.filename_prefix + stamp + extension
self.camerabin.set_property("filename", self.filename)
self.camerabin.emit("capture-start")
return self.filename
Then in on_message, I capture the message that it is done, and fire a signal:
       t = message.type
if t == gst.MESSAGE_ELEMENT:
if message.structure.get_name() == "image-captured":
#work around to keep the camera working after lots
#of pictures are taken
self.camerabin.set_state(gst.STATE_NULL)
self.camerabin.set_state(gst.STATE_PLAYING)

self.emit("image-captured", self.filename)
Play, Pause, and Start were trivially easy to implement:
        self.camerabin.set_state(gst.STATE_PLAYING)
self.camerabin.set_state(gst.STATE_PAUSED)
self.camerabin.set_state(gst.STATE_NULL)
Like I say, there is also some boiler plate to instantiate the camera and associate it with a gtk.DrawingArea. It took me a lot of iterations to get it working, as you can see from all of these pictures of me working on it ...

The net result is that it's now pretty easy to create an app with a web cam in it. Here's all the code for the WebCamBox test app.
if __name__ == "__main__":
"""creates a test WebCamBox"""
import quickly.prompts

#create and show a test window
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.set_title("WebCam Test Window")
win.connect("destroy",gtk.main_quit)
win.show()

#create a top level container
vbox = gtk.VBox(False, 10)
vbox.show()
win.add(vbox)

mb = WebCamBox()
mb.video_frame_rate = 30
vbox.add(mb)
mb.show()
mb.play()

mb.connect("image-captured", __image_captured)
play_butt = gtk.Button("Play")
pause_butt = gtk.Button("Pause")
stop_butt = gtk.Button("Stop")
pic_butt = gtk.Button("Picture")

play_butt.connect("clicked", lambda x:mb.play())
play_butt.show()
mb.pack_end(play_butt, False)

pause_butt.connect("clicked", lambda x:mb.pause())
pause_butt.show()
mb.pack_end(pause_butt, False)

stop_butt.connect("clicked", lambda x:mb.stop())
stop_butt.show()
mb.pack_end(stop_butt, False)

pic_butt.connect("clicked", lambda x:mb.take_picture())
pic_butt.show()
mb.pack_end(pic_butt, False)

gtk.main()
Almost all of it is standard code for creating widgets. I love that doing functions like play, pause, stop, and take a picture can be handled in lambdas. So much easier!

So my last step was to drop it into Photobomb. All I had to do was modify the CameraPage class that I had already set up for the PyGame based version.
import gtk
from quickly.widgets.web_cam_box import WebCamBox
from ImageListPage import ImageListPage

class CameraPage(ImageListPage):
def __init__(self):
gtk.VBox.__init__(self,False, 0)
self.__camera = WebCamBox()
self.__camera.connect("image-captured",self.image_captured)
self.__camera.show()
self.__camera.set_size_request(128, 128)
self.pack_start(self.__camera, False, False)

button = gtk.Button("Take Picture")
button.show()
button.connect("clicked", lambda x:self.__camera.take_picture())
self.pack_start(button, False, False)


def image_captured(self, widget, path):
self.emit("clicked",path)

def on_selected(self):
self.__camera.play()

def on_deselected(self):
self.__camera.stop()

Well, almost all I had to do. I discovered a bug where if the WebCamBox is not actually visible, it locks up Photobomb if you try to show it. For now, I've worked around this by putting the CameraPage as the first and open page, so it just works. However, I suspect the bug is due to the xid not being available when camerabin tries to display on it. I think with a little thought, I can block this condition, and perhaps not let the camera play if it's not ready yet.

Anyway, I ended up with a few lines of wrapper code, around my wrapper code, and it all works thanks to the efforts of the folks working on camerabin!

camerabin has a whole lot of functionality that I haven't wrapped yet. It takes video, including audio! Also, it looks like you can change encoders, and drop in filters and such into the pipeline. To handle this for now, WebCamBox exposes a "camerabin" public property, so if you are using the widget, you won't run into a wall.

Wednesday, September 1, 2010

Quickly Widget Dating

Earlier this summer I started some work on DictionaryGrid and GridFilter in order to make them easier to use in apps like PyTask.

Well, tonight I decided to finish what I started and get this stuff into trunk. Specifically, I wanted to have a DateFilter to go with DateColumn. I wanted to use a Calendar widget for users to select dates, instead of typing them in.

Before I could do that, I had to do some heavy refactoring in GridFilter. I originally made the simplifying assumption that users would enter text into an entry field to enter their values. The only exception was CheckFilter, which needed no gtk.Entry, but I just put in a small hack to make that work. So, this simplifying assumption meant that I could deliver grid filters really fast, but now it was time refactor so I could add new features.

Fortunately, it seems that I had started that and was well on the way, so I only had to finish a few things out for the refactoring. I had even already implemented CheckFilter in the new structure, so it was a simple matter to copy that pattern to get to the DateFilter working.

It's always an odd feeling when I am working with code that I had written a while back. There's a certain amount of detective work involved, "how did I go about making this all work?" There's a strange familiarity, but yet it's similar to debugging someone else's code. It's nice when I figure it out, especially when I think "that's just how I would have done it."

I also found a rather serious bug in CouchGrid along the way. So I stopped off and spent some time fixing CouchGrid, and adding test to make sure I don't see that bug again. The code slightly improved while I was in there, making sure that the grid doesn't have to render itself multiple times when it's initializing.

Anyway, I'm really happy to have made some progress on Quickly Widgets again. It was really fun and relaxing. Time well spent this evening.

Why I Have Nothing Interesting to Say

This posting has been kicking around in my draft's for almost 2 weeks now. I've been wanting to polish it a bit, since it's a bit personal, but Jono's posting a couple of weeks back inspired me to just run it over and get it out there, even if it's still rough. I have nothing interesting to say, anyway ;) Just be warned, the following is not well organized or concise in any way ....

Anyway ... I normally use my blog as a way to share and get feedback on projects like Quickly and Quickly Widgets. I haven't been blogging because I haven't been working much on those things lately, so haven't had much interesting to say along that front (though a friend did unblock me on my WebCam widget, so now I'm blocked on bending gstreamer to my will rather than a random crash.)

The reason that I haven't been working on those is two fold. One part, I've been traveling a lot for work and I took a holiday. But the main reason is related to a recent refactoring of the Ubuntu related teams at Canonical.

Changes to Canonical Organizational Structure
This refactoring (or "reorg" in corporate speak) was led by Matt Zimmerman and Robbie Williamson. The resulting structure broke the whole 100+ person Ubuntu team at Canonical into 3 teams:

1. Linaro Engineering. These are the Canonical folks working on the Linaro project.
2. Platform Services. This team is dedicated to doing work in Ubuntu for partner teams in Canonical, like OEM services.
3. Ubuntu Engineering. The team of Canonical developers focused on Ubuntu the Free and Open Source Community distribution.

I believe the purpose of this refactoring was to make the teams a bit smaller and more focused. However, one of the effects was to leave the Ubuntu Engineering Team with an even tighter focus on Ubuntu as a community distro. Ubuntu Engineering is the biggest team of the three, I believe 85 or so people working on it.

Changes to My Role(s) in Ubuntu
Another effect is that of the refactoring was that each of these teams needs a leader, or "Director" in terms of job title, each of whom will report to Matt. The reason that I have been a bit busy to work on Quickly and Quickly Widgets is that I interviewed for, and subsequently got the "Director" role for Ubuntu Engineering. So my job title is now "Ubuntu Engineering Director" (or something like that). I'm still also the Engineering Manager for the Desktop Team until we can find someone awesome to take that role (we're still interviewing, so if you are interested, please apply!!).

This all went down like 10 weeks ago or something. The personal effect on me is that I've been trying to learn how to do a new role while still trying to hold down the fort on the desktop. So, basically, I am working 2 full time roles. As you can imagine, I am not doing either very well.

Figuring Out My New Job
As Director, the engineering managers for the kernel, foundations, server, ARM, desktop, QA, and community now "report" to me. Of course, you know these folks (pgraner, robbiew, jib, davidm, tbh, marjo, and jono) and you know that they are awesome. There are a couple of new roles too (release manager and technical architect). We have very strong people in these roles as well.

So if the management team and the engineers are so awesome, what's my job? This is a question I have been asking myself, and I do see some areas where I should provide some leadership. I'd like to spend the rest of the post quickly commenting on just one of those areas. It's a bit hard to label, but I think I'll put it under the heading of "Nurturing the Ubuntu/Canonical Partnership".

Of course I was originally attracted to Ubuntu because it's a Free and Open Source Community Distro, but what made me quit my job and base my living around Ubuntu was that it's a community distro with a Commercial Partner. I thought that a commercial partner would make my efforts more relevant (by reaching more people) and more endurable (by sustaining the project for a long time). A commercial partner can also negotiate with OEMs and help fulfill the dream of a pre-installed FLOSS desktop.

So it's important for Ubuntu to honor this partnership in order to maintain it's staying power and relevance. Conversely, it's important to Canonical that Ubuntu is a thriving community open source distribution. The reasons for this are probably self-evident, so I'll leave that out. Anyway, it's helping Canonical with this part about being a good partner to Ubuntu that the rest of this post is about.

Being Part of the Community
Firstly, in my view, being employed by Canonical is not something that separates me from the Ubuntu Community. If anything, it provides me a lucky position within the community, if nothing else because I am paid full time to contribute to Ubuntu I have more time to dedicate to it. The point is that being on the Ubuntu Engineering Team means that I am part of the Ubuntu Community. This is true for allpeople employed by Canonical to work on the Ubuntu. The Ubuntu community is comprised of all kinds of people contributing in all kinds of ways, including some that get paid by Canonical to work on Ubuntu full time.

So, if Canonical and Ubuntu both benefit from this partnership, and I am both part of Canonical and the Ubuntu Community, I think that part of my new role of Director should be to help these partners work well together. There are some things that I think we (Canonical employees in the Ubuntu Community) can do better in this regard. I'm still thinking through it, but I am formulating two key goals at this point, one around transparency, and the other around growing the number of core contributors.

Transparency
I think that we (the whole community) still follow our transparent processes around UDS, blueprints, specs, and bugs. So we are transparent in the sense that anyone can come and carefully study our documents and learn pretty much anything they want about what Ubuntu is working on. I suspect that the way of being "transparent" work very well for the project when there were way fewer users and way fewer people working on the project. But now the project has grown a bit, and perhaps the old ways are not totally sufficient.

In one sense, we've made great strides in exposing what we are working on via our work item tracker. But this a very granular view. I'd like to see us do better in expressing the gestalt of a release, the high level goals for the release. I'd like to see us be able to *push* information at this level before, during, and after UDS, and throughout the cycle. I don't know if this goal is really about changing the way we work per se, so much as creating an information architecture around the work that we (and I mean "we" inclusively as the Ubuntu community) are doing, and then having the discipline to maintain a drum beat of communication within that architecture. In this way, the community should better be able to see what the Ubuntu Community and Canonical is focused on in developing Ubuntu, and how that work is going.

Growing Core Contributors
While I think the work item tracking system has been great for exposing what we are working on, and also for providing visibility into our status, I suspect it has had an unintended effect. I think it's turned the Canonical employees into feature creation machines. Something about a burn down chart motivates you to work to stay under that trend line. While creating lots of new features is great, I am concerned that it has come at the expense of other important work. A community needs investment, and I am wondering if our focus on work items and features has supplanted some amount of our investment in the community (and by "our" here, I am referring to Canonical Employees in the Ubuntu Community).

I can see several areas, such as patch reviews, REVU, archive admins, etc... that are bottlenecked by not having enough core contributors. But our very inability to focus on things like reviewing patches and REVU means that we are not inviting new people to build towards being core contributors. But new people is exactly what we need to remove the bottlenecks! A sweet catch-22. I think that this will require the bold move to hold back on commitments to features, to tilt Canonical Employees investments a bit toward nurturing those new comers (as well as our stalwart comrades, of course).

So there are 2 great topics for UDS discussions. Whatever the case, can I just say that I am thrilled to have this new gig, and I look forward to getting to know a whole lot of people and to help them with their goals for Ubuntu? I guess being my blog, I can say that ;)