Wednesday, December 29, 2010

This is Photobomb


The last couple of days I made some good solid progress on Photobomb:
  1. Refactored items on the goocanvas into PhotobombItems to make changes easier, and code easier to maintain.
  2. Fixed the Gwibber tab to pull images from the Gwibber sqlite database.
  3. Removed Python threads from throughout the application while keeping the UI from freezing during long running actions (thanks gobject.idle_add!).
  4. Added a "download-error" event to UrlFetchProgressBox and handled download errors better.
There are still a few things I want to get to, but I am making steady progress.

Anyway, I was talking to some folks about Photobomb, and they kept referring to it as an "Image Editor". To me, and image editor is used to open an image, modify the image, and save the image. Photobomb is decidedly not that! Photobomb integrates with your social desktop, allowing you to mashup images from your devices, the web, your feeds, and your web cam. Photobomb also lets you share those mashups into your feeds. So, it's a social app.

Here's a 5 minute video I made to try to help explain Photobomb ...

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:
  1. 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.
  2. 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.
  3. 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.
  4. 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.
  1. 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.
  2. 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.
  3. 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.
  4. I will change the Gwibber page to use libgwibber, and also the poster button to use libgwibber.
  5. 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.
  6. I want to add an undo/redo stack (which should be lots easier after I'm done with the PhotobombItem refactoring).
  7. 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.
  8. 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.
  9. 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.
If you want to play with latest Photobomb, get it from trunk.

Friday, December 10, 2010

Hot New Quickly Template Features

The Quickly Ubuntu Application template for Natty has cool new features already. Here's a couple of videos to highlight these changes.

Here are some changes contributed by Mike Terry. What he's done is:
  1. Reduce the code in the generate boiler plate down to about 65 lines. This makes it a lot easier to hack on and maintain.
  2. Make it so that you don't have to use the builder to access widgets that you've added in glade. Instead of "self.builder.get_object("entry1").set_text("hi"), you can just do self.ui.entry.set_text("hi"). In other words, Quickly just knows.
  3. The third thing demoed here is the new auto signals feature. Instead of picking a signal handler name, and defining it in Glade and in your code, if you follow some simple conventions when you name your function, Quickly will just know it's a signal handler, and it will work.




In this second video, you can see the much much much improved preferences system contributed by Tony Byrne. By following some naming conventions, and adding 2 lines of code, you can persist and access user settings with ease.

Alpha 1 Unity Checkpoint


While attending a sprint this week, I've gone ahead and updated my Dell mini 10v to Ubuntu 11.04 Alpha 1, and also took some updates on Tuesday.

I have to say, I am finding Unity to be running really really well on this computer. I can use the spider diagram to provide a more structured description to what I think is going well, and also, how far we still have to go before we have a shippable product.

Up
  • Launcher Appeal (6-7): The Launcher looks a lot nice n autohide mode.
  • Launcher Functionality (3-6): Significantly improved now that the launcher includes autohide and quicklists allow me to pin and unpin apps to the launcher. It's still too hard to use with workspaces, but code for that landed this week, so next week, I hope to pop this up to 7! Jason is absolutely rocking the Launcher functionality.
  • Application Window Management (5-6): Little tick marks in the launcher items show how many windows are open. Meta-W shows all the windows in a workspace. I think they should add an item for Meta-W to the launcher. That would make it really easy and discoverable to find your apps.
Down
  • Indicator Quality (6-4): Starting this week, there has been these times when the indicators stop responding to mouse clicks, or become don't activate for a really long time.

Unchanged
  • Launcher Performance (8): The launcher is even faster on my Dell mini 10v than on my desktop at home. I assume this is because I use a computer with a shared memory graphics chip (i965) for my desktop, but with a large screen. So the combination laptop graphics chip with desktop screen is not ideal. However, it's still plenty fast and snappy on my desktop. I'm tempted to pop this up to 9, but I want to see how it's working for folks with proprietary drivers first.
  • Application Launch Time (8): Nothing seems to have changed here.
  • Everything dash related. I could pop up Find and Launch apps since they tied the Ubuntu button to the Applications directory as a temporary measure until the dash is ready. However, I think I'll just wait until it's their real deal.
  • Indicator functionality hasn't changed, expect I hear there is code in trunk to bring back keyboard access and navigation! This has been a real productivity killer for me, so I can't wait until next week.
  • Global Menu Integration. However, I hear that there is a team working on Mozilla/Unity integration. I'll also be looking forward to when they can turn the shotwell menus back to the global menus.

Thursday, December 2, 2010

Log those Unity Crash Reports!


Natty Alpha 1 is baked and available!

This alpha is exciting to me because the Unity Launcher is already pretty usable. I'm using it daily, and am already addicted. The move to the new compiz has really really sped things up. Of course, I can't recommend to an average user that they rely daily on alpha software. This is fresh code, and it stresses more fresh code in the graphics stack. This means crashers.

However, you don't have to be a hacker to really help get Unity into shape stating right now. A great way to help Ubuntu and the Unity team right now is to get them as many crash reports as we can, so they can these issues fixed asap and move on to adding those features we are so much waiting for.

Way 1: Tonight, before the packages get updated, run Ubuntu Alpha 1 from a live session when it become available. If there are crashers, Apport, the crash report system, will kick in and help you log crash reports easily. If you can't get to it right away, no problems, but you'll want to use the current daily build to make sure you are testing up to date packages.

Way 2: Install Alpha 1 on a test machine. Enable Apport, and start upload crash reports when there are crashers. It's really easy to do, instructions are on the wiki. If you go this route, you can update daily and help by reporting new crashers as you encounter them.

Monday, November 29, 2010

Unity in Natty Evaluation 1


Today I am finally finding Natty to be usably stable. So long as I stay away from Open Office, it seems to be running quite fine. So, I updated my maverick spider diagram in an attempt to capture where I think Unity is in the journey to being the Ubuntu desktop.

In this first natty diagram, yellow is the target, blue is maverick, and that orangy color is my subjective assessment of Unity as it is today. You can review the criteria that I chose from assessment in a previous post.

Note that there is a large portion of the diagram missing. Everything related to the Dash is zero, because none of that is implement yet. Here is a summary of why I picked these values for the other items:

Natty > Maverick
  • Launcher Performance (3 to 8): The natty launcher feels snappy when you drag the items, and when the launcher overflow and "folds" items, the unfolding and access to those items is also totally responsive. This is a big improvement!
  • Application Launch Time(4 to 8): I was told a few times that apps didn't start any slower under Mutter. However, they sure always seemed to. Well, they seem to start nice and fast now, so I'm saying that application launch time is nice and fast.
  • File Management (3 to 6): The launcher features a nice big Nautilus item at the top of the launcher. This makes access to typical file management tasks much easier accomplish, because you can find them. Since there is no dash, there is no integration with dash and that search yet, so hopefully this particular area will improve.
Maverick > Natty
  • Launcher Quality (5 to 3): I'm probably being really unfair here, but I'm blaming all the crashiness, especially when I'm using OOo on the Launcher. It's probably really Compiz itself, but subjectively, it feels like the launcher is the new thing, so I'm blaming that.
  • Launcher Functionality (6 to 3): Without quick lists, this took an big hit. You can really only launch and switch now. Adding back in the quick lists, and then getting a hiding launcher, and we'll be in business.
  • Application Window Management (5 to 4): Not much has really changed here, except that without the quick lists there is no where to click on different windows from the same app. I use Alt-Tab, so this doesn't much impact me, personally. Minimized windows still disappear with no way to get them back.
  • Application Window Management:
Natty == Maverick
  • Launcher Appeal (6): The launcher is still a bit "blocky". I do like how the items look, and the attention getting animations as well. I expect to see lots of improvements to the look and feel of the launcher, especially when they start adding in some of the animations and transitions.
  • Global Menu Integration (5): I don't see any changes to this part. Firefox still has it's own menu, for example.
  • Indicator Appeal (7): I don't see any changes here, either. I expect to see some slightly tweaked icons and maybe and improvements to the look of the indicators themselves.
  • Indicator Performance (8): No changes here.
  • Indicator Functionality (6): No changes today, but I hear that the new indicator for the network manager was supposed to land today. That will mean that all the default functionality will be managed by indicators, so no more panel applets by default.
I also just noticed that key nav between the indicators isn't working! grrrr. It's also not working for the global menu. Well, Accessibility is already rated zero, so there's really no way to change my ratings based on that, unless I added it to "Indicator Functionality". I'll see how annoying it is to me, and maybe change it then.

Wednesday, November 24, 2010

Ubuntu is *not* moving to a rolling release

So, I just got asked to provide a statement about whether Ubuntu is moving to a rolling release. The statement I provided was:

"Ubuntu is not changing to a rolling release. We are confident that our customers, partners, and the FLOSS ecosystem are well served by our current release cadence. What the article was probably referring to was the possibility of making it easier for developers to use cutting edge versions of certain software packages on Ubuntu.This is a wide-ranging project that we will continue to pursue through our normal planning processes."
The reason that I was asked to comment on this was that an article appeared this morning that built off of some comments that Mark made regarding daily builds. The article went on to make some reasonable conjecture about possible implications. Links to this article were then labeled things like "Ubuntu Moves to Rolling Releases!"

I do like the idea of making it easier for developer and enthusiasts to use daily builds of software that they really care about, and maybe even have them discover this capability through the software center. Currently you have to find PPAs or maybe activate backports to do this. But having a stable release with a six month cadence plus the option to stay cutting edge on certain packags (at your own risk) is not really a rolling release.

Friday, November 19, 2010

3 Weeks In

I was about half of last week, and this Monday as well. So I didn't do a week 2 update. Again,, please note that these are things that are happening that I found interesting or important, or was otherwise involved in. This is not the status of work that I personally did. Here's my perspective on week 3 ...

Unity
This Week
  • Unity landed in Natty (today actually).
  • I installed Unity and turned it on in the Compiz settings. I was able to play a bit with the launcher, and it was very snappy, and it launched apps. Places is still not working. Compiz in general seems quite snappy.
  • Unfortunately running Unity caused so much crashing, that I was unable to evaluate it for a spider diagram again.
  • A decision was taken to focus Unity on for Natty, and not work on a Maverick PPA. Based on my experience with Unity today, this was a sane decision in my estimation.
  • I checked in with Luke and Gary regarding Unity accessibility. Luke is still working on getting his head around gobjects and such.
Next Week
  • Hopefully enough stability in Unity that we can really evaluate it.
  • Luke to start with some accessibility prototypes.
Testing
This Week
  • The QA team has started putting automated integration tests into place. These tests will try to catch bugs in the way applications work within Unity very quickly and frequently.
  • We started planning a sprint, where a few Canonical folks will get together for the first week of December and focus on tests for kernel SRU validation, as well as for desktop integration.
Next Week
  • More tests written and running.
  • Better definition for sprint goals.
Contributors
This Week
Next Week
  • Start of Patch Piloting schedule.
Software Center
This Week
  • Plans for New Apps in Maverick were finalized. Will be installed in /opt/extras.ubuntu.com. Python apps will lack per-compiled byte code if installed in this way for Maverick, but there should be a better solution in Natty.
  • didrocks landed changes in quickly to support installing to /opt in Natty.
  • mterry landed changes to the Quickly template to make it easier to attach to events (no more defining signal handler in Glade).
  • I'm not sure about the status of ratings and reviews. Since it's mvo driving, I assume all is well.
Next Week
  • ???
Misc.
This Week
  • Schedule-wise, there is one week until Feature definition freeze as of yesterday. So this week we asked all teams to have work items identified by eod yesterday so that we could finalize plans by the Feature Definition Freeze. You can see all the blueprints for natty. I summarized how some of the Essential and High importance blueprints will effect the Editions as well. Of course there will be lots of Medium and Low blueprints that have a lot of impact too!
  • Release meetings started again, with new format and agenda thanks to skaet.
Next Week
  • Next Thursday is Thanks Giving holiday in the US, so I'm expecting about 60% of normal productivity in Ubuntu.
  • Work items should be identified for Alpha 2, so I will prepare a detailed review and ensure that items are prioritized appropriately heading into the A2 milestone.

Friday, November 5, 2010

1 Week In

Back from UDS for a week now. Here's a progress update on some of the happenings in Ubuntu that I am tracking. There are, of course, myriad other aspects to the product that I care about, but that I am not following closely. You may notice a strong correspondence between these areas and The 5 Foci.

Of course I am doing almost none of this work personally. When it makes sense I'll credit the specific people and/or teams. Questions and comments welcome, of course. I have no idea if this kind of thing is useful to folks. But I wonder if I can keep up a weekly cadence of updates.

Unity
This week
  • Dx team is working to get the Compiz based experience ready for testing
  • Nothing new uploaded this week, so no update to the spider diagram :(
Next Week
  • I hope to start testing new compiz-based experience and update the spider diagram

Testing
This Week
  • ara has confirmed that mago will work with apps under unity so it's possible to start writing integration tests
  • Unity integration testing is blocked this week on looking into the global menu because of a bug in the dumper tool, but it should be unblocked next week
  • Server team outlined steps for packaging Hudson
Next Week
  • Switch Unity Integration testing on Natty
  • Start teseting the global menu on Unity (this is important because there are lots of bugs their in Maverick)
  • Get more tests in place and running daily
  • Progress on packaging and deploying Hudson
Contributors
This Week
  • Created documentation for Path Pilots (a tweak to our system for responding to contributors)
  • Straw man schedule for Ubuntu Engineering Engineers set up (these are engineers paid by Canonical to work on Ubuntu)
Next Week
  • Share Patch Piloting schedule with Ubuntu Engineering Engineers, let them change it around to suit self
  • Ensure documentation works for Patch Pilots
  • Pick a date to start with the tweaked system
Software Center
This Week
  • I followed up on UDS session regarding using /opt for installing new apps on a stable release, and drafted a proposal to the App Review Board that they ask the Tech Board to remove the /opt requirement for Maverick, since there are so few apps we can really review them carefully, and the technology is not there to support /opt properly in Maverick
  • didrocks broke out work items to ensure that Python build system and Quickly will support installing to /opt in the future
Next Week
  • Perhaps see some progress by didrocks on making the Python build system work with /opt
  • First meeting regarding Donations with IS, I requested that the notes from the call be posted to a mailing list or such
Misc
This Week
  • I confirmed with cjwatson that we can make good progress on "Text Free Boot" in Natty. It won't surprise anyone to know that I had trouble grocking the blueprint :)
  • Open stack is all packaged up and ready for better integration with Ubuntu Server
  • Set schedule to get to Feature Definition Freeze with the Ubuntu Engineering Managers (All Blueprints Accepted by 11/11, All Work Items Identified by 11/18)
Next Week
  • Perhaps create a system for getting feedback on which platforms can boot Text Fee so we can start to assemble the white or blacklist
  • Some server team members to attend Open Stack Design Summit next week
  • pitti to reset work item tracker to start burndowns for teams that are ready

Tuesday, October 26, 2010

This is it!

This is it! Porting the Unity view to Compiz, comibing the Desktop and UNE editions, and defaulting to UNE for users who can run it. This is is a huge opportunity for the Ubuntu community to make something that can deliver free desktops to millions and millions of people who don't have software freedome today. And also, having a lot of fun with our friends doing something really big along the way.

There is also a big risk here. We *have* to make Natty "really good". But what does "really good" mean? I guess this is inherently subjective, so here's my take on it. "Really good" is multi-faceted, and for me, I think about Unity "goodness" in the following dimensions.
  • Launcher Performance - Is the launcher snappy and responive?
  • Launcher Quality - Is the launcher robust and not buggy?
  • Launcher Appeal - Is the launcher visually beautiful and are the interactions fun?
  • Launcher Functionality - Does the Launcher have the essential functions that users need?
  • Find and Launch Apps - Can users easily launcher their apps?
  • File Management - Can users find their files and operate on them as desiered?
  • Search - Does the Unity search work well for users?
  • Dash Appeal - Is Places visually beautiful and are the interactions fun?
  • Dash Performance - Is places snappy and responsive?
  • Dash Quality - Is places robust and not buggy?
  • Indicator Functionality - Do the indicators have the essential functions users need?
  • Indicator Quality - Are the indicators robust and not buggy?
  • Indicator Performance - Are the indicators snappy and responsive?
  • Indicator Appeal - Are the idnicators visually beautiful and are the interactions fun?
  • Global Menu Integration - Are applications across the desktop working well with the Global Menu?
  • Application Launch Time - Do applications seem to launch quickly and smoothly?
  • Application Window Management - Can users position windows, and use desktops as desired?
  • Accessibility - Is the toolkit accessible to screen readers, is the functionality of the desktop universally available?
So, after thinking about all these different facets, I hit on the idea of represent the current state on the target state in a spider diagram. In the following diagram, the blue shape is the current shape of Unity (in Maverick) and the Red shape is where I think Unity needs to get to in Natty. I made this by grading each facet on scale of 1-10 in an Open Office Spreadsheet. Again, in a subjective manner.


So, clearly, there is a lot of work to do to get Unity "into shape". And, of course, we still need to be awesome maintainers. We need to keep up with upstreams, fix bugs, respond to users, etc... This part of our work has the further complication that the Server Edition is starting to get some more serious usage, so we need to ensure that we're doing the right things for server as well.

So, how do we be great maintainers, while getting Unity into great shape? Well, for the Ubuntu Engineering Team (of which I am the Director), the answer is to focus. I will be asking each team to limit their work items so that they can have plenty of bandwidth open to help with bug finding, bug fixing, enhancing performance, etc... whatever it takes to change the shape of the spider diagram.

Here are the 5 foci for Ubuntu engineering:
  1. Unity - Well, not much more to say what I mean here.
  2. 2D experience - Not all users will have hardware to run Unity. For these users, we must ensure that Ubuntu continues to work really really for them, just as well as Maverick works, and just as well as Unity in Natty works.
  3. Software Center - This an important area for us to continue to make innovation and progress in order to meet the needs and expectations of users and software developers. So, this is the one area of actual feature development that is staying on the list of focus areas.
  4. Testing - Ubuntu Engineering needs to become a testing organization. I want to see automated itnegration testing for Unity, and I want to see it starting soon.
  5. Contributions - This is possibly the most important part. We need to step up our responsiveness to existing core contributors and new contributors. We should be implementing fewer features ourselves, but we should be ensuring a really great and personal experience for people who contribute patches, apps, etc... So, Ubuntu Engineers should be signing up for fewer features, but more time for contributors.

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 ;)


Tuesday, August 10, 2010

Can we count users without uniquely identifying them?

Aaaah
Hi all. I'm just back from a rather nice holiday. Well, technically, I'm still on holiday, but there were a few things I wanted to take care of, so I popped in for a few hours of work yesterday and today. I saw that there was this post on Phoronix that triggered me writing a post that I've been meaning to do for the last few weeks, since the Canonical Platform Team got together in Prague three weeks ago, to be exact.

Pre-installed desktops ftw
One of the roles of Canonical relative to Ubuntu is to get Ubuntu pre-installed on as many computers as possible. This is one of the dreams of the Linux desktop. Pre-installs mean end users don't have to fiddle with configurations, installing drivers, etc... (at least when done well) and the users can make an apples to apples comparison between their free desktop and proprietary systems that normally come pre-installed.

Canonical does this by working with OEM customers. OEMs are companies that sell assembled computers to people. One of these customers asked Canonical if there was some way that they could know how many computers that they send out with Ubuntu on them keep Ubuntu on them. The customer's engineer came up with a system where they would create a unique identifier for each Ubuntu computer they sold, and then when the computers requested update info daily, it would send that unique identifier with it.

The customer didn't really want to use a unique identifier though, because though it was anonymous, the customer wanted to *count* computers, but unique identifiers are for *tracking* (following a user over time). We mulled it over and over, and finally, based on our experience with web browsers we hit upon a system of non-unique channel identifiers to do the counting. This would make tracking impossible, but of course, tracking is not the goal, counting is.

Non-unique channel identifiers
So, we flashed on this: if each install sent just the model name and the number of times it has updated, systems could be counted, but no unique data would ever be sent to the server. Now, I am not a mathematician, so each time I try to explain why I think this works, it takes me a while. But in the end, everyone is convinced. In fact, Matt Zimmerman ended up writing a test program to prove to himself that it worked. Let me try, stick with me here ...

Every day each computer from the customer sends it's model name and the number of times it has already sent this data to the server. So if a model of a computer is called, say "foo", the first day it sends "foo" and 0 to census.canonical.com. After sending the 0, the computer remembers that it already sent a 0, so it will send a 1 next time. When the server sees the foo.0 in the log data, it essential stars a new counter for the model foo. The total number of foo.0 are the total number of the model foo ever activated.

Take one of those foo computers. The next day it will send foo.1, saying "this is a computer of model foo, and this is the 2nd time it has pinged that it's alive". Notice that neither foo or the number 1 are unique data. Any number of computers will be reporting the exact same model name and increment number. When the server sees a 1 come in, it finds the first counter at 0 and increments that counter to 1. Now it knows the total number of computers ever activated (all the counters), and it can count all the counters that were incremented in a day and thereby know how many computers were online that day.

Future?
Currently this system is only slated to be used by the specific OEM customer who requested it, and it will be up to the customer to disclose the data they collect as they wish. I wonder if it would be a good thing to install on normal ISOs though, but this would be part of our normal participatory community decision making process. Projects like this make think that users would like to be counted, so long as they can't be tracked. We'll see how it plays out, it may be something to discuss at UDS if the community feels the data would be useful.

Sunday, June 20, 2010

New Quickly Widget: Text Editor

Here's an 8 minute demo showing how to use the new TextEditor Quickly Widget. This removes all the pain and suffering of adding text editing functionality to your app. No more gtk.TextBuffer, no more gtk.TextIter. Just a series of simple function calls, and you're ready to go. Of course, TextEditor is a gtk.TextView, so if you need to access any of the power and flexibility of the underlying Gtk library, it's right there.



TextEditor is now available in quidgets trunk.

Sorry for the loudness of the video. I made it in a coffee shop, and moved my mic closer to compensate for background noise. It didn't work out too well.

New Quickly App: Daily Journal



Quickly has started to unlock productivity for me in unexpected ways. I've mentioned about writing my own development tools, like bughugger, and slipcover. Last week I extended this to writing my own productivity apps. In this case, I wrote an app to replace my Tomboy usage to focus specifically on the functions in Tomboy that I actually used. The above video shows that app, "Daily Journal". It's available in my PPA.

In my next posting, I'll show how I used quickly.widgets.text_editor to create Daily Journal.

Monday, June 14, 2010

Go Here to Learn to Program from MIT

I run into folks who want to get started programming, but they "don't know a language". If you are in this camp, I highly recommend the online course from MIT. It's designed for people with no prior programming experience, and it's Python!

After the first few lessons, you'll know enough Python to start a Quickly app!.

Sunday, June 6, 2010

New Quickly Widget - async downloads with two lines of code




The Ubuntu Developer's Manual team was discussing the instructional app that we should use for the manual. During this discussion, it became apparent that there wasn't a way to download from a URL that was both easy and also asynch. Instead of choosing between simple and good, Stuart made a Quickly Widget that provides a way to fetch from a URL that is both simple *and* good.

fetcher = UrlFetchProgressBox("http://identi.ca/api/statusnet/groups/timeline/8.rss")
fetcher.connect("downloaded",self.create_grid_from_feed)
So, two lines! Just say what url you want to download, and tell it the function to call when it's done.

Tuesday, June 1, 2010

Having Users Makes Your Code So Much Better


I mentioned in a previous post that I was finding PyTask to be pretty cool. Of course, one of the cool things, for me, was that it used Quickly Widgets. As I mentioned, Quickly Widgets lacked some key features, like a DateColumn.

Having a user means that I know at least one way that someone it trying to use the code. I went ahead and implemented a DateColumn in PyTask, and my next step will be to add DateColumn to quickly widgets, so Ryan doesn't have to maintain the code in PyTask. First I need to kind of make room for this in the grid_filter module. I have a good idea of how to do it, so just a SMOP at this point.

There were other more subtle things that I ran into as well. For example, it turns out that I didn't handle the case of deleting rows in a CouchGrid, or even removing rows from a DictionaryGrid if that grid was filtered. The later case was "just" a bug. So I worked around this in PyTask code so that PyTask could ship while waiting for me to fix Quickly Widgets.

Since I have intimate knowledge about how the PyGtk was assembled, I was able to write this code for PyTask

    def remove_row(self, widget, data=None):
"""Removes the currently selected row from the couchgrid."""
# work around to actually delete records from desktopcouch
# in maverick, using delete=true in remove_selected_rows will have
# the same effect
database = CouchDatabase("pytask")
for r in self.grid.selected_rows:
database.delete_record(r["__desktopcouch_id"])

if type(self.grid.get_model()) is gtk.ListStore:
self.grid.remove_selected_rows()

else:

# The following code works around:
# https://bugs.edge.launchpad.net/quidgets/+bug/587568
# get the selected rows, and return if nothing is selected
model, rows = self.grid.get_selection().get_selected_rows()

if len(rows) == 0:
return

# store the last selected row to reselect after removal
next_to_select = rows[-1][0] + 1 - len(rows)

# loop through and remove
iters = [model.get_model().get_iter(path) for path in rows]
store_iters = []
for i in iters:
# convert the iter to a useful iter
store_iters.append(model.get_model().convert_iter_to_child_iter(i))

for store_iter in store_iters:
# remove the row from the store
self.filt.store.remove(store_iter)

# select a row for the user, nicer that way
rows_remaining = len(model)

# don't try to select anything if there are no rows left
if rows_remaining < 1:
return

# select the next row down, unless it's out of range
# in which case just select the last row
if next_to_select < rows_remaining:
self.grid.get_selection().select_path(next_to_select)
else:
self.grid.get_selection().select_path(rows_remaining - 1)
Essentially, it deletes the selected rows from desktop couch, and then goes on to figure if the grid is filtered, and if so, figures out where in the unfiltered model the rows are, and removes them from there. It also tries to select a row for the user after removing.

So I moved the code to delete records from desktop couch into CouchGrid.remove_selected_rows and all the "remove properly even if filtered" goo into DictionaryGrid.remove_selected_rows. The result is that when the next version of Quickly Widgets lands, Ryan will be able to simplify the function down to this:
    def remove_row(self, widget, data=None):
"""Removes the currently selected row from the couchgrid."""
self.grid.remove_selected_rows(delete=True)
A bit more sensible.

Another area where the DictionaryGrid lacked functionality was related to column titles. It was easy to write a little code to change the column titles:

        for c in self.grid.get_columns():
if c.get_title() == "name":
c.set_title(_("Name"))
elif c.get_title() == "priority":
c.set_title(_("Priority"))
elif c.get_title() == "due":
c.set_title(_("Due"))
elif c.get_title() == "project":
c.set_title(_("Project"))
if c.get_title() == "complete?":
c.set_title(_("Completed"))
Except, when doing this, it meant that the column titles in the GridFilter didn't match. :/ This is because the GridFilter got the names of the columns from the keys instead of the title.

Again, knowing the structure of the PyGtk intimately, I was able to work around this by modifying rows in the filter as each is created:
   def __new_filter_row(self, widget, data=None):
"""
new_filter row - hack to allow naming of columns
in a grid filter.

This code works around:
https://bugs.edge.launchpad.net/quidgets/+bug/587558

"""

row = self.filt.rows[len(self.filt.rows)-1]
row.connect("add_row_requested",self.__new_filter_row)
model = row.column_combo.get_model()

for i, k in enumerate(model):
itr = model.get_iter(i)
title = model.get_value(itr,0)
if title == "name":
model.set_value(itr,0,_("Name"))
elif title == "priority":
model.set_value(itr,0,_("Priority"))
elif title == "due":
model.set_value(itr,0,_("Due"))
elif title == "project":
model.set_value(itr,0,_("Project"))
if title == "complete?":
model.set_value(itr,0,_("Completed"))
I fixed this a bit easier in Quickly Widgets.

All of this managing the title stuff was really obtuse, and it seemed that setting column titles might be generally useful. So I added two things to DictionaryGrid to make this easier. First, I made a property that returns a dictionary of columns indexed by the column key, so you can easily get ahold of a column you want. Here's some code from one of the Quickly Widget tests:
        grid.columns["key1_1"].set_title("KEY")
That's a bit easier than for c in grid.get_columns(), etc...

I also made a convenience function that Ryan can use. Here's the code from the tests:
        titles = {"key1_1":"KEY1","key1_2":"KEY2","key1_3":"KEY3"}
grid.set_column_titles(titles)
So this should make it really trivial to manage the titles of columns separate from the keys in the dictionaries. Of course, if you don't want to care about column titles, that's fine too. They still work just by using the keys.

Anyway, thanks to Ryan for letting me use PyTask to improve Quickly Widgets!