diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General
+Public License instead of this License.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,6 @@
+#!/usr/bin/runhaskell 
+> module Main where
+> import Distribution.Simple
+> main :: IO ()
+> main = defaultMain
+
diff --git a/ltk.cabal b/ltk.cabal
new file mode 100644
--- /dev/null
+++ b/ltk.cabal
@@ -0,0 +1,53 @@
+name: ltk
+version: 0.8
+cabal-version: -any
+build-type: Simple
+license: GPL
+license-file: LICENSE
+copyright: Juergen "jutaro" Nicklisch-Franken
+maintainer: maintainer@leksah.org
+build-depends: Cabal >=1.6.0, base >=4.0.0.0 && <5.0.0.0,
+               containers >=0.2, filepath >=1.1.0, glib >=0.10.0, gtk >=0.10.0,
+               mtl >=1.1.0.2, parsec >=2.1.0.1, pretty >=1.0.1.0
+stability:
+homepage: http://www.leksah.org
+package-url: http://code.haskell.org/ltk
+bug-reports: http://code.google.com/p/leksah/issues/list
+synopsis: Leksah tool kit
+description: UI Framework used by leksah
+category: GUI
+author: Juergen "jutaro" Nicklisch-Franken
+tested-with: GHC ==6.10 || ==6.12
+data-files:
+data-dir: ""
+extra-source-files:
+extra-tmp-files:
+exposed-modules: Default MyMissing Control.Event
+                 Graphics.UI.Editor.Basics Graphics.UI.Editor.Composite
+                 Graphics.UI.Editor.DescriptionPP Graphics.UI.Editor.MakeEditor
+                 Graphics.UI.Editor.Parameters Graphics.UI.Editor.Simple
+                 Graphics.UI.Frame.Panes Graphics.UI.Frame.ViewFrame
+                 Text.PrinterParser
+exposed: True
+buildable: True
+build-tools:
+cpp-options:
+cc-options:
+ld-options:
+pkgconfig-depends:
+frameworks:
+c-sources:
+extensions: CPP
+extra-libraries:
+extra-lib-dirs:
+includes:
+install-includes:
+include-dirs:
+hs-source-dirs: src
+other-modules:
+ghc-prof-options:
+ghc-shared-options:
+ghc-options:
+hugs-options:
+nhc98-options:
+jhc-options:
diff --git a/src/Control/Event.hs b/src/Control/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Event.hs
@@ -0,0 +1,86 @@
+{-# OPTIONS_GHC -XMultiParamTypeClasses -XFunctionalDependencies #-}
+-----------------------------------------------------------------------------
+--
+-- Module      :  Control.Event
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | A simple event mechanism
+--
+-------------------------------------------------------------------------------
+module Control.Event (
+    EventSelector
+,   Event(..)
+,   EventSource(..)
+,   Handlers
+) where
+
+import Data.Map (Map)
+import qualified Data.Map as Map
+import Data.Unique
+import Control.Monad
+
+-- | Every event needs a selector, which should identify the type of event
+class (Eq delta, Ord delta, Show delta) =>  EventSelector delta
+
+-- | Every event needs to know its selector and its source
+class EventSelector delta => Event beta delta | beta -> delta, delta -> beta where
+    getSelector ::  beta -> delta
+
+-- | This shows the implementation of the event mechnism
+type Handlers beta gamma delta = Map delta [(Unique, beta  -> gamma beta)]
+
+-- | Everything which is an event source needs this
+class (Monad gamma, Event beta delta) => EventSource alpha beta gamma delta
+        | alpha -> beta, alpha -> gamma where
+    getHandlers     ::  alpha -> gamma (Handlers beta gamma delta)
+    setHandlers     ::  alpha -> Handlers beta gamma delta -> gamma ()
+    myUnique        ::  alpha -> gamma (Unique)
+
+    -- | Reimplement this in instances to make triggering of events possible
+    canTriggerEvent :: alpha -> delta -> Bool
+    canTriggerEvent _ _             =   False
+
+    -- | Returns the event, so that you may get values back from an event
+    triggerEvent ::  alpha -> beta -> gamma beta
+    triggerEvent o e    =
+        if canTriggerEvent o (getSelector e)
+            then do
+                handlerMap  <-  getHandlers o
+                let selector    =   getSelector e
+                case selector `Map.lookup` handlerMap of
+                    Nothing     ->  return e
+                    Just l      ->  foldM (\e (_,ah) -> ah e) e (reverse l)
+            else error $ "Can't trigger event " ++ show (getSelector e)
+
+    -- | use Left to register and Right to unregister
+    -- returns Unique if registration was successfull, else Nothing
+    registerEvent   ::  alpha -> delta
+        -> Either (beta -> gamma beta) Unique -> gamma (Maybe Unique)
+    registerEvent o e (Left handler) =
+        if canTriggerEvent o e
+            then do
+                handlerMap  <-  getHandlers o
+                unique      <-  myUnique o
+                let newHandlers =   case e `Map.lookup` handlerMap of
+                                        Nothing -> Map.insert e [(unique,handler)] handlerMap
+                                        Just l  -> Map.insert e ((unique,handler):l) handlerMap
+                setHandlers o newHandlers
+                return (Just unique)
+            else error $ "Can't register event " ++ show e
+    registerEvent o e (Right unique) =
+        if canTriggerEvent o e
+            then do
+                handlerMap  <-  getHandlers o
+                let newHandlers =   case e `Map.lookup` handlerMap of
+                                        Nothing -> handlerMap
+                                        Just l -> let newList = filter (\ (mu,_) -> mu /= unique) l
+                                                  in  Map.insert e newList handlerMap
+                setHandlers o newHandlers
+                return (Just unique)
+            else error $ "Can't register event " ++ show e
+
diff --git a/src/Default.hs b/src/Default.hs
new file mode 100644
--- /dev/null
+++ b/src/Default.hs
@@ -0,0 +1,46 @@
+
+-----------------------------------------------------------------------------
+--
+-- Module      :  Default
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  Juergen Nicklisch-Franken <info@leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Module for default values of a data type
+--
+------------------------------------------------------------------------------
+
+module Default (
+    Default(..)
+) where
+
+--
+-- | A class for providing default values for certain types of editors
+--
+class Default alpha where
+    getDefault      ::   alpha
+
+instance Default Int where
+    getDefault      =   1
+
+instance Default alpha  => Default (Either alpha beta) where
+        getDefault  =   Left getDefault
+
+instance (Default alpha, Default beta) => Default (alpha, beta) where
+        getDefault  =   (getDefault,getDefault)
+
+instance (Default alpha, Default beta, Default gamma) => Default (alpha, beta, gamma) where
+        getDefault  =   (getDefault,getDefault,getDefault)
+
+instance Default [alpha] where
+        getDefault  =   []
+
+instance Default (Maybe alpha) where
+    getDefault      =   Nothing
+
+instance Default Bool where
+    getDefault      =   True
+
diff --git a/src/Graphics/UI/Editor/Basics.hs b/src/Graphics/UI/Editor/Basics.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Editor/Basics.hs
@@ -0,0 +1,285 @@
+{-# OPTIONS_GHC -XMultiParamTypeClasses -XScopedTypeVariables #-}
+
+-----------------------------------------------------------------------------
+--
+-- Module      :  Graphics.UI.Editor.Basics
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Module for the basiscs of composing GUIs from editors
+--
+-----------------------------------------------------------------------------------
+
+module Graphics.UI.Editor.Basics (
+-- * Types
+    Getter
+,   Setter
+,   Injector
+,   Extractor
+,   Applicator
+,   Editor
+,   getStandardRegFunction
+,   emptyNotifier
+,   GUIEvent(..)
+,   GUIEventSelector(..)
+,   GtkRegFunc
+,   Notifier(..)
+,   GtkHandler
+
+,   activateEvent
+,   propagateEvent
+,   allGUIEvents
+) where
+
+import Graphics.UI.Gtk
+import qualified Graphics.UI.Gtk.Gdk.Events as Gtk
+import Data.Unique
+import Data.IORef
+import Control.Monad
+
+import Graphics.UI.Editor.Parameters
+import Control.Event
+import Data.Map (Map(..))
+import qualified Data.Map as Map  (delete,insert,lookup,empty)
+import Data.Maybe (isJust,fromJust)
+import Unsafe.Coerce (unsafeCoerce)
+import Control.Arrow (first)
+import MyMissing (allOf)
+
+-- ---------------------------------------------------------------------
+-- * Basic Types
+--
+
+--
+-- | A type for getting a field of a record
+--
+type Getter alpha beta     =   alpha -> beta
+--
+-- | A type for setting the field of a record
+--
+type Setter alpha beta     =   beta -> alpha -> alpha
+
+--
+-- | A type for injecting a value into an editor
+--
+type Injector beta     =   beta -> IO ()
+--
+-- | A type for extracting a value from an editor
+--
+type Extractor beta    =   IO (Maybe beta)
+--
+-- | A type for the application of a value to be reflected in the GUI
+--
+type Applicator beta gamma  =   beta -> gamma ()
+
+--
+-- | A type to describe an editor.
+-- alpha is the type of the individual field of the record
+type Editor alpha  =   Parameters -> Notifier
+                        -> IO(Widget, Injector alpha , Extractor alpha)
+
+
+--
+-- | A type for an event in the GUI
+--
+data GUIEvent = GUIEvent {
+    selector :: GUIEventSelector
+,   gtkEvent :: Gtk.Event
+,   eventPaneName :: String
+,   gtkReturn :: Bool -- ^ True means that the event has been completely handled,
+                      --  gtk shoudn't do any further action about it (Often not
+                      --  a good idea
+}
+instance Event GUIEvent GUIEventSelector where
+    getSelector = selector
+
+data GUIEventSelector =   Clicked
+                    |   FocusOut
+                    |   FocusIn
+                    |   SelectionChanged
+                    |   ButtonRelease
+                    |   AfterKeyRelease
+    deriving (Eq,Ord,Show,Enum,Bounded)
+
+instance EventSelector GUIEventSelector
+
+allGUIEvents :: [GUIEventSelector]
+allGUIEvents = allOf
+
+-- ------------------------------------------------------------
+-- * Implementation of GUI event system
+-- ------------------------------------------------------------
+
+--  | A type for handling an IO event
+--  Returning True: The event has been handles
+--  Returning False: Handling should proceed
+type GtkHandler = Gtk.Event -> IO Bool
+
+--
+-- | A type for a function to register a gtk event
+-- |
+type GtkRegFunc = Widget  -> GtkHandler -> IO (ConnectId Widget)
+
+--
+-- | The widgets are the real event sources.
+-- The GtkRegFunc is the function used to register the event.
+-- The connectIds are set, when the event is activated, and
+-- can be used to deactivate the event.
+-- Or it is a propagated event and:
+-- The Notifier List is a list of event sources, to which registrations
+-- are propageted.
+-- The last map is used to unregister propagated events properly
+--
+type GUIEventReg = ([ConnectId Widget],
+                        ([Notifier], Map Unique [(Unique,Notifier)]))
+
+--
+-- | The event source in the gtk editor context
+-- If the second argument is Left Handler the handler gets registered
+-- If the second argument is Right Unique the handler will be removed
+-- The returned unique value must be used for unregistering an event
+newtype Notifier =   Noti (IORef (Handlers GUIEvent IO GUIEventSelector,
+                                        Map GUIEventSelector GUIEventReg))
+
+
+emptyNotifier :: IO Notifier
+emptyNotifier                            =   do
+    h <- newIORef (Map.empty,Map.empty)
+    let noti      =  Noti h
+    return noti
+
+instance  EventSource Notifier GUIEvent IO GUIEventSelector where
+    getHandlers (Noti pairRef)              =   do
+        (h,_) <- readIORef pairRef
+        return h
+
+    setHandlers (Noti pairRef) h            =   do
+        (_,r) <- readIORef pairRef
+        writeIORef pairRef (h,r)
+
+    myUnique _                              =   newUnique
+
+    canTriggerEvent _ _                     =   True
+
+    registerEvent o@(Noti pairRef) eventSel hand@(Left handler) =   do
+        (handlers, ger)     <-  readIORef pairRef
+        unique              <-  myUnique o
+        newGer <- case Map.lookup eventSel ger of
+                    Nothing -> return ger
+                    Just (_,([],um))  -> return ger
+                    Just (cids,(notifiers,um))  -> do
+                        lu <-  mapM (\es -> registerEvent es eventSel hand)
+                                        notifiers
+                        let jl =  map (first fromJust)
+                                        $ filter (isJust.fst)
+                                            $ zip lu notifiers
+                        let newUm = Map.insert unique jl um
+                        return (Map.insert eventSel (cids,(notifiers,newUm)) ger)
+        let newHandlers =   case eventSel `Map.lookup` handlers of
+                                Nothing -> Map.insert eventSel
+                                                [(unique,handler)] handlers
+                                Just l  -> Map.insert eventSel
+                                                ((unique,handler):l) handlers
+        writeIORef pairRef (newHandlers,newGer)
+        return (Just unique)
+    registerEvent o@(Noti pairRef) eventSel (Right unique) =   do
+        (handlers, ger) <- readIORef pairRef
+        newGer <- case Map.lookup eventSel ger of
+            Nothing -> return ger
+            Just (cids,(notis,um))  ->
+                case unique `Map.lookup` um of
+                    Nothing ->  return ger
+                    Just l  ->  do
+                        mapM_  (\(u,es) -> registerEvent es eventSel (Right u)) l
+                        let newUm = unique `Map.delete` um
+                        return (Map.insert eventSel (cids,(notis,newUm)) ger)
+        let newHandlers =   case eventSel `Map.lookup` handlers of
+                                Nothing -> handlers
+                                Just l -> case filter (\ (mu,_) -> mu /= unique) l of
+                                            [] -> Map.delete eventSel handlers
+                                            l  -> Map.insert eventSel l handlers
+        writeIORef pairRef (newHandlers,newGer)
+        return (Just unique)
+
+--
+-- | Propagate the event with the selector from notifier to eventSource
+--
+propagateEvent :: Notifier -> [Notifier] -> GUIEventSelector -> IO ()
+propagateEvent (Noti pairRef) eventSources eventSel = do
+    (handlers,ger) <- readIORef pairRef
+    let newGer =    case Map.lookup eventSel ger of
+                            Nothing -> Map.insert eventSel
+                                        ([],(eventSources,Map.empty)) ger
+                            Just (w,(notiList,unregMap)) -> Map.insert eventSel
+                                (w,(eventSources ++ notiList,unregMap)) ger
+    --now propagate already registered events
+    newGer2 <- case eventSel `Map.lookup` handlers of
+        Nothing     ->  return newGer
+        Just hl     ->  foldM (repropagate eventSel) newGer hl
+    writeIORef pairRef (handlers,newGer)
+    where
+    repropagate :: GUIEventSelector
+        ->  Map GUIEventSelector GUIEventReg
+        ->  (Unique, GUIEvent -> IO GUIEvent)
+        ->  IO (Map GUIEventSelector GUIEventReg)
+    repropagate eventSet ger (unique,hand) =
+        case Map.lookup eventSel ger of
+            Just (cids,(notifiers,um))
+                -> do
+                    lu <-  mapM (\es -> registerEvent es eventSel (Left hand))
+                                    notifiers
+                    let jl =  map (first fromJust)
+                                    $ filter (isJust.fst)
+                                        $ zip lu notifiers
+                    let newUm = Map.insert unique jl um
+                    return (Map.insert eventSel (cids,(notifiers,newUm)) ger)
+            _   ->  error "Basics>>propagateEvent: impossible case"
+
+--
+-- | Activate the event after the event has been declared and the
+-- widget has been constructed
+--
+activateEvent :: Widget -> Notifier -> Maybe GtkRegFunc -> GUIEventSelector  -> IO()
+activateEvent widget (Noti pairRef) mbRegisterFunc eventSel = do
+    let registerFunc    =   case mbRegisterFunc of
+                                Just f  ->  f
+                                Nothing ->  getStandardRegFunction eventSel
+    cid <- registerFunc widget (\ e -> do
+                (hi,_) <- readIORef pairRef
+                case Map.lookup eventSel hi of
+                    Nothing -> return False
+                    Just [] -> return False
+                    Just handlers -> do
+                        name <- widgetGetName widget
+                        eventList <- mapM (\f -> do
+                            let ev = GUIEvent eventSel e name False
+                            f ev)
+                                (map snd handlers)
+                        let boolList = map gtkReturn eventList
+                        return (foldr (&&) True boolList))
+    (handerls,ger) <- readIORef pairRef
+    let newGer      =   case Map.lookup eventSel ger of
+                            Nothing ->  Map.insert eventSel ([cid],([],Map.empty))
+                                        ger
+                            Just (cids,prop) ->
+                                        Map.insert eventSel (cid:cids,prop) ger
+    writeIORef pairRef (handerls,newGer)
+
+--
+-- | A convinence method for not repeating this over and over again
+--
+getStandardRegFunction :: GUIEventSelector -> GtkRegFunc
+getStandardRegFunction FocusOut         =   \w h -> w `onFocusOut` h
+getStandardRegFunction FocusIn          =   \w h -> w `onFocusIn` h
+getStandardRegFunction ButtonRelease    =   \w h -> w `onButtonRelease` h
+getStandardRegFunction AfterKeyRelease  =   \w h -> w `afterKeyRelease` h
+getStandardRegFunction Clicked          =   \w h -> do
+        res     <-  onClicked (castToButton w) (do
+                        h (Gtk.Event True)
+                        return ())
+        return (unsafeCoerce res)
+getStandardRegFunction SelectionChanged =   error "yet not implemented"
diff --git a/src/Graphics/UI/Editor/Composite.hs b/src/Graphics/UI/Editor/Composite.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Editor/Composite.hs
@@ -0,0 +1,788 @@
+-----------------------------------------------------------------------------
+--
+-- Module      :  Graphics.UI.Editor.Composite
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Module for making composite editors
+--
+-----------------------------------------------------------------------------------
+
+module Graphics.UI.Editor.Composite (
+    maybeEditor
+,   pairEditor
+,   tupel3Editor
+--,   tupel4Editor
+--,   tupel5Editor
+--,   tupel6Editor
+--,   tupel7Editor
+,   splitEditor
+,   eitherOrEditor
+,   multisetEditor
+,   ColumnDescr(..)
+
+,   filesEditor
+,   stringsEditor
+
+,   versionEditor
+,   versionRangeEditor
+,   dependencyEditor
+,   dependenciesEditor
+) where
+
+import Graphics.UI.Gtk
+import Control.Monad
+import Data.IORef
+import Data.Maybe
+
+import Default
+import Control.Event
+import Graphics.UI.Editor.Parameters
+import Graphics.UI.Editor.Basics
+import Graphics.UI.Editor.MakeEditor
+import Graphics.UI.Editor.Simple
+import Data.List (sortBy, nub, sort, elemIndex)
+import Distribution.Simple
+    (orEarlierVersion,
+     orLaterVersion,
+     VersionRange(..),
+     PackageName(..),
+     Dependency(..),
+     PackageIdentifier(..))
+import Distribution.Text (simpleParse, display)
+import Distribution.Package (pkgName)
+import Data.Version (Version(..))
+import MyMissing (forceJust)
+
+--
+-- | An editor which composes two subeditors
+--
+pairEditor :: (Editor alpha, Parameters) -> (Editor beta, Parameters) -> Editor (alpha,beta)
+pairEditor (fstEd,fstPara) (sndEd,sndPara) parameters notifier = do
+    coreRef <- newIORef Nothing
+    noti1   <- emptyNotifier
+    noti2   <- emptyNotifier
+    mapM_ (propagateEvent notifier [noti2]) allGUIEvents
+    fst@(fstFrame,inj1,ext1) <- fstEd fstPara noti1
+    snd@(sndFrame,inj2,ext2) <- sndEd sndPara noti2
+    mkEditor
+        (\widget (v1,v2) -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    box <- case getParameter paraDirection parameters of
+                        Horizontal -> do
+                            b <- hBoxNew False 1
+                            return (castToBox b)
+                        Vertical -> do
+                            b <- vBoxNew False 1
+                            return (castToBox b)
+                    boxPackStart box fstFrame PackGrow 0
+                    boxPackStart box sndFrame PackGrow 0
+                    containerAdd widget box
+                    inj1 v1
+                    inj2 v2
+                    writeIORef coreRef (Just (fst,snd))
+                Just ((_,inj1,_),(_,inj2,_)) -> do
+                    inj1 v1
+                    inj2 v2)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just ((_,_,ext1),(_,_,ext2)) -> do
+                    r1 <- ext1
+                    r2 <- ext2
+                    if isJust r1 && isJust r2
+                        then return (Just (fromJust r1,fromJust r2))
+                        else return Nothing)
+        parameters
+        notifier
+
+tupel3Editor :: (Editor alpha, Parameters)
+    -> (Editor beta, Parameters)
+    -> (Editor gamma, Parameters)
+    -> Editor (alpha,beta,gamma)
+tupel3Editor p1 p2 p3 parameters notifier = do
+    coreRef <- newIORef Nothing
+    noti1   <- emptyNotifier
+    noti2   <- emptyNotifier
+    noti3   <- emptyNotifier
+    mapM_ (propagateEvent notifier [noti2]) allGUIEvents
+    r1@(frame1,inj1,ext1) <- (fst p1) (snd p1) noti1
+    r2@(frame2,inj2,ext2) <- (fst p2) (snd p2) noti2
+    r3@(frame3,inj3,ext3) <- (fst p3) (snd p3) noti3
+    mkEditor
+        (\widget (v1,v2,v3) -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    box <- case getParameter paraDirection parameters of
+                        Horizontal -> do
+                            b <- hBoxNew False 1
+                            return (castToBox b)
+                        Vertical -> do
+                            b <- vBoxNew False 1
+                            return (castToBox b)
+                    boxPackStart box frame1 PackGrow 0
+                    boxPackStart box frame2 PackGrow 0
+                    boxPackStart box frame3 PackGrow 0
+                    containerAdd widget box
+                    inj1 v1
+                    inj2 v2
+                    inj3 v3
+                    writeIORef coreRef (Just (r1,r2,r3))
+                Just ((_,inj1,_),(_,inj2,_),(_,inj3,_)) -> do
+                    inj1 v1
+                    inj2 v2
+                    inj3 v3)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just ((_,_,ext1),(_,_,ext2),(_,_,ext3)) -> do
+                    r1 <- ext1
+                    r2 <- ext2
+                    r3 <- ext3
+                    if isJust r1 && isJust r2 && isJust r3
+                        then return (Just (fromJust r1,fromJust r2, fromJust r3))
+                        else return Nothing)
+        parameters
+        notifier
+
+{--
+tupel4Editor :: (Editor alpha, Parameters)
+    -> (Editor beta, Parameters)
+    -> (Editor gamma, Parameters)
+    -> (Editor delta, Parameters)
+    -> Editor (alpha,beta,gamma,delta)
+tupel4Editor p1 p2 p3 p4 parameters notifier = do
+    (widg,inj,ext) <- pairEditor ((tupel3Editor p1 p2 p3), parameters) p4 parameters notifier
+    return (widg,
+        (\ (a, b, c, d) -> inj ((a,b,c),d)),
+        (do
+            mb <- ext
+            case mb of
+                Nothing        -> return Nothing
+                Just ((a,b,c),d) -> return (Just (a,b,c,d))))
+
+tupel5Editor :: (Editor alpha, Parameters)
+    -> (Editor beta, Parameters)
+    -> (Editor gamma, Parameters)
+    -> (Editor delta, Parameters)
+    -> (Editor epsilon, Parameters)
+    -> Editor (alpha,beta,gamma,delta,epsilon)
+tupel5Editor p1 p2 p3 p4 p5 parameters notifier = do
+    (widg,inj,ext) <- pairEditor ((tupel4Editor p1 p2 p3 p4), parameters) p5 parameters notifier
+    return (widg,
+        (\ (a, b, c, d, e) -> inj ((a,b,c,d),e)),
+        (do
+            mb <- ext
+            case mb of
+                Nothing        -> return Nothing
+                Just ((a,b,c,d),e) -> return (Just (a,b,c,d,e))))
+
+tupel6Editor :: (Editor alpha, Parameters)
+    -> (Editor beta, Parameters)
+    -> (Editor gamma, Parameters)
+    -> (Editor delta, Parameters)
+    -> (Editor epsilon, Parameters)
+    -> (Editor zeta, Parameters)
+    -> Editor (alpha,beta,gamma,delta,epsilon,zeta)
+tupel6Editor p1 p2 p3 p4 p5 p6 parameters notifier = do
+    (widg,inj,ext) <- pairEditor ((tupel5Editor p1 p2 p3 p4 p5), parameters) p6 parameters notifier
+    return (widg,
+        (\ (a, b, c, d, e, f) -> inj ((a,b,c,d,e),f)),
+        (do
+            mb <- ext
+            case mb of
+                Nothing        -> return Nothing
+                Just ((a,b,c,d,e),f) -> return (Just (a,b,c,d,e,f))))
+
+tupel7Editor :: (Editor alpha, Parameters)
+    -> (Editor beta, Parameters)
+    -> (Editor gamma, Parameters)
+    -> (Editor delta, Parameters)
+    -> (Editor epsilon, Parameters)
+    -> (Editor zeta, Parameters)
+    -> (Editor eta, Parameters)
+    -> Editor (alpha,beta,gamma,delta,epsilon,zeta,eta)
+tupel7Editor p1 p2 p3 p4 p5 p6 p7 parameters notifier = do
+    (widg,inj,ext) <- pairEditor ((tupel6Editor p1 p2 p3 p4 p5 p6), parameters) p7 parameters notifier
+    return (widg,
+        (\ (a, b, c, d, e, f, g) -> inj ((a,b,c,d,e,f),g)),
+        (do
+            mb <- ext
+            case mb of
+                Nothing        -> return Nothing
+                Just ((a,b,c,d,e,f),g) -> return (Just (a,b,c,d,e,f,g))))
+--}
+
+--
+-- | Like a pair editor, but with a moveable split
+--
+splitEditor :: (Editor alpha, Parameters) -> (Editor beta, Parameters) -> Editor (alpha,beta)
+splitEditor (fstEd,fstPara) (sndEd,sndPara) parameters notifier = do
+    coreRef <- newIORef Nothing
+    noti1   <- emptyNotifier
+    noti2   <- emptyNotifier
+    mapM_ (propagateEvent notifier [noti1,noti2]) allGUIEvents
+    fst@(fstFrame,inj1,ext1) <- fstEd fstPara noti1
+    snd@(sndFrame,inj2,ext2) <- sndEd sndPara noti2
+    mkEditor
+        (\widget (v1,v2) -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    paned <- case getParameter paraDirection parameters of
+                        Horizontal  -> do  h <- vPanedNew
+                                           return (castToPaned h)
+                        Vertical    -> do  v <- hPanedNew
+                                           return (castToPaned v)
+                    panedPack1 paned fstFrame True True
+                    panedPack2 paned sndFrame True True
+                    containerAdd widget paned
+                    inj1 v1
+                    inj2 v2
+                    writeIORef coreRef (Just (fst,snd))
+                Just ((_,inj1,_),(_,inj2,_)) -> do
+                    inj1 v1
+                    inj2 v2)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just ((_,_,ext1),(_,_,ext2)) -> do
+                    r1 <- ext1
+                    r2 <- ext2
+                    if isJust r1 && isJust r2
+                        then return (Just (fromJust r1,fromJust r2))
+                        else return Nothing)
+        parameters
+        notifier
+
+--
+-- | An editor with a subeditor which gets active, when a checkbox is selected
+-- or deselected (if the positive Argument is False)
+--
+maybeEditor :: Default beta => (Editor beta, Parameters) -> Bool -> String -> Editor (Maybe beta)
+maybeEditor (childEdit, childParams) positive boolLabel parameters notifier = do
+    coreRef <- newIORef Nothing
+    childRef  <- newIORef Nothing
+    notifierBool <- emptyNotifier
+    cNoti   <- emptyNotifier
+    mapM_ (propagateEvent notifier [notifierBool]) [Clicked,FocusIn]
+    mapM_ (propagateEvent notifier [cNoti]) allGUIEvents
+
+    mkEditor
+        (\widget mbVal -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    box <- case getParameter paraDirection parameters of
+                        Horizontal -> do
+                            b <- hBoxNew False 1
+                            return (castToBox b)
+                        Vertical -> do
+                            b <- vBoxNew False 1
+                            return (castToBox b)
+                    be@(boolFrame,inj1,ext1) <- boolEditor
+                        (paraName <<<- ParaName boolLabel $ emptyParams)
+                        notifierBool
+                    boxPackStart box boolFrame PackNatural 0
+                    containerAdd widget box
+                    registerEvent notifierBool Clicked (Left (onClickedHandler widget coreRef childRef cNoti))
+                    case mbVal of
+                        Nothing -> inj1 (not positive)
+                        Just val -> do
+                            (childWidget,inj2,ext2) <- getChildEditor childRef childEdit childParams cNoti
+                            boxPackEnd box childWidget PackGrow 0
+                            widgetShowAll childWidget
+                            inj1 positive
+                            inj2 val
+                    writeIORef coreRef (Just (be,box))
+                Just (be@(boolFrame,inj1,extt),box) -> do
+                    hasChild <- hasChildEditor childRef
+                    case mbVal of
+                        Nothing ->
+                            if hasChild
+                                then do
+                                    (childWidget,_,_) <- getChildEditor childRef childEdit childParams cNoti
+                                    inj1 (not positive)
+                                    widgetHideAll childWidget
+                                else inj1 (not positive)
+                        Just val ->
+                            if hasChild
+                                then do
+                                    inj1 positive
+                                    (childWidget,inj2,_) <- getChildEditor childRef childEdit childParams cNoti
+                                    widgetShowAll childWidget
+                                    inj2 val
+                                else do
+                                    inj1 positive
+                                    (childWidget,inj2,_) <- getChildEditor childRef childEdit childParams cNoti
+                                    boxPackEnd box childWidget PackGrow 0
+                                    widgetShowAll childWidget
+                                    inj2 val)
+        (do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> return Nothing
+                Just (be@(boolFrame,inj1,ext1),_) -> do
+                    bool <- ext1
+                    case bool of
+                        Nothing -> return Nothing
+                        Just bv | bv == positive -> do
+                            (_,_,ext2) <- getChildEditor childRef childEdit childParams cNoti
+                            value <- ext2
+                            case value of
+                                Nothing -> return Nothing
+                                Just value -> return (Just (Just value))
+                        otherwise -> return (Just Nothing))
+        parameters
+        notifier
+    where
+    onClickedHandler widget coreRef childRef cNoti event = do
+        core <- readIORef coreRef
+        case core of
+            Nothing  -> error "Impossible"
+            Just (be@(boolFrame,inj1,ext1),vBox) -> do
+                mbBool <- ext1
+                case mbBool of
+                    Just bool ->
+                        if bool /= positive
+                            then do
+                                hasChild <- hasChildEditor childRef
+                                when hasChild $ do
+                                    (childWidget,_,_) <- getChildEditor childRef childEdit childParams cNoti
+                                    widgetHideAll childWidget
+                            else do
+                                hasChild <- hasChildEditor childRef
+                                if hasChild
+                                    then do
+                                        (childWidget,_,_) <- getChildEditor childRef childEdit childParams cNoti
+                                        widgetShowAll childWidget
+                                    else do
+                                        (childWidget,inj2,_) <- getChildEditor childRef childEdit childParams cNoti
+                                        boxPackEnd vBox childWidget PackNatural 0
+                                        inj2 getDefault
+                                        widgetShowAll childWidget
+                    Nothing -> return ()
+                return (event {gtkReturn=True})
+    getChildEditor childRef childEditor childParams cNoti =  do
+        mb <- readIORef childRef
+        case mb of
+            Just editor -> return editor
+            Nothing -> do
+                let val = childEditor
+                editor@(_,_,_) <- childEditor childParams cNoti
+                writeIORef childRef (Just editor)
+                return editor
+    hasChildEditor childRef =  do
+        mb <- readIORef childRef
+        return (isJust mb)
+
+--
+-- | An editor with a subeditor which gets active, when a checkbox is selected
+-- or deselected (if the positive Argument is False)
+eitherOrEditor :: (Default alpha, Default beta) => (Editor alpha, Parameters) ->
+                        (Editor beta, Parameters) -> String -> Editor (Either alpha beta)
+eitherOrEditor (leftEditor,leftParams) (rightEditor,rightParams)
+            label2 parameters notifier = do
+    coreRef <- newIORef Nothing
+    noti1 <- emptyNotifier
+    noti2 <- emptyNotifier
+    noti3 <- emptyNotifier
+    mapM_ (propagateEvent notifier [noti1,noti2,noti3]) allGUIEvents
+    be@(boolFrame,inj1,ext1) <- boolEditor2  (getParameter paraName rightParams) leftParams noti1
+    le@(leftFrame,inj2,ext2) <- leftEditor (paraName <<<- ParaName "" $ leftParams) noti2
+    re@(rightFrame,inj3,ext3) <- rightEditor (paraName <<<- ParaName "" $ rightParams) noti3
+    mkEditor
+        (\widget v -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    registerEvent noti1 Clicked (Left (onClickedHandler widget coreRef))
+                    box <- case getParameter paraDirection parameters of
+                        Horizontal -> do
+                            b <- hBoxNew False 1
+                            return (castToBox b)
+                        Vertical -> do
+                            b <- vBoxNew False 1
+                            return (castToBox b)
+                    boxPackStart box boolFrame PackNatural 0
+                    containerAdd widget box
+                    case v of
+                        Left vl -> do
+                          boxPackStart box leftFrame PackNatural 0
+                          inj2 vl
+                          inj3 getDefault
+                          inj1 True
+                        Right vr  -> do
+                          boxPackStart box rightFrame PackNatural 0
+                          inj3 vr
+                          inj2 getDefault
+                          inj1 False
+                    writeIORef coreRef (Just (be,le,re,box))
+                Just ((_,inj1,_),(leftFrame,inj2,_),(rightFrame,inj3,_),box) ->
+                    case v of
+                            Left vl -> do
+                              containerRemove box rightFrame
+                              boxPackStart box leftFrame PackNatural 0
+                              inj2 vl
+                              inj3 getDefault
+                              inj1 True
+                            Right vr  -> do
+                              containerRemove box leftFrame
+                              boxPackStart box rightFrame PackNatural 0
+                              inj3 vr
+                              inj2 getDefault
+                              inj1 False)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just ((_,_,ext1),(_,_,ext2),(_,_,ext3),_) -> do
+                    mbbool <- ext1
+                    case mbbool of
+                        Nothing -> return Nothing
+                        Just True   ->  do
+                            value <- ext2
+                            case value of
+                                Nothing -> return Nothing
+                                Just value -> return (Just (Left value))
+                        Just False -> do
+                            value <- ext3
+                            case value of
+                                Nothing -> return Nothing
+                                Just value -> return (Just (Right value)))
+        (paraName <<<- ParaName "" $ parameters)
+        notifier
+    where
+    onClickedHandler widget coreRef event =  do
+        core <- readIORef coreRef
+        case core of
+            Nothing  -> error "Impossible"
+            Just (be@(_,_,ext1),(leftFrame,_,_),(rightFrame,_,_),box) -> do
+                mbBool <- ext1
+                case mbBool of
+                    Just bool ->
+                            if bool then do
+                              containerRemove box rightFrame
+                              boxPackStart box leftFrame PackNatural 0
+                              widgetShowAll box
+                            else do
+                              containerRemove box leftFrame
+                              boxPackStart box rightFrame PackNatural 0
+                              widgetShowAll box
+                    Nothing -> return ()
+                return event{gtkReturn=True}
+
+
+-- a trivial example: (ColumnDescr False [("",(\row -> [cellText := show row]))])
+-- and a nontrivial:
+--  [("Package",\(Dependency str _) -> [cellText := str])
+--  ,("Version",\(Dependency _ vers) -> [cellText := showVersionRange vers])])
+data ColumnDescr row = ColumnDescr Bool [(String,(row -> [AttrOp CellRendererText]))]
+
+--
+-- | An editor with a subeditor, of which a list of items can be selected
+multisetEditor :: (Show alpha, Default alpha, Eq alpha) => ColumnDescr alpha
+    -> (Editor alpha, Parameters)
+    -> Maybe ([alpha] -> [alpha]) -- ^ The 'mbSort' arg, a sort function if desired
+    -> Maybe (alpha -> alpha -> Bool) -- ^ The 'mbReplace' arg, a function which is a criteria for removing an
+                              --   old entry when adding a new value
+    -> Editor [alpha]
+multisetEditor (ColumnDescr showHeaders columnsDD) (singleEditor, sParams) mbSort mbReplace
+        parameters notifier = do
+    coreRef <- newIORef Nothing
+    cnoti   <- emptyNotifier
+    mapM_ (propagateEvent notifier [cnoti]) allGUIEvents
+    mkEditor
+        (\widget vs -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    (box,buttonBox) <- case getParameter paraDirection parameters of
+                        Horizontal -> do
+                            b  <- hBoxNew False 1
+                            bb <- vButtonBoxNew
+                            return (castToBox b,castToButtonBox bb)
+                        Vertical -> do
+                            b  <- vBoxNew False 1
+                            bb <- hButtonBoxNew
+                            return (castToBox b,castToButtonBox bb)
+                    (frameS,injS,extS) <- singleEditor sParams cnoti
+                    addButton   <- buttonNewWithLabel "Add"
+                    removeButton <- buttonNewWithLabel "Remove"
+                    containerAdd buttonBox addButton
+                    containerAdd buttonBox removeButton
+                    listStore   <-  listStoreNew ([]:: [alpha])
+                    treeView        <-  treeViewNewWithModel listStore
+                    let minSize =   getParameter paraMinSize parameters
+                    uncurry (widgetSetSizeRequest treeView) minSize
+                    sw          <-  scrolledWindowNew Nothing Nothing
+                    containerAdd sw treeView
+                    scrolledWindowSetPolicy sw PolicyAutomatic PolicyAutomatic
+                    sel         <-  treeViewGetSelection treeView
+                    treeSelectionSetMode sel SelectionSingle
+                    mapM_ (\(str,func) -> do
+                            col <- treeViewColumnNew
+                            treeViewColumnSetTitle  col str
+                            treeViewColumnSetResizable col True
+                            treeViewAppendColumn treeView col
+                            renderer <- cellRendererTextNew
+                            cellLayoutPackStart col renderer True
+                            cellLayoutSetAttributes col renderer listStore func
+                        ) columnsDD
+                    treeViewSetHeadersVisible treeView showHeaders
+                    sel  `onSelectionChanged` selectionHandler sel listStore injS
+                    boxPackStart box sw PackGrow 0
+                    boxPackStart box buttonBox PackNatural 0
+                    boxPackStart box frameS PackNatural 0
+                    activateEvent (castToWidget treeView) notifier Nothing FocusOut
+                    containerAdd widget box
+                    listStoreClear listStore
+                    mapM_ (listStoreAppend listStore)
+                        (case mbSort of
+                            Nothing -> vs
+                            Just sortF -> sortF vs)
+                    addButton `onClicked` do
+                        mbv <- extS
+                        case mbv of
+                            Just v -> do
+                                case mbReplace of
+                                    Nothing         -> return ()
+                                    Just replaceF   -> do
+                                         cont <- listStoreToList listStore
+                                         mapM_ (listStoreRemove listStore)
+                                            $ map fst
+                                                $ filter (\(_,e) -> replaceF v e)
+                                                    $ zip [0..] cont
+                                case mbSort of
+                                    Nothing    -> do
+                                        listStoreAppend listStore v
+                                        return ()
+                                    Just sortF -> do
+                                        cont <- listStoreToList listStore
+                                        listStoreClear listStore
+                                        mapM_ (listStoreAppend listStore) (sortF (v:cont))
+                                cont <- listStoreToList listStore
+                                case elemIndex v cont of
+                                    Just idx -> do
+                                        treeSelectionSelectPath sel [idx]
+                                        mbCol <- treeViewGetColumn treeView 0
+                                        case mbCol of
+                                            Nothing  -> return ()
+                                            Just col -> treeViewScrollToCell treeView [idx] col Nothing
+                                    Nothing -> return ()
+                            Nothing -> return ()
+                    removeButton `onClicked` do
+                        mbi <- treeSelectionGetSelected sel
+                        case mbi of
+                            Nothing -> return ()
+                            Just iter -> do
+                                [i] <- treeModelGetPath listStore iter
+                                listStoreRemove listStore i
+                    writeIORef coreRef (Just listStore)
+                    injS getDefault
+                Just listStore -> do
+                    listStoreClear listStore
+                    mapM_ (listStoreAppend listStore)
+                        (case mbSort of
+                            Nothing -> vs
+                            Just sortF -> sortF vs))
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just listStore -> do
+                    v <- listStoreToList listStore
+                    return (Just v))
+        (paraMinSize <<<- ParaMinSize (-1,-1) $ parameters)
+        notifier
+    where
+    selectionHandler :: TreeSelection -> ListStore a -> Injector a -> IO ()
+    selectionHandler sel listStore inj = do
+        ts <- treeSelectionGetSelected sel
+        case ts of
+            Nothing -> return ()
+            Just iter -> do
+                [i] <- treeModelGetPath listStore iter
+                v <- listStoreGetValue listStore i
+                inj v
+                return ()
+
+
+filesEditor :: Maybe FilePath -> FileChooserAction -> String -> Editor [FilePath]
+filesEditor fp act label p =
+    multisetEditor
+        (ColumnDescr False [("",(\row -> [cellText := row]))])
+        (fileEditor fp act label, emptyParams)
+        (Just sort)
+        (Just (==))
+        (paraShadow <<<- ParaShadow ShadowIn $
+            paraDirection  <<<- ParaDirection Vertical $ p)
+
+stringsEditor :: (String -> Bool) -> Editor [String]
+stringsEditor validation p =
+    multisetEditor
+        (ColumnDescr False [("",(\row -> [cellText := row]))])
+        (stringEditor validation, emptyParams)
+        (Just sort)
+        (Just (==))
+        (paraShadow <<<- ParaShadow ShadowIn $ p)
+
+dependencyEditor :: [PackageIdentifier] -> Editor Dependency
+dependencyEditor packages para noti = do
+    (wid,inj,ext) <- pairEditor
+        ((eitherOrEditor (comboSelectionEditor ((sort . nub) (map (display . pkgName) packages)) id
+            , paraName <<<- ParaName "Select" $ emptyParams)
+            (stringEditor (const True), paraName <<<- ParaName "Enter" $ emptyParams)
+            "Select from list?"), paraName <<<- ParaName "Name"$ emptyParams)
+        (versionRangeEditor,paraName <<<- ParaName "Version" $ emptyParams)
+        (paraDirection <<<- ParaDirection Vertical $ para)
+        noti
+    let pinj (Dependency pn@(PackageName s) v) = if elem s (map (display . pkgName) packages)
+                                                    then inj (Left s,v)
+                                                    else inj (Right s,v)
+    let pext = do
+        mbp <- ext
+        case mbp of
+            Nothing -> return Nothing
+            Just (Left "",v) -> return Nothing
+            Just (Left s,v) -> return (Just $ Dependency (PackageName s) v)
+            Just (Right "",v) -> return Nothing
+            Just (Right s,v) -> return (Just $ Dependency (PackageName s) v)
+    return (wid,pinj,pext)
+
+dependenciesEditor :: [PackageIdentifier] -> Editor [Dependency]
+dependenciesEditor packages p noti =
+    multisetEditor
+        (ColumnDescr True [("Package",\(Dependency (PackageName str) _) -> [cellText := str])
+                           ,("Version",\(Dependency _ vers) -> [cellText := display vers])])
+        (dependencyEditor packages,
+            paraOuterAlignment <<<- ParaInnerAlignment (0.0, 0.5, 1.0, 1.0)
+                $ paraInnerAlignment <<<- ParaOuterAlignment (0.0, 0.5, 1.0, 1.0)
+                   $ emptyParams)
+        (Just (sortBy (\ (Dependency p1 _) (Dependency p2 _) -> compare p1 p2)))
+        (Just (\ (Dependency p1 _) (Dependency p2 _) -> p1 == p2))
+        (paraShadow <<<- ParaShadow ShadowIn
+            $ paraOuterAlignment <<<- ParaInnerAlignment (0.0, 0.5, 1.0, 1.0)
+                $ paraInnerAlignment <<<- ParaOuterAlignment (0.0, 0.5, 1.0, 1.0)
+                    $ paraDirection  <<<-  ParaDirection Vertical
+                        $ paraPack <<<- ParaPack PackGrow
+                            $ p)
+        noti
+
+versionRangeEditor :: Editor VersionRange
+versionRangeEditor para noti = do
+    (wid,inj,ext) <-
+        maybeEditor
+            ((eitherOrEditor
+                (pairEditor
+                    (comboSelectionEditor v1 show, emptyParams)
+                    (versionEditor, paraName <<<- ParaName "Enter Version" $ emptyParams),
+                        (paraDirection <<<- ParaDirection Vertical
+                            $ paraName <<<- ParaName "Simple"
+                            $ paraOuterAlignment <<<- ParaOuterAlignment  (0.0, 0.0, 0.0, 0.0)
+                            $ paraOuterPadding <<<- ParaOuterPadding    (0, 0, 0, 0)
+                            $ paraInnerAlignment <<<- ParaInnerAlignment  (0.0, 0.0, 0.0, 0.0)
+                            $ paraInnerPadding <<<- ParaInnerPadding   (0, 0, 0, 0)
+                            $ emptyParams))
+                (tupel3Editor
+                    (comboSelectionEditor v2 show, emptyParams)
+                    (versionRangeEditor, paraShadow <<<- ParaShadow ShadowIn $ emptyParams)
+                    (versionRangeEditor, paraShadow <<<- ParaShadow ShadowIn $ emptyParams),
+                        paraName <<<- ParaName "Complex"
+                        $    paraDirection <<<- ParaDirection Vertical
+                        $ paraOuterAlignment <<<- ParaOuterAlignment  (0.0, 0.0, 0.0, 0.0)
+                        $ paraOuterPadding <<<- ParaOuterPadding    (0, 0, 0, 0)
+                        $ paraInnerAlignment <<<- ParaInnerAlignment  (0.0, 0.0, 0.0, 0.0)
+                        $ paraInnerPadding <<<- ParaInnerPadding   (0, 0, 0, 0)
+                        $ emptyParams) "Select version range"), emptyParams)
+            False "Any Version"
+            (paraDirection <<<- ParaDirection Vertical $ para)
+            noti
+    let vrinj AnyVersion                =   inj Nothing
+        vrinj (ThisVersion v)           =   inj (Just (Left (ThisVersionS,v)))
+        vrinj (LaterVersion v)          =   inj (Just (Left (LaterVersionS,v)))
+        vrinj (EarlierVersion v)        =   inj (Just (Left (EarlierVersionS,v)))
+        vrinj (UnionVersionRanges (ThisVersion v1) (LaterVersion v2)) | v1 == v2
+                                        =  inj (Just (Left (ThisOrLaterVersionS,v1)))
+        vrinj (UnionVersionRanges (LaterVersion v1) (ThisVersion v2)) | v1 == v2
+                                        =  inj (Just (Left (ThisOrLaterVersionS,v1)))
+        vrinj (UnionVersionRanges (ThisVersion v1) (EarlierVersion v2)) | v1 == v2
+                                        =  inj (Just (Left (ThisOrEarlierVersionS,v1)))
+        vrinj (UnionVersionRanges (EarlierVersion v1) (ThisVersion v2)) | v1 == v2
+                                        =  inj (Just (Left (ThisOrEarlierVersionS,v1)))
+        vrinj (UnionVersionRanges v1 v2)=  inj (Just (Right (UnionVersionRangesS,v1,v2)))
+        vrinj (IntersectVersionRanges v1 v2)
+                                        =    inj (Just (Right (IntersectVersionRangesS,v1,v2)))
+    let vrext = do  mvr <- ext
+                    case mvr of
+                        Nothing -> return (Just AnyVersion)
+                        Just Nothing -> return (Just AnyVersion)
+                        Just (Just (Left (ThisVersionS,v)))     -> return (Just (ThisVersion v))
+                        Just (Just (Left (LaterVersionS,v)))    -> return (Just (LaterVersion v))
+                        Just (Just (Left (EarlierVersionS,v)))   -> return (Just (EarlierVersion v))
+
+                        Just (Just (Left (ThisOrLaterVersionS,v)))   -> return (Just (orLaterVersion  v))
+                        Just (Just (Left (ThisOrEarlierVersionS,v)))   -> return (Just (orEarlierVersion  v))
+                        Just (Just (Right (UnionVersionRangesS,v1,v2)))
+                                                        -> return (Just (UnionVersionRanges v1 v2))
+                        Just (Just (Right (IntersectVersionRangesS,v1,v2)))
+                                                        -> return (Just (IntersectVersionRanges v1 v2))
+    return (wid,vrinj,vrext)
+        where
+            v1 = [ThisVersionS,LaterVersionS,ThisOrLaterVersionS,EarlierVersionS,ThisOrEarlierVersionS]
+            v2 = [UnionVersionRangesS,IntersectVersionRangesS]
+
+data Version1 = ThisVersionS | LaterVersionS | ThisOrLaterVersionS | EarlierVersionS | ThisOrEarlierVersionS
+    deriving (Eq)
+instance Show Version1 where
+    show ThisVersionS   =  "This Version"
+    show LaterVersionS  =  "Later Version"
+    show ThisOrLaterVersionS = "This or later Version"
+    show EarlierVersionS =  "Earlier Version"
+    show ThisOrEarlierVersionS = "This or earlier Version"
+
+data Version2 = UnionVersionRangesS | IntersectVersionRangesS
+    deriving (Eq)
+instance Show Version2 where
+    show UnionVersionRangesS =  "Union Version Ranges"
+    show IntersectVersionRangesS =  "Intersect Version Ranges"
+
+versionEditor :: Editor Version
+versionEditor para noti = do
+    (wid,inj,ext) <- stringEditor (\s -> not (null s)) para noti
+    let pinj v = inj (display v)
+    let pext = do
+        s <- ext
+        case s of
+            Nothing -> return Nothing
+            Just s -> return (simpleParse s)
+    return (wid, pinj, pext)
+
+instance Default Version1
+    where getDefault = ThisVersionS
+
+instance Default Version2
+    where getDefault = UnionVersionRangesS
+
+instance Default Version
+    where getDefault = forceJust (simpleParse "0") "PackageEditor>>default version"
+
+instance Default VersionRange
+    where getDefault = AnyVersion
+
+instance Default Dependency
+    where getDefault = Dependency getDefault getDefault
+
+instance Default PackageName
+    where getDefault = PackageName getDefault
+
+
+
+
+
+
diff --git a/src/Graphics/UI/Editor/DescriptionPP.hs b/src/Graphics/UI/Editor/DescriptionPP.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Editor/DescriptionPP.hs
@@ -0,0 +1,100 @@
+-----------------------------------------------------------------------------
+--
+-- Module      :  Graphics.UI.Editor.DescriptionPP
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Description of a editor with additional fileds for printing and parsing
+--
+-----------------------------------------------------------------------------------
+module Graphics.UI.Editor.DescriptionPP (
+    Applicator
+,   FieldDescriptionPP(..)
+,   mkFieldPP
+,   extractFieldDescription
+,   flattenFieldDescriptionPP
+,   flattenFieldDescriptionPPToS
+) where
+
+import Graphics.UI.Gtk
+import Control.Monad
+import qualified Text.PrettyPrint.HughesPJ as PP
+import qualified Text.ParserCombinators.Parsec as P
+
+import Text.PrinterParser hiding (fieldParser,parameters)
+import Graphics.UI.Editor.Parameters
+import Graphics.UI.Editor.MakeEditor
+--import IDE.Core.State
+import Graphics.UI.Editor.Basics (Applicator(..),Editor(..),Setter(..),Getter(..),Notifier(..),Extractor(..),Injector(..))
+
+data FieldDescriptionPP alpha gamma =  FDPP {
+        parameters      ::  Parameters
+    ,   fieldPrinter    ::  alpha -> PP.Doc
+    ,   fieldParser     ::  alpha -> P.CharParser () alpha
+    ,   fieldEditor     ::  alpha -> IO (Widget, Injector alpha , alpha -> Extractor alpha , Notifier)
+    ,   applicator      ::  alpha -> alpha -> gamma ()}
+    | VFDPP Parameters [FieldDescriptionPP alpha gamma]
+    | HFDPP Parameters [FieldDescriptionPP alpha gamma]
+    | NFDPP [(String,FieldDescriptionPP alpha gamma)]
+
+type MkFieldDescriptionPP alpha beta gamma =
+    Parameters      ->
+    (Printer beta)     ->
+    (Parser beta)      ->
+    (Getter alpha beta)    ->
+    (Setter alpha beta)    ->
+    (Editor beta)      ->
+    (Applicator beta gamma )  ->
+    FieldDescriptionPP alpha gamma
+
+mkFieldPP :: (Eq beta, Monad gamma) => MkFieldDescriptionPP alpha beta gamma
+mkFieldPP parameters printer parser getter setter editor applicator  =
+    let FD _ ed = mkField parameters getter setter editor
+    in FDPP parameters
+        (\ dat -> (PP.text (case getParameterPrim paraName parameters of
+                                    Nothing -> ""
+                                    Just str -> str) PP.<> PP.colon)
+                PP.$$ (PP.nest 15 (printer (getter dat)))
+                PP.$$ (PP.nest 5 (case getParameterPrim paraSynopsis parameters of
+                                    Nothing -> PP.empty
+                                    Just str -> PP.text $"--" ++ str)))
+        (\ dat -> P.try (do
+            symbol (case getParameterPrim paraName parameters of
+                                    Nothing -> ""
+                                    Just str -> str)
+            colon
+            val <- parser
+            return (setter val dat)))
+        ed
+        (\ newDat oldDat -> do --applicator
+            let newField = getter newDat
+            let oldField = getter oldDat
+            if newField == oldField
+                then return ()
+                else applicator newField)
+
+extractFieldDescription :: FieldDescriptionPP alpha gamma -> FieldDescription alpha
+extractFieldDescription (VFDPP paras descrs) =  VFD paras (map extractFieldDescription descrs)
+extractFieldDescription (HFDPP paras descrs) =  HFD paras (map extractFieldDescription descrs)
+extractFieldDescription (NFDPP descrsp)      =  NFD (map (\(s,d) ->
+                                                    (s, extractFieldDescription d)) descrsp)
+extractFieldDescription (FDPP parameters fieldPrinter fieldParser fieldEditor applicator) =
+    (FD parameters fieldEditor)
+
+flattenFieldDescriptionPP :: FieldDescriptionPP alpha gamma -> [FieldDescriptionPP alpha gamma]
+flattenFieldDescriptionPP (VFDPP paras descrs)  =   concatMap flattenFieldDescriptionPP descrs
+flattenFieldDescriptionPP (HFDPP paras descrs)  =   concatMap flattenFieldDescriptionPP descrs
+flattenFieldDescriptionPP (NFDPP descrsp)       =   concatMap (flattenFieldDescriptionPP . snd) descrsp
+flattenFieldDescriptionPP fdpp                  =   [fdpp]
+
+flattenFieldDescriptionPPToS :: FieldDescriptionPP alpha gamma -> [FieldDescriptionS alpha]
+flattenFieldDescriptionPPToS = map ppToS . flattenFieldDescriptionPP
+
+ppToS :: FieldDescriptionPP alpha gamma -> FieldDescriptionS alpha
+ppToS (FDPP para print pars _ _) = FDS para print pars
+ppToS _                          = error "DescriptionPP.ppToS Can't transform"
+
diff --git a/src/Graphics/UI/Editor/MakeEditor.hs b/src/Graphics/UI/Editor/MakeEditor.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Editor/MakeEditor.hs
@@ -0,0 +1,258 @@
+-----------------------------------------------------------------------------
+--group_Test
+-- Module      :  Graphics.UI.Editor.MakeEditor
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Module for making editors out of descriptions
+--
+-----------------------------------------------------------------------------------
+
+module Graphics.UI.Editor.MakeEditor (
+
+    buildEditor
+,   FieldDescription(..)
+,   mkField
+,   extractAndValidate
+,   extract
+,   mkEditor
+,   parameters
+
+,   flattenFieldDescription
+,   getRealWidget
+,   MkFieldDescription
+
+) where
+
+import Graphics.UI.Gtk
+import Control.Monad
+import Data.List(unzip4)
+
+import Control.Event
+import Graphics.UI.Editor.Parameters
+import Graphics.UI.Editor.Basics
+--import Graphics.UI.Frame.ViewFrame
+import Data.Maybe (isNothing)
+
+--
+-- | A constructor type for a field desciption
+--
+type MkFieldDescription alpha beta =
+    Parameters ->
+    (Getter alpha beta) ->
+    (Setter alpha beta) ->
+    (Editor beta) ->
+    FieldDescription alpha
+
+--
+-- | A type to describe a field of a record, which can be edited
+-- | alpha is the type of the individual field of the record
+data FieldDescription alpha =  FD Parameters (alpha -> IO (Widget, Injector alpha ,
+                                    alpha -> Extractor alpha , Notifier))
+    | VFD Parameters [FieldDescription alpha]
+    | HFD Parameters [FieldDescription alpha]
+    | NFD [(String,FieldDescription alpha)]
+
+parameters :: FieldDescription alpha -> Parameters
+parameters (FD p _) = p
+parameters (VFD p _) = p
+parameters (HFD p _) = p
+parameters (NFD _) = emptyParams
+
+--
+-- | Construct a new notebook
+--
+newNotebook :: IO Notebook
+newNotebook = do
+    nb <- notebookNew
+    notebookSetTabPos nb PosTop
+    notebookSetShowTabs nb True
+    notebookSetScrollable nb True
+    notebookSetPopup nb True
+    return nb
+
+buildEditor :: FieldDescription alpha -> alpha -> IO (Widget, Injector alpha , alpha -> Extractor alpha , Notifier)
+buildEditor (FD paras editorf) v  =   editorf v
+buildEditor (HFD paras descrs) v =   buildBoxEditor descrs Horizontal v
+buildEditor (VFD paras descrs) v =   buildBoxEditor descrs Vertical v
+buildEditor (NFD pairList)     v =   do
+    nb <- newNotebook
+    notebookSetShowTabs nb False
+    resList <- mapM (\d -> buildEditor d v) (map snd pairList)
+    let (widgets, setInjs, getExts, notifiers) = unzip4 resList
+    notifier <- emptyNotifier
+    mapM_ (\ (labelString, widget) -> do
+        sw <- scrolledWindowNew Nothing Nothing
+        scrolledWindowAddWithViewport sw widget
+        scrolledWindowSetPolicy sw PolicyAutomatic PolicyAutomatic
+        notebookAppendPage nb sw labelString)
+         (zip (map fst pairList) widgets)
+    listStore   <- listStoreNew (map fst pairList)
+    listView    <- treeViewNewWithModel listStore
+    widgetSetSizeRequest listView 100 (-1)
+    sel         <- treeViewGetSelection listView
+    treeSelectionSetMode sel SelectionSingle
+    renderer    <- cellRendererTextNew
+    col         <- treeViewColumnNew
+    treeViewAppendColumn listView col
+    cellLayoutPackStart col renderer True
+    cellLayoutSetAttributes col renderer listStore $ \row ->
+        [ cellText := row ]
+    treeViewSetHeadersVisible listView False
+    treeSelectionSelectPath sel [0]
+    notebookSetCurrentPage nb 0
+    sel `onSelectionChanged` (do
+        selections <- treeSelectionGetSelectedRows sel
+        case selections of
+            [[i]] -> notebookSetCurrentPage nb i
+            _ -> return ())
+
+    hb      <-  hBoxNew False 0
+    sw              <-  scrolledWindowNew Nothing Nothing
+    containerAdd sw listView
+    scrolledWindowSetPolicy sw PolicyNever PolicyAutomatic
+    boxPackStart hb sw PackNatural 0
+    boxPackEnd hb nb PackGrow 7
+    let newInj = (\v -> mapM_ (\ setInj -> setInj v) setInjs)
+    let newExt = (\v -> extract v getExts)
+    mapM_ (propagateEvent notifier notifiers) allGUIEvents
+    return (castToWidget hb, newInj, newExt, notifier)
+
+buildBoxEditor :: [FieldDescription alpha] -> Direction -> alpha
+    -> IO (Widget, Injector alpha , alpha -> Extractor alpha , Notifier)
+buildBoxEditor descrs dir v = do
+    resList <- mapM (\d -> buildEditor d v)  descrs
+    notifier <- emptyNotifier
+    let (widgets, setInjs, getExts, notifiers) = unzip4 resList
+    hb <- case dir of
+            Horizontal -> do
+                b <- hBoxNew False 0
+                return (castToBox b)
+            Vertical -> do
+                b <- vBoxNew False 0
+                return (castToBox b)
+    let newInj = (\v -> mapM_ (\ setInj -> setInj v) setInjs)
+    let fieldNames = map (\fd -> case getParameterPrim paraName (parameters fd) of
+                                    Just s -> s
+                                    Nothing -> "Unnamed") descrs
+    let packParas = map (\fd -> getParameter paraPack (parameters fd)) descrs
+    let newExt = (\v -> extractAndValidate v getExts fieldNames)
+    mapM_ (\ (w,p) -> boxPackStart hb w p 0) $ zip widgets packParas
+    mapM_ (propagateEvent notifier notifiers) allGUIEvents
+    return (castToWidget hb, newInj, newExt, notifier)
+
+
+flattenFieldDescription :: FieldDescription alpha -> [FieldDescription alpha]
+flattenFieldDescription (VFD paras descrs)  =   concatMap flattenFieldDescription descrs
+flattenFieldDescription (HFD paras descrs)  =   concatMap flattenFieldDescription descrs
+flattenFieldDescription (NFD descrp)        =   concatMap (flattenFieldDescription.snd) descrp
+flattenFieldDescription fd                  =   [fd]
+
+-- ------------------------------------------------------------
+-- * Implementation of editing
+-- ------------------------------------------------------------
+
+--
+-- | Function to construct a field description
+--
+mkField :: Eq beta => MkFieldDescription alpha beta
+mkField parameters getter setter editor =
+    FD parameters
+        (\ dat -> do
+            noti <- emptyNotifier
+            (widget,inj,ext) <- editor parameters noti
+            let pext = (\a -> do
+                            b <- ext
+                            case b of
+                                Just b -> return (Just (setter b a))
+                                Nothing -> return Nothing)
+            registerEvent noti FocusOut (Left (\e ->  do
+                let name = eventPaneName e
+                e2 <- ext
+                when (isNothing e2) $ do
+                    md <- messageDialogNew Nothing [] MessageWarning ButtonsClose
+                        $ "The field " ++ name ++ " has an invalid value "
+                    dialogRun md
+                    widgetDestroy md
+                return (e{gtkReturn=False})))
+            inj (getter dat)
+            return (widget,
+                    (\a -> inj (getter a)),
+                    pext,
+                    noti))
+
+-- | Function to construct an editor
+--
+mkEditor :: (Container -> Injector alpha) -> Extractor alpha -> Editor alpha
+mkEditor injectorC extractor parameters notifier = do
+    let (xalign, yalign, xscale, yscale) = getParameter paraOuterAlignment parameters
+    outerAlig <- alignmentNew xalign yalign xscale yscale
+    let (paddingTop, paddingBottom, paddingLeft, paddingRight) = getParameter paraOuterPadding parameters
+    alignmentSetPadding outerAlig paddingTop paddingBottom paddingLeft paddingRight
+    frame   <-  frameNew
+    frameSetShadowType frame (getParameter paraShadow parameters)
+    case getParameter paraName parameters of
+        "" -> return ()
+        str -> if getParameter paraShowLabel parameters
+                then frameSetLabel frame str
+                else return ()
+
+    containerAdd outerAlig frame
+    let (xalign, yalign, xscale, yscale) =  getParameter paraInnerAlignment parameters
+    innerAlig <- alignmentNew xalign yalign xscale yscale
+    let (paddingTop, paddingBottom, paddingLeft, paddingRight) = getParameter paraInnerPadding parameters
+    alignmentSetPadding innerAlig paddingTop paddingBottom paddingLeft paddingRight
+    containerAdd frame innerAlig
+    let (x,y) = getParameter paraMinSize parameters
+    widgetSetSizeRequest outerAlig x y
+    let name  =  getParameter paraName parameters
+    widgetSetName outerAlig name
+    let build = injectorC (castToContainer innerAlig)
+    return (castToWidget outerAlig, build, extractor)
+
+-- | Convenience method to validate and extract fields
+--
+extractAndValidate :: alpha -> [alpha -> Extractor alpha] -> [String] -> IO (Maybe alpha)
+extractAndValidate val getExts fieldNames = do
+    (newVal,errors) <- foldM (\ (val,errs) (ext,fn) -> do
+        extVal <- ext val
+        case extVal of
+            Just nval -> return (nval,errs)
+            Nothing -> return (val, (' ' : fn) : errs))
+                (val,[]) (zip getExts fieldNames)
+    if null errors
+        then return (Just newVal)
+        else do
+            md <- messageDialogNew Nothing [] MessageWarning ButtonsClose
+                     $ "The following fields have invalid values." ++ concat (reverse errors)
+            dialogRun md
+            widgetDestroy md
+            return Nothing
+
+extract :: alpha -> [alpha -> Extractor alpha] -> IO (Maybe alpha)
+extract val  =
+    foldM (\ mbVal ext ->
+        case mbVal of
+            Nothing -> return Nothing
+            Just val -> ext val)
+            (Just val)
+
+-- | get through outerAlignment, frame, innerAlignment
+getRealWidget :: Widget -> IO (Maybe Widget)
+getRealWidget w = do
+    mbF <- binGetChild (castToBin w)
+    case mbF of
+        Nothing -> return Nothing
+        Just f -> do
+            mbIA <- binGetChild (castToBin f)
+            case mbIA of
+                Nothing -> return Nothing
+                Just iA -> binGetChild (castToBin iA)
+
+
+
+
diff --git a/src/Graphics/UI/Editor/Parameters.hs b/src/Graphics/UI/Editor/Parameters.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Editor/Parameters.hs
@@ -0,0 +1,184 @@
+-----------------------------------------------------------------------------
+--
+-- Module      :  Graphics.UI.Editor.Parameters
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Module for parameters for editors
+--
+-----------------------------------------------------------------------------------
+
+module Graphics.UI.Editor.Parameters (
+    Parameters
+,   Parameter(..)
+,   paraName
+,   paraSynopsis
+,   paraDirection
+,   paraShowLabel
+,   paraShadow
+,   paraOuterAlignment
+,   paraInnerAlignment
+,   paraOuterPadding
+,   paraInnerPadding
+,   paraMinSize
+,   paraHorizontal
+,   paraStockId
+,   paraMultiSel
+,   paraPack
+
+,   getParameter
+,   getParameterPrim
+,   (<<<-)
+,   emptyParams
+,   Direction(..)
+,   HorizontalAlign(..)
+) where
+
+import Graphics.UI.Gtk
+import Data.Maybe
+import qualified Data.List as List
+
+
+--
+-- | The direction of a split
+--
+data Direction      =   Horizontal | Vertical
+    deriving (Eq,Show)
+
+data HorizontalAlign =   StartHorizontal | StopHorizontal | Keep
+    deriving (Eq,Show)
+--
+-- | A type for parameters for editors
+--
+type Parameters     =   [Parameter]
+
+data Parameter      =   ParaName String
+                    |   ParaSynopsis String
+                    |   ParaDirection Direction
+                    |   ParaShadow ShadowType
+                    |   ParaShowLabel Bool
+                    |   ParaOuterAlignment  (Float,Float,Float,Float)
+                                               -- | xalign yalign xscale yscale
+                    |   ParaOuterPadding    (Int,Int,Int,Int)
+                                                --  | paddingTop paddingBottom paddingLeft paddingRight
+                    |   ParaInnerAlignment  (Float,Float,Float,Float)
+                                                -- | xalign yalign xscale yscale
+                    |   ParaInnerPadding   (Int,Int,Int,Int)
+                                                --  | paddingTop paddingBottom paddingLeft paddingRight
+                    |   ParaMinSize         (Int, Int)
+                    |   ParaHorizontal      HorizontalAlign
+                    |   ParaStockId String
+                    |   ParaMultiSel Bool
+                    |   ParaPack Packing
+    deriving (Eq,Show)
+
+
+{--        #if MIN_VERSION_gtk(0,9,13)
+            -- now defined in gtk
+        #else
+        instance Show ShadowType
+            where show _    =   "Any Shadow"
+        #endif
+--}
+
+emptyParams         ::   [Parameter]
+emptyParams         =   []
+
+paraName                        ::   (Parameter -> (Maybe String))
+paraName (ParaName str)         =   Just str
+paraName _                      =   Nothing
+
+paraSynopsis                    ::   (Parameter -> (Maybe String))
+paraSynopsis (ParaSynopsis str) =   Just str
+paraSynopsis _                  =   Nothing
+
+paraShowLabel                    ::   (Parameter -> (Maybe Bool))
+paraShowLabel (ParaShowLabel b)  =   Just b
+paraShowLabel _                  =   Nothing
+
+paraDirection                   ::   (Parameter -> (Maybe Direction))
+paraDirection (ParaDirection d) =   Just d
+paraDirection _                 =   Nothing
+
+paraShadow                      ::   (Parameter -> (Maybe ShadowType))
+paraShadow (ParaShadow d)       =   Just d
+paraShadow _                    =   Nothing
+
+paraOuterAlignment              ::   (Parameter -> (Maybe (Float,Float,Float,Float)))
+paraOuterAlignment (ParaOuterAlignment d) = Just d
+paraOuterAlignment _            =   Nothing
+
+paraInnerAlignment              ::   (Parameter -> (Maybe (Float,Float,Float,Float)))
+paraInnerAlignment (ParaInnerAlignment d) = Just d
+paraInnerAlignment _            =   Nothing
+
+paraOuterPadding                ::   (Parameter -> (Maybe (Int,Int,Int,Int)))
+paraOuterPadding (ParaOuterPadding d) = Just d
+paraOuterPadding _              =   Nothing
+
+paraInnerPadding                ::   (Parameter -> (Maybe (Int,Int,Int,Int)))
+paraInnerPadding (ParaInnerPadding d) = Just d
+paraInnerPadding _              =   Nothing
+
+paraMinSize                     ::   (Parameter -> (Maybe (Int, Int)))
+paraMinSize (ParaMinSize d)     =   Just d
+paraMinSize _                   =   Nothing
+
+paraHorizontal                  ::   (Parameter -> (Maybe (HorizontalAlign)))
+paraHorizontal (ParaHorizontal d) =   Just d
+paraHorizontal _                =   Nothing
+
+paraStockId                     ::   (Parameter -> (Maybe String))
+paraStockId (ParaStockId str)   =   Just str
+paraStockId _                   =   Nothing
+
+paraMultiSel                    ::   (Parameter -> (Maybe Bool))
+paraMultiSel (ParaMultiSel b)   =   Just b
+paraMultiSel _                  =   Nothing
+
+paraPack                        ::   (Parameter -> (Maybe Packing))
+paraPack (ParaPack b)           =   Just b
+paraPack _                      =   Nothing
+
+--
+-- | Convenience method to get a parameter, or if not set the default parameter
+--
+getParameter :: (Parameter -> (Maybe beta)) -> Parameters -> beta
+getParameter selector parameter =
+    case getParameterPrim selector parameter of
+        Just ele       -> ele
+        _              -> case getParameterPrim selector defaultParameters of
+                            Just ele       -> ele
+                            _              -> error "default parameter not defined"
+
+getParameterPrim :: (Parameter -> (Maybe beta)) -> Parameters -> Maybe beta
+getParameterPrim selector parameter =
+    case filter isJust $ map selector parameter of
+        (Just ele) : _ -> Just ele
+        _              -> Nothing
+
+(<<<-) :: (Parameter -> (Maybe beta)) -> Parameter -> Parameters -> Parameters
+(<<<-) selector para  params = para : filter (isNothing . selector) params
+
+defaultParameters :: Parameters
+defaultParameters =
+    [   ParaName ""
+    ,   ParaStockId ""
+    ,   ParaSynopsis ""
+    ,   ParaDirection Horizontal
+    ,   ParaShadow ShadowNone
+    ,   ParaOuterAlignment  (0.4, 0.5, 1.0, 0.7)
+    ,   ParaOuterPadding    (5, 5, 5, 5)
+    ,   ParaInnerAlignment  (0.4, 0.5, 1.0, 0.7)
+    ,   ParaInnerPadding    (5, 5, 5, 5)
+    ,   ParaMinSize         (-1,-1)
+    ,   ParaHorizontal      Keep
+    ,   ParaMultiSel True
+    ,   ParaPack PackNatural
+    ,   ParaShowLabel True
+    ]
+
diff --git a/src/Graphics/UI/Editor/Simple.hs b/src/Graphics/UI/Editor/Simple.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Editor/Simple.hs
@@ -0,0 +1,783 @@
+{-# OPTIONS_GHC -XScopedTypeVariables #-}
+-----------------------------------------------------------------------------
+--
+-- Module      :  Graphics.UI.Editor.Simple
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Module for making simple editors
+--
+-----------------------------------------------------------------------------------
+
+module Graphics.UI.Editor.Simple (
+    noEditor
+,   boolEditor
+,   boolEditor2
+,   enumEditor
+,   clickEditor
+,   stringEditor
+,   multilineStringEditor
+,   intEditor
+,   genericEditor
+,   fontEditor
+,   colorEditor
+,   comboSelectionEditor
+,   staticListEditor
+,   staticListMultiEditor
+,   multiselectionEditor
+,   fileEditor
+,   otherEditor
+,   imageEditor
+
+,   okCancelFields
+) where
+
+import Graphics.UI.Gtk
+import qualified Graphics.UI.Gtk as Gtk
+import Control.Monad
+import Data.IORef
+import Data.List
+import Data.Maybe
+import System.FilePath.Posix
+
+import Graphics.UI.Editor.Parameters
+import Graphics.UI.Editor.Basics
+import Graphics.UI.Editor.MakeEditor
+import Control.Event
+import Graphics.UI.Gtk.Gdk.Events (Event(..))
+import MyMissing (allOf)
+
+-- ------------------------------------------------------------
+-- * Simple Editors
+-- ------------------------------------------------------------
+
+instance ContainerClass Widget
+instance BinClass Widget
+instance ButtonClass Widget
+
+--
+-- | An invisible editor without any effect
+--
+noEditor :: alpha -> Editor alpha
+noEditor proto parameters notifier =
+    mkEditor
+        (\ widget _ -> return ())
+        (return (Just proto))
+        parameters
+        notifier
+
+--
+-- | Editor for a boolean value in the form of a check button
+--
+boolEditor :: Editor Bool
+boolEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget bool -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    button <- checkButtonNewWithLabel (getParameter paraName parameters)
+                    widgetSetName button (getParameter paraName parameters)
+                    containerAdd widget button
+                    toggleButtonSetActive button bool
+                    mapM_ (activateEvent (castToWidget button) notifier Nothing)
+                        [Clicked,FocusOut,FocusIn]
+                    writeIORef coreRef (Just button)
+                Just button -> toggleButtonSetActive button bool)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just button -> do
+                    r <- toggleButtonGetActive button
+                    return (Just r))
+        (paraName <<<- ParaName "" $ parameters)
+        notifier
+
+--
+-- | Editor for a boolean value in the form of two radio buttons
+----
+boolEditor2 :: String -> Editor Bool
+boolEditor2 label2 parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget bool -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    box <- vBoxNew True 2
+                    radio1 <- radioButtonNewWithLabel (getParameter paraName parameters)
+                    radio2 <- radioButtonNewWithLabelFromWidget radio1 label2
+                    boxPackStart box radio1 PackGrow 2
+                    boxPackStart box radio2 PackGrow 2
+                    widgetSetName radio1 $ getParameter paraName parameters ++ ".1"
+                    widgetSetName radio2 $ getParameter paraName parameters ++ ".2"
+                    containerAdd widget box
+                    if bool
+                        then toggleButtonSetActive radio1 True
+                        else toggleButtonSetActive radio2 True
+                    mapM_ (activateEvent (castToWidget radio1) notifier Nothing)
+                                [Clicked,FocusOut,FocusIn]
+                    mapM_ (activateEvent (castToWidget radio2) notifier Nothing)
+                                [Clicked,FocusOut,FocusIn]
+                    writeIORef coreRef (Just (radio1,radio2))
+                Just (radio1,radio2) ->
+                    if bool
+                        then toggleButtonSetActive radio1 True
+                        else toggleButtonSetActive radio2 True)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just (radio1,radio2) -> do
+                    r <- toggleButtonGetActive radio1
+                    return (Just r))
+        (paraName <<<- ParaName "" $ parameters)
+        notifier
+
+--
+-- | Editor for an enum value in the form of n radio buttons
+----
+enumEditor :: forall alpha . (Show alpha, Enum alpha, Bounded alpha)  => [String] -> Editor alpha
+enumEditor labels parameters notifier = do
+    coreRef <- newIORef Nothing
+    let vals :: [alpha] =  allOf
+    mkEditor
+        (\widget enumValue -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    box <- vBoxNew True 2
+                    let label0 = if length labels > 0 then labels !! 0 else show (vals !! 0)
+                    button0 <- radioButtonNewWithLabel label0
+                    buttons <- mapM (\ v -> do
+                        let n = fromEnum v
+                        let label = if length labels > n then labels !! n else show v
+                        radio <- if n == 0
+                                    then return button0
+                                    else radioButtonNewWithLabelFromWidget button0 label
+                        boxPackStart box radio PackGrow 2
+                        widgetSetName radio (label ++ show n)
+                        return radio) vals
+                    containerAdd widget box
+                    mapM_
+                        (\e ->
+                            (mapM_
+                                (\b -> activateEvent (castToWidget b) notifier Nothing e)
+                             buttons))
+                        [Clicked,FocusOut,FocusIn]
+                    mapM_ (\(b,n) -> toggleButtonSetActive b (n == fromEnum enumValue))
+                                (zip buttons [0..length buttons - 1])
+                    writeIORef coreRef (Just buttons)
+                Just buttons -> do
+                    mapM_ (\(b,n) -> toggleButtonSetActive b (n == fromEnum enumValue))
+                                (zip buttons [0..length buttons - 1]))
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just buttons -> do
+                    boolArray <- mapM toggleButtonGetActive buttons
+                    let mbInd =  findIndex (== True) boolArray
+                    let res = case mbInd of
+                                Nothing -> Nothing
+                                Just i -> Just (vals !! i)
+                    return res)
+        (paraName <<<- ParaName "" $ parameters)
+        notifier
+
+-- | An Editor for nothing (which may report a click) in the form of a button
+--
+clickEditor :: Editor ()
+clickEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget bool -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    button <- case getParameter paraStockId parameters of
+                        "" ->   buttonNewWithLabel (getParameter paraName parameters)
+                        st ->   buttonNewFromStock st
+                    widgetSetName button (getParameter paraName parameters)
+                    containerAdd widget button
+                    activateEvent (castToWidget button) notifier Nothing Clicked
+                    writeIORef coreRef (Just button)
+                Just button -> return ())
+        (return (Just ()))
+        (paraName <<<- ParaName "" $ parameters)
+        notifier
+
+-- | An Editor to display an image
+--
+imageEditor :: Editor StockId
+imageEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget stockId -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    image <- imageNewFromStock stockId IconSizeLargeToolbar
+                    widgetSetName image (getParameter paraName parameters)
+                    containerAdd widget image
+                    writeIORef coreRef (Just (image,stockId))
+                Just (image,stockId2) -> imageSetFromStock image stockId IconSizeLargeToolbar)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just (_,stockId3) -> return (Just stockId3))
+        parameters
+        notifier
+
+--
+-- | Editor for a string in the form of a text entry
+--
+stringEditor :: (String -> Bool) -> Editor String
+stringEditor validation parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget string -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    entry   <-  entryNew
+                    widgetSetName entry (getParameter paraName parameters)
+                    mapM_ (activateEvent (castToWidget entry) notifier Nothing)
+                                [FocusOut,FocusIn,AfterKeyRelease]
+                    containerAdd widget entry
+                    entrySetText entry string
+                    writeIORef coreRef (Just entry)
+                Just entry -> entrySetText entry string)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just entry -> do
+                    r <- entryGetText entry
+                    if validation r
+                        then return (Just r)
+                        else return Nothing)
+        parameters
+        notifier
+
+--
+-- | Editor for a multiline string in the form of a multiline text entry
+--
+multilineStringEditor :: Editor String
+multilineStringEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget string -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    aTextView       <-  textViewNew
+                    widgetSetName aTextView (getParameter paraName parameters)
+                    aScrolledWindow <-  scrolledWindowNew Nothing Nothing
+                    scrolledWindowSetPolicy aScrolledWindow PolicyAutomatic PolicyAutomatic
+                    containerAdd aScrolledWindow aTextView
+                    containerAdd widget aScrolledWindow
+                    mapM_ (activateEvent (castToWidget aTextView) notifier Nothing)
+                        [ButtonRelease,FocusOut,FocusIn]
+                    buffer          <-  textViewGetBuffer aTextView
+                    textBufferSetText buffer string
+                    writeIORef coreRef (Just (aScrolledWindow,aTextView))
+                Just (aScrolledWindow,aTextView) -> do
+                    buffer          <-  textViewGetBuffer aTextView
+                    textBufferSetText buffer string)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just (aScrolledWindow, aTextView) -> do
+                    buffer          <-  textViewGetBuffer aTextView
+                    start           <-  textBufferGetStartIter buffer
+                    end             <-  textBufferGetEndIter buffer
+                    r               <-  textBufferGetText buffer start end False
+                    return (Just r))
+        parameters
+        notifier
+
+--
+-- | Editor for an integer in the form of a spin entry
+--
+intEditor :: (Double,Double,Double) -> Editor Int
+intEditor (min, max, step) parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget v -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    spin <- spinButtonNewWithRange min max step
+                    widgetSetName spin (getParameter paraName parameters)
+                    mapM_ (activateEvent (castToWidget spin) notifier Nothing)
+                                [FocusOut,FocusIn]
+                    containerAdd widget spin
+                    spinButtonSetValue spin (fromIntegral v)
+                    writeIORef coreRef (Just spin)
+                Just spin -> spinButtonSetValue spin (fromIntegral v))
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just spin -> do
+                    newNum <- spinButtonGetValue spin
+                    return (Just (truncate newNum)))
+        parameters
+        notifier
+
+--
+-- | Editor for for any value which is an instance of Read and Show in the form of a
+-- | text entry
+genericEditor :: (Show beta, Read beta) => Editor beta
+genericEditor parameters notifier = do
+    (wid,inj,ext) <- stringEditor (const True) parameters notifier
+    let ginj = inj . show
+    let gext = do
+        s <- ext
+        case s of
+            Nothing -> return Nothing
+            Just s -> catch (liftM Just (readIO s))
+                            (\e -> do
+                                putStrLn ("Generic editor no parse for " ++ s ++ " " ++ show e)
+                                return Nothing)
+    return (wid,ginj,gext)
+
+--
+-- | Editor for no value, it only emtis a clicked event and has the form of a check button
+--
+buttonEditor :: Editor ()
+buttonEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget _ -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    button <- buttonNewWithLabel (getParameter paraName parameters)
+                    widgetSetName button (getParameter paraName parameters)
+                    containerAdd widget button
+                    mapM_ (activateEvent (castToWidget button) notifier Nothing)
+                                [Clicked,FocusIn]
+                    writeIORef coreRef (Just button)
+                Just button -> return ())
+        (return (Just ()))
+        parameters
+        notifier
+
+--
+-- | Editor for the selection of some element from a static list of elements in the
+-- | form of a combo box
+
+comboSelectionEditor :: Eq beta => [beta] -> (beta -> String) -> Editor beta
+comboSelectionEditor list showF parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget obj -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    combo <- comboBoxNewText
+                    mapM_ (\o -> comboBoxAppendText combo (showF o)) list
+                    widgetSetName combo (getParameter paraName parameters)
+                    mapM_ (activateEvent (castToWidget combo) notifier Nothing)
+                            [FocusOut,FocusIn]
+                    comboBoxSetActive combo 1
+                    containerAdd widget combo
+                    let ind = elemIndex obj list
+                    case ind of
+                        Just i -> comboBoxSetActive combo i
+                        Nothing -> return ()
+                    writeIORef coreRef (Just combo)
+                Just combo -> do
+                    let ind = elemIndex obj list
+                    case ind of
+                        Just i -> comboBoxSetActive combo i
+                        Nothing -> return ())
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just combo -> do
+                    ind <- comboBoxGetActive combo
+                    case ind of
+                        (-1)   -> return Nothing
+                        otherwise  -> return (Just (list !! ind)))
+        parameters
+        notifier
+
+--
+-- | Editor for the selection of some elements from a list of elements in the
+-- | form of a list box
+multiselectionEditor :: (Show beta, Eq beta) => Editor [beta]
+multiselectionEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget objs -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    listStore   <- listStoreNew ([]:: [alpha])
+                    listView    <- treeViewNewWithModel listStore
+                    widgetSetName listView (getParameter paraName parameters)
+                    mapM_ (activateEvent (castToWidget listView) notifier Nothing)
+                            [FocusOut,FocusIn]
+                    sel         <- treeViewGetSelection listView
+                    treeSelectionSetMode sel SelectionMultiple
+                    renderer    <- cellRendererTextNew
+                    col         <- treeViewColumnNew
+                    treeViewAppendColumn listView col
+                    cellLayoutPackStart col renderer True
+                    cellLayoutSetAttributes col renderer listStore
+                        $ \row -> [ cellText := show row ]
+                    treeViewSetHeadersVisible listView False
+                    listStoreClear listStore
+                    mapM_ (listStoreAppend listStore) objs
+                    containerAdd widget listView
+                    treeSelectionUnselectAll sel
+                    --let inds = catMaybes $map (\obj -> elemIndex obj list) objs
+                    --mapM_ (\i -> treeSelectionSelectPath sel [i]) inds
+                    writeIORef coreRef (Just (listView,listStore))
+                Just (listView,listStore) -> do
+                    listStoreClear listStore
+                    mapM_ (listStoreAppend listStore) objs)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just (listView,listStore) -> do
+                    sel         <- treeViewGetSelection listView
+                    treePath    <- treeSelectionGetSelectedRows sel
+                    values      <- mapM (\[i] -> listStoreGetValue listStore i) treePath
+                    return (Just values))
+        parameters
+        notifier
+
+--
+-- | Editor for the selection of some elements from a static list of elements in the
+-- | form of a list box with toggle elements
+
+staticListMultiEditor :: (Eq beta) => [beta] -> (beta -> String) -> Editor [beta]
+staticListMultiEditor list showF parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget objs -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    listStore <- listStoreNew ([]:: [(Bool,beta)])
+                    listView <- treeViewNewWithModel listStore
+                    widgetSetName listView (getParameter paraName parameters)
+                    mapM_ (activateEvent (castToWidget listView) notifier Nothing)
+                            [FocusOut,FocusIn]
+                    sel <- treeViewGetSelection listView
+                    treeSelectionSetMode sel SelectionSingle
+                    rendererToggle <- cellRendererToggleNew
+                    set rendererToggle [cellToggleActivatable := True]
+                    rendererText <- cellRendererTextNew
+                    col1 <- treeViewColumnNew
+                    treeViewAppendColumn listView col1
+                    cellLayoutPackStart col1 rendererToggle True
+                    cellLayoutSetAttributes col1 rendererToggle listStore
+                        $ \row -> [ cellToggleActive := fst row]
+                    col2 <- treeViewColumnNew
+                    treeViewAppendColumn listView col2
+                    cellLayoutPackStart col2 rendererText True
+                    cellLayoutSetAttributes col2 rendererText listStore
+                        $ \row -> [ cellText := showF (snd row)]
+                    treeViewSetHeadersVisible listView False
+                    listStoreClear listStore
+                    mapM_ (listStoreAppend listStore) $ map (\e -> (elem e objs,e)) list
+                    let minSize =   getParameter paraMinSize parameters
+                    uncurry (widgetSetSizeRequest listView) minSize
+                    sw          <-  scrolledWindowNew Nothing Nothing
+                    containerAdd sw listView
+                    scrolledWindowSetPolicy sw PolicyAutomatic PolicyAutomatic
+                    containerAdd widget sw
+                      -- update the model when the toggle buttons are activated
+                    on rendererToggle cellToggled $ \pathStr -> do
+                        let (i:_) = stringToTreePath pathStr
+                        val <- listStoreGetValue listStore i
+                        listStoreSetValue listStore i (not (fst val),snd val)
+                    listView `onKeyPress` (\event -> do
+                        let Key { eventKeyName = name, eventModifier = modifier, eventKeyChar = char } = event
+                        case (name, modifier, char) of
+                            ("Return", _, _) -> do
+                                sel <- treeViewGetSelection listView
+                                rows <- treeSelectionGetSelectedRows sel
+                                mapM_ (\ (i:_) -> do
+                                    val <- listStoreGetValue listStore i
+                                    listStoreSetValue listStore i (not (fst val),snd val)) rows
+                                return True
+                            _ -> return False)
+                    writeIORef coreRef (Just (listView,listStore))
+                Just (listView,listStore) -> do
+                    let model = map (\e -> (elem e objs,e)) list
+                    listStoreClear listStore
+                    mapM_ (listStoreAppend listStore) $ map (\e -> (elem e objs,e)) list)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just (listView,listStore) -> do
+                    model <- listStoreToList listStore
+                    return (Just (map snd $ filter (\e -> fst e) model)))
+        parameters
+        notifier
+
+--
+-- | Editor for the selection of some elements from a static list of elements in the
+-- | form of a list box
+
+staticListEditor :: (Eq beta) => [beta] -> (beta -> String) -> Editor beta
+staticListEditor list showF parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget obj -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    listStore <- listStoreNew ([]:: [alpha])
+                    listView <- treeViewNewWithModel listStore
+                    widgetSetName listView (getParameter paraName parameters)
+                    mapM_ (activateEvent (castToWidget listView) notifier Nothing)
+                            [FocusOut,FocusIn]
+                    sel <- treeViewGetSelection listView
+                    treeSelectionSetMode sel
+                        (case getParameter paraMultiSel parameters of
+                            True  -> SelectionMultiple
+                            False -> SelectionSingle)
+                    renderer <- cellRendererTextNew
+                    col <- treeViewColumnNew
+                    treeViewAppendColumn listView col
+                    cellLayoutPackStart col renderer True
+                    cellLayoutSetAttributes col renderer listStore
+                        $ \row -> [ cellText := showF row ]
+                    treeViewSetHeadersVisible listView False
+                    listStoreClear listStore
+                    mapM_ (listStoreAppend listStore) list
+                    let minSize =   getParameter paraMinSize parameters
+                    uncurry (widgetSetSizeRequest listView) minSize
+                    sw          <-  scrolledWindowNew Nothing Nothing
+                    containerAdd sw listView
+                    scrolledWindowSetPolicy sw PolicyAutomatic PolicyAutomatic
+                    containerAdd widget sw
+                    treeSelectionUnselectAll sel
+                    let mbInd = elemIndex obj list
+                    case mbInd of
+                        Nothing -> return ()
+                        Just ind -> treeSelectionSelectPath sel [ind]
+                    writeIORef coreRef (Just listView)
+                Just listView -> do
+                    sel <- treeViewGetSelection listView
+                    treeSelectionUnselectAll sel
+                    let mbInd = elemIndex obj list
+                    case mbInd of
+                        Nothing -> return ()
+                        Just ind -> treeSelectionSelectPath sel [ind])
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just listView -> do
+                    sel <- treeViewGetSelection listView
+                    treePaths <- treeSelectionGetSelectedRows sel
+                    case treePaths of
+                        [[i]] -> return (Just (list !! i))
+                        _ -> return Nothing)
+        parameters
+        notifier
+
+
+--
+-- | Editor for the selection of a file path in the form of a text entry and a button,
+-- | which opens a gtk file chooser
+fileEditor :: Maybe FilePath -> FileChooserAction -> String -> Editor FilePath
+fileEditor mbFilePath action buttonName parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget filePath -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    button <- buttonNewWithLabel buttonName
+                    widgetSetName button $ getParameter paraName parameters ++ "-button"
+                    mapM_ (activateEvent (castToWidget button) notifier Nothing)
+                            [FocusOut,FocusIn,Clicked]
+                    entry   <-  entryNew
+                    widgetSetName entry $ getParameter paraName parameters ++ "-entry"
+                    -- set entry [ entryEditable := False ]
+                    mapM_ (activateEvent (castToWidget entry) notifier Nothing)
+                            [FocusOut,FocusIn]
+                    registerEvent notifier Clicked (Left (buttonHandler entry))
+                    box <- case getParameter paraDirection parameters of
+                                Horizontal  -> do
+                                    r <- hBoxNew False 1
+                                    return (castToBox r)
+                                Vertical    -> do
+                                    r <- vBoxNew False 1
+                                    return (castToBox r)
+                    boxPackStart box entry PackGrow 0
+                    boxPackEnd box button PackNatural 0
+                    containerAdd widget box
+                    entrySetText entry filePath
+                    writeIORef coreRef (Just entry)
+                Just entry -> entrySetText entry filePath)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just entry -> do
+                    str <- entryGetText entry
+                    return (Just str))
+        parameters
+        notifier
+    where
+    buttonHandler entry e =  do
+        mbFileName <- do
+            dialog <- fileChooserDialogNew
+                            (Just "Select File")
+                            Nothing
+                        action
+                        [("gtk-cancel"
+                        ,ResponseCancel)
+                        ,("gtk-open"
+                        ,ResponseAccept)]
+            widgetShow dialog
+            response <- dialogRun dialog
+            case response of
+                ResponseAccept -> do
+                    f <- fileChooserGetFilename dialog
+                    widgetDestroy dialog
+                    return f
+                ResponseCancel -> do
+                    widgetDestroy dialog
+                    return Nothing
+                ResponseDeleteEvent-> do
+                    widgetDestroy dialog
+                    return Nothing
+                _   -> return Nothing
+        case mbFileName of
+            Nothing -> return (e{gtkReturn=True})
+            Just fn -> do
+                let relative = case mbFilePath of
+                                Nothing -> fn
+                                Just rel -> makeRelative rel fn
+                entrySetText entry relative
+--                triggerEvent notifier SelectionChanged...
+                return (e{gtkReturn=True})
+
+--
+-- | Editor for a font selection
+--
+fontEditor :: Editor (Maybe String)
+fontEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget mbValue -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    fs <- fontButtonNew
+                    widgetSetName fs $ getParameter paraName parameters
+                    mapM_ (activateEvent (castToWidget fs) notifier Nothing)
+                            [FocusOut,FocusIn,Clicked]
+                    containerAdd widget fs
+                    case mbValue of
+                        Nothing -> return True
+                        Just s  -> fontButtonSetFontName fs s
+                    writeIORef coreRef (Just fs)
+                Just fs ->   case mbValue of
+                                Nothing -> return ()
+                                Just s  -> do
+                                    fontButtonSetFontName fs s
+                                    return ())
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just fs -> do
+                    f <- fontButtonGetFontName fs
+                    return (Just (Just f)))
+        parameters
+        notifier
+
+--
+-- | Editor for color selection
+--
+colorEditor :: Editor Color
+colorEditor parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget c -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    cs <- colorButtonNew
+                    widgetSetName cs $ getParameter paraName parameters
+                    mapM_ (activateEvent (castToWidget cs) notifier Nothing)
+                            [FocusOut,FocusIn,Clicked]
+                    containerAdd widget cs
+                    colorButtonSetColor cs c
+                    writeIORef coreRef (Just cs)
+                Just cs -> colorButtonSetColor cs c)
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just cs -> do
+                    c <- colorButtonGetColor cs
+                    return (Just c))
+        parameters
+        notifier
+
+--
+-- | An editor, which opens another editor
+--   You have to inject a value before the button can be clicked.
+--
+otherEditor :: (alpha  -> String -> IO (Maybe alpha)) -> Editor alpha
+otherEditor func parameters notifier = do
+    coreRef <- newIORef Nothing
+    mkEditor
+        (\widget val -> do
+            core <- readIORef coreRef
+            case core of
+                Nothing  -> do
+                    button <- buttonNewWithLabel (getParameter paraName parameters)
+                    widgetSetName button $ getParameter paraName parameters
+                    containerAdd widget button
+                    mapM_ (activateEvent (castToWidget button) notifier Nothing)
+                            [FocusOut,FocusIn,Clicked]
+                    registerEvent notifier Clicked (Left (buttonHandler coreRef))
+                    writeIORef coreRef (Just (button,val))
+                Just (button, oldval) -> writeIORef coreRef (Just (button, val)))
+        (do core <- readIORef coreRef
+            case core of
+                Nothing -> return Nothing
+                Just (_,val) -> return (Just val))
+        (paraName <<<- ParaName "" $ parameters)
+        notifier
+    where
+    buttonHandler coreRef e = do
+        core <- readIORef coreRef
+        case core of
+            Nothing -> error "You have to inject a value before the button can be clicked"
+            Just (b,val) -> do
+                res <- func val (getParameter paraName parameters)
+                case res of
+                    Nothing     -> return (e{gtkReturn=True})
+                    Just nval   -> do
+                        writeIORef coreRef (Just (b, nval))
+                        return (e{gtkReturn=True})
+
+okCancelFields :: FieldDescription ()
+okCancelFields = HFD emptyParams [
+        mkField
+            (paraStockId <<<- ParaStockId stockOk
+                $ paraName <<<- ParaName "Ok"
+                    $ emptyParams)
+            (const ())
+            (\ a b -> b)
+            clickEditor
+    ,   mkField
+            (paraStockId <<<- ParaStockId stockCancel
+                $ paraName <<<- ParaName "Cancel"
+                    $ emptyParams)
+            (const ())
+            (\ _ b -> b)
+            clickEditor]
+
diff --git a/src/Graphics/UI/Frame/Panes.hs b/src/Graphics/UI/Frame/Panes.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Frame/Panes.hs
@@ -0,0 +1,234 @@
+{-# OPTIONS_GHC
+    -XExistentialQuantification
+    -XMultiParamTypeClasses
+    -XFunctionalDependencies
+    -XNoMonomorphismRestriction -XCPP #-}
+-----------------------------------------------------------------------------
+--
+-- Module      :  IDE.Core.Panes
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional21
+-- Portability :  portable
+--
+-- | The basic definitions for all panes
+--
+-------------------------------------------------------------------------------
+
+module Graphics.UI.Frame.Panes (
+
+-- * Panes and pane layout
+    PaneMonad(..)
+,   IDEPane(..)
+,   Pane(..)
+,   RecoverablePane(..)
+,   PaneDirection(..)
+,   PanePathElement(..)
+,   PanePath
+,   PaneLayout(..)
+,   PaneName
+,   Connection(..)
+,   Connections
+,   StandardPath
+,   FrameState(..)
+,   signalDisconnectAll
+) where
+
+import Graphics.UI.Gtk hiding (get)
+import System.Glib.GObject
+import System.Glib.Signals
+import Data.Maybe
+import Data.Map (Map)
+import qualified Data.Map as Map
+import Data.Typeable
+import Control.Monad.Trans
+
+-- ---------------------------------------------------------------------
+-- Panes and pane layout
+--
+
+--
+-- | A path to a pane
+--
+type PanePath       =   [PanePathElement]
+
+--
+-- | An element of a path to a pane
+--
+data PanePathElement = SplitP PaneDirection | GroupP String
+    deriving (Eq,Show,Read)
+
+--
+-- | The relative direction to a pane from the parent
+--
+data PaneDirection  =   TopP | BottomP | LeftP | RightP
+    deriving (Eq,Show,Read)
+  	
+--
+-- | Description of a window layout
+-- Horizontal: top bottom Vertical: left right
+--
+data PaneLayout =       HorizontalP PaneLayout PaneLayout Int
+                    |   VerticalP PaneLayout PaneLayout Int
+                    |   TerminalP {
+                                paneGroups   :: Map String PaneLayout
+                            ,   paneTabs     :: Maybe PaneDirection
+                            ,   currentPage  :: Int
+                            ,   detachedId   :: Maybe String
+                            ,   detachedSize :: Maybe (Int, Int) }
+    deriving (Eq,Show,Read)
+
+--
+-- | All kinds of panes are instances of pane
+--
+
+class (Typeable alpha, PaneMonad delta) =>  Pane alpha delta | alpha -> delta  where
+
+    getTopWidget    ::   alpha -> Widget
+    -- ^ gets the top Widget of this pane
+    paneId          ::   alpha -> String
+    primPaneName    ::   alpha -> String
+
+    paneName        ::   alpha -> PaneName
+    paneName b      =   if getAddedIndex b == 0
+                            then primPaneName b
+                            else primPaneName b ++ "(" ++ show (getAddedIndex b) ++ ")"
+
+    getAddedIndex   ::   alpha -> Int
+    getAddedIndex _ =   0
+
+
+class (Pane alpha delta, Typeable beta, Show beta, Read beta) => RecoverablePane alpha beta delta | beta  -> alpha, alpha -> beta  where
+
+    saveState       ::   alpha -> delta (Maybe beta)
+    recoverState    ::   PanePath -> beta -> delta (Maybe alpha)
+
+    builder         ::   PanePath -> Notebook -> Window -> delta (Maybe alpha,Connections)
+
+    -- getEditor    ::   Editor alpha
+
+    makeActive      ::   alpha -> delta ()
+    makeActive pane =   activateThisPane pane []
+
+    closePane       ::   alpha -> delta Bool
+    closePane       =   closeThisPane
+
+    getPane         ::  delta (Maybe alpha)
+    getPane         =   getThisPane
+
+    forceGetPane    ::  Either PanePath String  -> delta alpha
+    forceGetPane pp =   do  mbPane <- getOrBuildPane pp
+                            case mbPane of
+                                Nothing -> error "Can't get pane "
+                                Just p -> return p
+
+    getOrBuildPane  ::  Either PanePath String -> delta (Maybe alpha)
+    getOrBuildPane  =   getOrBuildThisPane
+
+    displayPane     ::  alpha -> Bool -> delta ()
+    displayPane     =   displayThisPane
+
+    getAndDisplayPane :: Either PanePath String -> Bool  -> delta (Maybe alpha)
+    getAndDisplayPane pps b = do
+        mbP <- getOrBuildThisPane pps
+        case mbP of
+            Nothing -> return Nothing
+            Just p  -> do
+                displayPane p b
+                return (Just p)
+
+    buildPane       ::  PanePath ->
+                        Notebook ->
+                        (PanePath -> Notebook -> Window -> delta (Maybe alpha,Connections)) ->
+                        delta (Maybe alpha)
+    buildPane       =   buildThisPane
+
+
+
+class MonadIO delta =>  PaneMonad delta where
+    setFrameState   ::  FrameState delta -> delta ()
+    getFrameState   ::  delta (FrameState delta)
+    runInIO         ::  forall alpha beta. (beta -> delta alpha) -> delta (beta -> IO alpha)
+    panePathForGroup::  String -> delta PanePath
+
+    getThisPane     ::  forall alpha beta . RecoverablePane alpha beta delta => delta (Maybe alpha)
+    displayThisPane ::  forall alpha beta . RecoverablePane alpha beta delta => alpha -> Bool -> delta ()
+    getOrBuildThisPane
+                    ::  forall alpha beta . RecoverablePane alpha beta delta => Either PanePath String -> delta (Maybe alpha)
+    buildThisPane   ::  forall alpha beta . RecoverablePane alpha beta delta =>
+                        PanePath ->
+                        Notebook ->
+                        (PanePath -> Notebook -> Window -> delta (Maybe alpha,Connections)) ->
+                        delta (Maybe alpha)
+    activateThisPane :: forall alpha beta . RecoverablePane alpha beta delta =>  alpha -> Connections -> delta ()
+    closeThisPane   ::  forall alpha beta . RecoverablePane alpha beta delta =>  alpha -> delta Bool
+
+type PaneName = String
+
+data IDEPane delta       =   forall alpha beta. (RecoverablePane alpha beta delta) => PaneC alpha
+
+instance Eq (IDEPane delta) where
+    (==) (PaneC x) (PaneC y) = paneName x == paneName y
+
+instance Ord (IDEPane delta) where
+    (<=) (PaneC x) (PaneC y) = paneName x <=  paneName y
+
+instance Show (IDEPane delta) where
+    show (PaneC x)    = "Pane " ++ paneName x
+
+type StandardPath = PanePath
+
+data FrameState delta = FrameState {
+    windows         ::  [Window]
+,   uiManager       ::  UIManager
+,   panes           ::  Map PaneName (IDEPane delta)
+,   paneMap         ::  (Map PaneName (PanePath, Connections))
+,   activePane      ::  Maybe (PaneName, Connections)
+,   panePathFromNB  ::  ! (Map Notebook PanePath)
+,   layout          ::  PaneLayout}
+    deriving Show
+
+instance Show Window where
+    show _ = "a Window"
+
+instance Show UIManager where
+    show _ = "a UIManager"
+
+instance Show Connection where
+    show _ = "a Connection"
+
+instance Show Notebook where
+    show _ = "a Notebook"
+
+--
+-- | Signal handlers for the different pane types
+--
+data Connection =  forall alpha . GObjectClass alpha => ConnectC (ConnectId alpha)
+
+type Connections = [Connection]
+
+signalDisconnectAll :: Connections -> IO ()
+signalDisconnectAll = mapM_ (\ (ConnectC s) -> signalDisconnect s)
+
+
+-- Necessary with pre 10.1 verion of gtk2hs
+
+#ifdef MIN_VERSION_gtk
+#if MIN_VERSION_gtk(0,10,1)
+#else
+instance Eq Notebook
+    where (==) a b = let (GObject pa, GObject pb) = (toGObject a, toGObject b)
+                    in pa == pb
+instance Ord Notebook
+    where (<=) a b = let (GObject pa, GObject pb) = (toGObject a, toGObject b)
+                    in pa <= pb
+instance Eq Window
+    where (==) a b = let (GObject pa, GObject pb) = (toGObject a, toGObject b)
+                    in pa == pb
+instance Eq Widget
+    where (==) a b = let (GObject pa, GObject pb) = (toGObject a, toGObject b)
+                    in pa == pb
+#endif
+#endif
diff --git a/src/Graphics/UI/Frame/ViewFrame.hs b/src/Graphics/UI/Frame/ViewFrame.hs
new file mode 100644
--- /dev/null
+++ b/src/Graphics/UI/Frame/ViewFrame.hs
@@ -0,0 +1,1393 @@
+{-# OPTIONS_GHC
+    -XFunctionalDependencies
+    -XNoMonomorphismRestriction
+    -XFlexibleInstances
+    -XMultiParamTypeClasses
+    -XUndecidableInstances
+    -XDeriveDataTypeable #-}
+-----------------------------------------------------------------------------
+--
+-- Module      :  IDE.Core.ViewFrame
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  <maintainer at leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+--
+-- | Splittable panes containing notebooks with any widgets
+--
+---------------------------------------------------------------------------------
+
+
+module Graphics.UI.Frame.ViewFrame (
+    removePaneAdmin
+,   addPaneAdmin
+,   notebookInsertOrdered
+,   markLabel
+
+-- * Convenience methods for accesing Pane state
+,   posTypeToPaneDirection
+,   paneDirectionToPosType
+,   paneFromName
+,   mbPaneFromName
+,   guiPropertiesFromName
+
+-- * View Actions
+,   viewMove
+,   viewSplitHorizontal
+,   viewSplitVertical
+--,   viewSplit
+,   viewSplit'
+,   viewNewGroup
+,   newGroupOrBringToFront
+,   bringGroupToFront
+,   viewNest
+,   viewNest'
+,   viewDetach
+,   viewDetach'
+,   handleNotebookSwitch
+,   viewCollapse
+,   viewCollapse'
+,   viewTabsPos
+,   viewSwitchTabs
+
+,   closeGroup
+,   allGroupNames
+
+-- * View Queries
+,   getBestPanePath
+,   getBestPathForId
+,   getActivePanePath
+,   getActivePanePathOrStandard
+,   figureOutPaneName
+,   getNotebook
+,   getPaned
+,   getActiveNotebook
+,   getActivePane
+,   setActivePane
+,   getUiManager
+,   getWindows
+,   getMainWindow
+,   getLayout
+,   getPanesSt
+,   getPaneMapSt
+,   getPanePrim
+,   getPanes
+
+-- * View Actions
+,   bringPaneToFront
+,   newNotebook
+,   newNotebook'
+
+-- * Accessing GUI elements
+--,   widgetFromPath
+,   getUIAction
+,   widgetGet
+
+,   initGtkRc
+) where
+
+import Graphics.UI.Gtk hiding (afterToggleOverwrite,onToggleOverwrite)
+import Control.Monad.Reader
+import qualified Data.Map as Map
+import Data.List
+import Data.Maybe
+import Data.Unique
+import Data.Typeable
+
+import Graphics.UI.Frame.Panes
+import Graphics.UI.Editor.Parameters
+import System.Glib (GObjectClass(..), isA)
+import Graphics.UI.Gtk.Types (gTypeNotebook)
+import System.CPUTime (getCPUTime)
+import Graphics.UI.Gtk.Gdk.Enums (Modifier(..))
+import MyMissing
+import Graphics.UI.Gtk.Gdk.EventM (TimeStamp(..))
+import Graphics.UI.Editor.MakeEditor
+    (mkField, FieldDescription(..), buildEditor)
+import Graphics.UI.Editor.Simple (stringEditor, okCancelFields)
+import Control.Event (registerEvent)
+import Graphics.UI.Editor.Basics
+    (eventPaneName, GUIEventSelector(..))
+import qualified Data.Set as  Set (unions, member)
+import Data.Set (Set(..))
+import Graphics.UI.Gtk.Gdk.Events (Event(..))
+
+--import Debug.Trace (trace)
+trace a b = b
+
+groupPrefix = "_group_"
+
+withoutGroupPrefix :: String -> String
+withoutGroupPrefix s = case groupPrefix `stripPrefix` s of
+                            Nothing -> s
+                            Just s' -> s'
+
+initGtkRc :: IO ()
+initGtkRc = return ()
+{--	rcParseString ("style \"leksah-close-button-style\"\n" ++
+    "{\n" ++
+    "  GtkWidget::focus-padding = 0\n" ++
+    "  GtkWidget::focus-line-width = 0\n" ++
+    "  xthickness = 0\n" ++
+    "  ythickness = 0\n" ++
+    "}\n" ++
+    "widget \"*.leksah-close-button\" style \"leksah-close-button-style\"")
+--}
+
+removePaneAdmin :: RecoverablePane alpha beta delta =>  alpha -> delta ()
+removePaneAdmin pane = do
+    panes'          <-  getPanesSt
+    paneMap'        <-  getPaneMapSt
+    setPanesSt      (Map.delete (paneName pane) panes')
+    setPaneMapSt    (Map.delete (paneName pane) paneMap')
+
+addPaneAdmin :: RecoverablePane alpha beta delta => alpha -> Connections -> PanePath -> delta Bool
+addPaneAdmin pane conn pp = do
+    panes'          <-  getPanesSt
+    paneMap'        <-  getPaneMapSt
+    liftIO $ widgetSetName (getTopWidget pane) (paneName pane)
+    let b1 = case Map.lookup (paneName pane) paneMap' of
+                Nothing -> True
+                Just it -> False
+    let b2 = case Map.lookup (paneName pane) panes' of
+                Nothing -> True
+                Just it -> False
+    if b1 && b2
+        then do
+            setPaneMapSt (Map.insert (paneName pane) (pp, conn) paneMap')
+            setPanesSt (Map.insert (paneName pane) (PaneC pane) panes')
+            return True
+        else do
+            trace  ("ViewFrame>addPaneAdmin:pane with this name already exist" ++ paneName pane) $
+                return False
+
+getPanePrim ::  RecoverablePane alpha beta delta => delta (Maybe alpha)
+getPanePrim = do
+    selectedPanes <- getPanes
+    if null selectedPanes || length selectedPanes > 1
+        then return Nothing
+        else (return (Just $ head selectedPanes))
+
+getPanes ::  RecoverablePane alpha beta delta => delta ([alpha])
+getPanes = do
+    panes' <- getPanesSt
+    return (catMaybes
+                $ map (\(PaneC p) -> cast p)
+                    $ Map.elems panes')
+
+notebookInsertOrdered :: PaneMonad alpha => (NotebookClass self, WidgetClass child)		
+    => self	
+    -> child	-- child - the Widget to use as the contents of the page.
+    -> String
+    -> Maybe Label	-- the label for the page as String or Label
+    -> Bool
+    -> alpha ()
+notebookInsertOrdered nb widget labelStr mbLabel isGroup = do
+    label	    <-  case mbLabel of
+                        Nothing  -> liftIO $ labelNew (Just labelStr)
+                        Just l  -> return l
+    menuLabel   <-  liftIO $ labelNew (Just labelStr)
+    numPages    <-  liftIO $ notebookGetNPages nb
+    mbWidgets   <-  liftIO $ mapM (notebookGetNthPage nb) [0 .. (numPages-1)]
+    let widgets =   map (\v -> forceJust v "ViewFrame.notebookInsertOrdered: no widget") mbWidgets
+    labelStrs   <-  liftIO $ mapM widgetGetName widgets
+    let pos     =   case findIndex (\ s -> withoutGroupPrefix s > withoutGroupPrefix labelStr) labelStrs of
+                        Just i  ->  i
+                        Nothing ->  -1
+    labelBox    <-  if isGroup then groupLabel labelStr else mkLabelBox label labelStr
+    liftIO $ do
+        markLabel nb labelBox False
+        realPos     <-  notebookInsertPageMenu nb widget labelBox menuLabel pos
+        widgetShowAll labelBox
+        notebookSetCurrentPage nb realPos
+
+-- | Returns a label box
+mkLabelBox :: PaneMonad alpha => Label -> String -> alpha EventBox
+mkLabelBox lbl paneName = do
+    (tb,lb) <- liftIO $ do
+        miscSetAlignment (castToMisc lbl) 0.0 0.0
+        miscSetPadding  (castToMisc lbl) 0 0
+
+        labelBox  <- eventBoxNew
+        eventBoxSetVisibleWindow labelBox False
+        innerBox  <- hBoxNew False 0
+
+        tabButton <- buttonNew
+        widgetSetName tabButton "leksah-close-button"
+        buttonSetFocusOnClick tabButton False
+        buttonSetRelief tabButton ReliefNone
+        buttonSetAlignment tabButton (0.0,0.0)
+
+        image     <- imageNewFromStock stockClose IconSizeMenu
+        mbPB <- widgetRenderIcon tabButton stockClose IconSizeMenu ""
+        (height,width)   <-  case mbPB of
+                                Nothing -> return (14,14)
+                                Just pb -> do
+                                h <- pixbufGetHeight pb
+                                w <- pixbufGetWidth pb
+                                return (h,w)
+        on tabButton styleSet (\style -> do
+            widgetSetSizeRequest tabButton (height + 2) (width + 2))
+        containerSetBorderWidth tabButton 0
+        containerAdd tabButton image
+
+        boxPackStart innerBox lbl PackNatural 0
+        boxPackEnd innerBox tabButton PackNatural 0
+
+        containerAdd labelBox innerBox
+        dragSourceSet labelBox [Button1] [ActionCopy,ActionMove]
+        tl        <- targetListNew
+        targetListAddTextTargets tl 0
+        dragSourceSetTargetList labelBox tl
+        on labelBox dragDataGet (\ cont id timeStamp -> do
+            selectionDataSetText paneName
+            return ())
+        return (tabButton,labelBox)
+    cl <- runInIO closeHandler
+    liftIO $ onClicked tb (cl ())
+
+    return lb
+    where
+        closeHandler :: PaneMonad alpha => () -> alpha ()
+        closeHandler _ =    case groupPrefix `stripPrefix` paneName of
+                                Just group  -> do
+                                    closeGroup group
+                                Nothing -> do
+                                    (PaneC pane) <- paneFromName paneName
+                                    closePane pane
+                                    return ()
+
+groupLabel :: PaneMonad beta => String -> beta EventBox
+groupLabel group = do
+    label <- liftIO $ labelNew Nothing
+    liftIO $ labelSetUseMarkup label True
+    liftIO $ labelSetMarkup label ("<b>" ++ group ++ "</b>")
+    labelBox <- mkLabelBox label (groupPrefix ++ group)
+    liftIO $ widgetShowAll labelBox
+    return labelBox
+
+-- | Add the change mark or removes it
+markLabel :: (WidgetClass alpha, NotebookClass beta) => beta -> alpha -> Bool -> IO ()
+markLabel nb topWidget modified = do
+    mbBox   <- notebookGetTabLabel nb topWidget
+    case mbBox of
+        Nothing  -> return ()
+        Just box -> do
+            mbContainer <- binGetChild (castToBin box)
+            case mbContainer of
+                Nothing -> return ()
+                Just container -> do
+                    children <- containerGetChildren container
+                    let label = castToLabel $ forceHead children "ViewFrame>>markLabel: empty children"
+                    text <- widgetGetName topWidget
+                    labelSetUseMarkup (castToLabel label) True
+                    labelSetMarkup (castToLabel label)
+                        (if modified
+                              then "<span foreground=\"red\">" ++ text ++ "</span>"
+                          else text)
+
+-- | Constructs a unique pane name, which is an index and a string
+figureOutPaneName :: PaneMonad alpha => String -> Int -> alpha (Int,String)
+figureOutPaneName bn ind = do
+    bufs <- getPanesSt
+    let ind = foldr (\(PaneC buf) ind ->
+                if primPaneName buf == bn
+                    then max ind ((getAddedIndex buf) + 1)
+                    else ind)
+                0 (Map.elems bufs)
+    if ind == 0
+        then return (0,bn)
+        else return (ind,bn ++ "(" ++ show ind ++ ")")
+
+paneFromName :: PaneMonad alpha => PaneName -> alpha (IDEPane alpha)
+paneFromName pn = do
+    mbPane <- mbPaneFromName pn
+    case mbPane of
+        Just p -> return p
+        Nothing -> error $ "ViewFrame>>paneFromName:Can't find pane from unique name " ++ pn
+
+mbPaneFromName :: PaneMonad alpha => PaneName -> alpha (Maybe (IDEPane alpha))
+mbPaneFromName pn = do
+    panes  <- getPanesSt
+    return (Map.lookup pn panes)
+
+-- |
+guiPropertiesFromName :: PaneMonad alpha => PaneName -> alpha (PanePath, Connections)
+guiPropertiesFromName pn = do
+    paneMap <- getPaneMapSt
+    case Map.lookup pn paneMap of
+            Just it -> return it
+            otherwise  -> error $"Cant't find guiProperties from unique name " ++ pn
+
+posTypeToPaneDirection PosLeft      =   LeftP
+posTypeToPaneDirection PosRight     =   RightP	
+posTypeToPaneDirection PosTop       =   TopP
+posTypeToPaneDirection PosBottom    =   BottomP	
+
+paneDirectionToPosType LeftP        =   PosLeft
+paneDirectionToPosType RightP       =   PosRight   	
+paneDirectionToPosType TopP         =   PosTop
+paneDirectionToPosType BottomP      =   PosBottom
+
+--
+-- | Toggle the tabs of the current notebook
+--
+viewSwitchTabs :: PaneMonad alpha => alpha ()
+viewSwitchTabs = do
+    mbNb <- getActiveNotebook
+    case mbNb of
+        Nothing -> return ()
+        Just nb -> liftIO $ do
+            b <- notebookGetShowTabs nb
+            notebookSetShowTabs nb (not b)
+
+--
+-- | Sets the tab position in the current notebook
+--
+viewTabsPos :: PaneMonad alpha => PositionType -> alpha ()
+viewTabsPos pos = do
+    mbNb <- getActiveNotebook
+    case mbNb of
+        Nothing -> return ()
+        Just nb -> liftIO $notebookSetTabPos nb pos
+
+--
+-- | Split the currently active pane in horizontal direction
+--
+viewSplitHorizontal     :: PaneMonad alpha => alpha ()
+viewSplitHorizontal     = viewSplit Horizontal
+
+--
+-- | Split the currently active pane in vertical direction
+--
+viewSplitVertical :: PaneMonad alpha => alpha ()
+viewSplitVertical = viewSplit Vertical
+
+--
+-- | The active view can be split in two (horizontal or vertical)
+--
+viewSplit :: PaneMonad alpha => Direction -> alpha ()
+viewSplit dir = do
+    mbPanePath <- getActivePanePath
+    case mbPanePath of
+        Nothing -> return ()
+        Just panePath -> do
+            viewSplit' panePath dir
+
+viewSplit' :: PaneMonad alpha => PanePath -> Direction -> alpha ()
+viewSplit' panePath dir = do
+    l <- getLayout
+    case layoutFromPath panePath l of
+        (TerminalP _ _ _ (Just _) _) -> trace ("ViewFrame>>viewSplit': can't split detached: ") return ()
+        _                            -> do
+            activeNotebook  <- (getNotebook' "viewSplit") panePath
+            ind <- liftIO $ notebookGetCurrentPage activeNotebook
+            mbPD <- do
+                mbParent  <- liftIO $ widgetGetParent activeNotebook
+                case mbParent of
+                    Nothing -> trace ("ViewFrame>>viewSplit': parent not found: ") return Nothing
+                    Just parent -> do
+                        (nb,paneDir) <- do
+                            let (name,altname,paneDir,
+                                 oldPath,newPath) =  case dir of
+                                                        Horizontal  -> ("top",
+                                                                        "bottom",
+                                                                        TopP,
+                                                                        panePath ++ [SplitP TopP],
+                                                                        panePath ++ [SplitP BottomP])
+                                                        Vertical    -> ("left",
+                                                                        "right",
+                                                                        LeftP,
+                                                                        panePath ++ [SplitP LeftP],
+                                                                        panePath ++ [SplitP RightP])
+                            adjustNotebooks panePath oldPath
+                            frameState  <- getFrameState
+                            setPanePathFromNB $ Map.insert activeNotebook oldPath (panePathFromNB frameState)
+                            nb  <- newNotebook newPath
+                            (np,nbi) <- liftIO $ do
+                                newpane <- case dir of
+                                              Horizontal  -> do  h <- vPanedNew
+                                                                 return (castToPaned h)
+                                              Vertical    -> do  v <- hPanedNew
+                                                                 return (castToPaned v)
+                                rName <- widgetGetName activeNotebook
+                                widgetSetName newpane rName
+                                widgetSetName nb altname
+                                panedPack2 newpane nb True True
+                                nbIndex <- if parent `isA` gTypeNotebook
+                                            then notebookPageNum ((castToNotebook' "viewSplit'1") parent) activeNotebook
+                                            else trace ("ViewFrame>>viewSplit': parent not a notebook: ") return Nothing
+                                containerRemove (castToContainer parent) activeNotebook
+                                widgetSetName activeNotebook name
+                                panedPack1 newpane activeNotebook True True
+                                return (newpane,nbIndex)
+                            case (reverse panePath, nbi) of
+                                (SplitP dir:_, _)
+                                    | dir `elem` [TopP, LeftP] -> liftIO $ panedPack1 (castToPaned parent) np True True
+                                    | otherwise                -> liftIO $ panedPack2 (castToPaned parent) np True True
+                                (GroupP group:_, Just n) -> do
+                                    liftIO $ notebookInsertPage ((castToNotebook' "viewSplit' 2") parent) np group n
+                                    label <- groupLabel group
+                                    liftIO $ notebookSetTabLabel ((castToNotebook' "viewSplit' 3") parent) np label
+                                    label2 <- groupMenuLabel group
+                                    liftIO $ notebookSetMenuLabel ((castToNotebook' "viewSplit' 4") parent) np label2
+                                    return ()
+                                ([], _) -> do
+                                    liftIO $ boxPackStart (castToBox parent) np PackGrow 0
+                                    liftIO $ boxReorderChild (castToVBox parent) np 2
+                                _ -> error "No notebook index found in viewSplit"
+                            liftIO $ do
+                                widgetShowAll np
+                                widgetGrabFocus activeNotebook
+                                case nbi of
+                                    Just n -> do
+                                        notebookSetCurrentPage ((castToNotebook' "viewSplit' 5") parent) n
+                                        return ()
+                                    _      -> trace ("ViewFrame>>viewSplit': parent not a notebook2: ")return ()
+                                return (nb,paneDir)
+                        handleFunc <-  runInIO (handleNotebookSwitch nb)
+                        liftIO $ afterSwitchPage nb handleFunc
+                        return (Just (paneDir,dir))
+            case mbPD of
+              Just (paneDir,pdir) -> do
+                  adjustPanes panePath (panePath ++ [SplitP paneDir])
+                  adjustLayoutForSplit paneDir panePath
+                  mbWidget <- liftIO $ notebookGetNthPage activeNotebook ind
+                  when (isJust mbWidget) $ do
+                    name <- liftIO $ widgetGetName (fromJust mbWidget)
+                    mbPane  <- mbPaneFromName name
+                    case mbPane of
+                        Just (PaneC pane) -> move (panePath ++ [SplitP (otherDirection paneDir)]) pane
+                        Nothing -> return ()
+              Nothing -> return ()
+
+--
+-- | Two notebooks can be collapsed to one
+--
+viewCollapse :: PaneMonad alpha => alpha ()
+viewCollapse = do
+    mbPanePath        <- getActivePanePath
+    case mbPanePath of
+        Nothing -> return ()
+        Just panePath -> do
+            viewCollapse' panePath
+
+viewCollapse' :: PaneMonad alpha => PanePath -> alpha ()
+viewCollapse' panePath = trace "viewCollapse' called" $ do
+    layout1           <- getLayoutSt
+    case layoutFromPath panePath layout1 of
+        (TerminalP _ _ _ (Just _) _) -> trace ("ViewFrame>>viewCollapse': can't collapse detached: ")
+                                            return ()
+        _                            -> do
+            let newPanePath     = init panePath
+            let mbOtherSidePath = otherSide panePath
+            case mbOtherSidePath of
+                Nothing -> trace ("ViewFrame>>viewCollapse': no other side path found: ") return ()
+                Just otherSidePath -> do
+                    nbop <- getNotebookOrPaned otherSidePath castToWidget
+                    let nb = if nbop `isA` gTypeNotebook
+                                then Just ((castToNotebook' "viewCollapse' 0") nbop)
+                                else Nothing
+                    case nb of
+                        Nothing -> trace ("ViewFrame>>viewCollapse': other side path not collapsedXX: ") $
+                                case layoutFromPath otherSidePath layout1 of
+                                    VerticalP _ _ _ -> do
+                                        viewCollapse' (otherSidePath ++ [SplitP LeftP])
+                                        viewCollapse' panePath
+                                    HorizontalP _ _ _ -> do
+                                        viewCollapse' (otherSidePath ++ [SplitP TopP])
+                                        viewCollapse' panePath
+                                    otherwise -> trace ("ViewFrame>>viewCollapse': impossible1 ") return ()
+                        Just otherSideNotebook -> do
+                            paneMap           <- getPaneMapSt
+                            activeNotebook    <- (getNotebook' "viewCollapse' 1") panePath
+                            -- 1. Move panes and groups to one side (includes changes to paneMap and layout)
+                            let paneNamesToMove = map (\(w,(p,_)) -> w)
+                                                    $filter (\(w,(p,_)) -> otherSidePath == p)
+                                                        $Map.toList paneMap
+                            panesToMove       <- mapM paneFromName paneNamesToMove
+                            mapM_ (\(PaneC p) -> move panePath p) panesToMove
+                            let groupNames    =  map (\n -> groupPrefix ++ n) $
+                                                        getGroupsFrom otherSidePath layout1
+                            mapM_ (\n -> move' (n,activeNotebook)) groupNames
+                            -- 2. Remove unused notebook from admin
+                            st <- getFrameState
+                            let ! newMap = Map.delete otherSideNotebook (panePathFromNB st)
+                            setPanePathFromNB newMap
+                            -- 3. Remove one level and reparent notebook
+                            mbParent <- liftIO $ widgetGetParent activeNotebook
+                            case mbParent of
+                                Nothing -> error "collapse: no parent"
+                                Just parent -> do
+                                    mbGrandparent <- liftIO $ widgetGetParent parent
+                                    case mbGrandparent of
+                                        Nothing -> error "collapse: no grandparent"
+                                        Just grandparent -> do
+                                            nbIndex <- if grandparent `isA` gTypeNotebook
+                                                then liftIO $ notebookPageNum ((castToNotebook' "viewCollapse'' 1") grandparent) parent
+                                                else return Nothing
+                                            liftIO $ containerRemove (castToContainer grandparent) parent
+                                            liftIO $ containerRemove (castToContainer parent) activeNotebook
+                                            if length panePath > 1
+                                                then do
+                                                    let lasPathElem = last newPanePath
+                                                    case (lasPathElem, nbIndex) of
+                                                        (SplitP dir, _) | dir == TopP || dir == LeftP ->
+                                                            liftIO $ panedPack1 (castToPaned grandparent) activeNotebook True True
+                                                        (SplitP dir, _) | dir == BottomP || dir == RightP ->
+                                                            liftIO $ panedPack2 (castToPaned grandparent) activeNotebook True True
+                                                        (GroupP group, Just n) -> do
+                                                            liftIO $ notebookInsertPage ((castToNotebook' "viewCollapse'' 2") grandparent) activeNotebook group n
+                                                            label <- groupLabel group
+                                                            liftIO $ do
+                                                                notebookSetTabLabel ((castToNotebook' "viewCollapse'' 3") grandparent) activeNotebook label
+                                                                notebookSetCurrentPage ((castToNotebook' "viewCollapse'' 4") grandparent) n
+                                                                return ()
+                                                        _ -> error "collapse: Unable to find page index"
+                                                    liftIO $ widgetSetName activeNotebook $panePathElementToWidgetName lasPathElem
+                                                else liftIO $ do
+                                                    boxPackStart (castToVBox grandparent) activeNotebook PackGrow 0
+                                                    boxReorderChild (castToVBox grandparent) activeNotebook 2
+                                                    widgetSetName activeNotebook "root"
+                            -- 4. Change panePathFromNotebook
+                            adjustNotebooks panePath newPanePath
+                            -- 5. Change paneMap
+                            adjustPanes panePath newPanePath
+                            -- 6. Change layout
+                            adjustLayoutForCollapse panePath
+
+getGroupsFrom :: PanePath -> PaneLayout -> [String]
+getGroupsFrom path layout =
+    case layoutFromPath path layout of
+        t@(TerminalP _ _ _ _ _)   -> Map.keys (paneGroups t)
+        HorizontalP _ _ _   -> []
+        VerticalP _ _ _     -> []
+
+viewNewGroup :: PaneMonad alpha => alpha ()
+viewNewGroup = do
+    mainWindow <- getMainWindow
+    mbGroupName <- liftIO $ groupNameDialog mainWindow
+    case
+     mbGroupName of
+        Just groupName -> do
+            layout <- getLayoutSt
+            if groupName `Set.member` allGroupNames layout
+                then liftIO $ do
+                    md <- messageDialogNew (Just mainWindow) [] MessageWarning ButtonsClose
+                        ("Group name not unique " ++ groupName)
+                    dialogRun md
+                    widgetDestroy md
+                    return ()
+                else viewNest groupName
+        Nothing -> return ()
+
+newGroupOrBringToFront :: PaneMonad alpha => String -> PanePath -> alpha (Maybe PanePath,Bool)
+newGroupOrBringToFront groupName pp = do
+    layout <- getLayoutSt
+    if groupName `Set.member` allGroupNames layout
+        then do
+            mbPP <- bringGroupToFront groupName
+            return (mbPP,False)
+        else let realPath = getBestPanePath pp layout in do
+            viewNest' realPath groupName
+            return (Just (realPath ++ [GroupP groupName]),True)
+
+bringGroupToFront :: PaneMonad alpha => String -> alpha (Maybe PanePath)
+bringGroupToFront groupName = do
+    layout <- getLayoutSt
+    case findGroupPath groupName layout   of
+        Just path -> do
+            widget <- getNotebookOrPaned path castToWidget
+            liftIO $ setCurrentNotebookPages widget
+            return (Just path)
+        Nothing -> return Nothing
+
+
+--  Yet another stupid little dialog
+
+groupNameDialog :: Window -> IO (Maybe String)
+groupNameDialog parent =  liftIO $ do
+    dia                        <-   dialogNew
+    windowSetTransientFor dia parent
+    windowSetTitle dia "Enter group name"
+    upper                      <-   dialogGetUpper dia
+    lower                      <-   dialogGetActionArea dia
+    (widget,inj,ext,_)         <-   buildEditor moduleFields ""
+    (widget2,_,_,notifier)     <-   buildEditor okCancelFields ()
+    registerEvent notifier Clicked (Left (\e -> do
+            case eventPaneName e of
+                "Ok"    ->  dialogResponse dia ResponseOk
+                _       ->  dialogResponse dia ResponseCancel
+            return e))
+    boxPackStart upper widget PackGrow 7
+    boxPackStart lower widget2 PackNatural 7
+    widgetShowAll dia
+    resp <- dialogRun dia
+    value                      <- ext ("")
+    widgetDestroy dia
+    case resp of
+        ResponseOk | value /= Just ""  -> return value
+        _                             -> return Nothing
+    where
+        moduleFields :: FieldDescription String
+        moduleFields = VFD emptyParams [
+                mkField
+                    (paraName <<<- ParaName ("New group ")
+                            $ emptyParams)
+                    id
+                    (\ a b -> a)
+            (stringEditor (\s -> True))]
+
+viewNest :: PaneMonad alpha => String -> alpha ()
+viewNest group = do
+    mbPanePath        <- getActivePanePath
+    case mbPanePath of
+        Nothing -> return ()
+        Just panePath -> do
+            viewNest' panePath group
+
+viewNest' :: PaneMonad alpha => PanePath -> String -> alpha ()
+viewNest' panePath group = do
+    activeNotebook  <- (getNotebook' "viewNest' 1") panePath
+    mbParent  <- liftIO $ widgetGetParent activeNotebook
+    case mbParent of
+        Nothing -> return ()
+        Just parent -> do
+            layout          <-  getLayoutSt
+            let paneLayout  =   layoutFromPath panePath layout
+            case paneLayout of
+                (TerminalP {}) -> do
+                    nb <- newNotebook (panePath ++ [GroupP group])
+                    liftIO $ widgetSetName nb (groupPrefix ++ group)
+                    notebookInsertOrdered activeNotebook nb group Nothing True
+                    liftIO $ widgetShowAll nb
+                        --widgetGrabFocus activeNotebook
+                    handleFunc <-  runInIO (handleNotebookSwitch nb)
+                    liftIO $ afterSwitchPage nb handleFunc
+                    adjustLayoutForNest group panePath
+                _ -> return ()
+
+closeGroup :: PaneMonad alpha => String -> alpha ()
+closeGroup groupName = do
+    layout <- getLayout
+    let mbPath = findGroupPath groupName layout
+    mainWindow <- getMainWindow
+    case mbPath of
+        Nothing -> trace ("ViewFrame>>closeGroup: Group path not found: " ++ groupName) return ()
+        Just path -> do
+            panesMap <- getPaneMapSt
+            let nameAndpathList  = filter (\(a,pp) -> path `isPrefixOf` pp)
+                            $ map (\(a,b) -> (a,fst b)) (Map.assocs panesMap)
+            continue <- case nameAndpathList of
+                            (_:_) -> liftIO $ do
+                                md <- messageDialogNew (Just mainWindow) [] MessageQuestion ButtonsYesNo
+                                    ("Group " ++ groupName ++ " not empty. Close with all contents?")
+                                rid <- dialogRun md
+                                widgetDestroy md
+                                case rid of
+                                    ResponseYes ->  return True
+                                    otherwise   ->  return False
+                            []  -> return True
+            when continue $ do
+                panes <- mapM paneFromName $ map fst nameAndpathList
+                results <- mapM (\ (PaneC p) -> closePane p) panes
+                when (foldr (&&) True results) $ do
+                    nbOrPaned  <- getNotebookOrPaned path castToWidget
+                    mbParent <- liftIO $ widgetGetParent nbOrPaned
+                    case mbParent of
+                        Nothing -> error "ViewFrame>>closeGroup: closeGroup: no parent"
+                        Just parent -> liftIO $ containerRemove (castToContainer parent) nbOrPaned
+                    setLayoutSt (removeGL path layout)
+                    ppMap <- getPanePathFromNB
+                    setPanePathFromNB (Map.filter (\pa -> not (path `isPrefixOf` pa)) ppMap)
+
+viewDetach :: PaneMonad alpha => alpha (Maybe (Window,Widget))
+viewDetach = do
+    id <- liftIO $ fmap show getCPUTime
+    mbPanePath        <- getActivePanePath
+    case mbPanePath of
+        Nothing -> return Nothing
+        Just panePath -> do
+            viewDetach' panePath id
+
+viewDetach' :: PaneMonad alpha => PanePath -> String -> alpha (Maybe (Window,Widget))
+viewDetach' panePath id = do
+    activeNotebook  <- (getNotebook' "viewDetach'") panePath
+    mbParent  <- liftIO $ widgetGetParent activeNotebook
+    case mbParent of
+        Nothing -> return Nothing
+        Just parent -> do
+            layout          <-  getLayoutSt
+            let paneLayout  =   layoutFromPath panePath layout
+            case paneLayout of
+                (TerminalP{detachedSize = size}) -> do
+                    window <- liftIO $ do
+                        window <- windowNew
+                        windowSetTitle window "Leksah detached window"
+                        widgetSetName window id
+                        case size of
+                            Just (width, height) -> do
+                                windowSetDefaultSize window width height
+                            Nothing -> do
+                                (curWidth, curHeight) <- widgetGetSize activeNotebook
+                                windowSetDefaultSize window curWidth curHeight
+                        containerRemove (castToContainer parent) activeNotebook
+                        containerAdd window activeNotebook
+                        widgetShowAll window
+                        return window
+                    handleFunc <-  runInIO (handleReattach id window)
+                    liftIO $ window `onDelete` handleFunc
+                    windows <- getWindowsSt
+                    setWindowsSt $ windows ++ [window]
+                    adjustLayoutForDetach id panePath
+                    return (Just (window, castToWidget activeNotebook))
+                _ -> return Nothing
+
+
+
+handleReattach :: PaneMonad alpha => String -> Window -> Event -> alpha Bool
+handleReattach windowId window _ = do
+    layout <- getLayout
+    case findDetachedPath windowId layout of
+        Nothing -> trace ("ViewFrame>>handleReattach: panePath for id not found: " ++ windowId)
+                $ do
+            windows <- getWindowsSt
+            setWindowsSt $ delete window windows
+            return False
+        Just pp -> do
+            nb      <- (getNotebook' "handleReattach") pp
+            parent  <- getNotebookOrPaned (init pp) castToContainer
+            liftIO $ containerRemove (castToContainer window) nb
+            liftIO $ containerAdd parent nb
+            adjustLayoutForReattach pp
+            windows <- getWindowsSt
+            setWindowsSt $ delete window windows
+            case last pp of
+                GroupP groupName -> do
+                    label <- groupLabel groupName
+                    liftIO $ notebookSetTabLabel ((castToNotebook' "handleReattach") parent) nb label
+                otherwise       -> return ()
+            return False -- "now destroy the window"
+
+
+
+groupMenuLabel :: PaneMonad beta => String -> beta (Maybe Label)
+groupMenuLabel group = liftM Just (liftIO $ labelNew (Just group))
+
+handleNotebookSwitch :: PaneMonad beta => Notebook -> Int -> beta ()
+handleNotebookSwitch nb index = do
+    mbW <- liftIO $ notebookGetNthPage nb index
+    case mbW of
+        Nothing -> error "ViewFrame/handleNotebookSwitch: Can't find widget"
+        Just w  -> do
+            name   <-  liftIO $ widgetGetName w
+            mbPane <-  findPaneFor name
+            case mbPane of
+                Nothing         ->  return ()
+                Just (PaneC p)  ->  makeActive p
+    where
+        findPaneFor :: PaneMonad beta => String -> beta (Maybe (IDEPane beta))
+        findPaneFor n1   =   do
+            panes'      <-  getPanesSt
+            foldM (\r (PaneC p) -> do
+                n2 <- liftIO $ widgetGetName (getTopWidget p)
+                return (if n1 == n2 then (Just (PaneC p)) else r))
+                        Nothing (Map.elems panes')
+
+
+--
+-- | Moves the activePane in the given direction, if possible
+-- | If their are many possibilities choose the leftmost and topmost
+--
+viewMove :: PaneMonad beta => PaneDirection -> beta  ()
+viewMove direction = do
+    mbPane <- getActivePaneSt
+    case mbPane of
+        Nothing -> do
+            return ()
+        Just (paneName,_) -> do
+            (PaneC pane) <- paneFromName paneName
+            mbPanePath <- getActivePanePath
+            case mbPanePath of
+                Nothing -> do
+                    return ()
+                Just panePath -> do
+                  layout <- getLayoutSt
+                  case findMoveTarget panePath layout direction of
+                      Nothing -> do
+                        return ()
+                      Just moveTo -> move moveTo pane
+
+--
+-- | Find the target for a move
+--
+findMoveTarget :: PanePath -> PaneLayout -> PaneDirection -> Maybe PanePath
+findMoveTarget panePath layout direction=
+    let oppositeDir          = otherDirection direction
+        canMove []           = []
+        canMove reversedPath =
+            case head reversedPath of
+                SplitP d | d == oppositeDir
+                    -> SplitP direction : (tail reversedPath)
+                GroupP group -> []
+                _                     -> canMove (tail reversedPath)
+        basePath = reverse (canMove $ reverse panePath)
+    in case basePath of
+        [] -> Nothing
+        _  -> let layoutP  = layoutFromPath basePath layout
+             in  Just $basePath ++ findAppropriate layoutP oppositeDir
+
+--
+-- | Moves the given Pane to the given path
+--
+move ::  RecoverablePane alpha beta delta => PanePath -> alpha -> delta ()
+move toPanePath pane = do
+    let name    = paneName pane
+    toNB        <- (getNotebook' "move") toPanePath
+    move' (name,toNB)
+
+--
+-- | Moves the given Pane to the given path, care for groups (layout, paneMap)
+--
+move' :: PaneMonad alpha => (PaneName,Notebook) -> alpha ()
+move' (paneName,toNB) = do
+    paneMap         <-  getPaneMapSt
+    panes           <-  getPanesSt
+    layout          <-  getLayout
+    frameState      <-  getFrameState
+    case groupPrefix `stripPrefix` paneName of
+        Just group  -> do
+            case findGroupPath group layout of
+                Nothing -> trace ("ViewFrame>>move': group not found: " ++ group) return ()
+                Just fromPath -> do
+                    groupNBOrPaned <- getNotebookOrPaned fromPath castToWidget
+                    fromNB  <- (getNotebook' "move'") (init fromPath)
+                    case toNB `Map.lookup` (panePathFromNB frameState) of
+                        Nothing -> trace "ViewFrame>>move': panepath for Notebook not found1" return ()
+                        Just toPath -> do
+                            when (fromNB /= toNB && not (isPrefixOf fromPath toPath)) $ do
+                                mbNum <- liftIO $ notebookPageNum fromNB groupNBOrPaned
+                                case mbNum of
+                                    Nothing ->  trace "ViewFrame>>move': group notebook not found" return ()
+                                    Just num -> do
+                                        liftIO $ notebookRemovePage fromNB num
+                                        label <- groupLabel group
+                                        notebookInsertOrdered toNB groupNBOrPaned group Nothing True
+                                        liftIO $ notebookSetTabLabel toNB groupNBOrPaned label
+                                        adjustPanes fromPath (toPath ++ [GroupP group])
+                                        adjustLayoutForGroupMove fromPath toPath group
+                                        adjustNotebooks fromPath (toPath ++ [GroupP group])
+                                        layout2          <-  getLayout
+                                        return ()
+        Nothing     ->
+            case paneName `Map.lookup` panes of
+                Nothing -> trace ("ViewFrame>>move': pane not found: " ++ paneName) return ()
+                Just (PaneC pane) -> do
+                    case toNB `Map.lookup` (panePathFromNB frameState) of
+                        Nothing -> trace "ViewFrame>>move': panepath for Notebook not found2" return ()
+                        Just toPath ->
+                            case paneName `Map.lookup`paneMap of
+                                Nothing -> trace ("ViewFrame>>move': pane data not found: " ++ paneName)
+                                            return ()
+                                Just (fromPath,_) -> do
+                                    let child = getTopWidget pane
+                                    (fromPane,cid)  <-  guiPropertiesFromName paneName
+                                    fromNB          <-  (getNotebook' "move'") fromPane
+                                    when (fromNB /= toNB) $ do
+                                        mbNum <- liftIO $ notebookPageNum fromNB child
+                                        case mbNum of
+                                            Nothing ->  trace "ViewFrame>>move': widget not found" return ()
+                                            Just num -> do
+                                                liftIO $ notebookRemovePage fromNB num
+                                                notebookInsertOrdered toNB child paneName Nothing False
+                                                let paneMap1    =   Map.delete paneName paneMap
+                                                setPaneMapSt    $   Map.insert paneName (toPath,cid) paneMap1
+
+findAppropriate :: PaneLayout -> PaneDirection -> PanePath
+findAppropriate  (TerminalP {}) _ =   []
+findAppropriate  (HorizontalP t b _) LeftP     =   SplitP TopP    :  findAppropriate t LeftP
+findAppropriate  (HorizontalP t b _) RightP    =   SplitP TopP    :  findAppropriate t RightP
+findAppropriate  (HorizontalP t b _) BottomP   =   SplitP BottomP :  findAppropriate b BottomP
+findAppropriate  (HorizontalP t b _) TopP      =   SplitP TopP    :  findAppropriate b TopP
+findAppropriate  (VerticalP l r _) LeftP       =   SplitP LeftP   :  findAppropriate l LeftP
+findAppropriate  (VerticalP l r _) RightP      =   SplitP RightP  :  findAppropriate r RightP
+findAppropriate  (VerticalP l r _) BottomP     =   SplitP LeftP   :  findAppropriate l BottomP
+findAppropriate  (VerticalP l r _) TopP        =   SplitP LeftP   :  findAppropriate l TopP
+
+--
+-- | Bring the pane to the front position in its notebook
+--
+bringPaneToFront :: RecoverablePane alpha beta delta => alpha -> IO ()
+bringPaneToFront pane = do
+    let tv = getTopWidget pane
+    setCurrentNotebookPages tv
+
+
+setCurrentNotebookPages widget = do
+    mbParent <- widgetGetParent widget
+    case mbParent of
+        Just parent -> do
+            setCurrentNotebookPages parent
+            if parent `isA` gTypeNotebook
+                then do
+                    mbPageNum <- notebookPageNum ((castToNotebook' "setCurrentNotebookPage 1") parent) widget
+                    case mbPageNum of
+                        Just pageNum -> do
+                            notebookSetCurrentPage ((castToNotebook' "setCurrentNotebookPage 2") parent) pageNum
+                            return ()
+                        Nothing      -> return ()
+                else return ()
+        Nothing -> return ()
+
+--
+-- | Get a valid panePath from a standard path.
+--
+getBestPanePath :: StandardPath -> PaneLayout -> PanePath
+getBestPanePath sp pl = reverse $ getStandard' sp pl []
+    where
+    getStandard' (GroupP group:sp) (TerminalP {paneGroups = groups}) p
+        | group `Map.member` groups                 =   getStandard' sp (groups Map.! group) (GroupP group:p)
+    getStandard' _ (TerminalP {}) p              =   p
+    getStandard' (SplitP LeftP:sp) (VerticalP l r _) p     =   getStandard' sp l (SplitP LeftP:p)
+    getStandard' (SplitP RightP:sp) (VerticalP l r _) p    =   getStandard' sp r (SplitP RightP:p)
+    getStandard' (SplitP TopP:sp) (HorizontalP t b _) p    =   getStandard' sp t (SplitP TopP:p)
+    getStandard' (SplitP BottomP:sp) (HorizontalP t b _) p =   getStandard' sp b (SplitP BottomP:p)
+    -- if no match get leftmost topmost
+    getStandard' _ (VerticalP l r _) p              =   getStandard' [] l (SplitP LeftP:p)
+    getStandard' _ (HorizontalP t b _) p            =   getStandard' [] t (SplitP TopP:p)
+
+--
+-- | Get a standard path.
+--
+getBestPathForId :: PaneMonad alpha => String -> alpha PanePath
+getBestPathForId  id = do
+    p <- panePathForGroup id
+    l <- getLayout
+    return (getBestPanePath p l)
+		
+--
+-- | Construct a new notebook
+--
+newNotebook' :: IO Notebook
+newNotebook' = do
+    nb <- notebookNew
+    notebookSetTabPos nb PosTop
+    notebookSetShowTabs nb True
+    notebookSetScrollable nb True
+    notebookSetPopup nb True
+    return nb
+
+--
+-- | Construct a new notebook,
+--
+newNotebook :: PaneMonad alpha => PanePath -> alpha Notebook
+newNotebook pp = do
+    st  <- getFrameState
+    nb  <- liftIO newNotebook'
+    setPanePathFromNB $ Map.insert nb pp (panePathFromNB st)
+    func <- runInIO move'
+    liftIO $ do
+        tl <- targetListNew
+        targetListAddTextTargets tl 0
+        dragDestSet nb [DestDefaultAll] [ActionCopy, ActionMove]
+        dragDestSetTargetList nb tl
+        on nb dragDataReceived (dragFunc nb func)
+        return nb
+    where
+        dragFunc ::
+            Notebook ->
+            ((PaneName,Notebook) -> IO ()) ->
+            DragContext ->
+            Point ->
+            InfoId ->
+            TimeStamp ->
+            (SelectionDataM ())
+        dragFunc nb func cont point id timeStamp = do
+            mbText <- selectionDataGetText
+            case mbText of
+                Nothing -> return ()
+                Just str -> do
+                    liftIO $ func (str,nb)
+                    return ()
+
+terminalsWithPanePath :: PaneLayout -> [(PanePath,PaneLayout)]
+terminalsWithPanePath pl = map (\ (pp,l) -> (reverse pp,l)) $ terminalsWithPP [] pl
+    where
+        terminalsWithPP pp t@(TerminalP groups _ _ _ _) =  [(pp,t)]
+                                            ++ concatMap (terminalsFromGroup pp) (Map.toList groups)
+        terminalsWithPP pp (VerticalP l r _)       =  terminalsWithPP (SplitP LeftP : pp) l
+                                                        ++ terminalsWithPP (SplitP RightP : pp) r
+        terminalsWithPP pp (HorizontalP t b _)     =  terminalsWithPP (SplitP TopP : pp) t
+                                                        ++ terminalsWithPP (SplitP BottomP : pp) b
+        terminalsFromGroup pp (name,layout)        =  terminalsWithPP (GroupP name : pp) layout
+
+findGroupPath :: String -> PaneLayout -> Maybe PanePath
+findGroupPath group layout =
+    let terminalPairs = terminalsWithPanePath layout
+    in case (filter filterFunc terminalPairs) of
+        [] -> Nothing
+        (pp,_) : [] -> Just (pp ++ [GroupP group])
+        _ -> error ("ViewFrame>>group name not unique: " ++ group)
+    where
+        filterFunc (_,(TerminalP groups _ _ _ _)) =  group  `Set.member` Map.keysSet groups
+        filterFunc _                              =  error "ViewFrame>>findGroupPath: impossible"
+
+findDetachedPath :: String -> PaneLayout -> Maybe PanePath
+findDetachedPath id layout =
+    let terminalPairs = terminalsWithPanePath layout
+    in case (filter filterFunc terminalPairs) of
+        [] -> Nothing
+        (pp,_) : [] -> Just pp
+        _ -> error ("ViewFrame>>window id not unique: " ++ id)
+    where
+        filterFunc (_,(TerminalP _ _ _ (Just lid) _)) = lid == id
+        filterFunc _                                  = False
+
+
+allGroupNames :: PaneLayout -> Set String
+allGroupNames pl = Set.unions $ map getFunc (terminalsWithPanePath pl)
+    where
+        getFunc (_,(TerminalP groups _ _ _ _)) =  Map.keysSet groups
+        getFunc _                              =  error "ViewFrame>>allGroupNames: impossible"
+
+
+--
+-- | Get another pane path which points to the other side at the same level
+--
+otherSide :: PanePath -> Maybe PanePath
+otherSide []    =   Nothing
+otherSide p     =   let rp = reverse p
+                    in case head rp of
+                        SplitP d -> Just (reverse $ SplitP (otherDirection d) : tail rp)
+                        _        -> Nothing
+
+--
+-- | Get the opposite direction of a pane direction
+--
+otherDirection :: PaneDirection -> PaneDirection
+otherDirection LeftP    = RightP
+otherDirection RightP   = LeftP
+otherDirection TopP     = BottomP
+otherDirection BottomP  = TopP
+
+--
+-- | Get the layout at the given pane path
+--
+layoutFromPath :: PanePath -> PaneLayout -> PaneLayout
+layoutFromPath [] l                                   = l
+layoutFromPath (GroupP group:r) (TerminalP {paneGroups = groups})
+    | group `Map.member` groups                       = layoutFromPath r (groups Map.! group)
+layoutFromPath (SplitP TopP:r) (HorizontalP t _ _)    = layoutFromPath r t
+layoutFromPath (SplitP BottomP:r) (HorizontalP _ b _) = layoutFromPath r b
+layoutFromPath (SplitP LeftP:r) (VerticalP l _ _)     = layoutFromPath r l
+layoutFromPath (SplitP RightP:r) (VerticalP _ ri _)   = layoutFromPath r ri
+layoutFromPath pp l                                   = error
+    $"inconsistent layout (layoutFromPath) " ++ show pp ++ " " ++ show l
+
+layoutsFromPath :: PanePath -> PaneLayout -> [PaneLayout]
+layoutsFromPath (GroupP group:r) layout@(TerminalP {paneGroups = groups})
+    | group `Map.member` groups
+        = layout:layoutsFromPath r (groups Map.! group)
+layoutsFromPath [] layout                                     =   [layout]
+layoutsFromPath (SplitP TopP:r) layout@(HorizontalP t b _)    =   layout:layoutsFromPath r t
+layoutsFromPath (SplitP BottomP:r) layout@(HorizontalP t b _) =   layout:layoutsFromPath r b
+layoutsFromPath (SplitP LeftP:r) layout@(VerticalP l ri _)    =   layout:layoutsFromPath r l
+layoutsFromPath (SplitP RightP:r) layout@(VerticalP l ri _)   =   layout:layoutsFromPath r ri
+layoutsFromPath pp l                                      = error
+    $"inconsistent layout (layoutsFromPath) " ++ show pp ++ " " ++ show l
+
+getWidgetNameList :: PanePath -> PaneLayout -> [String]
+getWidgetNameList path layout = reverse $ nameList (reverse path) (reverse $ layoutsFromPath path layout)
+    where
+        nameList [] _ = reverse ["Leksah Main Window","topBox","root"]
+        nameList (pe:_) (TerminalP{detachedId = Just id}:_) = [panePathElementToWidgetName pe, id]
+        nameList (pe:rpath) (_:rlayout) = panePathElementToWidgetName pe : nameList rpath rlayout
+        nameList _ _ = error $ "inconsistent layout (getWidgetNameList) " ++ show path ++ " " ++ show layout
+
+getNotebookOrPaned :: PaneMonad alpha => PanePath -> (Widget -> beta) -> alpha beta
+getNotebookOrPaned p cf = do
+    layout <- getLayout
+    (widgetGet $ getWidgetNameList p layout) cf
+
+--
+-- | Get the notebook widget for the given pane path
+--
+getNotebook :: PaneMonad alpha => PanePath -> alpha  Notebook
+getNotebook p = getNotebookOrPaned p (castToNotebook' ("getNotebook " ++ show p))
+
+getNotebook' :: PaneMonad alpha => String -> PanePath -> alpha  Notebook
+getNotebook' str p = getNotebookOrPaned p (castToNotebook' ("getNotebook' " ++ str ++ " " ++ show p))
+
+
+--
+-- | Get the (gtk) Paned widget for a given path
+--
+getPaned :: PaneMonad alpha => PanePath -> alpha Paned
+getPaned p = getNotebookOrPaned p castToPaned
+
+--
+-- | Get the path to the active pane
+--
+getActivePanePath :: PaneMonad alpha => alpha  (Maybe PanePath)
+getActivePanePath = do
+    mbPane   <- getActivePaneSt
+    case mbPane of
+        Nothing -> return Nothing
+        Just (paneName,_) -> do
+            (pp,_)  <- guiPropertiesFromName paneName
+            return (Just (pp))
+
+getActivePanePathOrStandard :: PaneMonad alpha => StandardPath -> alpha  (PanePath)
+getActivePanePathOrStandard sp = do
+    mbApp <- getActivePanePath
+    case mbApp of
+        Just app -> return app
+        Nothing -> do
+            layout <- getLayoutSt
+            return (getBestPanePath sp layout)
+
+--
+-- | Get the active notebook
+--
+getActiveNotebook :: PaneMonad alpha => alpha  (Maybe Notebook)
+getActiveNotebook = do
+    mbPanePath <- getActivePanePath
+    case mbPanePath of
+        Just panePath -> do
+            nb <- (getNotebook' "getActiveNotebook") panePath
+            return (Just nb)
+        Nothing -> return Nothing
+
+
+--
+-- | Translates a pane direction to the widget name
+--
+paneDirectionToWidgetName           :: PaneDirection -> String
+paneDirectionToWidgetName TopP      =  "top"
+paneDirectionToWidgetName BottomP   =  "bottom"
+paneDirectionToWidgetName LeftP     =  "left"
+paneDirectionToWidgetName RightP    =  "right"
+
+panePathElementToWidgetName :: PanePathElement -> String
+panePathElementToWidgetName (SplitP dir)   = paneDirectionToWidgetName dir
+panePathElementToWidgetName (GroupP group) = groupPrefix ++ group
+
+--
+-- | Changes a pane path in the pane map
+--
+adjustPanes :: PaneMonad alpha => PanePath -> PanePath -> alpha ()
+adjustPanes fromPane toPane  = do
+    paneMap     <- getPaneMapSt
+    setPaneMapSt (Map.map (\(pp,other) ->
+        case stripPrefix fromPane pp of
+            Just rest -> (toPane ++ rest,other)
+            _         -> (pp,other)) paneMap)
+
+adjustNotebooks :: PaneMonad alpha => PanePath -> PanePath -> alpha ()
+adjustNotebooks fromPane toPane  = do
+    npMap <- trace ("+++ adjustNotebooks from: " ++ show fromPane ++ " to " ++ show toPane)
+                getPanePathFromNB
+    setPanePathFromNB  (Map.map (\pp ->
+        case stripPrefix fromPane pp of
+            Just rest -> toPane ++ rest
+            _         -> pp) npMap)
+
+--
+-- | Changes the layout for a split
+--
+adjustLayoutForSplit :: PaneMonad alpha => PaneDirection -> PanePath -> alpha ()
+adjustLayoutForSplit  dir path  = do
+    layout          <-  getLayoutSt
+    let paneLayout  =   layoutFromPath path layout
+        newLayout   =   TerminalP Map.empty Nothing 0 Nothing Nothing
+        newTerm     =   case dir of
+                            LeftP   -> VerticalP paneLayout newLayout 0
+                            RightP  -> VerticalP newLayout paneLayout 0
+                            TopP    -> HorizontalP paneLayout newLayout 0
+                            BottomP -> HorizontalP newLayout paneLayout 0
+    setLayoutSt     $   adjustLayout path layout newTerm
+
+--
+-- | Changes the layout for a nest
+--
+adjustLayoutForNest :: PaneMonad alpha => String -> PanePath -> alpha ()
+adjustLayoutForNest group path = do
+    layout          <-  getLayoutSt
+    let paneLayout  =   layoutFromPath path layout
+        newTerm     =   case paneLayout of
+                            (TerminalP {paneGroups = groups}) -> paneLayout {
+                                paneGroups = Map.insert group (TerminalP Map.empty Nothing 0 Nothing Nothing) groups}
+                            _          -> error "Unexpected layout type in adjustLayoutForNest"
+    setLayoutSt     $   adjustLayout path layout newTerm
+
+--
+-- | Changes the layout for a detach
+--
+adjustLayoutForDetach :: PaneMonad alpha => String -> PanePath -> alpha ()
+adjustLayoutForDetach id path = do
+    layout          <-  getLayoutSt
+    let paneLayout  =   layoutFromPath path layout
+        newTerm     =   case paneLayout of
+                            (TerminalP {}) -> paneLayout {detachedId = Just id}
+                            _              -> error "Unexpected layout type in adjustLayoutForDetach"
+    setLayoutSt     $   adjustLayout path layout newTerm
+
+--
+-- | Changes the layout for a reattach
+--
+adjustLayoutForReattach :: PaneMonad alpha => PanePath -> alpha ()
+adjustLayoutForReattach path = do
+    layout          <-  getLayoutSt
+    let paneLayout  =   layoutFromPath path layout
+        newTerm     =   case paneLayout of
+                            (TerminalP {}) -> paneLayout {detachedId = Nothing, detachedSize = Nothing}
+                            _   -> error "Unexpected layout type in adjustLayoutForReattach"
+    setLayoutSt     $   adjustLayout path layout newTerm
+
+--
+-- | Changes the layout for a collapse
+--
+adjustLayoutForCollapse :: PaneMonad alpha => PanePath -> alpha ()
+adjustLayoutForCollapse oldPath  = do
+    layout          <-  getLayoutSt
+    let pathLayout  =   layoutFromPath oldPath layout
+    setLayoutSt     $   adjustLayout (init oldPath) layout pathLayout
+
+--
+-- | Changes the layout for a move
+--
+adjustLayoutForGroupMove :: PaneMonad alpha => PanePath -> PanePath -> String -> alpha ()
+adjustLayoutForGroupMove fromPath toPath group = do
+    layout <- getLayout
+    let layoutToMove = layoutFromPath fromPath layout
+    let newLayout = removeGL fromPath layout
+    setLayoutSt (addGL layoutToMove (toPath ++ [GroupP group])  newLayout)
+
+--
+-- | Changes the layout for a remove
+--
+adjustLayoutForGroupRemove :: PaneMonad alpha => PanePath -> String -> alpha ()
+adjustLayoutForGroupRemove fromPath group = do
+    layout <- getLayout
+    setLayoutSt (removeGL fromPath layout)
+
+--
+-- | Remove group layout at a certain path
+--
+removeGL :: PanePath -> PaneLayout -> PaneLayout
+removeGL [GroupP group] t@(TerminalP oldGroups _ _ _ _)
+    | group `Map.member` oldGroups                        =  t{paneGroups = group `Map.delete` oldGroups}
+removeGL (GroupP group:r)  old@(TerminalP {paneGroups = groups})
+    | group `Map.member` groups                             = old{paneGroups = Map.adjust (removeGL r) group groups}
+removeGL (SplitP TopP:r)  (HorizontalP tp bp _)     = HorizontalP (removeGL r tp) bp 0
+removeGL (SplitP BottomP:r)  (HorizontalP tp bp _)  = HorizontalP tp (removeGL r bp) 0
+removeGL (SplitP LeftP:r)  (VerticalP lp rp _)      = VerticalP (removeGL r lp) rp 0
+removeGL (SplitP RightP:r)  (VerticalP lp rp _)     = VerticalP lp (removeGL r rp) 0
+removeGL p l = error $"ViewFrame>>removeGL: inconsistent layout " ++ show p ++ " " ++ show l
+
+--
+-- | Add group layout at a certain path
+--
+addGL :: PaneLayout -> PanePath -> PaneLayout -> PaneLayout
+addGL toAdd [GroupP group] t@(TerminalP oldGroups _ _ _ _)  =  t{paneGroups = Map.insert group toAdd oldGroups}
+addGL toAdd (GroupP group:r)  old@(TerminalP {paneGroups = groups})
+    | group `Map.member` groups = old{paneGroups       = Map.adjust (addGL toAdd r) group groups}
+addGL toAdd (SplitP TopP:r)  (HorizontalP tp bp _)     = HorizontalP (addGL toAdd r tp) bp 0
+addGL toAdd (SplitP BottomP:r)  (HorizontalP tp bp _)  = HorizontalP tp (addGL toAdd r bp) 0
+addGL toAdd (SplitP LeftP:r)  (VerticalP lp rp _)      = VerticalP (addGL toAdd r lp) rp 0
+addGL toAdd (SplitP RightP:r)  (VerticalP lp rp _)     = VerticalP lp (addGL toAdd r rp) 0
+addGL _ p l = error $"ViewFrame>>addGL: inconsistent layout" ++ show p ++ " " ++ show l
+
+--
+-- | Changes the layout by replacing element at pane path (pp) with replace
+--
+adjustLayout :: PanePath -> PaneLayout -> PaneLayout -> PaneLayout
+adjustLayout pp layout replace    = adjust' pp layout
+    where
+    adjust' [] _                                       = replace
+    adjust' (GroupP group:r)  old@(TerminalP {paneGroups = groups})
+        | group `Map.member` groups =
+            old{paneGroups = Map.adjust (adjustPaneGroupLayout r) group groups}
+    adjust' (SplitP TopP:r)  (HorizontalP tp bp _)     = HorizontalP (adjust' r tp) bp 0
+    adjust' (SplitP BottomP:r)  (HorizontalP tp bp _)  = HorizontalP tp (adjust' r bp) 0
+    adjust' (SplitP LeftP:r)  (VerticalP lp rp _)      = VerticalP (adjust' r lp) rp 0
+    adjust' (SplitP RightP:r)  (VerticalP lp rp _)     = VerticalP lp (adjust' r rp) 0
+    adjust' p l = error $"inconsistent layout (adjust) " ++ show p ++ " " ++ show l
+    adjustPaneGroupLayout p group = adjust' p group
+
+--
+-- | Get the widget from a list of strings
+--
+widgetFromPath :: Widget -> [String] -> IO (Widget)
+widgetFromPath w [] = return w
+widgetFromPath w path = do
+    children    <- containerGetChildren (castToContainer w)
+    chooseWidgetFromPath children path
+
+chooseWidgetFromPath :: [Widget] -> [String] -> IO (Widget)
+chooseWidgetFromPath _ [] = error $"Cant't find widget (empty path)"
+chooseWidgetFromPath widgets (h:t) = do
+    names       <- mapM widgetGetName widgets
+    let mbiInd  =  findIndex (== h) names
+    case mbiInd of
+        Nothing     -> error $"Cant't find widget path " ++ show (h:t) ++ " found only " ++ show names
+        Just ind    -> widgetFromPath (widgets !! ind) t
+
+widgetGet :: PaneMonad alpha => [String] -> (Widget -> b) -> alpha  (b)
+widgetGet strL cf = do
+    windows <- getWindowsSt
+    r <- liftIO $chooseWidgetFromPath (map castToWidget windows) strL
+    return (cf r)
+
+widgetGetRel :: Widget -> [String] -> (Widget -> b) -> IO (b)
+widgetGetRel w sl cf = do
+    r <- widgetFromPath w sl
+    return (cf r)
+
+getUIAction :: PaneMonad alpha => String -> (Action -> a) -> alpha (a)
+getUIAction str f = do
+    uiManager <- getUiManagerSt
+    liftIO $ do
+        findAction <- uiManagerGetAction uiManager str
+        case findAction of
+            Just act -> return (f act)
+            Nothing  -> error $"getUIAction can't find action " ++ str
+
+getThis :: PaneMonad delta =>  (FrameState delta -> alpha) -> delta alpha
+getThis sel = do
+    st <- getFrameState
+    return (sel st)
+setThis :: PaneMonad delta =>  (FrameState delta -> alpha -> FrameState delta) -> alpha -> delta ()
+setThis sel value = do
+    st <- getFrameState
+    trace ("!!! setFrameState " ++ show (sel st value)) $ setFrameState (sel st value)
+
+getWindowsSt    = getThis windows
+setWindowsSt    = setThis (\st value -> st{windows = value})
+getUiManagerSt  = getThis uiManager
+getPanesSt      =  getThis panes
+setPanesSt      = setThis (\st value -> st{panes = value})
+getPaneMapSt    = getThis paneMap
+setPaneMapSt    = setThis (\st value -> st{paneMap = value})
+getActivePaneSt = getThis activePane
+setActivePaneSt = setThis (\st value -> st{activePane = value})
+getLayoutSt     = getThis layout
+setLayoutSt     = setThis (\st value -> st{layout = value})
+getPanePathFromNB  = getThis panePathFromNB
+setPanePathFromNB  = setThis (\st value -> st{panePathFromNB = value})
+
+getActivePane   = getActivePaneSt
+setActivePane   = setActivePaneSt
+getUiManager    = getUiManagerSt
+getWindows      = getWindowsSt
+getMainWindow   = liftM head getWindows
+getLayout       = getLayoutSt
+
+castToNotebook' :: GObjectClass obj => String -> obj -> Notebook
+castToNotebook' str obj = if obj `isA` gTypeNotebook
+                            then castToNotebook obj
+                            else error ("Not a notebook " ++ str)
+
diff --git a/src/MyMissing.hs b/src/MyMissing.hs
new file mode 100644
--- /dev/null
+++ b/src/MyMissing.hs
@@ -0,0 +1,82 @@
+{-# OPTIONS_GHC -XScopedTypeVariables #-}
+-----------------------------------------------------------------------------
+--
+-- Module      :  MyMissing
+-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
+-- License     :  GNU-GPL
+--
+-- Maintainer  :  Juergen Nicklisch-Franken <info@leksah.org>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- | Module for missing base functions
+--
+------------------------------------------------------------------------------
+
+module MyMissing (
+    allOf
+,   forceJust
+,   forceHead
+,   split
+,   replace
+,   nonEmptyLines
+,   trim
+) where
+
+import Data.List (find,unfoldr)
+import Data.Maybe (isJust)
+import Data.Char (isSpace)
+
+
+-- | remove leading and trailing spaces
+trim :: String -> String
+trim      = f . f
+   where f = reverse . dropWhile isSpace
+
+nonEmptyLines :: String -> [String]
+nonEmptyLines = filter (\line -> isJust $ find (not . isSpace) line) . lines
+
+
+allOf :: forall alpha. (Bounded alpha, Enum alpha) =>  [alpha]
+allOf = map toEnum [fromEnum (minBound :: alpha) .. fromEnum (maxBound :: alpha)]
+
+-- ---------------------------------------------------------------------
+-- Convenience methods with error handling
+--
+forceJust :: Maybe alpha -> String -> alpha
+forceJust mb str = case mb of
+			Nothing -> error str
+			Just it -> it
+
+-- ---------------------------------------------------------------------
+-- Convenience methods with error handling
+--
+forceHead :: [alpha] -> String -> alpha
+forceHead (h:_) str = h
+forceHead [] str = error str
+
+
+-- ---------------------------------------------------------------------
+-- Splitting a string into parts based on a token delimiter
+--
+
+split :: Eq a => a -> [a] -> [[a]]
+split =  unfoldr . split'
+
+split' :: Eq a => a -> [a] -> Maybe ([a], [a])
+split' c l
+  | null l = Nothing
+  | otherwise = Just (h, drop 1 t)
+  where (h, t) = span (/=c) l
+
+-- ---------------------------------------------------------------------
+-- Simple replacement
+--
+
+replace :: Eq a => [a] -> [a] -> [a] -> [a]
+replace _ _ [] = []
+replace from to xs@(a:as) =
+    if isPrefixOf from xs
+        then to ++ replace from to (drop (length from) xs)
+        else a : replace from to as
+    where isPrefixOf as bs = and $ zipWith (== ) as bs
diff --git a/src/Text/PrinterParser.hs b/src/Text/PrinterParser.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrinterParser.hs
@@ -0,0 +1,244 @@
+{-# OPTIONS_GHC -XTypeSynonymInstances #-}
+--
+-- | Module for saving and restoring preferences and settings
+--
+
+module Text.PrinterParser (
+
+    Printer
+,   Parser
+,   FieldDescriptionS(..)
+,   MkFieldDescriptionS
+,   mkFieldS
+
+,   applyFieldParsers
+,   boolParser
+,   intParser
+,   lineParser
+,   pairParser
+,   identifier
+,   emptyParser
+,   whiteSpace
+,   stringParser
+,   readParser
+,   colorParser
+
+,   emptyPrinter
+,   Pretty(..)
+,   prettyPrint
+,   maybePP
+
+,   symbol
+,   colon
+
+,   writeFields
+,   showFields
+,   readFields
+,   parseFields
+) where
+
+import Text.ParserCombinators.Parsec.Language
+import qualified Text.ParserCombinators.Parsec.Token as P
+import Text.ParserCombinators.Parsec hiding(Parser)
+import qualified Text.PrettyPrint as PP
+
+import Graphics.UI.Editor.Parameters
+import Graphics.UI.Editor.Basics
+import Data.Maybe (listToMaybe)
+import Graphics.UI.Gtk (Color(..))
+import Data.List (foldl')
+import qualified Text.ParserCombinators.Parsec as  P
+    ((<?>), CharParser(..), parseFromFile)
+
+
+type Printer beta       =   beta -> PP.Doc
+type Parser beta        =   CharParser () beta
+
+-- ------------------------------------------------------------
+-- * Parsing with Parsec
+-- ------------------------------------------------------------
+
+data FieldDescriptionS alpha =  FDS {
+        parameters      ::  Parameters
+    ,   fieldPrinter    ::  alpha -> PP.Doc
+    ,   fieldParser     ::  alpha -> CharParser () alpha
+    }
+
+type MkFieldDescriptionS alpha beta =
+    Parameters ->
+    (Printer beta) ->
+    (Parser beta) ->
+    (Getter alpha beta) ->
+    (Setter alpha beta) ->
+    FieldDescriptionS alpha
+
+mkFieldS :: {--Eq beta =>--} MkFieldDescriptionS alpha beta
+mkFieldS parameter printer parser getter setter =
+    FDS parameter
+        (\ dat -> (PP.text (case getParameterPrim paraName parameter of
+                                    Nothing -> ""
+                                    Just str -> str) PP.<> PP.colon)
+                PP.$$ (PP.nest 15 (printer (getter dat)))
+                PP.$$ (PP.nest 5 (case getParameterPrim paraSynopsis parameter of
+                                    Nothing -> PP.empty
+                                    Just str -> PP.text $"--" ++ str)))
+        (\ dat -> try (do
+            symbol (case getParameterPrim paraName parameter of
+                                    Nothing -> ""
+                                    Just str -> str)
+            colon
+            val <- parser
+            return (setter val dat)))
+
+applyFieldParsers ::  a ->  [a ->  CharParser () a] ->  CharParser () a
+applyFieldParsers prefs parseF = do
+    eof
+    return (prefs)
+    <|> do
+    let parsers = map (\a ->  a prefs) parseF
+    newprefs <-  choice parsers
+    whiteSpace
+    applyFieldParsers newprefs parseF
+    <?> "field parser"
+
+boolParser ::  CharParser () Bool
+boolParser = do
+    (symbol "True" <|> symbol "true")
+    return True
+    <|> do
+    (symbol "False"<|> symbol "false")
+    return False
+    <?> "bool parser"
+
+
+readParser ::  Read a =>  CharParser () a
+readParser = do
+    str <- many (noneOf ['\n'])
+    if null str
+        then unexpected "read parser on empty string"
+        else do
+            case maybeRead str of
+                Nothing -> unexpected $ "read parser no parse " ++ str
+                Just r -> return r
+    <?> "read parser"
+        where maybeRead = listToMaybe . map fst . filter (null . snd) . reads
+
+pairParser ::  CharParser () alpha ->  CharParser () (alpha,alpha)
+pairParser p2 = do
+    char '('
+    v1 <-  p2
+    char ','
+    v2 <-  p2
+    char ')'
+    return (v1,v2)
+    <?> "pair parser"
+
+stringParser ::  CharParser () String
+stringParser = do
+    char '"'
+    str <- many (noneOf ['"'])
+    char '"'
+    return (str)
+    <?> "string parser"
+
+lineParser ::  CharParser () String
+lineParser = do
+    str <- many (noneOf ['\n'])
+    return (str)
+    <?> "line parser"
+
+
+intParser ::  CharParser () Int
+intParser = do
+    i <-  integer
+    return (fromIntegral i)
+
+colorParser :: CharParser () Color
+colorParser = do
+    string "Color"
+    whiteSpace
+    r <- integer
+    whiteSpace
+    g <- integer
+    whiteSpace
+    b <- integer
+    return $ Color (fromIntegral r) (fromIntegral g) (fromIntegral b)
+
+emptyParser ::  CharParser () ()
+emptyParser = pzero
+
+prefsStyle  ::  P.LanguageDef st
+prefsStyle  = emptyDef  {
+        P.commentStart   = "{-"
+    ,   P.commentEnd     = "-}"
+    ,   P.commentLine    = "--"
+    }
+
+lexer :: P.TokenParser st
+lexer = P.makeTokenParser prefsStyle
+
+whiteSpace :: CharParser st ()
+whiteSpace = P.whiteSpace lexer
+
+symbol :: String -> CharParser st String
+symbol = P.symbol lexer
+
+identifier, colon :: CharParser st String
+identifier = P.identifier lexer
+colon = P.colon lexer
+
+integer = P.integer lexer
+
+-- ------------------------------------------------------------
+-- * Printing
+-- ------------------------------------------------------------
+-- | pretty-print with the default style and 'defaultMode'.
+prettyPrint :: Pretty a => a -> String
+prettyPrint a = PP.renderStyle  PP.style (pretty a)
+
+-- | Things that can be pretty-printed
+class Pretty a where
+	-- | Pretty-print something in isolation.
+	pretty :: a -> PP.Doc
+	-- | Pretty-print something in a precedence context.
+	prettyPrec :: Int -> a -> PP.Doc
+	pretty = prettyPrec 0
+	prettyPrec _ = pretty
+	
+emptyPrinter ::  () ->  PP.Doc
+emptyPrinter _ = PP.empty
+
+maybePP :: (a -> PP.Doc) -> Maybe a -> PP.Doc
+maybePP _ Nothing = PP.empty
+maybePP pp (Just a) = pp a
+
+instance Pretty String where
+    pretty str = PP.text str
+
+-- ------------------------------------------------------------
+-- * Read and write
+-- ------------------------------------------------------------
+
+writeFields :: FilePath -> alpha -> [FieldDescriptionS alpha] -> IO ()
+writeFields fpath date dateDesc = writeFile fpath (showFields date dateDesc)
+
+showFields ::  alpha  -> [FieldDescriptionS alpha] ->  String
+showFields date dateDesc = PP.render $
+    foldl' (\ doc (FDS _ printer _) ->  doc PP.$+$ printer date) PP.empty dateDesc
+
+readFields :: FilePath -> [FieldDescriptionS alpha] -> alpha -> IO alpha
+readFields fn fieldDescrs defaultValue = catch (do
+    res <- P.parseFromFile (parseFields defaultValue fieldDescrs) fn
+    case res of
+                Left pe -> error $ "Error reading file " ++ show fn ++ " " ++ show pe
+                Right r -> return r)
+    (\ e -> error $ "Error reading file " ++ show fn ++ " " ++ show e)
+
+parseFields ::  alpha ->  [FieldDescriptionS alpha] ->  P.CharParser () alpha
+parseFields defaultValue descriptions =
+    let parsersF = map fieldParser descriptions in do
+        res <-  applyFieldParsers defaultValue parsersF
+        return res
+        P.<?> "prefs parser"
+
+
