diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,29 @@
+{-# LANGUAGE CPP #-}
+
+import Control.Monad (foldM_, forM_)
+import Data.Maybe ( fromMaybe )
+import System.Cmd
+import System.Exit
+import System.Info (os)
+import System.FilePath
+import System.Directory ( doesFileExist, copyFile, removeFile, createDirectoryIfMissing )
+
+import Distribution.PackageDescription
+import Distribution.MacOSX
+import Distribution.Simple.Setup
+import Distribution.Simple
+import Distribution.Simple.LocalBuildInfo
+
+main :: IO ()
+main = defaultMainWithHooks $ simpleUserHooks
+    { postInst = appBundleInstallHook [geniApp DoNotChase]
+    , postBuild = appBundleBuildHook  [geniApp DoNotChase]
+    }
+
+geniApp :: ChaseDeps -> MacApp
+geniApp =
+  MacApp "geni-gui"
+         (Just "macstuff/wxmac.icns")
+         (Just "macstuff/Info.plist")
+         []
+         []
diff --git a/geni-gui.cabal b/geni-gui.cabal
new file mode 100644
--- /dev/null
+++ b/geni-gui.cabal
@@ -0,0 +1,61 @@
+Name:           geni-gui
+Version:        0.22.1
+License:        GPL
+License-file:   LICENSE
+Author:         Carlos Areces and Eric Kow
+Category:       Natural Language Processing
+Synopsis:       GenI graphical user interface
+Homepage:       http://projects.haskell.org/GenI
+Maintainer:     geni-users@loria.fr
+Build-Type:     Custom
+Cabal-Version: >=1.8
+Extra-source-files:
+            macstuff/Info.plist,
+            macstuff/wxmac.icns
+
+Library
+  Exposed-Modules:
+                NLP.GenI.BuilderGui
+                NLP.GenI.Graphviz
+                NLP.GenI.GraphvizShow
+                NLP.GenI.GraphvizShowPolarity
+                NLP.GenI.Gui
+                NLP.GenI.GuiHelper
+                NLP.GenI.MainGui
+                NLP.GenI.Simple.SimpleGui 
+  Other-Modules:
+                Paths_geni_gui
+
+  Hs-Source-Dirs: src
+  Ghc-options:    -Wall
+  Ghc-prof-options: -auto-all
+
+  Build-Depends: base >= 4 && < 5
+               , GenI
+               , cabal-macosx == 0.2.*
+               , array
+               , containers
+               , directory
+               , filepath
+               , yaml-light
+               , hslogger
+               , json
+               , mtl
+               , process
+               , split
+               , utf8-string
+               , strict-io
+               , wx       >= 0.12
+               , wxcore
+               , text
+               , graphviz >= 2999.12 && < 2999.14
+
+Executable     geni-gui
+ Main-Is:        geni-gui.hs
+ Hs-Source-Dirs: .
+
+ Ghc-options:    -Wall -rtsopts
+ Ghc-prof-options: -auto-all
+ Build-Depends: base >= 4 && < 5
+              , GenI
+              , geni-gui
diff --git a/geni-gui.hs b/geni-gui.hs
new file mode 100644
--- /dev/null
+++ b/geni-gui.hs
@@ -0,0 +1,20 @@
+-- GenI surface realiser
+-- Copyright (C) 2005 Carlos Areces and Eric Kow
+--
+-- 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; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+module Main (module NLP.GenI.MainGui) where
+
+import NLP.GenI.MainGui
diff --git a/macstuff/Info.plist b/macstuff/Info.plist
new file mode 100644
--- /dev/null
+++ b/macstuff/Info.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>geni-gui</string>
+	<key>CFBundleGetInfoString</key>
+	<string>GenI</string>
+	<key>CFBundleIconFile</key>
+	<string>wxmac.icns</string>
+	<key>CFBundleIdentifier</key>
+	<string>fr.loria.geni</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleLongVersionString</key>
+	<string>(c) 2005-2009 LORIA</string>
+	<key>CFBundleName</key>
+	<string>GenI</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>0</string>
+	<key>CSResourcesFileMapped</key>
+	<true/>
+	<key>LSRequiresCarbon</key>
+	<true/>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright 2005-2009 LORIA</string>
+</dict>
+</plist>
diff --git a/macstuff/wxmac.icns b/macstuff/wxmac.icns
new file mode 100644
Binary files /dev/null and b/macstuff/wxmac.icns differ
diff --git a/src/NLP/GenI/BuilderGui.hs b/src/NLP/GenI/BuilderGui.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/BuilderGui.hs
@@ -0,0 +1,59 @@
+-- GenI surface realiser
+-- Copyright (C) 2005 Carlos Areces and Eric Kow
+--
+-- 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; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+{-# LANGUAGE RankNTypes #-}
+module NLP.GenI.BuilderGui where
+
+import Graphics.UI.WX
+
+import qualified NLP.GenI.Builder as B
+import NLP.GenI (ProgStateRef, GeniResult)
+import NLP.GenI.Semantics
+import NLP.GenI.Statistics (Statistics)
+
+-- | Once upon a time, GenI had two very different algorithms for tree assembly,
+--   a CKY/Early style one using packed trees; and the traditional “simple“
+--   algorithm that remains in 2012-GenI.  Diffrent algorithms may use different
+--   chart items, and different debugger visualisations, hence this data structure
+--
+--   I hope one day to make a move towards implementing the fancier algorithms,
+--   which is why I'm keeping around this infrastructure
+data BuilderGui = BuilderGui
+    { -- | A 'resultsPnl' returns results, statistics and layouts for
+      --   a panel showing detailed results (eg. with trees and what not)
+      --   and one showing a summary of the results
+      resultsPnl  :: forall a
+                   . ProgStateRef 
+                  -> Window a -- ^ parent
+                  -> SemInput
+                  -> IO ([GeniResult],Statistics,Layout,Layout)
+    -- | Just a sentence summary tab (small part of the resultsPnl)
+    , summaryPnl :: forall a
+                  . ProgStateRef
+                 -> Window a -- ^ parent
+                 -> [GeniResult]
+                 -> Statistics
+                 -> IO Layout
+    , debuggerPnl :: forall a
+                   . ProgStateRef
+                  -> Window a -- ^ parent
+                  -> B.Input
+                  -> String   -- ^ name of the builder algorithm
+                  -> ([GeniResult] -> Statistics -> IO ())
+                  -- ^ what to do when we get results
+                  -> IO Layout
+    }
diff --git a/src/NLP/GenI/Graphviz.hs b/src/NLP/GenI/Graphviz.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/Graphviz.hs
@@ -0,0 +1,149 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
+
+{-
+ GenI surface realiser
+ Copyright (C) 2005 Carlos Areces and Eric Kow
+ 
+ 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; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+-}
+
+{- | Graphviz is an open source tool which converts an abstract
+     representation of a graph (node foo is connected to node bar, etc.)
+     into a nicely laid out graphic.  This module contains methods 
+     to invoke graphviz and to convert graphs and trees to its input format.
+
+     You can download this (open source) tool at
+     <http://www.research.att.com/sw/tools/graphviz>
+-}
+
+module NLP.GenI.Graphviz
+where
+
+import Control.Arrow ( second )
+import Data.GraphViz
+import Data.GraphViz.Printing ( printIt )
+import Data.GraphViz.Attributes.Complete
+
+import qualified Data.Text.Lazy as T
+import qualified Data.Text.Lazy.IO as T
+import Data.Text.Lazy ( Text )
+import Data.Tree
+import Prelude hiding ( writeFile )
+
+{- |
+     Data structures which can be visualised with GraphViz should
+     implement this class.  Note the first argument to graphvizShowGraph is
+     so that you can parameterise your show function (i.e. pass in
+     flags to change the way you show particular object).  Note
+     that by default, all graphs are treated as directed graphs.  You
+     can hide this by turning off edge arrows.
+-}
+class GraphvizShow b where
+  graphvizShowGraph       :: b -> DotGraph Text
+  graphvizShowAsSubgraph  :: Text   -- ^ prefix
+                          -> b      -- ^ item
+                          -> [DotSubGraph Text] -- ^ gv output
+  graphvizLabel           :: b      -- ^ item
+                          -> Text   -- ^ gv output
+  graphvizParams          :: b -> [GlobalAttributes]
+
+  graphvizShowGraph b  =
+    DotGraph False True Nothing $ DotStmts
+       (addLabel (graphvizLabel b) $ graphvizParams b)
+       (graphvizShowAsSubgraph "_" b)
+       []
+       []
+    where
+      addLabel :: Text -> [GlobalAttributes] -> [GlobalAttributes]
+      addLabel "" = id
+      addLabel l  = (GraphAttrs [Label (StrLabel l)] :)
+
+  graphvizLabel _ = ""
+  graphvizParams _ = []
+
+class GraphvizShowNode b where
+  graphvizShowNode :: Text   -- ^ prefix
+                   -> b      -- ^ item 
+                   -> DotNode Text -- ^ gv output
+
+-- | Things which are meant to be displayed within some other graph
+--   as (part) of a node label
+class GraphvizShowString b where
+  graphvizShow :: b      -- ^ item
+               -> Text   -- ^ gv output
+
+-- | Note: the 'dotFile' argument allows you to save the intermediary
+-- dot output to a file.  You can pass in the empty string if you don't
+toGraphviz :: GraphvizShow a     => a
+                                 -> String -- ^ the 'dotFile'
+                                 -> String -> IO FilePath
+toGraphviz x dotFile outputFile = do
+   T.writeFile dotFile (printIt g)
+   runGraphviz g Png outputFile
+ where
+  g = graphvizShowGraph x
+
+-- ---------------------------------------------------------------------
+-- useful utility functions
+-- ---------------------------------------------------------------------
+
+gvUnlines :: [Text] -> Text
+gvUnlines = T.intercalate "\n"
+
+-- ---------------------------------------------------------------------
+-- some instances 
+-- ---------------------------------------------------------------------
+
+instance GraphvizShow b => GraphvizShow (Maybe b) where
+  graphvizShowAsSubgraph _ Nothing  = []
+  graphvizShowAsSubgraph p (Just b) = graphvizShowAsSubgraph p b
+
+  graphvizLabel Nothing  = ""
+  graphvizLabel (Just b) = graphvizLabel b
+
+  graphvizParams Nothing = []
+  graphvizParams (Just b) = graphvizParams b
+
+-- | Displays a tree in graphviz format.  
+{- Note that we could make this an
+   instance of GraphvizShow, but I'm not too sure about the wisdom of
+   such a move.  
+
+   Maybe if we had some really super-sophisticated types in Haskell, where
+   we can define this as the default instance which could be overrided by
+   something more specific, that would be cool.
+
+   The prefix argument is interpreted as the name of the top node.  Node
+   names below are basically Gorn addresses (e.g. n0x2x3 means 3rd child of
+   the 2nd child of the root) to keep them distinct.  Note : We use the
+   letter `x' as seperator because graphviz will choke on `.' or `-', even
+   underscore. -}
+gvShowTree :: GraphvizShowNode n =>
+     Text                   -- ^ node prefix
+  -> Tree n                 -- ^ the tree
+  -> DotSubGraph Text
+gvShowTree prefix t =
+  DotSG False Nothing $ DotStmts atts [] nodes edges
+ where
+  atts = [ EdgeAttrs [ ArrowHead noArrow ] ] -- should be none
+  (nodes, edges) = second concat . unzip $ walk prefix t
+  --
+  walk pref (Node node xs) =
+    let mkPrefix i = T.concat [pref, "x", T.pack (show i)]
+        ns = graphvizShowNode pref node
+        ps = map mkPrefix [1::Int .. length xs]
+        es = map (\n -> DotEdge pref n []) ps
+    in (ns, es) : concat (zipWith walk ps xs)
diff --git a/src/NLP/GenI/GraphvizShow.hs b/src/NLP/GenI/GraphvizShow.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/GraphvizShow.hs
@@ -0,0 +1,277 @@
+--  GenI surface realiser
+--  Copyright (C) 2009 Eric Kow
+--
+--  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; if not, write to the Free Software
+--  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, MultiParamTypeClasses, FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-- | Outputting core GenI data to graphviz.
+module NLP.GenI.GraphvizShow
+where
+
+import Control.Applicative ( (<$>) )
+import Data.FullList ( fromFL )
+import Data.List ( nub )
+import Data.Maybe(listToMaybe, maybeToList, mapMaybe)
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text as T
+
+import Data.GraphViz
+import Data.GraphViz.Attributes.Complete
+
+import NLP.GenI.FeatureStructure ( AvPair(..), Flist )
+import NLP.GenI.General ( clumpBy )
+import NLP.GenI.Pretty
+import NLP.GenI.GeniVal (GeniVal(..), isConst)
+import NLP.GenI.Graphviz
+    ( GraphvizShow(graphvizShowAsSubgraph, graphvizLabel, graphvizParams)
+    , GraphvizShowNode(graphvizShowNode)
+    , GraphvizShowString(graphvizShow)
+    , gvUnlines, gvShowTree
+    )
+import NLP.GenI.Semantics ( Sem )
+import NLP.GenI.Tag
+    ( TagDerivation, TagItem(..), TagElem(..)
+    , DerivationStep(..), dsChild, dsParent
+    )
+import NLP.GenI.TreeSchema ( GNode(..), GType(..) )
+
+-- ----------------------------------------------------------------------
+--
+-- ----------------------------------------------------------------------
+
+-- | Imagine some kind of menu system that displays a list of items
+--   and displays the selected item
+data GvItem flg itm = GvHeader T.Text      -- ^ no actual item
+                    | GvItem T.Text flg itm
+
+gvItemLabel :: GvItem a b -> T.Text
+gvItemLabel (GvHeader h)   = h
+gvItemLabel (GvItem l _ _) = l
+
+gvItemSetFlag :: f -> GvItem f a -> GvItem f a
+gvItemSetFlag _  g@(GvHeader _) = g
+gvItemSetFlag f2 (GvItem l _ x) = GvItem l f2 x
+
+instance GraphvizShow a => GraphvizShow (GvItem () a) where
+    graphvizShowAsSubgraph _ (GvHeader _ )   = []
+    graphvizShowAsSubgraph p (GvItem _ () b) = graphvizShowAsSubgraph p b
+
+    graphvizLabel (GvHeader _)     = ""
+    graphvizLabel (GvItem _ () b)  = graphvizLabel b
+
+    graphvizParams (GvHeader _)    = []
+    graphvizParams (GvItem _ () b) = graphvizParams b
+
+instance Functor (GvItem flg) where
+    fmap _  (GvHeader h)     = GvHeader h
+    fmap fn (GvItem l flg x) = GvItem l flg (fn x)
+
+-- ----------------------------------------------------------------------
+-- For GraphViz
+-- ----------------------------------------------------------------------
+
+type GNodeHighlights = (Bool, Highlights (GNode GeniVal))
+type Highlights a    = (a -> Maybe Color)
+
+nullHighlighter :: Highlights a
+nullHighlighter = const Nothing
+
+addNullHighlighter :: GvItem Bool x -> GvItem GNodeHighlights x
+addNullHighlighter (GvHeader h)   = GvHeader h
+addNullHighlighter (GvItem l f x) = GvItem l (f, nullHighlighter) x
+
+instance GraphvizShow (GvItem Bool TagElem) where
+    graphvizShowAsSubgraph p = graphvizShowAsSubgraph p . addNullHighlighter
+    graphvizLabel  = graphvizLabel  . addNullHighlighter
+    graphvizParams = graphvizParams . addNullHighlighter
+
+instance TagItem t => GraphvizShow (GvItem GNodeHighlights t) where
+    graphvizShowAsSubgraph _      (GvHeader _) = []
+    graphvizShowAsSubgraph prefix (GvItem _ (sf, hfn) te) =
+        [ gvShowTree (prefix `TL.append` "DerivedTree0")
+                     (fmap toDetails (tgTree te))
+        ]
+      where
+        toDetails x = Details { ddetails = sf
+                              , dcolour  = hfn x
+                              , dnode    = x
+                              }
+
+    graphvizLabel (GvHeader _)    = ""
+    graphvizLabel (GvItem _ _ te) =
+        gvUnlines [ treename, semlist ]
+      where
+        -- we display the tree semantics as the graph label
+        treename   = "name: "      `TL.append` TL.fromChunks [tgIdName te]
+        semlist    = "semantics: " `TL.append` gvShowSem (tgSemantics te)
+
+    graphvizParams _ =
+        [ GraphAttrs [ FontSize 10, RankSep [0.3] ]
+        , NodeAttrs  [ FontSize 10 ]
+        , EdgeAttrs  [ FontSize 10, ArrowHead normal ]
+        ]
+
+gvShowSem :: Sem -> TL.Text
+gvShowSem = gvUnlines
+          . map (TL.pack . unwords)
+          . clumpBy length 72
+          . words
+          . prettyStr
+
+-- ----------------------------------------------------------------------
+-- Helper functions for the TagElem GraphvizShow instance
+-- ----------------------------------------------------------------------
+
+data Details n = Details
+    { ddetails :: Bool
+    , dcolour  :: Maybe Color
+    , dnode    :: n
+    }
+
+instance GraphvizShowNode (Details (GNode GeniVal)) where
+    -- compact -> (node, mcolour) -> String
+    graphvizShowNode prefix dn =
+        DotNode prefix (body : shapeParams ++ colorParams)
+      where
+        -- attributes
+        filledParam         = Style [SItem Filled []]
+        fillcolorParam      = FillColor (X11Color LemonChiffon)
+        shapeRecordParam    = Shape Record
+        shapePlaintextParam = Shape PlainText
+        --
+        colorParams = FontColor <$> maybeToList (dcolour dn)
+        shapeParams = if ddetails dn
+                         then [ shapeRecordParam, filledParam, fillcolorParam ]
+                         else [ shapePlaintextParam ]
+        -- content
+        gn    = dnode dn
+        stub  = showGnStub gn
+        extra = showGnDecorations gn
+        summary = if TL.null extra
+                     then FieldLabel stub
+                     else FlipFields [ FieldLabel stub, FieldLabel extra ]
+        body = Label $
+            if not (ddetails dn)
+               then (StrLabel (graphvizShow_ gn))
+               else RecordLabel [ FlipFields $
+                                     [ summary
+                                     , FieldLabel . showFs $ gup gn
+                                     ] ++ maybeFs (gdown gn)
+                                ]
+          where
+            showFs = gvUnlines . map graphvizShow_
+            maybeFs fs = if null fs then [] else [FieldLabel (showFs fs)]
+
+instance GraphvizShowString (GNode GeniVal) where
+    graphvizShow gn =
+        stub `TL.append` extra
+      where
+        stub  = showGnStub gn
+        extra = showGnDecorations gn
+
+instance GraphvizShowString (AvPair GeniVal) where
+    graphvizShow (AvPair a v) = TL.fromChunks [a, ":"] `TL.append` graphvizShow_ v
+
+instance GraphvizShowString GeniVal where
+    graphvizShow g =
+        case (gLabel g, gConstraints g) of
+            (Nothing, Nothing) -> "?_"
+            (Nothing, Just cs) -> constraints cs
+            (Just l,  Nothing) -> plainVar l
+            (Just l,  Just cs) -> TL.concat [plainVar l, "/", constraints cs]
+      where
+        plainVar l = '?' `TL.cons` TL.fromChunks [l]
+        constraints cs = TL.intercalate "!" $ map TL.fromChunks [fromFL cs]
+
+showGnDecorations :: GNode GeniVal -> TL.Text
+showGnDecorations gn =
+    case gtype gn of
+        Subs -> "↓"
+        Foot -> "*"
+        _    -> if gaconstr gn then "ᴺᴬ"   else ""
+
+showGnStub :: GNode GeniVal -> TL.Text
+showGnStub gn =
+    TL.intercalate ":" $ filter (not . TL.null) [ cat, idx, lexeme ]
+  where
+    cat = case getGnVal gup "cat" gn of
+              Nothing -> ""
+              Just v  -> graphvizShow_ v
+    getIdx f = case getGnVal f "idx" gn of
+                   Nothing -> ""
+                   Just v  -> if isConst v then graphvizShow_ v else ""
+    idxT = getIdx gup
+    idxB = getIdx gdown
+    idx  = tackOn "." idxT idxB
+    --
+    lexeme  = TL.intercalate "!" [ TL.fromChunks [n] | n <- glexeme gn ]
+
+getGnVal :: (GNode GeniVal -> Flist GeniVal)
+         -> T.Text
+         -> GNode GeniVal
+         -> Maybe GeniVal
+getGnVal getFeat attr gn =
+    listToMaybe [ v | AvPair a v <- getFeat gn, a == attr ]
+
+-- | @x `tackOn p` y@` is @TL.concat [x, p, y]@ if @y@ is not null
+--   otherwise is just x
+tackOn :: TL.Text -> TL.Text -> TL.Text -> TL.Text
+tackOn p x y = if TL.null y then x else TL.concat [ x, p, y ]
+
+graphvizShow_ :: GraphvizShowString a => a -> TL.Text
+graphvizShow_ = graphvizShow
+
+-- ----------------------------------------------------------------------
+-- Derivation tree
+-- ----------------------------------------------------------------------
+
+graphvizShowDerivation :: TagDerivation -> [DotSubGraph TL.Text]
+graphvizShowDerivation = maybeToList . derivationToGv
+
+derivationToGv :: TagDerivation -> Maybe (DotSubGraph TL.Text)
+derivationToGv deriv =
+ if null histNodes
+    then Nothing
+    else Just $ DotSG False Nothing $ DotStmts atts [] nodes edges
+  where
+    atts = [ NodeAttrs [ Shape PlainText ]
+           , EdgeAttrs [ ArrowHead noArrow ]
+           ]
+    nodes = map mkNode histNodes
+    edges = mapMaybe mkEdge deriv
+    --
+    histNodes = reverse $ nub $ concatMap (\d -> dsChild d : maybeToList (dsParent d)) deriv
+    mkNode n  =
+        DotNode (gvDerivationLab n) [ Label . StrLabel $ label n ]
+    mkEdge ds = do
+     p <- dsParent ds
+     return $ DotEdge (gvDerivationLab p)
+                      (gvDerivationLab (dsChild ds))
+                      (edgeStyle ds)
+    edgeStyle (AdjunctionStep {}) = [Style [SItem Dashed []]]
+    edgeStyle _ = []
+    label n =
+        case T.splitOn ":" n of
+            name:fam:tree:_ -> TL.fromChunks [ name <> ":" <> fam <> "\n" <> tree ]
+            _               -> TL.fromChunks [n] `TL.append` " (geni/gv ERROR)"
+
+gvDerivationLab :: T.Text -> TL.Text
+gvDerivationLab xs = "Derivation" `TL.append` gvMunge xs
+
+-- | Node names can't have hyphens in them
+gvMunge :: T.Text -> TL.Text
+gvMunge = TL.fromChunks . T.split (`elem` ":-") . T.replace "." "x"
diff --git a/src/NLP/GenI/GraphvizShowPolarity.hs b/src/NLP/GenI/GraphvizShowPolarity.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/GraphvizShowPolarity.hs
@@ -0,0 +1,101 @@
+-- GenI surface realiser
+-- Copyright (C) 2005 Carlos Areces and Eric Kow
+--
+-- 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; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module NLP.GenI.GraphvizShowPolarity
+where
+
+import Data.List (intercalate)
+import qualified Data.Map as Map
+import Data.Maybe ( catMaybes )
+import Data.GraphViz
+import Data.GraphViz.Attributes.Complete
+
+import qualified Data.Text.Lazy as TL
+import NLP.GenI.General(showInterval)
+import NLP.GenI.Polarity(PolAut, PolState(PolSt), NFA(states, transitions), finalSt)
+import NLP.GenI.Pretty
+import NLP.GenI.Graphviz(GraphvizShow(..), gvUnlines)
+import NLP.GenI.Tag (idname)
+
+instance GraphvizShow PolAut where
+  -- we want a directed graph (arrows)
+  graphvizShowGraph aut =
+     DotGraph False True Nothing $ DotStmts
+         [ GraphAttrs [RankDir FromLeft, RankSep [0.02], Pack (PackMargin 1)]
+         , NodeAttrs [FontSize 10]
+         , EdgeAttrs [FontSize 10]
+         ]
+         (graphvizShowAsSubgraph "aut" aut)
+         [] -- all nodes are in the subgraph
+         []
+
+  --
+  graphvizShowAsSubgraph prefix aut =
+    [ DotSG False Nothing
+            $ DotStmts [ NodeAttrs [ Shape Ellipse, Peripheries 1 ] ]
+                       []
+                       (zipWith (gvShowState fin) ids st)
+                       (concat $ zipWith (gvShowTrans aut stmap) ids st)
+    ]
+    where
+       st  = (concat.states) aut
+       fin = finalSt aut
+       ids = map (\x -> prefix `TL.append` TL.pack (show x)) ([0..] :: [Int])
+       -- map which permits us to assign an id to a state
+       stmap = Map.fromList $ zip st ids
+
+gvShowState :: [PolState] -> TL.Text -> PolState -> DotNode TL.Text
+gvShowState fin stId st =
+  DotNode stId $ decorate [ Label . StrLabel . showSt $ st ]
+  where
+   showSt (PolSt _ ex po) =
+          gvUnlines . catMaybes $
+            [ Nothing -- Just (snd3 pr)
+            , if null ex then Nothing else Just (TL.fromChunks [pretty ex])
+            , Just . TL.pack . intercalate "," $ map showInterval po
+            ]
+   decorate = if st `elem` fin
+                 then (Peripheries 2 :)
+                 else id
+
+gvShowTrans :: PolAut -> Map.Map PolState TL.Text
+               -> TL.Text -> PolState -> [DotEdge TL.Text]
+gvShowTrans aut stmap idFrom st =
+  let -- outgoing transition labels from st
+      trans = Map.findWithDefault Map.empty st $ transitions aut
+      -- returns the graphviz dot command to draw a labeled transition
+      drawTrans (stTo,x) = case Map.lookup stTo stmap of
+                             Nothing   -> drawTrans' ("id_error_" `TL.append` (TL.pack (sem_ stTo))) x
+                             Just idTo -> drawTrans' idTo x
+                           where sem_ (PolSt i _ _) = show i
+                                 --showSem (PolSt (_,pred,_) _ _) = pred
+      drawTrans' idTo x = DotEdge idFrom idTo [Label (drawLabel x)]
+      drawLabel labels  = StrLabel . gvUnlines $ labs
+        where
+          lablen  = length labels
+          maxlabs = 6
+          excess = TL.pack $ "...and " ++ show (lablen - maxlabs) ++ " more"
+          --
+          name t  = TL.fromChunks [ idname t ]
+          labstrs = map (maybe "EMPTY" name) labels
+          labs = if lablen > maxlabs
+                 then take maxlabs labstrs ++ [ excess ]
+                 else labstrs
+  in map drawTrans (Map.toList trans)
diff --git a/src/NLP/GenI/Gui.hs b/src/NLP/GenI/Gui.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/Gui.hs
@@ -0,0 +1,675 @@
+-- GenI surface realiser
+-- Copyright (C) 2005 Carlos Areces and Eric Kow
+--
+-- 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; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+{-# LANGUAGE NamedFieldPuns, RecordWildCards #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
+module NLP.GenI.Gui (guiGeni) where
+
+import Control.Applicative ( (<$>) )
+import Control.Exception ( catch, try, SomeException )
+import Control.Monad ( unless )
+import Data.IORef ( readIORef, modifyIORef )
+import Data.List ( nub, delete, findIndex)
+import Data.Maybe ( fromMaybe, catMaybes )
+import Data.Text ( Text )
+import Data.Version ( showVersion )
+import Prelude hiding ( catch )
+import System.Directory
+import System.Exit (exitWith, ExitCode(ExitSuccess))
+import System.FilePath ( makeRelative )
+import qualified Data.Text as T
+
+import Graphics.UI.WX
+import Graphics.UI.WXCore
+
+import NLP.GenI
+    ( ProgState(..), ProgStateRef, initGeni , GeniResult(..), prettyResult
+    , parseSemInput, loadEverything, loadTestSuite
+    )
+import NLP.GenI.Configuration
+    ( Params(..), Instruction, hasOpt , hasFlagP
+    , deleteFlagP, setFlagP, getFlagP, getListFlagP
+    , parseFlagWithParsec
+    --
+    , DetectPolaritiesFlg(..) , LexiconFlg(..)
+    , MacrosFlg(..) , MorphCmdFlg(..) , MorphInfoFlg(..), OptimisationsFlg(..)
+    , RankingConstraintsFlg(..) , RootFeatureFlg(..) , TestCaseFlg(..)
+    , TestSuiteFlg(..) , TestInstructionsFlg(..) , ViewCmdFlg(..)
+    --
+    , Optimisation(..) , BuilderType(..), mainBuilderTypes
+    )
+import NLP.GenI.General (fst3, prettyException, trim)
+import NLP.GenI.GeniShow ( geniShow, geniShowText )
+import NLP.GenI.GuiHelper
+import NLP.GenI.Parser hiding ( choice, label, tab, try )
+import NLP.GenI.Polarity
+import NLP.GenI.Pretty
+import NLP.GenI.Semantics
+import NLP.GenI.Simple.SimpleGui
+import NLP.GenI.TestSuite ( TestCase(..) )
+import Paths_geni_gui ( version )
+import qualified NLP.GenI.Builder as B
+import qualified NLP.GenI.BuilderGui as BG
+
+-- Main Gui
+
+guiGeni :: ProgStateRef -> IO()
+guiGeni pstRef = start (mainGui pstRef)
+
+mainGui :: ProgStateRef -> IO ()
+mainGui pstRef = do
+    pst <- readIORef pstRef
+    -- Top Window
+    f <- frame [text := "Geni Project"]
+    -- create statusbar field
+    status <- statusField   []
+    -- create the file menu
+    fileMen   <- menuPane [text := "&File"]
+    loadMenIt <- menuItem fileMen [text := "&Open files or configure GenI"]
+    quitMenIt <- menuQuit fileMen [text := "&Quit"]
+    set quitMenIt [on command := close f ]
+    -- create the help menu
+    helpMen   <- menuPane [text := "&Help"]
+    aboutMeIt <- menuAbout helpMen [help := "About"]
+    -- Tie the menu to this window
+    set f [ statusBar := [status]
+          , menuBar := [fileMen, helpMen]
+          -- put the menu event handler for an about box on the frame.
+          , on (menu aboutMeIt) := infoDialog f "About GenI"
+             ("The GenI generator " ++ showVersion version ++
+              ".\nhttp://projects.haskell.org/GenI" )
+          -- event handler for the tree browser
+          -- , on (menu gbrowserMenIt) := do { loadEverything pstRef; treeBrowserGui pstRef }
+          ]
+    -- -----------------------------------------------------------------
+    -- buttons
+    -- -----------------------------------------------------------------
+    let config     = pa pst
+        hasSem     = hasFlagP TestSuiteFlg config
+    -- Target Semantics
+    testSuiteChoice <- choice f [ selection := 0, enabled := hasSem ]
+    tsTextBox <- textCtrl f [ wrap := WrapWord
+                            , clientSize := sz 400 80
+                            , enabled := hasSem
+                            , text := "" ]
+    testCaseChoice <- choice f [ selection := 0
+                               , enabled := hasSem ]
+    -- Detect polarities and root feature
+    let initialDP = maybe "" showPolarityAttrs (getFlagP DetectPolaritiesFlg config)
+        initialRF = maybe "" prettyStr (getFlagP RootFeatureFlg config)
+    detectPolsTxt <- entry f [ text := initialDP ]
+    rootFeatTxt   <- entry f [ text := initialRF ]
+    -- Box and Frame for files loaded
+    macrosFileLabel  <- staticText f [ text := getListFlagP MacrosFlg config  ]
+    lexiconFileLabel <- staticText f [ text := getListFlagP LexiconFlg config ]
+    -- Generate and Debug
+    let genfn = doGenerate f pstRef tsTextBox detectPolsTxt rootFeatTxt
+    pauseOnLexChk <- checkBox f [ text := "Inspect lex", tooltip := "Affects debugger only"  ]
+    debugBt <- button f [ text := "Debug"
+                        , on command := get pauseOnLexChk checked >>= genfn True ]
+    genBt  <- button f  [text := "Generate", on command := genfn False False ]
+    quitBt <- button f  [ text := "Quit",
+              on command := close f]
+    -- -----------------------------------------------------------------
+    -- optimisations
+    -- -----------------------------------------------------------------
+    let setBuilder b = modifyIORef pstRef . modifyParams
+                     $ \p -> p { builderType = b }
+        initialSelection = case builderType config of
+                             SimpleBuilder         -> 0
+                             SimpleOnePhaseBuilder -> 1
+    algoChoiceBox <- radioBox f Vertical (map show mainBuilderTypes) []
+    setSelection algoChoiceBox mainBuilderTypes initialSelection setBuilder
+    polChk <- optCheckBox f pstRef polarisedBio
+    useSemConstraintsChk <- optCheckBox f pstRef semConstraintBio
+    -- -----------------------------------------------------------------
+    -- layout; packing it all together
+    -- -----------------------------------------------------------------
+    -- set any last minute handlers, run any last minute functions
+    let myWidgets = MainWidgets
+            { f = f
+            , macrosFileLabel  = macrosFileLabel
+            , lexiconFileLabel = lexiconFileLabel
+            , testSuiteChoice  = testSuiteChoice
+            , testCaseChoice   = testCaseChoice
+            , tsTextBox        = tsTextBox
+            }
+        onLoad = mainOnLoad pstRef myWidgets
+    set loadMenIt [ on command := configGui pstRef onLoad ]
+    onLoad
+    --
+    let labeledRow l w = row 1 [ label l, hfill (widget w) ]
+    let gramsemBox = boxed "Files last loaded" $
+                hfill $ column 1
+                  [ labeledRow "trees:"   macrosFileLabel
+                  , labeledRow "lexicon:" lexiconFileLabel
+                  ]
+        optimBox =  --boxed "Optimisations " $ -- can't used boxed with wxwidgets 2.6 -- bug?
+                 column 5 [ label "Algorithm"
+                          , dynamic $ widget algoChoiceBox
+                          , label "Optimisations"
+                          , dynamic $ widget polChk
+                          , dynamic $ widget useSemConstraintsChk
+                          ]
+    set f [layout := column 5 [ gramsemBox
+                , row 5 [ fill $ -- boxed "Input Semantics" $
+                          hfill $ column 5
+                            [ labeledRow "test suite: " testSuiteChoice
+                            , labeledRow "test case: "  testCaseChoice
+                            , fill  $ widget tsTextBox
+                            , row 1 [ label "detect pols: "
+                                    , hfill (widget detectPolsTxt)
+                                    , glue
+                                    , label "root feature: "
+                                    , hfill (widget rootFeatTxt)
+                                    ]
+                            ]
+                        , vfill optimBox ]
+                 -- ----------------------------- Generate and quit
+                , row 1 [ widget quitBt
+                       , hfloatRight $ row 5 [ widget pauseOnLexChk, widget debugBt, widget genBt ]] ]
+         -- , clientSize := sz 625 325
+         , on closing := exitWith ExitSuccess
+         ]
+
+data MainWidgets = MainWidgets
+    { f                :: Frame ()
+    , macrosFileLabel  :: StaticText ()
+    , lexiconFileLabel :: StaticText ()
+    , testSuiteChoice  :: Choice ()
+    , testCaseChoice   :: Choice ()
+    , tsTextBox        :: TextCtrl ()
+    }
+
+mainOnLoad :: ProgStateRef -> MainWidgets -> IO ()
+mainOnLoad pstRef (MainWidgets {..}) = do
+    cfg <- pa `fmap` readIORef pstRef -- we want the latest config!
+    -- errHandler title err = errorDialog f title (show err)
+    set macrosFileLabel  [ text := getListFlagP MacrosFlg cfg ]
+    set lexiconFileLabel [ text := getListFlagP LexiconFlg cfg ]
+    -- read the test suite if there is one
+    case getListFlagP TestInstructionsFlg cfg of
+      [] -> do
+          set testSuiteChoice [ enabled := False, items := [] ]
+          set testCaseChoice  [ enabled := False, items := [] ]
+      is -> do
+          set testSuiteChoice [ enabled := True,  items := map fst is ]
+          setSelection testSuiteChoice is 0 $
+             \t -> loadTestSuiteAndRefresh f pstRef t (tsTextBox, testCaseChoice)
+
+-- ----------------------------------------------------------------------
+-- Toggling optimisations
+-- ----------------------------------------------------------------------
+
+-- | optimisation or pessimisation?
+data OptType = Opti | Pessi
+
+data OptBio = OptBio
+    { odType     :: OptType
+    , odOpt      :: Optimisation
+    , odShortTxt :: String -- ^ confusing detail: always describes an optimisation
+                           --   (so it says the straightforward thing for optimisations
+                           --    but the opposite meaning for pessimisations)
+    , odToolTip  :: String -- ^ see confusing detail above
+    }
+
+polarisedBio :: OptBio
+polarisedBio = OptBio Opti Polarised
+    "Polarities"
+    "Use the polarity optimisation"
+
+semConstraintBio :: OptBio
+semConstraintBio = OptBio Pessi NoConstraints
+    "Sem constraints"
+    "Use any sem constraints the user provides"
+
+optBios :: [OptBio]
+optBios = [ polarisedBio, semConstraintBio ]
+
+-- | Note the following point about pessimisations: An pessimisation
+--   disables a default behaviour which is assumed to be "optimisation".  But of
+--   course we don't want to confuse the GUI user, so we confuse the programmer
+--   instead: Given an pessimisation DisableFoo, we have a check box UseFoo.  If
+--   UseFoo is checked, we remove DisableFoo from the list; if it is unchecked, we
+--   add it to the list.  This is the opposite of the default behaviour, but the
+--   result, I hope, is intuitive for the user.
+optCheckBox :: Window a -> ProgStateRef -> OptBio -> IO (CheckBox ())
+optCheckBox f pstRef od = do
+    config <- pa <$> readIORef pstRef
+    chk <- checkBox f [ checked := flippy (hasOpt o config)
+                      , text    := odShortTxt od
+                      , tooltip := odToolTip od
+                      ]
+    set chk [ on command := onCheck chk ]
+    return chk
+  where
+    o = odOpt od
+    flippy = case odType od of
+               Opti  -> id
+               Pessi -> not
+    onCheck chk = do
+        isChecked <- get chk checked
+        config    <- pa <$> readIORef pstRef
+        let modopt  = if flippy isChecked then (o:) else delete o
+            newopts = nub . modopt $ getListFlagP OptimisationsFlg config
+        modifyIORef pstRef . modifyParams $ setFlagP OptimisationsFlg newopts
+
+-- --------------------------------------------------------------------
+-- Loading files
+-- --------------------------------------------------------------------
+
+-- | Load the given test suite and update the GUI accordingly.
+--   This is used when you first start the graphical interface
+--   or when you run the configuration menu.
+loadTestSuiteAndRefresh :: (Textual a, Selecting b, Selection b, Items b String)
+              => Window w
+              -> ProgStateRef
+              -> Instruction
+              -> (a, b) -- ^ test suite text and case selector widgets
+              -> IO ()
+loadTestSuiteAndRefresh f pstRef (suitePath,mcs) widgets = do
+    pst    <- readIORef pstRef
+    msuite <- try (loadTestSuite pstRef)
+    let mcase = getFlagP TestCaseFlg (pa pst)
+    case msuite of
+        Left e  -> errorDialog f ("Error reading test suite " ++ suitePath) $ show (e :: SomeException)
+        Right s -> onTestSuiteLoaded f s mcs mcase widgets
+
+-- | Helper for 'loadTestSuiteAndRefresh'
+onTestSuiteLoaded :: (Textual a, Selecting b, Selection b, Items b String)
+                  => Window w
+                  -> [TestCase]     -- ^ loaded suite
+                  -> Maybe [Text]   -- ^ subset of test cases to select (instructions)
+                  -> Maybe Text     -- ^ particular test case to focus on
+                  -> (a, b) -- ^ test suite text and case selector widgets
+                  -> IO ()
+onTestSuiteLoaded f suite mcs mcase (tsBox, caseChoice) = do
+    -- if the instructions specify a set of cases, we hide the cases that aren't mentioned
+    let suiteCases = case filter (\c -> tcName c `elem` fromMaybe [] mcs) suite of
+                       []  -> suite
+                       res -> res
+    -- handler for selecting a test case
+    unless (null suiteCases) $ do
+        initial <- getInitialSelection mcase suiteCases
+        set caseChoice [ items := zipWith numfn [1..] suiteCases ]
+        setSelection caseChoice suiteCases initial setTsBox
+  where
+    -- we number the cases for easy identification, putting
+    -- a star to highlight the selected test case (if available)
+    numfn :: Int -> TestCase -> String
+    numfn n t = concat [ if hasName (fromMaybe "" mcase) t then "* " else ""
+                       , show  n
+                       , ". "
+                       , T.unpack (tcName t)
+                       ]
+    -- first case selected is either specified
+    getInitialSelection Nothing  _      = return 0
+    getInitialSelection (Just n) tcases =
+        case findIndex (hasName n) tcases of
+            Nothing -> do
+                errorDialog f "" ("No such test case: " ++ T.unpack n)
+                return 0
+            Just i  -> return i
+    hasName name tc = tcName tc == name
+    --
+    setTsBox (TestCase {..}) =
+        set tsBox [ text := geniShow (toSemInputString tcSem tcSemString) ]
+
+-- --------------------------------------------------------------------
+-- Configuration
+-- --------------------------------------------------------------------
+
+-- | 'configGui' @pstRef loadFn@ provides the configuration GUI. The continuation
+--   @loadFn@ tells us what to do when the user closes this window.
+configGui ::  ProgStateRef -> IO () -> IO ()
+configGui pstRef loadFn = do
+    pst <- readIORef pstRef
+    let config = pa pst
+    --
+    f  <- frame []
+    p  <- panel f []
+    nb <- notebook p []
+    let browseTxt = "Browse"
+    --
+    let fakeBoxed title lst = hstretch $ column 3 $ map hfill $
+          [ hrule 1 , alignRight $ label title, vspace 5 ]
+          ++ map hfill lst
+    let longSize  = sz 20 (25 :: Int)
+    -- -----------------------------------------------------------------
+    -- basic options tab
+    -- -----------------------------------------------------------------
+    pbas <- panel nb []
+    -- files loaded (labels)
+    macrosFileLabel  <- staticText pbas [ text := getListFlagP MacrosFlg config  ]
+    lexiconFileLabel <- staticText pbas [ text := getListFlagP LexiconFlg config ]
+    tsFileLabel      <- staticText pbas [ text := getListFlagP TestSuiteFlg config ]
+    -- "Browse buttons"
+    macrosBrowseBt  <- button pbas [ text := browseTxt ]
+    lexiconBrowseBt <- button pbas [ text := browseTxt ]
+    tsBrowseBt      <- button pbas [ text := browseTxt ]
+    -- root feature
+    detectPolsTxt <- entry pbas
+        [ text := maybe "" showPolarityAttrs
+                      (getFlagP DetectPolaritiesFlg config)
+        , size := longSize ]
+    rootFeatTxt <- entry pbas
+        [ text := maybe "" prettyStr (getFlagP RootFeatureFlg config)
+        , size := longSize ]
+    let layFiles = [ row 1 [ label "trees:"
+                           , fill $ widget macrosFileLabel
+                           , widget macrosBrowseBt  ]
+                   , row 1 [ label "lexicon:"
+                           , fill $ widget lexiconFileLabel
+                           , widget lexiconBrowseBt ]
+                   , row 1 [ label "test suite:"
+                           , fill $ widget tsFileLabel
+                           , widget tsBrowseBt ]
+                   , hspace 5
+                   , hfill $ vrule 1
+                   , row 3 [ label "detect polarities"
+                           , hglue
+                           , rigid $ widget detectPolsTxt ]
+                   , row 3 [ label "root features"
+                           , hglue
+                           , rigid $ widget rootFeatTxt ]
+                   ]
+      -- the layout for the basic stuff
+    let layBasic = dynamic $ container pbas $ -- boxed "Basic options" $
+            hfloatLeft $ dynamic $ fill $ column 4 $ map (dynamic.hfill) layFiles
+    -- -----------------------------------------------------------------
+    -- advanced options tab
+    -- -----------------------------------------------------------------
+    padv <- panel nb []
+    -- XMG tools
+    viewCmdTxt <- entry padv
+        [ tooltip := "Command used for XMG tree viewing"
+        , text := getListFlagP ViewCmdFlg config ]
+    let layXMG = fakeBoxed "XMG tools"
+            [ row 3 [ label "XMG view command"
+                    , marginRight $ hfill $ widget viewCmdTxt ] ]
+    -- morphology
+    morphFileLabel    <- staticText padv [ text := getListFlagP MorphInfoFlg config ]
+    morphFileBrowseBt <- button padv [ text := browseTxt ]
+    morphCmdTxt    <- entry padv
+       [ tooltip := "Commmand used for morphological generation"
+       , text    := getListFlagP MorphCmdFlg config ]
+    let layMorph = fakeBoxed "Morphology"
+            [ row 3 [ label "morph info:"
+                    , expand $ hfill $ widget morphFileLabel
+                    , widget morphFileBrowseBt ]
+            , row 3 [ label "morph command"
+                    , (marginRight.hfill) $ widget morphCmdTxt ] ]
+    -- put the whole darn thing together
+    let layAdvanced = hfloatLeft $ container padv
+                    $ column 10 [ layXMG, layMorph ]
+    -- -----------------------------------------------------------------
+    -- browse button action
+    --
+    -- When the user clicks on a Browse button, an open file dialogue
+    -- should pop up.  It gets its value from the file label on its left
+    -- (passed in as an argument), and updates said label when the user has
+    -- made a selection.
+    -- -----------------------------------------------------------------
+    -- helper functions
+    curDir <- getCurrentDirectory
+    let onBrowse theLabel = do
+            rawFilename <- get theLabel text
+            let filename = makeRelative curDir rawFilename
+                filetypes = [("Any file",["*","*.*"])]
+            fsel <- fileOpenDialog f False True
+                      "Choose your file..." filetypes "" filename
+            case fsel of
+              -- if the user does not select any file there are no changes
+              Nothing   -> return ()
+              Just file -> set theLabel [ text := makeRelative curDir file ]
+    -- end onBrowse
+    -- activate those "Browse" buttons
+    let setBrowse w l = set w [ on command := onBrowse l ]
+    setBrowse macrosBrowseBt macrosFileLabel
+    setBrowse lexiconBrowseBt lexiconFileLabel
+    setBrowse tsBrowseBt tsFileLabel
+    setBrowse morphFileBrowseBt morphFileLabel
+    -- -----------------------------------------------------------------
+    -- config GUI layout
+    -- -----------------------------------------------------------------
+    let parseRF  = parseFlagWithParsec "root features" geniFeats
+        -- TODO: this is horrible! parseFlagWithParsec should be replaced with
+        -- something safer
+        onLoad
+         = do macrosVal <- get macrosFileLabel text
+              lexconVal <- get lexiconFileLabel text
+              tsVal     <- get tsFileLabel text
+              --
+              detectPolsVal <- get detectPolsTxt text
+              rootCatVal  <- get rootFeatTxt  text
+              --
+              viewVal   <- get viewCmdTxt text
+              --
+              morphCmdVal  <- get morphCmdTxt text
+              morphInfoVal <- get morphFileLabel text
+              --
+              let maybeSet fl fn x =
+                     if null x then deleteFlagP fl else setFlagP fl (fn x)
+                  maybeSetStr fl = maybeSet fl id
+              let setConfig = id
+                    . maybeSetStr MacrosFlg    macrosVal
+                    . maybeSetStr LexiconFlg   lexconVal
+                    . maybeSetStr TestSuiteFlg tsVal
+                    . maybeSetStr TestInstructionsFlg [(tsVal,Nothing)]
+                    . setFlagP DetectPolaritiesFlg (readPolarityAttrs detectPolsVal)
+                    . maybeSet RootFeatureFlg parseRF rootCatVal
+                    . maybeSetStr ViewCmdFlg   viewVal
+                    . maybeSetStr MorphCmdFlg  morphCmdVal
+                    . maybeSetStr MorphInfoFlg morphInfoVal
+              modifyIORef pstRef (modifyParams setConfig)
+              loadFn
+    -- end onLoad
+      -- the button bar
+    cancelBt <- button p [ text := "Cancel", on command := close f ]
+    loadBt   <- button p [ text := "Load", on command := do { onLoad; close f } ]
+    --
+    set f [ layout := dynamic $ fill $ container p $ column 0
+              [ fill $ tabs nb [ tab "Basic" layBasic
+                               , tab "Advanced" layAdvanced ]
+              , hfill $ row 1 [ hfloatLeft  (widget cancelBt)
+                              , hfloatRight (widget loadBt) ]
+              ]
+          ]
+
+-- --------------------------------------------------------------------
+-- Generation
+-- --------------------------------------------------------------------
+
+-- | 'doGenerate' parses the target semantics, then calls the generator and
+--   displays the result in a results gui (below).
+doGenerate :: Textual tb => Window a -> ProgStateRef
+                         -> tb -- ^ sem
+                         -> tb -- ^ polarities to detect
+                         -> tb -- ^ root feature
+                         -> Bool -> Bool -> IO ()
+doGenerate f pstRef sembox detectPolsTxt rootFeatTxt useDebugger pauseOnLex = do
+    let parseRF  = parseFlagWithParsec "root features" geniFeats
+    rootCatVal    <- get rootFeatTxt text
+    detectPolsVal <- get detectPolsTxt text
+    --
+    let maybeSet fl fn x =
+           if null x then deleteFlagP fl else setFlagP fl (fn x)
+    let setConfig = id
+                  . maybeSet RootFeatureFlg parseRF rootCatVal
+                  . setFlagP DetectPolaritiesFlg (readPolarityAttrs detectPolsVal)
+    modifyIORef pstRef (modifyParams setConfig)
+    minput <- do
+        set sembox [ text :~ trim ]
+        loadEverything   pstRef
+        parseSemInput <$> get sembox text
+    case minput of
+      Left e -> errorDialog f "Please give me better input" (show e)
+      Right semInput -> do
+          let doDebugger bg = debugGui   bg pstRef semInput pauseOnLex
+              doResults  bg = resultsGui bg pstRef semInput
+          catch
+              (withBuilderGui $ if useDebugger then doDebugger else doResults)
+              (handler "Error during realisation" prettyException)
+  where
+    handler title fn err = errorDialog f title (fn err)
+    withBuilderGui a = do
+      config <- pa <$> readIORef pstRef
+      case builderType config of
+        SimpleBuilder         -> a simpleGui2p
+        SimpleOnePhaseBuilder -> a simpleGui1p
+
+resultsGui :: BG.BuilderGui -> ProgStateRef -> SemInput -> IO ()
+resultsGui builderGui pstRef semInput = do
+    -- results window
+    f <- frame [ text := "Results"
+               , fullRepaintOnResize := False
+               , layout := stretch $ label "Generating..."
+               , clientSize := sz 300 300
+               ]
+    p    <- panel f []
+    nb   <- notebook p []
+    pst  <- readIORef pstRef
+    -- input tab
+    inputTab <- inputInfoGui nb (pa pst) semInput
+    -- realisations tab
+    (results,_,summTab,resTab) <- BG.resultsPnl builderGui pstRef nb semInput
+    -- ranking tab
+    mRankTab <- if hasFlagP RankingConstraintsFlg (pa pst)
+                   then Just <$> messageGui nb (purty pst results)
+                   else return Nothing
+    -- tabs
+    let myTabs = catMaybes
+           [ Just (tab "summary"       summTab)
+           , Just (tab "realisations"  resTab)
+           , tab "ranking" <$> mRankTab
+           , Just (tab "input"         inputTab)
+           ]
+    -- pack it all together
+    set f [ layout := container p $ column 0 [ tabs nb myTabs ]
+          , clientSize := bigSize ]
+    repaint f
+    return ()
+  where
+    purty pst res = T.unlines $ map (prettyResult pst) [ x | GSuccess x <- res ]
+
+
+-- --------------------------------------------------------------------
+-- Debugging
+-- --------------------------------------------------------------------
+
+-- | Information about the config/input in this session
+inputInfoGui :: Window a -- ^ parent window
+             -> Params
+             -> SemInput
+             -> IO Layout
+inputInfoGui f config semInput = messageGui f . T.unlines $
+    [ geniShowText semInput
+    , ""
+    , "Options"
+    , "-------"
+    , "Root feature: " <> maybe "" pretty (getFlagP RootFeatureFlg config)
+    , ""
+    , "Optimisations"
+    , "-------------"
+    ] ++ map optStatus optBios ++ polStuff
+
+ where
+  optStatus od = T.pack (odShortTxt od) <> ": " <>
+                 if enabld od then "Yes" else "No"
+  enabld od = case odType od of
+                Opti  -> configged od
+                Pessi -> not (configged od)
+  configged od = hasOpt  (odOpt od) config
+  dps = maybe "" showPolarityAttrs (getFlagP DetectPolaritiesFlg config)
+  polStuff = if enabld polarisedBio
+              then [ ""
+                   , "Detect polarities: " <> T.pack dps
+                   ]
+              else []
+
+-- | We provide here a universal debugging interface, which makes use of some
+--   parameterisable bits as defined in the BuilderGui module.
+debugGui :: BG.BuilderGui -> ProgStateRef -> SemInput -> Bool -> IO ()
+debugGui builderGui pstRef semInput pauseOnLex = do
+    config <- pa <$> readIORef pstRef
+    let btype = show (builderType config)
+    --
+    f <- frame [ text := "GenI Debugger - " ++ btype ++ " edition"
+               , fullRepaintOnResize := False
+               , clientSize := sz 300 300
+               ]
+    p    <- panel f []
+    nb   <- notebook p []
+    let addTabs [] = return ()
+        addTabs ts = do
+           oldCount <- notebookGetPageCount nb
+           set f [ layout := container p (tabs nb ts) -- appends ts
+                 , clientSize := bigSize
+                 ]
+           notebookSetSelection nb oldCount >> return ()
+    -- generation step 1
+    (initStuff, initWarns) <- initGeni pstRef semInput
+    let (cand,_)   = unzip $ B.inCands initStuff
+    -- continuation for tree assembly tab
+    let step3 results stats = do
+            resPnl <- BG.summaryPnl builderGui pstRef nb results stats
+            addTabs [tab "summary" resPnl]
+    -- continuation for candidate selection tab
+    let step2 newCands = do
+           -- generation step 2.A (run polarity stuff)
+           let newInitStuff = initStuff { B.inCands = map noBv newCands }
+               (input2, autstuff) = B.preInit newInitStuff config
+           -- automata tab
+           mAutPnl <- if hasOpt Polarised config
+                         then Just <$> myPolarityGui nb autstuff
+                         else return Nothing
+           -- generation step 2.B (start the generator for each path)
+           debugPnl <- BG.debuggerPnl builderGui pstRef nb input2 btype step3
+           let mAutTab  = tab "automata" <$> mAutPnl
+               debugTab = tab "tree assembly" debugPnl
+           addTabs $ catMaybes [ mAutTab, Just debugTab ]
+    -- inputs tab
+    inpPnl <- inputInfoGui nb config semInput
+    -- lexical selection tab
+    pst <- readIORef pstRef
+    (canPnl,_,_) <- pauseOnLexGui (pa pst) nb
+                       (B.inLex initStuff) cand initWarns $
+                       if pauseOnLex then Just step2 else Nothing
+    -- basic tabs
+    addTabs [ tab "input"             inpPnl
+            , tab "lexical selection" canPnl
+            ]
+    -- display all tabs if we are not told to pause on lex selection
+    unless pauseOnLex (step2 cand)
+  where
+    myPolarityGui nb autstuff =
+       fst3 <$> polarityGui nb (prIntermediate autstuff) (prFinal autstuff)
+    noBv x = (x, -1) -- all true?
+
+-- ----------------------------------------------------------------------
+-- odds and ends
+-- ----------------------------------------------------------------------
+
+bigSize :: Size2D Int
+bigSize = sz 700 600
+
+modifyParams :: (Params -> Params) -> ProgState -> ProgState
+modifyParams f pst = pst { pa = f (pa pst) }
+
+-- vim: set sw=4:
diff --git a/src/NLP/GenI/GuiHelper.hs b/src/NLP/GenI/GuiHelper.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/GuiHelper.hs
@@ -0,0 +1,810 @@
+-- GenI surface realiser
+-- Copyright (C) 2005 Carlos Areces and Eric Kow
+--
+-- 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; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+{-# LANGUAGE NamedFieldPuns, RecordWildCards #-}
+{-# LANGUAGE OverlappingInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+module NLP.GenI.GuiHelper where
+
+import Control.Applicative ( (<$>) )
+import Control.Exception hiding ( bracket )
+import Control.Monad ( unless, forM_ )
+import Control.Monad.State.Strict ( execStateT, runState )
+import Data.Array ( (!), listArray )
+import Data.GraphViz.Exception ( GraphvizException(..) )
+import Data.IORef
+import Data.Text ( Text )
+import Prelude hiding ( catch )
+import System.Directory
+import System.FilePath ((<.>),(</>),dropExtensions)
+import System.Process (runProcess)
+import qualified Control.Monad as Monad
+import qualified Data.Map as Map
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+
+import Graphics.UI.WX
+
+import NLP.GenI
+import NLP.GenI.Automaton (numStates, numTransitions)
+import NLP.GenI.Builder (queryCounter, num_iterations, chart_size, num_comparisons)
+import NLP.GenI.Configuration ( Params(..), MetricsFlg(..), setFlagP, getFlagP
+                              , hasOpt, Optimisation(..)
+                              , MacrosFlg(..), ViewCmdFlg(..) )
+import NLP.GenI.General (dropTillIncluding, ePutStrLn)
+import NLP.GenI.Parser ( geniTagElems, parseFromFile )
+import NLP.GenI.GeniShow ( geniShowText )
+import NLP.GenI.Graphviz
+import NLP.GenI.GraphvizShow (GvItem(..), gvItemSetFlag, gvItemLabel)
+import NLP.GenI.GraphvizShowPolarity ()
+import NLP.GenI.Lexicon
+import NLP.GenI.Polarity (PolAut, AutDebug, suggestPolFeatures)
+import NLP.GenI.Pretty
+import NLP.GenI.Statistics
+import NLP.GenI.Tag ( idname, mapBySem, TagElem(ttrace, tinterface), TagItem(tgIdName), tagLeaves )
+import NLP.GenI.TreeSchema ( showLexeme )
+import NLP.GenI.Warning
+import qualified NLP.GenI.Builder as B
+
+-- ----------------------------------------------------------------------
+-- Types
+-- ----------------------------------------------------------------------
+
+data GraphvizStatus = GvError String
+                    | GvNoSuchItem Int
+                    | GvCached
+                    | GvCreated FilePath
+  deriving Show
+
+-- ----------------------------------------------------------------------
+-- Lexically selected items
+-- ----------------------------------------------------------------------
+
+-- | 'pauseOnLexGui' allows the user to see lexical selection only and either
+--   dump it to file or read replace it by the contents of some other file
+pauseOnLexGui :: Params
+              -> Window a             -- ^ parent window
+              -> [LexEntry]          -- ^ lexically selected items (before anchoring)
+              -> [TagElem]            -- ^ lexically selected items
+              -> GeniWarnings         -- ^ lexical selection warnings
+              -> Maybe ([TagElem] -> IO ()) -- ^ run when “begin” is clicked
+              -> GvIO () (GvItem Bool TagElem)
+pauseOnLexGui config f lexs xs warns mjob = do
+    p <- panel f []
+    candV <- varCreate xs
+    (tb, ref, updater) <- candidateGui config p xs warns
+    -- supplementary button bar
+    let dispCmd = T.putStrLn (geniShowText lexs)
+        saveCmd = do
+            cs <- varGet candV
+            maybeSaveAsFile f (geniShowText cs <> "\n")
+        loadCmd = loadLex $ \cs -> do
+            varSet candV cs
+            setGvDrawables ref (sectionsBySem cs)
+            updater
+    --
+    dispBt <- button p [ text := "Show lexical entries", on command := dispCmd ]
+    saveBt <- button p [ text := "Save selection", on command := saveCmd ]
+    loadBt <- button p [ text := "Load", on command := loadCmd ]
+    nextBt <- button p [ text := "Begin" ]
+    let disableBar = forM_ [ loadBt, nextBt ] $
+            \w -> set w [ enabled := False ]
+        continue job = do
+            disableBar
+            varGet candV >>= job
+    case mjob of
+        Nothing -> disableBar
+        Just j  -> set nextBt [ on command := continue j ]
+    let lay = fill $ container p $ column 5
+              [ fill tb, hfill (vrule 1)
+              , row 0 [ row 5 [ widget dispBt, widget saveBt, widget loadBt ]
+                      , hfloatRight $ widget nextBt ] ]
+    return (lay, ref, updater)
+  where
+    loadLex job = do
+        fsel <- fileOpenDialog f False True
+                    "Choose your file..."
+                    anyFile "" ""
+        flip maybeIO fsel $ \file -> do
+            parsed <- parseFromFile geniTagElems file
+            case parsed of
+                Left err -> errorDialog f "" (show err)
+                Right c  -> job c
+
+
+-- | 'candidateGui' displays the lexically selected items, grouped by the
+--   semantics they subsume.
+candidateGui :: Params
+             -> Window a
+             -> [TagElem]
+             -> GeniWarnings
+             -> GvIO () (GvItem Bool TagElem)
+candidateGui config f xs warns = do
+    pouter <- panel f []
+    split  <- splitterWindow pouter []
+    p  <- panel split []
+    (tb,gvRef,updater) <- tagViewerGui config p "lexically selected item" "candidates"
+                          $ sectionsBySem xs
+    let polFeats = "Polarity attributes detected:" <+>
+                   case suggestPolFeatures xs of
+                       [] -> "None! :-("
+                       fs -> T.unwords fs
+        addPolFeats fs = if hasOpt Polarised config then polFeats : fs else fs
+        lexWarnings = concatMap showGeniWarning . fromGeniWarnings . sortWarnings $ warns
+        warning = T.unlines $ filter (not .  T.null) (addPolFeats lexWarnings)
+    -- side panel
+    sidePnl <- panel p []
+    ifaceLst <- singleListBox sidePnl [ tooltip := "interface for this tree (double-click me!)" ]
+    traceLst <- singleListBox sidePnl [ tooltip := "trace for this tree (double-click me!)" ]
+    tNoted <- textCtrl sidePnl [ wrap := WrapWord, text := "Hint: copy from below and paste into the sem:\n" ]
+    let laySide = container sidePnl $ column 2
+                    [ label "interface"
+                    ,  fill $ widget ifaceLst
+                    , label "trace"
+                    ,  fill $ widget traceLst
+                    , label "notes"
+                    ,  fill $ widget tNoted ]
+    -- handlers
+    let addLine :: String -> String -> String
+        addLine x y = y ++ "\n" ++ x
+        --
+        addToNoted w =
+          do sel    <- get w selection
+             things <- get w items
+             when (sel > 0) $ set tNoted [ text :~ addLine (things !! sel) ]
+    set ifaceLst [ on doubleClick := \_ -> addToNoted ifaceLst ]
+    set traceLst [ on doubleClick := \_ -> addToNoted traceLst ]
+    -- updaters : what happens when the user selects an item
+    let updateTrace = gvOnSelect (return ())
+          (\s -> set traceLst [ items := map T.unpack $ ttrace s ])
+        updateIface = gvOnSelect (return ())
+          (\s -> set ifaceLst [ items := map prettyStr $ tinterface s ])
+    Monad.unless (null xs) $ do
+        addGvHandler gvRef updateTrace
+        addGvHandler gvRef updateIface
+        -- first time run
+        gvSt <- readIORef gvRef
+        updateIface gvSt
+        updateTrace gvSt
+    --
+    let layMain = fill $ row 2 [ fill tb, vfill laySide ]
+    warningTxt <- textCtrl split [ text := T.unpack warning ]
+    let lay = fill . container pouter
+            $ fill $ hsplit split 5 100 (widget warningTxt) (container p layMain)
+    return (lay, gvRef, updater)
+
+sectionsBySem :: (TagItem t) => [t] -> [GvItem Bool t]
+sectionsBySem tsem =
+    concatMap section sem
+  where
+    semmap   = mapBySem tsem
+    sem      = Map.keys semmap
+    --
+    lookupTr k = Map.findWithDefault [] k semmap
+    section  k = GvHeader header : map tlab (lookupTr k)
+      where
+        header = "___" <> pretty k <> "___"
+        tlab t = GvItem (tgIdName t) False t
+
+-- ----------------------------------------------------------------------
+-- Polarity Automata
+-- ----------------------------------------------------------------------
+
+-- | A browser to see the automata constructed during the polarity optimisation
+--   step.
+polarityGui :: Window a   -- ^ parent window
+            -> [AutDebug] -- ^ intermediary automata
+            -> PolAut     -- ^ final automaton
+            -> GvIO () (GvItem () PolAut)
+polarityGui   f xs final = do
+    gvRef   <- newGvRef () "automata"
+    setGvDrawables gvRef $ concatMap toItem xs ++ [finalItem]
+    graphvizGui f "polarity" gvRef
+ where
+    toItem (pkey, a1, a2) = [ it (pretty pkey) a1
+                            , it (pretty pkey <+> "pruned") a2 ]
+    finalItem = it "final" final
+    it  n a = GvItem (lab n a) () a
+    lab n a = (n <+>) $ parens $
+         pretty (numStates a)      <> "st " <>
+         pretty (numTransitions a) <> "tr"
+
+-- ----------------------------------------------------------------------
+-- Helpers
+-- ----------------------------------------------------------------------
+
+-- | Any data structure which has corresponds to a TAG tree and which
+--   has some notion of derivation
+class XMGDerivation a where
+    getSourceTrees :: a -> [Text]
+
+instance XMGDerivation TagElem where
+    getSourceTrees te = [idname te]
+
+-- | 'toSentence' almost displays a 'TagElem' as a sentence, but only good
+-- enough for debugging needs.  The problem is that each leaf may be
+-- an atomic disjunction. Our solution is just to display each choice and
+-- use some delimiter to seperate them.  We also do not do any
+-- morphological processing.
+toSentence :: TagElem -> Text
+toSentence = T.unwords . map squishLeaf . tagLeaves
+
+squishLeaf :: (a,([Text], b)) -> Text
+squishLeaf = showLexeme . fst . snd
+
+-- ----------------------------------------------------------------------
+-- TAG viewer
+-- ----------------------------------------------------------------------
+
+-- | Variant of 'graphvizGui' with a toggle to view feature structures
+tagViewerGui :: (GraphvizShow (GvItem Bool t), XMGDerivation t)
+             => Params
+             -> Window a        -- ^ parent
+             -> Text            -- ^ tooltip
+             -> FilePath        -- ^ cache directory for graphviz
+             -> [GvItem Bool t] -- ^ items
+             -> GvIO () (GvItem Bool t)
+tagViewerGui config f tip cachedir itNlab = do
+    p <- panel f []
+    gvRef <- newGvRef () tip
+    setGvDrawables gvRef itNlab
+    (lay,ref,onUpdate) <- graphvizGui p cachedir gvRef
+    -- button bar widgets
+    detailsChk <- checkBox p [ text := "Show features"
+                             , checked := False ]
+    viewTagLay <- viewTagWidgets p gvRef config
+    -- handlers
+    let onDetailsChk = do
+            isDetailed <- get detailsChk checked
+            modifyGvItems gvRef (gvItemSetFlag isDetailed)
+            onUpdate
+    set detailsChk [ on command := onDetailsChk ]
+    -- pack it all in
+    let cmdBar = hfill $ row 5 [ dynamic $ widget detailsChk, viewTagLay ]
+        lay2   = fill  $ container p $ column 5 [ fill lay, cmdBar ]
+    return (lay2,ref,onUpdate)
+
+-- ----------------------------------------------------------------------
+-- XMG Metagrammar stuff.
+-- See <http://sourcesup.cru.fr/xmg/>
+-- ----------------------------------------------------------------------
+
+-- | Calls Yannick Parmentier's handy visualisation tool ViewTAG.
+viewTagWidgets :: (GraphvizShow (GvItem Bool t), XMGDerivation t)
+               => Window a -- ^ parent window
+               -> GraphvizGuiRef st (GvItem Bool t)
+               -> Params
+               -> IO Layout
+viewTagWidgets p gvRef config = do
+    viewTagBtn <- button p [ text := "ViewTAG" ]
+    viewTagCom <- choice p [ tooltip := "derivation tree" ]
+    -- handlers
+    let onViewTag d = readIORef gvRef >>=
+         gvOnSelect (return ()) (const (runViewTag config (T.unpack d)))
+    -- when the user selects a tree, we want to update the list of derivations
+    let updateDerivationList = gvOnSelect
+          (set viewTagCom [ enabled := False ])
+          (\s -> do
+               let dervs = getSourceTrees s
+               set viewTagCom [ enabled := True
+                              , items := map T.unpack dervs
+                              ]
+               setSelection viewTagCom dervs 0 $ \d ->
+                   set viewTagBtn [ on command := onViewTag d ]
+          )
+    addGvHandler gvRef updateDerivationList
+    updateDerivationList =<< readIORef gvRef
+    --
+    return $ row 5 $ map dynamic [ widget viewTagCom, widget viewTagBtn ]
+
+runViewTag :: Params -> String -> IO ()
+runViewTag params drName =
+    maybeOrWarn warnTf (getFlagP MacrosFlg params)  $ \f ->
+    maybeOrWarn warnVc (getFlagP ViewCmdFlg params) $ \cmd ->
+       actuallyView f cmd
+  where
+    warnTf = "Warning: No tree schema file specified (runViewTag)"
+    warnVc = "Warning: No viewcmd specified (runViewTag)"
+    treenameOnly = takeWhile (/= ':')
+                 . dropTillIncluding ':' . dropTillIncluding ':'
+    -- run the viewer
+    actuallyView f cmd =
+        runProcess cmd [ dropExtensions f <.> "rec", treenameOnly drName]
+           Nothing Nothing Nothing Nothing Nothing >> return ()
+
+-- --------------------------------------------------------------------
+-- Graphical debugger (helper functions)
+-- --------------------------------------------------------------------
+
+
+type DebuggerItemBar st flg itm =
+       Panel ()                           -- ^ parent panel
+    -> GraphvizGuiRef st (GvItem flg itm) -- ^ gv ref to use
+    -> GvUpdater -- ^ onUpdate
+    -> IO (Layout, GvUpdater)
+
+data GraphvizShow (GvItem flg itm) => Debugger st flg itm = Debugger
+    { dBuilder :: B.Builder st itm Params
+      -- ^ builder to use
+    , dToGv :: st -> [GvItem flg itm]
+      -- ^ function to convert a Builder state into lists of items
+      --   and their labels, the way graphvizGui likes it
+    , dControlPnl :: DebuggerItemBar st flg itm
+      -- ^ function returning a control panel configuring
+      --   how you want the currently selected item in the debugger
+      --   to be displayed
+    , dCacheDir :: FilePath
+      -- ^ graphviz cache directory
+    , dNext     :: [GeniResult] -> Statistics -> IO ()
+    }
+
+-- | A generic graphical debugger widget for GenI, including
+--
+--   * item viewer which allows the user to select one of the items in the
+--     builder state.
+--
+--   * item bar which provides some options on how to view the currently
+--     selected item, for example, if you want to display the features or not.
+--
+--   * A dashboard which lets the user do things like ``go ahead 6 steps''.
+--
+--   Besides the Builder, there are two functions you need to pass in make this
+--   work:
+--
+--      1. a 'stateToGv' which converts the builder state into a list of items
+--         and labels the way 'graphvizGui' likes it
+--
+--      2. an 'item bar' function which lets you control what bits you display
+--         of a selected item (for example, if you want a detailed view or not)
+--         the item bar should return a layout
+--
+--   Note that we don't constrain the type of item returned by the builder to
+--   be the same as the type handled by your gui: that's quite normal because
+--   you might want to decorate the type with some other information
+debuggerPanel :: GraphvizShow (GvItem flg itm)
+              => Debugger st flg itm
+              -> ProgStateRef
+              -> Window a -- ^ parent window
+              -> B.Input
+              -> IO Layout
+debuggerPanel (Debugger {..}) pstRef f input = do
+    config <- (setMetrics . pa) <$> readIORef pstRef
+    let (initS, initStats) = initBuilder input config
+    p <- panel f []
+    -- ---------------------------------------------------------
+    -- item viewer: select and display an item
+    -- ---------------------------------------------------------
+    gvRef <- newGvRef initS "debugger session"
+    setGvDrawables gvRef (dToGv initS)
+    (layItemViewer,_,onUpdateMain) <- graphvizGui p dCacheDir gvRef
+    -- ----------------------------------------------------------
+    -- item bar: controls for how an individual item is displayed
+    -- ----------------------------------------------------------
+    (layItemBar,onUpdateItemBar) <- dControlPnl p gvRef onUpdateMain
+    -- -------------------------------------------
+    -- dashboard: controls for the debugger itself
+    -- -------------------------------------------
+    let onUpdate = onUpdateMain >> onUpdateItemBar
+    db <- panel p []
+    restartBt <- button db [text := "Start over"]
+    nextBt    <- button db [text := "Step by..."]
+    leapVal   <- entry  db [ text := "1", clientSize := sz 30 25 ]
+    finishBt  <- button db [text := "Leap to end"]
+    statsTxt  <- staticText db []
+    done      <- varCreate False
+    -- dashboard commands
+    let showQuery c gs = maybe "???" show (queryCounter c gs)
+        updateStatsTxt gs = set statsTxt [ text :~ (\_ -> txtStats gs) ]
+        txtStats   gs =  unwords [ "itr",  showQuery num_iterations gs
+                                 , "chart sz", showQuery chart_size gs
+                                 ]
+                      ++ "\ncomparisons: " ++ showQuery num_comparisons gs
+    let genStep _ (st,stats) = runState (execStateT nextStep st) stats
+    let showNext s_stats = do
+            leapTxt <- get leapVal text
+            let leapInt :: Integer
+                leapInt = read leapTxt
+                (s2,stats2) = foldr genStep s_stats [1..leapInt]
+            modifyIORef gvRef $ \g -> g { gvcore = s2 }
+            setGvDrawables gvRef (dToGv s2)
+            setGvSel gvRef 1
+            onUpdate
+            updateStatsTxt stats2
+            set nextBt [ on command :~ (\_ -> showNext (s2,stats2) ) ]
+            case B.finished dBuilder s2 of
+                B.Active -> return ()
+                _        -> callNext done stats2 s2
+    let showLast = do
+             -- redo generation from scratch
+             let (s2, stats2) = runState (execStateT allSteps initS) initStats
+             setGvDrawables gvRef (dToGv s2)
+             onUpdate
+             updateStatsTxt stats2
+             callNext done stats2 s2
+    let showReset = do
+             set nextBt   [ on command  := showNext (initS, initStats) ]
+             updateStatsTxt initStats
+             setGvDrawables gvRef (dToGv initS)
+             setGvSel gvRef 1
+             onUpdate
+    -- dashboard handlers
+    set finishBt  [ on command := showLast ]
+    set restartBt [ on command := showReset ]
+    showReset
+    -- dashboard layout
+    let layCmdBar = hfill $ container db $ row 5
+                     [ widget statsTxt, hfloatRight $ row 5
+                       [ widget restartBt, widget nextBt
+                       , widget leapVal, label " step(s)"
+                       , widget finishBt ] ]
+    -- -------------------------------------------
+    -- overall layout
+    -- -------------------------------------------
+    return $ fill $ container p $ column 5 [ layItemViewer, layItemBar, hfill (vrule 1), layCmdBar ]
+  where
+    initBuilder = B.init  dBuilder
+    nextStep    = B.step  dBuilder
+    allSteps    = B.stepAll dBuilder
+    setMetrics  = setFlagP MetricsFlg B.defaultMetricNames
+    -- builder stateToGv itemBar f config_ input cachedir = do
+    callNext d stats st = do
+        done <- varGet d
+        unless done $ do
+            varSet d True
+            results <- extractResults pstRef dBuilder st
+            dNext results stats
+
+-- --------------------------------------------------------------------
+-- Graphviz GUI
+-- --------------------------------------------------------------------
+
+
+data GraphvizOrder = GvoParams | GvoItems | GvoSel
+  deriving Eq
+
+data GraphvizGuiSt st a = GvSt
+    { gvcore    :: st
+    , gvitems   :: Map.Map Int a
+    , gvlabels  :: [Text]
+    , gvtip     :: Text -- ^ tooltip for the selection box
+    -- | handler function to call when the selection is
+    --   updated (note: before displaying the object)
+    , gvhandler :: Maybe (GraphvizGuiSt st a -> IO ())
+    , gvsel     :: Int
+    , gvorders  :: [GraphvizOrder]
+    }
+
+-- | This provides a mechanism for communicating with the GUI.  The basic idea:
+--
+--  1. you create a GvRef with newGvRef
+--
+--  2. you call 'graphvizGui' and get back an updater function
+--
+--  3. whenever you want to modify something, you use setGvWhatever and call
+--     the updater function
+--
+--  4. if you want to react to the selection being changed, you should set
+--     gvhandler
+type GraphvizGuiRef st a = IORef (GraphvizGuiSt st a)
+
+newGvRef :: st -> Text -> IO (GraphvizGuiRef st a)
+newGvRef initSt t = newIORef GvSt
+    { gvcore = initSt
+    , gvitems  = Map.empty
+    , gvlabels  = []
+    , gvhandler = Nothing
+    , gvtip    = t
+    , gvsel    = 0
+    , gvorders = []
+    }
+
+setGvSel :: GraphvizGuiRef st a -> Int -> IO ()
+setGvSel gvref s  = modifyIORef gvref $ \x ->
+    x { gvsel = s, gvorders = GvoSel : gvorders x }
+
+modifyGvItems :: GraphvizGuiRef st a -> (a -> a) -> IO ()
+modifyGvItems gvref fn =
+    modifyIORef gvref $ \s -> s { gvitems = Map.map fn (gvitems s) }
+
+setGvDrawables :: GraphvizGuiRef st (GvItem f a) -> [GvItem f a] -> IO ()
+setGvDrawables gvref itlb = modifyIORef gvref $ \x ->
+    x { gvitems  = Map.fromList $ zip [0..] itlb
+      , gvlabels = map gvItemLabel itlb
+      , gvorders = GvoItems : gvorders x
+      }
+
+-- | Helper function for making selection handlers (see 'addGvHandler')
+--   Note that this was designed for cases where the contents is a Maybe
+gvOnSelect :: IO () -> (a -> IO ()) -> GraphvizGuiSt st (GvItem f a) -> IO ()
+gvOnSelect onNothing onJust gvSt =
+    case Map.lookup sel things of
+      Just (GvItem _  _ s) -> onJust s
+      _                    -> onNothing
+  where
+    sel    = gvsel gvSt
+    things = gvitems gvSt
+
+setGvHandler :: GraphvizGuiRef st a -> Maybe (GraphvizGuiSt st a -> IO ()) -> IO ()
+setGvHandler gvref mh = do
+    gvSt <- readIORef gvref
+    modifyIORef gvref (\x -> x { gvhandler = mh })
+    maybeIO ($ gvSt) mh
+
+-- | add a selection handler - if there already is a handler
+--   this handler will be called before the new one
+addGvHandler :: GraphvizGuiRef st a -> (GraphvizGuiSt st a -> IO ()) -> IO ()
+addGvHandler gvref h = do
+    gvSt <- readIORef gvref
+    let newH = case gvhandler gvSt of
+                 Nothing   -> h
+                 Just oldH -> \g -> oldH g >> h g
+    setGvHandler gvref (Just newH)
+
+type GvIO st d  = IO (Layout, GraphvizGuiRef st d, GvUpdater)
+type GvUpdater = IO ()
+
+-- |'graphvizGui' @f glab cachedir gvRef@ is a general-purpose GUI for
+-- displaying a list of items graphically via AT&T's excellent Graphviz
+-- utility.  We have a list box where we display all the labels the user
+-- provided.  If the user selects an entry from this box, then the item
+-- corresponding to that label will be displayed.
+--
+-- This returns a layout (wxhaskell container) and a function that you're
+-- expected to call whever something changes that would require the GUI to
+-- refresh itself (for example, you create a new chart item)
+--
+--  * @f@ - (parent window) the GUI is provided as a panel within the parent.
+--    Note: we use window in the WxWidget's sense, meaning it could be
+--    anything as simple as a another panel, or a notebook tab.
+--  * @glab@ - (gui labels) a tuple of strings (tooltip, next button text)
+--  * @cachedir@ - the cache subdirectory.  We intialise this by creating a cache
+--    directory for images which will be generated from the results
+--  * @gvRef@ - see above
+graphvizGui :: GraphvizShow d => Window a -> String -> GraphvizGuiRef st d -> GvIO st d
+graphvizGui f cachedir gvRef = do
+    initGvSt <- readIORef gvRef
+    -- widgets
+    p <- panel f [ fullRepaintOnResize := False ]
+    split <- splitterWindow p []
+    (dtBitmap,sw) <- scrolledBitmap split
+    rchoice  <- singleListBox split [ tooltip := T.unpack (gvtip initGvSt) ]
+    -- set handlers
+    let openFn   = openImage sw dtBitmap
+    -- pack it all together
+    let lay = fill $ container p $ margin 1 $ fill $
+              vsplit split 5 200 (widget rchoice) (widget sw)
+    set p [ on closing := closeImage dtBitmap ]
+    ------------------------------------------------
+    -- create an updater function
+    ------------------------------------------------
+    let withoutSelector job =
+          bracket ( swap rchoice (on select) (return ()) )
+                  ( \fn -> set rchoice [ on select := fn ] )
+                  ( const job )
+        -- the selector calls onUpdate which calls the selector
+        -- indirectly by setting the selection
+    let onUpdate = withoutSelector $ do
+          gvSt <- readIORef gvRef
+          let orders = gvorders gvSt
+          initCacheDir cachedir
+          Monad.when (GvoItems `elem` orders) $
+            set rchoice [ items := map T.unpack (gvlabels gvSt) ]
+          Monad.when (GvoSel `elem` orders) $
+            set rchoice [ selection := gvsel gvSt ]
+          modifyIORef gvRef (\x -> x { gvorders = []})
+          createAndOpenImage cachedir p gvRef openFn
+    ------------------------------------------------
+    -- enable the tree selector
+    -- FIXME: not sure that this is correct
+    ------------------------------------------------
+    let selectAndShow = do
+          -- putStrLn "selectAndShow called"
+          sel  <- get rchoice selection
+          -- note: do not use setGvSel (infinite loop)
+          modifyIORef gvRef (\x -> x { gvsel = sel })
+          -- call the handler if there is one
+          gvSt <- readIORef gvRef
+          maybeIO ($ gvSt) (gvhandler gvSt)
+          -- now do the update
+          onUpdate
+    ------------------------------------------------
+    set rchoice [ on select := selectAndShow ]
+    -- call the updater function for the first time
+    setGvSel gvRef 1
+    onUpdate
+    -- return the layout, the gvRef, and an updater function
+    -- The gvRef is to make it easier for users to muck around with the
+    -- state of the gui.  Here, it's trivial, but when people combine guis
+    -- together, it might be easier to keep track of when returned
+    return (lay, gvRef, onUpdate)
+
+-- ----------------------------------------------------------------------
+-- Bitmap stuff
+-- ----------------------------------------------------------------------
+
+-- | Bitmap with a scrollbar
+scrolledBitmap :: Window a -> IO(VarBitmap, ScrolledWindow ())
+scrolledBitmap p = do
+    dtBitmap <- variable [value := Nothing]
+    sw       <- scrolledWindow p [ scrollRate := sz 10 10
+                                 , bgcolor := white
+                                 , on paint := onPaint dtBitmap
+                                 , fullRepaintOnResize := False
+                                 ]
+    return (dtBitmap, sw)
+
+type OpenImageFn = FilePath -> IO ()
+type VarBitmap   = Var (Maybe (Bitmap ()))
+
+openImage :: Window a -> VarBitmap -> OpenImageFn
+openImage sw vbitmap fname = do
+    -- load the new bitmap
+    bm <- bitmapCreateFromFile fname  -- can fail with exception
+    closeImage vbitmap
+    set vbitmap [value := Just bm]
+    -- reset the scrollbars
+    bmsize <- get bm size
+    set sw [virtualSize := bmsize]
+    repaint sw
+
+closeImage :: VarBitmap -> IO ()
+closeImage vbitmap =
+    maybeIO objectDelete =<< swap vbitmap value Nothing
+
+onPaint :: VarBitmap -> DC a -> b -> IO ()
+onPaint vbitmap dc _ =
+    maybeIO draw =<< get vbitmap value
+  where
+    draw bm = dcClear dc >> drawBitmap dc bm pointZero False []
+
+-- | 'createAndOpenImage' attempts to draw an image (or retrieve it from cache)
+-- and opens it if we succeed.  Otherwise, it does nothing at all; the creation
+-- function will display an error message if it fails.
+createAndOpenImage :: GraphvizShow b
+                   => FilePath  -- ^ cache directory
+                   -> Window a  -- ^ parent window
+                   -> GraphvizGuiRef st b
+                   -> OpenImageFn
+                   -> IO ()
+createAndOpenImage cachedir f gvref openFn = do
+    gvStatus <- createImage cachedir f gvref
+    case gvStatus of
+      GvCreated g    -> openGraphic g
+      GvNoSuchItem _ -> return ()
+      GvError err    -> errorDialog f "" err
+      GvCached       -> return ()
+  where
+    openGraphic graphic = do
+        exists <- doesFileExist graphic
+        if exists
+           then openFn graphic
+           else errorDialog f "" (noFile graphic)
+    noFile g = "The file " ++ g ++ " was not created! Is graphviz installed?"
+
+-- | Creates a graphical visualisation for anything which can be displayed
+--   by graphviz.
+createImage :: GraphvizShow b
+            => FilePath            -- ^ cache directory
+            -> Window a            -- ^ parent window
+            -> GraphvizGuiRef st b -- ^ stuff to display
+            -> IO GraphvizStatus
+createImage cachedir f gvref = do
+    gvSt <- readIORef gvref
+    -- putStrLn $ "creating image via graphviz"
+    let drawables = gvitems  gvSt
+        sel       = gvsel    gvSt
+    dotFile <- createDotPath cachedir (show sel)
+    graphicFile <-  createImagePath cachedir (show sel)
+    let create x = do _ <- toGraphviz x dotFile graphicFile
+                      return . GvCreated $ graphicFile
+        handler :: GraphvizException -> IO GraphvizStatus
+        handler err = do
+            errorDialog f "Error calling graphviz. Is it installed?" (show err)
+            return . GvError . show $ err
+    exists <- doesFileExist graphicFile
+    -- we only call graphviz if the image is not in the cache
+    if exists
+       then return (GvCreated graphicFile)
+       else case Map.lookup sel drawables of
+              Nothing -> return (GvNoSuchItem sel)
+              Just it -> create it `catch` handler
+
+-- | Directory to dump image files in so that we can avoid regenerating them.
+--   If the directory already exists, we can just delete all the files in it.
+initCacheDir :: String -> IO()
+initCacheDir cachesubdir = do
+    mainCacheDir <- gvCACHEDIR
+    cmainExists  <- doesDirectoryExist mainCacheDir
+    unless cmainExists $ createDirectory mainCacheDir
+    let cachedir = mainCacheDir </> cachesubdir
+    cExists <- doesDirectoryExist cachedir
+    if cExists
+       then do
+           contents <- filter notJunk <$> getDirectoryContents cachedir
+           mapM_ (removeFile . (cachedir </>)) contents
+       else createDirectory cachedir
+  where
+    notJunk = (`notElem` [".", ".."])
+
+-- ----------------------------------------------------------------------
+-- Miscellaneous
+-- ----------------------------------------------------------------------
+
+-- | Set a selection widget's selection reactor
+--   We assume you've already populated it (radio boxes cannot be added to,
+--   so we have to let you do it manually on initialisation)
+setSelection :: (Selecting w, Selection w, Items w String)
+             => w                    -- ^ widget
+             -> [a]                  -- ^ items
+             -> Int                  -- ^ initial selection
+             -> (a -> IO ())         -- ^ on selection
+             -> IO ()
+setSelection widgt xs initial reactor = do
+    set widgt [ selection := initial
+              , on select := onSelection ]
+    onSelection
+  where
+    imap = listArray (0, length xs - 1) xs
+    onSelection = do
+        sel <- get widgt selection
+        reactor (imap ! sel)
+
+-- | Save the given string to a file, if the user selets one via the file save
+--   dialog. Otherwise, don't do anything.
+maybeSaveAsFile :: Window a -> Text -> IO ()
+maybeSaveAsFile f msg = do
+    fsel <- fileSaveDialog f False True "Save to" anyFile "" ""
+    case fsel of
+      Nothing   -> return ()
+      Just file -> T.writeFile file msg
+
+-- | A message panel for use by the Results gui panels.
+messageGui :: Window a -> Text -> IO Layout
+messageGui f msg = do
+    p <- panel f []
+    -- sw <- scrolledWindow p [scrollRate := sz 10 10 ]
+    t  <- textCtrl p [ text := T.unpack msg, enabled := False ]
+    return $ fill $ container p $ column 1 [ fill (widget t) ]
+
+gvCACHEDIR :: IO String
+gvCACHEDIR = do
+    home <- getHomeDirectory
+    return (home </> ".gvcache")
+
+createImagePath :: String -> String -> IO String
+createImagePath subdir name = do
+    cdir <- gvCACHEDIR
+    return (cdir </> subdir </> name <.> "png")
+
+createDotPath :: String -> String -> IO String
+createDotPath subdir name = do
+    cdir <- gvCACHEDIR
+    return (cdir </> subdir </> name <.> "dot")
+
+maybeOrWarn :: String  -- ^ warning
+            -> Maybe a
+            -> (a -> IO ())
+            -> IO ()
+maybeOrWarn warning m job = maybe (ePutStrLn warning) job m
+
+maybeIO :: (a -> IO ()) -> Maybe a -> IO ()
+maybeIO = maybe (return ())
+
+anyFile :: [ (String,[String]) ]
+anyFile = [("Any file",["*","*.*"])]
diff --git a/src/NLP/GenI/MainGui.hs b/src/NLP/GenI/MainGui.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/MainGui.hs
@@ -0,0 +1,57 @@
+-- GenI surface realiser
+-- Copyright (C) 2005 Carlos Areces and Eric Kow
+--
+-- 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; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+{-# LANGUAGE CPP #-}
+module NLP.GenI.MainGui where
+
+import Data.IORef(newIORef)
+import Data.Typeable( Typeable )
+import Data.Version ( showVersion )
+import System.Environment(getArgs, getProgName)
+
+import Paths_geni_gui ( version )
+import NLP.GenI ( ProgState(..), emptyProgState )
+import NLP.GenI.Configuration
+    ( treatArgs, optionsForStandardGenI, processInstructions, usage
+    , optionsSections, hasFlagP
+    , BatchDirFlg(..), DumpDerivationFlg(..),  FromStdinFlg(..)
+    , HelpFlg(..), VersionFlg(..)
+    , readGlobalConfig, setLoggers
+    )
+import NLP.GenI.Console(consoleGeni)
+import NLP.GenI.Gui(guiGeni)
+
+main :: IO ()
+main =  getArgs
+    >>= treatArgs optionsForStandardGenI
+    >>= processInstructions
+    >>= (mainWithState . emptyProgState)
+
+mainWithState :: ProgState -> IO ()
+mainWithState pst = do
+    pname <- getProgName
+    maybe (return ()) setLoggers =<< readGlobalConfig
+    pstRef <- newIORef pst
+    let has :: (Typeable f, Typeable x) => (x -> f) -> Bool
+        has = flip hasFlagP (pa pst)
+        mustRunInConsole = has DumpDerivationFlg || has FromStdinFlg
+                        || has BatchDirFlg
+    case () of
+      _ | has HelpFlg      -> putStrLn (usage optionsSections pname)
+        | has VersionFlg   -> putStrLn ("GenI " ++ showVersion version)
+        | mustRunInConsole -> consoleGeni pstRef
+        | otherwise        -> guiGeni pstRef
diff --git a/src/NLP/GenI/Simple/SimpleGui.hs b/src/NLP/GenI/Simple/SimpleGui.hs
new file mode 100644
--- /dev/null
+++ b/src/NLP/GenI/Simple/SimpleGui.hs
@@ -0,0 +1,293 @@
+-- GenI surface realiser
+-- Copyright (C) 2005 Carlos Areces and Eric Kow
+--
+-- 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; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module NLP.GenI.Simple.SimpleGui where
+
+import Control.Applicative ( (<$>) )
+import Control.Arrow ( (***) )
+import Data.IORef
+import Data.List ( sort, partition )
+import Data.Maybe ( fromMaybe )
+import qualified Data.Map as Map
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+
+import qualified Data.GraphViz as GV
+import qualified Data.GraphViz.Attributes.Complete as GV
+import Graphics.UI.WX
+
+import NLP.GenI
+    ( ProgStateRef, ProgState(pa), runGeni
+    , GeniResults(..) , GeniResult(..)
+    , GeniSuccess(..), GeniError(..), isSuccess
+    )
+import NLP.GenI.Configuration ( Params(..) )
+import NLP.GenI.FeatureStructure ( AvPair(..) )
+import NLP.GenI.General ( snd3, buckets )
+import NLP.GenI.GeniVal ( mkGConstNone, GeniVal )
+import NLP.GenI.Graphviz ( GraphvizShow(..), gvUnlines )
+import NLP.GenI.GraphvizShow
+    ( graphvizShowDerivation, GvItem(..)
+    , gvItemSetFlag, GNodeHighlights, Highlights )
+import NLP.GenI.GuiHelper
+    ( messageGui, tagViewerGui, maybeSaveAsFile, debuggerPanel
+    , Debugger (..)
+    , DebuggerItemBar, GvIO, newGvRef, GraphvizGuiSt(..), viewTagWidgets
+    , XMGDerivation(getSourceTrees), modifyGvItems
+    )
+import NLP.GenI.Morphology (LemmaPlus(..))
+import NLP.GenI.Polarity hiding ( finalSt )
+import NLP.GenI.Pretty
+import NLP.GenI.Semantics ( SemInput )
+import NLP.GenI.Simple.SimpleBuilder
+    ( simpleBuilder, SimpleStatus, SimpleItem(..), SimpleGuiItem(..)
+    , unpackResult ,step
+    , theResults, theAgenda, theHoldingPen, theChart, theTrash
+    )
+import NLP.GenI.Statistics (Statistics, showFinalStats)
+import NLP.GenI.Tag (dsChild, TagItem(..))
+import NLP.GenI.TreeSchema ( GNode(..), GType(..) )
+import qualified NLP.GenI.Builder    as B
+import qualified NLP.GenI.BuilderGui as BG
+
+-- --------------------------------------------------------------------
+-- Interface
+-- --------------------------------------------------------------------
+
+simpleGui2p, simpleGui1p :: BG.BuilderGui
+simpleGui2p = simpleGui True
+simpleGui1p = simpleGui False
+
+simpleGui :: Bool -> BG.BuilderGui
+simpleGui twophase = BG.BuilderGui
+    { BG.resultsPnl  = resultsPnl twophase
+    , BG.summaryPnl  = summaryGui
+    , BG.debuggerPnl = simpleDebuggerTab twophase
+    }
+
+resultsPnl :: Bool -> ProgStateRef -> Window a -> SemInput -> IO ([GeniResult], Statistics, Layout, Layout)
+resultsPnl twophase pstRef f semInput = do
+    (gresults, finalSt) <- runGeni pstRef semInput (simpleBuilder twophase)
+    let sentences = grResults    gresults
+        stats     = grStatistics gresults
+    (resultsL, _, _) <- realisationsGui pstRef f $ theResults finalSt
+    summaryL         <- summaryGui pstRef f sentences stats
+    return (sentences, stats, summaryL, resultsL)
+
+-- --------------------------------------------------------------------
+-- Results
+-- --------------------------------------------------------------------
+
+-- Derived Trees
+
+-- | Browser for derived/derivation trees, except if there are no results, we show a
+--   message box
+realisationsGui :: ProgStateRef -> Window a -> [SimpleItem]
+                -> GvIO () (GvItem Bool SimpleItem)
+realisationsGui _   f [] = do
+    m <- messageGui f "No results found"
+    g <- newGvRef () ""
+    return (m, g, return ())
+realisationsGui pstRef f resultsRaw = do
+    config <- pa <$> readIORef pstRef
+    tagViewerGui config f tip "derived" itNlabl
+  where
+    tip = "result"
+    mkItNLabl x = GvItem (siToSentence x) False x
+    itNlabl = map mkItNLabl resultsRaw
+
+summaryGui :: ProgStateRef
+           -> Window a
+           -> [GeniResult]
+           -> Statistics -> IO Layout
+summaryGui _ f results stats = do
+    p <- panel f []
+    statsTxt <- textCtrl p [ text := showFinalStats stats ]
+    t <- textCtrl p [ text := T.unpack msg ]
+    saveBt <- button p [ text := "Save to file"
+                       , on command := maybeSaveAsFile f msg ]
+    return $ fill $ container p $ column 1
+        [ hfill $ label "Performance data"
+        , hfill $ widget statsTxt
+        , hfill $ label $ "Realisations (" ++ show totalResults ++ " found)"
+        , fill  $ widget t
+        , hfloatRight $ widget saveBt
+        ]
+  where
+    (succeses, errors) = partitionGeniResult results
+    taggedResults = concatMap sentences succeses
+    resultBuckets = buckets snd taggedResults
+    sentences gr  = map (\r -> (grOrigin gr, r)) (grRealisations gr)
+    prettyBucket (s, xys) = s <+> parens instances
+      where
+        instances = if length ys == 1
+                       then ys_str
+                       else pretty (length ys) <+> "instances:" <+> ys_str
+        ys = map fst xys
+        ys_str = T.intercalate ", " . map pretty . sort $ ys
+    msg = T.unlines $ concatMap fromError errors
+                 ++ (if null succeses
+                        then [ "(none)" ]
+                        else map prettyBucket resultBuckets)
+    totalResults  = length taggedResults
+    fromError (GeniError e) = e
+
+partitionGeniResult :: [GeniResult] -> ([GeniSuccess],[GeniError])
+partitionGeniResult results = (map unSucc *** map unErr)
+                            $ partition isSuccess results
+  where
+    unSucc (GSuccess x) = x
+    unSucc _ = error "NLP.GenI.Simple.SimpleGui unSucc"
+    unErr  (GError x) = x
+    unErr  _ = error "NLP.GenI.Simple.SimpleGui unErr"
+
+-- --------------------------------------------------------------------
+-- Debugger
+-- --------------------------------------------------------------------
+
+simpleDebuggerTab :: Bool
+                  -> ProgStateRef
+                  -> Window a
+                  -> B.Input
+                  -> String
+                  -> ([GeniResult] -> Statistics -> IO ())
+                  -> IO Layout
+simpleDebuggerTab twophase pstRef f input name job = do
+    config <- pa <$> readIORef pstRef
+    debuggerPanel (dbg config) pstRef f input
+  where
+    dbg :: Params -> Debugger SimpleStatus Bool SimpleItem
+    dbg config = Debugger
+        { dBuilder    = simpleBuilder twophase
+        , dToGv       = stToGraphviz
+        , dControlPnl = simpleItemBar config
+        , dNext       = job
+        , dCacheDir   = name
+        }
+
+stToGraphviz :: SimpleStatus -> [GvItem Bool SimpleItem]
+stToGraphviz st =
+    concat [ agenda, auxAgenda, chart, trash, results ]
+  where
+    agenda    = section "AGENDA"    $ theAgenda    st
+    auxAgenda = section "HOLDING"   $ theHoldingPen st
+    trash     = section "TRASH"     $ theTrash     st
+    chart     = section "CHART"     $ theChart     st
+    results   = section "RESULTS"   $ theResults   st
+    --
+    section n i = hd : map tlFn i
+      where
+        hd     = GvHeader ("___" <> n <> "___")
+        tlFn x = GvItem (siToSentence x <+> prettyPaths x) False x
+    prettyPaths  = parens . prettyPolPaths . siPolpaths
+
+simpleItemBar :: Params -> DebuggerItemBar SimpleStatus Bool SimpleItem
+simpleItemBar config f gvRef updaterFn = do
+    ib <- panel f []
+    phaseTxt   <- staticText ib [ text := "" ]
+    detailsChk <- checkBox ib [ text := "Show features"
+                              , checked := False ]
+    viewTagLay <- viewTagWidgets ib gvRef config
+    -- handlers
+    let onDetailsChk = do
+            isDetailed <- get detailsChk checked
+            modifyGvItems gvRef (gvItemSetFlag isDetailed)
+            updaterFn
+    set detailsChk [ on command := onDetailsChk ]
+    --
+    let lay = hfloatCentre . container ib . row 5 $
+               [ hspace 5
+               , widget phaseTxt
+               , hglue
+               , widget detailsChk
+               , hglue
+               , viewTagLay
+               , hspace 5 ]
+    let onUpdate = do
+            status <- gvcore `fmap` readIORef gvRef
+            set phaseTxt [ text := show (step status) ]
+    return (lay, onUpdate)
+
+-- --------------------------------------------------------------------
+-- Miscellaneous
+-- -------------------------------------------------------------------
+
+-- to have the basic GraphvizShow functionality
+newtype SimpleItemWrapper = SimpleItemWrapper { fromSimpleItemWrapper :: SimpleItem }
+
+instance TagItem SimpleItemWrapper where
+    tgIdName    = siIdname . siGuiStuff . fromSimpleItemWrapper
+    tgIdNum     = siId . fromSimpleItemWrapper
+    tgSemantics = siFullSem . siGuiStuff . fromSimpleItemWrapper
+    tgTree si   =
+        lookupOrBug <$> siDerived (fromSimpleItemWrapper si)
+      where
+        lookupOrBug k = fromMaybe (buggyNode k) $ Map.lookup k nodeMap
+        nodeMap = fromListUsingKey gnname (siNodes (fromSimpleItemWrapper si))
+        buggyNode k = GN
+            { gup     = [ AvPair "cat"
+                             (mkGConstNone $ "ERROR looking up" <+> k)
+                        ]
+            , gdown   = []
+            , gnname  = "ERROR"
+            , glexeme = []
+            , gtype   = Other
+            , ganchor  = False
+            , gaconstr = False
+            , gorigin = "ERROR"
+            }
+
+fromListUsingKey :: Ord k => (a -> k) -> [a] -> Map.Map k a
+fromListUsingKey f xs = Map.fromList [ (f x, x) | x <- xs ]
+
+instance XMGDerivation SimpleItem where
+    -- Note: this is XMG-related stuff
+    getSourceTrees it = map dsChild (siDerivation it)
+
+instance GraphvizShow (GvItem Bool SimpleItem) where
+    graphvizLabel (GvHeader _)     = ""
+    graphvizLabel g@(GvItem _ _ c) =
+        gvUnlines $ graphvizLabel (highlightSimpleItem g)
+                  : map TL.pack (siDiagnostic (siGuiStuff c))
+
+    graphvizParams = graphvizParams . highlightSimpleItem
+
+    graphvizShowAsSubgraph _ (GvHeader _) = []
+    graphvizShowAsSubgraph p g@(GvItem _ _ it) =
+           graphvizShowAsSubgraph (p `TL.append` "TagElem") (highlightSimpleItem g)
+        ++ graphvizShowDerivation (siDerivation it)
+
+highlightSimpleItem :: GvItem Bool SimpleItem -> GvItem GNodeHighlights SimpleItemWrapper
+highlightSimpleItem (GvHeader h)    = GvHeader h
+highlightSimpleItem (GvItem l f it) = GvItem l (f, highlights) (SimpleItemWrapper it)
+  where
+    highlights :: Highlights (GNode GeniVal)
+    highlights n =
+        if gnname n `elem` siHighlight (siGuiStuff it)
+           then Just (GV.X11Color GV.Red)
+           else Nothing
+
+siToSentence :: SimpleItem -> T.Text 
+siToSentence si =
+    case unpackResult si of
+        []    -> siIdname . siGuiStuff $ si
+        (h:_) -> T.unwords ((idstr <> ".") : map lpLemma (snd3 h))
+  where
+    idstr = pretty (siId si)
