]> git.saurik.com Git - wxWidgets.git/blobdiff - user/wxLayout/wxllist.cpp
new location for setup.h.in file
[wxWidgets.git] / user / wxLayout / wxllist.cpp
index ecf7e883d9ab88b11cf2d17b9dfc6757b6d845c4..caf366bcb2ef3ec43be2005a3477ebfbcce76a65 100644 (file)
 
 #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
@@ -34,6 +38,7 @@
 #   include   <wx/dcps.h>
 #   include   <wx/print.h>
 #   include   <wx/log.h>
+#   include   <wx/filefn.h>
 #endif
 
 #include <ctype.h>
@@ -102,16 +107,58 @@ void GrowRect(wxRect &r, CoordType x, CoordType y)
       r.height = y - r.y;
 }
 
+#if 0
+// unused
 /// returns true if the point is in the rectangle
 static
 bool Contains(const wxRect &r, const wxPoint &p)
 {
    return r.x <= p.x && r.y <= p.y && (r.x+r.width) >= p.x && (r.y + r.height) >= p.y;
 }
+#endif
 
 
 //@}
 
+
+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)
+{
+   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
@@ -139,6 +186,23 @@ wxLayoutObjectText::Copy(void)
    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
 {
@@ -152,7 +216,7 @@ wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords,
                          wxLayoutList *wxllist,
                          CoordType begin, CoordType end)
 {
-   if(begin == -1)
+   if( end <= 0)
       dc.DrawText(m_Text, coords.x, coords.y-m_Top);
    else
    {
@@ -162,6 +226,10 @@ wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords,
          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);
@@ -204,7 +272,7 @@ wxLayoutObjectText::GetOffsetScreen(wxDC &dc, CoordType xpos) const
 }
 
 void
-wxLayoutObjectText::Layout(wxDC &dc)
+wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList * )
 {
    long descent = 0l;
 
@@ -213,6 +281,7 @@ wxLayoutObjectText::Layout(wxDC &dc)
    m_Top = m_Height - m_Bottom;
 }
 
+
 #ifdef WXLAYOUT_DEBUG
 void
 wxLayoutObjectText::Debug(void)
@@ -233,6 +302,38 @@ 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)
 {
@@ -257,7 +358,7 @@ wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords,
 }
 
 void
-wxLayoutObjectIcon::Layout(wxDC & /* dc */)
+wxLayoutObjectIcon::Layout(wxDC & /* dc */, class wxLayoutList * )
 {
 }
 
@@ -273,54 +374,158 @@ wxLayoutObjectIcon::GetSize(CoordType *top, CoordType *bottom) const
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 
-   wxLayoutObjectIcon
+   wxLayoutObjectCmd
 
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
-                                     weight, bool underline,
-                                     wxColour &fg, wxColour &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;
+   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)
+{
+   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(int family, int size, int style, int
+                                     weight, int underline,
+                                     wxColour *fg, wxColour *bg)
    
 {
-   m_font = new wxFont(size,family,style,weight,underline);
-   m_ColourFG = fg;
-   m_ColourBG = bg;
+   m_StyleInfo = new wxLayoutStyleInfo(family, size,style,weight,underline,fg,bg);
 }
 
 wxLayoutObject *
 wxLayoutObjectCmd::Copy(void)
 {
-   wxLayoutStyleInfo si;
-   GetStyle(&si);
-   
    wxLayoutObjectCmd *obj = new wxLayoutObjectCmd(
-      si.size, si.family, si.style, si.weight, si.underline,
-      m_ColourFG, m_ColourBG);
+      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::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)
+{
+   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_font;
+   delete m_StyleInfo;
 }
 
-void
-wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo *si) const
+wxLayoutStyleInfo *
+wxLayoutObjectCmd::GetStyle(void) const
 {
-   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();
-
-   si->fg_red = m_ColourFG.Red();
-   si->fg_green = m_ColourFG.Green();
-   si->fg_blue = m_ColourFG.Blue();
-   si->bg_red = m_ColourBG.Red();
-   si->bg_green = m_ColourBG.Green();
-   si->bg_blue = m_ColourBG.Blue();
+   return m_StyleInfo;
 }
 
 void
@@ -328,17 +533,15 @@ wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */,
                         wxLayoutList *wxllist,
                         CoordType begin, CoordType /* len */)
 {
-   wxASSERT(m_font);
-   dc.SetFont(*m_font);
-   dc.SetTextForeground(m_ColourFG);
-   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), NULL);
+   Draw(dc, wxPoint(0,0), llist);
 }
 
 
@@ -362,7 +565,6 @@ wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
       m_LineNumber = m_Previous->GetLineNumber()+1;
       m_Next = m_Previous->GetNextLine();
       m_Previous->m_Next = this;
-      m_Height = m_Previous->GetHeight();
    }
    if(m_Next)
    {
@@ -380,9 +582,13 @@ wxLayoutLine::~wxLayoutLine()
 wxPoint
 wxLayoutLine::RecalculatePosition(wxLayoutList *llist)
 {
+   wxASSERT(m_Previous || GetLineNumber() == 0);
+
    if(m_Previous)
-      m_Position = m_Previous->GetPosition() +
-         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);
@@ -392,6 +598,11 @@ wxLayoutLine::RecalculatePosition(wxLayoutList *llist)
 void
 wxLayoutLine::RecalculatePositions(int recurse, wxLayoutList *llist)
 {
+   //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.
+   
    wxASSERT(recurse >= 0);
    wxPoint pos = m_Position;
    CoordType height = m_Height;
@@ -449,12 +660,10 @@ wxLayoutLine::FindObjectScreen(wxDC &dc,
    
    for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      (**i).Layout(dc);
       width = (**i).GetWidth();
       if( x <= xpos && xpos <= x + width )
       {
          *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
-         wxLogDebug("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos);
          if(found) *found = true;
          return i;
       }
@@ -467,11 +676,45 @@ wxLayoutLine::FindObjectScreen(wxDC &dc,
    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
 wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
 {
    wxASSERT(xpos >= 0);
    wxASSERT(obj != NULL);
+   //FIXME: this could be optimised, for now be prudent:
+   m_Dirty = true;
    CoordType offset;
    wxLOiterator i = FindObject(xpos, &offset);
    if(i == NULLIT)
@@ -526,6 +769,8 @@ 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)
@@ -547,6 +792,8 @@ wxLayoutLine::Delete(CoordType xpos, CoordType npos)
 
    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)
    {
@@ -600,6 +847,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);
 
@@ -670,7 +919,11 @@ wxLayoutLine::Draw(wxDC &dc,
    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
@@ -682,20 +935,7 @@ wxLayoutLine::Draw(wxDC &dc,
       {
          // parts of the line need highlighting
          tempto = xpos+(**i).GetLength();
-         if(tempto >= from && xpos <= to)
-         {
-            tempto = to-xpos;
-            if(tempto > (**i).GetLength())
-               tempto = (**i).GetLength();
-            CoordType tmp = from-xpos;
-            if(tmp < 0) tmp = 0;
-            (**i).Draw(dc, pos, llist, from-xpos, to);
-         }
-         else
-         {
-            llist->EndHighlighting(dc); // FIXME! inefficient
-            (**i).Draw(dc, pos, llist);
-         }
+         (**i).Draw(dc, pos, llist, from-xpos, to-xpos);
       }
       else
          (**i).Draw(dc, pos, llist);
@@ -728,15 +968,20 @@ wxLayoutLine::Layout(wxDC &dc,
    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)
@@ -792,18 +1037,10 @@ wxLayoutLine::Layout(wxDC &dc,
 
    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;
    }
 
    
@@ -826,6 +1063,7 @@ wxLayoutLine::Layout(wxDC &dc,
       if(m_BaseLine >= cursorSize->y) // the normal case anyway
          cursorPos->y += m_BaseLine-cursorSize->y;
    }
+   RecalculatePositions(1, llist);
 }
 
 
@@ -833,8 +1071,13 @@ wxLayoutLine *
 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, llist);
       if(m_Previous == NULL)
@@ -842,12 +1085,11 @@ wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
          // 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, llist);
-      return this;
+      return m_Previous;
    }
    
    CoordType offset;
@@ -890,9 +1132,11 @@ wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
 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;
    
    for(i = list.begin(); i != list.end();)
    {
@@ -903,6 +1147,7 @@ wxLayoutLine::MergeNextLine(wxLayoutList *llist)
    wxLayoutLine *oldnext = GetNextLine();
    SetNext(GetNextLine()->GetNextLine());
    delete oldnext;
+   GetNextLine()->MoveLines(-1);
    RecalculatePositions(1, llist);
 }
 
@@ -969,15 +1214,81 @@ wxLayoutLine::Debug(void)
 {
    wxString tmp;
    wxPoint pos = GetPosition();
-   tmp.Printf("Line %ld, Pos (%ld,%ld), Height %ld",
+   WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
               (long int) GetLineNumber(),
               (long int) pos.x, (long int) pos.y,
-              (long int) GetHeight());
-              
-   wxLogDebug(tmp);
+               (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
@@ -986,10 +1297,7 @@ wxLayoutLine::Debug(void)
 
 wxLayoutList::wxLayoutList()
 {
-   m_DefaultSetting = NULL;
    m_FirstLine = NULL;
-   m_ColourFG = *wxBLACK;
-   m_ColourBG = *wxWHITE;
    InvalidateUpdateRect();
    Clear();
 }
@@ -1019,11 +1327,20 @@ void
 wxLayoutList::InternalClear(void)
 {
    Empty();
-   if(m_DefaultSetting)
-   {
-      delete m_DefaultSetting;
-      m_DefaultSetting = NULL;
-   }
+   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
@@ -1031,18 +1348,21 @@ wxLayoutList::SetFont(int family, int size, int style, int weight,
                       int underline, wxColour *fg,
                       wxColour *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;
-   
+   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
@@ -1064,31 +1384,35 @@ wxLayoutList::SetFont(int family, int size, int style, int weight,
 
 void
 wxLayoutList::Clear(int family, int size, int style, int weight,
-                    int /* underline */, wxColour *fg, wxColour *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;
-   if(fg) m_ColourFG = *fg;
-   if(bg) m_ColourBG = *bg;
-
-   m_ColourFG = *wxBLACK;
-   m_ColourBG = *wxWHITE;
-   
-   if(m_DefaultSetting)
-      delete m_DefaultSetting;
-
-   m_DefaultSetting = new
-      wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
-                        m_FontWeight,m_FontUnderline,
-                        m_ColourFG, m_ColourBG);
+   m_DefaultSetting = wxLayoutStyleInfo(family, size, style, weight,
+                                        underline, fg, bg);
+   m_CurrentSetting = m_DefaultSetting;
 }
 
+wxPoint
+wxLayoutList::FindText(const wxString &needle, const wxPoint &cpos) const
+{
+   int xpos;
+   
+   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
@@ -1220,6 +1544,7 @@ wxLayoutList::Insert(wxString const &text)
    SetUpdateRect(m_CursorScreenPos+m_CursorSize);
    m_CursorLine->Insert(m_CursorPos.x, text);
    m_CursorPos.x += text.Length();
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
    return true;
 }
 
@@ -1227,13 +1552,38 @@ bool
 wxLayoutList::Insert(wxLayoutObject *obj)
 {
    wxASSERT(m_CursorLine);
+   if(! m_CursorLine) m_CursorLine = GetFirstLine();
    SetUpdateRect(m_CursorScreenPos);
    SetUpdateRect(m_CursorScreenPos+m_CursorSize);
    m_CursorLine->Insert(m_CursorPos.x, obj);
    m_CursorPos.x += obj->GetLength();
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
    return true;
 }
 
+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)
 {
@@ -1244,8 +1594,11 @@ wxLayoutList::LineBreak(void)
    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();
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
    return true;
 }
 
@@ -1267,6 +1620,7 @@ wxLayoutList::WrapLine(CoordType column)
       LineBreak();
       Delete(1); // delete the space
       m_CursorPos.x = newpos;
+      m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
       return true;
    }
 }
@@ -1308,6 +1662,7 @@ wxLayoutList::Delete(CoordType npos)
       }
    }
    while(left);
+   m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
    return left == 0;
 }
 
@@ -1324,6 +1679,7 @@ wxLayoutList::DeleteLines(int n)
       {  // we cannot delete this line, but we can clear it
          MoveCursorToBeginOfLine();
          DeleteToEndOfLine();
+         m_CursorLine->RecalculatePositions(2, this);
          return n-1;
       }
       //else:
@@ -1345,7 +1701,7 @@ wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
 
    // first, make sure everything is calculated - this might not be
    // needed, optimise it later
-   m_DefaultSetting->Layout(dc);
+   ApplyStyle(&m_DefaultSetting, dc);
    while(line)
    {
       line->RecalculatePosition(this); // so we don't need to do it all the time
@@ -1369,22 +1725,32 @@ wxLayoutList::GetCursorScreenPos(wxDC &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)
+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
-   m_DefaultSetting->Layout(dc);
+   ApplyStyle(&m_DefaultSetting, dc);
    while(line)
    {
-      if(line == m_CursorLine)
-         line->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
-      else
-         line->Layout(dc, this);
-      // little condition to speed up redrawing:
-      if(bottom != -1 && line->GetPosition().y > bottom) break;
+      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();
    }
 
@@ -1407,30 +1773,29 @@ wxLayoutList::Draw(wxDC &dc,
 {
    wxLayoutLine *line = m_FirstLine;
 
-   Layout(dc, bottom);
-   m_DefaultSetting->Draw(dc, wxPoint(0,0), this);
-   wxBrush brush(m_ColourBG, wxSOLID);
+   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 + 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();
 
-   wxLogDebug("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);
+   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 *
@@ -1443,7 +1808,7 @@ wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos,
    wxPoint p;
    
    // we need to run a layout here to get font sizes right :-(
-   m_DefaultSetting->Layout(dc);
+   ApplyStyle(&m_DefaultSetting, dc);
    while(line)
    {
       p = line->GetPosition();
@@ -1490,6 +1855,7 @@ wxLayoutList::GetSize(void) const
    return maxPoint;
 }
 
+
 void
 wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
 {
@@ -1511,11 +1877,19 @@ wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
    dc.SetLogicalFunction(wxXOR);
    dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
    if(active)
-      dc.DrawRectangle(coords.x, coords.y, m_CursorSize.x,
-                       m_CursorSize.y);
+   {
+      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+m_CursorSize.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);
 }
@@ -1536,21 +1910,29 @@ wxLayoutList::SetUpdateRect(CoordType x, CoordType y)
 }
 
 void
-wxLayoutList::StartSelection(void)
+wxLayoutList::StartSelection(wxPoint cpos)
 {
-   wxLogDebug("Starting selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y);
-   m_Selection.m_CursorA = m_CursorPos;
+   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(void)
+wxLayoutList::ContinueSelection(wxPoint cpos)
 {
+   if(cpos.x == -1)
+      cpos = m_CursorPos;
    wxASSERT(m_Selection.m_selecting == true);
    wxASSERT(m_Selection.m_valid == false);
-   wxLogDebug("Continuing selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y);
-   m_Selection.m_CursorB = m_CursorPos;
+   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))
    {
@@ -1561,10 +1943,12 @@ wxLayoutList::ContinueSelection(void)
 }
 
 void
-wxLayoutList::EndSelection(void)
+wxLayoutList::EndSelection(wxPoint cpos)
 {
-   ContinueSelection();
-   wxLogDebug("Ending selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y);
+   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;
 }
@@ -1626,28 +2010,207 @@ wxLayoutList::IsSelected(const wxLayoutLine *line, CoordType *from,
       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)
 {
-   dc.SetTextForeground(m_ColourBG);
-   dc.SetTextBackground(m_ColourFG);
+#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)
 {
-   dc.SetTextForeground(m_ColourFG);
-   dc.SetTextBackground(m_ColourBG);
+#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)
+wxLayoutList::Debug(void) 
 {
    wxLayoutLine *line;
 
@@ -1673,6 +2236,9 @@ 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()
@@ -1830,3 +2396,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();
+}