diff --git a/po/ru_games.po b/po/ru_games.po
index 5fd798ed..6832b0a2 100644
--- a/po/ru_games.po
+++ b/po/ru_games.po
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PySol 0.0.1\n"
 "POT-Creation-Date: Fri Aug 11 02:15:03 2006\n"
-"PO-Revision-Date: 2006-08-09 23:52+0400\n"
+"PO-Revision-Date: 2006-08-17 20:14+0400\n"
 "Last-Translator: Скоморох <skomoroh@gmail.com>\n"
 "Language-Team: Russian <ru@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -2729,7 +2729,7 @@ msgid "Pyramid 2"
 msgstr "Пирамида 2"
 
 msgid "Pyramid Golf"
-msgstr "Пирамидальный Голф"
+msgstr "Пирамидальный Гольф"
 
 msgid "Q.C."
 msgstr ""
diff --git a/pysollib/game.py b/pysollib/game.py
index fc8e7eac..e35e8839 100644
--- a/pysollib/game.py
+++ b/pysollib/game.py
@@ -46,8 +46,7 @@ from mfxutil import format_time
 from util import get_version_tuple, Timer
 from util import ACE, QUEEN, KING
 from version import VERSION, VERSION_TUPLE
-from settings import PACKAGE
-from settings import TOP_TITLE
+from settings import PACKAGE, TOOLKIT, TOP_TITLE
 from gamedb import GI
 from resource import CSI
 from pysolrandom import PysolRandom, LCRandom31
@@ -518,10 +517,15 @@ class Game:
         self.busy = old_busy
 
     def resetGame(self):
+        ##print '--- resetGame ---'
         self.hints.list = None
         self.s.talon.removeAllCards()
         for stack in self.allstacks:
+            ##print stack
             stack.resetGame()
+            if TOOLKIT == 'gtk':
+                # FIXME (pyramid like games)
+                stack.group.tkraise()
         if self.preview <= 1:
             for t in (self.texts.score, self.texts.base_rank,):
                 if t:
diff --git a/pysollib/pysolgtk/menubar.py b/pysollib/pysolgtk/menubar.py
index 905784b0..9a048d35 100644
--- a/pysollib/pysolgtk/menubar.py
+++ b/pysollib/pysolgtk/menubar.py
@@ -39,6 +39,7 @@ from gtk import gdk
 # PySol imports
 from pysollib.gamedb import GI
 from pysollib.actions import PysolMenubarActions
+from pysollib.settings import PACKAGE
 
 # toolkit imports
 from tkutil import setTransient
@@ -47,6 +48,14 @@ from selectcardset import SelectCardsetDialogWithPreview
 from selectcardset import SelectCardsetByTypeDialogWithPreview
 from selecttile import SelectTileDialogWithPreview
 
+from selectgame import SelectGameDialogWithPreview
+
+gettext = _
+
+
+def ltk2gtk(s):
+    return gettext(s).replace('&', '_')
+
 
 # /***********************************************************************
 # // - create menubar
@@ -78,71 +87,74 @@ class PysolMenubar(PysolMenubarActions):
     def createMenubar(self):
 
         entries = (
-  ('new',     gtk.STOCK_NEW,     '_New', 'N', 'New game', self.mNewGame),
-  ('open',    gtk.STOCK_OPEN,    '_Open', '<control>O', 'Open a\nsaved game', self.mOpen),
-  ('restart', gtk.STOCK_REFRESH, '_Restart', '<control>G', 'Restart the\ncurrent game', self.mRestart),
-  ('save',    gtk.STOCK_SAVE,    '_Save', '<control>S', 'Save game', self.mSave),
-  ('undo',    gtk.STOCK_UNDO,    'Undo', 'Z', 'Undo', self.mUndo),
-  ('redo',    gtk.STOCK_REDO,    'Redo', 'R', 'Redo', self.mRedo),
-  ('autodrop',gtk.STOCK_JUMP_TO, '_Auto drop', 'A', 'Auto drop', self.mDrop),
-  ('stats',   gtk.STOCK_HOME,    'Stats', None, 'Statistics', self.mStatus),
-  ('rules',   gtk.STOCK_HELP,    'Rules', 'F1', 'Rules', self.mHelpRules),
-  ('quit',    gtk.STOCK_QUIT,    'Quit', '<control>Q', 'Quit PySol', self.mQuit),
+  ('newgame', gtk.STOCK_NEW,     ltk2gtk('&New game'), 'N', ltk2gtk('New game'), self.mNewGame),
+  ('open',    gtk.STOCK_OPEN,    ltk2gtk('&Open...'), '<control>O', ltk2gtk('Open a\nsaved game'), self.mOpen),
+  ('restart', gtk.STOCK_REFRESH, ltk2gtk('&Restart'), '<control>G', ltk2gtk('Restart the\ncurrent game'), self.mRestart),
+  ('save',    gtk.STOCK_SAVE,    ltk2gtk('&Save'), '<control>S', ltk2gtk('Save game'), self.mSave),
+  ('undo',    gtk.STOCK_UNDO,    ltk2gtk('&Undo'), 'Z', ltk2gtk('Undo'), self.mUndo),
+  ('redo',    gtk.STOCK_REDO,    ltk2gtk('&Redo'), 'R', ltk2gtk('Redo'), self.mRedo),
+  ('autodrop',gtk.STOCK_JUMP_TO, ltk2gtk('&Auto drop'), 'A', ltk2gtk('Auto drop'), self.mDrop),
+  ('stats',   gtk.STOCK_HOME,    ltk2gtk('Stats'), None, ltk2gtk('Statistics'), self.mStatus),
+  ('rules',   gtk.STOCK_HELP,    ltk2gtk('Rules'), 'F1', ltk2gtk('Rules'), self.mHelpRules),
+  ('quit',    gtk.STOCK_QUIT,    ltk2gtk('&Quit'), '<control>Q', ltk2gtk('Quit PySol'), self.mQuit),
 
-  ('file',          None, '_File' ),
-  ('selectgame',    None, 'Select _game'),
-  ('edit',          None, '_Edit'),
-  ('game',          None, '_Game'),
-  ('assist',        None, '_Assist'),
-  ('options',       None, '_Options'),
-  ("automaticplay", None, "_Automatic play"),
+  ('file',          None, ltk2gtk('&File')),
+  ('selectgame',    None, ltk2gtk('Select &game')),
+  ('edit',          None, ltk2gtk('&Edit')),
+  ('game',          None, ltk2gtk('&Game')),
+  ('assist',        None, ltk2gtk('&Assist')),
+  ('options',       None, ltk2gtk('&Options')),
+  ("automaticplay", None, ltk2gtk("&Automatic play")),
 
-  ('animations', None, '_Animations'),
-  ('help',       None, '_Help'),
+  ('animations', None, ltk2gtk('A&nimations')),
+  ('help',       None, ltk2gtk('&Help')),
 
-  ('selectgamebynumber', None, 'Select game by number...', None, None, self.mSelectGameById),
-  ('saveas',    None, 'Save _as...', None, None, self.m),
-  ('redoall',   None, 'Redo _all',   None, None, self.mRedoAll),
-  ('dealcards', None, '_Deal cards', 'D',  None, self.mDeal),
-  ('status',    None, 'S_tatus...',  'T',  None, self.mStatus),
-  ('hint',      None, '_Hint',       'H',  None, self.mHint),
-  ('highlightpiles', None, 'Highlight _piles', None, None, self.mHighlightPiles),
-  ('demo',         None,'_Demo',     '<control>D',None,self.mDemo),
-  ('demoallgames', None,'Demo (all games)',  None,None,self.mMixedDemo),
-  ('playeroptions',None,'_Player options...',None,None,self.mOptPlayerOptions),
-  ('tabletile',    None,'Table t_ile...',    None,None,self.mOptTableTile),
-  ('contents',     None,'_Contents','<control>F1',None,self.mHelp),
-  ('aboutpysol',   None,'_About PySol...',   None,None,self.mHelpAbout),
+  ('playablepreview', None, ltk2gtk('Playable pre&view...'), 'V', None, self.mSelectGameDialogWithPreview),
+  ('selectgamebynumber', None, ltk2gtk('Select game by nu&mber...'), None, None, self.mSelectGameById),
+  ('saveas',    None, ltk2gtk('Save &as...'), None, None, self.m),
+  ('redoall',   None, ltk2gtk('Redo &all'),   None, None, self.mRedoAll),
+  ('dealcards', None, ltk2gtk('&Deal cards'), 'D',  None, self.mDeal),
+  ('status',    None, ltk2gtk('S&tatus...'),  'T',  None, self.mStatus),
+  ('hint',      None, ltk2gtk('&Hint'),       'H',  None, self.mHint),
+  ('highlightpiles', None, ltk2gtk('Highlight p&iles'), None, None, self.mHighlightPiles),
+  ('demo',         None,ltk2gtk('&Demo'),     '<control>D',None,self.mDemo),
+  ('demoallgames', None,ltk2gtk('Demo (&all games)'),  None,None,self.mMixedDemo),
+  ('playeroptions',None,ltk2gtk('&Player options...'),None,None,self.mOptPlayerOptions),
+  ('tabletile',    None,ltk2gtk('Table t&ile...'),    None,None,self.mOptTableTile),
+  ('contents',     None,ltk2gtk('&Contents'),'<control>F1',None,self.mHelp),
+  ('aboutpysol',   None,ltk2gtk('&About ')+PACKAGE+'...',   None,None,self.mHelpAbout),
 )
 
         #
         toggle_entries = (
-  ('pause', gtk.STOCK_STOP, '_Pause', 'P', 'Pause game', self.mPause),
-  ('optautodrop', None, 'A_uto drop',    None, None, self.mOptAutoDrop),
-  ('autofaceup',  None, 'Auto _face up', None, None, self.mOptAutoFaceUp),
-  ("autodeal",    None, "Auto _deal",    None, None, self.mOptAutoDeal),
-  ("quickplay",   None, '_Quick play',   None, None, self.mOptQuickPlay),
+  ('pause', gtk.STOCK_STOP, ltk2gtk('&Pause'), 'P', ltk2gtk('Pause game'), self.mPause),
+  ('optautodrop', None, ltk2gtk('A&uto drop'),    None, None, self.mOptAutoDrop),
+  ('autofaceup',  None, ltk2gtk('Auto &face up'), None, None, self.mOptAutoFaceUp),
+  ("autodeal",    None, ltk2gtk("Auto &deal"),    None, None, self.mOptAutoDeal),
+  ("quickplay",   None, ltk2gtk('&Quick play'),   None, None, self.mOptQuickPlay),
 
-  ('highlightmatchingcards', None, 'Highlight _matching cards', None, None, self.mOptEnableHighlightCards),
-  ('cardshadow',      None, 'Card shadow',       None, None, self.mOptShadow),
-  ('shadelegalmoves', None, 'Shade legal moves', None, None, self.mOptShade),
+  ('highlightmatchingcards', None, ltk2gtk('Highlight &matching cards'), None, None, self.mOptEnableHighlightCards),
+  ('cardshadow',      None, ltk2gtk('Card shado&w'),       None, None, self.mOptShadow),
+  ('shadelegalmoves', None, ltk2gtk('Shade &legal moves'), None, None, self.mOptShade),
 
 )
 
         #
         animations_entries = (
-            ('animationnone',     None, '_None',        None, None, 0),
-            ('animationfast',     None, '_Fast',        None, None, 1),
-            ('animationtimer',    None, '_Timer based', None, None, 2),
-            ('animationslow',     None, '_Slow',        None, None, 3),
-            ('animationveryslow', None, '_Very slow',   None, None, 4),
+ ('animationnone',     None, ltk2gtk('&None'),        None, None, 0),
+ ('animationfast',     None, ltk2gtk('&Fast'),        None, None, 1),
+ ('animationtimer',    None, ltk2gtk('&Timer based'), None, None, 2),
+ ('animationslow',     None, ltk2gtk('&Slow'),        None, None, 3),
+ ('animationveryslow', None, ltk2gtk('&Very slow'),   None, None, 4),
         )
         #
         ui_info = '''<ui>
   <menubar name='menubar'>
 
     <menu action='file'>
+      <menuitem action='newgame'/>
       <menuitem action='selectgamebynumber'/>
+      <menuitem action='playablepreview'/>
       <menu action='selectgame'/>
       <separator/>
       <menuitem action='open'/>
@@ -179,7 +191,7 @@ class PysolMenubar(PysolMenubarActions):
       <menuitem action='playeroptions'/>
       <menu action='automaticplay'>
         <menuitem action='autofaceup'/>
-        <menuitem action='autodrop'/>
+        <menuitem action='optautodrop'/>
         <menuitem action='autodeal'/>
         <separator/>
         <menuitem action='quickplay'/>
@@ -245,6 +257,7 @@ class PysolMenubar(PysolMenubarActions):
     def _addSelectGameSubMenu(self, games, menu, command, group):
         for g in games:
             label = g.name
+            label = gettext(label)
             menu_item = gtk.RadioMenuItem(group, label)
             group = menu_item
             menu.add(menu_item)
@@ -262,7 +275,9 @@ class PysolMenubar(PysolMenubarActions):
             if not games[n:n+d]:
                 break
             m = min(n+d-1, len(games)-1)
-            label = games[n].name[:3]+' - '+games[m].name[:3]
+            n1, n2 = games[n].name, games[m].name
+            n1, n2 = gettext(n1), gettext(n2)
+            label = n1[:3]+' - '+n2[:3]
             submenu = self._createSubMenu(menu, label=label)
             group = self._addSelectGameSubMenu(games[n:n+d], submenu,
                                                command, group)
@@ -276,7 +291,10 @@ class PysolMenubar(PysolMenubarActions):
 ## WARNING: setMenuState: not found: /menubar/file/holdandquit
 ## WARNING: setMenuState: not found: /menubar/assist/findcard
     def setMenuState(self, state, path):
-        path_map = {'help.rulesforthisgame': '/menubar/help/rules',}
+        path_map = {
+            'help.rulesforthisgame': '/menubar/help/rules',
+            'options.automaticplay.autodrop': '/menubar/options/automaticplay/optautodrop'
+            }
         if path_map.has_key(path):
             path = path_map[path]
         else:
@@ -302,11 +320,80 @@ class PysolMenubar(PysolMenubarActions):
     # menu actions
     #
 
+    def _createFileChooser(self, title, action, idir, ifile):
+        d = gtk.FileChooserDialog(title, self.top, action,
+                                  (gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT,
+                                   gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
+
+        d.set_current_folder(idir)
+        if ifile:
+            d.set_current_name(ifile)
+
+        filter = gtk.FileFilter()
+        filter.set_name('PySol files')
+        filter.add_pattern('*.pso')
+        d.add_filter(filter)
+
+        filter = gtk.FileFilter()
+        filter.set_name('All files')
+        filter.add_pattern('*')
+        d.add_filter(filter)
+
+        resp = d.run()
+        if resp == gtk.RESPONSE_ACCEPT:
+            filename = d.get_filename()
+        else:
+            filename = None
+        d.destroy()
+        return filename
+
+
     def mOpen(self, *args):
-        pass
+        if self._cancelDrag(break_pause=False): return
+        filename = self.game.filename
+        if filename:
+            idir, ifile = os.path.split(os.path.normpath(filename))
+        else:
+            idir, ifile = "", ""
+        if not idir:
+            idir = self.app.dn.savegames
+        filename = self._createFileChooser(_('Open Game'),
+                                           gtk.FILE_CHOOSER_ACTION_OPEN,
+                                           idir, '')
+        if filename:
+            ##filename = os.path.normpath(filename)
+            ##filename = os.path.normcase(filename)
+            if os.path.isfile(filename):
+                self.game.loadGame(filename)
+
 
     def mSaveAs(self, *event):
-        pass
+        if self._cancelDrag(break_pause=False): return
+        if not self.menustate.save_as:
+            return
+        filename = self.game.filename
+        if not filename:
+            filename = self.app.getGameSaveName(self.game.id)
+            if os.name == "posix":
+                filename = filename + "-" + self.game.getGameNumber(format=0)
+            elif os.path.supports_unicode_filenames: # new in python 2.3
+                filename = filename + "-" + self.game.getGameNumber(format=0)
+            else:
+                filename = filename + "-01"
+            filename = filename + '.pso'
+        idir, ifile = os.path.split(os.path.normpath(filename))
+        if not idir:
+            idir = self.app.dn.savegames
+        ##print self.game.filename, ifile
+        filename = self._createFileChooser(_('Save Game'),
+                                           gtk.FILE_CHOOSER_ACTION_SAVE,
+                                           idir, ifile)
+        if filename:
+            ##filename = os.path.normpath(filename)
+            ##filename = os.path.normcase(filename)
+            self.game.saveGame(filename)
+            self.updateMenus()
+
 
     def mOptCardset(self, *args):
         pass
@@ -353,3 +440,32 @@ class PysolMenubar(PysolMenubarActions):
         tile.color = color
         self.app.setTile(0)
 
+
+    def mSelectGameDialogWithPreview(self, *event):
+        if self._cancelDrag(break_pause=False): return
+##         self.game.setCursor(cursor=CURSOR_WATCH)
+        bookmark = None
+##         if 0:
+##             # use a bookmark for our preview game
+##             if self.game.setBookmark(-2, confirm=0):
+##                 bookmark = self.game.gsaveinfo.bookmarks[-2][0]
+##                 del self.game.gsaveinfo.bookmarks[-2]
+        ##~ after_idle(self.top, self.__restoreCursor)
+        d = SelectGameDialogWithPreview(self.top, title=_("Select game"),
+                                        app=self.app, gameid=self.game.id,
+                                        bookmark=bookmark)
+        return self._mSelectGameDialog(d)
+
+    def _mSelectGameDialog(self, d):
+        if d.status == 0 and d.button == 0 and d.gameid != self.game.id:
+            ##~ self.tkopt.gameid.set(d.gameid)
+            ##~ self.tkopt.gameid_popular.set(d.gameid)
+            if 0:
+                self._mSelectGame(d.gameid, random=d.random)
+            else:
+                # don't ask areYouSure()
+                self._cancelDrag()
+                self.game.endGame()
+                self.game.quitGame(d.gameid, random=d.random)
+
+
diff --git a/pysollib/pysolgtk/playeroptionsdialog.py b/pysollib/pysolgtk/playeroptionsdialog.py
index 352ad045..7f556c9e 100644
--- a/pysollib/pysolgtk/playeroptionsdialog.py
+++ b/pysollib/pysolgtk/playeroptionsdialog.py
@@ -93,7 +93,6 @@ class PlayerOptionsDialog(MfxDialog):
                   strings=(_('&OK'), _('&Cancel'),),
                   default=0,
                   #resizable=1,
-                  #font=None,
                   padx=10, pady=10,
                   #width=600, height=400,
                   ##~ buttonpadx=10, buttonpady=5,
diff --git a/pysollib/pysolgtk/progressbar.py b/pysollib/pysolgtk/progressbar.py
index 93c41362..6238455b 100644
--- a/pysollib/pysolgtk/progressbar.py
+++ b/pysollib/pysolgtk/progressbar.py
@@ -35,7 +35,6 @@ import os, sys
 
 import gtk
 from gtk import gdk
-TRUE, FALSE = True, False
 
 # Toolkit imports
 from tkutil import makeToplevel, setTransient
@@ -55,8 +54,7 @@ class PysolProgressBar:
         self.norm = norm
         self.top = makeToplevel(parent, title=title)
         self.top.set_position(gtk.WIN_POS_CENTER)
-        ##self.top.set_policy(FALSE, FALSE, FALSE)
-        self.top.set_resizable(FALSE)
+        self.top.set_resizable(False)
         self.top.connect("delete_event", self.wmDeleteWindow)
 
         # hbox
@@ -67,21 +65,22 @@ class PysolProgressBar:
                               0, 1, 0, 1,
                               0,    0,
                               0,    0)
-
         # hbox-1: image
         if images and images[0]:
             im = gtk.Image()
             im.set_from_pixbuf(images[0].pixbuf)
             hbox.pack_start(im, expand=False, fill=False)
             im.show()
+            im.set_property('xpad', 10)
+            im.set_property('ypad', 5)
         # hbox-2:vbox
         vbox = gtk.VBox()
         vbox.show()
-        hbox.pack_start(vbox, FALSE, FALSE)
+        hbox.pack_start(vbox, False, False)
         # hbox-2:vbox:pbar
         self.pbar = gtk.ProgressBar()
         self.pbar.show()
-        vbox.pack_start(self.pbar, TRUE, FALSE)
+        vbox.pack_start(self.pbar, True, False)
         self.pbar.realize()
         ##~ self.pbar.set_show_text(show_text)
         self.pbar.set_text(str(show_text)+'%')
@@ -99,6 +98,8 @@ class PysolProgressBar:
             im.set_from_pixbuf(images[1].pixbuf)
             hbox.pack_end(im, expand=False)
             im.show()
+            im.set_property('xpad', 10)
+            im.set_property('ypad', 5)
         # set icon
         if app:
             try:
@@ -130,15 +131,17 @@ class PysolProgressBar:
         percent = min(100, max(0, percent))
         self.pbar.set_fraction(percent / 100.0)
         self.pbar.set_text(str(percent)+'%')
-        ##~ self.pbar.update(self.percent / 100.0)
         self.update_idletasks()
 
+    def reset(self, percent=0):
+        self.percent = percent
+
     def update_idletasks(self):
         while gtk.events_pending():
             gtk.main_iteration()
 
     def wmDeleteWindow(self, *args):
-        return TRUE
+        return True
 
 
 # /***********************************************************************
@@ -160,9 +163,9 @@ class TestProgressBar:
         if self.progress.percent >= 100:
             self.progress.destroy()
             mainquit()
-            return FALSE
+            return False
         self.progress.update(step=1)
-        return TRUE
+        return True
 
 def progressbar_main(args):
     root = gtk.Window()
diff --git a/pysollib/pysolgtk/selectgame.py b/pysollib/pysolgtk/selectgame.py
new file mode 100644
index 00000000..0c54618f
--- /dev/null
+++ b/pysollib/pysolgtk/selectgame.py
@@ -0,0 +1,605 @@
+## vim:ts=4:et:nowrap
+##
+##---------------------------------------------------------------------------##
+##
+## PySol -- a Python Solitaire game
+##
+## Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+## Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+## Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+## Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+## Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+## Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+## All Rights Reserved.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; see the file COPYING.
+## If not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+##
+## Markus F.X.J. Oberhumer
+## <markus@oberhumer.com>
+## http://www.oberhumer.com/pysol
+##
+##---------------------------------------------------------------------------##
+
+
+# imports
+import os, re, sys, types
+import gtk, gobject
+
+#from UserList import UserList
+
+# PySol imports
+from pysollib.mfxutil import destruct, Struct, KwStruct
+from pysollib.mfxutil import kwdefault
+from pysollib.mfxutil import format_time
+from pysollib.gamedb import GI
+from pysollib.help import helpHTML
+from pysollib.resource import CSI
+
+# Toolkit imports
+from tkutil import unbind_destroy
+from tkwidget import MfxDialog
+from tkcanvas  import MfxCanvas, MfxCanvasText
+
+gettext = _
+
+
+# /***********************************************************************
+# // Dialog
+# ************************************************************************/
+
+class SelectGameDialogWithPreview(MfxDialog):
+    #Tree_Class = SelectGameTreeWithPreview
+    game_store = None
+    #
+    _paned_position = 300
+    _expanded_rows = []
+    _geometry = None
+    _selected_row = None
+    _vadjustment_position = None
+
+    def __init__(self, parent, title, app, gameid, bookmark=None, **kw):
+        kw = self.initKw(kw)
+        MfxDialog.__init__(self, parent, title, **kw)
+        #
+        self.app = app
+        self.gameid = gameid
+        self.bookmark = bookmark
+        self.random = None
+        #
+        if self.game_store is None:
+            self.createGameStore()
+        #
+        top_box, bottom_box = self.createHBox()
+        # paned
+        hpaned = gtk.HPaned()
+        self.hpaned = hpaned
+        hpaned.show()
+        top_box.pack_start(hpaned, expand=True, fill=True)
+        # left
+        sw = gtk.ScrolledWindow()
+        sw.show()
+        self.sw_vadjustment = sw.get_vadjustment()
+        hpaned.pack1(sw, True, True)
+        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        # tree
+        treeview = gtk.TreeView(self.game_store)
+        self.treeview = treeview
+        treeview.show()
+        sw.add(treeview)
+        treeview.set_rules_hint(True)
+        treeview.set_headers_visible(False)
+        renderer = gtk.CellRendererText()
+        renderer.set_property('xalign', 0.0)
+        column = gtk.TreeViewColumn('Games', renderer, text=0)
+        column.set_clickable(True)
+        treeview.append_column(column)
+        selection = treeview.get_selection()
+        selection.connect('changed', self.showSelected)
+        # right
+        table = gtk.Table(2, 2, False)
+        table.show()
+        hpaned.pack2(table, True, True)
+        # frames
+        frame = gtk.Frame(label=_('About game'))
+        frame.show()
+        table.attach(frame,
+                     0, 1,      0, 1,
+                     gtk.FILL,  gtk.FILL,
+                     0,         0)
+        frame.set_border_width(4)
+        info_frame = gtk.Table(2, 7, False)
+        info_frame.show()
+        frame.add(info_frame)
+        info_frame.set_border_width(4)
+        #
+        frame = gtk.Frame(label=_('Statistics'))
+        frame.show()
+        table.attach(frame,
+                     1, 2,      0, 1,
+                     gtk.FILL,  gtk.FILL,
+                     0,         0)
+        frame.set_border_width(4)
+        stats_frame = gtk.Table(2, 6, False)
+        stats_frame.show()
+        frame.add(stats_frame)
+        stats_frame.set_border_width(4)
+        # info
+        self.info_labels = {}
+        i = 0
+        for n, t, f, row in (
+            ('name',        _('Name:'),             info_frame,   0),
+            ('altnames',    _('Alternate names:'),  info_frame,   1),
+            ('category',    _('Category:'),         info_frame,   2),
+            ('type',        _('Type:'),             info_frame,   3),
+            ('skill_level', _('Skill level:'),      info_frame,   4),
+            ('decks',       _('Decks:'),            info_frame,   5),
+            ('redeals',     _('Redeals:'),          info_frame,   6),
+            #
+            ('played',      _('Played:'),           stats_frame,  0),
+            ('won',         _('Won:'),              stats_frame,  1),
+            ('lost',        _('Lost:'),             stats_frame,  2),
+            ('time',        _('Playing time:'),     stats_frame,  3),
+            ('moves',       _('Moves:'),            stats_frame,  4),
+            ('percent',     _('% won:'),            stats_frame,  5),
+            ):
+            title_label = gtk.Label()
+            title_label.show()
+            title_label.set_text(t)
+            title_label.set_alignment(0., 0.)
+            title_label.set_property('xpad', 2)
+            title_label.set_property('ypad', 2)
+            f.attach(title_label,
+                     0, 1,      row, row+1,
+                     gtk.FILL,  0,
+                     0,         0)
+            text_label = gtk.Label()
+            text_label.show()
+            text_label.set_alignment(0., 0.)
+            text_label.set_property('xpad', 2)
+            text_label.set_property('ypad', 2)
+            f.attach(text_label,
+                     1, 2,      row, row+1,
+                     gtk.FILL,  0,
+                     0,         0)
+            self.info_labels[n] = (title_label, text_label)
+        # canvas
+        self.preview = MfxCanvas(self)
+        self.preview.show()
+        table.attach(self.preview,
+            0, 2,                            1, 2,
+            gtk.EXPAND|gtk.FILL|gtk.SHRINK,  gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+            0,                               0)
+        self.preview.set_border_width(4)
+        self.preview.setTile(app, app.tabletile_index, force=True)
+
+        # set the scale factor
+        self.preview.preview = 2
+        # create a preview of the current game
+        self.preview_key = -1
+        self.preview_game = None
+        self.preview_app = None
+        ##~ self.updatePreview(gameid, animations=0)
+        ##~ SelectGameTreeWithPreview.html_viewer = None
+
+        self.connect('unrealize', self._unrealizeEvent)
+
+        self.createButtons(bottom_box, kw)
+        self._restoreSettings()
+        self.show_all()
+        gtk.main()
+
+
+    def _addGamesFromData(self, data, store, root_iter, root_label, all_games):
+        gl = []
+        for label, selecter in data:
+            games = self._selectGames(all_games, selecter)
+            if games:
+                gl.append((label, games))
+        if not gl:
+            return
+        iter = store.append(root_iter)
+        store.set(iter, 0, root_label, 1, -1)
+        for label, games in gl:
+            label = gettext(label)
+            label = label.replace("&", "")
+            self._addGames(store, iter, label, games)
+
+
+    def _addGames(self, store, root_iter, root_label, games):
+        if not games:
+            return
+        iter = store.append(root_iter)
+        store.set(iter, 0, root_label, 1, -1)
+        for id, name in games:
+            child_iter = store.append(iter)
+            name = gettext(name)
+            store.set(child_iter, 0, name, 1, id)
+
+    #def _addNode(self, store, root_iter, root_label, games):
+
+
+    def _selectGames(self, all_games, selecter):
+        # return list of tuples (gameid, gamename)
+        if selecter is None:
+            return [(gi.id, gi.name) for gi in all_games]
+        elif selecter == 'alt':
+            return all_games
+        return [(gi.id, gi.name) for gi in all_games if selecter(gi)]
+
+
+    def createGameStore(self):
+        store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_INT)
+        app = self.app
+        gdb = app.gdb
+
+        all_games = map(gdb.get, gdb.getGamesIdSortedByName())
+        #
+        alter_games = gdb.getGamesTuplesSortedByAlternateName()
+        for label, games, selecter in (
+            (_('All Games'),       all_games,   None),
+            (_('Alternate Names'), alter_games, 'alt'),
+            (_('Popular Games'),   all_games, lambda gi: gi.si.game_flags & GI.GT_POPULAR),
+            ):
+            games = self._selectGames(games, selecter)
+            self._addGames(store, None, label, games)
+
+        # by type
+        games = self._selectGames(all_games,
+                                  lambda gi: gi.si.game_type == GI.GT_MAHJONGG)
+        self._addGames(store, None, _("Mahjongg Games"), games)
+        self._addGamesFromData(GI.SELECT_ORIENTAL_GAME_BY_TYPE, store,
+                               None, _("Oriental Games"), all_games)
+        self._addGamesFromData(GI.SELECT_SPECIAL_GAME_BY_TYPE, store,
+                               None, _("Special Games"), all_games)
+        self._addGamesFromData(GI.SELECT_GAME_BY_TYPE, store,
+                               None, _("French games"), all_games)
+        # by skill level
+        data = (
+          (_('Luck only'),    lambda gi: gi.skill_level == GI.SL_LUCK),
+          (_('Mostly luck'),  lambda gi: gi.skill_level == GI.SL_MOSTLY_LUCK),
+          (_('Balanced'),     lambda gi: gi.skill_level == GI.SL_BALANCED),
+          (_('Mostly skill'), lambda gi: gi.skill_level == GI.SL_MOSTLY_SKILL),
+          (_('Skill only'),   lambda gi: gi.skill_level == GI.SL_SKILL),
+          )
+        self._addGamesFromData(data, store, None,
+                               _("by Skill Level"), all_games)
+
+        # by game feature
+        root_iter = store.append(None)
+        store.set(root_iter, 0, _('by Game Feature'), 1, -1)
+        data = (
+            (_("32 cards"),     lambda gi: gi.si.ncards == 32),
+            (_("48 cards"),     lambda gi: gi.si.ncards == 48),
+            (_("52 cards"),     lambda gi: gi.si.ncards == 52),
+            (_("64 cards"),     lambda gi: gi.si.ncards == 64),
+            (_("78 cards"),     lambda gi: gi.si.ncards == 78),
+            (_("104 cards"),    lambda gi: gi.si.ncards == 104),
+            (_("144 cards"),    lambda gi: gi.si.ncards == 144),
+            (_("Other number"), lambda gi: gi.si.ncards not in (32, 48, 52, 64, 78, 104, 144)),)
+        self._addGamesFromData(data, store, root_iter,
+                             _("by Number of Cards"), all_games)
+        data = (
+            (_("1 deck games"), lambda gi: gi.si.decks == 1),
+            (_("2 deck games"), lambda gi: gi.si.decks == 2),
+            (_("3 deck games"), lambda gi: gi.si.decks == 3),
+            (_("4 deck games"), lambda gi: gi.si.decks == 4),)
+        self._addGamesFromData(data, store, root_iter,
+                             _("by Number of Decks"), all_games)
+        data = (
+            (_("No redeal"), lambda gi: gi.si.redeals == 0),
+            (_("1 redeal"),  lambda gi: gi.si.redeals == 1),
+            (_("2 redeals"), lambda gi: gi.si.redeals == 2),
+            (_("3 redeals"), lambda gi: gi.si.redeals == 3),
+            (_("Unlimited redeals"), lambda gi: gi.si.redeals == -1),
+            ##(_("Variable redeals"), lambda gi: gi.si.redeals == -2),
+            (_("Other number of redeals"), lambda gi: gi.si.redeals not in (-1, 0, 1, 2, 3)),)
+        self._addGamesFromData(data, store, root_iter,
+                               _("by Number of Redeals"), all_games)
+
+        data = []
+        for label, vg in GI.GAMES_BY_COMPATIBILITY:
+            selecter = lambda gi, vg=vg: gi.id in vg
+            label = gettext(label)
+            data.append((label, selecter))
+        self._addGamesFromData(data, store, root_iter,
+                               _("by Compatibility"), all_games)
+
+        # by PySol version
+        data = []
+        for version, vg in GI.GAMES_BY_PYSOL_VERSION:
+            selecter = lambda gi, vg=vg: gi.id in vg
+            label = _("New games in v. ") + version
+            data.append((label, selecter))
+        self._addGamesFromData(data, store, None,
+                               _("by PySol version"), all_games)
+
+        #
+        data = (
+            (_("Games for Children (very easy)"), lambda gi: gi.si.game_flags & GI.GT_CHILDREN),
+            (_("Games with Scoring"),  lambda gi: gi.si.game_flags & GI.GT_SCORE),
+            (_("Games with Separate Decks"),  lambda gi: gi.si.game_flags & GI.GT_SEPARATE_DECKS),
+            (_("Open Games (all cards visible)"), lambda gi: gi.si.game_flags & GI.GT_OPEN),
+            (_("Relaxed Variants"),  lambda gi: gi.si.game_flags & GI.GT_RELAXED),)
+        self._addGamesFromData(data, store, None,
+                               _("Other Categories"), all_games)
+
+        #
+        self._addGamesFromData(GI.SELECT_ORIGINAL_GAME_BY_TYPE, store,
+                               None, _("Original Games"), all_games)
+        ##self._addGamesFromData(GI.SELECT_CONTRIB_GAME_BY_TYPE, store,
+        ##              None, _("Contrib Game"), all_games)
+
+        SelectGameDialogWithPreview.game_store = store
+        return
+
+
+    def initKw(self, kw):
+        kwdefault(kw,
+                  strings=(_("&Select"), _("&Rules"), _("&Cancel"),),
+                  default=0,
+                  ##padx=10, pady=10,
+                  width=600, height=400,
+                  ##~ buttonpadx=10, buttonpady=5,
+                  )
+        return MfxDialog.initKw(self, kw)
+
+
+    def _unrealizeEvent(self, w):
+        self.deletePreview(destroy=1)
+        #self.preview.unbind_all()
+        self._saveSettings()
+
+
+    def _saveSettings(self):
+        SelectGameDialogWithPreview._geometry = self.get_size()
+        self._saveExpandedRows()
+        SelectGameDialogWithPreview._paned_position = self.hpaned.get_position()
+        selection = self.treeview.get_selection()
+        model, path = selection.get_selected_rows()
+        if path:
+            print 'save selected:', path
+            SelectGameDialogWithPreview._selected_row = path[0]
+        SelectGameDialogWithPreview._vadjustment_position = self.sw_vadjustment.get_value()
+
+
+    def _restoreSettings(self):
+        if self._geometry:
+            self.resize(self._geometry[0], self._geometry[1])
+        self._loadExpandedRows()
+        self.hpaned.set_position(self._paned_position)
+        if self._selected_row:
+            selection = self.treeview.get_selection()
+            ##selection.select_path(self._selected_row)
+            ##selection.unselect_all()
+            gtk.idle_add(selection.select_path, self._selected_row)
+        if self._vadjustment_position is not None:
+            ##self.sw_vadjustment.set_value(self._vadjustment_position)
+            gtk.idle_add(self.sw_vadjustment.set_value,
+                         self._vadjustment_position)
+
+
+    def _getSelected(self):
+        selection = self.treeview.get_selection()
+        model, path = selection.get_selected_rows()
+        if not path:
+            return None
+        iter = model.get_iter(path[0])
+        index = model.get_value(iter, 1)
+        if index < 0:
+            return None
+        return index
+
+
+    def showSelected(self, w):
+        id = self._getSelected()
+        if id:
+            self.updatePreview(id)
+            ##self.updateInfo(id)
+
+
+    def deletePreview(self, destroy=0):
+        self.preview_key = -1
+        # clean up the canvas
+        if self.preview:
+            unbind_destroy(self.preview)
+            self.preview.deleteAllItems()
+            ##~ if destroy:
+            ##~     self.preview.delete("all")
+        #
+        #for l in self.info_labels.values():
+        #    l.config(text='')
+        # destruct the game
+        if self.preview_game:
+            self.preview_game.endGame()
+            self.preview_game.destruct()
+            destruct(self.preview_game)
+        self.preview_game = None
+        # destruct the app
+        if destroy:
+            if self.preview_app:
+                destruct(self.preview_app)
+            self.preview_app = None
+
+    def updatePreview(self, gameid, animations=5):
+        if gameid == self.preview_key:
+            return
+        self.deletePreview()
+        canvas = self.preview
+        #
+        gi = self.app.gdb.get(gameid)
+        if not gi:
+            self.preview_key = -1
+            return
+        #
+        if self.preview_app is None:
+            self.preview_app = Struct(
+                # variables
+                audio = self.app.audio,
+                canvas = canvas,
+                cardset = self.app.cardset.copy(),
+                comments = self.app.comments.new(),
+                debug = 0,
+                gamerandom = self.app.gamerandom,
+                gdb = self.app.gdb,
+                gimages = self.app.gimages,
+                images = self.app.subsampled_images,
+                menubar = None,
+                miscrandom = self.app.miscrandom,
+                opt = self.app.opt.copy(),
+                startup_opt = self.app.startup_opt,
+                stats = self.app.stats.new(),
+                top = None,
+                top_cursor = self.app.top_cursor,
+                toolbar = None,
+                # methods
+                constructGame = self.app.constructGame,
+                getFont = self.app.getFont,
+            )
+            self.preview_app.opt.shadow = 0
+            self.preview_app.opt.shade = 0
+        #
+        self.preview_app.audio = None    # turn off audio for intial dealing
+        if animations >= 0:
+            self.preview_app.opt.animations = animations
+        #
+        if self.preview_game:
+            self.preview_game.endGame()
+            self.preview_game.destruct()
+        ##self.top.wm_title("Select Game - " + self.app.getGameTitleName(gameid))
+        title = self.app.getGameTitleName(gameid)
+        self.set_title(_("Playable Preview - ") + title)
+        #
+        self.preview_game = gi.gameclass(gi)
+        self.preview_game.createPreview(self.preview_app)
+        tx, ty = 0, 0
+        gw, gh = self.preview_game.width, self.preview_game.height
+        ##~ canvas.config(scrollregion=(-tx, -ty, -tx, -ty))
+        ##~ canvas.xview_moveto(0)
+        ##~ canvas.yview_moveto(0)
+        #
+        random = None
+        if gameid == self.gameid:
+            random = self.app.game.random.copy()
+        if gameid == self.gameid and self.bookmark:
+            self.preview_game.restoreGameFromBookmark(self.bookmark)
+        else:
+            self.preview_game.newGame(random=random, autoplay=1)
+        ##~ canvas.config(scrollregion=(-tx, -ty, gw, gh))
+        #
+        self.preview_app.audio = self.app.audio
+        if self.app.opt.animations:
+            self.preview_app.opt.animations = 5
+        else:
+            self.preview_app.opt.animations = 0
+        # save seed
+        self.random = self.preview_game.random.copy()
+        self.random.origin = self.random.ORIGIN_PREVIEW
+        self.preview_key = gameid
+        #
+        self.updateInfo(gameid)
+        #
+        rules_button = self.buttons[1]
+        if self.app.getGameRulesFilename(gameid):
+            rules_button.set_sensitive(True)
+        else:
+            rules_button.set_sensitive(False)
+
+    def updateInfo(self, gameid):
+        gi = self.app.gdb.get(gameid)
+        # info
+        name = gettext(gi.name)
+        altnames = '\n'.join([gettext(n) for n in gi.altnames])
+        category = gettext(CSI.TYPE[gi.category])
+        type = ''
+        if GI.TYPE_NAMES.has_key(gi.si.game_type):
+            type = gettext(GI.TYPE_NAMES[gi.si.game_type])
+        sl = {
+            GI.SL_LUCK:         _('Luck only'),
+            GI.SL_MOSTLY_LUCK:  _('Mostly luck'),
+            GI.SL_BALANCED:     _('Balanced'),
+            GI.SL_MOSTLY_SKILL: _('Mostly skill'),
+            GI.SL_SKILL:        _('Skill only'),
+            }
+        skill_level = sl.get(gi.skill_level)
+        if    gi.redeals == -2: redeals = _('variable')
+        elif  gi.redeals == -1: redeals = _('unlimited')
+        else:                   redeals = str(gi.redeals)
+        # stats
+        won, lost, time, moves = self.app.stats.getFullStats(self.app.opt.player, gameid)
+        if won+lost > 0: percent = "%.1f" % (100.0*won/(won+lost))
+        else: percent = "0.0"
+        time = format_time(time)
+        moves = str(round(moves, 1))
+        for n, t in (
+            ('name',        name),
+            ('altnames',    altnames),
+            ('category',    category),
+            ('type',        type),
+            ('skill_level', skill_level),
+            ('decks',       gi.decks),
+            ('redeals',     redeals),
+            ('played',      won+lost),
+            ('won',         won),
+            ('lost',        lost),
+            ('time',        time),
+            ('moves',       moves),
+            ('percent',     percent),
+            ):
+            title_label, text_label = self.info_labels[n]
+            if t == '':
+                title_label.hide()
+                text_label.hide()
+            else:
+                title_label.show()
+                text_label.show()
+            text_label.set_text(str(t))
+            #self.info_labels[n].config(text=t)
+
+    def _saveExpandedRows(self):
+        treeview = self.treeview
+        SelectGameDialogWithPreview._expanded_rows = []
+        treeview.map_expanded_rows(
+            lambda tv, path, self=self:
+                SelectGameDialogWithPreview._expanded_rows.append(path))
+        print self._expanded_rows
+
+    def _loadExpandedRows(self):
+        for path in self._expanded_rows:
+            self.treeview.expand_to_path(path)
+
+    def done(self, button):
+        button = button.get_data("user_data")
+        print 'done', button
+        if button == 0:                    # Ok or double click
+            id = self._getSelected()
+            if id:
+                self.gameid = id
+            ##~ self.tree.n_expansions = 1  # save xyview in any case
+        if button == 1:                    # Rules
+            id = self._getSelected()
+            if id:
+                doc = self.app.getGameRulesFilename(id)
+                if not doc:
+                    return
+            dir = os.path.join("html", "rules")
+            helpHTML(self.app, doc, dir, self)
+            return
+
+        self.status = 0
+        self.button = button
+        self.quit()
+
+
diff --git a/pysollib/pysolgtk/selecttile.py b/pysollib/pysolgtk/selecttile.py
index 0bf43a24..4cb3b9bd 100644
--- a/pysollib/pysolgtk/selecttile.py
+++ b/pysollib/pysolgtk/selecttile.py
@@ -184,7 +184,6 @@ class SelectTileDialogWithPreview(MfxDialog):
                   strings=(_('&OK'), _('&Solid color...'), _('&Cancel'),),
                   default=0,
                   resizable=1,
-                  font=None,
                   padx=10, pady=10,
                   width=600, height=400,
                   ##~ buttonpadx=10, buttonpady=5,
diff --git a/pysollib/pysolgtk/statusbar.py b/pysollib/pysolgtk/statusbar.py
index 4182fbbe..310a5b72 100644
--- a/pysollib/pysolgtk/statusbar.py
+++ b/pysollib/pysolgtk/statusbar.py
@@ -50,21 +50,25 @@ class BasicStatusbar:
                          column, column+columnspan,   row, row+1,
                          gtk.EXPAND | gtk.FILL,       0,
                          0,                           0)
-        self.createLabel('space', width=2)
 
 
-    def createLabel(self, name, fill=False, expand=False, grip=False, width=0):
+    def createLabel(self, name, fill=False, expand=False,
+                    tooltip=None, grip=False, width=0):
         label = gtk.Statusbar()
         self.hbox.pack_start(label, fill=fill, expand=expand)
         label.show()
         if not grip:
             label.set_has_resize_grip(False)
         setattr(self, name + "_label", label)
-        label.set_size_request(width*8, -1)
-        ##lb = label.get_children()[0].get_children()[0]
-        ##lb.set_justify(gtk.JUSTIFY_CENTER)
+        label.set_size_request(width*7, -1)
+        lb = label.get_children()[0].get_children()[0]
+        lb.set_alignment(0.5, 0.0)
         self._widgets.append(label)
         ##label.push(0, '')
+##         if tooltip:
+##             tt = gtk.Tooltips()
+##             tt.set_tip(label, tooltip, '')
+##             tt.enable()
 
 
     def updateText(self, **kw):
@@ -75,8 +79,11 @@ class BasicStatusbar:
 
 
     def configLabel(self, name, **kw):
-        print 'statusbar.configLabel', kw
-        pass
+        label = getattr(self, name + "_label")
+        # FIXME kw['fg']
+        label.pop(0)
+        label.push(0, unicode(kw['text']))
+
 
     def show(self, show=True, resize=False):
         if show:
@@ -107,7 +114,7 @@ class PysolStatusbar(BasicStatusbar):
             ("gamenumber",  _("Game number"),             26),
             ("stats",       _("Games played: won/lost"),  12),
             ):
-            self.createLabel(n, width=w)
+            self.createLabel(n, width=w, tooltip=t)
         #
         l = self.createLabel("info", fill=True, expand=True, grip=True)
 
diff --git a/pysollib/pysolgtk/tkcanvas.py b/pysollib/pysolgtk/tkcanvas.py
index a66a95fa..2875d3b4 100644
--- a/pysollib/pysolgtk/tkcanvas.py
+++ b/pysollib/pysolgtk/tkcanvas.py
@@ -60,6 +60,7 @@ TRUE, FALSE = True, False
 # toolkit imports
 from tkutil import anchor_tk2gtk, loadImage, bind
 
+
 # /***********************************************************************
 # // canvas items
 # //
@@ -75,17 +76,19 @@ class _CanvasItem:
     def __init__(self, canvas):
         self.canvas = canvas
         canvas._all_items.append(self)
+        self._group = None
 
     def addtag(self, group):
         ##print self, 'addtag'
         ##~ assert isinstance(group._item, CanvasGroup)
         self._item.reparent(group._item)
+        self._group = group
 
     def dtag(self, group):
-        pass
         ##print self, 'dtag'
         ##~ assert isinstance(group._item, CanvasGroup)
         ##self._item.reparent(self.canvas.root())
+        self._group = None
 
     def bind(self, sequence, func, add=None):
         bind(self._item, sequence, func, add)
@@ -100,23 +103,33 @@ class _CanvasItem:
             self._item = None
 
     def lower(self, positions=None):
-        ##print "lower", self._item, positions
+        print "lower", self._item, positions
         if positions is None:
-            self._item.lower_to_bottom()
+            if self._group:
+                self._group._item.lower_to_bottom()
+                ##self._item.lower_to_bottom()
+            else:
+                self._item.lower_to_bottom()
         else:
+            print self, 'lower', positions
             ##~ assert type(positions) is types.IntType and positions > 0
-            ##~ self._item.lower(positions)
-            pass
+            self._item.lower(positions)
+
     def tkraise(self, positions=None):
-        ##print "tkraise", self._item, positions
+        ##print "tkraise", self._group, self._item.get_property('parent') #self._item, positions
         if positions is None:
             self._item.raise_to_top()
+            self._item.get_property('parent').raise_to_top()
+##             if self._group:
+##                 self._group._item.raise_to_top()
+##                 ##self._item.raise_to_top()
+##             else:
+##                 self._item.raise_to_top()
         else:
-            print 'tkraise', positions
+            print self, 'tkraise', positions
             ##~ assert type(positions) is types.IntType and positions > 0
             ##~ self._item.raise_(positions)
             self._item.raise_to_top()
-            pass
 
     def move(self, x, y):
         self._item.move(x, y)
@@ -141,7 +154,6 @@ class MfxCanvasGroup(_CanvasItem):
         self._item = canvas.root().add(gnome.canvas.CanvasGroup, x=0, y=0)
 
 
-
 class MfxCanvasImage(_CanvasItem):
     def __init__(self, canvas, x, y, image, anchor=gtk.ANCHOR_NW):
         _CanvasItem.__init__(self, canvas)
@@ -188,10 +200,10 @@ class MfxCanvasLine(_CanvasItem):
 class MfxCanvasRectangle(_CanvasItem):
     def __init__(self, canvas, x1, y1, x2, y2, width, fill, outline):
         _CanvasItem.__init__(self, canvas)
-        self._item = canvas.root().add('rect', x1=x1, y1=y1, x2=x2, y2=y2,
-                                       width_pixels=width, outline_color=outline)
-        if fill is not None:
-            self._item.set(fill_color=fill)
+        kw = {'x1': x1, 'x2': x2, 'y1': y1, 'y2': y2, 'width_pixels': width}
+        if fill: kw['fill_color'] = fill
+        if outline: kw['outline_color'] = outline
+        self._item = canvas.root().add(gnome.canvas.CanvasRect, **kw)
 
 
 class MfxCanvasText(_CanvasItem):
@@ -200,6 +212,7 @@ class MfxCanvasText(_CanvasItem):
         if preview < 0:
             preview = canvas.preview
         if preview > 1:
+            self._item = None
             return
         anchor = anchor_tk2gtk(anchor)
         self._item = canvas.root().add(gnome.canvas.CanvasText,
@@ -240,7 +253,6 @@ class MfxCanvasText(_CanvasItem):
 
 class MfxCanvas(gnome.canvas.Canvas):
     def __init__(self, top, bg=None, highlightthickness=0):
-        print 'MfxCanvas', bg
         self.preview = 0
         # Tkinter compat
         self.items = {}
@@ -263,12 +275,12 @@ class MfxCanvas(gnome.canvas.Canvas):
         self.set_style(style)
         self.top_bg = top.style.bg[gtk.STATE_NORMAL]
 
-
         ##
         self.top = top
         self.xmargin, self.ymargin = 0, 0
 
         self.connect('size-allocate', self._sizeAllocate)
+        self.connect('destroy', self.destroyEvent)
 
 
     def __setattr__(self, name, value):
@@ -294,9 +306,27 @@ class MfxCanvas(gnome.canvas.Canvas):
             # FIXME
             return gdk.LEFT_PTR
             return self.get_window().get_cursor(v)
+        elif attr == 'width':
+            return self.get_size()[0]
+        elif attr == 'height':
+            return self.get_size()[1]
         print "TkCanvas cget:", attr
         raise AttributeError, attr
 
+    def xview(self):
+        w, h = self.get_size()
+        dx, dy = self.world_to_window(0, 0)
+        return -float(dx)/w, 1.0
+    def yview(self):
+        w, h = self.get_size()
+        dx, dy = self.world_to_window(0, 0)
+        return -float(dy)/h, 1.0
+
+    def winfo_width(self):
+        return self.get_size()[0]
+    def winfo_height(self):
+        return self.get_size()[1]
+
     def configure(self, **kw):
         height, width = -1, -1
         for k, v in kw.items():
@@ -320,10 +350,6 @@ class MfxCanvas(gnome.canvas.Canvas):
                 raise AttributeError, k
         if height > 0 and width > 0:
             self.set_size_request(width, height)
-            #self.queue_draw()
-            #self.queue_resize()
-            #self.show()
-            #pass
 
     config = configure
 
@@ -335,7 +361,7 @@ class MfxCanvas(gnome.canvas.Canvas):
                 i._item.destroy()
             ##i._item = None
         self._all_items = []
-        if self.__tileimage:
+        if 0: #self.__tileimage:
             self.__tileimage.destroy()
             self.__tileimage = None
 
@@ -457,7 +483,6 @@ class MfxCanvas(gnome.canvas.Canvas):
         self.__tileimage = w
 
 
-
     def setTopImage(self, image, cw=0, ch=0):
         if self.__topimage:
             self.__topimage.destroy()
@@ -482,6 +507,7 @@ class MfxCanvas(gnome.canvas.Canvas):
         #gdk.window_process_all_updates()
         #self.show_now()
         self.update_now()
+        pass
 
 
     def grid(self, *args, **kw):
@@ -492,19 +518,22 @@ class MfxCanvas(gnome.canvas.Canvas):
         self.show()
 
 
-    def _resize(self):
-        ##print '_resize:', self._width, self._height
-        #if self.window:
-        self.set_size(self._width, self._height)
-        self.window.resize(self._width, self._height)
-
     def setInitialSize(self, width, height):
         ##print 'setInitialSize:', width, height
         self._width, self._height = width, height
         self.set_size_request(width, height)
         #self.set_size(width, height)
         #self.queue_resize()
-        #gobject.idle_add(self._resize, priority=gobject.PRIORITY_HIGH_IDLE)
+
+
+    def destroyEvent(self, w):
+        #print 'MfxCanvas.destroyEvent'
+        self.hide()
+##         self.deleteAllItems()
+##         if self.__topimage:
+##             self.__topimage.destroy()
+##             self.__topimage = None
+
 
 
 class MfxScrolledCanvas(MfxCanvas):
diff --git a/pysollib/pysolgtk/tkutil.py b/pysollib/pysolgtk/tkutil.py
index 7e576770..69b07582 100644
--- a/pysollib/pysolgtk/tkutil.py
+++ b/pysollib/pysolgtk/tkutil.py
@@ -119,14 +119,20 @@ def color_gtk2tk(col):
 
 
 class _PysolPixmap:
-    def __init__(self, file=None):
+    def __init__(self, file=None, pixbuf=None, width=0, height=0,
+                 fill=None, outline=None):
         if file:
             self.pixbuf = gdk.pixbuf_new_from_file(file)
+        elif pixbuf:
+            self.pixbuf = pixbuf
         else:
-            self.pixbuf = gdk.Pixbuf()
+            self.pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB,
+                                     True, 8, width, height)
 
     def clone(self):
-        return self.pixbuf.copy()
+        pixbuf = self.pixbuf.copy()
+        im = _PysolPixmap(pixbuf=pixbuf)
+        return im
 
     def width(self):
         return self.pixbuf.get_width()
@@ -134,19 +140,24 @@ class _PysolPixmap:
     def height(self):
         return self.pixbuf.get_height()
 
-    def subsample(self, x, y=None):
-        ## FIXME
-        return None
+    def subsample(self, r):
+        w, h = self.pixbuf.get_width(), self.pixbuf.get_height()
+        w, h = int(float(w)/r), int(float(h)/r)
+        pixbuf = self.pixbuf.scale_simple(w, h, gdk.INTERP_BILINEAR)
+        im = _PysolPixmap(pixbuf=pixbuf)
+        return im
 
 
 def loadImage(file):
     return _PysolPixmap(file=file)
 
 def copyImage(image, x, y, width, height):
-    return image
+    # FIXME
+    return image.clone()
 
 def createImage(width, height, fill, outline=None):
-    return _PysolPixmap()
+    # FIXME
+    return _PysolPixmap(width=width, height=height, fill=fill, outline=outline)
 
 
 # /***********************************************************************
diff --git a/pysollib/pysolgtk/tkwidget.py b/pysollib/pysolgtk/tkwidget.py
index 34a7f8b8..1cef442c 100644
--- a/pysollib/pysolgtk/tkwidget.py
+++ b/pysollib/pysolgtk/tkwidget.py
@@ -74,8 +74,6 @@ class MfxDialog(_MyDialog):
                  text='', justify='center',
                  strings=("OK",), default=0,
                  separatorwidth=0,
-                 font=None,
-                 buttonfont=None,
                  padx=20, pady=20,
                  bitmap=None, bitmap_side='left',
                  bitmap_padx=20, bitmap_pady=20,
@@ -84,6 +82,7 @@ class MfxDialog(_MyDialog):
         _MyDialog.__init__(self)
         self.status = 1
         self.button = -1
+        self.buttons = []
 
         modal=True
         if modal:
@@ -121,7 +120,8 @@ class MfxDialog(_MyDialog):
                      "question": gtk.STOCK_DIALOG_QUESTION} [kw['bitmap']]
             im = gtk.image_new_from_stock(stock, gtk.ICON_SIZE_DIALOG)
             box.pack_start(im)
-            im.xpad, im.ypad = kw['bitmap_padx'], kw['bitmap_pady']
+            im.set_property('xpad', kw['bitmap_padx'])
+            im.set_property('ypad', kw['bitmap_pady'])
             im.show()
         elif kw['image']:
             im = gtk.Image()
@@ -130,7 +130,8 @@ class MfxDialog(_MyDialog):
                 box.pack_start(im)
             else:
                 box.pack_end(im)
-            im.xpad, im.ypad = kw['image_padx'], kw['image_pady']
+            im.set_property('xpad', kw['image_padx'])
+            im.set_property('ypad', kw['image_pady'])
             im.show()
 
     def createButtons(self, box, kw):
@@ -149,6 +150,7 @@ class MfxDialog(_MyDialog):
             b.connect("clicked", self.done)
             box.pack_start(b)
             b.show()
+            self.buttons.append(b)
 
     def initKw(self, kw):
         kwdefault(kw,
diff --git a/pysollib/pysolgtk/tkwrap.py b/pysollib/pysolgtk/tkwrap.py
index abf38f50..a11f3977 100644
--- a/pysollib/pysolgtk/tkwrap.py
+++ b/pysollib/pysolgtk/tkwrap.py
@@ -202,7 +202,6 @@ class _MfxToplevel(gtk.Window):
 
     def wm_geometry(self, newGeometry=None):
         ##print 'wm_geometry', newGeometry
-        print 'allow_shrink:', self.allow_shrink
         if not newGeometry:
             pass
             ##self.reshow_with_initial_size()
diff --git a/pysollib/pysolgtk/toolbar.py b/pysollib/pysolgtk/toolbar.py
index 046a39f3..f2e7845d 100644
--- a/pysollib/pysolgtk/toolbar.py
+++ b/pysollib/pysolgtk/toolbar.py
@@ -60,7 +60,7 @@ class PysolToolbar(PysolToolbarActions):
         ui_info = '''
 <ui>
   <toolbar  name='toolbar'>
-    <toolitem action='new'/>
+    <toolitem action='newgame'/>
     <toolitem action='restart'/>
     <separator/>
     <toolitem action='open'/>
diff --git a/pysollib/tk/menubar.py b/pysollib/tk/menubar.py
index 56b26082..f43b3b33 100644
--- a/pysollib/tk/menubar.py
+++ b/pysollib/tk/menubar.py
@@ -853,7 +853,8 @@ class PysolMenubar(PysolMenubarActions):
         if not idir:
             idir = self.app.dn.savegames
         d = tkFileDialog.Open()
-        filename = d.show(filetypes=self.FILETYPES, defaultextension=self.DEFAULTEXTENSION,
+        filename = d.show(filetypes=self.FILETYPES,
+                          defaultextension=self.DEFAULTEXTENSION,
                           initialdir=idir, initialfile=ifile)
         if filename:
             filename = os.path.normpath(filename)
@@ -880,7 +881,8 @@ class PysolMenubar(PysolMenubarActions):
             idir = self.app.dn.savegames
         ##print self.game.filename, ifile
         d = tkFileDialog.SaveAs()
-        filename = d.show(filetypes=self.FILETYPES, defaultextension=self.DEFAULTEXTENSION,
+        filename = d.show(filetypes=self.FILETYPES,
+                          defaultextension=self.DEFAULTEXTENSION,
                           initialdir=idir, initialfile=ifile)
         if filename:
             filename = os.path.normpath(filename)