]> git.saurik.com Git - wxWidgets.git/blobdiff - user/wxLayout/wxllist.cpp
Added wxWindow_FromHWND(hWnd) for wxMSW to construct a wxWindow from a
[wxWidgets.git] / user / wxLayout / wxllist.cpp
index 81e2d690d44d02833f7231b7660aedf76d8f744e..69083fdeb5b9af5b65e30d64e60f2811283c9a37 100644 (file)
@@ -1,9 +1,9 @@
 /*-*- c++ -*-********************************************************
- * wxFTCanvas: a canvas for editing formatted text                  *
+ * wxllist: wxLayoutList, a layout engine for text and graphics     *
  *                                                                  *
  * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
  *                                                                  *
- * $Id$       *
+ * $Id$
  *******************************************************************/
 
 /*
   - 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
-  - during redraw each line gets iterated over twice, first just
-    calculating baselines and positions, second to actually draw it
-  - the cursor position is the position before an object, i.e. if the
+  - 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
+    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).
+
+
+    The redrawing of the cursor no longer erases it at the last
+    position, because the list gets redrawn anyway.
+*/
+
+/*
+  TODO:
+
+  - 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?
 */
 
 #ifdef __GNUG__
 #pragma implementation "wxllist.h"
 #endif
 
-// these two lines are for use in M:
 //#include "Mpch.h"
-//#include "gui/wxllist.h"
-
-#include   "wxllist.h"
+#ifdef M_PREFIX
+#   include "gui/wxllist.h"
+#else
+#   include "wxllist.h"
+#endif
 
 #ifndef USE_PCH
-#  include   "iostream.h"
-
-#  include   <wx/dc.h>
-#  include   <wx/postscrp.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>
 #endif
 
 #define   BASELINESTRETCH   12
 
+// This should never really get created
+#define   WXLLIST_TEMPFILE   "__wxllist.tmp"
+
 #ifdef WXLAYOUT_DEBUG
 static const char *g_aTypeStrings[] = 
 { 
@@ -46,17 +68,19 @@ static const char *g_aTypeStrings[] =
 };
    
 #  define   wxLayoutDebug        wxLogDebug
-#  define   WXL_VAR(x)           cerr << #x " = " << x ;
-#  define   WXL_DBG_POINT(p)     wxLogDebug(#p ": (%d, %d)", p.x, p.y)
-#  define   WXL_TRACE(f)         wxLogDebug(#f ": ")
+#  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)
 {
    CoordType bl = 0;
-   wxLogDebug("%s: size = %dx%d, bl = %d",
-              TypeString(GetType()), GetSize(&bl).x, GetSize(&bl).y, bl); 
+   wxLayoutDebug("%s: size = %dx%d, pos=%d,%d, bl = %d",
+                 TypeString(GetType()), GetSize(&bl).x,
+                 GetSize(&bl).y,
+                 GetPosition().x, GetPosition().y, bl); 
 }
 
 #else 
@@ -76,6 +100,7 @@ wxLayoutObjectText::wxLayoutObjectText(const String &txt)
    m_Text = txt;
    m_Width = 0;
    m_Height = 0;
+   m_Position = wxPoint(-1,-1);
 }
 
 
@@ -87,22 +112,26 @@ wxLayoutObjectText::GetSize(CoordType *baseLine) const
 }
 
 void
-wxLayoutObjectText::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
-                         bool draw)
+wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &translate)
+{
+   dc.DrawText(Str(m_Text), m_Position.x + translate.x, m_Position.y+translate.y);
+   m_IsDirty = false;
+}
+
+
+void
+wxLayoutObjectText::Layout(wxDC &dc, wxPoint position, CoordType baseLine)
 {
    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);
-   //FIXME: wxGTK does not set descent to a descent value yet.
-   if(descent == 0)
-      descent = (2*m_Height)/10;  // crude fix
    m_BaseLine = m_Height - descent;
-   position.y += baseLine-m_BaseLine;
-   if(draw)
-      dc.DrawText(Str(m_Text),position.x,position.y);
-   // Don't remove this, important help for debugging layout.
-#   ifdef   WXLAYOUT_DEBUG
-//   dc.DrawRectangle(position.x, position.y, m_Width, m_Height);
-#   endif
+   if(m_Position.x != position.x || m_Position.y != position.y)
+      m_IsDirty = true;
 }
 
 #ifdef WXLAYOUT_DEBUG
@@ -110,31 +139,41 @@ void
 wxLayoutObjectText::Debug(void)
 {
    wxLayoutObjectBase::Debug();
-   wxLogDebug(" `%s`", m_Text.c_str());
+   wxLayoutDebug(" `%s`", m_Text.c_str());
 }
 #endif
 
 //-------------------------- wxLayoutObjectIcon
 
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon const &icon)
+{
+   m_Position = wxPoint(-1,-1);
+   m_Icon = new wxIcon(icon);
+}
+
 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
-   : m_Icon(icon)
 {
+   m_Icon = icon;
 }
 
 void
-wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
-                         bool draw)
+wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &translate)
 {
-   position.y += baseLine - m_Icon->GetHeight();
-   if(draw)
-      dc.DrawIcon(m_Icon,position.x,position.y);
+   dc.DrawIcon(*m_Icon,m_Position.x+translate.x, m_Position.y+translate.y);
+}
+
+void
+wxLayoutObjectIcon::Layout(wxDC &dc, wxPoint position, CoordType baseLine)
+{
+   if(m_Position.x != position.x || m_Position.y != position.y)
+      m_IsDirty = true;
+   m_Position = position;
 }
 
 wxPoint
 wxLayoutObjectIcon::GetSize(CoordType *baseLine) const
 {
-   wxASSERT(baseLine);
-   *baseLine = m_Icon->GetHeight();
+   if(baseLine)   *baseLine = m_Icon->GetHeight();
    return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
 }
 
@@ -179,24 +218,32 @@ wxLayoutObjectCmd::GetStyle(void) const
 }
 
 void
-wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint position, CoordType lineHeight,
-                        bool draw)
+wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const &translate)
 {
    wxASSERT(m_font);
-   // this get called even when draw==false, so that recalculation
-   // uses right font sizes
-   dc.SetFont(m_font);
+   dc.SetFont(*m_font);
    if(m_ColourFG)
       dc.SetTextForeground(*m_ColourFG);
    if(m_ColourBG)
       dc.SetTextBackground(*m_ColourBG);
 }
+void
+wxLayoutObjectCmd::Layout(wxDC &dc, wxPoint p, CoordType baseline)
+{
+   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));
+}
 
-//-------------------------- wxwxLayoutList
+//-------------------------- wxLayoutList
 
 wxLayoutList::wxLayoutList()
 {
    m_DefaultSetting = NULL;
+   m_WrapMargin = -1;
+   m_Editable = FALSE;
+   m_boldCursor = FALSE;
+   
    Clear();
 }
 
@@ -211,7 +258,6 @@ void
 wxLayoutList::LineBreak(void)
 {
    Insert(new wxLayoutObjectLineBreak);
-   m_CursorPosition.x = 0; m_CursorPosition.y++;
 }
 
 void
@@ -262,219 +308,94 @@ wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y,
    if(lineHeight) *lineHeight = m_LineHeight;
 }
 
-wxLayoutObjectBase *
-wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const
-                   &findCoords, int pageNo, bool reallyDraw)
+void
+wxLayoutList::ResetSettings(wxDC &dc)
 {
-   wxLayoutObjectList::iterator i;
+   // 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));
+}
+
+void
+wxLayoutList::Layout(wxDC &dc, wxLayoutMargins *margins)
+{
+   iterator i;
 
-   // in case we need to look for an object
-   wxLayoutObjectBase *foundObject = NULL;
-   
    // first object in current line
    wxLayoutObjectList::iterator headOfLine;
-
-   // do we need to recalculate current line?
-   bool recalculate = false;
-
-   // do we calculate or draw? Either true or false.
-   bool draw = false;
-   // drawing parameters:
-   wxPoint position = wxPoint(0,0);
-   wxPoint position_HeadOfLine;
+   // where we draw next
+   wxPoint position, position_HeadOfLine;
+   // size of last object
+   wxPoint size;
    CoordType baseLine = m_FontPtSize;
    CoordType baseLineSkip = (BASELINESTRETCH * baseLine)/10;
-
-   // where to draw the cursor
-   wxPoint
-      cursorPosition = wxPoint(0,0),
-      cursorSize = wxPoint(1,baseLineSkip);
-   
-   // the cursor position inside the object
-   CoordType cursorOffset = 0;
-   // object under cursor
-   wxLayoutObjectList::iterator cursorObject = FindCurrentObject(&cursorOffset);
-   
-   // queried from each object:
-   wxPoint       size = wxPoint(0,0);
-   CoordType     objBaseLine = baseLine;
+   CoordType objBaseLine = baseLine;
    wxLayoutObjectType type;
-
-   // used temporarily
-   wxLayoutObjectText *tobj = NULL;
-
-
-   // this is needed for printing to a printer:
-   // only interesting for printer/PS output
-   int pageWidth, pageHeight;   //GetSize() still needs int at the moment
-   struct
-   {
-      int top, bottom, left, right;
-   } margins;
-
-   int currentPage = 1;
    
-   if(pageNo > 0)
+   // we need to count cursor positions
+   wxPoint cursorPos = wxPoint(0,0);
+   
+   if(margins)
    {
-      dc.GetSize(&pageWidth, &pageHeight);
-      WXL_VAR(pageHeight);
-      margins.top = 0;   //(1*pageHeight)/10;    // 10%
-      margins.bottom = pageHeight;// (9*pageHeight)/10; // 90%
-      margins.left = 0;  //(1*pageWidth)/10;
-      margins.right = pageWidth; //(9*pageWidth)/10;
+      position.y = margins->top;
+      position.x = margins->left;
    }
    else
    {
-      margins.top = 0; margins.left = 0;
-      margins.right = -1;
-      margins.bottom = -1;
+      position.y = 0;
+      position.x = 0;
    }
-   position.y = margins.top;
-   position.x = margins.left;
    
-   // if the cursorobject is a cmd, we need to find the first
-   // printable object:
-   while(cursorObject != end()
-         && (*cursorObject)->GetType() == WXLO_TYPE_CMD)
-      cursorObject++;
-
-   headOfLine = begin();
+   ResetSettings(dc);
+   
+   i = begin();
+   headOfLine = i;
    position_HeadOfLine = position;
 
-   // setting up the default:
-   dc.SetTextForeground( *wxBLACK );
-   dc.SetTextBackground( *wxWHITE );
-   dc.SetBackgroundMode( wxSOLID ); // to enable setting of text background
-   dc.SetFont( *wxNORMAL_FONT );
-
-
-   //FIXME: who frees the brush, how long does it need to exist?
-   if(m_DefaultSetting)
-      m_DefaultSetting->Draw(dc,wxPoint(0,0),0,true);
-
-   // we calculate everything for drawing a line, then rewind to the
-   // begin of line and actually draw it
-   i = begin();
-   for(;;)
+   do
    {
-      recalculate = false;
-
       if(i == end())
-         break;
+         return;
+   
       type = (*i)->GetType();
-
-      // to initialise sizes of objects, we need to call Draw
-      if(draw && (pageNo == -1 || pageNo == currentPage))
-      {
-         (*i)->Draw(dc, position, baseLine, draw);
-#ifdef   WXLAYOUT_DEBUG
-         if(i == begin())
-            wxLogDebug("first position = (%d,%d)",(int) position.x, (int)position.y);
-#endif
-      }
-      // update coordinates for next object:
+      (*i)->Layout(dc, position, baseLine);
       size = (*i)->GetSize(&objBaseLine);
-      if(findObject && draw)  // we need to look for an object
-      {
-         if(findCoords.y >= position.y
-            && findCoords.y <= position.y+size.y
-            && findCoords.x >= position.x
-            && findCoords.x <= position.x+size.x)
-         {
-            foundObject = *i;
-            findObject = false; // speeds things up
-         }
-      }
-      // draw the cursor
-      if(m_Editable && draw && i == cursorObject)
-      {
-         WXL_VAR((**cursorObject).GetType());
-         WXL_VAR(m_CursorPosition.x); WXL_VAR(m_CursorPosition.y);
-         if(type == WXLO_TYPE_TEXT) // special treatment
-         {
-            long descent = 0l; long width, height;
-            tobj = (wxLayoutObjectText *)*i;
-            String  str = tobj->GetText();
-            WXL_VAR(m_CursorPosition.x);
-            str = str.substr(0, cursorOffset);
-            dc.GetTextExtent(Str(str), &width,&height, &descent);
-            cursorPosition = wxPoint(position.x+width,
-                                     position.y+(baseLineSkip-height));
-            cursorSize = wxPoint(1, height);
-         }
-         else if(type == WXLO_TYPE_LINEBREAK)
-         {
-            WXL_VAR(cursorOffset);
-            if(cursorOffset)
-               cursorPosition = wxPoint(0, position.y+baseLineSkip);
-            else
-               cursorPosition = wxPoint(0, position.y);
-            cursorSize = wxPoint(1,baseLineSkip);
-               
-         }
-         else
-         {
-            // 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);
-            cursorPosition = wxPoint(position.x+size.x, position.y+(size.y-baseLineSkip));
-            cursorSize = wxPoint(1, baseLineSkip);
-         }
-      }
-
       // calculate next object's position:
       position.x += size.x;
-      if(position.x > m_MaxX)
-         m_MaxX = position.x;
-      
+   
       // do we need to increase the line's height?
       if(size.y > baseLineSkip)
       {
          baseLineSkip = size.y;
-         recalculate = true;
+         i = headOfLine; position = position_HeadOfLine;
+         continue;
       }
       if(objBaseLine > baseLine)
       {
          baseLine = objBaseLine;
-         recalculate = true;
+         i = headOfLine; position = position_HeadOfLine;
+         continue;
       }
 
-      // now check whether we have finished handling this line:
-      if(type == WXLO_TYPE_LINEBREAK || i == tail())
+      // 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)
       {
-         if(recalculate)  // do this line again
-         {
-            position.x = position_HeadOfLine.x;
-            i = headOfLine;
-            continue;
-         }
-
-         if(! draw) // finished calculating sizes
-         {
-            // if the this line needs to go onto a new page, we need
-            // to change pages before drawing it:
-            if(pageNo > 0 && position.y > margins.bottom)
-            {
-               currentPage++;
-               position_HeadOfLine.y = margins.top;
-            }
-            if(reallyDraw && (pageNo == -1 || pageNo == currentPage))
-            {
-               // do this line again, this time drawing it
-               position = position_HeadOfLine;
-               draw = true;
-               i = headOfLine;
-               continue;
-            }
-         }
-         else // we have drawn a line, so continue calculating next one
-            draw = false;
+         cursorPos.x = 0; cursorPos.y ++;
       }
-
-      // is it a linebreak?
-      if(type == WXLO_TYPE_LINEBREAK || i == tail())
+      else
+         cursorPos.x += (**i).CountPositions();
+      
+      // now check whether we have finished handling this line:
+      if(type == WXLO_TYPE_LINEBREAK && i != tail()) 
       {
-         position.x = margins.left;
+         position.x = margins ? margins->left : 0;
          position.y += baseLineSkip;
          baseLine = m_FontPtSize;
          objBaseLine = baseLine; // not all objects set it
@@ -483,70 +404,208 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const
          headOfLine++;
          position_HeadOfLine = position;
       }
+      if(i == m_CursorObject)
+         CalculateCursor(dc);
       i++;
    }
-   // draw the cursor
-   if(m_Editable)
+   while(i != end());
+   m_MaxY = position.y + baseLineSkip;
+}
+
+void
+wxLayoutList::Draw(wxDC &dc,
+                   CoordType fromLine, CoordType toLine,
+                   iterator start,
+                   wxPoint const &translate)
+{
+   //Layout(dc); // FIXME just for now
+
+   ResetSettings(dc);
+
+   wxLayoutObjectList::iterator i;
+   
+   if(start == iterator(NULL))
+      start = begin();
+   else // we need to restore font settings
+   {
+      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++;
+   }
+   for( i = start ;
+        i != end() && (toLine == -1 || (**i).GetPosition().y < toLine) ;
+        i++ )
+      (*i)->Draw(dc,translate);
+}
+
+/** Erase at least to end of line */
+void
+wxLayoutList::EraseAndDraw(wxDC &dc, iterator start, wxPoint const &translate)
+{
+   //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;
+   
+   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,translate);
+   //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
+}
+
+
+void
+wxLayoutList::CalculateCursor(wxDC &dc)
+{
+   if(! m_CursorMoved)
+      return;
+   
+   CoordType width, height, descent;
+   CoordType baseLineSkip = 20; //FIXME
+
+   int cursorWidth = m_boldCursor ? 4 : 2;
+   
+   if( m_CursorObject == iterator(NULL))  // empty list
+   {
+      m_CursorCoords = wxPoint(0,0);
+      m_CursorSize = wxPoint(cursorWidth,baseLineSkip);
+      m_CursorMoved = false; // coords are valid
+      return;
+   }
+   wxLayoutObjectBase &obj = **m_CursorObject;
+
+   m_CursorCoords = obj.GetPosition();
+   if(obj.GetType() == WXLO_TYPE_TEXT)
    {
-      dc.DrawRectangle(cursorPosition.x, cursorPosition.y,
-                       cursorSize.x, cursorSize.y);
+      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(cursorWidth,height);
    }
-   m_MaxY = position.y;
-   return foundObject;
+   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(cursorWidth,baseLineSkip);
+   }
+   else
+   {
+      // 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(cursorWidth, obj.GetSize().y);
+      if(m_CursorSize.y < 1) m_CursorSize.y = baseLineSkip;
+   }
+   m_CursorMoved = false; // coords are valid
 }
 
+void
+wxLayoutList::DrawCursor(wxDC &dc, bool erase, wxPoint const &translate)
+{
+   if(! m_Editable)
+      return;
+   
+   if(erase)
+      ;
+#if 0
+   dc.Blit(m_CursorCoords.x+translate.x,
+              m_CursorCoords.y+translate.y,
+              m_CursorSize.x,m_CursorSize.y,
+              &m_CursorMemDC,
+           0, 0, 0, 0);
+#endif
+   else
+   {
+      // erase it at the old position:
+      if(IsDirty() || CursorMoved())
+      {
+         // We don't need to erase the cursor because the screen gets
+         // redrawn completely.
+//         DrawCursor(dc,true);
+         // this is needed to update the cursor coordinates
+         Layout(dc);
+      }
+#if      0
+// 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+translate.x,
+                         m_CursorCoords.y+translate.y, 0, 0);
+#endif
+      // draw it:
+      dc.SetBrush(*wxBLACK_BRUSH);
+      dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+      dc.DrawRectangle(m_CursorCoords.x+translate.x, m_CursorCoords.y+translate.y,
+                       m_CursorSize.x, m_CursorSize.y);
+   }
+}
+
+
+
+
+
+
+
 #ifdef WXLAYOUT_DEBUG
 void
 wxLayoutList::Debug(void)
 {
-   CoordType               offs;
    wxLayoutObjectList::iterator i;
 
-   wxLogDebug("------------------------debug start-------------------------"); 
+   wxLayoutDebug("------------------------ debug start ------------------------"); 
    for(i = begin(); i != end(); i++)
       (*i)->Debug();
-   wxLogDebug("-----------------------debug end----------------------------");
+   wxLayoutDebug("-------------------------- list end -------------------------");
    
    // show current object:
    ShowCurrentObject();
-   i = FindCurrentObject(&offs);
-   wxLogDebug(" line length: %l", (long int) GetLineLength(i,offs));
-   if(i == end())
-   {
-      wxLogDebug("<<no object found>>");
-      return;  // FIXME we should set cursor position to maximum allowed
-      // value then
-   }
-   if((*i)->GetType() == WXLO_TYPE_TEXT)
-      wxLogDebug(" \"%s\", offs=%d",((wxLayoutObjectText *)(*i))->GetText().c_str(), (int) offs);
-   else
-      wxLogDebug(g_aTypeStrings[(*i)->GetType()]);
-
+   wxLayoutDebug("------------------------- debug end -------------------------");
 }
 
 void
 wxLayoutList::ShowCurrentObject()
 {
-   CoordType offs;
-   wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
-
-   wxLayoutDebug("Cursor is at (%d, %d)",
-                 m_CursorPosition.x, m_CursorPosition.y);
-
-   i = FindCurrentObject(&offs);
-   wxLogDebug(" Line length: %d", GetLineLength(i));
-
-   if(i == end())
+   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
    {
-      wxLogDebug("<<no object found>>");
-      return;  // FIXME we should set cursor position to maximum allowed
-// value then
+      if((*m_CursorObject)->GetType() == WXLO_TYPE_TEXT)
+         wxLayoutDebug(" \"%s\", offs: %d",
+                       ((wxLayoutObjectText *)(*m_CursorObject))->GetText().c_str(),
+                       m_CursorOffset);
+      else
+         wxLayoutDebug(" %s", TypeString((*m_CursorObject)->GetType()));
    }
-   if((*i)->GetType() == WXLO_TYPE_TEXT)
-      wxLogDebug(" \"%s\", offs: %d",
-                 ((wxLayoutObjectText *)(*i))->GetText().c_str(), offs);
-   else
-      wxLogDebug(" %s", TypeString((*i)->GetType()));
+   wxLayoutDebug("Line length: %d", GetLineLength(m_CursorObject));
+
 }
 
 #endif
@@ -571,13 +630,27 @@ wxLayoutObjectList::iterator
 wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
 {
    wxPoint object = wxPoint(0,0);  // runs along the objects
-   CoordType width;
-   wxLayoutObjectList::iterator i;
-
-#ifdef WXLAYOUT_DEBUG
-   wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
-#endif
-   for(i = begin(); i != end() && object.y <= cpos->y; i++)
+   CoordType width = 0;
+   wxLayoutObjectList::iterator i, begin_it;
+   int go_up;
+   
+//#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;
+   else
+      go_up = 0;
+
+   //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; )
    {
       width = (**i).CountPositions();
       if(cpos->y == object.y) // a possible candidate
@@ -587,151 +660,202 @@ wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
             if(cpos->x == object.x)
             {
                if(offset) *offset = 0;
-               return i;
+               return m_FoundIterator = i;
             }
             if(offset) *offset=1;
             cpos->x = object.x;
-            return i;
+            return m_FoundIterator = i;
          }
          if(cpos->x >= object.x && cpos->x <= object.x+width) // overlap
          {
             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 i;
+//#ifdef WXLAYOUT_DEBUG
+//            wxLayoutDebug("   found object at (%d, %d), type: %s",
+//                          object.x,  object.y, TypeString((*i)->GetType()));
+//#endif      
+            return m_FoundIterator = i;
          }
       }
-// no overlap, increment coordinates
+      // no overlap, increment coordinates
       object.x += width;
       if((**i).GetType() == WXLO_TYPE_LINEBREAK)
       {
          object.x = 0;
          object.y++;
       }
-   }
-#ifdef WXLAYOUT_DEBUG
-   wxLayoutDebug("   not found");
-#endif
+      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 i;
+      return m_FoundIterator = i;
    if((**i).GetType()==WXLO_TYPE_LINEBREAK)
    {
       if(offset)
          *offset = 1;
-      return i;
+      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 i; // not found
-}
-
-wxLayoutObjectList::iterator 
-wxLayoutList::FindCurrentObject(CoordType *offset)
-{
-   wxLayoutObjectList::iterator obj = end();
-
-   obj = FindObjectCursor(&m_CursorPosition, offset);
-   if(obj == end())  // not ideal yet
-   {
-      obj = tail();
-      if(obj != end()) // tail really exists
-         *offset = (*obj)->CountPositions(); // at the end of it
-   }
-   return obj;
+   return m_FoundIterator = i; // not found
 }
 
 bool
 wxLayoutList::MoveCursor(int dx, int dy)
 {
-   CoordType offs, lineLength;
-   wxLayoutObjectList::iterator i;
+   CoordType diff;
 
-   bool rc = true; // have we moved?
+   m_CursorMoved = true;  
+   
+   enum { up, down} direction;
 
-   if(dy > 0 && m_CursorPosition.y < m_MaxLine)
-      m_CursorPosition.y += dy;
-   else if(dy < 0 && m_CursorPosition.y > 0)
-      m_CursorPosition.y += dy; // dy is negative
-   if(m_CursorPosition.y < 0)
-   {
-      m_CursorPosition.y = 0;
-      rc = false;
-   }
-   else if (m_CursorPosition.y > m_MaxLine)
+   wxPoint newPos = wxPoint(m_CursorPos.x + dx,
+                            m_CursorPos.y + dy);
+
+   // 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;
+
+   //FIXME: quick and dirty hack: as last object in buffer should be a 
+   // linebreak, we don't allow to go there
+   if(newPos.y >= m_MaxLine)
+      return false;
+
+   if(newPos.y > m_CursorPos.y ||
+      newPos.y == m_CursorPos.y &&
+      newPos.x >= m_CursorPos.x)
+      direction = down;
+   else
+      direction = up;
+
+   if ( !m_CursorObject )
    {
-      m_CursorPosition.y = m_MaxLine;
-      rc = false;
+      // list is empty
+       return FALSE;
    }
-   
-   while(dx > 0)
+
+   // now move cursor forwards until at the new position:
+
+   // first, go to the right line:
+   while(newPos.y != m_CursorPos.y)
    {
-      i = FindCurrentObject(&offs);
-      lineLength = GetLineLength(i,offs);
-      if(m_CursorPosition.x < lineLength)
-      {
-         m_CursorPosition.x ++;
-         dx--;
-         continue;
-      }
-      else
+      if(direction == down)
       {
-         if(m_CursorPosition.y < m_MaxLine)
+         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_CursorPosition.y++;
-            m_CursorPosition.x = 0;
-            dx--;
+            m_CursorPos.y++; m_CursorPos.x = 0;
          }
-         else
+         m_CursorObject ++; m_CursorOffset = 0;
+      }
+      else // up
+      {
+         if(m_CursorObject == begin())
+            break;  // can't go any further
+
+         if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK &&
+            m_CursorOffset == 1)
          {
-            rc = false;
-            break; // cannot move there
+            m_CursorPos.y--;
+            m_CursorPos.x = GetLineLength(m_CursorObject);
          }
+         m_CursorPos.x -= m_CursorOffset;
+         m_CursorObject --; m_CursorOffset = (**m_CursorObject).CountPositions();
       }
    }
-   while(dx < 0)
+   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:
+   if(dx == 0) // we are moving up or down only
+   {
+      int max_x = GetLineLength(m_CursorObject);
+      if(max_x <= newPos.x)  // ... so we don't want to cross linebreaks
+         newPos.x = max_x-1; // but just go to the right column
+   }
+   direction = newPos.x >= m_CursorPos.x ? down : up;
+   while(newPos.x != m_CursorPos.x)
    {
-      if(m_CursorPosition.x > 0)
+      if(direction == down)
       {
-         m_CursorPosition.x --;
-         dx++;
+         diff = newPos.x - m_CursorPos.x;
+         if(diff > (**m_CursorObject).CountPositions()-m_CursorOffset)
+         {
+            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)
+            {
+               newPos.y++; newPos.x -= m_CursorPos.x+1;
+               m_CursorPos = wxPoint(0,m_CursorPos.y+1);
+            }
+            else
+               m_CursorPos.x += diff;
+            m_CursorOffset += diff;
+         }
       }
-      else
+      else // up
       {
-         if(m_CursorPosition.y > 0)
+         if(m_CursorPos.x == 0 && m_CursorOffset == 1 &&
+            (**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK) // can we go further up?
          {
-            m_CursorPosition.y --;
-            m_CursorPosition.x = 0;
-            i = FindCurrentObject(&offs);
-            lineLength = GetLineLength(i,offs);
-            m_CursorPosition.x = lineLength;
-            dx++;
+            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
          {
-            rc = false;
-            break; // cannot move left any more
+            m_CursorPos.x -= diff;
+            m_CursorOffset -= diff;
          }
       }
    }
-// final adjustment:
-   i = FindCurrentObject(&offs);
-   lineLength = GetLineLength(i,offs);
-   if(m_CursorPosition.x > lineLength)
-   {
-      m_CursorPosition.x = lineLength;
-      rc = false;
-   }
-#ifdef   WXLAYOUT_DEBUG
-   ShowCurrentObject();
-#endif
-   return rc;
+
+   return true; // FIXME: when return what?
+}
+void
+wxLayoutList::SetCursor(wxPoint const &p)
+{
+   m_CursorPos = p;
+   m_CursorObject = FindObjectCursor(&m_CursorPos, &m_CursorOffset);
+   m_CursorMoved = true;  
 }
 
 void
@@ -742,33 +866,35 @@ wxLayoutList::Delete(CoordType count)
    if(!m_Editable)
       return;
 
-   WXL_VAR(count);
-
-   CoordType offs;
+   m_bModified = true;
+   
+   CoordType offs = 0;
    wxLayoutObjectList::iterator i;
       
    do
    {
-      i  = FindCurrentObject(&offs);
+      i  = m_CursorObject;
    startover: // ugly, but easiest way to do it
       if(i == end())
          return; // we cannot delete anything more
 
-/* Here we need to treat linebreaks differently.
-   If offs==0 we are before the linebreak, otherwise behind.  */
+   /* Here we need to treat linebreaks differently.
+      If m_CursorOffset==0 we are before the linebreak, otherwise behind.  */
       if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
       {
-         if(offs == 0)
+         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
-            offs=0;
+            m_CursorOffset=0;
             goto startover; 
          }
       }
@@ -776,24 +902,33 @@ wxLayoutList::Delete(CoordType count)
       {
          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 == offs)
+         /* 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++;
-            offs = 0;
+            m_CursorOffset = 0;
             goto startover;
          }
-         else if(len <= count) // delete this object
-         {
-            count -= len;
-            erase(i);
-            continue; 
-         }
          else
          {
-            len = count;
-            tobj->GetText().erase(offs,len);
+            if(m_CursorOffset == 0 && len <= count) // delete this object
+            {
+               count -= len;
+               erase(i);
+               m_CursorObject = i;
+               m_CursorOffset = 0;
+               continue; 
+            }
+
+            int todelete = count;
+            if(todelete > len-m_CursorOffset)
+               todelete = len-m_CursorOffset;
+            
+            len = len - todelete;
+            tobj->GetText().erase(m_CursorOffset,todelete);
+            count -= todelete;
+            // cursor unchanged
             return; // we are done
          }
       }
@@ -805,13 +940,16 @@ wxLayoutList::Delete(CoordType count)
          if(offs == 0)
          {
             count = count > len ? count -= len : 0;
-            erase(i); // after this, i is the iterator for the following object
+            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
-            offs=0;
+            m_CursorOffset=0;
             goto startover; 
          }
       }
@@ -819,48 +957,66 @@ wxLayoutList::Delete(CoordType count)
    while(count && i != end());      
 }
 
+
 void
 wxLayoutList::Insert(wxLayoutObjectBase *obj)
 {
-   wxASSERT(obj);
-   CoordType offs;
-   wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
+   wxCHECK_RET( obj, "no object to insert" );
 
-   WXL_TRACE(Insert(obj));
+   m_bModified = true;
 
+   wxLayoutObjectList::iterator i = m_CursorObject;
+
+   if(i != iterator(NULL) && (*obj).GetType() == WXLO_TYPE_LINEBREAK)
+   {
+      m_CursorPos.x = 0; m_CursorPos.y ++;
+   }
+   
    if(i == end())
+   {
       push_back(obj);
-   else if(offs == 0)
+      m_CursorObject = tail();
+   }
+   else if(m_CursorOffset == 0)
+   {
       insert(i,obj);
-// do we have to split a text object?
-   else if((*i)->GetType() == WXLO_TYPE_TEXT && offs != (*i)->CountPositions())
+      m_CursorObject = i;
+   }
+   // do we have to split a text object?
+   else if((*i)->GetType() == WXLO_TYPE_TEXT && m_CursorOffset != (*i)->CountPositions())
    {
       wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
-#ifdef WXLAYOUT_DEBUG
-      wxLayoutDebug("text: %s", tobj->GetText().c_str());
-      WXL_VAR(offs);
-#endif
-      String left = tobj->GetText().substr(0,offs); // get part before cursor
-      WXL_VAR(left.c_str());
-      tobj->GetText() = tobj->GetText().substr(offs,(*i)->CountPositions()-offs); // keeps the right half
-      WXL_VAR(tobj->GetText().c_str());
+      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
    }
    else
    {
-// all other cases, append after object:
+      // all other cases, append after object:
       wxLayoutObjectList::iterator j = i; // we want to apend after this object
       j++;
       if(j != end())
+      {
          insert(j, obj);
+         m_CursorObject = j;
+      }
       else
+      {
          push_back(obj);
+         m_CursorObject = tail();
+      }
    }
+
+   if(obj->GetType() != WXLO_TYPE_LINEBREAK) // handled separately above
+      m_CursorPos.x += obj->CountPositions();
+   // applies also for linebreak:
+   m_CursorOffset = obj->CountPositions();
    
-   m_CursorPosition.x += obj->CountPositions();
    if(obj->GetType() == WXLO_TYPE_LINEBREAK)
       m_MaxLine++;
+   m_CursorMoved = true;
 }
 
 void
@@ -869,13 +1025,14 @@ wxLayoutList::Insert(String const &text)
    wxLayoutObjectText *tobj = NULL;
    wxLayoutObjectList::iterator j;
 
-   WXL_TRACE(Insert(text));
+//   WXL_TRACE(Insert(text));
 
    if(! m_Editable)
       return;
 
-   CoordType offs;
-   wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
+   m_bModified = true;
+
+   wxLayoutObjectList::iterator i = m_CursorObject;
 
    if(i == end())
    {
@@ -887,60 +1044,68 @@ wxLayoutList::Insert(String const &text)
    {
    case WXLO_TYPE_TEXT:
 // insert into an existing text object:
-      WXL_TRACE(inserting into existing object);
       tobj = (wxLayoutObjectText *)*i ;
       wxASSERT(tobj);
-      tobj->GetText().insert(offs,text);
+      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(offs == 0) // try to append to previous object
+      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;
+         }
       }
-      else // cursor after linebreak
+      else // offset == 1 : cursor after linebreak
       {
          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;
          }
          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();
+            }
          }
       }
       break;
-#if 0
-   default:
-      j = i; j--;
-      WXL_TRACE(checking previous object);
-      if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
-      {
-         tobj = (wxLayoutObjectText *)*j;
-         tobj->GetText()+=text;
-      }
-      else  // insert a new text object
-      {
-         WXL_TRACE(creating new object);
-         Insert(new wxLayoutObjectText(text));  //FIXME not too optimal, slow
-         return;  // position gets incremented in Insert(obj)
-      }
-#endif
    }
-   m_CursorPosition.x += strlen(text.c_str());
+   m_CursorMoved = true;
 }
 
 CoordType
@@ -952,8 +1117,11 @@ wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs)
    CoordType len = 0;
 
    if(offs == 0 && (**i).GetType() == WXLO_TYPE_LINEBREAK)
-// we are before a linebrak
-      return 0;
+      if(i != begin())
+         i--;
+      else
+         return 0; // at begin of buffer in front of a linebreak
+         
 // search backwards for beginning of line:
    while(i != begin() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
       i--;
@@ -965,6 +1133,7 @@ wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs)
       len += (*i)->CountPositions();
       i++;
    }
+   len++; // one extra for the linebreak
    return len;
 }
 
@@ -972,12 +1141,18 @@ 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(4,4);
+   m_CursorMemDC.SelectObject(bm);
+
    while(i != end()) // == while valid
       erase(i);
 
-// set defaults
+   // set defaults
    m_FontPtSize = size;
    m_FontUnderline = false;
    m_FontFamily = family;
@@ -990,14 +1165,22 @@ wxLayoutList::Clear(int family, int size, int style, int weight,
    if(! m_ColourBG) m_ColourBG = wxWHITE;
    
    m_Position = wxPoint(0,0);
-   m_CursorPosition = wxPoint(0,0);
+   m_CursorPos = wxPoint(0,0);
+   m_CursorObject = iterator(NULL);
+   m_CursorOffset = 0;
+   m_CursorSize = wxPoint(2,(BASELINESTRETCH*m_FontPtSize)/10);
+   
    m_MaxLine = 0;
    m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10;
    m_MaxX = 0; m_MaxY = 0;
 
+
+   m_FoundCursor = wxPoint(0,0);
+   m_FoundIterator = begin();
    
    if(m_DefaultSetting)
       delete m_DefaultSetting;
+
    m_DefaultSetting = new
       wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
                         m_FontWeight,m_FontUnderline,
@@ -1005,67 +1188,213 @@ wxLayoutList::Clear(int family, int size, int style, int weight,
 }
 
 
+wxLayoutObjectBase *
+wxLayoutList::Find(wxPoint coords) const
+{
+   wxLayoutObjectList::iterator i = begin();
+
+   wxPoint topleft, bottomright;
+   
+   while(i != end()) // == while valid
+   {
+      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++;
+   }
+   return NULL;
+}
+
+
+void
+wxLayoutList::SetWrapMargin(long n)
+{
+   m_WrapMargin = n;
+}
+
+void
+wxLayoutList::WrapLine(void)
+{
+   wxASSERT(m_CursorObject);
+
+   iterator i = m_CursorObject;
+
+   if(!DoWordWrap() || !i ) // empty list
+      return;
+   int cursorpos = m_CursorPos.x, cpos, offset;
+   
+   if(cursorpos < m_WrapMargin)
+      return;
+
+   // else: break line
+
+   // find the right object to break:
+   // is it the current one?
+
+   i = m_CursorObject;
+   cpos = cursorpos-m_CursorOffset;
+   while(i != begin() && cpos >= m_WrapMargin)
+   {
+      i--;
+      cpos -= (**i).CountPositions();
+   }
+   // now i is the object to break and cpos its position
+
+   offset = m_WrapMargin - cpos;
+   wxASSERT(offset <= (**i).CountPositions());
 
+   // split it
+   if((**i).GetType() == WXLO_TYPE_TEXT)
+   {
+      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); // get part before cursor
+            t.GetText() = t.GetText().substr(offset+1,t.CountPositions()-offset-1); // keeps the right halve
+            insert(i,new wxLayoutObjectLineBreak);
+            insert(i,new wxLayoutObjectText(left)); // inserts before
+            break;
+         }
+      if(offset == 0)
+      {
+         // 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
+      }
+   }
+   else
+      insert(i,new wxLayoutObjectLineBreak);
+   m_MaxLine++;
+   m_CursorPos.y++;
+   m_CursorPos.x -= offset;
+   m_CursorOffset -= offset;
+}
 /******************** printing stuff ********************/
 
+wxLayoutPrintout::wxLayoutPrintout(wxLayoutList &llist,
+                                   wxString const & title)
+:wxPrintout(title)
+{
+   m_llist = &llist;
+   m_title = title;
+}
+
 bool wxLayoutPrintout::OnPrintPage(int page)
 {
-  wxDC *dc = GetDC();
-  if (dc)
-  {
-     m_llist->Draw(*dc,false,wxPoint(0,0),page);
-     return TRUE;
-  }
-  else
-    return FALSE;
+   wxDC *dc = GetDC();
+   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);
+      return true;
+   }
+   else
+      return false;
 }
 
 bool wxLayoutPrintout::OnBeginDocument(int startPage, int endPage)
 {
-  if (!wxPrintout::OnBeginDocument(startPage, endPage))
-    return FALSE;
+   if (!wxPrintout::OnBeginDocument(startPage, endPage))
+    return false;
 
-  return TRUE;
+  return true;
 }
 
-void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
+void
+wxLayoutPrintout::OnPreparePrinting(void)
 {
+   
+}
 
-   // This code doesn't work, because we don't have a DC yet.
-   // How on earth are we supposed to calculate the number of pages then?
 
-   *minPage = 1;
-   *maxPage = 32000;
+void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
+{
+   // ugly hack to get number of pages
+#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
 
-   *selPageFrom = 1;
-   *selPageTo = 1;
+   // 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;
 
-#if 0
-   CoordType height;
-   int pageWidth, pageHeight;
+   // This is the length of the printable area.
+   m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15); 
 
-   wxDC *dc = GetDC();
-   wxASSERT(dc);
+   //FIXME this is wrong but not used at the moment
+   m_PageWidth = m_Margins.right - m_Margins.left;
 
-   dc->GetSize(&pageWidth, &pageHeight);
-// don't draw but just recalculate sizes:
-   m_llist->Draw(*dc,false,wxPoint(0,0),-1,false);
-   m_llist->GetSize(NULL,&height,NULL);
-   
+   m_NumOfPages = (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight) + 0.5);
    *minPage = 1;
-   *maxPage = height/pageHeight+1;
+   *maxPage = m_NumOfPages;
 
    *selPageFrom = 1;
-   *selPageTo = *maxPage;
-   m_maxPage = *maxPage;
-#endif
-   
+   *selPageTo = m_NumOfPages;
+   wxRemoveFile(WXLLIST_TEMPFILE);
 }
 
 bool wxLayoutPrintout::HasPage(int pageNum)
 {
-   return true;
-//   return m_maxPage >= pageNum;
+   return pageNum <= m_NumOfPages;
+}
+
+
+void
+wxLayoutPrintout::DrawHeader(wxDC &dc,
+                             wxPoint topleft, wxPoint bottomright,
+                             int pageno)
+{
+   // make backups of all essential parameters
+   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);  
+   dc.SetBrush(*wxBLACK_BRUSH);
+   wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
+                          wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
+   dc.SetFont(myfont);
+
+   wxString page;
+   page = "9999/9999  ";  // many pages...
+   long w,h;
+   dc.GetTextExtent(page,&w,&h);
+   page.Printf("%d/%d", pageno, (int) m_NumOfPages);
+   dc.DrawText(page,bottomright.x-w,topleft.y+h/2);
+   dc.GetTextExtent("XXXX", &w,&h);
+   dc.DrawText(m_title, topleft.x+w,topleft.y+h/2);
+
+   // restore settings
+   dc.SetPen(pen);
+   dc.SetBrush(brush);
+   dc.SetFont(font);
 }