]> git.saurik.com Git - wxWidgets.git/blobdiff - user/wxLayout/wxllist.cpp
some changes, untested
[wxWidgets.git] / user / wxLayout / wxllist.cpp
index c66496c0fee44eadaf5102c9786bec550fdcc11f..d0a3bc05a5aa59d8550c24e03c2a2393d82b3719 100644 (file)
 /*-*- c++ -*-********************************************************
  * wxllist: wxLayoutList, a layout engine for text and graphics     *
  *                                                                  *
- * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
+ * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net)            *
  *                                                                  *
  * $Id$
  *******************************************************************/
 
 /*
-  - each Object knows its size and how to draw itself
-  - the list is responsible for calculating positions
-  - the draw coordinates for each object are the top left corner
-  - coordinates only get calculated when things get redrawn
-  - The cursor position is the position before an object, i.e. if the
-    buffer starts with a text-object, cursor 0,0 is just before the
-    first character. For all non-text objects, the cursor positions
-    are 0==before or 1==behind. So that all non-text objects count as
-    one cursor position.
-  - Linebreaks are at the end of a line, that is a line like "abc\n"
-    is four cursor positions long. This makes sure that cursor
-    positions are "as expected", i.e. in "abc\ndef" the 'd' would be
-    at positions (x=0,y=1).
-*/
-
-/*
-  TODO:
-
-  - cursor redraw problems
-  - blinking cursor
-  - mouse click positions cursor
-  - selection (SetMark(), GetSelection())
-  - DND acceptance of text / clipboard support
-  - wxlwindow: formatting menu: problem with checked/unchecked consistency gtk bug?
-*/
-
-/*
-  Known wxGTK bugs:
-  - MaxX()/MaxY() don't get set
-*/
-
+  
+ */
  
 #ifdef __GNUG__
 #pragma implementation "wxllist.h"
 #endif
 
-//#include "Mpch.h"
+#include "Mpch.h"
+
+
+#include "wx/wxprec.h"
+#ifdef __BORLANDC__
+#  pragma hdrstop
+#endif
+
 #ifdef M_BASEDIR
 #   include "gui/wxllist.h"
+#   define  SHOW_SELECTIONS 1
 #else
 #   include "wxllist.h"
+#   include "wxlparser.h"
+#   define SHOW_SELECTIONS 1
 #endif
 
 #ifndef USE_PCH
 #   include   "iostream.h"
 #   include   <wx/dc.h>
-#   include   <wx/postscrp.h>
+#   include   <wx/dcps.h>
 #   include   <wx/print.h>
 #   include   <wx/log.h>
 #endif
 
-#define   BASELINESTRETCH   12
+#include <ctype.h>
 
-// This should never really get created
+/// This should never really get created
 #define   WXLLIST_TEMPFILE   "__wxllist.tmp"
 
 #ifdef WXLAYOUT_DEBUG
-static const char *g_aTypeStrings[] = 
-{ 
-   "invalid", "text", "cmd", "icon", "linebreak"
-};
-   
-#  define   wxLayoutDebug        wxLogDebug
-#  define   WXL_VAR(x)           cerr << #x " = " << x << endl;
-#  define   WXL_DBG_POINT(p)     wxLayoutDebug(#p ": (%d, %d)", p.x, p.y)
-#  define   WXL_TRACE(f)         wxLayoutDebug(#f ": ")
-#  define   TypeString(t)        g_aTypeStrings[t]
 
-void
-wxLayoutObjectBase::Debug(void)
+#  define   TypewxString(t)        g_aTypewxStrings[t]
+#  define   WXLO_DEBUG(x)      wxLogDebug x
+
+   static const char *g_aTypewxStrings[] = 
+   { 
+      "invalid", "text", "cmd", "icon"
+   };
+   void
+   wxLayoutObject::Debug(void)
+   {
+      WXLO_DEBUG(("%s",g_aTypewxStrings[GetType()])); 
+   }
+#else 
+#  define   TypewxString(t)        ""
+#  define   WXLO_DEBUG(x)      
+#endif
+
+
+/// Cursors smaller than this disappear in XOR drawing mode
+#define WXLO_MINIMUM_CURSOR_WIDTH   4
+
+/// Use this character to estimate a cursor size when none is available.
+#define WXLO_CURSORCHAR   "E"
+/** @name Helper functions */
+//@{
+/// allows me to compare to wxPoints
+bool operator ==(wxPoint const &p1, wxPoint const &p2)
 {
-   CoordType bl = 0;
-   wxLayoutDebug("%s: size = %dx%d, pos=%d,%d, bl = %d",
-                 TypeString(GetType()), GetSize(&bl).x,
-                 GetSize(&bl).y,
-                 GetPosition().x, GetPosition().y, bl); 
+   return p1.x == p2.x && p1.y == p2.y;
 }
 
-#else 
-#  define   WXL_VAR(x)   
-#  define   WXL_DBG_POINT(p)   
-#  define   WXL_TRACE(f)
-#  define   ShowCurrentObject()
-#  define   TypeString(t)        ""
-inline void wxLayoutDebug(const char *, ...) { }
+/// allows me to compare to wxPoints
+bool operator !=(wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.x != p2.x || p1.y != p2.y;
+}
+
+/// allows me to compare to wxPoints
+bool operator <=(wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.y < p2.y || (p1.y == p2.y && p1.x <= p2.x);
+}
+
+/// grows a wxRect so that it includes the given point
+
+static
+void GrowRect(wxRect &r, CoordType x, CoordType y)
+{
+   if(r.x > x)
+      r.x = x;
+   else if(r.x + r.width < x)
+      r.width = x - r.x;
+   
+   if(r.y > y)
+      r.y = y;
+   else if(r.y + r.height < y)
+      r.height = y - r.y;
+}
+
+#if 0
+// unused
+/// returns true if the point is in the rectangle
+static
+bool Contains(const wxRect &r, const wxPoint &p)
+{
+   return r.x <= p.x && r.y <= p.y && (r.x+r.width) >= p.x && (r.y + r.height) >= p.y;
+}
 #endif
 
 
-//-------------------------- wxLayoutObjectText
+//@}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectText
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-wxLayoutObjectText::wxLayoutObjectText(const String &txt)
+wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
 {
    m_Text = txt;
    m_Width = 0;
    m_Height = 0;
-   m_Position = wxPoint(-1,-1);
+   m_Top = 0;
+   m_Bottom = 0;
 }
 
+wxLayoutObject *
+wxLayoutObjectText::Copy(void)
+{
+   wxLayoutObjectText *obj = new wxLayoutObjectText(m_Text);
+   obj->m_Width = m_Width;
+   obj->m_Height = m_Height;
+   obj->m_Top = m_Top;
+   obj->m_Bottom = m_Bottom;
+   obj->SetUserData(m_UserData);
+   return obj;
+}
 
 wxPoint
-wxLayoutObjectText::GetSize(CoordType *baseLine) const
+wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
 {
-   if(baseLine) *baseLine = m_BaseLine;
+
+   *top = m_Top; *bottom = m_Bottom;
    return wxPoint(m_Width, m_Height);
 }
 
 void
-wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &translate)
+wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords,
+                         wxLayoutList *wxllist,
+                         CoordType begin, CoordType end)
 {
-   dc.DrawText(Str(m_Text), m_Position.x + translate.x, m_Position.y+translate.y);
-   m_IsDirty = false;
+   if(begin == -1)
+      dc.DrawText(m_Text, coords.x, coords.y-m_Top);
+   else
+   {
+      // highlight the bit between begin and len
+      wxString str;
+      CoordType
+         xpos = coords.x,
+         ypos = coords.y-m_Top;
+      long width, height, descent;
+      
+      str = m_Text.Mid(0, begin);
+      dc.DrawText(str, xpos, ypos);
+      dc.GetTextExtent(str, &width, &height, &descent);
+      xpos += width;
+      wxllist->StartHighlighting(dc);
+      str = m_Text.Mid(begin, end-begin);
+      dc.DrawText(str, xpos, ypos);
+      dc.GetTextExtent(str, &width, &height, &descent);
+      xpos += width;
+      wxllist->EndHighlighting(dc);
+      str = m_Text.Mid(end, m_Text.Length()-end);
+      dc.DrawText(str, xpos, ypos);
+   }
 }
 
+CoordType
+wxLayoutObjectText::GetOffsetScreen(wxDC &dc, CoordType xpos) const
+{
+   CoordType
+      offs = 1,
+      maxlen = m_Text.Length();
+   long
+      width = 0,
+      height, descent = 0l;
+
+   if(xpos == 0) return 0; // easy
+   
+   while(width < xpos && offs < maxlen)
+   {
+      dc.GetTextExtent(m_Text.substr(0,offs),
+                       &width, &height, &descent);
+      offs++;
+   }
+   /* We have to substract 1 to compensate for the offs++, and another 
+      one because we don't want to position the cursor behind the
+      object what we clicked on, but before - otherwise it looks
+      funny. */
+   return (xpos > 2) ? offs-2 : 0;  
+}
 
 void
-wxLayoutObjectText::Layout(wxDC &dc, wxPoint position, CoordType baseLine)
+wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList * )
 {
    long descent = 0l;
 
-   if(m_Position.x != position.x || m_Position.y != position.y)
-      m_IsDirty = true;
-   
-   m_Position = position;
-   dc.GetTextExtent(Str(m_Text),&m_Width, &m_Height, &descent);
-   m_BaseLine = m_Height - descent;
-   if(m_Position.x != position.x || m_Position.y != position.y)
-      m_IsDirty = true;
+   dc.GetTextExtent(m_Text,&m_Width, &m_Height, &descent);
+   m_Bottom = descent;
+   m_Top = m_Height - m_Bottom;
 }
 
 #ifdef WXLAYOUT_DEBUG
 void
 wxLayoutObjectText::Debug(void)
 {
-   wxLayoutObjectBase::Debug();
-   wxLayoutDebug(" `%s`", m_Text.c_str());
+   wxLayoutObject::Debug();
+   WXLO_DEBUG((" `%s`", m_Text.c_str()));
 }
 #endif
 
-//-------------------------- wxLayoutObjectIcon
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectIcon
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon const &icon)
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
 {
-   m_Position = wxPoint(-1,-1);
-   m_Icon = new wxIcon(icon);
+   m_Icon = new wxBitmap(icon);
 }
 
-wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
+wxLayoutObject *
+wxLayoutObjectIcon::Copy(void)
+{
+   wxLayoutObjectIcon *obj = new wxLayoutObjectIcon(new
+                                                    wxBitmap(*m_Icon));
+   obj->SetUserData(m_UserData);
+   return obj;
+}
+
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
 {
    m_Icon = icon;
 }
 
 void
-wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &translate)
+wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords,
+                         wxLayoutList *wxllist,
+                         CoordType begin, CoordType /* len */)
 {
-   dc.DrawIcon(m_Icon,wxPoint(m_Position.x+translate.x, m_Position.y+translate.y));
+   dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight(),
+                 (m_Icon->GetMask() == NULL) ? FALSE : TRUE);
 }
 
 void
-wxLayoutObjectIcon::Layout(wxDC &dc, wxPoint position, CoordType baseLine)
+wxLayoutObjectIcon::Layout(wxDC & /* dc */, class wxLayoutList * )
 {
-   if(m_Position.x != position.x || m_Position.y != position.y)
-      m_IsDirty = true;
-   m_Position = position;
 }
 
 wxPoint
-wxLayoutObjectIcon::GetSize(CoordType *baseLine) const
+wxLayoutObjectIcon::GetSize(CoordType *top, CoordType *bottom) const
 {
-   if(baseLine)   *baseLine = m_Icon->GetHeight();
+   *top = m_Icon->GetHeight();
+   *bottom = 0;
    return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
 }
 
-//-------------------------- wxLayoutObjectCmd
 
 
-wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
-                                     weight, bool underline,
-                                     wxColour const *fg, wxColour const *bg)
-   
-{
-   m_font = new wxFont(size,family,style,weight,underline);
-   m_ColourFG = fg;
-   m_ColourBG = bg;
-}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 
-wxLayoutObjectCmd::~wxLayoutObjectCmd()
+   wxLayoutObjectCmd
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily,
+                                     int isize,
+                                     int istyle,
+                                     int iweight,
+                                     int iul,
+                                     wxColour *fg,
+                                     wxColour *bg)
 {
-   delete m_font;
+   family = ifamily; size = isize;
+   style = istyle; weight = iweight;
+   underline = iul;
+   if(fg)
+   {
+      fg_valid = true;
+      fg_red = fg->Red();
+      fg_blue = fg->Blue();
+      fg_green = fg->Green();
+   }
+   else
+      fg_valid = false;
+   if(bg)
+   {
+      bg_valid = true;
+      bg_red = bg->Red();
+      bg_blue = bg->Blue();
+      bg_green = bg->Green();
+   }
+   else
+      bg_valid = false;
 }
 
-wxLayoutStyleInfo *
-wxLayoutObjectCmd::GetStyle(void) const
-{
-   wxLayoutStyleInfo *si = new wxLayoutStyleInfo();
+#define SET_SI(what) tmp.what = (what != -1) ? what : ( si ? si->what : wxNORMAL);
 
 
-   si->size = m_font->GetPointSize();
-   si->family = m_font->GetFamily();
-   si->style = m_font->GetStyle();
-   si->underline = m_font->GetUnderlined();
-   si->weight = m_font->GetWeight();
+wxFont *
+wxLayoutStyleInfo::GetFont(wxLayoutStyleInfo *si)
+{
+   wxLayoutStyleInfo tmp;
+   
+   SET_SI(family);
+   SET_SI(size);
+   SET_SI(style);
+   SET_SI(weight);
+   SET_SI(underline);
 
-   si->fg_red = m_ColourFG->Red();
-   si->fg_green = m_ColourFG->Green();
-   si->fg_blue = m_ColourFG->Blue();
-   si->bg_red = m_ColourBG->Red();
-   si->bg_green = m_ColourBG->Green();
-   si->bg_blue = m_ColourBG->Blue();
+   return new wxFont(tmp.size,tmp.family,tmp.style,tmp.weight,tmp.underline);
 
-   return si;
 }
 
-void
-wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const &translate)
+wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
+                                     weight, int underline,
+                                     wxColour *fg, wxColour *bg)
+   
 {
-   wxASSERT(m_font);
-   dc.SetFont(*m_font);
-   if(m_ColourFG)
-      dc.SetTextForeground(*m_ColourFG);
-   if(m_ColourBG)
-      dc.SetTextBackground(*m_ColourBG);
+   m_StyleInfo = new
+      wxLayoutStyleInfo(size,family,style,weight,underline,fg,bg);
+   m_font = NULL;
 }
-void
-wxLayoutObjectCmd::Layout(wxDC &dc, wxPoint p, CoordType baseline)
+
+wxLayoutObject *
+wxLayoutObjectCmd::Copy(void)
 {
-   m_Position = p; // required so we can find the right object for cursor
-   // this get called, so that recalculation uses right font sizes
-   Draw(dc,wxPoint(0,0));
+   wxColour
+      * fg = NULL,
+      * bg = NULL;
+   if(m_StyleInfo->fg_valid)
+      fg = new
+         wxColour(m_StyleInfo->fg_red,m_StyleInfo->fg_green,m_StyleInfo->fg_blue);
+   if(m_StyleInfo->bg_valid)
+      bg = new
+         wxColour(m_StyleInfo->bg_red,m_StyleInfo->bg_green,m_StyleInfo->bg_blue);
+   
+   wxLayoutObjectCmd *obj = new wxLayoutObjectCmd(
+      m_StyleInfo->size,
+      m_StyleInfo->family,
+      m_StyleInfo->style,
+      m_StyleInfo->weight,
+      m_StyleInfo->underline,
+      fg, bg);
+   obj->SetUserData(m_UserData);
+
+   if(fg) delete fg;
+   if(bg) delete bg;
+   return obj;
 }
 
-//-------------------------- wxLayoutList
 
-wxLayoutList::wxLayoutList()
+wxLayoutObjectCmd::~wxLayoutObjectCmd()
 {
-   m_DefaultSetting = NULL;
-   m_WrapMargin = -1;
-   m_Editable = FALSE;
-
-   Clear();
+   delete m_StyleInfo;
+   if(m_font) delete m_font;
 }
 
-wxLayoutList::~wxLayoutList()
+wxLayoutStyleInfo *
+wxLayoutObjectCmd::GetStyle(void) const
 {
-   if(m_DefaultSetting)
-      delete m_DefaultSetting;
-   // no deletion of objects, they are owned by the list
+   return m_StyleInfo;
 }
 
 void
-wxLayoutList::LineBreak(void)
+wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */,
+                        wxLayoutList *wxllist,
+                        CoordType begin, CoordType /* len */)
 {
-   Insert(new wxLayoutObjectLineBreak);
-//   m_CursorPos.x = 0; m_CursorPos.y++;
+   wxASSERT(m_StyleInfo);
+   dc.SetFont(*m_font);
+   wxllist->ApplyStyle(m_StyleInfo, dc);
 }
 
 void
-wxLayoutList::SetFont(int family, int size, int style, int weight,
-                      int underline, wxColour const *fg,
-                      wxColour const *bg)
+wxLayoutObjectCmd::Layout(wxDC &dc, class wxLayoutList * llist)
 {
-   if(family != -1)    m_FontFamily = family;
-   if(size != -1)      m_FontPtSize = size;
-   if(style != -1)     m_FontStyle = style;
-   if(weight != -1)    m_FontWeight = weight;
-   if(underline != -1) m_FontUnderline = underline != 0;
+   if(m_font) delete m_font;
+   m_font = m_StyleInfo->GetFont(llist->GetStyleInfo());
 
-   if(fg != NULL)     m_ColourFG = fg;
-   if(bg != NULL)     m_ColourBG = bg;
-   
-   Insert(
-      new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
-                            m_ColourFG, m_ColourBG));
+
+   // this get called, so that recalculation uses right font sizes
+   Draw(dc, wxPoint(0,0), llist);
 }
 
-void
-wxLayoutList::SetFont(int family, int size, int style, int weight,
-                      int underline, char const *fg, char const *bg)
 
-{
-   wxColour const
-      * cfg = NULL,
-      * cbg = NULL;
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 
-   if( fg )
-      cfg = wxTheColourDatabase->FindColour(fg);
-   if( bg )
-      cbg = wxTheColourDatabase->FindColour(bg);
-   
-   SetFont(family,size,style,weight,underline,cfg,cbg);
-}
+   The wxLayoutLine object
 
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-/// for access by wxLayoutWindow:
-void
-wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y,
-                      CoordType *lineHeight)
+wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
 {
-   
-   if(max_x) *max_x = m_MaxX;
-   if(max_y) *max_y = m_MaxY;
-   if(lineHeight) *lineHeight = m_LineHeight;
+   m_LineNumber = 0;
+   m_Width = m_Height = 0;
+   m_Length = 0;
+   m_Dirty = true;
+   m_Previous = prev;
+   m_Next = NULL;
+   RecalculatePosition(llist);
+   if(m_Previous)
+   {
+      m_LineNumber = m_Previous->GetLineNumber()+1;
+      m_Next = m_Previous->GetNextLine();
+      m_Previous->m_Next = this;
+      m_Height = m_Previous->GetHeight();
+   }
+   if(m_Next)
+   {
+      m_Next->m_Previous = this;
+      m_Next->MoveLines(+1);
+      m_Next->RecalculatePositions(1,llist);
+   }
 }
 
-void
-wxLayoutList::ResetSettings(wxDC &dc)
+wxLayoutLine::~wxLayoutLine()
 {
-   // setting up the default:
-   dc.SetTextForeground( *wxBLACK );
-   dc.SetTextBackground( *wxWHITE );
-   dc.SetBackgroundMode( wxSOLID ); // to enable setting of text background
-   dc.SetFont( *wxNORMAL_FONT );
-   if(m_DefaultSetting)
-      m_DefaultSetting->Draw(dc,wxPoint(0,0));
+   // kbList cleans itself
 }
 
-void
-wxLayoutList::Layout(wxDC &dc, wxLayoutMargins *margins)
+wxPoint
+wxLayoutLine::RecalculatePosition(wxLayoutList *llist)
 {
-   iterator i;
+   wxASSERT(m_Previous || GetLineNumber() == 0);
 
-   // first object in current line
-   wxLayoutObjectList::iterator headOfLine;
-   // where we draw next
-   wxPoint position, position_HeadOfLine;
-   // size of last object
-   wxPoint size;
-   CoordType baseLine = m_FontPtSize;
-   CoordType baseLineSkip = (BASELINESTRETCH * baseLine)/10;
-   CoordType objBaseLine = baseLine;
-   wxLayoutObjectType type;
-   
-   // we need to count cursor positions
-   wxPoint cursorPos = wxPoint(0,0);
-   
-   if(margins)
+   if(m_Previous)
    {
-      position.y = margins->top;
-      position.x = margins->left;
+      m_Position = m_Previous->GetPosition();
+      m_Position.y += m_Previous->GetHeight();
    }
    else
+      m_Position = wxPoint(0,0);
+   llist->SetUpdateRect(m_Position);
+   return m_Position;
+}
+
+void
+wxLayoutLine::RecalculatePositions(int recurse, wxLayoutList *llist)
+{
+   wxASSERT(recurse >= 0);
+   wxPoint pos = m_Position;
+   CoordType height = m_Height;
+   
+//   WXLO_TRACE("RecalculatePositions()");
+   RecalculatePosition(llist);
+   if(m_Next)
    {
-      position.y = 0;
-      position.x = 0;
+      if(recurse > 0)
+         m_Next->RecalculatePositions(--recurse, llist);
+      else if(pos != m_Position || m_Height != height)
+         m_Next->RecalculatePositions(0, llist);         
    }
-   
-   ResetSettings(dc);
-   
-   i = begin();
-   headOfLine = i;
-   position_HeadOfLine = position;
+}
 
-   do
-   {
-      if(i == end())
-         return;
-   
-      type = (*i)->GetType();
-      (*i)->Layout(dc, position, baseLine);
-      size = (*i)->GetSize(&objBaseLine);
-      // calculate next object's position:
-      position.x += size.x;
+wxLayoutObjectList::iterator
+wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const
+{
+   wxASSERT(xpos >= 0);
+   wxASSERT(offset);
+   wxLayoutObjectList::iterator
+      i,
+      found = NULLIT;
+   CoordType x = 0, len;
    
-      // do we need to increase the line's height?
-      if(size.y > baseLineSkip)
-      {
-         baseLineSkip = size.y;
-         i = headOfLine; position = position_HeadOfLine;
-         continue;
-      }
-      if(objBaseLine > baseLine)
-      {
-         baseLine = objBaseLine;
-         i = headOfLine; position = position_HeadOfLine;
-         continue;
-      }
-
-      // when we reach here, the coordinates are valid, this part of
-      // the loop gets run only once per object
-      if(position.x > m_MaxX)
-         m_MaxX = position.x;
-      if(type == WXLO_TYPE_LINEBREAK)
-      {
-         cursorPos.x = 0; cursorPos.y ++;
-      }
-      else
-         cursorPos.x += (**i).CountPositions();
-      
-      // now check whether we have finished handling this line:
-      if(type == WXLO_TYPE_LINEBREAK && i != tail()) 
+   /* We search through the objects. As we don't like returning the
+      object that the cursor is behind, we just remember such an
+      object in "found" so we can return it if there is really no
+      further object following it. */
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      len = (**i).GetLength();
+      if( x <= xpos && xpos <= x + len )
       {
-         position.x = margins ? margins->left : 0;
-         position.y += baseLineSkip;
-         baseLine = m_FontPtSize;
-         objBaseLine = baseLine; // not all objects set it
-         baseLineSkip = (BASELINESTRETCH * baseLine)/10;
-         headOfLine = i;
-         headOfLine++;
-         position_HeadOfLine = position;
+         *offset = xpos-x;
+         if(xpos == x + len) // is there another object behind?
+            found = i;
+         else  // we are really inside this object
+            return i;
       }
-      if(i == m_CursorObject)
-         CalculateCursor(dc);
-      i++;
+      x += (**i).GetLength();
    }
-   while(i != end());
-   m_MaxY = position.y + baseLineSkip;
+   return found;  // ==NULL if really none found
 }
 
-void
-wxLayoutList::Draw(wxDC &dc,
-                   CoordType fromLine, CoordType toLine,
-                   iterator start,
-                   wxPoint const &translate)
+wxLayoutObjectList::iterator
+wxLayoutLine::FindObjectScreen(wxDC &dc,
+                               CoordType xpos, CoordType *cxpos,
+                               bool *found) const
 {
-   Layout(dc); // FIXME just for now
-
-   ResetSettings(dc);
-
+   wxASSERT(cxpos);
+   wxASSERT(cxpos);
    wxLayoutObjectList::iterator i;
+   CoordType x = 0, cx = 0, width;
    
-   if(start == iterator(NULL))
-      start = begin();
-   else // we need to restore font settings
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      for( i = begin() ; i != start; i++)
-         if((**i).GetType() == WXLO_TYPE_CMD)
-            (**i).Draw(dc,translate);  // apply font settings
-   }
-      
-   while( start != end() && (**start).GetPosition().y < fromLine)
-   {
-      if((**start).GetType() == WXLO_TYPE_CMD)
-         (**start).Draw(dc,translate);  // apply font settings
-      start++;
+//FIXME!      (**i).Layout(dc, NULL);
+      width = (**i).GetWidth();
+      if( x <= xpos && xpos <= x + width )
+      {
+         *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
+//         WXLO_DEBUG(("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos));
+         if(found) *found = true;
+         return i;
+      }
+      x += (**i).GetWidth();
+      cx += (**i).GetLength();
    }
-   for( i = start ;
-        i != end() && (toLine == -1 || (**i).GetPosition().y < toLine) ;
-        i++ )
-      (*i)->Draw(dc,translate);
+   // behind last object:
+   *cxpos = cx;
+   if(found) *found = false;
+   return m_ObjectList.tail();
 }
 
-/** Erase at least to end of line */
-void
-wxLayoutList::EraseAndDraw(wxDC &dc, iterator start)
-{
-   //look for begin of line
-   while(start != end() && start != begin() && (**start).GetType() !=
-         WXLO_TYPE_LINEBREAK)
-      start--;
-   if(start == iterator(NULL))
-      start = begin();
-   if(start == iterator(NULL))
-      return;
+/** Finds text in this line.
+    @param needle the text to find
+    @param xpos the position where to start the search
+    @return the cursoor coord where it was found or -1
+*/
+CoordType
+wxLayoutLine::FindText(const wxString &needle, CoordType xpos = 0) const
+{
+   int
+      cpos = 0,
+      relpos = -1;
+   wxString const *text;
    
-   wxPoint p = (**start).GetPosition();
-
-   //FIXME: wxGTK: MaxX()/MaxY() broken
-   //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY());
-
-   dc.SetBrush(wxBrush(*m_ColourBG, wxSOLID));
-   dc.SetPen(wxPen(*m_ColourBG,0,wxTRANSPARENT));
-   dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
-   Draw(dc,-1,-1,start,wxPoint(0,0));
-   //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
+   for(wxLOiterator i = m_ObjectList.begin(); i != m_ObjectList.end(); i++)
+   {
+      if(cpos >= xpos) // search from here!
+      {
+         if((**i).GetType() == WXLO_TYPE_TEXT)
+         {
+            text = & ((wxLayoutObjectText*)(*i))->GetText();
+            relpos = text->Find(needle);
+            if(relpos >= cpos-xpos) // -1 if not found
+            {
+               return cpos+relpos;
+            }
+         }
+         cpos += (**i).GetLength();
+      }
+   }
+   return -1; // not found
 }
 
-
-void
-wxLayoutList::CalculateCursor(wxDC &dc)
+bool
+wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
 {
-   CoordType width, height, descent;
-   CoordType baseLineSkip = 20; //FIXME
-
-   if( m_CursorObject == iterator(NULL))  // empty list
+   wxASSERT(xpos >= 0);
+   wxASSERT(obj != NULL);
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i == NULLIT)
    {
-      m_CursorCoords = wxPoint(0,0);
-      m_CursorSize = wxPoint(2,baseLineSkip);
-      m_CursorMoved = false; // coords are valid
-      return;
+      if(xpos == 0 ) // aha, empty line!
+      {
+         m_ObjectList.push_back(obj);
+         m_Length += obj->GetLength();
+         return true;
+      }
+      else
+         return false;
    }
-   wxLayoutObjectBase &obj = **m_CursorObject;
 
-   m_CursorCoords = obj.GetPosition();
-   if(obj.GetType() == WXLO_TYPE_TEXT)
-   {
-      wxLayoutObjectText *tobj = (wxLayoutObjectText *)&obj;
-      String & str = tobj->GetText();
-      String sstr = str.substr(0,m_CursorOffset);
-      dc.GetTextExtent(sstr,&width,&height,&descent);
-      m_CursorCoords = wxPoint(m_CursorCoords.x+width,
-                               m_CursorCoords.y);
-      m_CursorSize = wxPoint(2,height);
-   }
-   else if(obj.GetType() == WXLO_TYPE_LINEBREAK)
-   {
-      if(m_CursorOffset == 1) // behind linebreak
-         m_CursorCoords = wxPoint(0, m_CursorCoords.y + baseLineSkip);
-      //m_CursorCoords = wxPoint(0, m_CursorCoords.y);
-      m_CursorSize = wxPoint(2,baseLineSkip);
+   CoordType len = (**i).GetLength();
+   if(offset == 0 /*&& i != m_ObjectList.begin()*/) // why?
+   {  // insert before this object
+      m_ObjectList.insert(i,obj);
+      m_Length += obj->GetLength();
+      return true;
    }
-   else
+   if(offset == len )
    {
-      // this is not necessarily the most "beautiful" solution:
-      //cursorPosition = wxPoint(position.x, position.y);
-      //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
-      m_CursorCoords = wxPoint(m_CursorCoords.x+obj.GetSize().x, m_CursorCoords.y);
-      m_CursorSize = wxPoint(2, obj.GetSize().y);
-      if(m_CursorSize.y < 1) m_CursorSize.y = baseLineSkip;
+      if( i == m_ObjectList.tail()) // last object?
+         m_ObjectList.push_back(obj);
+      else
+      {  // insert after current object
+         i++;
+         m_ObjectList.insert(i,obj);
+      }
+         m_Length += obj->GetLength();
+      return true;
    }
-   m_CursorMoved = false; // coords are valid
+   /* Otherwise we need to split the current object.
+      Fortunately this can only be a text object. */
+   wxASSERT((**i).GetType() == WXLO_TYPE_TEXT);
+   wxString left, right;
+   wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+   left = tobj->GetText().substr(0,offset);
+   right = tobj->GetText().substr(offset,len-offset);
+   // current text object gets set to right half
+   tobj->GetText() = right; // set new text
+   // before it we insert the new object
+   m_ObjectList.insert(i,obj);
+   m_Length += obj->GetLength();
+   // and before that we insert the left half
+   m_ObjectList.insert(i,new wxLayoutObjectText(left));
+   return true;
 }
-
-void
-wxLayoutList::DrawCursor(wxDC &dc, bool erase)
-{
-   if(! m_Editable)
-      return;
    
-   if(erase)
+bool
+wxLayoutLine::Insert(CoordType xpos, wxString text)
+{
+   wxASSERT(xpos >= 0);
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
    {
-      //dc.SetBrush(*wxWHITE_BRUSH);
-      //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
-      //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y);
-      dc.Blit(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x,
-              m_CursorSize.y, &m_CursorMemDC,
-              0, 0, 0, 0);
+      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+      tobj->GetText().insert(offset, text);
+      m_Length += text.Length();
+
+      return true;
    }
    else
+      return Insert(xpos, new wxLayoutObjectText(text));
+}
+
+CoordType
+wxLayoutLine::Delete(CoordType xpos, CoordType npos)
+{
+   CoordType offset, len;
+
+   wxASSERT(xpos >= 0);
+   wxASSERT(npos >= 0);
+   wxLOiterator i = FindObject(xpos, &offset);
+   while(npos > 0)
    {
-      if(IsDirty() || CursorMoved())
+      if(i == NULLIT)  return npos;
+      // now delete from that object:
+      if((**i).GetType() != WXLO_TYPE_TEXT)
       {
-         DrawCursor(dc,true);
-         Layout(dc);
+         if(offset != 0) // at end of line after a non-text object
+            return npos;
+         // always len == 1:
+         len = (**i).GetLength();
+         m_Length -= len;
+         npos -= len;
+         m_ObjectList.erase(i);
+      }
+      else
+      {
+         // tidy up: remove empty text objects
+         if((**i).GetLength() == 0)
+         {
+            m_ObjectList.erase(i);
+            continue;
+         }
+         // Text object:
+         CoordType max = (**i).GetLength() - offset;
+         if(npos < max) max = npos;
+         if(max == 0)
+         {
+            if(xpos == GetLength())
+               return npos;
+            else 
+            {  // at    the end of an object
+               // move to    begin of next object:
+               i++; offset = 0;
+               continue; // start over
+            }
+         }
+         npos -= max;
+         m_Length -= max;
+         if(offset == 0 && max == (**i).GetLength())
+            m_ObjectList.erase(i);  // remove the whole object
+         else
+            ((wxLayoutObjectText *)(*i))->GetText().Remove(offset,max);
       }
-      // Save background:
-      wxBitmap bm(m_CursorSize.x+1,m_CursorSize.y+1);
-      m_CursorMemDC.SelectObject(bm);
-      m_CursorMemDC.Blit(0, 0, m_CursorSize.x, m_CursorSize.y,
-                         &dc, m_CursorCoords.x,
-                         m_CursorCoords.y, 0, 0);
-      dc.SetBrush(*wxBLACK_BRUSH);
-      dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
-      dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y,
-                       m_CursorSize.x, m_CursorSize.y);
    }
+   return npos;
 }
 
-
-
-
-
-
-
-#ifdef WXLAYOUT_DEBUG
-void
-wxLayoutList::Debug(void)
+bool
+wxLayoutLine::DeleteWord(CoordType xpos)
 {
-   wxLayoutObjectList::iterator i;
+   wxASSERT(xpos >= 0);
+   CoordType offset;
 
-   wxLayoutDebug("------------------------ debug start ------------------------"); 
-   for(i = begin(); i != end(); i++)
-      (*i)->Debug();
-   wxLayoutDebug("-------------------------- list end -------------------------");
-   
-   // show current object:
-   ShowCurrentObject();
-   wxLayoutDebug("------------------------- debug end -------------------------");
-}
+   wxLOiterator i = FindObject(xpos, &offset);
 
-void
-wxLayoutList::ShowCurrentObject()
-{
-   wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos.x, (int) m_CursorPos.y);
-   wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset);
-   wxLayoutDebug("CursorObject = %p", m_CursorObject);
-   if(m_CursorObject == iterator(NULL))
-      wxLayoutDebug("<<no object found>>");
-   else
+   for(;;)
    {
-      if((*m_CursorObject)->GetType() == WXLO_TYPE_TEXT)
-         wxLayoutDebug(" \"%s\", offs: %d",
-                       ((wxLayoutObjectText *)(*m_CursorObject))->GetText().c_str(),
-                       m_CursorOffset);
+      if(i == NULLIT) return false;
+      if((**i).GetType() != WXLO_TYPE_TEXT)
+      {
+         // This should only happen when at end of line, behind a non-text 
+         // object:
+         if(offset == (**i).GetLength()) return false;
+         m_Length -= (**i).GetLength(); // -1
+         m_ObjectList.erase(i);
+         return true; // we are done
+      }
       else
-         wxLayoutDebug(" %s", TypeString((*m_CursorObject)->GetType()));
+      {  // text object:
+         if(offset == (**i).GetLength()) // at end of object
+         {
+            i++; offset = 0;
+            continue;
+         }
+         wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+         size_t count = 0;
+         wxString str = tobj->GetText();
+         str = str.substr(offset,str.Length()-offset);
+         // Find out how many positions we need to delete:
+         // 1. eat leading space
+         while(isspace(str.c_str()[count])) count++;
+         // 2. eat the word itself:
+         while(isalnum(str.c_str()[count])) count++;
+         // now delete it:
+         wxASSERT(count+offset <= (size_t) (**i).GetLength());
+         ((wxLayoutObjectText *)*i)->GetText().erase(offset,count);
+         m_Length -= count;
+         return true;
+      }      
    }
-   wxLayoutDebug("Line length: %d", GetLineLength(m_CursorObject));
-
+   wxASSERT(0); // we should never arrive here
 }
 
-#endif
-
-/******************** editing stuff ********************/
-
-// don't change this, I know how to optimise this and will do it real 
-// soon (KB)
-
-/*
- * FindObjectCursor:
- * Finds the object belonging to a given cursor position cpos and
- * returns an iterator to that object and stores the relative cursor
- * position in offset.
- *
- * For linebreaks, the offset can be 0=before or 1=after.
- *
- * If the cpos coordinates don't exist, they are modified.
- */
+wxLayoutLine *
+wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist)
+{
+   if(m_Next) m_Next->m_Previous = m_Previous;
+   if(m_Previous) m_Previous->m_Next = m_Next;
+   if(update)
+   {
+      m_Next->MoveLines(-1);
+      m_Next->RecalculatePositions(1, llist);
+   }
+   wxLayoutLine *next = m_Next;
+   delete this;
+   return next;
+}
 
-wxLayoutObjectList::iterator 
-wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
+void
+wxLayoutLine::Draw(wxDC &dc,
+                   wxLayoutList *llist,
+                   const wxPoint & offset) const
 {
-   wxPoint object = wxPoint(0,0);  // runs along the objects
-   CoordType width = 0;
-   wxLayoutObjectList::iterator i, begin_it;
-   int go_up;
+   wxLayoutObjectList::iterator i;
+   wxPoint pos = offset;
+   pos = pos + GetPosition();
    
-//#ifdef WXLAYOUT_DEBUG
-//   wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
-//#endif
-
-   // optimisation: compare to last looked at object:
-   if(cpos->y > m_FoundCursor.y || (cpos->y == m_FoundCursor.y &&
-                                    cpos->x >= m_FoundCursor.x))
-      go_up = 1;
+   pos.y += m_BaseLine;
+
+   CoordType xpos = 0; // cursorpos, lenght of line
+
+   CoordType from, to, tempto;
+   int highlight = llist->IsSelected(this, &from, &to);
+//   WXLO_DEBUG(("highlight=%d",  highlight ));
+   if(highlight == 1) // we need to draw the whole line inverted!
+      llist->StartHighlighting(dc);
    else
-      go_up = 0;
+      llist->EndHighlighting(dc);
 
-   //broken at the moment
-   //begin_it = m_FoundIterator;
-   //m_FoundCursor = *cpos;
-   begin_it = begin();
-   go_up = 1;
-   for(i = begin_it; i != end() && object.y <= cpos->y; )
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      width = (**i).CountPositions();
-      if(cpos->y == object.y) // a possible candidate
+      if(highlight == -1) // partially highlight line
       {
-         if((**i).GetType() ==WXLO_TYPE_LINEBREAK)
+         // parts of the line need highlighting
+         tempto = xpos+(**i).GetLength();
+         if(tempto >= from && xpos <= to)
          {
-            if(cpos->x == object.x)
-            {
-               if(offset) *offset = 0;
-               return m_FoundIterator = i;
-            }
-            if(offset) *offset=1;
-            cpos->x = object.x;
-            return m_FoundIterator = i;
+            tempto = to-xpos;
+            if(tempto > (**i).GetLength())
+               tempto = (**i).GetLength();
+            CoordType tmp = from-xpos;
+            if(tmp < 0) tmp = 0;
+            (**i).Draw(dc, pos, llist, from-xpos, tempto);
          }
-         if(cpos->x >= object.x && cpos->x <= object.x+width) // overlap
+         else
          {
-            if(offset) *offset = cpos->x-object.x;
-//#ifdef WXLAYOUT_DEBUG
-//            wxLayoutDebug("   found object at (%d, %d), type: %s",
-//                          object.x,  object.y, TypeString((*i)->GetType()));
-//#endif      
-            return m_FoundIterator = i;
+            llist->EndHighlighting(dc); // FIXME! inefficient
+            (**i).Draw(dc, pos, llist);
          }
       }
-      // no overlap, increment coordinates
-      object.x += width;
-      if((**i).GetType() == WXLO_TYPE_LINEBREAK)
-      {
-         object.x = 0;
-         object.y++;
-      }
-      if(go_up)
-         i++;
       else
-         i--;
-   }//for
-//#ifdef WXLAYOUT_DEBUG
-//   wxLayoutDebug("   not found");
-//#endif
-// return last object, coordinates of that one:
-   i = tail();
-   if(i == end())
-      return m_FoundIterator = i;
-   if((**i).GetType()==WXLO_TYPE_LINEBREAK)
-   {
-      if(offset)
-         *offset = 1;
-      return m_FoundIterator = i;
-   }
-   cpos->x = object.x; // would be the coordinate of next object
-   cpos->y = object.y;
-   cpos->x += width; // last object's width
-   if(*offset)  *offset = cpos->x-object.x;
-   return m_FoundIterator = i; // not found
+         (**i).Draw(dc, pos, llist);
+      pos.x += (**i).GetWidth();
+      xpos += (**i).GetLength();
+   }
 }
 
-bool
-wxLayoutList::MoveCursor(int dx, int dy)
+void
+wxLayoutLine::Layout(wxDC &dc,
+                     wxLayoutList *llist,
+                     wxPoint *cursorPos,
+                     wxPoint *cursorSize,
+                     int cx) 
 {
-   CoordType diff;
+   wxLayoutObjectList::iterator i;
 
-   m_CursorMoved = true;  
-   
-   enum { up, down} direction;
+   CoordType
+      oldHeight = m_Height;
+   CoordType
+      topHeight, bottomHeight;  // above and below baseline
+   CoordType
+      objHeight = 0,
+      objTopHeight, objBottomHeight;
+   CoordType
+      len, count = 0;
+   m_Height = 0; m_BaseLine = 0;
+   m_Width = 0;
+   topHeight = 0; bottomHeight = 0;
+   wxPoint size;
+   bool cursorFound = false;
 
-   wxPoint newPos = wxPoint(m_CursorPos.x + dx,
-                            m_CursorPos.y + dy);
+   if(cursorPos)
+   {
+      *cursorPos = m_Position;
+      if(cursorSize) *cursorSize = wxPoint(0,0);
+   }
+   
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      (**i).Layout(dc, llist);
+      size = (**i).GetSize(&objTopHeight, &objBottomHeight);
 
-   // check for bounds
-   //if(newPos.x < 0) newPos.x = 0;
-   if(newPos.y < 0) newPos.y = 0;
-   else if(newPos.y > m_MaxLine) newPos.y = m_MaxLine;
+      if(cursorPos && ! cursorFound)
+      {  // we need to check whether the text cursor is here
+         len = (**i).GetLength();
+         if(count <= cx && count+len > cx)
+         {
+            if((**i).GetType() == WXLO_TYPE_TEXT)
+            {
+               len = cx - count; // pos in object
+               CoordType width, height, descent;
+               dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len), 
+                                &width, &height, &descent);
+               cursorPos->x += width;
+               cursorPos->y = m_Position.y;
+               wxString str;
+               if(len < (**i).GetLength())
+                  str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1);
+               else
+                  str = WXLO_CURSORCHAR;
+               dc.GetTextExtent(str, &width, &height, &descent);
+               wxASSERT(cursorSize);
+               // Just in case some joker inserted an empty string object:
+               if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH;
+               if(height == 0) height = objHeight;
+               cursorSize->x = width;
+               cursorSize->y = height;
+               cursorFound = true; // no more checks
+            }
+            else 
+            { // on some other object
+               CoordType top, bottom; // unused
+               *cursorSize = (**i).GetSize(&top,&bottom);
+               cursorPos->y = m_Position.y;
+               cursorFound = true; // no more checks
+            }
+         }
+         else
+         {
+            count += len;
+            cursorPos->x += (**i).GetWidth();
+         }
+      } // cursor finding
+      objHeight = size.y;
+      m_Width += size.x;
+      if(objHeight > m_Height) m_Height = objHeight;
+      if(objTopHeight > topHeight) topHeight = objTopHeight;
+      if(objBottomHeight > bottomHeight) bottomHeight = objBottomHeight;
+   }
+   if(topHeight + bottomHeight > m_Height) m_Height =
+                                              topHeight+bottomHeight;
+   m_BaseLine = topHeight;
 
-   if(newPos.y > m_CursorPos.y ||
-      newPos.y == m_CursorPos.y &&
-      newPos.x >= m_CursorPos.x)
-      direction = down;
-   else
-      direction = up;
+   if(m_Height == 0)
+   {
+      if(GetPreviousLine()) // empty line
+      {
+         m_Height = GetPreviousLine()->GetHeight();
+         m_BaseLine = GetPreviousLine()->m_BaseLine;
+      }
+      else
+      {
+            CoordType width, height, descent;
+            dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+            m_Height = height;
+            m_BaseLine = m_Height - descent;
+      }
+   }
 
-   wxASSERT(m_CursorObject);
-   // now move cursor forwards until at the new position:
+   
+   // tell next line about coordinate change
+   if(m_Next && objHeight != oldHeight)
+      m_Next->RecalculatePositions(0, llist);
 
-   // first, go to the right line:
-   while(newPos.y != m_CursorPos.y)
+   // We need to check whether we found a valid cursor size:
+   if(cursorPos)
    {
-      if(direction == down)
+      // this might be the case if the cursor is at the end of the
+      // line or on a command object:
+      if(cursorSize->y < WXLO_MINIMUM_CURSOR_WIDTH)
       {
-         m_CursorPos.x +=
-            (**m_CursorObject).CountPositions() - m_CursorOffset;
-         if(m_CursorObject == tail())
-            break;  // can't go any further
-         if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK
-            && m_CursorOffset == 0)
-         {
-            m_CursorPos.y++; m_CursorPos.x = 0;
-         }
-         m_CursorObject ++; m_CursorOffset = 0;
+         CoordType width, height, descent;
+         dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+         cursorSize->x = width;
+         cursorSize->y = height;
       }
-      else // up
-      {
-         if(m_CursorObject == begin())
-            break;  // can't go any further
+      if(m_BaseLine >= cursorSize->y) // the normal case anyway
+         cursorPos->y += m_BaseLine-cursorSize->y;
+   }
+}
 
-         if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK &&
-            m_CursorOffset == 1)
-         {
-            m_CursorPos.y--;
-            m_CursorPos.x = GetLineLength(m_CursorObject);
-         }
-         m_CursorPos.x -= m_CursorOffset;
-         m_CursorObject --; m_CursorOffset = (**m_CursorObject).CountPositions();
+
+wxLayoutLine *
+wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
+{
+   wxASSERT(xpos >= 0);
+   
+   if(xpos == 0)
+   { // insert an empty line before this one
+      wxLayoutLine *prev = new wxLayoutLine(m_Previous, llist);
+      if(m_Previous == NULL)
+      {  // We were in first line, need to link in new empty line
+         // before this.
+         prev->m_Next = this;
+         m_Previous = prev;
+         m_Previous->m_Height = GetHeight(); // this is a wild guess
       }
+      MoveLines(+1);
+      if(m_Next)
+         m_Next->RecalculatePositions(1, llist);
+      return this;
    }
-   if(newPos.y != m_CursorPos.y) // reached begin/end of list,
-      newPos.y = m_CursorPos.y;  // exited by break
-      
-   // now line is right, go to right column:
-   direction = newPos.x >= m_CursorPos.x ? down : up;
-   while(newPos.x != m_CursorPos.x)
+   
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i == NULLIT)
+      // must be at the end of the line then
+      return new wxLayoutLine(this, llist);
+   // split this line:
+
+   wxLayoutLine *newLine = new wxLayoutLine(this, llist);
+   // split object at i:
+   if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0)
+   {
+      wxString left, right;
+      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+      left = tobj->GetText().substr(0,offset);
+      right = tobj->GetText().substr(offset,tobj->GetLength()-offset);
+      // current text object gets set to left half
+      tobj->GetText() = left; // set new text
+      newLine->Append(new wxLayoutObjectText(right));
+      m_Length -= right.Length();
+      i++; // don't move this object to the new list
+   }
+   else
+      if(offset > 0)
+         i++; // move objects from here to new list
+
+   while(i != m_ObjectList.end())
+   {
+      newLine->Append(*i);
+      m_Length -= (**i).GetLength();
+      m_ObjectList.remove(i); // remove without deleting it
+   }
+   if(m_Next)
+      m_Next->RecalculatePositions(2, llist);
+   return newLine;
+}
+   
+
+void
+wxLayoutLine::MergeNextLine(wxLayoutList *llist)
+{
+   wxASSERT(GetNextLine());
+   wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
+   wxLOiterator i;
+   
+   for(i = list.begin(); i != list.end();)
+   {
+      Append(*i);
+      list.remove(i); // remove without deleting it
+   }
+   wxASSERT(list.empty());
+   wxLayoutLine *oldnext = GetNextLine();
+   SetNext(GetNextLine()->GetNextLine());
+   delete oldnext;
+   RecalculatePositions(1, llist);
+}
+
+CoordType
+wxLayoutLine::GetWrapPosition(CoordType column)
+{
+   CoordType offset;
+   wxLOiterator i = FindObject(column, &offset);
+   if(i == NULLIT) return -1; // cannot wrap
+
+   // go backwards through the list and look for space in text objects 
+   do
    {
-      if(direction == down)
+      if((**i).GetType() == WXLO_TYPE_TEXT)
       {
-         diff = newPos.x - m_CursorPos.x;
-         if(diff > (**m_CursorObject).CountPositions()-m_CursorOffset)
+         do
          {
-            m_CursorPos.x +=
-               (**m_CursorObject).CountPositions()-m_CursorOffset;
-            if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK &&
-               m_CursorOffset == 0)
-               m_CursorPos = wxPoint(0, m_CursorPos.y+1);
-            if(m_CursorObject == tail())
-               break; // cannot go further
-            m_CursorObject++; m_CursorOffset = 0;
-         }
-         else
-         {
-            if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK)
+            if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
+               return column;
+            else
             {
-               newPos.y++; newPos.x -= m_CursorPos.x+1;
-               m_CursorPos = wxPoint(0,m_CursorPos.y+1);
+               offset--;
+               column--;
             }
-            else
-               m_CursorPos.x += diff;
-            m_CursorOffset += diff;
-         }
+         }while(offset != -1);
+         i--;  // move on to previous object
       }
-      else // up
+      else
       {
-         if(m_CursorPos.x == 0 && m_CursorOffset == 1 &&
-            (**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK) // can we go further up?
-         {
-            m_CursorPos.y--;
-            newPos.y--; 
-            m_CursorOffset = 0;
-            m_CursorPos.x = GetLineLength(m_CursorObject)-1;
-            newPos.x += m_CursorPos.x+1;
-            continue;
-         }
-         diff = m_CursorPos.x - newPos.x;
-         if(diff >= m_CursorOffset)
-         {
-            if(m_CursorObject == begin())
-            {
-               m_CursorOffset = 0;
-               m_CursorPos.x = 0;
-               break; // cannot go further
-            }
-            m_CursorObject--;
-            m_CursorPos.x -= m_CursorOffset;
-            m_CursorOffset = (**m_CursorObject).CountPositions();
-         }
-         else
-         {
-            m_CursorPos.x -= diff;
-            m_CursorOffset -= diff;
-         }
+         column -= (**i).GetLength();
+         i--;
       }
+      if( i != NULLIT)
+         offset = (**i).GetLength();
+   }while(i != NULLIT);
+   /* If we reached the begin of the list and have more than one
+      object, that one is longer than the margin, so break behind
+      it. */
+   CoordType pos = 0;
+   i = m_ObjectList.begin();
+   while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
+   {
+      pos += (**i).GetLength();
+      i++;
+   }
+   if(i == NULLIT) return -1;  //why should this happen?
+   pos += (**i).GetLength();
+   i++;
+   while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
+   {
+            pos += (**i).GetLength();
+            i++;
    }
-   return true; // FIXME: when return what?
+   if(i == NULLIT) return -1;  //this is possible, if there is only one text object
+   // now we are at the second text object:
+   pos -= (**i).GetLength();
+   return pos; // in front of it
 }
+   
 
+#ifdef WXLAYOUT_DEBUG
 void
-wxLayoutList::Delete(CoordType count)
+wxLayoutLine::Debug(void)
 {
-   WXL_TRACE(Delete);
+   wxString tmp;
+   wxPoint pos = GetPosition();
+   WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
+              (long int) GetLineNumber(),
+              (long int) pos.x, (long int) pos.y,
+               (long int) GetHeight()));
+   if(m_ObjectList.begin() != NULLIT)
+      (**m_ObjectList.begin()).Debug();
 
-   if(!m_Editable)
-      return;
+}
+#endif
+
+void
+wxLayoutLine::Copy(wxLayoutList *llist,
+                   CoordType from,
+                   CoordType to)
+{
+   CoordType firstOffset, lastOffset;
 
-   m_bModified = true;
+   if(to == -1) to = GetLength();
    
-   CoordType offs = 0;
-   wxLayoutObjectList::iterator i;
-      
-   do
-   {
-      i  = m_CursorObject;
-   startover: // ugly, but easiest way to do it
-      if(i == end())
-         return; // we cannot delete anything more
+   wxLOiterator first = FindObject(from, &firstOffset);
+   wxLOiterator last  = FindObject(to, &lastOffset);
 
-/* Here we need to treat linebreaks differently.
-   If m_CursorOffset==0 we are before the linebreak, otherwise behind.  */
-      if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
+   // Common special case: only one object
+   if( *first == *last )
+   {
+      if( (**first).GetType() == WXLO_TYPE_TEXT )
       {
-         if(m_CursorOffset == 0)
-         {
-            m_MaxLine--;
-            erase(i);
-            m_CursorObject = i; // new i!
-            m_CursorOffset = 0; // Pos unchanged
-            count--;
-            continue; // we're done
-         }
-         else // delete the object behind the linebreak
-         {
-            i++; // we increment and continue as normal
-            m_CursorOffset=0;
-            goto startover; 
-         }
+         llist->Insert(new wxLayoutObjectText(
+            ((wxLayoutObjectText
+              *)*first)->GetText().substr(firstOffset,
+                                          lastOffset-firstOffset))
+            );
+         return;
       }
-      else if((*i)->GetType() == WXLO_TYPE_TEXT)
+      else // what can we do?
       {
-         wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
-         CoordType len = tobj->CountPositions();
-// If we find the end of a text object, this means that we
-// have to delete from the object following it.
-         if(len == m_CursorOffset)
-         {
-            i++;
-            m_CursorOffset = 0;
-            goto startover;
-         }
-         else if(len <= count) // delete this object
-         {
-            count -= len;
-            erase(i);
-            m_CursorObject = i;
-            m_CursorOffset = 0;
-            continue; 
-         }
-         else
-         {
-            len = count;
-            tobj->GetText().erase(m_CursorOffset,len);
-            // cursor unchanged
-            return; // we are done
-         }
+         if(lastOffset > firstOffset) // i.e. +1 :-)
+            llist->Insert( (**first).Copy() );
+         return;
       }
-      else// all other objects: delete the object
-// this only works as expected  if the non-text object has 0/1
-// as offset values. Not tested with "longer" objects.
+   }
+
+   // If we reach here, we can safely copy the whole first object from 
+   // the firstOffset position on:
+   if((**first).GetType() == WXLO_TYPE_TEXT && firstOffset != 0)
+   {
+      llist->Insert(new wxLayoutObjectText(
+         ((wxLayoutObjectText *)*first)->GetText().substr(firstOffset))
+         );
+   }
+   else if(firstOffset == 0)
+      llist->Insert( (**first).Copy() );
+   // else nothing to copy :-(
+   
+   // Now we copy all objects before the last one:
+   wxLOiterator i = first; i++;
+   for( ; i != last; i++)
+      llist->Insert( (**i).Copy() );
+
+   // And now the last object:
+   if(lastOffset != 0)
+   {
+      if( (**last).GetType() == WXLO_TYPE_TEXT )
       {
-         CoordType len = (*i)->CountPositions();
-         if(offs == 0)
-         {
-            count = count > len ? count -= len : 0;
-            erase(i); // after this, i is the iterator for the
-                      // following object
-            m_CursorObject = i;
-            m_CursorOffset = 0;
-            continue;
-         }
-         else // delete the following object
-         {
-            i++; // we increment and continue as normal
-            m_CursorOffset=0;
-            goto startover; 
-         }
+         llist->Insert(new wxLayoutObjectText(
+            ((wxLayoutObjectText *)*last)->GetText().substr(0,lastOffset))
+            );
       }
+      else
+         llist->Insert( (**last).Copy() );
    }
-   while(count && i != end());      
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+   
+   The wxLayoutList object
+   
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutList::wxLayoutList()
+{
+   m_DefaultSetting = NULL;
+   m_FirstLine = NULL;
+   m_ColourFG = *wxBLACK;
+   m_ColourBG = *wxWHITE;
+   InvalidateUpdateRect();
+   Clear();
+}
+
+wxLayoutList::~wxLayoutList()
+{
+   InternalClear();
+   m_FirstLine->DeleteLine(false, this);
 }
 
 void
-wxLayoutList::Insert(wxLayoutObjectBase *obj)
+wxLayoutList::Empty(void)
 {
-   wxCHECK_RET( obj, "no object to insert" );
+   while(m_FirstLine)
+      m_FirstLine = m_FirstLine->DeleteLine(false, this);
 
-   m_bModified = true;
+   m_CursorPos = wxPoint(0,0);
+   m_CursorScreenPos = wxPoint(0,0);
+   m_CursorSize = wxPoint(0,0);
+   m_FirstLine = new wxLayoutLine(NULL, this); // empty first line
+   m_CursorLine = m_FirstLine;
+   InvalidateUpdateRect();
+}
 
-   wxLayoutObjectList::iterator i = m_CursorObject;
 
-   if(i != iterator(NULL) && (*obj).GetType() == WXLO_TYPE_LINEBREAK)
+void
+wxLayoutList::InternalClear(void)
+{
+   Empty();
+   if(m_DefaultSetting)
    {
-      m_CursorPos.x = 0; m_CursorPos.y ++;
+      delete m_DefaultSetting;
+      m_DefaultSetting = NULL;
    }
-   
-   if(i == end())
+   m_Selection.m_selecting = false;
+   m_Selection.m_valid = false;
+
+   m_CurrentSetting.family = wxSWISS;
+   m_CurrentSetting.size = WXLO_DEFAULTFONTSIZE;
+   m_CurrentSetting.style = wxNORMAL;
+   m_CurrentSetting.weight = wxNORMAL;
+   m_CurrentSetting.underline = 0;
+}
+
+void
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+                      int underline, wxColour *fg,
+                      wxColour *bg)
+{
+   if(family != -1)    m_CurrentSetting.family = family;
+   if(size != -1)      m_CurrentSetting.size = size;
+   if(style != -1)     m_CurrentSetting.style = style;
+   if(weight != -1)    m_CurrentSetting.weight = weight;
+   if(underline != -1) m_CurrentSetting.underline = underline != 0;
+   if(fg)
    {
-      push_back(obj);
-      m_CursorObject = tail();
+      m_CurrentSetting.fg_valid = true;
+      m_CurrentSetting.fg_red = fg->Red();
+      m_CurrentSetting.fg_blue = fg->Blue();
+      m_CurrentSetting.fg_green = fg->Green();
    }
-   else if(m_CursorOffset == 0)
+   if(bg)
    {
-      insert(i,obj);
-      m_CursorObject = i;
+      m_CurrentSetting.bg_valid = true;
+      m_CurrentSetting.bg_red = bg->Red();
+      m_CurrentSetting.bg_blue = bg->Blue();
+      m_CurrentSetting.bg_green = bg->Green();
    }
-   // do we have to split a text object?
-   else if((*i)->GetType() == WXLO_TYPE_TEXT && m_CursorOffset != (*i)->CountPositions())
+   Insert(
+      new wxLayoutObjectCmd(
+         m_CurrentSetting.size,
+         m_CurrentSetting.family,
+         m_CurrentSetting.style,
+         m_CurrentSetting.weight,
+         m_CurrentSetting.underline, fg, bg));
+}
+
+void
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+                      int underline, char const *fg, char const *bg)
+
+{
+   wxColour
+      *cfg = NULL,
+      *cbg = NULL;
+
+   if( fg )
+      cfg = wxTheColourDatabase->FindColour(fg);
+   if( bg )
+      cbg = wxTheColourDatabase->FindColour(bg);
+   
+   SetFont(size,family,style,weight,underline,cfg,cbg);
+}
+
+void
+wxLayoutList::Clear(int family, int size, int style, int weight,
+                    int underline, wxColour *fg, wxColour *bg)
+{
+   InternalClear();
+   
+   if(m_DefaultSetting)
+      delete m_DefaultSetting;
+
+   m_DefaultSetting = new 
+      wxLayoutStyleInfo(family,size,style,weight,underline,fg,bg);
+}
+
+wxPoint
+wxLayoutList::FindText(const wxString &needle, const wxPoint &cpos) const
+{
+   int xpos;
+   
+   wxLayoutLine *line;
+   for(line = m_FirstLine;
+       line;
+       line = line->GetNextLine())
    {
-      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
-      String left = tobj->GetText().substr(0,m_CursorOffset); // get part before cursor
-      tobj->GetText() = tobj->GetText().substr(m_CursorOffset,(*i)->CountPositions()-m_CursorOffset); // keeps the right half
-      insert(i,obj);
-      m_CursorObject = i; // == obj
-      insert(i,new wxLayoutObjectText(left)); // inserts before
+      if(line->GetLineNumber() >= cpos.y)
+      {
+         xpos = line->FindText(needle,
+                               (line->GetLineNumber() == cpos.y) ?
+                               cpos.x : 0);
+         if(xpos != -1)
+            return wxPoint(xpos, line->GetLineNumber());
+      }
    }
-   else
+   return wxPoint(-1,-1);
+}
+
+
+bool
+wxLayoutList::MoveCursorTo(wxPoint const &p)
+{
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   wxLayoutLine *line = m_FirstLine;
+   while(line && line->GetLineNumber() != p.y)
+      line = line->GetNextLine();
+   if(line && line->GetLineNumber() == p.y) // found it
    {
-      // all other cases, append after object:
-      wxLayoutObjectList::iterator j = i; // we want to apend after this object
-      j++;
-      if(j != end())
+      m_CursorPos.y = p.y;
+      m_CursorLine = line;
+      CoordType len = line->GetLength();
+      if(len >= p.x)
       {
-         insert(j, obj);
-         m_CursorObject = j;
+         m_CursorPos.x = p.x;
+         return true;
       }
       else
       {
-         push_back(obj);
-         m_CursorObject = tail();
+         m_CursorPos.x = len;
+         return false;
       }
    }
-
-   if(obj->GetType() != WXLO_TYPE_LINEBREAK) // handled separately above
-      m_CursorPos.x += obj->CountPositions();
-   // applies also for linebreak:
-   m_CursorOffset = obj->CountPositions();
+   return false;
+}
    
-   if(obj->GetType() == WXLO_TYPE_LINEBREAK)
-      m_MaxLine++;
-   m_CursorMoved = true;
+bool
+wxLayoutList::MoveCursorVertically(int n)
+{
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   bool rc;
+   if(n  < 0) // move up
+   {
+      if(m_CursorLine == m_FirstLine) return false;
+      while(n < 0 && m_CursorLine)
+      {
+         m_CursorLine = m_CursorLine->GetPreviousLine();
+         m_CursorPos.y--;
+         n++;
+      }
+      if(! m_CursorLine)
+      {
+         m_CursorLine = m_FirstLine;
+         m_CursorPos.y = 0;
+         rc = false;
+      }
+      else
+      {
+         if(m_CursorPos.x > m_CursorLine->GetLength())
+            m_CursorPos.x = m_CursorLine->GetLength();
+         rc = true;
+      }
+   }
+   else // move down
+   {
+      wxLayoutLine *last = m_CursorLine;
+      if(! m_CursorLine->GetNextLine()) return false;
+      while(n > 0 && m_CursorLine)
+      {
+         n--;
+         m_CursorPos.y ++;
+         m_CursorLine = m_CursorLine->GetNextLine();
+      }
+      if(! m_CursorLine)
+      {
+         m_CursorLine = last;
+         m_CursorPos.y ++;
+         rc = false;
+      }
+      else
+      {
+         if(m_CursorPos.x > m_CursorLine->GetLength())
+            m_CursorPos.x = m_CursorLine->GetLength();
+         rc = true;
+      }
+   }
+   return rc;
 }
 
-void
-wxLayoutList::Insert(String const &text)
+bool
+wxLayoutList::MoveCursorHorizontally(int n)
 {
-   wxLayoutObjectText *tobj = NULL;
-   wxLayoutObjectList::iterator j;
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   int move;
+   while(n < 0)
+   {
+      if(m_CursorPos.x == 0) // at begin of line
+      {
+         if(! MoveCursorVertically(-1))
+            break;
+         MoveCursorToEndOfLine();
+         n++;
+         continue;
+      }
+      move = -n;
+      if(move > m_CursorPos.x) move = m_CursorPos.x;
+      m_CursorPos.x -= move; n += move;
+   }
 
-//   WXL_TRACE(Insert(text));
+   while(n > 0)
+   {
+      int len =  m_CursorLine->GetLength();
+      if(m_CursorPos.x == len) // at end of line
+      {
+         if(! MoveCursorVertically(1))
+            break;
+         MoveCursorToBeginOfLine();
+         n--;
+         continue;
+      }
+      move = n;
+      if( move >= len-m_CursorPos.x) move = len-m_CursorPos.x;
+      m_CursorPos.x += move;
+      n -= move;
+   }
+   return n == 0;
+}
 
-   if(! m_Editable)
-      return;
+bool
+wxLayoutList::Insert(wxString const &text)
+{
+   wxASSERT(m_CursorLine);
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   m_CursorLine->Insert(m_CursorPos.x, text);
+   m_CursorPos.x += text.Length();
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+   return true;
+}
 
-   m_bModified = true;
+bool
+wxLayoutList::Insert(wxLayoutObject *obj)
+{
+   wxASSERT(m_CursorLine);
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   m_CursorLine->Insert(m_CursorPos.x, obj);
+   m_CursorPos.x += obj->GetLength();
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+   return true;
+}
 
-   wxLayoutObjectList::iterator i = m_CursorObject;
+bool
+wxLayoutList::LineBreak(void)
+{
+   wxASSERT(m_CursorLine);
+   bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
+   if(setFirst) // we were at beginning of first line
+      m_FirstLine = m_CursorLine->GetPreviousLine();
+   m_CursorPos.y++;
+   m_CursorPos.x = 0;
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+   return true;
+}
 
-   if(i == end())
+bool
+wxLayoutList::WrapLine(CoordType column)
+{
+   if(m_CursorPos.x <= column || column < 1)
+      return false; // do nothing yet
+   else
    {
-      Insert(new wxLayoutObjectText(text));
-      return;
+      CoordType xpos = m_CursorLine->GetWrapPosition(column);
+      if(xpos == -1)
+         return false; // cannot break line
+      //else:
+      CoordType newpos = m_CursorPos.x - xpos - 1;
+      m_CursorPos.x = xpos;
+      SetUpdateRect(m_CursorScreenPos);
+      SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+      LineBreak();
+      Delete(1); // delete the space
+      m_CursorPos.x = newpos;
+      m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+      return true;
    }
+}
 
-   switch((**i).GetType())
-   {
-   case WXLO_TYPE_TEXT:
-// insert into an existing text object:
-      tobj = (wxLayoutObjectText *)*i ;
-      wxASSERT(tobj);
-      tobj->GetText().insert(m_CursorOffset,text);
-      m_CursorObject = i;
-      m_CursorOffset = m_CursorOffset + text.length();
-      m_CursorPos.x += text.length();
-      break;
-   case WXLO_TYPE_LINEBREAK:
-   default:
-      j = i;
-      if(m_CursorOffset == 0) // try to append to previous object
-      {
-         j--;
-         if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
-         {
-            tobj = (wxLayoutObjectText *)*j;
-            tobj->GetText()+=text;
-            m_CursorObject = j;
-            m_CursorOffset = (**j).CountPositions();
-            m_CursorPos.x += text.length();
-         }
-         else
-         {
-            insert(i,new wxLayoutObjectText(text));
-            m_CursorObject = i;
-            m_CursorOffset = (**i).CountPositions();
-            m_CursorPos.x += m_CursorOffset;
-         }
+bool
+wxLayoutList::Delete(CoordType npos)
+{
+   wxASSERT(m_CursorLine);
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   CoordType left;
+   do
+   {
+      left = m_CursorLine->Delete(m_CursorPos.x, npos);
+      if(left == 0)
+         return true;
+      // More to delete, continue on next line.
+      // First, check if line is empty:
+      if(m_CursorLine->GetLength() == 0)
+      {  // in this case, updating could probably be optimised
+#ifdef WXLO_DEBUG   
+         wxASSERT(DeleteLines(1) == 0);
+#else
+         DeleteLines(1);
+#endif
+         
+         left--;
       }
-      else // offset == 1 : cursor after linebreak
+      else 
       {
-         j++;
-         m_CursorObject = j;
-         m_CursorOffset = 0;
-         if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
-         {
-            tobj = (wxLayoutObjectText *)*j;
-            tobj->GetText()=text+tobj->GetText();
-            m_CursorOffset = text.length();
-            m_CursorPos.x += m_CursorOffset;
-         }
+         // Need to join next line
+         if(! m_CursorLine->GetNextLine())
+            break; // cannot
          else
          {
-            if(j == end())
-            {
-               push_back(new wxLayoutObjectText(text));
-               m_CursorObject = tail();
-               m_CursorOffset = (**m_CursorObject).CountPositions();
-               m_CursorPos.x += text.length();
-            }
-            else
-            {
-               insert(j,new wxLayoutObjectText(text));
-               m_CursorObject = j;
-               m_CursorOffset = (**j).CountPositions();
-               m_CursorPos.x += text.length();
-            }
+            m_CursorLine->MergeNextLine(this);
+            left--;
          }
       }
-      break;
    }
-   m_CursorMoved = true;
+   while(left);
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+   return left == 0;
 }
 
-CoordType
-wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs)
+int
+wxLayoutList::DeleteLines(int n)
 {
-   if(i == end())
-      return 0;
+   wxASSERT(m_CursorLine);
+   wxLayoutLine *line;
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+   while(n > 0)
+   {
+      if(!m_CursorLine->GetNextLine())
+      {  // we cannot delete this line, but we can clear it
+         MoveCursorToBeginOfLine();
+         DeleteToEndOfLine();
+         m_CursorLine->RecalculatePositions(2, this);
+         return n-1;
+      }
+      //else:
+      line = m_CursorLine;
+      m_CursorLine = m_CursorLine->DeleteLine(true, this);
+      n--;
+      if(line == m_FirstLine) m_FirstLine = m_CursorLine;
+      wxASSERT(m_FirstLine);
+      wxASSERT(m_CursorLine);
+   }
+   m_CursorLine->RecalculatePositions(2, this);
+   return n;
+}
 
-   CoordType len = 0;
+void
+wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
+{
+   wxLayoutLine *line = m_FirstLine;
 
-   if(offs == 0 && (**i).GetType() == WXLO_TYPE_LINEBREAK)
-      i--;
-         
-// search backwards for beginning of line:
-   while(i != begin() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
-      i--;
-   if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
-      i++;
-// now we can start counting:
-   while(i != end() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
+   // first, make sure everything is calculated - this might not be
+   // needed, optimise it later
+   ApplyStyle(m_DefaultSetting, dc);
+   while(line)
    {
-      len += (*i)->CountPositions();
-      i++;
+      line->RecalculatePosition(this); // so we don't need to do it all the time
+      // little condition to speed up redrawing:
+      if(bottom != -1 && line->GetPosition().y > bottom) break;
+      line = line->GetNextLine();
    }
-   len++; // one extra for the linebreak
-   return len;
 }
 
 void
-wxLayoutList::Clear(int family, int size, int style, int weight,
-                    int underline, char const *fg, char const *bg)
-{
-   m_bModified = true;
-   m_CursorMoved = true;
-   m_dirty = true;  // force redraw/recalc
-   wxLayoutObjectList::iterator i = begin();
-
-   wxBitmap bm(1,1);
-   m_CursorMemDC.SelectObject(bm);
-
-   while(i != end()) // == while valid
-      erase(i);
-
-   // set defaults
-   m_FontPtSize = size;
-   m_FontUnderline = false;
-   m_FontFamily = family;
-   m_FontStyle = style;
-   m_FontWeight = weight;
-   m_ColourFG = wxTheColourDatabase->FindColour(fg);
-   m_ColourBG = wxTheColourDatabase->FindColour(bg);
-
-   if(! m_ColourFG) m_ColourFG = wxBLACK;
-   if(! m_ColourBG) m_ColourBG = wxWHITE;
+wxLayoutList::UpdateCursorScreenPos(wxDC &dc)
+{
+   wxASSERT(m_CursorLine);
+   m_CursorLine->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+}
+
+wxPoint
+wxLayoutList::GetCursorScreenPos(wxDC &dc)
+{
+   UpdateCursorScreenPos(dc);
+   return m_CursorScreenPos;
+}
+
+void
+wxLayoutList::Layout(wxDC &dc, CoordType bottom)
+{
+   wxLayoutLine *line = m_FirstLine;
+
+   // first, make sure everything is calculated - this might not be
+   // needed, optimise it later
+   ApplyStyle(m_DefaultSetting, dc);
+   while(line)
+   {
+      if(line == m_CursorLine)
+         line->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+      else
+         line->Layout(dc, this);
+      // little condition to speed up redrawing:
+      if(bottom != -1 && line->GetPosition().y > bottom) break;
+      line = line->GetNextLine();
+   }
+
+///FIXME: disabled for now
+#if 0
+   // can only be 0 if we are on the first line and have no next line
+   wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
+                                    m_CursorLine->GetNextLine() == NULL &&
+                                    m_CursorLine == m_FirstLine));
+#endif
+   SetUpdateRect(m_CursorScreenPos);
+   SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+}
+
+void
+wxLayoutList::Draw(wxDC &dc,
+                   wxPoint const &offset,
+                   CoordType top,
+                   CoordType bottom)
+{
+   wxLayoutLine *line = m_FirstLine;
+
+   Layout(dc, bottom);
+   ApplyStyle(m_DefaultSetting, dc);
+   wxBrush brush(m_ColourBG, wxSOLID);
+   dc.SetBrush(brush);
    
-   m_Position = wxPoint(0,0);
-   m_CursorPos = wxPoint(0,0);
-   m_CursorObject = iterator(NULL);
-   m_CursorOffset = 0;
-   m_CursorSize = wxPoint(2,(BASELINESTRETCH*m_FontPtSize)/10);
+   while(line)
+   {
+      // only draw if between top and bottom:
+      if((top == -1 || line->GetPosition().y + line->GetHeight() >= top))
+         line->Draw(dc, this, offset);
+      // little condition to speed up redrawing:
+      if(bottom != -1 && line->GetPosition().y > bottom) break;
+      line = line->GetNextLine();
+   }
+   InvalidateUpdateRect();
+
+   WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
+               m_Selection.m_valid ? "valid" : "invalid",
+               m_Selection.m_CursorA.x, m_Selection.m_CursorA.y,
+               m_Selection.m_CursorB.x, m_Selection.m_CursorB.y));
+}
+
+wxLayoutObject *
+wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos,
+                               wxPoint *cursorPos,
+                               bool *found)
+{
+   // First, find the right line:
+   wxLayoutLine *line = m_FirstLine;
+   wxPoint p;
+   
+   // we need to run a layout here to get font sizes right :-(
+   ApplyStyle(m_DefaultSetting, dc);
+   while(line)
+   {
+      p = line->GetPosition();
+      if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
+         break;
+      line->Layout(dc, this);
+      line = line->GetNextLine();
+   }
+   if(line == NULL)
+   {
+      if(found) *found = false;
+      return NULL; // not found
+   }
+   if(cursorPos) cursorPos->y = line->GetLineNumber();
+   // Now, find the object in the line:
+   wxLOiterator i = line->FindObjectScreen(dc, pos.x,
+                                           cursorPos ? & cursorPos->x : NULL ,
+                                           found);
+   return (i == NULLIT) ? NULL : *i;
    
-   m_MaxLine = 1;
-   m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10;
-   m_MaxX = 0; m_MaxY = 0;
+}
 
+wxPoint
+wxLayoutList::GetSize(void) const
+{
+   wxLayoutLine
+      *line = m_FirstLine,
+      *last = line;
+   if(! line)
+      return wxPoint(0,0);
 
-   m_FoundCursor = wxPoint(0,0);
-   m_FoundIterator = begin();
+   wxPoint maxPoint(0,0);
    
-   if(m_DefaultSetting)
-      delete m_DefaultSetting;
+   // find last line:
+   while(line)
+   {
+      if(line->GetWidth() > maxPoint.x)
+          maxPoint.x = line->GetWidth();
+      last = line;
+      line = line->GetNextLine();
+   }
 
-   m_DefaultSetting = new
-      wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
-                        m_FontWeight,m_FontUnderline,
-                        m_ColourFG, m_ColourBG);
+   maxPoint.y = last->GetPosition().y + last->GetHeight();
+   return maxPoint;
 }
 
 
-wxLayoutObjectBase *
-wxLayoutList::Find(wxPoint coords) const
+void
+wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
 {
-   wxLayoutObjectList::iterator i = begin();
+   wxPoint coords;
+   coords = m_CursorScreenPos;
+   coords.x += translate.x;
+   coords.y += translate.y;
 
-   wxPoint topleft, bottomright;
+#ifdef WXLAYOUT_DEBUG
+   WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
+               (long)m_CursorPos.x, (long)m_CursorPos.y,
+               (long)coords.x, (long)coords.y,
+               (long)m_CursorSize.x, (long)m_CursorSize.y,
+               (long)m_CursorLine->GetLineNumber(),
+               (long)m_CursorLine->GetLength()));
+#endif
    
-   while(i != end()) // == while valid
+   dc.SetBrush(*wxBLACK_BRUSH);
+   dc.SetLogicalFunction(wxXOR);
+   dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+   if(active)
    {
-      wxLayoutObjectBase *object = *i;
-      topleft = object->GetPosition();
-      if(coords.y >= topleft.y && coords.x >= topleft.x)
-      {
-         bottomright = topleft;
-         bottomright.x += object->GetSize().x;
-         bottomright.y += object->GetSize().y;
-         if(coords.x <= bottomright.x && coords.y <= bottomright.y)
-            return *i;
-      }
-      i++;
+      dc.DrawRectangle(coords.x, coords.y,
+                       m_CursorSize.x, m_CursorSize.y);
+      SetUpdateRect(coords.x, coords.y);
+      SetUpdateRect(coords.x+m_CursorSize.x, coords.y+m_CursorSize.y);
    }
-   return NULL;
+   else
+   {
+      dc.DrawLine(coords.x, coords.y+m_CursorSize.y-1,
+                  coords.x, coords.y);
+      SetUpdateRect(coords.x, coords.y+m_CursorSize.y-1);
+      SetUpdateRect(coords.x, coords.y);
+   }
+   dc.SetLogicalFunction(wxCOPY);
+   //dc.SetBrush(wxNullBrush);
 }
 
+void
+wxLayoutList::SetUpdateRect(CoordType x, CoordType y)
+{
+   if(m_UpdateRectValid)
+      GrowRect(m_UpdateRect, x, y);
+   else
+   {
+      m_UpdateRect.x = x;
+      m_UpdateRect.y = y;
+      m_UpdateRect.width = 4; // large enough to avoid surprises from
+      m_UpdateRect.height = 4;// wxGTK :-)
+      m_UpdateRectValid = true;
+   }
+}
 
 void
-wxLayoutList::SetWrapMargin(long n)
+wxLayoutList::StartSelection(void)
 {
-   m_WrapMargin = n;
+   WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y));
+   m_Selection.m_CursorA = m_CursorPos;
+   m_Selection.m_CursorB = m_CursorPos;
+   m_Selection.m_selecting = true;
+   m_Selection.m_valid = false;
+}
+
+void
+wxLayoutList::ContinueSelection(void)
+{
+   wxASSERT(m_Selection.m_selecting == true);
+   wxASSERT(m_Selection.m_valid == false);
+   WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y));
+   m_Selection.m_CursorB = m_CursorPos;
+   // We always want m_CursorA <= m_CursorB!
+   if(! (m_Selection.m_CursorA <= m_Selection.m_CursorB))
+   {
+      wxPoint help = m_Selection.m_CursorB;
+      m_Selection.m_CursorB = m_Selection.m_CursorA;
+      m_Selection.m_CursorA = help;
+   }
 }
 
 void
-wxLayoutList::WrapLine(void)
+wxLayoutList::EndSelection(void)
+{
+   ContinueSelection();
+   WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y));
+   m_Selection.m_selecting = false;
+   m_Selection.m_valid = true;
+}
+
+
+bool
+wxLayoutList::IsSelecting(void)
+{
+   return m_Selection.m_selecting;
+}
+
+bool
+wxLayoutList::IsSelected(const wxPoint &cursor)
+{
+   if(! m_Selection.m_valid && ! m_Selection.m_selecting)
+      return false;
+   return m_Selection.m_CursorA <= cursor
+      && cursor <= m_Selection.m_CursorB;
+}
+
+
+/** Tests whether this layout line is selected and needs
+    highlighting.
+    @param line to test for
+    @return 0 = not selected, 1 = fully selected, -1 = partially
+    selected
+    */
+int
+wxLayoutList::IsSelected(const wxLayoutLine *line, CoordType *from,
+                         CoordType *to)
 {
-   wxASSERT(m_CursorObject);
+   wxASSERT(line); wxASSERT(to); wxASSERT(from);
 
-   iterator i = m_CursorObject;
+   if(! m_Selection.m_valid && ! m_Selection.m_selecting)
+      return 0;
 
-   if(!DoWordWrap() || !i ) // empty list
+   CoordType y = line->GetLineNumber();
+   if(m_Selection.m_CursorA.y < y && m_Selection.m_CursorB.y > y)
+      return 1;
+   else if(m_Selection.m_CursorA.y == y)
+   {
+      *from = m_Selection.m_CursorA.x;
+      if(m_Selection.m_CursorB.y == y)
+         *to = m_Selection.m_CursorB.x;
+      else
+         *to = line->GetLength();
+      return -1;
+   }
+   else if(m_Selection.m_CursorB.y == y)
+   {
+      *to = m_Selection.m_CursorB.x;
+      if(m_Selection.m_CursorA.y == y)
+         *from = m_Selection.m_CursorA.x;
+      else
+         *from = 0;
+      return -1;
+   }
+   else
+      return 0;
+}
+
+void
+wxLayoutList::DeleteSelection(void)
+{
+   if(! m_Selection.m_valid)
       return;
-   int cursorpos = m_CursorPos.x, cpos, offset;
+
+   m_Selection.m_valid = false;
    
-   if(cursorpos < m_WrapMargin)
+   // Only delete part of the current line?
+   if(m_Selection.m_CursorA.y == m_Selection.m_CursorB.y)
+   {
+      MoveCursorTo(m_Selection.m_CursorA);
+      Delete(m_Selection.m_CursorB.x - m_Selection.m_CursorA.x);
       return;
+   }
+
+
+   wxLayoutLine
+      * firstLine = NULL,
+      * lastLine = NULL;
+
+   for(firstLine = m_FirstLine;
+       firstLine && firstLine->GetLineNumber() < m_Selection.m_CursorA.y;
+       firstLine=firstLine->GetNextLine())
+      ;
+   if(!firstLine || firstLine->GetLineNumber() != m_Selection.m_CursorA.y)
+      return;
+
+
+   for(lastLine = m_FirstLine;
+       lastLine && lastLine->GetLineNumber() < m_Selection.m_CursorB.y;
+       lastLine=lastLine->GetNextLine())
+      ;
+   if(!lastLine || lastLine->GetLineNumber() != m_Selection.m_CursorB.y)
+      return;
+
+
+   // We now know that the two lines are different:
+
+   // First, delete what's left of this line:
+   MoveCursorTo(m_Selection.m_CursorA);
+   DeleteToEndOfLine();
+
+   wxLayoutLine *nextLine = firstLine->GetNextLine();
+   while(nextLine && nextLine != lastLine)
+      nextLine = nextLine->DeleteLine(false, this);
+
+   // Now nextLine = lastLine;
+   Delete(1); // This joins firstLine and nextLine
+   Delete(m_Selection.m_CursorB.x); // This deletes the first x
+   // positions
+   
+   /// Recalculate:
+   firstLine->RecalculatePositions(1, this);
+}
+   
+/// Starts highlighting the selection
+void
+wxLayoutList::StartHighlighting(wxDC &dc)
+{
+#if SHOW_SELECTIONS
+   dc.SetTextForeground(m_ColourBG);
+   dc.SetTextBackground(m_ColourFG);
+#endif
+}
 
-   // else: break line
+/// Ends highlighting the selection
+void
+wxLayoutList::EndHighlighting(wxDC &dc)
+{
+#if SHOW_SELECTIONS
+   dc.SetTextForeground(m_ColourFG);
+   dc.SetTextBackground(m_ColourBG);
+#endif
+}
 
-   // find the right object to break:
-   // is it the current one?
 
-   i = m_CursorObject;
-   cpos = cursorpos-m_CursorOffset;
-   while(i != begin() && cpos >= m_WrapMargin)
+wxLayoutList *
+wxLayoutList::Copy(const wxPoint &from,
+                   const wxPoint &to)
+{
+   wxLayoutLine
+      * firstLine = NULL,
+      * lastLine = NULL;
+
+   for(firstLine = m_FirstLine;
+       firstLine && firstLine->GetLineNumber() < from.y;
+       firstLine=firstLine->GetNextLine())
+      ;
+   if(!firstLine || firstLine->GetLineNumber() != from.y)
+      return NULL;
+
+   for(lastLine = m_FirstLine;
+       lastLine && lastLine->GetLineNumber() < to.y;
+       lastLine=lastLine->GetNextLine())
+      ;
+   if(!lastLine || lastLine->GetLineNumber() != to.y)
+      return NULL;
+
+   if(to <= from)
    {
-      i--;
-      cpos -= (**i).CountPositions();
+      wxLayoutLine *tmp = firstLine;
+      firstLine = lastLine;
+      lastLine = tmp;
    }
-   // now i is the object to break and cpos its position
 
-   offset = m_WrapMargin - cpos;
-   wxASSERT(offset <= (**i).CountPositions());
+   wxLayoutList *llist = new wxLayoutList();
 
-   // split it
-   if((**i).GetType() == WXLO_TYPE_TEXT)
+   if(firstLine == lastLine)
    {
-      wxLayoutObjectText &t = *(wxLayoutObjectText *)*i;
-      for(; offset > 0; offset--)
-         if(t.GetText().c_str()[offset] == ' ' || t.GetText().c_str()[offset] == '\t')
-         {
-            String left = t.GetText().substr(0,offset-1); // get part before cursor
-            t.GetText() = t.GetText().substr(offset,t.CountPositions()-offset); // keeps the right halve
-            insert(i,new wxLayoutObjectLineBreak);
-            insert(i,new wxLayoutObjectText(left)); // inserts before
-            break;
-         }
-      if(offset == 0)
+      firstLine->Copy(llist, from.x, to.x);
+   }
+   else
+   {
+      // Extract objects from first line
+      firstLine->Copy(llist, from.x);
+      llist->LineBreak();
+      // Extract all lines between
+      for(wxLayoutLine *line = firstLine->GetNextLine();
+          line != lastLine;
+          line = line->GetNextLine())
       {
-         // only insert a line break if there  isn't already one
-         iterator j = i; j--;
-         if(j && j != begin() && (**j).GetType() != WXLO_TYPE_LINEBREAK)
-            insert(i,new wxLayoutObjectLineBreak);
-         else
-            return; // do nothing
+         line->Copy(llist);
+         llist->LineBreak();
       }
+      // Extract objects from last line
+      lastLine->Copy(llist, 0, to.x);
    }
-   else
-      insert(i,new wxLayoutObjectLineBreak);
-   m_MaxLine++;
-   m_CursorPos.y++;
-   m_CursorPos.x -= offset;
-   m_CursorOffset -= offset;
+   return llist;
 }
-/******************** printing stuff ********************/
 
-wxLayoutPrintout::wxLayoutPrintout(wxLayoutList &llist,
+wxLayoutList *
+wxLayoutList::GetSelection(void)
+{
+   if(! m_Selection.m_valid)
+   {
+      if(m_Selection.m_selecting)
+         EndSelection();
+      else
+         return NULL;
+   }
+   
+   m_Selection.m_valid = false;
+   return Copy( m_Selection.m_CursorA, m_Selection.m_CursorB );
+}
+
+
+
+#define COPY_SI(what) if(si->what != -1) m_CurrentSetting.what = si->what;
+
+void
+wxLayoutList::ApplyStyle(wxLayoutStyleInfo *si, wxDC &dc)
+{
+   COPY_SI(family);
+   COPY_SI(size);
+   COPY_SI(style);
+   COPY_SI(weight);
+   COPY_SI(underline);
+
+   
+   if(si->fg_valid)
+   {
+      m_CurrentSetting.fg_valid = true;
+      m_CurrentSetting.fg_red = si->fg_red;
+      m_CurrentSetting.fg_green = si->fg_green;
+      m_CurrentSetting.fg_blue = si->fg_blue;
+   }
+   if(si->bg_valid)
+   {
+      m_CurrentSetting.bg_valid = true;
+      m_CurrentSetting.bg_red = si->bg_red;
+      m_CurrentSetting.bg_green = si->bg_green;
+      m_CurrentSetting.bg_blue = si->bg_blue;
+   }
+
+   m_ColourFG = wxColour(m_CurrentSetting.fg_red,
+                         m_CurrentSetting.fg_green,
+                         m_CurrentSetting.fg_blue);
+   m_ColourBG = wxColour(m_CurrentSetting.bg_red,
+                         m_CurrentSetting.bg_green,
+                         m_CurrentSetting.bg_blue);
+   dc.SetTextForeground(m_ColourFG);
+   dc.SetTextBackground(m_ColourBG);
+}
+
+
+#ifdef WXLAYOUT_DEBUG
+
+void
+wxLayoutList::Debug(void) 
+{
+   wxLayoutLine *line;
+
+
+   for(line = m_FirstLine;
+       line;
+       line = line->GetNextLine())
+      line->Debug();
+}
+
+#endif
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutPrintout
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist,
                                    wxString const & title)
 :wxPrintout(title)
 {
-   m_llist = &llist;
+   m_llist = llist;
    m_title = title;
 }
 
+wxLayoutPrintout::~wxLayoutPrintout()
+{
+}
+
+float
+wxLayoutPrintout::ScaleDC(wxDC *dc)
+{
+   // The following bit is taken from the printing sample, let's see
+   // whether it works for us.
+   
+   /* You might use THIS code to set the printer DC to ROUGHLY reflect
+    * the screen text size. This page also draws lines of actual length 5cm
+    * on the page.
+    */
+  // Get the logical pixels per inch of screen and printer
+   int ppiScreenX, ppiScreenY;
+   GetPPIScreen(&ppiScreenX, &ppiScreenY);
+   int ppiPrinterX, ppiPrinterY;
+   GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
+
+   if(ppiScreenX == 0) // not yet set, need to guess
+   {
+      ppiScreenX = 100;
+      ppiScreenY = 100;
+   }
+   if(ppiPrinterX == 0) // not yet set, need to guess
+   {
+      ppiPrinterX = 72;
+      ppiPrinterY = 72;
+   }
+  
+  // This scales the DC so that the printout roughly represents the
+  // the screen scaling. The text point size _should_ be the right size
+  // but in fact is too small for some reason. This is a detail that will
+  // need to be addressed at some point but can be fudged for the
+  // moment.
+  float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
+
+  // Now we have to check in case our real page size is reduced
+  // (e.g. because we're drawing to a print preview memory DC)
+  int pageWidth, pageHeight;
+  int w, h;
+  dc->GetSize(&w, &h);
+  GetPageSizePixels(&pageWidth, &pageHeight);
+  if(pageWidth != 0) // doesn't work always
+  {
+     // If printer pageWidth == current DC width, then this doesn't
+     // change. But w might be the preview bitmap width, so scale down.
+     scale = scale * (float)(w/(float)pageWidth);
+  }
+  dc->SetUserScale(scale, scale);
+  return scale;
+}
+
 bool wxLayoutPrintout::OnPrintPage(int page)
 {
    wxDC *dc = GetDC();
+
+   ScaleDC(dc);
+   
    if (dc)
    {
-      DrawHeader(*dc,wxPoint(m_Margins.left,m_Margins.top/2),wxPoint(m_Margins.right,m_Margins.top),page);
       int top, bottom;
       top = (page - 1)*m_PrintoutHeight;
       bottom = top + m_PrintoutHeight;
       // SetDeviceOrigin() doesn't work here, so we need to manually
       // translate all coordinates.
-      wxPoint translate(m_Margins.left,-top+m_Margins.top);
-      m_llist->Draw(*dc,top,bottom,wxLayoutObjectList::iterator(NULL),translate);
+      wxPoint translate(m_Offset.x,m_Offset.y-top);
+      m_llist->Draw(*dc, translate, top, bottom);
       return true;
    }
    else
       return false;
 }
 
-bool wxLayoutPrintout::OnBeginDocument(int startPage, int endPage)
-{
-   if (!wxPrintout::OnBeginDocument(startPage, endPage))
-    return false;
-
-  return true;
-}
-
-void
-wxLayoutPrintout::OnPreparePrinting(void)
-{
-   
-}
-
-
 void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
 {
-   // ugly hack to get number of pages
+   /* We allocate a temporary wxDC for printing, so that we can
+      determine the correct paper size and scaling. We don't actually
+      print anything on it. */
 #ifdef __WXMSW__
    wxPrinterDC psdc("","",WXLLIST_TEMPFILE,false);
 #else
    wxPostScriptDC psdc(WXLLIST_TEMPFILE,false);
 #endif
-   psdc.GetSize(&m_PageWidth, &m_PageHeight); // that's all we need it for
 
-   // We do 5% margins on top and bottom, and a 5% high header line.
-   m_Margins.top = m_PageHeight / 10 ;      // 10%, half of it header
-   m_Margins.bottom = m_PageHeight - m_PageHeight / 20;   // 95%
-   // On the sides we reserve 10% each for the margins.
-   m_Margins.left = m_PageWidth / 10;
-   m_Margins.right = m_PageWidth - m_PageWidth / 10;
+   float scale = ScaleDC(&psdc);
 
-   // This is the length of the printable area.
-   m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15); 
+   psdc.GetSize(&m_PageWidth, &m_PageHeight);
+   // This sets a left/top origin of 15% and 20%:
+   m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20);
 
-   //FIXME this is wrong but not used at the moment
-   m_PageWidth = m_Margins.right - m_Margins.left;
+   // This is the length of the printable area.
+   m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15);
+   m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
+   
+   
+   m_NumOfPages = 1 +
+      (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));
 
-   m_NumOfPages = (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight) + 0.5);
    *minPage = 1;
    *maxPage = m_NumOfPages;
 
@@ -1315,17 +2161,20 @@ bool wxLayoutPrintout::HasPage(int pageNum)
    return pageNum <= m_NumOfPages;
 }
 
-
+/*
+  Stupid wxWindows doesn't draw proper ellipses, so we comment this
+  out. It's a waste of paper anyway.
+*/
+#if 0
 void
 wxLayoutPrintout::DrawHeader(wxDC &dc,
                              wxPoint topleft, wxPoint bottomright,
                              int pageno)
 {
    // make backups of all essential parameters
-   wxBrush &brush = dc.GetBrush();
-   wxPen   &pen = dc.GetPen();
-   wxFont  &font = dc.GetFont(),
-           *myfont;
+   const wxBrush& brush = dc.GetBrush();
+   const wxPen&   pen = dc.GetPen();
+   const wxFont&  font = dc.GetFont();
    
    dc.SetBrush(*wxWHITE_BRUSH);
    dc.SetPen(wxPen(*wxBLACK,0,wxSOLID));
@@ -1333,8 +2182,9 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
                            topleft.y,bottomright.x-topleft.x,
                            bottomright.y-topleft.y);  
    dc.SetBrush(*wxBLACK_BRUSH);
-   myfont = new wxFont((WXLO_DEFAULTFONTSIZE*12)/10,wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
-   dc.SetFont(*myfont);
+   wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
+                          wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
+   dc.SetFont(myfont);
 
    wxString page;
    page = "9999/9999  ";  // many pages...
@@ -1349,13 +2199,7 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
    dc.SetPen(pen);
    dc.SetBrush(brush);
    dc.SetFont(font);
-
-   delete myfont;
 }
+#endif
 
 
-wxLayoutPrintout *
-wxLayoutList::MakePrintout(wxString const &name)
-{
-   return new wxLayoutPrintout(*this,name);
-}