]> git.saurik.com Git - wxWidgets.git/blobdiff - user/wxLayout/wxllist.cpp
First part of fixes to make this work under MSW.
[wxWidgets.git] / user / wxLayout / wxllist.cpp
index 2181189c6d7bdf5453c508062ffb41483da61596..906aead71a11c6d338f5533e793eda2a67b7eab3 100644 (file)
@@ -7,28 +7,45 @@
  *******************************************************************/
 
 /*
-  
+
  */
+
 #ifdef __GNUG__
-#pragma implementation "wxllist.h"
+    #pragma implementation "wxllist.h"
+#endif
+
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#  pragma hdrstop
 #endif
 
-//#include "Mpch.h"
-#ifdef M_PREFIX
+#include "Mpch.h"
+
+#ifdef M_BASEDIR
 #   include "gui/wxllist.h"
+#   include "gui/wxlparser.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/dcps.h>
-#   include   <wx/print.h>
-#   include   <wx/log.h>
+#   include <iostream.h>
+
+#   include <wx/dc.h>
+#   include <wx/dcps.h>
+#   include <wx/print.h>
+#   include <wx/log.h>
+#   include <wx/filefn.h>
 #endif
 
+#ifdef WXLAYOUT_USE_CARET
+#   include <wx/caret.h>
+#endif // WXLAYOUT_USE_CARET
+
 #include <ctype.h>
 
 /// This should never really get created
 
 #ifdef WXLAYOUT_DEBUG
 
-#  define   TypewxString(t)        g_aTypewxStrings[t]
+#  define   TypeString(t)      g_aTypeStrings[t]
 #  define   WXLO_DEBUG(x)      wxLogDebug x
 
-   static const char *g_aTypewxStrings[] = 
-   { 
+   static const char *g_aTypeStrings[] =
+   {
       "invalid", "text", "cmd", "icon"
    };
    void
    wxLayoutObject::Debug(void)
    {
-      WXLO_DEBUG(("%s",g_aTypewxStrings[GetType()])); 
+      WXLO_DEBUG(("%s",g_aTypeStrings[GetType()]));
    }
-#else 
-#  define   TypewxString(t)        ""
-#  define   WXLO_DEBUG(x)      
+#else
+#  define   TypeString(t)        ""
+#  define   WXLO_DEBUG(x)
 #endif
 
+// FIXME under MSW, this constant is needed to make the thing properly redraw
+//       itself - I don't know where the size calculation error is and I can't
+//       waste time looking for it right now. Search for occurences of
+//       MSW_CORRECTION to find all the places where I did it.
+#ifdef __WXMSW__
+   static const int MSW_CORRECTION = 10;
+#else
+   static const int MSW_CORRECTION = 0;
+#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)
+{
+   return p1.y < p2.y || (p1.y == p2.y && p1.x <= p2.x);
+}
+
+/// grows a wxRect so that it includes the given point
 
-/// Helper function, allows me to compare to wxPoints
-bool operator ==(wxPoint const &p1, wxPoint const &p2)
+static
+void GrowRect(wxRect &r, CoordType x, CoordType y)
 {
-   return p1.x == p2.x && p1.y == p2.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;
 }
 
-/// Helper function, allows me to compare to wxPoints
-bool operator !=(wxPoint const &p1, wxPoint const &p2)
+#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
+
+
+//@}
+
+
+void ReadString(wxString &to, wxString &from)
+{
+   to = "";
+   const char *cptr = from.c_str();
+   while(*cptr && *cptr != '\n')
+      to += *cptr++;
+   if(*cptr) cptr++;
+   from = cptr;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObject
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* static */
+wxLayoutObject *
+wxLayoutObject::Read(wxString &istr)
 {
-   return p1.x != p2.x || p1.y != p2.y;
+   wxString tmp;
+   ReadString(tmp, istr);
+   int type = -1;
+   sscanf(tmp.c_str(),"%d", &type);
+
+   switch(type)
+   {
+   case WXLO_TYPE_TEXT:
+      return wxLayoutObjectText::Read(istr);
+   case WXLO_TYPE_CMD:
+      return wxLayoutObjectCmd::Read(istr);
+   case WXLO_TYPE_ICON:
+      return wxLayoutObjectIcon::Read(istr);
+   default:
+      return NULL;
+   }
 }
 
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
    wxLayoutObjectText
 
@@ -87,6 +176,34 @@ wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
    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;
+}
+
+
+void
+wxLayoutObjectText::Write(wxString &ostr)
+{
+   ostr << (int) WXLO_TYPE_TEXT << '\n'
+        << m_Text << '\n';
+}
+/* static */
+wxLayoutObjectText *
+wxLayoutObjectText::Read(wxString &istr)
+{
+   wxString text;
+   ReadString(text, istr);
+
+   return new wxLayoutObjectText(text);
+}
 
 wxPoint
 wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
@@ -97,22 +214,100 @@ wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
 }
 
 void
-wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords)
+wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords,
+                         wxLayoutList *wxllist,
+                         CoordType begin, CoordType end)
 {
-   dc.DrawText(m_Text, coords.x, coords.y-m_Top);
+   if( end <= 0)
+      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;
+
+      if(begin < 0) begin = 0;
+      if( end > (signed)m_Text.Length() )
+         end = m_Text.Length();
+
+      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)
+wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList *llist)
 {
    long descent = 0l;
 
-   dc.GetTextExtent(m_Text,&m_Width, &m_Height, &descent);
+   CoordType widthOld = m_Width,
+             heightOld = m_Height;
+   dc.GetTextExtent(m_Text, &m_Width, &m_Height, &descent);
+
+   if ( widthOld != m_Width || heightOld != m_Height )
+   {
+      // as the text length changed, it must be refreshed
+      wxLayoutLine *line = GetLine();
+
+      wxCHECK_RET( line, "wxLayoutObjectText can't refresh itself" );
+
+      // as our size changed, we need to repaint the part which was appended
+      wxPoint position(line->GetPosition());
+
+      // this is not the most efficient way (we repaint the whole line), but
+      // it's not too slow and is *simple*
+      if ( widthOld < m_Width )
+         widthOld = m_Width;
+      if ( heightOld < m_Height )
+         heightOld = m_Height;
+
+      llist->SetUpdateRect(position.x + widthOld + MSW_CORRECTION,
+                           position.y + heightOld + MSW_CORRECTION);
+   }
+
    m_Bottom = descent;
    m_Top = m_Height - m_Bottom;
 }
 
+
 #ifdef WXLAYOUT_DEBUG
 void
 wxLayoutObjectText::Debug(void)
@@ -122,7 +317,7 @@ wxLayoutObjectText::Debug(void)
 }
 #endif
 
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
    wxLayoutObjectIcon
 
@@ -133,19 +328,63 @@ wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
    m_Icon = new wxBitmap(icon);
 }
 
+
+void
+wxLayoutObjectIcon::Write(wxString &ostr)
+{
+   /* Exports icon through a temporary file. */
+
+   wxString file = wxGetTempFileName("wxloexport");
+
+   ostr << WXLO_TYPE_ICON << '\n'
+        << file << '\n';
+   m_Icon->SaveFile(file, WXLO_BITMAP_FORMAT);
+}
+/* static */
+wxLayoutObjectIcon *
+wxLayoutObjectIcon::Read(wxString &istr)
+{
+   wxString file;
+   ReadString(file, istr);
+
+   if(! wxFileExists(file))
+      return NULL;
+   wxLayoutObjectIcon *obj = new wxLayoutObjectIcon;
+
+   if(!obj->m_Icon->LoadFile(file, WXLO_BITMAP_FORMAT))
+   {
+      delete obj;
+      return NULL;
+   }
+   else
+      return obj;
+}
+
+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 &coords)
+wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords,
+                         wxLayoutList *wxllist,
+                         CoordType begin, CoordType /* len */)
 {
-   dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight());
+   dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight(),
+                 (m_Icon->GetMask() == NULL) ? FALSE : TRUE);
 }
 
 void
-wxLayoutObjectIcon::Layout(wxDC & /* dc */)
+wxLayoutObjectIcon::Layout(wxDC & /* dc */, class wxLayoutList * )
 {
 }
 
@@ -159,88 +398,205 @@ wxLayoutObjectIcon::GetSize(CoordType *top, CoordType *bottom) const
 
 
 
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
-   wxLayoutObjectIcon
+   wxLayoutObjectCmd
 
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
-                                     weight, bool underline,
-                                     wxColour const *fg, wxColour const *bg)
-   
+
+wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily,
+                                     int isize,
+                                     int istyle,
+                                     int iweight,
+                                     int iul,
+                                     wxColour *fg,
+                                     wxColour *bg)
+{
+   family = ifamily; size = isize;
+   style = istyle; weight = iweight;
+   underline = iul != 0;
+   if(fg)
+   {
+      m_fg = *fg;
+      m_fg_valid = TRUE;
+   }
+   else
+      m_fg = *wxBLACK;
+   if(bg)
+   {
+      m_bg = *bg;
+      m_bg_valid = TRUE;
+   }
+   else
+      m_bg = *wxWHITE;
+}
+
+#define COPY_SI_(what) if(right.what != -1) what = right.what;
+
+wxLayoutStyleInfo &
+wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo &right)
 {
-   m_font = new wxFont(size,family,style,weight,underline);
-   m_ColourFG = fg;
-   m_ColourBG = bg;
+   COPY_SI_(family);
+   COPY_SI_(style);
+   COPY_SI_(size);
+   COPY_SI_(weight);
+   COPY_SI_(underline);
+   if(right.m_fg_valid) m_fg = right.m_fg;
+   if(right.m_bg_valid) m_bg = right.m_bg;
+   return *this;
 }
 
-wxLayoutObjectCmd::~wxLayoutObjectCmd()
+wxLayoutObjectCmd::wxLayoutObjectCmd(int family, int size, int style, int
+                                     weight, int underline,
+                                     wxColour *fg, wxColour *bg)
+
+{
+   m_StyleInfo = new wxLayoutStyleInfo(family, size,style,weight,underline,fg,bg);
+}
+
+wxLayoutObject *
+wxLayoutObjectCmd::Copy(void)
 {
-   delete m_font;
+   wxLayoutObjectCmd *obj = new wxLayoutObjectCmd(
+      m_StyleInfo->size,
+      m_StyleInfo->family,
+      m_StyleInfo->style,
+      m_StyleInfo->weight,
+      m_StyleInfo->underline,
+      m_StyleInfo->m_fg_valid ?
+      &m_StyleInfo->m_fg : NULL,
+      m_StyleInfo->m_bg_valid ?
+      &m_StyleInfo->m_bg : NULL);
+   obj->SetUserData(m_UserData);
+   return obj;
 }
 
 void
-wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo *si) const
+wxLayoutObjectCmd::Write(wxString &ostr)
+{
+   ostr << WXLO_TYPE_CMD << '\n'
+        << m_StyleInfo->size << '\n'
+        << m_StyleInfo->family << '\n'
+        << m_StyleInfo->style << '\n'
+        << m_StyleInfo->weight << '\n'
+        << m_StyleInfo->underline << '\n'
+        << m_StyleInfo->m_fg_valid << '\n'
+        << m_StyleInfo->m_bg_valid << '\n';
+   if(m_StyleInfo->m_fg_valid)
+   {
+      ostr << m_StyleInfo->m_fg.Red() << '\n'
+           << m_StyleInfo->m_fg.Green() << '\n'
+           << m_StyleInfo->m_fg.Blue() << '\n';
+   }
+   if(m_StyleInfo->m_bg_valid)
+   {
+      ostr << m_StyleInfo->m_bg.Red() << '\n'
+           << m_StyleInfo->m_bg.Green() << '\n'
+           << m_StyleInfo->m_bg.Blue() << '\n';
+   }
+}
+/* static */
+wxLayoutObjectCmd *
+wxLayoutObjectCmd::Read(wxString &istr)
 {
-   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();
+   wxLayoutObjectCmd *obj = new wxLayoutObjectCmd;
+
+   wxString tmp;
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->size);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->family);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->style);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->weight);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->underline);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_fg_valid);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_bg_valid);
+   if(obj->m_StyleInfo->m_fg_valid)
+   {
+      int red, green, blue;
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &red);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &green);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &blue);
+      obj->m_StyleInfo->m_fg = wxColour(red, green, blue);
+   }
+   if(obj->m_StyleInfo->m_bg_valid)
+   {
+      int red, green, blue;
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &red);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &green);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &blue);
+      obj->m_StyleInfo->m_bg = wxColour(red, green, blue);
+   }
+   return obj;
+}
+
+
+wxLayoutObjectCmd::~wxLayoutObjectCmd()
+{
+   delete m_StyleInfo;
+}
 
-   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();
+wxLayoutStyleInfo *
+wxLayoutObjectCmd::GetStyle(void) const
+{
+   return m_StyleInfo;
 }
 
 void
-wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */)
+wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */,
+                        wxLayoutList *wxllist,
+                        CoordType begin, CoordType /* len */)
 {
-   wxASSERT(m_font);
-   dc.SetFont(*m_font);
-   if(m_ColourFG) dc.SetTextForeground(*m_ColourFG);
-   if(m_ColourBG) dc.SetTextBackground(*m_ColourBG);
+   wxASSERT(m_StyleInfo);
+   wxllist->ApplyStyle(m_StyleInfo, dc);
 }
 
 void
-wxLayoutObjectCmd::Layout(wxDC &dc)
+wxLayoutObjectCmd::Layout(wxDC &dc, class wxLayoutList * llist)
 {
    // this get called, so that recalculation uses right font sizes
-   Draw(dc, wxPoint(0,0));
+   Draw(dc, wxPoint(0,0), llist);
 }
 
 
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
    The wxLayoutLine object
 
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-wxLayoutLine::wxLayoutLine(wxLayoutLine *prev)
+wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
 {
    m_LineNumber = 0;
-   m_Height = 0;
+   m_Width = m_Height = 0;
    m_Length = 0;
    m_Dirty = true;
    m_Previous = prev;
    m_Next = NULL;
-   RecalculatePosition();
+   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);
+      m_Next->RecalculatePositions(1,llist);
    }
 }
 
@@ -250,33 +606,42 @@ wxLayoutLine::~wxLayoutLine()
 }
 
 wxPoint
-wxLayoutLine::RecalculatePosition(void)
+wxLayoutLine::RecalculatePosition(wxLayoutList *llist)
 {
+   wxASSERT(m_Previous || GetLineNumber() == 0);
+
    if(m_Previous)
-      m_Position = m_Previous->RecalculatePosition() +
-         wxPoint(0,m_Previous->GetHeight());
+   {
+      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)
+wxLayoutLine::RecalculatePositions(int recurse, wxLayoutList *llist)
 {
-   wxPoint pos = RecalculatePosition();
+   //FIXME: is this really needed? We run Layout() anyway.
+   // Recursing here, drives computation time up exponentially, as
+   // each line will cause all following lines to be recalculated.
+   // Yes, or linenumbers go wrong.
 
-   if(pos != m_Position)
-   {
-      m_Position = pos;
-      if(m_Next) m_Next->RecalculatePositions(--recurse);
-   }
-   else
+   wxASSERT(recurse >= 0);
+   wxPoint pos = m_Position;
+   CoordType height = m_Height;
+
+//   WXLO_TRACE("RecalculatePositions()");
+   RecalculatePosition(llist);
+   if(m_Next)
    {
-      m_Position = pos;
-      if(recurse && m_Next)
-         m_Next->RecalculatePositions(--recurse);
+      if(recurse > 0)
+         m_Next->RecalculatePositions(--recurse, llist);
+      else if(pos != m_Position || m_Height != height)
+         m_Next->RecalculatePositions(0, llist);
    }
-      
 }
 
 wxLayoutObjectList::iterator
@@ -284,20 +649,89 @@ wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const
 {
    wxASSERT(xpos >= 0);
    wxASSERT(offset);
-   wxLayoutObjectList::iterator i;
+   wxLayoutObjectList::iterator
+      i,
+      found = NULLIT;
    CoordType x = 0, len;
-   
+
+   /* 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 )
       {
          *offset = xpos-x;
-         return i;
+         if(xpos == x + len) // is there another object behind?
+            found = i;
+         else  // we are really inside this object
+            return i;
       }
       x += (**i).GetLength();
    }
-   return NULLIT;
+   return found;  // ==NULL if really none found
+}
+
+wxLayoutObjectList::iterator
+wxLayoutLine::FindObjectScreen(wxDC &dc,
+                               CoordType xpos, CoordType *cxpos,
+                               bool *found) const
+{
+   wxASSERT(cxpos);
+   wxASSERT(cxpos);
+   wxLayoutObjectList::iterator i;
+   CoordType x = 0, cx = 0, width;
+
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      width = (**i).GetWidth();
+      if( x <= xpos && xpos <= x + width )
+      {
+         *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
+         if(found) *found = true;
+         return i;
+      }
+      x += (**i).GetWidth();
+      cx += (**i).GetLength();
+   }
+   // behind last object:
+   *cxpos = cx;
+   if(found) *found = false;
+   return m_ObjectList.tail();
+}
+
+/** 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) const
+{
+   int
+      cpos = 0,
+      relpos = -1;
+   wxString const *text;
+
+   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
 }
 
 bool
@@ -305,6 +739,12 @@ wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
 {
    wxASSERT(xpos >= 0);
    wxASSERT(obj != NULL);
+
+   // in any case, the object is going to belong to this line
+   obj->AttachToLine(this);
+
+   //FIXME: this could be optimised, for now be prudent:
+   m_Dirty = true;
    CoordType offset;
    wxLOiterator i = FindObject(xpos, &offset);
    if(i == NULLIT)
@@ -329,16 +769,13 @@ wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
    if(offset == len )
    {
       if( i == m_ObjectList.tail()) // last object?
-      {
          m_ObjectList.push_back(obj);
-         m_Length += obj->GetLength();
-      }
       else
       {  // insert after current object
          i++;
          m_ObjectList.insert(i,obj);
-         m_Length += obj->GetLength();
       }
+         m_Length += obj->GetLength();
       return true;
    }
    /* Otherwise we need to split the current object.
@@ -357,11 +794,13 @@ wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
    m_ObjectList.insert(i,new wxLayoutObjectText(left));
    return true;
 }
-   
+
 bool
 wxLayoutLine::Insert(CoordType xpos, wxString text)
 {
    wxASSERT(xpos >= 0);
+   //FIXME: this could be optimised, for now be prudent:
+   m_Dirty = true;
    CoordType offset;
    wxLOiterator i = FindObject(xpos, &offset);
    if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
@@ -379,22 +818,25 @@ wxLayoutLine::Insert(CoordType xpos, wxString text)
 CoordType
 wxLayoutLine::Delete(CoordType xpos, CoordType npos)
 {
-   CoordType offset;
+   CoordType offset, len;
 
    wxASSERT(xpos >= 0);
    wxASSERT(npos >= 0);
+   //FIXME: this could be optimised, for now be prudent:
+   m_Dirty = true;
    wxLOiterator i = FindObject(xpos, &offset);
    while(npos > 0)
    {
-      if(i == NULLIT)  return false; // FIXME
+      if(i == NULLIT)  return npos;
       // now delete from that object:
       if((**i).GetType() != WXLO_TYPE_TEXT)
       {
          if(offset != 0) // at end of line after a non-text object
             return npos;
          // always len == 1:
-         m_Length -= (**i).GetLength();
-         npos -= m_Length;
+         len = (**i).GetLength();
+         m_Length -= len;
+         npos -= len;
          m_ObjectList.erase(i);
       }
       else
@@ -412,7 +854,7 @@ wxLayoutLine::Delete(CoordType xpos, CoordType npos)
          {
             if(xpos == GetLength())
                return npos;
-            else 
+            else
             {  // at    the end of an object
                // move to    begin of next object:
                i++; offset = 0;
@@ -427,6 +869,7 @@ wxLayoutLine::Delete(CoordType xpos, CoordType npos)
             ((wxLayoutObjectText *)(*i))->GetText().Remove(offset,max);
       }
    }
+
    return npos;
 }
 
@@ -435,6 +878,8 @@ wxLayoutLine::DeleteWord(CoordType xpos)
 {
    wxASSERT(xpos >= 0);
    CoordType offset;
+   //FIXME: this could be optimised, for now be prudent:
+   m_Dirty = true;
 
    wxLOiterator i = FindObject(xpos, &offset);
 
@@ -443,7 +888,7 @@ wxLayoutLine::DeleteWord(CoordType xpos)
       if(i == NULLIT) return false;
       if((**i).GetType() != WXLO_TYPE_TEXT)
       {
-         // This should only happen when at end of line, behind a non-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
@@ -463,28 +908,28 @@ wxLayoutLine::DeleteWord(CoordType xpos)
          str = str.substr(offset,str.Length()-offset);
          // Find out how many positions we need to delete:
          // 1. eat leading space
-         while(isspace(str[count])) count++;
+         while(isspace(str.c_str()[count])) count++;
          // 2. eat the word itself:
-         while(isalnum(str[count])) count++;
+         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;
-      }      
+      }
    }
    wxASSERT(0); // we should never arrive here
 }
 
 wxLayoutLine *
-wxLayoutLine::DeleteLine(bool update)
+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);
+      m_Next->RecalculatePositions(1, llist);
    }
    wxLayoutLine *next = m_Next;
    delete this;
@@ -492,29 +937,55 @@ wxLayoutLine::DeleteLine(bool update)
 }
 
 void
-wxLayoutLine::Draw(wxDC &dc, const wxPoint & offset) const
+wxLayoutLine::Draw(wxDC &dc,
+                   wxLayoutList *llist,
+                   const wxPoint & offset) const
 {
    wxLayoutObjectList::iterator i;
    wxPoint pos = offset;
    pos = pos + GetPosition();
-   
+
    pos.y += m_BaseLine;
-   
+
+   CoordType xpos = 0; // cursorpos, lenght of line
+
+   CoordType from, to, tempto;
+   //FIXME This doesn't work yet, needs updating afterr default
+   //settings for list or a wxLayoutObjectCmd have changed:
+   //llist->ApplyStyle(&((wxLayoutLine *)this)->m_StyleInfo, dc);
+   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
+      llist->EndHighlighting(dc);
+
    for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      (**i).Draw(dc, pos);
+      if(highlight == -1) // partially highlight line
+      {
+         // parts of the line need highlighting
+         tempto = xpos+(**i).GetLength();
+         (**i).Draw(dc, pos, llist, from-xpos, to-xpos);
+      }
+      else
+         (**i).Draw(dc, pos, llist);
       pos.x += (**i).GetWidth();
+      xpos += (**i).GetLength();
    }
 }
 
 void
-wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, wxPoint
-                     *cursorSize,
-                     int cx) 
+wxLayoutLine::Layout(wxDC &dc,
+                     wxLayoutList *llist,
+                     wxPoint *cursorPos,
+                     wxPoint *cursorSize,
+                     int cx)
 {
    wxLayoutObjectList::iterator i;
 
    CoordType
+      oldWidth = m_Width,
       oldHeight = m_Height;
    CoordType
       topHeight, bottomHeight;  // above and below baseline
@@ -529,14 +1000,20 @@ wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, wxPoint
    wxPoint size;
    bool cursorFound = false;
 
+   m_Dirty = false;
+
    if(cursorPos)
    {
       *cursorPos = m_Position;
+      if(cursorSize) *cursorSize = wxPoint(0,0);
    }
-   
+
+   //FIXME This doesn't work yet, needs updating afterr default
+   //settings for list or a wxLayoutObjectCmd have changed:
+   //llist->ApplyStyle(&m_StyleInfo, dc);
    for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      (**i).Layout(dc);
+      (**i).Layout(dc, llist);
       size = (**i).GetSize(&objTopHeight, &objBottomHeight);
 
       if(cursorPos && ! cursorFound)
@@ -548,7 +1025,7 @@ wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, wxPoint
             {
                len = cx - count; // pos in object
                CoordType width, height, descent;
-               dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len), 
+               dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len),
                                 &width, &height, &descent);
                cursorPos->x += width;
                cursorPos->y = m_Position.y;
@@ -566,7 +1043,7 @@ wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, wxPoint
                cursorSize->y = height;
                cursorFound = true; // no more checks
             }
-            else 
+            else
             { // on some other object
                CoordType top, bottom; // unused
                *cursorSize = (**i).GetSize(&top,&bottom);
@@ -586,100 +1063,86 @@ wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, wxPoint
       if(objTopHeight > topHeight) topHeight = objTopHeight;
       if(objBottomHeight > bottomHeight) bottomHeight = objBottomHeight;
    }
-   if(topHeight + bottomHeight > m_Height) m_Height =
-                                              topHeight+bottomHeight;
+
+   // special case of a line which becomes empty (after deletion, for example):
+   // we should invalidate the screen space it occupied (usually this happens
+   // from wxLayoutObject::Layout called in the loop above)
+   if ( m_ObjectList.empty() )
+   {
+      wxPoint position(GetPosition());
+      llist->SetUpdateRect(position.x + oldWidth + MSW_CORRECTION,
+                           position.y + oldHeight + MSW_CORRECTION);
+   }
+
+   if(topHeight + bottomHeight > m_Height)
+      m_Height = topHeight+bottomHeight;
    m_BaseLine = topHeight;
 
    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;
-      }
+      CoordType width, height, descent;
+      dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+      m_Height = height;
+      m_BaseLine = m_Height - descent;
    }
 
-   
+
    // tell next line about coordinate change
    if(m_Next && objHeight != oldHeight)
-      m_Next->RecalculatePositions();
+      m_Next->RecalculatePositions(0, llist);
 
+   // We need to check whether we found a valid cursor size:
    if(cursorPos)
    {
       // 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)
       {
-         if(m_BaseLine > 0)
-         {
-            cursorSize->y = m_BaseLine;
-            if(cursorSize->x < WXLO_MINIMUM_CURSOR_WIDTH) cursorSize->x = WXLO_MINIMUM_CURSOR_WIDTH;
-         }
-         else // empty line
-         {
-            CoordType width, height, descent;
-            dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
-            cursorSize->x = width;
-            cursorSize->y = height;
-         }
+         CoordType width, height, descent;
+         dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+         cursorSize->x = width;
+         cursorSize->y = height;
       }
       if(m_BaseLine >= cursorSize->y) // the normal case anyway
          cursorPos->y += m_BaseLine-cursorSize->y;
    }
+   RecalculatePositions(1, llist);
 }
 
-wxLayoutObject *
-wxLayoutLine::FindObject(CoordType xpos)
-{
-   wxASSERT(xpos >= 0);
-   if(xpos > GetWidth()) return NULL;
-
-   CoordType x = 0;
-   for(wxLOiterator i = m_ObjectList.begin(); i != NULLIT; i++)
-   {
-      x += (**i).GetWidth();
-      if(x > xpos) // we just crossed it
-         return *i;
-   }
-   return NULL;
-}
 
 wxLayoutLine *
-wxLayoutLine::Break(CoordType xpos)
+wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
 {
    wxASSERT(xpos >= 0);
-   
-   if(xpos == 0)
+   //FIXME: this could be optimised, for now be prudent:
+   m_Dirty = true;
+
+   /* If we are at the begin of a line, we want to move all other
+      lines down and stay with the cursor where we are. However, if we
+      are in an empty line, we want to move down with it. */
+   if(xpos == 0 && GetLength() > 0)
    { // insert an empty line before this one
-      wxLayoutLine *prev = new wxLayoutLine(m_Previous);
+      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
+         m_Previous->m_Height = 0; // this is a wild guess
       }
-      MoveLines(+1);
       if(m_Next)
-         m_Next->RecalculatePositions(1);
-      return this;
+         m_Next->RecalculatePositions(1, llist);
+      return m_Previous;
    }
-   
+
    CoordType offset;
    wxLOiterator i = FindObject(xpos, &offset);
    if(i == NULLIT)
       // must be at the end of the line then
-      return new wxLayoutLine(this);
+      return new wxLayoutLine(this, llist);
    // split this line:
 
-   wxLayoutLine *newLine = new wxLayoutLine(this);
+   wxLayoutLine *newLine = new wxLayoutLine(this, llist);
    // split object at i:
    if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0)
    {
@@ -690,7 +1153,7 @@ wxLayoutLine::Break(CoordType xpos)
       // current text object gets set to left half
       tobj->GetText() = left; // set new text
       newLine->Append(new wxLayoutObjectText(right));
-      m_Length -= m_Length - offset;
+      m_Length -= right.Length();
       i++; // don't move this object to the new list
    }
    else
@@ -704,86 +1167,275 @@ wxLayoutLine::Break(CoordType xpos)
       m_ObjectList.remove(i); // remove without deleting it
    }
    if(m_Next)
-      m_Next->RecalculatePositions(2);
+      m_Next->RecalculatePositions(2, llist);
    return newLine;
 }
-   
+
 
 void
-wxLayoutLine::MergeNextLine(void)
+wxLayoutLine::MergeNextLine(wxLayoutList *llist)
 {
-   wxASSERT(GetNextLine());
+   wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
    wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
    wxLOiterator i;
-   
+   //FIXME: this could be optimised, for now be prudent:
+   m_Dirty = true;
+
+   wxLayoutObject *last = NULL;
    for(i = list.begin(); i != list.end();)
    {
-      Append(*i);
-      list.remove(i); // remove without deleting it
+      wxLayoutObject *current = *i;
+
+      // merge text objects together for efficiency
+      if ( last && last->GetType() == WXLO_TYPE_TEXT &&
+                   current->GetType() == WXLO_TYPE_TEXT )
+      {
+         wxLayoutObjectText *textObj = (wxLayoutObjectText *)last;
+         wxString text(textObj->GetText());
+         text += ((wxLayoutObjectText *)current)->GetText();
+         textObj->SetText(text);
+
+         list.erase(i); // remove and delete it
+      }
+      else
+      {
+         // just append the object "as was"
+         current->UnattachFromLine();
+         Append(current);
+
+         list.remove(i); // remove without deleting it
+      }
    }
    wxASSERT(list.empty());
+
    wxLayoutLine *oldnext = GetNextLine();
-   SetNext(GetNextLine()->GetNextLine());
+   wxLayoutLine *nextLine = oldnext->GetNextLine();
+   SetNext(nextLine);
    delete oldnext;
-   RecalculatePositions(1);
-}
-
-   
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-   
-   The wxLayoutList object
-   
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-wxLayoutList::wxLayoutList()
-{
-   m_DefaultSetting = NULL;
-   m_FirstLine = NULL;
-   InternalClear();
-}
+   if ( nextLine )
+   {
+      nextLine->MoveLines(-1);
+   }
 
-wxLayoutList::~wxLayoutList()
-{
-   InternalClear();
+   // no RecalculatePositions needed - called from Delete() anyhow
 }
 
-void
-wxLayoutList::InternalClear(void)
+CoordType
+wxLayoutLine::GetWrapPosition(CoordType column)
 {
-   while(m_FirstLine)
-      m_FirstLine = m_FirstLine->DeleteLine(false);
+   CoordType offset;
+   wxLOiterator i = FindObject(column, &offset);
+   if(i == NULLIT) return -1; // cannot wrap
 
-   if(m_DefaultSetting)
+   // go backwards through the list and look for space in text objects
+   do
    {
-      delete m_DefaultSetting;
-      m_DefaultSetting = NULL;
-   }
-
-   m_CursorPos = wxPoint(0,0);
-   m_CursorScreenPos = wxPoint(0,0);
-   m_CursorSize = wxPoint(0,0);
-   m_FirstLine = new wxLayoutLine(NULL); // empty first line
-   m_CursorLine = m_FirstLine;
-}
+      if((**i).GetType() == WXLO_TYPE_TEXT)
+      {
+         do
+         {
+            if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
+               return column;
+            else
+            {
+               offset--;
+               column--;
+            }
+         }while(offset != -1);
+         i--;  // move on to previous object
+      }
+      else
+      {
+         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++;
+   }
+   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
+wxLayoutLine::Debug(void)
+{
+   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();
+
+}
+#endif
+
+void
+wxLayoutLine::Copy(wxLayoutList *llist,
+                   CoordType from,
+                   CoordType to)
+{
+   CoordType firstOffset, lastOffset;
+
+   if(to == -1) to = GetLength();
+   if(from == to) return;
+
+   wxLOiterator first = FindObject(from, &firstOffset);
+   wxLOiterator last  = FindObject(to, &lastOffset);
+
+   // Common special case: only one object
+   if( first != NULLIT && last != NULLIT && *first == *last )
+   {
+      if( (**first).GetType() == WXLO_TYPE_TEXT )
+      {
+         llist->Insert(new wxLayoutObjectText(
+            ((wxLayoutObjectText
+              *)*first)->GetText().substr(firstOffset,
+                                          lastOffset-firstOffset))
+            );
+         return;
+      }
+      else // what can we do?
+      {
+         if(lastOffset > firstOffset) // i.e. +1 :-)
+            llist->Insert( (**first).Copy() );
+         return;
+      }
+   }
+
+   // 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 )
+      {
+         llist->Insert(new wxLayoutObjectText(
+            ((wxLayoutObjectText *)*last)->GetText().substr(0,lastOffset))
+            );
+      }
+      else
+         llist->Insert( (**last).Copy() );
+   }
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayoutList object
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutList::wxLayoutList()
+{
+#ifdef WXLAYOUT_USE_CARET
+   m_caret = NULL;
+#endif // WXLAYOUT_USE_CARET
+
+   m_FirstLine = NULL;
+   InvalidateUpdateRect();
+   Clear();
+}
+
+wxLayoutList::~wxLayoutList()
+{
+   InternalClear();
+   m_FirstLine->DeleteLine(false, this);
+}
+
+void
+wxLayoutList::Empty(void)
+{
+   while(m_FirstLine)
+      m_FirstLine = m_FirstLine->DeleteLine(false, this);
+
+   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();
+}
+
+
+void
+wxLayoutList::InternalClear(void)
+{
+   Empty();
+   m_Selection.m_selecting = false;
+   m_Selection.m_valid = false;
+
+   m_DefaultSetting.family = wxSWISS;
+   m_DefaultSetting.size = WXLO_DEFAULTFONTSIZE;
+   m_DefaultSetting.style = wxNORMAL;
+   m_DefaultSetting.weight = wxNORMAL;
+   m_DefaultSetting.underline = 0;
+   m_DefaultSetting.m_fg_valid = TRUE;
+   m_DefaultSetting.m_fg = *wxBLACK;
+   m_DefaultSetting.m_bg_valid = TRUE;
+   m_DefaultSetting.m_bg = *wxWHITE;
+
+   m_CurrentSetting = m_DefaultSetting;
+}
 
 void
 wxLayoutList::SetFont(int family, int size, int style, int weight,
-                      int underline, wxColour const *fg,
-                      wxColour const *bg)
-{
-   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(fg != NULL)     m_ColourFG = fg;
-   if(bg != NULL)     m_ColourBG = bg;
-   
+                      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) m_CurrentSetting.m_fg = *fg;
+   if(bg) m_CurrentSetting.m_bg = *bg;
    Insert(
-      new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
-                            m_ColourFG, m_ColourBG));
+      new wxLayoutObjectCmd(
+         m_CurrentSetting.family,
+         m_CurrentSetting.size,
+         m_CurrentSetting.style,
+         m_CurrentSetting.weight,
+         m_CurrentSetting.underline,
+         fg, bg));
 }
 
 void
@@ -791,53 +1443,59 @@ wxLayoutList::SetFont(int family, int size, int style, int weight,
                       int underline, char const *fg, char const *bg)
 
 {
-   wxColour const
-      * cfg = NULL,
-      * cbg = NULL;
+   wxColour
+      *cfg = NULL,
+      *cbg = NULL;
 
    if( fg )
       cfg = wxTheColourDatabase->FindColour(fg);
    if( bg )
       cbg = wxTheColourDatabase->FindColour(bg);
-   
+
    SetFont(family,size,style,weight,underline,cfg,cbg);
 }
 
 void
 wxLayoutList::Clear(int family, int size, int style, int weight,
-                    int /* underline */, char const *fg, char const *bg)
+                    int underline, wxColour *fg, wxColour *bg)
 {
    InternalClear();
-   
-   // 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);
+   m_DefaultSetting = wxLayoutStyleInfo(family, size, style, weight,
+                                        underline, fg, bg);
+   m_CurrentSetting = m_DefaultSetting;
+}
 
-   if(! m_ColourFG) m_ColourFG = wxBLACK;
-   if(! m_ColourBG) m_ColourBG = wxWHITE;
-   
-   if(m_DefaultSetting)
-      delete m_DefaultSetting;
+wxPoint
+wxLayoutList::FindText(const wxString &needle, const wxPoint &cpos) const
+{
+   int xpos;
 
-   m_DefaultSetting = new
-      wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
-                        m_FontWeight,m_FontUnderline,
-                        m_ColourFG, m_ColourBG);
+   wxLayoutLine *line;
+   for(line = m_FirstLine;
+       line;
+       line = line->GetNextLine())
+   {
+      if(line->GetLineNumber() >= cpos.y)
+      {
+         xpos = line->FindText(needle,
+                               (line->GetLineNumber() == cpos.y) ?
+                               cpos.x : 0);
+         if(xpos != -1)
+            return wxPoint(xpos, line->GetLineNumber());
+      }
+   }
+   return wxPoint(-1,-1);
 }
 
 
-
 bool
 wxLayoutList::MoveCursorTo(wxPoint const &p)
 {
+   AddCursorPosToUpdateRect();
+
    wxLayoutLine *line = m_FirstLine;
    while(line && line->GetLineNumber() != p.y)
-      ;
+      line = line->GetNextLine();
    if(line && line->GetLineNumber() == p.y) // found it
    {
       m_CursorPos.y = p.y;
@@ -856,10 +1514,13 @@ wxLayoutList::MoveCursorTo(wxPoint const &p)
    }
    return false;
 }
-   
+
 bool
 wxLayoutList::MoveCursorVertically(int n)
 {
+   AddCursorPosToUpdateRect();
+
+   bool rc;
    if(n  < 0) // move up
    {
       if(m_CursorLine == m_FirstLine) return false;
@@ -873,13 +1534,13 @@ wxLayoutList::MoveCursorVertically(int n)
       {
          m_CursorLine = m_FirstLine;
          m_CursorPos.y = 0;
-         return false;
+         rc = false;
       }
       else
       {
          if(m_CursorPos.x > m_CursorLine->GetLength())
             m_CursorPos.x = m_CursorLine->GetLength();
-         return true;
+         rc = true;
       }
    }
    else // move down
@@ -896,20 +1557,23 @@ wxLayoutList::MoveCursorVertically(int n)
       {
          m_CursorLine = last;
          m_CursorPos.y ++;
-         return false;
+         rc = false;
       }
       else
       {
          if(m_CursorPos.x > m_CursorLine->GetLength())
             m_CursorPos.x = m_CursorLine->GetLength();
-         return true;
+         rc = true;
       }
    }
+   return rc;
 }
 
 bool
 wxLayoutList::MoveCursorHorizontally(int n)
 {
+   AddCursorPosToUpdateRect();
+
    int move;
    while(n < 0)
    {
@@ -949,8 +1613,12 @@ bool
 wxLayoutList::Insert(wxString const &text)
 {
    wxASSERT(m_CursorLine);
+
+   AddCursorPosToUpdateRect();
+
    m_CursorLine->Insert(m_CursorPos.x, text);
    m_CursorPos.x += text.Length();
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
    return true;
 }
 
@@ -958,55 +1626,160 @@ bool
 wxLayoutList::Insert(wxLayoutObject *obj)
 {
    wxASSERT(m_CursorLine);
+
+   if(! m_CursorLine)
+      m_CursorLine = GetFirstLine();
+
+   AddCursorPosToUpdateRect();
+
    m_CursorLine->Insert(m_CursorPos.x, obj);
    m_CursorPos.x += obj->GetLength();
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
    return true;
 }
 
+bool
+wxLayoutList::Insert(wxLayoutList *llist)
+{
+   wxASSERT(llist);
+   bool rc = TRUE;
+
+   for(wxLayoutLine *line = llist->GetFirstLine();
+       line;
+       line = line->GetNextLine()
+      )
+   {
+      for(wxLOiterator i = line->GetFirstObject();
+          i != NULLIT;
+          i++)
+         rc |= Insert(*i);
+      LineBreak();
+   }
+   return rc;
+}
+
 bool
 wxLayoutList::LineBreak(void)
 {
    wxASSERT(m_CursorLine);
-
    bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
-   m_CursorLine = m_CursorLine->Break(m_CursorPos.x);
+
+   AddCursorPosToUpdateRect();
+
+   wxPoint position(m_CursorLine->GetPosition());
+
+   wxCoord width = m_CursorLine->GetWidth(),
+           height = m_CursorLine->GetHeight();
+
+   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++;
+   if(m_CursorPos.x != 0)
+      m_CursorPos.y++;
    m_CursorPos.x = 0;
+// doesn't help   m_CursorLine.MarkDirty();
+
+   wxLayoutLine *prev = m_CursorLine->GetPreviousLine();
+   wxCHECK_MSG(prev, false, "just broke the line, where is the previous one?");
+
+   height += prev->GetHeight();
+
+   SetUpdateRect(position);
+   SetUpdateRect(position.x + width + MSW_CORRECTION,
+                 position.y + height + MSW_CORRECTION);
+
    return true;
 }
 
+bool
+wxLayoutList::WrapLine(CoordType column)
+{
+   if(m_CursorPos.x <= column || column < 1)
+      return false; // do nothing yet
+   else
+   {
+      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;
+
+      AddCursorPosToUpdateRect();
+
+      LineBreak();
+      Delete(1); // delete the space
+      m_CursorPos.x = newpos;
+      m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+      return true;
+   }
+}
+
 bool
 wxLayoutList::Delete(CoordType npos)
 {
-   wxASSERT(m_CursorLine);
+   wxCHECK_MSG(m_CursorLine, false, "can't delete in non existing line");
+   wxASSERT_MSG(npos > 0, "nothing to delete?");
+
+   AddCursorPosToUpdateRect();
+
+   // were other lines appended to this one (this is important to know because
+   // this means that our width _increased_ as the result of deletion)
+   bool wasMerged = false;
+
+   // the size of the region to update
+   CoordType totalHeight = m_CursorLine->GetHeight(),
+             totalWidth = m_CursorLine->GetWidth();
+
    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
-         m_CursorLine = m_CursorLine->DeleteLine(true);
-         left--;
-      }
-      else 
+
+      if( left > 0 )
       {
-         // Need to join next line
-         if(! m_CursorLine->GetNextLine())
-            break; // cannot
-         else
+         // More to delete, continue on next line.
+
+         // First, check if line is empty:
+         if(m_CursorLine->GetLength() == 0)
          {
-            m_CursorLine->MergeNextLine();
+            // in this case, updating could probably be optimised
+#ifdef WXLO_DEBUG
+            wxASSERT(DeleteLines(1) == 0);
+#else
+            DeleteLines(1);
+#endif
+
             left--;
          }
+         else
+         {
+            // Need to join next line
+            if(! m_CursorLine->GetNextLine())
+               break; // cannot
+            else
+            {
+               wasMerged = true;
+               wxLayoutLine *next = m_CursorLine->GetNextLine();
+               if ( next )
+                  totalHeight += next->GetHeight();
+               m_CursorLine->MergeNextLine(this);
+               left--;
+            }
+         }
       }
    }
-   while(left);
+   while ( left> 0 );
+
+   // we need to update the whole tail of the line and the lines which
+   // disappeared
+   if ( wasMerged )
+   {
+      wxPoint position(m_CursorLine->GetPosition());
+      SetUpdateRect(position.x + totalWidth + MSW_CORRECTION,
+                    position.y + totalHeight + MSW_CORRECTION);
+   }
+
    return left == 0;
 }
 
@@ -1015,91 +1788,164 @@ wxLayoutList::DeleteLines(int n)
 {
    wxASSERT(m_CursorLine);
    wxLayoutLine *line;
+
+   AddCursorPosToUpdateRect();
+
    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);
+      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);
+   m_CursorLine->RecalculatePositions(2, this);
    return n;
 }
 
 void
-wxLayoutList::Layout(wxDC &dc, CoordType bottom) const
+wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
 {
    wxLayoutLine *line = m_FirstLine;
 
    // first, make sure everything is calculated - this might not be
    // needed, optimise it later
-   m_DefaultSetting->Layout(dc);
+   ApplyStyle(&m_DefaultSetting, dc);
    while(line)
    {
-      if(line == m_CursorLine)
-         line->Layout(dc, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
-      else
-         line->Layout(dc);
+      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();
    }
+}
+
+void
+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;
+}
+
+/*
+  Is called before each Draw(). Now, it will re-layout all lines which
+  have changed.
+*/
+void
+wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll)
+{
+   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(forceAll || line->IsDirty())
+      {
+         line->GetStyleInfo() = m_CurrentSetting;
+         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->RecalculatePositions(1,this);
+      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
+   AddCursorPosToUpdateRect();
 }
 
 void
-wxLayoutList::Draw(wxDC &dc, wxPoint const &offset,
-                   CoordType top, CoordType bottom) const
+wxLayoutList::Draw(wxDC &dc,
+                   wxPoint const &offset,
+                   CoordType top,
+                   CoordType bottom)
 {
    wxLayoutLine *line = m_FirstLine;
 
-   Layout(dc, bottom);
-   m_DefaultSetting->Draw(dc, wxPoint(0,0));
+   Layout(dc);
+   ApplyStyle(&m_DefaultSetting, dc);
+   wxBrush brush(m_CurrentSetting.m_bg, wxSOLID);
+   dc.SetBrush(brush);
+   dc.SetBackgroundMode(wxTRANSPARENT);
+
    while(line)
    {
       // only draw if between top and bottom:
-      if((top == -1 || line->GetPosition().y >= top))
-         line->Draw(dc, offset);
+      if((top == -1 || line->GetPosition().y + line->GetHeight() >= top))
+         line->Draw(dc, this, offset);
+      else
+         line->Layout(dc, this);
       // little condition to speed up redrawing:
       if(bottom != -1 && line->GetPosition().y > bottom) break;
       line = line->GetNextLine();
    }
-   // 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));
+   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::FindObject(wxPoint const pos)
+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) return NULL; // not found
+   if(line == NULL)
+   {
+      if(found) *found = false;
+      return NULL; // not found
+   }
+   if(cursorPos) cursorPos->y = line->GetLineNumber();
    // Now, find the object in the line:
-   return line->FindObject(pos.x);
-   
+   wxLOiterator i = line->FindObjectScreen(dc, pos.x,
+                                           cursorPos ? & cursorPos->x : NULL ,
+                                           found);
+   return (i == NULLIT) ? NULL : *i;
+
 }
 
 wxPoint
@@ -1111,27 +1957,27 @@ wxLayoutList::GetSize(void) const
    if(! line)
       return wxPoint(0,0);
 
-   wxPoint max(0,0);
-   
+   wxPoint maxPoint(0,0);
+
    // find last line:
    while(line)
    {
-      if(line->GetWidth() > max.x) max.x = line->GetWidth();
+      if(line->GetWidth() > maxPoint.x)
+          maxPoint.x = line->GetWidth();
       last = line;
       line = line->GetNextLine();
    }
 
-   max.y = last->GetPosition().y + last->GetHeight();
-   return max;
+   maxPoint.y = last->GetPosition().y + last->GetHeight();
+   return maxPoint;
 }
 
+
 void
 wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
 {
-   wxPoint coords;
-   coords = m_CursorScreenPos;
-   coords.x += translate.x;
-   coords.y += translate.y;
+   wxPoint coords(m_CursorScreenPos);
+   coords += translate;
 
 #ifdef WXLAYOUT_DEBUG
    WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
@@ -1140,20 +1986,367 @@ wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
                (long)m_CursorSize.x, (long)m_CursorSize.y,
                (long)m_CursorLine->GetLineNumber(),
                (long)m_CursorLine->GetLength()));
+
+   wxLogStatus("Cursor is at (%d, %d)", m_CursorPos.x, m_CursorPos.y);
 #endif
-   
-   if(active)
-      dc.SetBrush(*wxBLACK_BRUSH);
-   dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+
+#ifdef WXLAYOUT_USE_CARET
+   m_caret->Move(coords);
+#else // !WXLAYOUT_USE_CARET
+   dc.SetBrush(*wxBLACK_BRUSH);
    dc.SetLogicalFunction(wxXOR);
-   dc.DrawRectangle(coords.x, coords.y, m_CursorSize.x, m_CursorSize.y);
+   dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+   if(active)
+   {
+      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);
+   }
+   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);
+   //dc.SetBrush(wxNullBrush);
+#endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
 }
 
+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::StartSelection(wxPoint cpos)
+{
+   if(cpos.x == -1)
+      cpos = m_CursorPos;
+   WXLO_DEBUG(("Starting selection at %ld/%ld", cpos.x, cpos.y));
+   m_Selection.m_CursorA = cpos;
+   m_Selection.m_CursorB = cpos;
+   m_Selection.m_selecting = true;
+   m_Selection.m_valid = false;
+}
+
+void
+wxLayoutList::ContinueSelection(wxPoint cpos)
+{
+   if(cpos.x == -1)
+      cpos = m_CursorPos;
+   wxASSERT(m_Selection.m_selecting == true);
+   wxASSERT(m_Selection.m_valid == false);
+   WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos.x, cpos.y));
+   if(m_Selection.m_CursorB <= cpos)
+      m_Selection.m_CursorB = cpos;
+   else
+      m_Selection.m_CursorA = cpos;
+   // 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::EndSelection(wxPoint cpos)
+{
+   if(cpos.x == -1)
+      cpos = m_CursorPos;
+   ContinueSelection(cpos);
+   WXLO_DEBUG(("Ending selection at %ld/%ld", cpos.x, cpos.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(line); wxASSERT(to); wxASSERT(from);
+
+   if(! m_Selection.m_valid && ! m_Selection.m_selecting)
+      return 0;
+
+   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;
+
+   m_Selection.m_valid = false;
+
+   // 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_CurrentSetting.m_bg);
+   dc.SetTextBackground(m_CurrentSetting.m_fg);
+   dc.SetBackgroundMode(wxSOLID);
+#endif
+}
+
+/// Ends highlighting the selection
+void
+wxLayoutList::EndHighlighting(wxDC &dc)
+{
+#if SHOW_SELECTIONS
+   dc.SetTextForeground(m_CurrentSetting.m_fg);
+   dc.SetTextBackground(m_CurrentSetting.m_bg);
+   dc.SetBackgroundMode(wxTRANSPARENT);
+#endif
+}
+
+
+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)
+   {
+      wxLayoutLine *tmp = firstLine;
+      firstLine = lastLine;
+      lastLine = tmp;
+   }
+
+   wxLayoutList *llist = new wxLayoutList();
+
+   if(firstLine == lastLine)
+   {
+      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())
+      {
+         line->Copy(llist);
+         llist->LineBreak();
+      }
+      // Extract objects from last line
+      lastLine->Copy(llist, 0, to.x);
+   }
+   return llist;
+}
+
+wxLayoutList *
+wxLayoutList::GetSelection(wxLayoutDataObject *wxlo, bool invalidate)
+{
+   if(! m_Selection.m_valid)
+   {
+      if(m_Selection.m_selecting)
+         EndSelection();
+      else
+         return NULL;
+   }
+
+   if(invalidate) m_Selection.m_valid = false;
+
+   wxLayoutList *llist = Copy( m_Selection.m_CursorA,
+                               m_Selection.m_CursorB );
+
+   if(llist && wxlo) // export as data object, too
+   {
+      wxString string;
+
+      wxLayoutExportObject *export;
+      wxLayoutExportStatus status(llist);
+      while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_OBJECTS)) != NULL)
+      {
+         if(export->type == WXLO_EXPORT_EMPTYLINE)
+            ; //FIXME missing support for linebreaks in string format
+         else
+            export->content.object->Write(string);
+         delete export;
+      }
+
+      wxlo->SetData(string.c_str(), string.Length()+1);
+   }
+   return llist;
+}
+
+
+
+#define COPY_SI(what) if(si->what != -1) { m_CurrentSetting.what = si->what; fontChanged = TRUE; }
+
+void
+wxLayoutList::ApplyStyle(wxLayoutStyleInfo *si, wxDC &dc)
+{
+   bool fontChanged = FALSE;
+   COPY_SI(family);
+   COPY_SI(size);
+   COPY_SI(style);
+   COPY_SI(weight);
+   COPY_SI(underline);
+   if(fontChanged)
+      dc.SetFont( m_FontCache.GetFont(m_CurrentSetting) );
+
+   if(si->m_fg_valid)
+   {
+      m_CurrentSetting.m_fg = si->m_fg;
+      dc.SetTextForeground(m_CurrentSetting.m_fg);
+   }
+   if(si->m_bg_valid)
+   {
+      m_CurrentSetting.m_bg = si->m_bg;
+      dc.SetTextBackground(m_CurrentSetting.m_bg);
+   }
+}
+
+
+#ifdef WXLAYOUT_DEBUG
+
+void
+wxLayoutList::Debug(void)
+{
+   wxLayoutLine *line;
+
+
+   for(line = m_FirstLine;
+       line;
+       line = line->GetNextLine())
+      line->Debug();
+}
+
+#endif
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
    wxLayoutPrintout
 
@@ -1165,6 +2358,13 @@ wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist,
 {
    m_llist = llist;
    m_title = title;
+   // remove any highlighting which could interfere with printing:
+   m_llist->StartSelection();
+   m_llist->EndSelection();
+}
+
+wxLayoutPrintout::~wxLayoutPrintout()
+{
 }
 
 float
@@ -1172,7 +2372,7 @@ 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.
@@ -1193,7 +2393,7 @@ wxLayoutPrintout::ScaleDC(wxDC *dc)
       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
@@ -1222,7 +2422,7 @@ bool wxLayoutPrintout::OnPrintPage(int page)
    wxDC *dc = GetDC();
 
    ScaleDC(dc);
-   
+
    if (dc)
    {
       int top, bottom;
@@ -1252,21 +2452,17 @@ void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom,
    float scale = ScaleDC(&psdc);
 
    psdc.GetSize(&m_PageWidth, &m_PageHeight);
-   // This sets a left/top origin of 10% and 20%:
-   m_Offset = wxPoint(m_PageWidth/10, m_PageHeight/20);
+   // This sets a left/top origin of 15% and 20%:
+   m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20);
 
    // This is the length of the printable area.
-   m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.1);
+   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 = (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight) + 0.5);
-
-   // This is a crude hack to get it right for very small
-   // printouts. No idea why this is required, I thought +0.5 would do 
-   // the job. :-(
-   if(m_NumOfPages == 0 && m_llist->GetSize().y > 0)
-      m_NumOfPages = 1;
+
+
+   m_NumOfPages = 1 +
+      (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));
+
    *minPage = 1;
    *maxPage = m_NumOfPages;
 
@@ -1294,12 +2490,12 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
    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));
    dc.DrawRoundedRectangle(topleft.x,
                            topleft.y,bottomright.x-topleft.x,
-                           bottomright.y-topleft.y);  
+                           bottomright.y-topleft.y);
    dc.SetBrush(*wxBLACK_BRUSH);
    wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
                           wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
@@ -1322,3 +2518,18 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
 #endif
 
 
+wxFont &
+wxFontCache::GetFont(int family, int size, int style, int weight,
+                     bool underline)
+{
+   for(wxFCEList::iterator i = m_FontList.begin();
+       i != m_FontList.end(); i++)
+      if( (**i).Matches(family, size, style, weight, underline) )
+         return (**i).GetFont();
+   // not found:
+   wxFontCacheEntry *fce = new wxFontCacheEntry(family, size, style,
+                                                weight, underline);
+   m_FontList.push_back(fce);
+   return fce->GetFont();
+}
+