How do I deal with multiple common user interfaces?
Asked Answered
I

3

7

I'm working on a python application that runs on 2 different platforms, namely regular desktop linux and Maemo 4. We use PyGTK on both platforms but on Maemo there are a bunch of little tweaks to make it look nice which are implemented as follows:

if util.platform.MAEMO:
    # do something fancy for maemo
else:
    # regular pygtk

There are roughly 15 of these if statements needed to get the UI looking and working nice on Maemo 4.

This has been very manageable for all this time. The problem is that a while ago there was a new version of Maemo released (5, aka fremantle) and it has some big differences compared to Maemo 4. I don't want to add a bunch of checks throughout the GUI code in order to get all 3 platforms working nicely with the same codebase because that would get messy. I also don't want to create a copy of the original GUI code for each platform and simply modify it for the specific platform (I'd like to re-use as much code as possible).

So, what are ways to have slightly different UIs for different platforms which are based on the same core UI code? I don't think this is a python or Maemo-specific question, I'd just like to know how this is done.

Infralapsarian answered 7/1, 2010 at 18:0 Comment(2)
What kind of code is different between the platforms: the callbacks, the widgets used, the way the widgets are arranged (i.e. in different containers or different orders), or just certain platform-specific properties on the widgets?Stoneware
Sorry I forgot that. It's all of the above. At the core on all platforms it's PyGTK, then on Maemo 4 there's some hildon stuff (Maemo-specific widgets which have different names/signals/etc) and then on Maemo 5 there's even more fancy hildon stuff and other some other widgets which make the app more usable. Also, on the Maemo 5 version we want to have rotation support which does require re-arranging widgets on the fly.Infralapsarian
F
10

You could wind up much of this in a factory:

def createSpec():
  if util.platform.MAEMO: return Maemo4Spec()
  elif util.platform.MAEMO5: return Maemo5Spec()
  return StandardPyGTKSpec()

Then, somewhere early in your code, you just call that factory:

 spec = createSpec()

Now, everywhere else you had conditions, you just call the necessary function:

 spec.drawComboBox()

As long as drawComboBox(), handles anything specific to the platform, you should be in good shape.

Fresher answered 7/1, 2010 at 18:9 Comment(0)
S
0

You could isolate the platform specific stuff you need to do into small consistently named functions inside a platform module, create the right function name using the platform you're running on and then getattr the right one and call it. The if/else boilerplate would disappear then.

Sondrasone answered 7/1, 2010 at 18:7 Comment(0)
B
0

I've made a separate module to handle all of my specializing between normal Linux, Maemo 4.1, and Maemo 5. It detects what features are available and allows the program to gracefully degrade.

For example

 def _fremantle_hildonize_window(app, window):
         oldWindow = window
         newWindow = hildon.StackableWindow()
         oldWindow.get_child().reparent(newWindow)
         app.add_window(newWindow)
         return newWindow


 def _hildon_hildonize_window(app, window):
         oldWindow = window
         newWindow = hildon.Window()
         oldWindow.get_child().reparent(newWindow)
         app.add_window(newWindow)
         return newWindow


 def _null_hildonize_window(app, window):
         return window


 try:
         hildon.StackableWindow
         hildonize_window = _fremantle_hildonize_window
 except AttributeError:
         try:
                 hildon.Window
                 hildonize_window = _hildon_hildonize_window
         except AttributeError:
                 hildonize_window = _null_hildonize_window

For more, see Dialcentral, Gonert, ejpi, or Quicknote's source code for a file called hildonize.py https://garage.maemo.org/plugins/ggit/browse.php/?p=gc-dialer;a=blob;f=src/hildonize.py;

Another example from The One Ring's GObject Utils (go_utils.py)

 def _old_timeout_add_seconds(timeout, callback):
         return gobject.timeout_add(timeout * 1000, callback)


 def _timeout_add_seconds(timeout, callback):
         return gobject.timeout_add_seconds(timeout, callback)


 try:
         gobject.timeout_add_seconds
         timeout_add_seconds = _timeout_add_seconds
 except AttributeError:
         timeout_add_seconds = _old_timeout_add_seconds
Bevatron answered 11/2, 2010 at 17:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.