]> 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 b26995e0b97e65cf92743c776cc9713f4b7e87d6..69083fdeb5b9af5b65e30d64e60f2811283c9a37 100644 (file)
@@ -1,5 +1,5 @@
 /*-*- 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)                 *
  *                                                                  *
   - 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 cursor position and size must be decided at layout/draw time
-    or the fonts will be wrong
+
+    The redrawing of the cursor no longer erases it at the last
+    position, because the list gets redrawn anyway.
 */
 
 /*
-  Known wxGTK bugs:
-  - MaxX()/MaxY() don't get set
+  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?
 */
 
  
@@ -32,7 +42,7 @@
 #endif
 
 //#include "Mpch.h"
-#ifdef M_BASEDIR
+#ifdef M_PREFIX
 #   include "gui/wxllist.h"
 #else
 #   include "wxllist.h"
@@ -41,7 +51,7 @@
 #ifndef USE_PCH
 #   include   "iostream.h"
 #   include   <wx/dc.h>
-#   include   <wx/postscrp.h>
+#   include   <wx/dcps.h>
 #   include   <wx/print.h>
 #   include   <wx/log.h>
 #endif
@@ -59,16 +69,18 @@ static const char *g_aTypeStrings[] =
    
 #  define   wxLayoutDebug        wxLogDebug
 #  define   WXL_VAR(x)           cerr << #x " = " << x << endl;
-#  define   WXL_DBG_POINT(p)     wxLogDebug(#p ": (%d, %d)", p.x, p.y)
-#  define   WXL_TRACE(f)         wxLogDebug(#f ": ")
+#  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 
@@ -127,7 +139,7 @@ void
 wxLayoutObjectText::Debug(void)
 {
    wxLayoutObjectBase::Debug();
-   wxLogDebug(" `%s`", m_Text.c_str());
+   wxLayoutDebug(" `%s`", m_Text.c_str());
 }
 #endif
 
@@ -147,7 +159,7 @@ wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
 void
 wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &translate)
 {
-   dc.DrawIcon(m_Icon,m_Position.x+translate.x, m_Position.y+translate.y);
+   dc.DrawIcon(*m_Icon,m_Position.x+translate.x, m_Position.y+translate.y);
 }
 
 void
@@ -209,7 +221,7 @@ void
 wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const &translate)
 {
    wxASSERT(m_font);
-   dc.SetFont(m_font);
+   dc.SetFont(*m_font);
    if(m_ColourFG)
       dc.SetTextForeground(*m_ColourFG);
    if(m_ColourBG)
@@ -228,6 +240,10 @@ wxLayoutObjectCmd::Layout(wxDC &dc, wxPoint p, CoordType baseline)
 wxLayoutList::wxLayoutList()
 {
    m_DefaultSetting = NULL;
+   m_WrapMargin = -1;
+   m_Editable = FALSE;
+   m_boldCursor = FALSE;
+   
    Clear();
 }
 
@@ -242,7 +258,6 @@ void
 wxLayoutList::LineBreak(void)
 {
    Insert(new wxLayoutObjectLineBreak);
-   m_CursorPosition.x = 0; m_CursorPosition.y++;
 }
 
 void
@@ -324,8 +339,6 @@ wxLayoutList::Layout(wxDC &dc, wxLayoutMargins *margins)
    // we need to count cursor positions
    wxPoint cursorPos = wxPoint(0,0);
    
-   wxLayoutObjectBase *cursorObject = NULL; // let's find it again
-   
    if(margins)
    {
       position.y = margins->top;
@@ -391,15 +404,8 @@ wxLayoutList::Layout(wxDC &dc, wxLayoutMargins *margins)
          headOfLine++;
          position_HeadOfLine = position;
       }
-      if(cursorObject == NULL && cursorPos.y == m_CursorPosition.y) // look for cursor
-      {
-         if(cursorPos.x >= m_CursorPosition.x &&
-            m_CursorPosition.x-cursorPos.x+(**i).CountPositions()) // cursor is in current object
-         {
-            cursorObject = *i;
-            CalculateCursor(dc);
-         }
-      }
+      if(i == m_CursorObject)
+         CalculateCursor(dc);
       i++;
    }
    while(i != end());
@@ -412,7 +418,7 @@ wxLayoutList::Draw(wxDC &dc,
                    iterator start,
                    wxPoint const &translate)
 {
-   Layout(dc); // FIXME just for now
+   //Layout(dc); // FIXME just for now
 
    ResetSettings(dc);
 
@@ -441,7 +447,7 @@ wxLayoutList::Draw(wxDC &dc,
 
 /** Erase at least to end of line */
 void
-wxLayoutList::EraseAndDraw(wxDC &dc, iterator start)
+wxLayoutList::EraseAndDraw(wxDC &dc, iterator start, wxPoint const &translate)
 {
    //look for begin of line
    while(start != end() && start != begin() && (**start).GetType() !=
@@ -454,13 +460,13 @@ wxLayoutList::EraseAndDraw(wxDC &dc, iterator start)
    
    wxPoint p = (**start).GetPosition();
 
-   WXL_VAR(p.x);WXL_VAR(p.y);
    //FIXME: wxGTK: MaxX()/MaxY() broken
    //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY());
-   dc.SetBrush(*wxWHITE_BRUSH);
-   dc.SetPen(wxPen(*wxWHITE,0,wxTRANSPARENT));
+
+   dc.SetBrush(wxBrush(*m_ColourBG, wxSOLID));
+   dc.SetPen(wxPen(*m_ColourBG,0,wxTRANSPARENT));
    dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
-   Draw(dc,-1,-1,start,wxPoint(0,0));
+   Draw(dc,-1,-1,start,translate);
    //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
 }
 
@@ -468,32 +474,40 @@ wxLayoutList::EraseAndDraw(wxDC &dc, iterator start)
 void
 wxLayoutList::CalculateCursor(wxDC &dc)
 {
+   if(! m_CursorMoved)
+      return;
+   
    CoordType width, height, descent;
    CoordType baseLineSkip = 20; //FIXME
 
-   CoordType offset;
-   wxLayoutObjectBase &obj = **FindCurrentObject(&offset);
+   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;
 
-   WXL_VAR(offset);
-   DrawCursor(dc,true); // erase it
    m_CursorCoords = obj.GetPosition();
-   WXL_VAR(m_CursorCoords.x); 
    if(obj.GetType() == WXLO_TYPE_TEXT)
    {
       wxLayoutObjectText *tobj = (wxLayoutObjectText *)&obj;
       String & str = tobj->GetText();
-      String sstr = str.substr(0,offset);
-      WXL_VAR(sstr);
+      String sstr = str.substr(0,m_CursorOffset);
       dc.GetTextExtent(sstr,&width,&height,&descent);
-      WXL_VAR(width);
       m_CursorCoords = wxPoint(m_CursorCoords.x+width,
                                m_CursorCoords.y);
-      m_CursorSize = wxPoint(2,height);
+      m_CursorSize = wxPoint(cursorWidth,height);
    }
    else if(obj.GetType() == WXLO_TYPE_LINEBREAK)
    {
-      m_CursorCoords = wxPoint(0, m_CursorCoords.y);
-      m_CursorSize = wxPoint(2,baseLineSkip);
+      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
    {
@@ -501,41 +515,52 @@ wxLayoutList::CalculateCursor(wxDC &dc)
       //cursorPosition = wxPoint(position.x, position.y);
       //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
       m_CursorCoords = wxPoint(m_CursorCoords.x+obj.GetSize().x, m_CursorCoords.y);
-      m_CursorSize = wxPoint(2, obj.GetSize().y);
+      m_CursorSize = wxPoint(cursorWidth, obj.GetSize().y);
       if(m_CursorSize.y < 1) m_CursorSize.y = baseLineSkip;
    }
-   WXL_VAR(m_CursorCoords.x); 
    m_CursorMoved = false; // coords are valid
 }
 
 void
-wxLayoutList::DrawCursor(wxDC &dc, bool erase)
+wxLayoutList::DrawCursor(wxDC &dc, bool erase, wxPoint const &translate)
 {
+   if(! m_Editable)
+      return;
+   
    if(erase)
-   {
-      //dc.SetBrush(*wxWHITE_BRUSH);
-      //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
-      //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y);
-      dc.Blit(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x,
-              m_CursorSize.y, &m_CursorMemDC,
-              0, 0, 0, 0);
-   }
+      ;
+#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())
       {
-         DrawCursor(dc,true);
+         // 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);
       }
-      // Save background:
+#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,
-                         m_CursorCoords.y, 0, 0);
+      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, m_CursorCoords.y,
+      dc.DrawRectangle(m_CursorCoords.x+translate.x, m_CursorCoords.y+translate.y,
                        m_CursorSize.x, m_CursorSize.y);
    }
 }
@@ -550,54 +575,37 @@ wxLayoutList::DrawCursor(wxDC &dc, bool erase)
 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
@@ -700,109 +708,154 @@ wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
    return m_FoundIterator = 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;
-}
-
 bool
 wxLayoutList::MoveCursor(int dx, int dy)
 {
-   CoordType offs, lineLength;
-   wxLayoutObjectList::iterator i;
+   CoordType diff;
 
    m_CursorMoved = true;  
    
-   bool rc = true; // have we moved?
+   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
@@ -813,35 +866,35 @@ wxLayoutList::Delete(CoordType count)
    if(!m_Editable)
       return;
 
-   WXL_VAR(count);
-
    m_bModified = true;
    
-   CoordType offs;
+   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; 
          }
       }
@@ -849,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
          }
       }
@@ -878,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; 
          }
       }
@@ -892,6 +957,7 @@ wxLayoutList::Delete(CoordType count)
    while(count && i != end());      
 }
 
+
 void
 wxLayoutList::Insert(wxLayoutObjectBase *obj)
 {
@@ -899,42 +965,55 @@ wxLayoutList::Insert(wxLayoutObjectBase *obj)
 
    m_bModified = true;
 
-   CoordType offs;
-   wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
-
-//   WXL_TRACE(Insert(obj));
+   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;
@@ -953,8 +1032,7 @@ wxLayoutList::Insert(String const &text)
 
    m_bModified = true;
 
-   CoordType offs;
-   wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
+   wxLayoutObjectList::iterator i = m_CursorObject;
 
    if(i == end())
    {
@@ -966,44 +1044,67 @@ 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;
    }
-   m_CursorPosition.x += strlen(text.c_str());
    m_CursorMoved = true;
 }
 
@@ -1016,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--;
@@ -1029,6 +1133,7 @@ wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs)
       len += (*i)->CountPositions();
       i++;
    }
+   len++; // one extra for the linebreak
    return len;
 }
 
@@ -1041,7 +1146,7 @@ wxLayoutList::Clear(int family, int size, int style, int weight,
    m_dirty = true;  // force redraw/recalc
    wxLayoutObjectList::iterator i = begin();
 
-   wxBitmap bm(1,1);
+   wxBitmap bm(4,4);
    m_CursorMemDC.SelectObject(bm);
 
    while(i != end()) // == while valid
@@ -1060,7 +1165,11 @@ 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;
@@ -1104,8 +1213,83 @@ wxLayoutList::Find(wxPoint coords) const
 }
 
 
+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();
@@ -1144,7 +1328,7 @@ void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom,
 {
    // ugly hack to get number of pages
 #ifdef __WXMSW__
-   wxPrinterDC psdc(WXLLIST_TEMPFILE,false);
+   wxPrinterDC psdc("","",WXLLIST_TEMPFILE,false);
 #else
    wxPostScriptDC psdc(WXLLIST_TEMPFILE,false);
 #endif
@@ -1174,7 +1358,7 @@ void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom,
 
 bool wxLayoutPrintout::HasPage(int pageNum)
 {
-   return pageNum < m_NumOfPages;
+   return pageNum <= m_NumOfPages;
 }
 
 
@@ -1184,10 +1368,9 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
                              int pageno)
 {
    // make backups of all essential parameters
-   wxBrush *brush = dc.GetBrush();
-   wxPen   *pen = dc.GetPen();
-   wxFont  *font = dc.GetFont(),
-           *myfont;;
+   const wxBrush& brush = dc.GetBrush();
+   const wxPen&   pen = dc.GetPen();
+   const wxFont&  font = dc.GetFont();
    
    dc.SetBrush(*wxWHITE_BRUSH);
    dc.SetPen(wxPen(*wxBLACK,0,wxSOLID));
@@ -1195,8 +1378,9 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
                            topleft.y,bottomright.x-topleft.x,
                            bottomright.y-topleft.y);  
    dc.SetBrush(*wxBLACK_BRUSH);
-   myfont = new wxFont((WXLO_DEFAULTFONTSIZE*12)/10,wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
-   dc.SetFont(*myfont);
+   wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
+                          wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
+   dc.SetFont(myfont);
 
    wxString page;
    page = "9999/9999  ";  // many pages...
@@ -1208,11 +1392,9 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
    dc.DrawText(m_title, topleft.x+w,topleft.y+h/2);
 
    // restore settings
-   dc.SetPen(*pen);
-   dc.SetBrush(*brush);
-   dc.SetFont(*font);
-
-   delete myfont;
+   dc.SetPen(pen);
+   dc.SetBrush(brush);
+   dc.SetFont(font);
 }