New, rewritten, wxLayout. Almost complete.
authorKarsten Ballüder <ballueder@usa.net>
Sun, 7 Mar 1999 21:38:50 +0000 (21:38 +0000)
committerKarsten Ballüder <ballueder@usa.net>
Sun, 7 Mar 1999 21:38:50 +0000 (21:38 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1873 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

user/wxLayout/TODO [new file with mode: 0644]
user/wxLayout/kbList.h
user/wxLayout/wxLayout.cpp
user/wxLayout/wxLayout.h
user/wxLayout/wxllist.cpp
user/wxLayout/wxllist.h
user/wxLayout/wxlparser.cpp
user/wxLayout/wxlparser.h
user/wxLayout/wxlwindow.cpp
user/wxLayout/wxlwindow.h

diff --git a/user/wxLayout/TODO b/user/wxLayout/TODO
new file mode 100644 (file)
index 0000000..cd9ff62
--- /dev/null
@@ -0,0 +1,25 @@
+
+BUGS
+=====================================================================
+
+- Delete():
+  1 - occasionally delete deletes too much, maybe when at begin of
+      line?
+  2 - when in an empty line, Delete() doesn't always merge lines
+  3 - line numbers aren't updated properly, may be related to 2.
+  4 - deleting lines leaves later parts of the list unaffected
+       --> just redrawing at least the next two lines doesn't seem
+           enough, strange, don't positions change?
+- dmalloc shows duplicate deletion after merging two lines and
+  deleting the second half
+
+TODO
+=====================================================================
+
+- Add word wrap to wxlwindow/wxllist.
+- Cursor to mouseclick
+- Focus feedback for cursor
+- Selections
+
+- More optimisations
+
index 257c6f552839a64d03009e7e99af5d761b0b71f9..9f35abb450bb09292970d9776c1b74ae5a771a57 100644 (file)
@@ -311,5 +311,5 @@ protected: \
 /// define the most commonly used list type once:
 KBLIST_DEFINE(kbStringList, String);
 #endif
-
+//@}
 #endif // KBLIST_H
index b37f721142070f58c106537a363381145db1eb7b..504fef1d1f06d676aa6ee6be684b9910aa01a61b 100644 (file)
@@ -30,34 +30,34 @@ IMPLEMENT_APP(MyApp)
 // MyFrame
 //-----------------------------------------------------------------------------
 
-   enum ids{ ID_EDIT = 1, ID_ADD_SAMPLE, ID_CLEAR, ID_PRINT,
+   enum ids{ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
              ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
              ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
-             ID_DPRINT, ID_WRAP, ID_NOWRAP,
+             ID_WRAP, ID_NOWRAP,
              ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT, ID_TEST };
 
 
 IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
 
    BEGIN_EVENT_TABLE(MyFrame,wxFrame)
-    EVT_MENU(ID_PRINT, MyFrame::OnPrint)
-    EVT_MENU(ID_PREVIEW, MyFrame::OnPrintPreview)
-    EVT_MENU(ID_PRINT_SETUP, MyFrame::OnPrintSetup)
-    EVT_MENU(ID_PAGE_SETUP, MyFrame::OnPageSetup)
-    EVT_MENU(ID_PRINT_PS, MyFrame::OnPrintPS)
-    EVT_MENU(ID_PREVIEW_PS, MyFrame::OnPrintPreviewPS)
-    EVT_MENU(ID_PRINT_SETUP_PS, MyFrame::OnPrintSetupPS)
-    EVT_MENU(ID_PAGE_SETUP_PS, MyFrame::OnPageSetupPS)
-    EVT_MENU    (-1,       MyFrame::OnCommand)
-    EVT_COMMAND (-1,-1,    MyFrame::OnCommand)
-    EVT_CHAR    (  wxLayoutWindow::OnChar  )
+   EVT_MENU(ID_PRINT, MyFrame::OnPrint)
+   EVT_MENU(ID_PREVIEW, MyFrame::OnPrintPreview)
+   EVT_MENU(ID_PRINT_SETUP, MyFrame::OnPrintSetup)
+   EVT_MENU(ID_PAGE_SETUP, MyFrame::OnPageSetup)
+   EVT_MENU(ID_PRINT_PS, MyFrame::OnPrintPS)
+   EVT_MENU(ID_PREVIEW_PS, MyFrame::OnPrintPreviewPS)
+   EVT_MENU(ID_PRINT_SETUP_PS, MyFrame::OnPrintSetupPS)
+   EVT_MENU(ID_PAGE_SETUP_PS, MyFrame::OnPageSetupPS)
+   EVT_MENU    (-1,       MyFrame::OnCommand)
+   EVT_COMMAND (-1,-1,    MyFrame::OnCommand)
+   EVT_CHAR    (  wxLayoutWindow::OnChar  )
    END_EVENT_TABLE()
 
 
-int orientation = wxPORTRAIT;
+   int orientation = wxPORTRAIT;
 
 MyFrame::MyFrame(void) :
-      wxFrame( (wxFrame *) NULL, -1, (char *) "wxLayout", wxPoint(20,20), wxSize(600,360) )
+   wxFrame( (wxFrame *) NULL, -1, (char *) "wxLayout", wxPoint(20,20), wxSize(600,360) )
 {
    CreateStatusBar( 1 );
   
@@ -66,29 +66,25 @@ MyFrame::MyFrame(void) :
    wxMenu *file_menu = new wxMenu;
    file_menu->Append( ID_CLEAR, "Clear");
    file_menu->Append( ID_ADD_SAMPLE, "Example");
-//   file_menu->Append( ID_EDIT, "Edit");
-//   file_menu->Append( ID_WXLAYOUT_DEBUG, "Debug");
 
-  file_menu->Append(ID_PRINT, "&Print...", "Print");
-  file_menu->Append(ID_PRINT_SETUP, "Print &Setup...","Setup printer properties");
-  file_menu->Append(ID_PAGE_SETUP, "Page Set&up...", "Page setup");
-  file_menu->Append(ID_PREVIEW, "Print Pre&view", "Preview");
+   file_menu->Append(ID_PRINT, "&Print...", "Print");
+   file_menu->Append(ID_PRINT_SETUP, "Print &Setup...","Setup printer properties");
+   file_menu->Append(ID_PAGE_SETUP, "Page Set&up...", "Page setup");
+   file_menu->Append(ID_PREVIEW, "Print Pre&view", "Preview");
 #ifdef __WXMSW__
-  file_menu->AppendSeparator();
-  file_menu->Append(ID_PRINT_PS, "Print PostScript...", "Print (PostScript)");
-  file_menu->Append(ID_PRINT_SETUP_PS, "Print Setup PostScript...", "Setup printer properties (PostScript)");
-  file_menu->Append(ID_PAGE_SETUP_PS, "Page Setup PostScript...", "Page setup (PostScript)");
-  file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)");
+   file_menu->AppendSeparator();
+   file_menu->Append(ID_PRINT_PS, "Print PostScript...", "Print (PostScript)");
+   file_menu->Append(ID_PRINT_SETUP_PS, "Print Setup PostScript...", "Setup printer properties (PostScript)");
+   file_menu->Append(ID_PAGE_SETUP_PS, "Page Setup PostScript...", "Page setup (PostScript)");
+   file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)");
 #endif
-  file_menu->AppendSeparator();
-  file_menu->Append(ID_WRAP, "Wrap mode", "Activate wrapping at pixel 200.");
-  file_menu->Append(ID_NOWRAP, "No-wrap mode", "Deactivate wrapping.");
+   file_menu->AppendSeparator();
+   file_menu->Append(ID_WRAP, "Wrap mode", "Activate wrapping at pixel 200.");
+   file_menu->Append(ID_NOWRAP, "No-wrap mode", "Deactivate wrapping.");
 
-  file_menu->AppendSeparator();
-//   file_menu->Append( ID_DPRINT, "Direct Print");
+   file_menu->AppendSeparator();
    file_menu->Append( ID_TEXT, "Export Text");
    file_menu->Append( ID_HTML, "Export HTML");
-//   file_menu->Append( ID_TEST, "Test");
    file_menu->Append( ID_QUIT, "Exit");
   
    wxMenuBar *menu_bar = new wxMenuBar();
@@ -102,75 +98,74 @@ MyFrame::MyFrame(void) :
 
    m_lwin = new wxLayoutWindow(this);
    m_lwin->SetMouseTracking(true);
-   m_lwin->GetLayoutList().SetEditable(true);
+   m_lwin->SetEditable(true);
    m_lwin->Clear(wxROMAN,16,wxNORMAL,wxNORMAL, false);
    m_lwin->SetFocus();
 };
 
 void
-MyFrame::AddSampleText(wxLayoutList &llist)
+MyFrame::AddSampleText(wxLayoutList *llist)
 {
-   llist.SetFont(wxROMAN,16,wxNORMAL,wxNORMAL, false);
-   llist.Insert("--");
-   llist.LineBreak();
-
-   llist.SetFont(wxROMAN);
-   llist.Insert("The quick brown fox jumps over the lazy dog.");
-   llist.LineBreak();
-   llist.Insert("Hello ");
-   llist.Insert(new wxLayoutObjectIcon(new wxICON(Micon)));
-   llist.LineBreak();
-   llist.SetFontWeight(wxBOLD);
-   llist.Insert("World! ");
-   llist.SetFontWeight(wxNORMAL);
-   llist.Insert("The quick brown fox jumps...");
-   llist.LineBreak();
-
-   llist.Insert("over the lazy dog.");
-   llist.SetFont(-1,-1,-1,-1,true);
-   llist.Insert("underlined");
-   llist.SetFont(-1,-1,-1,-1,false);
-   llist.SetFont(wxROMAN);
-   llist.Insert("This is ");
-   llist.SetFont(-1,-1,-1,wxBOLD);  llist.Insert("BOLD ");  llist.SetFont(-1,-1,-1,wxNORMAL);
-   llist.Insert("and ");
-   llist.SetFont(-1,-1,wxITALIC);
-   llist.Insert("italics ");
-   llist.SetFont(-1,-1,wxNORMAL);
-   llist.LineBreak();
+   llist->SetFont(wxROMAN,16,wxNORMAL,wxNORMAL, false);
+   llist->Insert("--");
+   llist->LineBreak();
+
+   llist->SetFont(wxROMAN);
+   llist->Insert("The quick brown fox jumps over the lazy dog.");
+   llist->LineBreak();
+   llist->Insert("Hello ");
+   llist->Insert(new wxLayoutObjectIcon(new wxICON(Micon)));
+   llist->SetFontWeight(wxBOLD);
+   llist->Insert("World! ");
+   llist->SetFontWeight(wxNORMAL);
+   llist->Insert("The quick brown fox jumps...");
+   llist->LineBreak();
+
+   llist->Insert("over the lazy dog.");
+   llist->SetFont(-1,-1,-1,-1,true);
+   llist->Insert("underlined");
+   llist->SetFont(-1,-1,-1,-1,false);
+   llist->SetFont(wxROMAN);
+   llist->Insert("This is ");
+   llist->SetFont(-1,-1,-1,wxBOLD);  llist->Insert("BOLD ");  llist->SetFont(-1,-1,-1,wxNORMAL);
+   llist->Insert("and ");
+   llist->SetFont(-1,-1,wxITALIC);
+   llist->Insert("italics ");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->LineBreak();
   
-   llist.Insert("and ");
-   llist.SetFont(-1,-1,wxSLANT);
-   llist.Insert("slanted");
-   llist.SetFont(-1,-1,wxNORMAL);
-   llist.Insert(" text.");
-   llist.LineBreak();
-
-   llist.Insert("and ");
-   llist.SetFont(-1,-1,-1,-1,-1,"blue");
-   llist.Insert("blue");
-   llist.SetFont(-1,-1,-1,-1,-1,"black");
-   llist.Insert(" and ");
-   llist.SetFont(-1,-1,-1,-1,-1,"green","black");
-   llist.Insert("green on black");
-   llist.SetFont(-1,-1,-1,-1,-1,"black","white");
-   llist.Insert(" text.");
-   llist.LineBreak();
-
-   llist.SetFont(-1,-1,wxSLANT);
-   llist.Insert("Slanted");
-   llist.SetFont(-1,-1,wxNORMAL);
-   llist.Insert(" and normal text and ");
-   llist.SetFont(-1,-1,wxSLANT);
-   llist.Insert("slanted");
-   llist.SetFont(-1,-1,wxNORMAL);
-   llist.Insert(" again.");
-   llist.LineBreak();
+   llist->Insert("and ");
+   llist->SetFont(-1,-1,wxSLANT);
+   llist->Insert("slanted");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->Insert(" text.");
+   llist->LineBreak();
+
+   llist->Insert("and ");
+   llist->SetFont(-1,-1,-1,-1,-1,"blue");
+   llist->Insert("blue");
+   llist->SetFont(-1,-1,-1,-1,-1,"black");
+   llist->Insert(" and ");
+   llist->SetFont(-1,-1,-1,-1,-1,"green","black");
+   llist->Insert("green on black");
+   llist->SetFont(-1,-1,-1,-1,-1,"black","white");
+   llist->Insert(" text.");
+   llist->LineBreak();
+
+   llist->SetFont(-1,-1,wxSLANT);
+   llist->Insert("Slanted");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->Insert(" and normal text and ");
+   llist->SetFont(-1,-1,wxSLANT);
+   llist->Insert("slanted");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->Insert(" again.");
+   llist->LineBreak();
 
    // add some more text for testing:
-   llist.Insert("And here the source for the test program:");
-   llist.LineBreak();
-   llist.SetFont(wxTELETYPE,16);
+   llist->Insert("And here the source for the test program:");
+   llist->LineBreak();
+   llist->SetFont(wxTELETYPE,16);
    char buffer[1024];
    FILE *in = fopen("wxLayout.cpp","r");
    if(in)
@@ -180,79 +175,44 @@ MyFrame::AddSampleText(wxLayoutList &llist)
          fgets(buffer,1024,in);
          if(feof(in))
             break;
-         llist.Insert(buffer);
-         llist.LineBreak();
+         llist->Insert(buffer);
+         llist->LineBreak();
       }
    }
-   
+   llist->MoveCursorTo(wxPoint(0,0));
+   m_lwin->SetDirty();
    m_lwin->Refresh();
-   m_lwin->UpdateScrollbars();
-   llist.SetEditable();
-   llist.SetCursor(wxPoint(0,0));
 }
 
 void
 MyFrame::Clear(void)
 {
    m_lwin->Clear(wxROMAN,16,wxNORMAL,wxNORMAL, false);
-   m_lwin->UpdateScrollbars();
 }
 
-/* test the editing */
-void MyFrame::Edit(void)
-{
-   wxLayoutList & llist = m_lwin->GetLayoutList();
-   //m_lwin->SetEventId(ID_CLICK);
-  
-   llist.MoveCursor(0);
-   llist.MoveCursor(5);
-   llist.MoveCursor(0,2);
-   llist.Delete(2);
-   llist.MoveCursor(2);
-   llist.Insert("not");
-   llist.LineBreak();
-   m_lwin->Refresh();
-}
 
 void MyFrame::OnCommand( wxCommandEvent &event )
 {
-   cerr << "id:" << event.GetId() << endl;
    switch (event.GetId())
    {
    case ID_QUIT:
       Close( TRUE );
       break;
    case ID_PRINT:
-{
-   wxPrinter printer;
-   wxLayoutPrintout printout(m_lwin->GetLayoutList(),_("M: Printout"));
-   if (! printer.Print(this, &printout, TRUE))
-      wxMessageBox(                           
-         _("There was a problem with printing the message:\n"
-           "perhaps your current printer is not set up correctly?"),
-         _("Printing"), wxOK);
-}
-      break;
-   case ID_NOWRAP:
-   case ID_WRAP:
-      m_lwin->GetLayoutList().SetWrapMargin(
-         event.GetId() == ID_NOWRAP ? -1 : 40);
-      break;
-   case ID_DPRINT:
    {
-      wxLayoutList llist;
-      AddSampleText(llist);
-      wxPostScriptDC   dc("layout.ps",true,this);
-      if (dc.Ok() && dc.StartDoc((char *)_("Printing message...")))
-      {
-         //dc.SetUserScale(1.0, 1.0);
-         llist.Draw(dc); //,false,wxPoint(0,0),true);
-         dc.EndDoc();
-      }
+      wxPrinter printer;
+      wxLayoutPrintout printout(m_lwin->GetLayoutList(),_("M: Printout"));
+      if (! printer.Print(this, &printout, TRUE))
+         wxMessageBox(                           
+            _("There was a problem with printing the message:\n"
+              "perhaps your current printer is not set up correctly?"),
+            _("Printing"), wxOK);
    }
    break;
-   case ID_EDIT:
-      Edit();
+   case ID_NOWRAP:
+   case ID_WRAP:
+////      m_lwin->GetLayoutList()->SetWrapMargin(
+////         event.GetId() == ID_NOWRAP ? -1 : 40);
       break;
    case ID_ADD_SAMPLE:
       AddSampleText(m_lwin->GetLayoutList());
@@ -260,19 +220,15 @@ void MyFrame::OnCommand( wxCommandEvent &event )
    case ID_CLEAR:
       Clear();
       break;
-   case ID_WXLAYOUT_DEBUG:
-      m_lwin->GetLayoutList().Debug();
-      break;
    case ID_CLICK:
       cerr << "Received click event." << endl;
       break;
    case ID_HTML:
    {
       wxLayoutExportObject *export;
-      wxLayoutList::iterator i = m_lwin->GetLayoutList().begin();
+      wxLayoutExportStatus status(m_lwin->GetLayoutList());
 
-      while((export = wxLayoutExport(m_lwin->GetLayoutList(),
-                                     i,WXLO_EXPORT_AS_HTML)) != NULL)
+      while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_HTML)) != NULL)
       {
          if(export->type == WXLO_EXPORT_HTML)
             cout << *(export->content.text);
@@ -285,10 +241,9 @@ void MyFrame::OnCommand( wxCommandEvent &event )
    case ID_TEXT:
    {
       wxLayoutExportObject *export;
-      wxLayoutList::iterator i = m_lwin->GetLayoutList().begin();
+      wxLayoutExportStatus status(m_lwin->GetLayoutList());
 
-      while((export = wxLayoutExport(m_lwin->GetLayoutList(),
-                                     i,WXLO_EXPORT_AS_TEXT)) != NULL)
+      while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_TEXT)) != NULL)
       {
          if(export->type == WXLO_EXPORT_TEXT)
             cout << *(export->content.text);
@@ -304,136 +259,136 @@ void MyFrame::OnCommand( wxCommandEvent &event )
 void MyFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
 {
 #ifdef __WXMSW__
-      wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
 #else
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 #endif
-      wxPrinter printer;
-      wxLayoutPrintout printout( m_lwin->GetLayoutList(),"Printout from wxLayout");
-      if (! printer.Print(this, &printout, TRUE))
-         wxMessageBox(
-            "There was a problem printing.\nPerhaps your current printer is not set correctly?",
-            "Printing", wxOK);  
+   wxPrinter printer;
+   wxLayoutPrintout printout( m_lwin->GetLayoutList(),"Printout from wxLayout");
+   if (! printer.Print(this, &printout, TRUE))
+      wxMessageBox(
+         "There was a problem printing.\nPerhaps your current printer is not set correctly?",
+         "Printing", wxOK);  
 }
 
 void MyFrame::OnPrintPS(wxCommandEvent& WXUNUSED(event))
 {
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 
-      wxPostScriptPrinter printer;
-      wxLayoutPrintout printout( m_lwin->GetLayoutList(),"My printout");
-      printer.Print(this, &printout, TRUE);
+   wxPostScriptPrinter printer;
+   wxLayoutPrintout printout( m_lwin->GetLayoutList(),"My printout");
+   printer.Print(this, &printout, TRUE);
 }
 
 void MyFrame::OnPrintPreview(wxCommandEvent& WXUNUSED(event))
 {
 #ifdef __WXMSW__
-      wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
 #else
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 #endif
-      wxPrintData printData;
-      printData.SetOrientation(orientation);
-
-      // Pass two printout objects: for preview, and possible printing.
-      wxPrintPreview *preview = new wxPrintPreview(new
-                                                   wxLayoutPrintout(
-                                                      m_lwin->GetLayoutList()), new wxLayoutPrintout( m_lwin->GetLayoutList()), & printData);  
-      if (!preview->Ok())
-      {
-        delete preview;
-        wxMessageBox("There was a problem previewing.\nPerhaps your current printer is not set correctly?", "Previewing", wxOK);
-        return;
-      }
+   wxPrintData printData;
+   printData.SetOrientation(orientation);
+
+   // Pass two printout objects: for preview, and possible printing.
+   wxPrintPreview *preview = new wxPrintPreview(new
+                                                wxLayoutPrintout(
+                                                   m_lwin->GetLayoutList()), new wxLayoutPrintout( m_lwin->GetLayoutList()), & printData);  
+   if (!preview->Ok())
+   {
+      delete preview;
+      wxMessageBox("There was a problem previewing.\nPerhaps your current printer is not set correctly?", "Previewing", wxOK);
+      return;
+   }
       
-      wxPreviewFrame *frame = new wxPreviewFrame(preview, this, "Demo Print Preview", wxPoint(100, 100), wxSize(600, 650));
-      frame->Centre(wxBOTH);
-      frame->Initialize();
-      frame->Show(TRUE);
+   wxPreviewFrame *frame = new wxPreviewFrame(preview, this, "Demo Print Preview", wxPoint(100, 100), wxSize(600, 650));
+   frame->Centre(wxBOTH);
+   frame->Initialize();
+   frame->Show(TRUE);
 }
 
 void MyFrame::OnPrintPreviewPS(wxCommandEvent& WXUNUSED(event))
 {
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 
-      wxPrintData printData;
-      printData.SetOrientation(orientation);
+   wxPrintData printData;
+   printData.SetOrientation(orientation);
 
-      // Pass two printout objects: for preview, and possible printing.
-      wxPrintPreview *preview = new wxPrintPreview(new wxLayoutPrintout( m_lwin->GetLayoutList()), new wxLayoutPrintout( m_lwin->GetLayoutList()), & printData);
-      wxPreviewFrame *frame = new wxPreviewFrame(preview, this, "Demo Print Preview", wxPoint(100, 100), wxSize(600, 650));
-      frame->Centre(wxBOTH);
-      frame->Initialize();
-      frame->Show(TRUE);
+   // Pass two printout objects: for preview, and possible printing.
+   wxPrintPreview *preview = new wxPrintPreview(new wxLayoutPrintout( m_lwin->GetLayoutList()), new wxLayoutPrintout( m_lwin->GetLayoutList()), & printData);
+   wxPreviewFrame *frame = new wxPreviewFrame(preview, this, "Demo Print Preview", wxPoint(100, 100), wxSize(600, 650));
+   frame->Centre(wxBOTH);
+   frame->Initialize();
+   frame->Show(TRUE);
 }
 
 void MyFrame::OnPrintSetup(wxCommandEvent& WXUNUSED(event))
 {
 #ifdef __WXMSW__
-      wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
 #else
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 #endif
-      wxPrintData data;
-      data.SetOrientation(orientation);
+   wxPrintData data;
+   data.SetOrientation(orientation);
 
 #ifdef __WXMSW__
-      wxPrintDialog printerDialog(this, & data);
+   wxPrintDialog printerDialog(this, & data);
 #else
-      wxGenericPrintDialog printerDialog(this, & data);
+   wxGenericPrintDialog printerDialog(this, & data);
 #endif
-      printerDialog.GetPrintData().SetSetupDialog(TRUE);
-      printerDialog.ShowModal();
+   printerDialog.GetPrintData().SetSetupDialog(TRUE);
+   printerDialog.ShowModal();
 
-      orientation = printerDialog.GetPrintData().GetOrientation();
+   orientation = printerDialog.GetPrintData().GetOrientation();
 }
 
 void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
 {
 #ifdef __WXMSW__
-      wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
 #else
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 #endif
-      wxPageSetupData data;
-      data.SetOrientation(orientation);
+   wxPageSetupData data;
+   data.SetOrientation(orientation);
 
 #ifdef __WXMSW__
-      wxPageSetupDialog pageSetupDialog(this, & data);
+   wxPageSetupDialog pageSetupDialog(this, & data);
 #else
-      wxGenericPageSetupDialog pageSetupDialog(this, & data);
+   wxGenericPageSetupDialog pageSetupDialog(this, & data);
 #endif
-      pageSetupDialog.ShowModal();
+   pageSetupDialog.ShowModal();
 
-      data = pageSetupDialog.GetPageSetupData();
-      orientation = data.GetOrientation();
+   data = pageSetupDialog.GetPageSetupData();
+   orientation = data.GetOrientation();
 }
 
 void MyFrame::OnPrintSetupPS(wxCommandEvent& WXUNUSED(event))
 {
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 
-      wxPrintData data;
-      data.SetOrientation(orientation);
+   wxPrintData data;
+   data.SetOrientation(orientation);
 
-      wxGenericPrintDialog printerDialog(this, & data);
-      printerDialog.GetPrintData().SetSetupDialog(TRUE);
-      printerDialog.ShowModal();
+   wxGenericPrintDialog printerDialog(this, & data);
+   printerDialog.GetPrintData().SetSetupDialog(TRUE);
+   printerDialog.ShowModal();
 
-      orientation = printerDialog.GetPrintData().GetOrientation();
+   orientation = printerDialog.GetPrintData().GetOrientation();
 }
 
 void MyFrame::OnPageSetupPS(wxCommandEvent& WXUNUSED(event))
 {
-      wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
 
-      wxPageSetupData data;
-      data.SetOrientation(orientation);
+   wxPageSetupData data;
+   data.SetOrientation(orientation);
 
-      wxGenericPageSetupDialog pageSetupDialog(this, & data);
-      pageSetupDialog.ShowModal();
+   wxGenericPageSetupDialog pageSetupDialog(this, & data);
+   pageSetupDialog.ShowModal();
 
-      orientation = pageSetupDialog.GetPageSetupData().GetOrientation();
+   orientation = pageSetupDialog.GetPageSetupData().GetOrientation();
 }
 
 
index 90d4ae3eecc56921997804107f77a235b897ec67..ea811b8c678ea65f42781cd43a5ebc39a386cccf 100644 (file)
@@ -31,8 +31,7 @@ class MyFrame: public wxFrame
   public:
   
    MyFrame(void);
-   void Edit(void);
-   void AddSampleText(wxLayoutList &llist);
+   void AddSampleText(wxLayoutList *llist);
    void Clear(void);
    void OnCommand( wxCommandEvent &event );
 
index 69083fdeb5b9af5b65e30d64e60f2811283c9a37..1b92f5cc5d5bdffe7dc557e304eda5e1e3ceb6aa 100644 (file)
@@ -1,41 +1,14 @@
 /*-*- c++ -*-********************************************************
  * wxllist: wxLayoutList, a layout engine for text and graphics     *
  *                                                                  *
- * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
+ * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net)            *
  *                                                                  *
  * $Id$
  *******************************************************************/
 
 /*
-  - each Object knows its size and how to draw itself
-  - the list is responsible for calculating positions
-  - the draw coordinates for each object are the top left corner
-  - coordinates only get calculated when things get redrawn
-  - The cursor position is the position before an object, i.e. if the
-    buffer starts with a text-object, cursor 0,0 is just before the
-    first character. For all non-text objects, the cursor positions
-    are 0==before or 1==behind. So that all non-text objects count as
-    one cursor position.
-  - Linebreaks are at the end of a line, that is a line like "abc\n"
-    is four cursor positions long. This makes sure that cursor
-    positions are "as expected", i.e. in "abc\ndef" the 'd' would be
-    at positions (x=0,y=1).
-
-
-    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"
 #   include   <wx/log.h>
 #endif
 
-#define   BASELINESTRETCH   12
+#include <ctype.h>
 
-// This should never really get created
+/// This should never really get created
 #define   WXLLIST_TEMPFILE   "__wxllist.tmp"
 
 #ifdef WXLAYOUT_DEBUG
-static const char *g_aTypeStrings[] = 
-{ 
-   "invalid", "text", "cmd", "icon", "linebreak"
-};
-   
-#  define   wxLayoutDebug        wxLogDebug
-#  define   WXL_VAR(x)           cerr << #x " = " << x << endl;
-#  define   WXL_DBG_POINT(p)     wxLayoutDebug(#p ": (%d, %d)", p.x, p.y)
-#  define   WXL_TRACE(f)         wxLayoutDebug(#f ": ")
-#  define   TypeString(t)        g_aTypeStrings[t]
 
-void
-wxLayoutObjectBase::Debug(void)
-{
-   CoordType bl = 0;
-   wxLayoutDebug("%s: size = %dx%d, pos=%d,%d, bl = %d",
-                 TypeString(GetType()), GetSize(&bl).x,
-                 GetSize(&bl).y,
-                 GetPosition().x, GetPosition().y, bl); 
-}
+#  define   TypewxString(t)        g_aTypewxStrings[t]
+#  define   WXLO_DEBUG(x)      wxLogDebug x
 
+   static const char *g_aTypewxStrings[] = 
+   { 
+      "invalid", "text", "cmd", "icon"
+   };
+   void
+   wxLayoutObject::Debug(void)
+   {
+      WXLO_DEBUG(("%s",g_aTypewxStrings[GetType()])); 
+   }
 #else 
-#  define   WXL_VAR(x)   
-#  define   WXL_DBG_POINT(p)   
-#  define   WXL_TRACE(f)
-#  define   ShowCurrentObject()
-#  define   TypeString(t)        ""
-inline void wxLayoutDebug(const char *, ...) { }
+#  define   TypewxString(t)        ""
+#  define   WXLO_DEBUG(x)      
 #endif
 
 
-//-------------------------- wxLayoutObjectText
+/// Cursors smaller than this disappear in XOR drawing mode
+#define WXLO_MINIMUM_CURSOR_WIDTH   4
+
+/// Use this character to estimate a cursor size when none is available.
+#define WXLO_CURSORCHAR   "E"
+
+/// Helper function, allows me to compare to wxPoints
+bool operator ==(wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.x == p2.x && p1.y == p2.y;
+}
+
+/// Helper function, allows me to compare to wxPoints
+bool operator !=(wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.x != p2.x || p1.y != p2.y;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectText
 
-wxLayoutObjectText::wxLayoutObjectText(const String &txt)
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
 {
    m_Text = txt;
    m_Width = 0;
    m_Height = 0;
-   m_Position = wxPoint(-1,-1);
+   m_Top = 0;
+   m_Bottom = 0;
 }
 
 
 wxPoint
-wxLayoutObjectText::GetSize(CoordType *baseLine) const
+wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
 {
-   if(baseLine) *baseLine = m_BaseLine;
+
+   *top = m_Top; *bottom = m_Bottom;
    return wxPoint(m_Width, m_Height);
 }
 
 void
-wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &translate)
+wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords)
 {
-   dc.DrawText(Str(m_Text), m_Position.x + translate.x, m_Position.y+translate.y);
-   m_IsDirty = false;
+   dc.DrawText(m_Text, coords.x, coords.y-m_Top);
 }
 
 
 void
-wxLayoutObjectText::Layout(wxDC &dc, wxPoint position, CoordType baseLine)
+wxLayoutObjectText::Layout(wxDC &dc)
 {
    long descent = 0l;
 
-   if(m_Position.x != position.x || m_Position.y != position.y)
-      m_IsDirty = true;
-   
-   m_Position = position;
-   dc.GetTextExtent(Str(m_Text),&m_Width, &m_Height, &descent);
-   m_BaseLine = m_Height - descent;
-   if(m_Position.x != position.x || m_Position.y != position.y)
-      m_IsDirty = true;
+   dc.GetTextExtent(m_Text,&m_Width, &m_Height, &descent);
+   m_Bottom = descent;
+   m_Top = m_Height - m_Bottom;
 }
 
 #ifdef WXLAYOUT_DEBUG
 void
 wxLayoutObjectText::Debug(void)
 {
-   wxLayoutObjectBase::Debug();
-   wxLayoutDebug(" `%s`", m_Text.c_str());
+   wxLayoutObject::Debug();
+   WXLO_DEBUG((" `%s`", m_Text.c_str()));
 }
 #endif
 
-//-------------------------- wxLayoutObjectIcon
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectIcon
 
-wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon const &icon)
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
 {
-   m_Position = wxPoint(-1,-1);
-   m_Icon = new wxIcon(icon);
+   m_Icon = new wxBitmap(icon);
 }
 
-wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
 {
    m_Icon = icon;
 }
 
 void
-wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &translate)
+wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords)
 {
-   dc.DrawIcon(*m_Icon,m_Position.x+translate.x, m_Position.y+translate.y);
+   dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight());
 }
 
 void
-wxLayoutObjectIcon::Layout(wxDC &dc, wxPoint position, CoordType baseLine)
+wxLayoutObjectIcon::Layout(wxDC & /* dc */)
 {
-   if(m_Position.x != position.x || m_Position.y != position.y)
-      m_IsDirty = true;
-   m_Position = position;
 }
 
 wxPoint
-wxLayoutObjectIcon::GetSize(CoordType *baseLine) const
+wxLayoutObjectIcon::GetSize(CoordType *top, CoordType *bottom) const
 {
-   if(baseLine)   *baseLine = m_Icon->GetHeight();
+   *top = m_Icon->GetHeight();
+   *bottom = 0;
    return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
 }
 
-//-------------------------- wxLayoutObjectCmd
 
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectIcon
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
 wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
                                      weight, bool underline,
                                      wxColour const *fg, wxColour const *bg)
@@ -195,12 +180,9 @@ wxLayoutObjectCmd::~wxLayoutObjectCmd()
    delete m_font;
 }
 
-wxLayoutStyleInfo *
-wxLayoutObjectCmd::GetStyle(void) const
+void
+wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo *si) const
 {
-   wxLayoutStyleInfo *si = new wxLayoutStyleInfo();
-
-
    si->size = m_font->GetPointSize();
    si->family = m_font->GetFamily();
    si->style = m_font->GetStyle();
@@ -213,1141 +195,1076 @@ wxLayoutObjectCmd::GetStyle(void) const
    si->bg_red = m_ColourBG->Red();
    si->bg_green = m_ColourBG->Green();
    si->bg_blue = m_ColourBG->Blue();
-
-   return si;
 }
 
 void
-wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const &translate)
+wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */)
 {
    wxASSERT(m_font);
    dc.SetFont(*m_font);
-   if(m_ColourFG)
-      dc.SetTextForeground(*m_ColourFG);
-   if(m_ColourBG)
-      dc.SetTextBackground(*m_ColourBG);
+   if(m_ColourFG) dc.SetTextForeground(*m_ColourFG);
+   if(m_ColourBG) dc.SetTextBackground(*m_ColourBG);
 }
+
 void
-wxLayoutObjectCmd::Layout(wxDC &dc, wxPoint p, CoordType baseline)
+wxLayoutObjectCmd::Layout(wxDC &dc)
 {
-   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));
-}
-
-//-------------------------- wxLayoutList
-
-wxLayoutList::wxLayoutList()
-{
-   m_DefaultSetting = NULL;
-   m_WrapMargin = -1;
-   m_Editable = FALSE;
-   m_boldCursor = FALSE;
-   
-   Clear();
-}
-
-wxLayoutList::~wxLayoutList()
-{
-   if(m_DefaultSetting)
-      delete m_DefaultSetting;
-   // no deletion of objects, they are owned by the list
+   Draw(dc, wxPoint(0,0));
 }
 
-void
-wxLayoutList::LineBreak(void)
-{
-   Insert(new wxLayoutObjectLineBreak);
-}
 
-void
-wxLayoutList::SetFont(int family, int size, int style, int weight,
-                      int underline, wxColour const *fg,
-                      wxColour const *bg)
-{
-   if(family != -1)    m_FontFamily = family;
-   if(size != -1)      m_FontPtSize = size;
-   if(style != -1)     m_FontStyle = style;
-   if(weight != -1)    m_FontWeight = weight;
-   if(underline != -1) m_FontUnderline = underline != 0;
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 
-   if(fg != NULL)     m_ColourFG = fg;
-   if(bg != NULL)     m_ColourBG = bg;
-   
-   Insert(
-      new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
-                            m_ColourFG, m_ColourBG));
-}
+   The wxLayoutLine object
 
-void
-wxLayoutList::SetFont(int family, int size, int style, int weight,
-                      int underline, char const *fg, char const *bg)
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
+wxLayoutLine::wxLayoutLine(wxLayoutLine *prev)
 {
-   wxColour const
-      * cfg = NULL,
-      * cbg = NULL;
-
-   if( fg )
-      cfg = wxTheColourDatabase->FindColour(fg);
-   if( bg )
-      cbg = wxTheColourDatabase->FindColour(bg);
-   
-   SetFont(family,size,style,weight,underline,cfg,cbg);
+   m_LineNumber = 0;
+   m_Height = 0;
+   m_Length = 0;
+   m_Dirty = true;
+   m_Previous = prev;
+   m_Next = NULL;
+   RecalculatePosition();
+   if(m_Previous)
+   {
+      m_LineNumber = m_Previous->GetLineNumber()+1;
+      m_Next = m_Previous->GetNextLine();
+      m_Previous->m_Next = this;
+      m_Height = m_Previous->GetHeight();
+   }
+   if(m_Next)
+   {
+      m_Next->m_Previous = this;
+      m_Next->MoveLines(+1);
+      m_Next->RecalculatePositions(1);
+   }
 }
 
-
-/// for access by wxLayoutWindow:
-void
-wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y,
-                      CoordType *lineHeight)
+wxLayoutLine::~wxLayoutLine()
 {
-   
-   if(max_x) *max_x = m_MaxX;
-   if(max_y) *max_y = m_MaxY;
-   if(lineHeight) *lineHeight = m_LineHeight;
+   // kbList cleans itself
 }
 
-void
-wxLayoutList::ResetSettings(wxDC &dc)
+wxPoint
+wxLayoutLine::RecalculatePosition(void)
 {
-   // 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));
+   if(m_Previous)
+      m_Position = m_Previous->RecalculatePosition() +
+         wxPoint(0,m_Previous->GetHeight());
+   else
+      m_Position = wxPoint(0,0);
+   return m_Position;
 }
 
 void
-wxLayoutList::Layout(wxDC &dc, wxLayoutMargins *margins)
+wxLayoutLine::RecalculatePositions(int recurse)
 {
-   iterator i;
+   wxPoint pos = RecalculatePosition();
 
-   // first object in current line
-   wxLayoutObjectList::iterator headOfLine;
-   // where we draw next
-   wxPoint position, position_HeadOfLine;
-   // size of last object
-   wxPoint size;
-   CoordType baseLine = m_FontPtSize;
-   CoordType baseLineSkip = (BASELINESTRETCH * baseLine)/10;
-   CoordType objBaseLine = baseLine;
-   wxLayoutObjectType type;
-   
-   // we need to count cursor positions
-   wxPoint cursorPos = wxPoint(0,0);
-   
-   if(margins)
+   if(pos != m_Position)
    {
-      position.y = margins->top;
-      position.x = margins->left;
+      m_Position = pos;
+      if(m_Next) m_Next->RecalculatePositions(--recurse);
    }
    else
    {
-      position.y = 0;
-      position.x = 0;
+      m_Position = pos;
+      if(recurse && m_Next)
+         m_Next->RecalculatePositions(--recurse);
    }
-   
-   ResetSettings(dc);
-   
-   i = begin();
-   headOfLine = i;
-   position_HeadOfLine = position;
+      
+}
 
-   do
-   {
-      if(i == end())
-         return;
-   
-      type = (*i)->GetType();
-      (*i)->Layout(dc, position, baseLine);
-      size = (*i)->GetSize(&objBaseLine);
-      // calculate next object's position:
-      position.x += size.x;
+wxLayoutObjectList::iterator
+wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const
+{
+   wxASSERT(xpos >= 0);
+   wxASSERT(offset);
+   wxLayoutObjectList::iterator i;
+   CoordType x = 0, len;
    
-      // do we need to increase the line's height?
-      if(size.y > baseLineSkip)
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      len = (**i).GetLength();
+      if( x <= xpos && xpos <= x + len )
       {
-         baseLineSkip = size.y;
-         i = headOfLine; position = position_HeadOfLine;
-         continue;
+         *offset = xpos-x;
+         return i;
       }
-      if(objBaseLine > baseLine)
+      x += (**i).GetLength();
+   }
+   return NULLIT;
+}
+
+bool
+wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
+{
+   wxASSERT(xpos >= 0);
+   wxASSERT(obj != NULL);
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i == NULLIT)
+   {
+      if(xpos == 0 ) // aha, empty line!
       {
-         baseLine = objBaseLine;
-         i = headOfLine; position = position_HeadOfLine;
-         continue;
+         m_ObjectList.push_back(obj);
+         m_Length += obj->GetLength();
+         return true;
       }
+      else
+         return false;
+   }
 
-      // 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)
+   CoordType len = (**i).GetLength();
+   if(offset == 0 /*&& i != m_ObjectList.begin()*/) // why?
+   {  // insert before this object
+      m_ObjectList.insert(i,obj);
+      m_Length += obj->GetLength();
+      return true;
+   }
+   if(offset == len )
+   {
+      if( i == m_ObjectList.tail()) // last object?
       {
-         cursorPos.x = 0; cursorPos.y ++;
+         m_ObjectList.push_back(obj);
+         m_Length += obj->GetLength();
       }
       else
-         cursorPos.x += (**i).CountPositions();
-      
-      // now check whether we have finished handling this line:
-      if(type == WXLO_TYPE_LINEBREAK && i != tail()) 
-      {
-         position.x = margins ? margins->left : 0;
-         position.y += baseLineSkip;
-         baseLine = m_FontPtSize;
-         objBaseLine = baseLine; // not all objects set it
-         baseLineSkip = (BASELINESTRETCH * baseLine)/10;
-         headOfLine = i;
-         headOfLine++;
-         position_HeadOfLine = position;
+      {  // insert after current object
+         i++;
+         m_ObjectList.insert(i,obj);
+         m_Length += obj->GetLength();
       }
-      if(i == m_CursorObject)
-         CalculateCursor(dc);
-      i++;
+      return true;
    }
-   while(i != end());
-   m_MaxY = position.y + baseLineSkip;
+   /* Otherwise we need to split the current object.
+      Fortunately this can only be a text object. */
+   wxASSERT((**i).GetType() == WXLO_TYPE_TEXT);
+   wxString left, right;
+   wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+   left = tobj->GetText().substr(0,offset);
+   right = tobj->GetText().substr(offset,len-offset);
+   // current text object gets set to right half
+   tobj->GetText() = right; // set new text
+   // before it we insert the new object
+   m_ObjectList.insert(i,obj);
+   m_Length += obj->GetLength();
+   // and before that we insert the left half
+   m_ObjectList.insert(i,new wxLayoutObjectText(left));
+   return true;
 }
-
-void
-wxLayoutList::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)
+bool
+wxLayoutLine::Insert(CoordType xpos, wxString text)
+{
+   wxASSERT(xpos >= 0);
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
    {
-      if((**start).GetType() == WXLO_TYPE_CMD)
-         (**start).Draw(dc,translate);  // apply font settings
-      start++;
+      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+      tobj->GetText().insert(offset, text);
+      m_Length += text.Length();
    }
-   for( i = start ;
-        i != end() && (toLine == -1 || (**i).GetPosition().y < toLine) ;
-        i++ )
-      (*i)->Draw(dc,translate);
+   else
+      return Insert(xpos, new wxLayoutObjectText(text));
 }
 
-/** Erase at least to end of line */
-void
-wxLayoutList::EraseAndDraw(wxDC &dc, iterator start, wxPoint const &translate)
+CoordType
+wxLayoutLine::Delete(CoordType xpos, CoordType npos)
 {
-   //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();
+   CoordType offset;
 
-   //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());
+   wxASSERT(xpos >= 0);
+   wxASSERT(npos >= 0);
+   wxLOiterator i = FindObject(xpos, &offset);
+   while(npos > 0)
+   {
+      if(i == NULLIT)  return false; // FIXME
+      // now delete from that object:
+      if((**i).GetType() != WXLO_TYPE_TEXT)
+      {
+         if(offset != 0) // at end of line after a non-text object
+            return npos;
+         // always len == 1:
+         m_Length -= (**i).GetLength();
+         npos -= m_Length;
+         m_ObjectList.erase(i);
+      }
+      else
+      {
+         // tidy up: remove empty text objects
+         if((**i).GetLength() == 0)
+         {
+            m_ObjectList.erase(i);
+            continue;
+         }
+         // Text object:
+         CoordType max = (**i).GetLength() - offset;
+         if(npos < max) max = npos;
+         if(max == 0)
+         {
+            if(xpos == GetLength())
+               return npos;
+            else 
+            {  // at    the end of an object
+               // move to    begin of next object:
+               i++; offset = 0;
+               continue; // start over
+            }
+         }
+         npos -= max;
+         m_Length -= max;
+         if(offset == 0 && max == (**i).GetLength())
+            m_ObjectList.erase(i);  // remove the whole object
+         else
+            ((wxLayoutObjectText *)(*i))->GetText().Remove(offset,max);
+      }
+   }
+   return npos;
 }
 
-
-void
-wxLayoutList::CalculateCursor(wxDC &dc)
+bool
+wxLayoutLine::DeleteWord(CoordType xpos)
 {
-   if(! m_CursorMoved)
-      return;
-   
-   CoordType width, height, descent;
-   CoordType baseLineSkip = 20; //FIXME
+   wxASSERT(xpos >= 0);
+   CoordType 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;
+   wxLOiterator i = FindObject(xpos, &offset);
 
-   m_CursorCoords = obj.GetPosition();
-   if(obj.GetType() == WXLO_TYPE_TEXT)
-   {
-      wxLayoutObjectText *tobj = (wxLayoutObjectText *)&obj;
-      String & str = tobj->GetText();
-      String sstr = str.substr(0,m_CursorOffset);
-      dc.GetTextExtent(sstr,&width,&height,&descent);
-      m_CursorCoords = wxPoint(m_CursorCoords.x+width,
-                               m_CursorCoords.y);
-      m_CursorSize = wxPoint(cursorWidth,height);
-   }
-   else if(obj.GetType() == WXLO_TYPE_LINEBREAK)
+   for(;;)
    {
-      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);
+      if(i == NULLIT) return false;
+      if((**i).GetType() != WXLO_TYPE_TEXT)
+      {
+         // This should only happen when at end of line, behind a non-text 
+         // object:
+         if(offset == (**i).GetLength()) return false;
+         m_Length -= (**i).GetLength(); // -1
+         m_ObjectList.erase(i);
+         return true; // we are done
+      }
+      else
+      {  // text object:
+         if(offset == (**i).GetLength()) // at end of object
+         {
+            i++; offset = 0;
+            continue;
+         }
+         wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+         size_t count = 0;
+         wxString str = tobj->GetText();
+         str = str.substr(offset,str.Length()-offset);
+         // Find out how many positions we need to delete:
+         // 1. eat leading space
+         while(isspace(str[count])) count++;
+         // 2. eat the word itself:
+         while(isalnum(str[count])) count++;
+         // now delete it:
+         wxASSERT(count+offset <= (size_t) (**i).GetLength());
+         ((wxLayoutObjectText *)*i)->GetText().erase(offset,count);
+         m_Length -= count;
+         return true;
+      }      
    }
-   else
+   wxASSERT(0); // we should never arrive here
+}
+
+wxLayoutLine *
+wxLayoutLine::DeleteLine(bool update)
+{
+   if(m_Next) m_Next->m_Previous = m_Previous;
+   if(m_Previous) m_Previous->m_Next = m_Next;
+   if(update)
    {
-      // 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_Next->MoveLines(-1);
+      m_Next->RecalculatePositions(1);
    }
-   m_CursorMoved = false; // coords are valid
+   wxLayoutLine *next = m_Next;
+   delete this;
+   return next;
 }
 
 void
-wxLayoutList::DrawCursor(wxDC &dc, bool erase, wxPoint const &translate)
+wxLayoutLine::Draw(wxDC &dc, const wxPoint & offset) const
 {
-   if(! m_Editable)
-      return;
+   wxLayoutObjectList::iterator i;
+   wxPoint pos = offset;
+   pos = pos + GetPosition();
    
-   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
+   pos.y += m_BaseLine;
+   
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      // 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);
+      (**i).Draw(dc, pos);
+      pos.x += (**i).GetWidth();
    }
 }
 
-
-
-
-
-
-
-#ifdef WXLAYOUT_DEBUG
 void
-wxLayoutList::Debug(void)
+wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, wxPoint
+                     *cursorSize,
+                     int cx) 
 {
    wxLayoutObjectList::iterator i;
 
-   wxLayoutDebug("------------------------ debug start ------------------------"); 
-   for(i = begin(); i != end(); i++)
-      (*i)->Debug();
-   wxLayoutDebug("-------------------------- list end -------------------------");
-   
-   // show current object:
-   ShowCurrentObject();
-   wxLayoutDebug("------------------------- debug end -------------------------");
-}
+   CoordType
+      oldHeight = m_Height;
+   CoordType
+      topHeight, bottomHeight;  // above and below baseline
+   CoordType
+      objHeight = 0,
+      objTopHeight, objBottomHeight;
+   CoordType
+      len, count = 0;
+   m_Height = 0; m_BaseLine = 0;
+   m_Width = 0;
+   topHeight = 0; bottomHeight = 0;
+   wxPoint size;
+   bool cursorFound = false;
 
-void
-wxLayoutList::ShowCurrentObject()
-{
-   wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos.x, (int) m_CursorPos.y);
-   wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset);
-   wxLayoutDebug("CursorObject = %p", m_CursorObject);
-   if(m_CursorObject == iterator(NULL))
-      wxLayoutDebug("<<no object found>>");
-   else
+   if(cursorPos)
    {
-      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()));
+      *cursorPos = m_Position;
    }
-   wxLayoutDebug("Line length: %d", GetLineLength(m_CursorObject));
-
-}
-
-#endif
-
-/******************** editing stuff ********************/
-
-// don't change this, I know how to optimise this and will do it real 
-// soon (KB)
-
-/*
- * FindObjectCursor:
- * Finds the object belonging to a given cursor position cpos and
- * returns an iterator to that object and stores the relative cursor
- * position in offset.
- *
- * For linebreaks, the offset can be 0=before or 1=after.
- *
- * If the cpos coordinates don't exist, they are modified.
- */
-
-wxLayoutObjectList::iterator 
-wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
-{
-   wxPoint object = wxPoint(0,0);  // runs along the objects
-   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; )
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      width = (**i).CountPositions();
-      if(cpos->y == object.y) // a possible candidate
-      {
-         if((**i).GetType() ==WXLO_TYPE_LINEBREAK)
+      (**i).Layout(dc);
+      size = (**i).GetSize(&objTopHeight, &objBottomHeight);
+
+      if(cursorPos && ! cursorFound)
+      {  // we need to check whether the text cursor is here
+         len = (**i).GetLength();
+         if(count <= cx && count+len > cx)
          {
-            if(cpos->x == object.x)
+            if((**i).GetType() == WXLO_TYPE_TEXT)
             {
-               if(offset) *offset = 0;
-               return m_FoundIterator = i;
+               len = cx - count; // pos in object
+               CoordType width, height, descent;
+               dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len), 
+                                &width, &height, &descent);
+               cursorPos->x += width;
+               cursorPos->y = m_Position.y;
+               wxString str;
+               if(len < (**i).GetLength())
+                  str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1);
+               else
+                  str = WXLO_CURSORCHAR;
+               dc.GetTextExtent(str, &width, &height, &descent);
+               wxASSERT(cursorSize);
+               // Just in case some joker inserted an empty string object:
+               if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH;
+               if(height == 0) height = objHeight;
+               cursorSize->x = width;
+               cursorSize->y = height;
+               cursorFound = true; // no more checks
+            }
+            else 
+            { // on some other object
+               CoordType top, bottom; // unused
+               *cursorSize = (**i).GetSize(&top,&bottom);
+               cursorPos->y = m_Position.y;
+               cursorFound = true; // no more checks
             }
-            if(offset) *offset=1;
-            cpos->x = object.x;
-            return m_FoundIterator = i;
          }
-         if(cpos->x >= object.x && cpos->x <= object.x+width) // overlap
+         else
          {
-            if(offset) *offset = cpos->x-object.x;
-//#ifdef WXLAYOUT_DEBUG
-//            wxLayoutDebug("   found object at (%d, %d), type: %s",
-//                          object.x,  object.y, TypeString((*i)->GetType()));
-//#endif      
-            return m_FoundIterator = i;
+            count += len;
+            cursorPos->x += (**i).GetWidth();
          }
-      }
-      // no overlap, increment coordinates
-      object.x += width;
-      if((**i).GetType() == WXLO_TYPE_LINEBREAK)
+      } // cursor finding
+      objHeight = size.y;
+      m_Width += size.x;
+      if(objHeight > m_Height) m_Height = objHeight;
+      if(objTopHeight > topHeight) topHeight = objTopHeight;
+      if(objBottomHeight > bottomHeight) bottomHeight = objBottomHeight;
+   }
+   if(topHeight + bottomHeight > m_Height) m_Height =
+                                              topHeight+bottomHeight;
+   m_BaseLine = topHeight;
+
+   if(m_Height == 0)
+   {
+      if(GetPreviousLine()) // empty line
       {
-         object.x = 0;
-         object.y++;
+         m_Height = GetPreviousLine()->GetHeight();
+         m_BaseLine = GetPreviousLine()->m_BaseLine;
       }
-      if(go_up)
-         i++;
       else
-         i--;
-   }//for
-//#ifdef WXLAYOUT_DEBUG
-//   wxLayoutDebug("   not found");
-//#endif
-// return last object, coordinates of that one:
-   i = tail();
-   if(i == end())
-      return m_FoundIterator = i;
-   if((**i).GetType()==WXLO_TYPE_LINEBREAK)
-   {
-      if(offset)
-         *offset = 1;
-      return m_FoundIterator = i;
+      {
+            CoordType width, height, descent;
+            dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+            m_Height = height;
+            m_BaseLine = m_Height - descent;
+      }
    }
-   cpos->x = object.x; // would be the coordinate of next object
-   cpos->y = object.y;
-   cpos->x += width; // last object's width
-   if(*offset)  *offset = cpos->x-object.x;
-   return m_FoundIterator = i; // not found
-}
-
-bool
-wxLayoutList::MoveCursor(int dx, int dy)
-{
-   CoordType diff;
 
-   m_CursorMoved = true;  
    
-   enum { up, down} direction;
-
-   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;
+   // tell next line about coordinate change
+   if(m_Next && objHeight != oldHeight)
+      m_Next->RecalculatePositions();
 
-   if(newPos.y > m_CursorPos.y ||
-      newPos.y == m_CursorPos.y &&
-      newPos.x >= m_CursorPos.x)
-      direction = down;
-   else
-      direction = up;
-
-   if ( !m_CursorObject )
-   {
-      // list is empty
-       return FALSE;
-   }
-
-   // now move cursor forwards until at the new position:
-
-   // first, go to the right line:
-   while(newPos.y != m_CursorPos.y)
+   if(cursorPos)
    {
-      if(direction == down)
+      // this might be the case if the cursor is at the end of the
+      // line or on a command object:
+      if(cursorSize->y < WXLO_MINIMUM_CURSOR_WIDTH)
       {
-         m_CursorPos.x +=
-            (**m_CursorObject).CountPositions() - m_CursorOffset;
-         if(m_CursorObject == tail())
-            break;  // can't go any further
-         if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK
-            && m_CursorOffset == 0)
+         if(m_BaseLine > 0)
          {
-            m_CursorPos.y++; m_CursorPos.x = 0;
+            cursorSize->y = m_BaseLine;
+            if(cursorSize->x < WXLO_MINIMUM_CURSOR_WIDTH) cursorSize->x = WXLO_MINIMUM_CURSOR_WIDTH;
          }
-         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)
+         else // empty line
          {
-            m_CursorPos.y--;
-            m_CursorPos.x = GetLineLength(m_CursorObject);
+            CoordType width, height, descent;
+            dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+            cursorSize->x = width;
+            cursorSize->y = height;
          }
-         m_CursorPos.x -= m_CursorOffset;
-         m_CursorObject --; m_CursorOffset = (**m_CursorObject).CountPositions();
       }
+      if(m_BaseLine >= cursorSize->y) // the normal case anyway
+         cursorPos->y += m_BaseLine-cursorSize->y;
    }
-   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
+}
+
+wxLayoutObject *
+wxLayoutLine::FindObject(CoordType xpos)
+{
+   wxASSERT(xpos >= 0);
+   if(xpos > GetWidth()) return NULL;
+
+   CoordType x = 0;
+   for(wxLOiterator i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      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
+      x += (**i).GetWidth();
+      if(x > xpos) // we just crossed it
+         return *i;
+   }
+   return NULL;
+}
+
+wxLayoutLine *
+wxLayoutLine::Break(CoordType xpos)
+{
+   wxASSERT(xpos >= 0);
+   
+   if(xpos == 0)
+   { // insert an empty line before this one
+      wxLayoutLine *prev = new wxLayoutLine(m_Previous);
+      if(m_Previous == NULL)
+      {  // We were in first line, need to link in new empty line
+         // before this.
+         prev->m_Next = this;
+         m_Previous = prev;
+         m_Previous->m_Height = GetHeight(); // this is a wild guess
+      }
+      MoveLines(+1);
+      if(m_Next)
+         m_Next->RecalculatePositions(1);
+      return this;
    }
-   direction = newPos.x >= m_CursorPos.x ? down : up;
-   while(newPos.x != m_CursorPos.x)
+   
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i == NULLIT)
+      // must be at the end of the line then
+      return new wxLayoutLine(this);
+   // split this line:
+
+   wxLayoutLine *newLine = new wxLayoutLine(this);
+   // split object at i:
+   if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0)
    {
-      if(direction == down)
-      {
-         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 // up
-      {
-         if(m_CursorPos.x == 0 && m_CursorOffset == 1 &&
-            (**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK) // can we go further up?
-         {
-            m_CursorPos.y--;
-            newPos.y--; 
-            m_CursorOffset = 0;
-            m_CursorPos.x = GetLineLength(m_CursorObject)-1;
-            newPos.x += m_CursorPos.x+1;
-            continue;
-         }
-         diff = m_CursorPos.x - newPos.x;
-         if(diff >= m_CursorOffset)
-         {
-            if(m_CursorObject == begin())
-            {
-               m_CursorOffset = 0;
-               m_CursorPos.x = 0;
-               break; // cannot go further
-            }
-            m_CursorObject--;
-            m_CursorPos.x -= m_CursorOffset;
-            m_CursorOffset = (**m_CursorObject).CountPositions();
-         }
-         else
-         {
-            m_CursorPos.x -= diff;
-            m_CursorOffset -= diff;
-         }
-      }
+      wxString left, right;
+      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+      left = tobj->GetText().substr(0,offset);
+      right = tobj->GetText().substr(offset,tobj->GetLength()-offset);
+      // current text object gets set to left half
+      tobj->GetText() = left; // set new text
+      newLine->Append(new wxLayoutObjectText(right));
+      m_Length -= m_Length - offset;
+      i++; // don't move this object to the new list
    }
+   else
+      if(offset > 0)
+         i++; // move objects from here to new list
 
-   return true; // FIXME: when return what?
+   while(i != m_ObjectList.end())
+   {
+      newLine->Append(*i);
+      m_Length -= (**i).GetLength();
+      m_ObjectList.remove(i); // remove without deleting it
+   }
+   if(m_Next)
+      m_Next->RecalculatePositions(2);
+   return newLine;
 }
+   
+
 void
-wxLayoutList::SetCursor(wxPoint const &p)
+wxLayoutLine::MergeNextLine(void)
 {
-   m_CursorPos = p;
-   m_CursorObject = FindObjectCursor(&m_CursorPos, &m_CursorOffset);
-   m_CursorMoved = true;  
+   wxASSERT(GetNextLine());
+   wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
+   wxLOiterator i;
+   
+   for(i = list.begin(); i != list.end();)
+   {
+      Append(*i);
+      list.remove(i); // remove without deleting it
+   }
+   wxASSERT(list.empty());
+   wxLayoutLine *oldnext = GetNextLine();
+   SetNext(GetNextLine()->GetNextLine());
+   delete oldnext;
+   RecalculatePositions(1);
 }
 
-void
-wxLayoutList::Delete(CoordType count)
+   
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+   
+   The wxLayoutList object
+   
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutList::wxLayoutList()
+{
+   m_DefaultSetting = NULL;
+   m_FirstLine = NULL;
+   InternalClear();
+}
+
+wxLayoutList::~wxLayoutList()
 {
-   WXL_TRACE(Delete);
+   InternalClear();
+}
 
-   if(!m_Editable)
-      return;
+void
+wxLayoutList::InternalClear(void)
+{
+   while(m_FirstLine)
+      m_FirstLine = m_FirstLine->DeleteLine(false);
 
-   m_bModified = true;
-   
-   CoordType offs = 0;
-   wxLayoutObjectList::iterator i;
-      
-   do
+   if(m_DefaultSetting)
    {
-      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 m_CursorOffset==0 we are before the linebreak, otherwise behind.  */
-      if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
-      {
-         if(m_CursorOffset == 0)
-         {
-            m_MaxLine--;
-            erase(i);
-            m_CursorObject = i; // new i!
-            m_CursorOffset = 0; // Pos unchanged
-            count--;
-            continue; // we're done
-         }
-         else // delete the object behind the linebreak
-         {
-            i++; // we increment and continue as normal
-            m_CursorOffset=0;
-            goto startover; 
-         }
-      }
-      else if((*i)->GetType() == WXLO_TYPE_TEXT)
-      {
-         wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
-         CoordType len = tobj->CountPositions();
-         /* If we find the end of a text object, this means that we
-            have to delete from the object following it. */
-         if(len == m_CursorOffset)
-         {
-            i++;
-            m_CursorOffset = 0;
-            goto startover;
-         }
-         else
-         {
-            if(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
-         }
-      }
-      else// all other objects: delete the object
-// this only works as expected  if the non-text object has 0/1
-// as offset values. Not tested with "longer" objects.
-      {
-         CoordType len = (*i)->CountPositions();
-         if(offs == 0)
-         {
-            count = count > len ? count -= len : 0;
-            erase(i); // after this, i is the iterator for the
-                      // following object
-            m_CursorObject = i;
-            m_CursorOffset = 0;
-            continue;
-         }
-         else // delete the following object
-         {
-            i++; // we increment and continue as normal
-            m_CursorOffset=0;
-            goto startover; 
-         }
-      }
+      delete m_DefaultSetting;
+      m_DefaultSetting = NULL;
    }
-   while(count && i != end());      
+
+   m_CursorPos = wxPoint(0,0);
+   m_CursorScreenPos = wxPoint(0,0);
+   m_CursorSize = wxPoint(0,0);
+   m_FirstLine = new wxLayoutLine(NULL); // empty first line
+   m_CursorLine = m_FirstLine;
 }
 
+void
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+                      int underline, wxColour const *fg,
+                      wxColour const *bg)
+{
+   if(family != -1)    m_FontFamily = family;
+   if(size != -1)      m_FontPtSize = size;
+   if(style != -1)     m_FontStyle = style;
+   if(weight != -1)    m_FontWeight = weight;
+   if(underline != -1) m_FontUnderline = underline != 0;
+
+   if(fg != NULL)     m_ColourFG = fg;
+   if(bg != NULL)     m_ColourBG = bg;
+   
+   Insert(
+      new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
+                            m_ColourFG, m_ColourBG));
+}
 
 void
-wxLayoutList::Insert(wxLayoutObjectBase *obj)
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+                      int underline, char const *fg, char const *bg)
+
 {
-   wxCHECK_RET( obj, "no object to insert" );
+   wxColour const
+      * cfg = NULL,
+      * cbg = NULL;
 
-   m_bModified = true;
+   if( fg )
+      cfg = wxTheColourDatabase->FindColour(fg);
+   if( bg )
+      cbg = wxTheColourDatabase->FindColour(bg);
+   
+   SetFont(family,size,style,weight,underline,cfg,cbg);
+}
 
-   wxLayoutObjectList::iterator i = m_CursorObject;
+void
+wxLayoutList::Clear(int family, int size, int style, int weight,
+                    int /* underline */, char const *fg, char const *bg)
+{
+   InternalClear();
+   
+   // set defaults
+   m_FontPtSize = size;
+   m_FontUnderline = false;
+   m_FontFamily = family;
+   m_FontStyle = style;
+   m_FontWeight = weight;
+   m_ColourFG = wxTheColourDatabase->FindColour(fg);
+   m_ColourBG = wxTheColourDatabase->FindColour(bg);
 
-   if(i != iterator(NULL) && (*obj).GetType() == WXLO_TYPE_LINEBREAK)
-   {
-      m_CursorPos.x = 0; m_CursorPos.y ++;
-   }
+   if(! m_ColourFG) m_ColourFG = wxBLACK;
+   if(! m_ColourBG) m_ColourBG = wxWHITE;
    
-   if(i == end())
-   {
-      push_back(obj);
-      m_CursorObject = tail();
-   }
-   else if(m_CursorOffset == 0)
+   if(m_DefaultSetting)
+      delete m_DefaultSetting;
+
+   m_DefaultSetting = new
+      wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
+                        m_FontWeight,m_FontUnderline,
+                        m_ColourFG, m_ColourBG);
+}
+
+
+
+bool
+wxLayoutList::MoveCursorTo(wxPoint const &p)
+{
+   wxLayoutLine *line = m_FirstLine;
+   while(line && line->GetLineNumber() != p.y)
+      ;
+   if(line && line->GetLineNumber() == p.y) // found it
    {
-      insert(i,obj);
-      m_CursorObject = i;
+      m_CursorPos.y = p.y;
+      m_CursorLine = line;
+      CoordType len = line->GetLength();
+      if(len >= p.x)
+      {
+         m_CursorPos.x = p.x;
+         return true;
+      }
+      else
+      {
+         m_CursorPos.x = len;
+         return false;
+      }
    }
-   // do we have to split a text object?
-   else if((*i)->GetType() == WXLO_TYPE_TEXT && m_CursorOffset != (*i)->CountPositions())
+   return false;
+}
+   
+bool
+wxLayoutList::MoveCursorVertically(int n)
+{
+   if(n  < 0) // move up
    {
-      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
-      String left = tobj->GetText().substr(0,m_CursorOffset); // get part before cursor
-      tobj->GetText() = tobj->GetText().substr(m_CursorOffset,(*i)->CountPositions()-m_CursorOffset); // keeps the right half
-      insert(i,obj);
-      m_CursorObject = i; // == obj
-      insert(i,new wxLayoutObjectText(left)); // inserts before
+      if(m_CursorLine == m_FirstLine) return false;
+      while(n < 0 && m_CursorLine)
+      {
+         m_CursorLine = m_CursorLine->GetPreviousLine();
+         m_CursorPos.y--;
+         n++;
+      }
+      if(! m_CursorLine)
+      {
+         m_CursorLine = m_FirstLine;
+         m_CursorPos.y = 0;
+         return false;
+      }
+      else
+      {
+         if(m_CursorPos.x > m_CursorLine->GetLength())
+            m_CursorPos.x = m_CursorLine->GetLength();
+         return true;
+      }
    }
-   else
+   else // move down
    {
-      // all other cases, append after object:
-      wxLayoutObjectList::iterator j = i; // we want to apend after this object
-      j++;
-      if(j != end())
+      wxLayoutLine *last = m_CursorLine;
+      if(! m_CursorLine->GetNextLine()) return false;
+      while(n > 0 && m_CursorLine)
       {
-         insert(j, obj);
-         m_CursorObject = j;
+         n--;
+         m_CursorPos.y ++;
+         m_CursorLine = m_CursorLine->GetNextLine();
+      }
+      if(! m_CursorLine)
+      {
+         m_CursorLine = last;
+         m_CursorPos.y ++;
+         return false;
       }
       else
       {
-         push_back(obj);
-         m_CursorObject = tail();
+         if(m_CursorPos.x > m_CursorLine->GetLength())
+            m_CursorPos.x = m_CursorLine->GetLength();
+         return true;
       }
    }
-
-   if(obj->GetType() != WXLO_TYPE_LINEBREAK) // handled separately above
-      m_CursorPos.x += obj->CountPositions();
-   // applies also for linebreak:
-   m_CursorOffset = obj->CountPositions();
-   
-   if(obj->GetType() == WXLO_TYPE_LINEBREAK)
-      m_MaxLine++;
-   m_CursorMoved = true;
 }
 
-void
-wxLayoutList::Insert(String const &text)
+bool
+wxLayoutList::MoveCursorHorizontally(int n)
 {
-   wxLayoutObjectText *tobj = NULL;
-   wxLayoutObjectList::iterator j;
+   int move;
+   while(n < 0)
+   {
+      if(m_CursorPos.x == 0) // at begin of line
+      {
+         if(! MoveCursorVertically(-1))
+            break;
+         MoveCursorToEndOfLine();
+         n++;
+         continue;
+      }
+      move = -n;
+      if(move > m_CursorPos.x) move = m_CursorPos.x;
+      m_CursorPos.x -= move; n += move;
+   }
 
-//   WXL_TRACE(Insert(text));
+   while(n > 0)
+   {
+      int len =  m_CursorLine->GetLength();
+      if(m_CursorPos.x == len) // at end of line
+      {
+         if(! MoveCursorVertically(1))
+            break;
+         MoveCursorToBeginOfLine();
+         n--;
+         continue;
+      }
+      move = n;
+      if( move >= len-m_CursorPos.x) move = len-m_CursorPos.x;
+      m_CursorPos.x += move;
+      n -= move;
+   }
+   return n == 0;
+}
 
-   if(! m_Editable)
-      return;
+bool
+wxLayoutList::Insert(wxString const &text)
+{
+   wxASSERT(m_CursorLine);
+   m_CursorLine->Insert(m_CursorPos.x, text);
+   m_CursorPos.x += text.Length();
+   return true;
+}
 
-   m_bModified = true;
+bool
+wxLayoutList::Insert(wxLayoutObject *obj)
+{
+   wxASSERT(m_CursorLine);
+   m_CursorLine->Insert(m_CursorPos.x, obj);
+   m_CursorPos.x += obj->GetLength();
+   return true;
+}
 
-   wxLayoutObjectList::iterator i = m_CursorObject;
+bool
+wxLayoutList::LineBreak(void)
+{
+   wxASSERT(m_CursorLine);
 
-   if(i == end())
-   {
-      Insert(new wxLayoutObjectText(text));
-      return;
-   }
+   bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
+   m_CursorLine = m_CursorLine->Break(m_CursorPos.x);
+   if(setFirst) // we were at beginning of first line
+      m_FirstLine = m_CursorLine->GetPreviousLine();
+   m_CursorPos.y++;
+   m_CursorPos.x = 0;
+   return true;
+}
 
-   switch((**i).GetType())
+bool
+wxLayoutList::Delete(CoordType npos)
+{
+   wxASSERT(m_CursorLine);
+   CoordType left;
+   do
    {
-   case WXLO_TYPE_TEXT:
-// insert into an existing text object:
-      tobj = (wxLayoutObjectText *)*i ;
-      wxASSERT(tobj);
-      tobj->GetText().insert(m_CursorOffset,text);
-      m_CursorObject = i;
-      m_CursorOffset = m_CursorOffset + text.length();
-      m_CursorPos.x += text.length();
-      break;
-   case WXLO_TYPE_LINEBREAK:
-   default:
-      j = i;
-      if(m_CursorOffset == 0) // try to append to previous object
-      {
-         j--;
-         if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
-         {
-            tobj = (wxLayoutObjectText *)*j;
-            tobj->GetText()+=text;
-            m_CursorObject = j;
-            m_CursorOffset = (**j).CountPositions();
-            m_CursorPos.x += text.length();
-         }
-         else
-         {
-            insert(i,new wxLayoutObjectText(text));
-            m_CursorObject = i;
-            m_CursorOffset = (**i).CountPositions();
-            m_CursorPos.x += m_CursorOffset;
-         }
+      left = m_CursorLine->Delete(m_CursorPos.x, npos);
+      if(left == 0)
+         return true;
+      // More to delete, continue on next line.
+      // First, check if line is empty:
+      if(m_CursorLine->GetLength() == 0)
+      {  // in this case, updating could probably be optimised
+         m_CursorLine = m_CursorLine->DeleteLine(true);
+         left--;
       }
-      else // offset == 1 : cursor after linebreak
+      else 
       {
-         j++;
-         m_CursorObject = j;
-         m_CursorOffset = 0;
-         if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
-         {
-            tobj = (wxLayoutObjectText *)*j;
-            tobj->GetText()=text+tobj->GetText();
-            m_CursorOffset = text.length();
-            m_CursorPos.x += m_CursorOffset;
-         }
+         // Need to join next line
+         if(! m_CursorLine->GetNextLine())
+            break; // cannot
          else
          {
-            if(j == end())
-            {
-               push_back(new wxLayoutObjectText(text));
-               m_CursorObject = tail();
-               m_CursorOffset = (**m_CursorObject).CountPositions();
-               m_CursorPos.x += text.length();
-            }
-            else
-            {
-               insert(j,new wxLayoutObjectText(text));
-               m_CursorObject = j;
-               m_CursorOffset = (**j).CountPositions();
-               m_CursorPos.x += text.length();
-            }
+            m_CursorLine->MergeNextLine();
+            left--;
          }
       }
-      break;
    }
-   m_CursorMoved = true;
+   while(left);
+   return left == 0;
 }
 
-CoordType
-wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs)
+int
+wxLayoutList::DeleteLines(int n)
 {
-   if(i == end())
-      return 0;
-
-   CoordType len = 0;
-
-   if(offs == 0 && (**i).GetType() == WXLO_TYPE_LINEBREAK)
-      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--;
-   if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
-      i++;
-// now we can start counting:
-   while(i != end() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
+   wxASSERT(m_CursorLine);
+   wxLayoutLine *line;
+   while(n > 0)
    {
-      len += (*i)->CountPositions();
-      i++;
+      if(!m_CursorLine->GetNextLine())
+      {  // we cannot delete this line, but we can clear it
+         MoveCursorToBeginOfLine();
+         DeleteToEndOfLine();
+         return n-1;
+      }
+      //else:
+      line = m_CursorLine;
+      m_CursorLine = m_CursorLine->DeleteLine(true);
+      n--;
+      if(line == m_FirstLine) m_FirstLine = m_CursorLine;
+      wxASSERT(m_FirstLine);
+      wxASSERT(m_CursorLine);
    }
-   len++; // one extra for the linebreak
-   return len;
+   m_CursorLine->RecalculatePositions(2);
+   return n;
 }
 
 void
-wxLayoutList::Clear(int family, int size, int style, int weight,
-                    int underline, char const *fg, char const *bg)
+wxLayoutList::Layout(wxDC &dc, CoordType bottom) const
 {
-   m_bModified = true;
-   m_CursorMoved = true;
-   m_dirty = true;  // force redraw/recalc
-   wxLayoutObjectList::iterator i = begin();
+   wxLayoutLine *line = m_FirstLine;
 
-   wxBitmap bm(4,4);
-   m_CursorMemDC.SelectObject(bm);
+   // first, make sure everything is calculated - this might not be
+   // needed, optimise it later
+   m_DefaultSetting->Layout(dc);
+   while(line)
+   {
+      if(line == m_CursorLine)
+         line->Layout(dc, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+      else
+         line->Layout(dc);
+      // 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));
+}
 
-   while(i != end()) // == while valid
-      erase(i);
+void
+wxLayoutList::Draw(wxDC &dc, wxPoint const &offset,
+                   CoordType top, CoordType bottom) const
+{
+   wxLayoutLine *line = m_FirstLine;
 
-   // set defaults
-   m_FontPtSize = size;
-   m_FontUnderline = false;
-   m_FontFamily = family;
-   m_FontStyle = style;
-   m_FontWeight = weight;
-   m_ColourFG = wxTheColourDatabase->FindColour(fg);
-   m_ColourBG = wxTheColourDatabase->FindColour(bg);
+   Layout(dc, bottom);
+   m_DefaultSetting->Draw(dc, wxPoint(0,0));
+   while(line)
+   {
+      // only draw if between top and bottom:
+      if((top == -1 || line->GetPosition().y >= top))
+         line->Draw(dc, offset);
+      // 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));
+}
 
-   if(! m_ColourFG) m_ColourFG = wxBLACK;
-   if(! m_ColourBG) m_ColourBG = wxWHITE;
-   
-   m_Position = wxPoint(0,0);
-   m_CursorPos = wxPoint(0,0);
-   m_CursorObject = iterator(NULL);
-   m_CursorOffset = 0;
-   m_CursorSize = wxPoint(2,(BASELINESTRETCH*m_FontPtSize)/10);
+wxLayoutObject *
+wxLayoutList::FindObject(wxPoint const pos)
+{
+   // First, find the right line:
+   wxLayoutLine *line = m_FirstLine;
+   wxPoint p;
    
-   m_MaxLine = 0;
-   m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10;
-   m_MaxX = 0; m_MaxY = 0;
-
-
-   m_FoundCursor = wxPoint(0,0);
-   m_FoundIterator = begin();
+   while(line)
+   {
+      p = line->GetPosition();
+      if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
+         break;
+      line = line->GetNextLine();
+   }
+   if(! line) return NULL; // not found
+   // Now, find the object in the line:
+   return line->FindObject(pos.x);
    
-   if(m_DefaultSetting)
-      delete m_DefaultSetting;
-
-   m_DefaultSetting = new
-      wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
-                        m_FontWeight,m_FontUnderline,
-                        m_ColourFG, m_ColourBG);
 }
 
-
-wxLayoutObjectBase *
-wxLayoutList::Find(wxPoint coords) const
+wxPoint
+wxLayoutList::GetSize(void) const
 {
-   wxLayoutObjectList::iterator i = begin();
+   wxLayoutLine
+      *line = m_FirstLine,
+      *last = line;
+   if(! line)
+      return wxPoint(0,0);
 
-   wxPoint topleft, bottomright;
+   wxPoint max(0,0);
    
-   while(i != end()) // == while valid
+   // find last line:
+   while(line)
    {
-      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++;
+      if(line->GetWidth() > max.x) max.x = line->GetWidth();
+      last = line;
+      line = line->GetNextLine();
    }
-   return NULL;
-}
-
 
-void
-wxLayoutList::SetWrapMargin(long n)
-{
-   m_WrapMargin = n;
+   max.y = last->GetPosition().y + last->GetHeight();
+   return max;
 }
 
 void
-wxLayoutList::WrapLine(void)
+wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
 {
-   wxASSERT(m_CursorObject);
+   wxPoint coords;
+   coords = m_CursorScreenPos;
+   coords.x += translate.x;
+   coords.y += translate.y;
 
-   iterator i = m_CursorObject;
-
-   if(!DoWordWrap() || !i ) // empty list
-      return;
-   int cursorpos = m_CursorPos.x, cpos, offset;
+#ifdef WXLAYOUT_DEBUG
+   WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
+               (long)m_CursorPos.x, (long)m_CursorPos.y,
+               (long)coords.x, (long)coords.y,
+               (long)m_CursorSize.x, (long)m_CursorSize.y,
+               (long)m_CursorLine->GetLineNumber(),
+               (long)m_CursorLine->GetLength()));
+#endif
    
-   if(cursorpos < m_WrapMargin)
-      return;
+   if(active)
+      dc.SetBrush(*wxBLACK_BRUSH);
+   dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+   dc.SetLogicalFunction(wxXOR);
+   dc.DrawRectangle(coords.x, coords.y, m_CursorSize.x, m_CursorSize.y);
+   dc.SetLogicalFunction(wxCOPY);
+   dc.SetBrush(wxNullBrush);
+}
 
-   // 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());
+   wxLayoutPrintout
 
-   // 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,
+wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist,
                                    wxString const & title)
 :wxPrintout(title)
 {
-   m_llist = &llist;
+   m_llist = llist;
    m_title = title;
 }
 
+float
+wxLayoutPrintout::ScaleDC(wxDC *dc)
+{
+   // The following bit is taken from the printing sample, let's see
+   // whether it works for us.
+   
+   /* You might use THIS code to set the printer DC to ROUGHLY reflect
+    * the screen text size. This page also draws lines of actual length 5cm
+    * on the page.
+    */
+  // Get the logical pixels per inch of screen and printer
+   int ppiScreenX, ppiScreenY;
+   GetPPIScreen(&ppiScreenX, &ppiScreenY);
+   int ppiPrinterX, ppiPrinterY;
+   GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
+
+   if(ppiScreenX == 0) // not yet set, need to guess
+   {
+      ppiScreenX = 100;
+      ppiScreenY = 100;
+   }
+   if(ppiPrinterX == 0) // not yet set, need to guess
+   {
+      ppiPrinterX = 72;
+      ppiPrinterY = 72;
+   }
+  
+  // This scales the DC so that the printout roughly represents the
+  // the screen scaling. The text point size _should_ be the right size
+  // but in fact is too small for some reason. This is a detail that will
+  // need to be addressed at some point but can be fudged for the
+  // moment.
+  float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
+
+  // Now we have to check in case our real page size is reduced
+  // (e.g. because we're drawing to a print preview memory DC)
+  int pageWidth, pageHeight;
+  int w, h;
+  dc->GetSize(&w, &h);
+  GetPageSizePixels(&pageWidth, &pageHeight);
+  if(pageWidth != 0) // doesn't work always
+  {
+     // If printer pageWidth == current DC width, then this doesn't
+     // change. But w might be the preview bitmap width, so scale down.
+     scale = scale * (float)(w/(float)pageWidth);
+  }
+  dc->SetUserScale(scale, scale);
+  return scale;
+}
+
 bool wxLayoutPrintout::OnPrintPage(int page)
 {
    wxDC *dc = GetDC();
+
+   ScaleDC(dc);
+   
    if (dc)
    {
-      DrawHeader(*dc,wxPoint(m_Margins.left,m_Margins.top/2),wxPoint(m_Margins.right,m_Margins.top),page);
       int top, bottom;
       top = (page - 1)*m_PrintoutHeight;
       bottom = top + m_PrintoutHeight;
       // SetDeviceOrigin() doesn't work here, so we need to manually
       // translate all coordinates.
-      wxPoint translate(m_Margins.left,-top+m_Margins.top);
-      m_llist->Draw(*dc,top,bottom,wxLayoutObjectList::iterator(NULL),translate);
+      wxPoint translate(m_Offset.x,m_Offset.y-top);
+      m_llist->Draw(*dc, translate, top, bottom);
       return true;
    }
    else
       return false;
 }
 
-bool wxLayoutPrintout::OnBeginDocument(int startPage, int endPage)
-{
-   if (!wxPrintout::OnBeginDocument(startPage, endPage))
-    return false;
-
-  return true;
-}
-
-void
-wxLayoutPrintout::OnPreparePrinting(void)
-{
-   
-}
-
-
 void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
 {
-   // ugly hack to get number of pages
+   /* We allocate a temporary wxDC for printing, so that we can
+      determine the correct paper size and scaling. We don't actually
+      print anything on it. */
 #ifdef __WXMSW__
    wxPrinterDC psdc("","",WXLLIST_TEMPFILE,false);
 #else
    wxPostScriptDC psdc(WXLLIST_TEMPFILE,false);
 #endif
-   psdc.GetSize(&m_PageWidth, &m_PageHeight); // that's all we need it for
 
-   // We do 5% margins on top and bottom, and a 5% high header line.
-   m_Margins.top = m_PageHeight / 10 ;      // 10%, half of it header
-   m_Margins.bottom = m_PageHeight - m_PageHeight / 20;   // 95%
-   // On the sides we reserve 10% each for the margins.
-   m_Margins.left = m_PageWidth / 10;
-   m_Margins.right = m_PageWidth - m_PageWidth / 10;
+   float scale = ScaleDC(&psdc);
 
-   // This is the length of the printable area.
-   m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15); 
-
-   //FIXME this is wrong but not used at the moment
-   m_PageWidth = m_Margins.right - m_Margins.left;
+   psdc.GetSize(&m_PageWidth, &m_PageHeight);
+   // This sets a left/top origin of 10% and 20%:
+   m_Offset = wxPoint(m_PageWidth/10, m_PageHeight/20);
 
+   // This is the length of the printable area.
+   m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.1);
+   m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
+   
+   
    m_NumOfPages = (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight) + 0.5);
+
+   // This is a crude hack to get it right for very small
+   // printouts. No idea why this is required, I thought +0.5 would do 
+   // the job. :-(
+   if(m_NumOfPages == 0 && m_llist->GetSize().y > 0)
+      m_NumOfPages = 1;
    *minPage = 1;
    *maxPage = m_NumOfPages;
 
@@ -1361,7 +1278,11 @@ bool wxLayoutPrintout::HasPage(int pageNum)
    return pageNum <= m_NumOfPages;
 }
 
-
+/*
+  Stupid wxWindows doesn't draw proper ellipses, so we comment this
+  out. It's a waste of paper anyway.
+*/
+#if 0
 void
 wxLayoutPrintout::DrawHeader(wxDC &dc,
                              wxPoint topleft, wxPoint bottomright,
@@ -1396,10 +1317,6 @@ wxLayoutPrintout::DrawHeader(wxDC &dc,
    dc.SetBrush(brush);
    dc.SetFont(font);
 }
+#endif
 
 
-wxLayoutPrintout *
-wxLayoutList::MakePrintout(wxString const &name)
-{
-   return new wxLayoutPrintout(*this,name);
-}
index c6a91246fc7fec9ae063739a03684a7eee5362e3..2ae0e081298fcc71a7b0182840551331a392d0fd 100644 (file)
@@ -1,7 +1,7 @@
 /*-*- c++ -*-********************************************************
  * wxLayoutList.h - a formatted text rendering engine for wxWindows *
  *                                                                  *
- * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
+ * (C) 1999 by Karsten Ballüder (Ballueder@usa.net)                 *
  *                                                                  *
  * $Id$
  *******************************************************************/
 #include   "wx/generic/prntdlgg.h"
 
 // skip the following defines if embedded in M application
-#ifdef   M_BASEDIR
-#   ifdef   DEBUG
-#      define   WXLAYOUT_DEBUG
-#   endif
-#else
-    // for testing only:
-#   define WXLAYOUT_DEBUG
-    // The wxLayout classes can be compiled with std::string instead of wxString
-    //#   define USE_STD_STRING
+#ifndef   M_BASEDIR
 #   define WXMENU_LAYOUT_LCLICK     1111
-#   define WXMENU_LAYOUT_RCLICK    1112
+#   define WXMENU_LAYOUT_RCLICK     1112
 #   define WXMENU_LAYOUT_DBLCLICK   1113
 #endif
 
-#ifdef USE_STD_STRING
-#   include   <string>
-    typedef   std::string String;
-#   define    Str(str)(str.c_str())
-#else
-    typedef   wxString String;
-#   define    Str(str) str
+#ifdef   __WXDEBUG__
+#   define   WXLAYOUT_DEBUG
 #endif
 
-#define   WXLO_DEFAULTFONTSIZE 12
+#ifndef WXLO_DEFAULTFONTSIZE
+#   define WXLO_DEFAULTFONTSIZE 12
+#endif
 
 /// Types of currently supported layout objects.
 enum wxLayoutObjectType
-{ WXLO_TYPE_INVALID = 0, WXLO_TYPE_TEXT, WXLO_TYPE_CMD, WXLO_TYPE_ICON, WXLO_TYPE_LINEBREAK };
+{
+   /// illegal object type, should never appear
+   WXLO_TYPE_INVALID = 0,
+   /// text object, containing normal text
+   WXLO_TYPE_TEXT,
+   /// command object, containing font or colour changes
+   WXLO_TYPE_CMD,
+   /// icon object, any kind of image
+   WXLO_TYPE_ICON
+};
 
-/// Type used for coordinates in drawing.
+/// Type used for coordinates in drawing. Must be signed.
 typedef long CoordType;
 
+// Forward declarations.
 class wxLayoutList;
-class wxLayoutObjectBase;
-
+class wxLayoutObject;
 class wxDC;
 class wxColour;
 class wxFont;
 
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   The wxLayout objects which make up the lines.
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+                                                                               
 /** The base class defining the interface to each object which can be
     part of the layout. Each object needs to draw itself and calculate 
     its size.
 */
-class wxLayoutObjectBase
+class wxLayoutObject
 {
 public:
+   /// This structure can be used to contain data associated with the object.
    struct UserData
    {
       virtual ~UserData() { }
    };
 
    /// return the type of this object
-   virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_INVALID; } ;
-   /** Calculates the position etc of an object.
+   virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_INVALID; }
+   /** Calculates the size of an object.
        @param dc the wxDC to draw on
-       @param position where to draw the top left corner
-       @param baseLine the baseline for alignment, from top of box
    */
-   virtual void Layout(wxDC & dc,
-                       wxPoint position,
-                       CoordType baseLine)
-      { m_Position = position; }
+   virtual void Layout(wxDC &) = 0;
 
    /** Draws an object.
        @param dc the wxDC to draw on
-       @param translation to be added to coordinates
+       @param coords where to draw the baseline of the object.
    */
-   virtual void Draw(wxDC & dc, wxPoint const &translate) {}
+   virtual void Draw(wxDC & /* dc */, wxPoint const & /* coords */)  { }
 
    /** Calculates and returns the size of the object. 
-       @param baseLine pointer where to store the baseline position of 
-       this object (i.e. the height from the top of the box to the
-       baseline)
+       @param top where to store height above baseline
+       @param bottom where to store height below baseline
        @return the size of the object's box in pixels
    */
-   virtual wxPoint GetSize(CoordType * baseLine = NULL) const
-      { return wxPoint(0,0); }
-
-   /** Calculates and returns the position of the object.
-       @return the size of the object's box in pixels
-   */
-   virtual wxPoint GetPosition(void) const { return m_Position; }
+   virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const
+      { *top = 0; *bottom = 0; return wxPoint(0,0); }
 
+   /// Return just the width of the object on the screen.
+   virtual CoordType GetWidth(void) const { return 0; }
    /// returns the number of cursor positions occupied by this object
-   virtual CoordType CountPositions(void) const { return 1; }
+   virtual CoordType GetLength(void) const { return 1; }
 
    /// constructor
-   wxLayoutObjectBase() { m_UserData = NULL; }
+   wxLayoutObject() { m_UserData = NULL; }
    /// delete the user data
-   virtual ~wxLayoutObjectBase() { if(m_UserData) delete m_UserData; }
+   virtual ~wxLayoutObject() { if(m_UserData) delete m_UserData; }
 
 #ifdef WXLAYOUT_DEBUG
    virtual void Debug(void);
 #endif
 
-   /// query whether coordinates have changed since last drawing
-   virtual bool IsDirty(void) const { return true; }  
-   
    /** Tells the object about some user data. This data is associated
        with the object and will be deleted at destruction time.
    */
@@ -131,96 +125,124 @@ public:
 private:
    /// optional data for application's use
    UserData *m_UserData;
-protected:
-   wxPoint m_Position;
 };
 
-/// Define a list type of wxLayoutObjectBase pointers.
-KBLIST_DEFINE(wxLayoutObjectList, wxLayoutObjectBase);
+/// Define a list type of wxLayoutObject pointers.
+KBLIST_DEFINE(wxLayoutObjectList, wxLayoutObject);
 
+/// An illegal iterator to save typing.
+#define NULLIT (wxLayoutObjectList::iterator(NULL))
+/// The iterator type.
+#define wxLOiterator   wxLayoutObjectList::iterator
 
-/// object for text block
-class wxLayoutObjectText : public wxLayoutObjectBase
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectText
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxLayoutObject holding plain text.
+ */
+class wxLayoutObjectText : public wxLayoutObject
 {
 public:
-   wxLayoutObjectText(const String &txt);
+   wxLayoutObjectText(const wxString &txt);
 
    virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_TEXT; }
-   virtual void Layout(wxDC &dc, wxPoint position, CoordType
-                       baseLine);
-   
-   virtual void Draw(wxDC &dc, wxPoint const &translate);
-   /** This returns the height and in baseLine the position of the
-       text's baseline within it's box. This is needed to properly
-       align text objects.
+   virtual void Layout(wxDC &dc);
+   virtual void Draw(wxDC &dc, wxPoint const &coords);
+   /** Calculates and returns the size of the object. 
+       @param top where to store height above baseline
+       @param bottom where to store height below baseline
+       @return the size of the object's box in pixels
    */
-   virtual wxPoint GetSize(CoordType *baseLine = NULL) const;
+   virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const;
+   /// Return just the width of the object on the screen.
+   virtual CoordType GetWidth(void) const { return m_Width; }
 
 #ifdef WXLAYOUT_DEBUG
    virtual void Debug(void);
 #endif
 
-   virtual CoordType CountPositions(void) const { return strlen(m_Text.c_str()); }
-   virtual bool IsDirty(void) const { return m_IsDirty; }  
+   virtual CoordType GetLength(void) const { return strlen(m_Text.c_str()); }
 
    // for editing:
-   String & GetText(void) { return m_Text; }
-   void SetText(String const &text) { m_Text = text; }
+   wxString & GetText(void) { return m_Text; }
+   void SetText(wxString const &text) { m_Text = text; }
 
 private:
-   String m_Text;
+   wxString m_Text;
    /// size of the box containing text
    long   m_Width, m_Height;
-   /// the position of the baseline counted from the top of the box
-   long   m_BaseLine;
-   /// coordinates have changed
-   bool m_IsDirty;
+   /// Height above baseline.
+   long   m_Top;
+   /// Height below baseline.
+   long   m_Bottom;
 };
 
-/// icon/pictures:
-class wxLayoutObjectIcon : public wxLayoutObjectBase
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectIcon
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxLayoutObject holding a graphic.
+ */
+class wxLayoutObjectIcon : public wxLayoutObject
 {
 public:
-   wxLayoutObjectIcon(wxIcon *icon);
-   wxLayoutObjectIcon(wxIcon const &icon);
+   wxLayoutObjectIcon(wxBitmap *icon);
+   wxLayoutObjectIcon(wxBitmap const &icon);
 
    ~wxLayoutObjectIcon() { delete m_Icon; }
 
    virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_ICON; }
-   virtual void Layout(wxDC &dc, wxPoint position, CoordType baseLine);
-   virtual void Draw(wxDC &dc, wxPoint const &translate);
+   virtual void Layout(wxDC &dc);
+   virtual void Draw(wxDC &dc, wxPoint const &coords);
 
-   virtual wxPoint GetSize(CoordType *baseLine = NULL) const;
-   virtual bool IsDirty(void) const { return m_IsDirty; }  
+   /** Calculates and returns the size of the object. 
+       @param top where to store height above baseline
+       @param bottom where to store height below baseline
+       @return the size of the object's box in pixels
+   */
+   virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const;
+   /// Return just the width of the object on the screen.
+   virtual CoordType GetWidth(void) const { return m_Icon->GetWidth(); }
 
 private:
-   wxIcon *m_Icon;
-   /// coordinates have changed
-   bool m_IsDirty;
+   wxBitmap *m_Icon;
 };
 
 /// for export to html:
 struct wxLayoutStyleInfo
 {
+   wxLayoutStyleInfo()
+      {
+         family = -1; // this marks the styleinfo as uninitialised
+      }
    int  size, family, style, weight;
    bool underline;
    unsigned fg_red, fg_green, fg_blue;
    unsigned bg_red, bg_green, bg_blue;
 };
 
-/// pseudo-object executing a formatting command in Draw()
-class wxLayoutObjectCmd : public wxLayoutObjectBase
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+
+   wxLayoutObjectCmd
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxLayoutObject holding style change commands.
+ */
+class wxLayoutObjectCmd : public wxLayoutObject
 {
 public:
    virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_CMD; }
-   virtual void Draw(wxDC &dc, wxPoint const &translate);
-   virtual void Layout(wxDC &dc, wxPoint position, CoordType baseLine);
+   virtual void Layout(wxDC &dc);
+   virtual void Draw(wxDC &dc, wxPoint const &coords);
    wxLayoutObjectCmd(int size, int family, int style, int weight,
                 bool underline,
                 wxColour const *fg, wxColour const *bg);
    ~wxLayoutObjectCmd();
-   /// caller must free pointer:
-   wxLayoutStyleInfo *GetStyle(void) const ;
+   /** Stores the current style in the styleinfo structure */
+   void GetStyle(wxLayoutStyleInfo *si) const;
    /// return the background colour for setting colour of window
    wxColour const *GetBGColour(void) const { return m_ColourBG; }
 private:
@@ -232,47 +254,334 @@ private:
    wxColour const *m_ColourBG;
 };
 
-/// this object doesn't do anything at all
-class wxLayoutObjectLineBreak : public wxLayoutObjectBase
-{
-public:
-   virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_LINEBREAK; }
-};
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 
+   The wxLayoutLine object
 
-class wxLayoutPrintout;
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-class wxLayoutMargins
+/** This class represents a single line of objects to be displayed.
+    It knows its height and total size and whether it needs to be
+    redrawn or not.
+    It has pointers to its first and next line so it can automatically 
+    update them as needed.
+*/
+class wxLayoutLine
 {
 public:
-   wxLayoutMargins() { top = left = 0; bottom = right = -1; }
-   int top;
-   int left;
-   int bottom;
-   int right;
+   /** Constructor.
+       @param prev pointer to previous line or NULL
+       @param next pointer to following line or NULL
+   */
+   wxLayoutLine(wxLayoutLine *prev);
+   /** This function inserts a new object at cursor position xpos.
+       @param xpos where to insert new object
+       @param obj  the object to insert
+       @return true if that xpos existed and the object was inserted
+   */
+   bool Insert(CoordType xpos, wxLayoutObject *obj);
+   
+   /** This function inserts text at cursor position xpos.
+       @param xpos where to insert
+       @param text  the text to insert
+       @return true if that xpos existed and the object was inserted
+   */
+   bool Insert(CoordType xpos, wxString text);
+
+   /** This function appends an object to the line.
+       @param obj  the object to insert
+   */
+   void Append(wxLayoutObject * obj)
+      {
+         wxASSERT(obj);
+         m_ObjectList.push_back(obj);
+         m_Length += obj->GetLength();
+      }
+
+   /** This function appens the next line to this, i.e. joins the two
+       lines into one.
+   */
+   void MergeNextLine(void);
+
+   /** This function deletes npos cursor positions from position xpos.
+       @param xpos where to delete
+       @param npos how many positions
+       @return number of positions still to be deleted
+   */
+   CoordType Delete(CoordType xpos, CoordType npos);
+
+   /** This function breaks the line at a given cursor position.
+       @param xpos where to break it
+       @return pointer to the new line object replacing the old one
+   */
+   wxLayoutLine *Break(CoordType xpos);
+
+   /** Deletes the next word from this position, including leading
+       whitespace.
+       This function does not delete over font changes, i.e. a word
+       with formatting instructions in the middle of it is treated as
+       two (three actually!) words. In fact, if the cursor is on a non-text object, that 
+       one is treated as a word.
+       @param xpos from where to delete
+       @return true if a word was deleted
+   */
+   bool DeleteWord(CoordType npos);
+   
+   /** Finds the object which covers the cursor position xpos in this
+       line.
+       @param xpos the column number
+       @param offset where to store the difference between xpos and
+       the object's head
+       @return iterator to the object or NULLIT
+   */
+   wxLayoutObjectList::iterator FindObject(CoordType xpos, CoordType
+                                           *offset) const ;
+
+   /** Get the first object in the list. This is used by the wxlparser 
+       functions to export the list.
+       @return iterator to the first object
+   */
+   wxLayoutObjectList::iterator GetFirstObject(void)
+      {
+         return m_ObjectList.begin();
+      }
+       
+   /** Deletes this line, returns pointer to next line.
+       @param update If true, update all following lines.
+   */
+   wxLayoutLine *DeleteLine(bool update);
+
+   /**@name Cursor Management */
+   //@{
+   /** Return the line number of this line.
+       @return the line number
+   */
+   CoordType GetLineNumber(void) const { return m_LineNumber; }
+   /** Return the length of the line.
+       @return line lenght in cursor positions
+   */
+   CoordType GetLength(void) const { return m_Length; }
+   //@}
+
+   /**@name Drawing and Layout */
+   //@{
+   /** Draws the line on a wxDC.
+       @param dc the wxDC to draw on
+       @param offset an optional offset to shift printout
+   */
+   void Draw(wxDC &dc, const wxPoint &offset = wxPoint(0,0)) const;
+   
+   /** Recalculates the positions of objects and the height of the
+       line.
+       @param dc the wxDC to draw on
+       @param cursorPos if not NULL, set cursor screen position in there
+       @param cursorSize if not cursorPos != NULL, set cursor size in there
+       @param cx if cursorPos != NULL, the cursor x position
+   */
+   void Layout(wxDC &dc,
+               wxPoint *cursorPos = NULL,
+               wxPoint *cursorSize = NULL,
+               int cx = 0);
+   /** This function finds an object belonging to a given cursor
+       position. It assumes that Layout() has been called before.
+       @param xpos screen x position
+       @return pointer to the object
+   */
+   wxLayoutObject * FindObject(CoordType xpos);
+   //@}
+
+   /**@name List traversal */
+   //@{
+   /// Returns pointer to next line.
+   wxLayoutLine *GetNextLine(void) const { return m_Next; }
+   /// Returns pointer to previous line.
+   wxLayoutLine *GetPreviousLine(void) const { return m_Previous; }
+   /// Sets the link to the next line.
+   void SetNext(wxLayoutLine *next)
+      { m_Next = next; if(next) next->m_Previous = this; }
+   /// Sets the link to the previous line.
+   void SetPrevious(wxLayoutLine *previous)
+      { m_Previous = previous; if(previous) previous->m_Next = this; }
+   //@}
+
+   /// Returns the position of this line on the canvas.
+   wxPoint GetPosition(void) const { return m_Position; }
+   /// Returns the height of this line.
+   CoordType GetHeight(void) const { return m_Height; }
+   /// Returns the width of this line.
+   CoordType GetWidth(void) const { return m_Width; }
+   /** This will recalculate the position and size of this line.
+       If called recursively it will abort if the position of an
+       object is unchanged, assuming that none of the following
+       objects need to move.
+       @param recurse if greater 0 then it will be used as the
+       minimum(!) recursion level, continue with all lines till the end of
+       the list or until the coordinates no longer changed.
+   */
+   void RecalculatePositions(int recurse = 0);
+private:
+   /// Destructor is private. Use DeleteLine() to remove it.
+   ~wxLayoutLine();
+
+   /**@name Functions to let the lines synchronise with each other. */
+   //@{
+   /** Sets the height of this line. Will mark following lines as
+       dirty.
+       @param height new height
+   */
+   void SetHeight(CoordType height)
+      { m_Height = height; RecalculatePositions(true); }
+   /// Recalculates the position of this line on the canvas.
+   wxPoint RecalculatePosition(void);
+
+   /** Moves the linenumbers one on, because a line has been inserted
+       or deleted.
+       @param delta either +1 or -1
+    */
+   void MoveLines(int delta)
+      {
+         m_LineNumber += delta;
+         if(m_Next) m_Next->MoveLines(delta);
+      }
+   //@}
+private:
+   /// The line number.
+   CoordType m_LineNumber;
+   /// The line length in cursor positions.
+   CoordType m_Length;
+   /// The total height of the line.
+   CoordType m_Height;
+   /// The total width of the line on screen.
+   CoordType m_Width;
+   /// The baseline for drawing objects
+   CoordType m_BaseLine;
+   /// The position on the canvas.
+   wxPoint   m_Position;
+   /// The list of objects
+   wxLayoutObjectList m_ObjectList;
+   /// Have we been changed since the last layout?
+   bool m_Dirty;
+   /// Pointer to previous line if it exists.
+   wxLayoutLine *m_Previous;
+   /// Pointer to next line if it exists.
+   wxLayoutLine *m_Next;
+   /// Just to suppress gcc compiler warnings.
+   friend class dummy;
 };
 
-/**
-   This class provides a high level abstraction to the wxFText
-   classes.
-   It handles most of the character events with its own callback
-   functions, providing an editing ability. All events which cannot be
-   handled get passed to the parent window's handlers.
-*/
-class wxLayoutList : public wxLayoutObjectList
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+   
+   The wxLayoutList object
+   
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** The wxLayoutList is a list of wxLayoutLine objects. It provides a
+    higher level of abstraction for the text and can generally be considered 
+    as representing "the text". 
+ */
+class wxLayoutList
 {
 public:
+   /// Constructor.
    wxLayoutList();
-   
    /// Destructor.
    ~wxLayoutList();
 
-   /// adds an object:
-   void AddObject(wxLayoutObjectBase *obj);
-   /// adds a text object
-   void AddText(String const &txt);
-   /// adds a line break
-   void LineBreak(void);
+   /// Clear the list.
+   void Clear(int family = wxROMAN,
+              int size=WXLO_DEFAULTFONTSIZE,
+              int style=wxNORMAL,
+              int weight=wxNORMAL,
+              int underline=0,
+              char const *fg="black",
+              char const *bg="white");
+
+   /**@name Cursor Management */
+   //@{
+   /** Set new cursor position.
+       @param p new position
+       @return bool if it could be set
+   */
+   bool MoveCursorTo(wxPoint const &p);
+   /** Move cursor up or down.
+       @param n
+       @return bool if it could be moved
+   */
+   bool MoveCursorVertically(int n);
+   /** Move cursor left or right.
+       @param n
+       @return bool if it could be moved
+   */
+   bool MoveCursorHorizontally(int n);
+
+   /// Move cursor to end of line.
+   void MoveCursorToEndOfLine(void)
+      {
+         wxASSERT(m_CursorLine);
+         MoveCursorHorizontally(m_CursorLine->GetLength()-m_CursorPos.x); 
+      }
+   
+   /// Move cursor to begin of line.
+   void MoveCursorToBeginOfLine(void)
+      { MoveCursorHorizontally(-m_CursorPos.x); }
+
+   /// Returns current cursor position.
+   wxPoint GetCursorPos(void) const { return m_CursorPos; }
+   //@}
+
+   /**@name Editing functions.
+    All of these functions return true on success and false on
+    failure. */
+   //@{
+   /// Insert text at current cursor position.
+   bool Insert(wxString const &text);
+   /// Insert some other object at current cursor position.
+   bool Insert(wxLayoutObject *obj);
+   /// Inserts a linebreak at current cursor position.
+   bool LineBreak(void);
+   /** This function deletes npos cursor positions.
+       @param npos how many positions
+       @return true if everything got deleted
+   */
+   bool Delete(CoordType npos);
+
+   /** Delete the next n lines.
+       @param n how many lines to delete
+       @return how many it could not delete
+   */
+   int DeleteLines(int n);
+   
+   /// Delete to end of line.
+   void DeleteToEndOfLine(void)
+      {
+         wxASSERT(m_CursorLine);
+         Delete(m_CursorLine->GetLength()-m_CursorPos.x);
+      }
+   /// Delete to begin of line.
+   void DeleteToBeginOfLine(void)
+      {
+         wxASSERT(m_CursorLine);
+         CoordType n = m_CursorPos.x;
+#ifdef WXLAYOUT_DEBUG
+         wxASSERT(MoveCursorHorizontally(-n));
+#else
+         MoveCursorHorizontally(-n);
+#endif
+         Delete(n);
+      }
+
+   /** Delete the next word.
+   */
+   void DeleteWord(void)
+      {
+         wxASSERT(m_CursorLine);
+         m_CursorLine->DeleteWord(m_CursorPos.x);
+      }
+
+   //@}
+
+   /**@name Formatting options */
+   //@{
    /// sets font parameters
    void SetFont(int family, int size, int style,
                 int weight, int underline,
@@ -302,107 +611,93 @@ public:
    inline void SetFontUnderline(bool ul) { SetFont(-1,-1,-1,-1,(int)ul); }
    /// set font colours by name
    inline void SetFontColour(char const *fg, char const *bg = NULL) { SetFont(-1,-1,-1,-1,-1,fg,bg); }
-      
-   /** Sets the wrap margin in cursor positions.
-       @param n the wrap margin, -1 to disable auto wrap
+   /**
+      Returns a pointer to the default settings.
+      This is only valid temporarily and should not be stored
+      anywhere.
+      @return the default settings of the list
    */
-   void SetWrapMargin(long n = -1);
+   wxLayoutObjectCmd const *GetDefaults(void) const { return m_DefaultSetting ; }
+   //@}
 
-   /// Wraps the current line if word wrap is enabled.
-   void WrapLine(void);
-   
-   /** Re-layouts the list on a DC.
-       @param dc the dc to layout for
-       @param margins if not NULL, use these top and left margins
-   */
-   void Layout(wxDC &dc, wxLayoutMargins *margins = NULL);
-                            
-  /** Draw the list on a given DC.
-      @param dc the dc to layout for
-      @param fromLine the first graphics line from where to draw
-      @param toLine the last line at which to draw
-      @param start if != iterator(NULL) start drawing from here
-   */
-   void Draw(wxDC &dc,
-             CoordType fromLine = -1,
-             CoordType toLine = -1,
-             iterator start = iterator(NULL),
-             wxPoint const &translate = wxPoint(0,0));
-
-   /** Deletes at least to the end of line and redraws */
-   void EraseAndDraw(wxDC &dc, iterator start = iterator(NULL),
-                     wxPoint const &translate = wxPoint(0,0));
-   
-   /** Finds the object occupying a certain screen position.
-       @return pointer to wxLayoutObjectBase or NULL if not found
+   /**@name Drawing */
+   //@{
+   /** Draws the complete list on a wxDC.
+       @param dc the wxDC to draw on
+       @param offset an optional offset to shift printout
+       @param top optional y coordinate where to start drawing
+       @param bottom optional y coordinate where to stop drawing
    */
-   wxLayoutObjectBase *Find(wxPoint coords) const;
-   
-#ifdef WXLAYOUT_DEBUG
-   void Debug(void);
-   void ShowCurrentObject();
-#endif
+   void Draw(wxDC &dc, const wxPoint &offset = wxPoint(0,0),
+             CoordType top = -1, CoordType bottom = -1) const;
 
-   /// dirty?
-   bool IsDirty() const { return m_bModified; }
-   bool CursorMoved(void) const { return m_CursorMoved; }  
+   /** Calculates new layout for the list, like Draw() but does not
+       actually draw it.
+       @param dc the wxDC to draw on
+       @param bottom optional y coordinate where to stop calculating
+   */
+   void Layout(wxDC &dc, CoordType bottom = -1) const;
+   /** Returns the size of the list in screen coordinates.
+       The return value only makes sense after the list has been
+       drawn.
+       @return a wxPoint holding the maximal x/y coordinates used for
+       drawing
+   */
+   wxPoint GetSize(void) const;
 
-   /// called after the contents is saved, for example
-   void ResetDirty() { m_bModified = FALSE; }
+   /** Returns the cursor position on the screen.
+       @return cursor position in pixels
+   */
+   wxPoint GetCursorScreenPos(void) const
+      { return m_CursorScreenPos; }
+   
+   /** Draws the cursor.
+       @param active If true, draw a bold cursor to mark window as
+       active.
+       @param translate optional translation of cursor coords on screen
+   */
+   void DrawCursor(wxDC &dc,
+                   bool active = true,
+                   const wxPoint & translate = wxPoint(0,0));
+
+   /** This function finds an object belonging to a given cursor
+       position. It assumes that Layout() has been called before.
+       @param pos screen position
+       @return pointer to the object
+   */
+   wxLayoutObject * FindObject(wxPoint const pos);
 
-   /// for access by wxLayoutWindow:
-   void GetSize(CoordType *max_x, CoordType *max_y,
-                CoordType *lineHeight);
+   //@}
 
-   
-   /**@name Functionality for editing */
+   /**@name For exporting one object after another. */
    //@{
-   /// set list editable or read only
-   void SetEditable(bool editable = true) { m_Editable = editable; }
-   /// return true if list is editable
-   bool IsEditable(void) const { return m_Editable; }
-   /// move cursor, returns true if it could move to the desired position
-   bool MoveCursor(int dx = 0, int dy = 0);
-   void SetCursor(wxPoint const &p);
-   void DrawCursor(wxDC &dc, bool erase = false,wxPoint const &translate = wxPoint(0,0));
-   /// Get current cursor position cursor coords
-   wxPoint GetCursor(void) const { return m_CursorPos; }
-   /// Gets graphical coordinates of cursor
-   wxPoint GetCursorCoords(void) const { return m_CursorCoords; }
+   /** Returns a pointer to the first line in the list. */
+   wxLayoutLine *GetFirstLine(void)
+      {
+         wxASSERT(m_FirstLine);
+         return m_FirstLine;
+      }
+   //@}
+private:
+   /// Clear the list.
+   void InternalClear(void);
    
-   /// delete one or more cursor positions
-   void Delete(CoordType count = 1);
-   void Insert(String const &text);
-   void Insert(wxLayoutObjectBase *obj);
-   void Clear(int family = wxROMAN, int size=WXLO_DEFAULTFONTSIZE, int style=wxNORMAL, int weight=wxNORMAL,
-                    int underline=0, char const *fg="black", char const *bg="white");
-
-   /// return a pointer to the default settings (dangerous, why?) FIXME:
-   wxLayoutObjectCmd const *GetDefaults(void) const { return m_DefaultSetting ; }
+   /// The list of lines.
+   wxLayoutLine *m_FirstLine;
+   /**@name Cursor Management */
+   //@{
+   /// Where the text cursor (column,line) is.
+   wxPoint   m_CursorPos;
+   /// The size of the cursor.
+   wxPoint   m_CursorSize;
+   /// Where the cursor should be drawn.
+   wxPoint   m_CursorScreenPos;
+   /// The line where the cursor is.
+   wxLayoutLine *m_CursorLine;
+   //@}   
 
-   /// returns the iterator for the object under the cursor
-   wxLayoutObjectList::iterator GetCurrentObject(CoordType *offset =
-                                                 NULL)
-   { if(offset) *offset = m_CursorOffset; return m_CursorObject; }
-   
-   // get the length of the line with the object pointed to by i, offs 
-   // only used to decide whether we are before or after linebreak
-   CoordType GetLineLength(wxLayoutObjectList::iterator i,
-                           CoordType offs = 0);
-   wxLayoutPrintout *MakePrintout(wxString const &name);
-
-   /// Return maximum X,Y coordinates
-   wxPoint GetSize(void) const { return wxPoint(m_MaxX, m_MaxY); }
-
-   /// calculates current cursor coordinates, called in Layout()
-   void CalculateCursor(wxDC &dc);
-
-   /// toggle normal/bold cursor
-   void SetBoldCursor(bool bold = true)
-      { m_boldCursor = bold; m_CursorMoved = true;}
-//@}
-protected:
-   /// font parameters:
+   /** @name Font parameters. */
+   //@{
    int m_FontFamily, m_FontStyle, m_FontWeight;
    int m_FontPtSize;
    bool m_FontUnderline;
@@ -411,86 +706,76 @@ protected:
    wxColour const * m_ColourBG;
    /// the default setting:
    wxLayoutObjectCmd *m_DefaultSetting;
-   
-   /// needs recalculation?
-   bool m_dirty;
-   /// cursor moved
-   bool m_CursorMoved;
+   //@}
+};
 
-   /// needs saving (i.e., was modified?)
-   bool m_bModified;
 
-   // the currently updated line:
-   /// where do we draw next:
-   wxPoint   m_Position;
-   /// the height of the current line:
-   CoordType m_LineHeight;
-   /// maximum drawn x position so far
-   CoordType m_MaxX;
-   /// maximum drawn y position:
-   CoordType m_MaxY;
-
-   //---- this is needed for editing:
-   /// where is the text cursor (column,line):
-   wxPoint   m_CursorPos;
-   /// where to draw the cursor
-   wxPoint   m_CursorCoords;
-   /// how large to draw it
-   wxPoint   m_CursorSize;
-   /// object iterator for current cursor position:
-   iterator  m_CursorObject;
-   /// position of cursor within m_CursorObject:
-   CoordType m_CursorOffset;
-   
-   /// to store content overwritten by cursor
-   wxMemoryDC m_CursorMemDC;
-
-   /// which is the last line
-   CoordType m_MaxLine;
-   /// can we edit it?
-   bool      m_Editable;
-   /// find the object to the cursor position and returns the offset
-   /// in there
-   wxLayoutObjectList::iterator FindObjectCursor(wxPoint *cpos, CoordType *offset = NULL);
-   /// get the wrap margin
-   inline long GetWrapMargin(void) const { return m_WrapMargin; }
-   /// do we do wrapping?
-   inline bool DoWordWrap(void) const { return m_WrapMargin != -1; }
-private:
-   /// Resets the font settings etc to default values
-   void ResetSettings(wxDC &dc);
-   /// remembers the last cursor position for which FindObjectCursor was called
-   wxPoint m_FoundCursor;
-   /// remembers the iterator to the object related to m_FoundCursor
-   wxLayoutObjectList::iterator m_FoundIterator;
-   /// the wrap margin
-   long m_WrapMargin;
-   /// draw a bold cursor?
-   bool m_boldCursor;
-};
 
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+   
+   The wxLayoutPrintout object for printing within the wxWindows print
+   framework.
+   
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxPrintout for printing a wxLayoutList within
+    the wxWindows printing framework.
+ */
 class wxLayoutPrintout: public wxPrintout
 {
- public:
-   wxLayoutPrintout(wxLayoutList &llist, wxString const & title =
+public:
+   /** Constructor.
+       @param llist pointer to the wxLayoutList to be printed
+       @param title title for PS file or windows
+   */
+   wxLayoutPrintout(wxLayoutList *llist,
+                    wxString const & title =
                     "wxLayout Printout");
+   /** Function which prints the n-th page.
+       @param page the page number to print
+       @return bool true if we are not at end of document yet
+   */
    bool OnPrintPage(int page);
+   /** Checks whether page exists in document.
+       @param page number of page
+       @return true if page exists
+   */
    bool HasPage(int page);
-   bool OnBeginDocument(int startPage, int endPage);
-   void GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int
-                    *selPageTo);
-   void OnPreparePrinting(void);
+
+   /** Gets called from wxWindows to find out which pages are existing.
+       I'm not totally sure about the parameters though.
+       @param minPage the first page in the document
+       @param maxPage the last page in the document
+       @param selPageFrom the first page to be printed
+       @param selPageTo the last page to be printed
+   */
+   void GetPageInfo(int *minPage, int *maxPage,
+                    int *selPageFrom, int *selPageTo);
 protected:
-   virtual void DrawHeader(wxDC &dc, wxPoint topleft, wxPoint bottomright, int pageno);
-                           
+   /** This little function scales the DC so that the printout has
+       roughly the same size as the output on screen.
+       @param dc the wxDC to scale
+       @return the scale that was applied
+   */
+   float ScaleDC(wxDC *dc);
+
+   /* no longer used
+     virtual void DrawHeader(wxDC &dc, wxPoint topleft, wxPoint bottomright, int pageno);
+   */                      
 private:
+   /// The list to print.
    wxLayoutList *m_llist;
+   /// Title for PS file or window.
    wxString      m_title;
+   /// The real paper size.
    int           m_PageHeight, m_PageWidth;
-   // how much we actually print per page
+   /// How much we actually print per page.
    int           m_PrintoutHeight;
-   wxLayoutMargins m_Margins;
+   /// How many pages we need to print.
    int           m_NumOfPages;
+   /// Top left corner where we start printing.
+   wxPoint       m_Offset;
 };
 
+
 #endif // WXLLIST_H
index db83335f3af325ac350e11f57ed942ac1800801c..6ebe3a5ce39cb24faa4333a2d829ee7c880d73cd 100644 (file)
@@ -32,7 +32,7 @@ inline static bool IsEndOfLine(const char *p, int mode)
       (((*p == '\r') && (*(p + 1) == '\n'))||(*p == '\n'));
 }
 
-void wxLayoutImportText(wxLayoutList &list, String const &str, int withflag)
+void wxLayoutImportText(wxLayoutList &list, wxString const &str, int withflag)
 {
    char * cptr = (char *)str.c_str(); // string gets changed only temporarily
    const char * begin = cptr;
@@ -63,32 +63,29 @@ void wxLayoutImportText(wxLayoutList &list, String const &str, int withflag)
 }
 
 static
-String wxLayoutExportCmdAsHTML(wxLayoutObjectCmd const & cmd,
-                               wxLayoutStyleInfo **lastStylePtr)
+wxString wxLayoutExportCmdAsHTML(wxLayoutObjectCmd const & cmd,
+                                 wxLayoutStyleInfo *styleInfo)
 {
    static char buffer[20];
-   String html;
+   wxString html;
    
-   wxLayoutStyleInfo *si = cmd.GetStyle();
-   wxLayoutStyleInfo *last_si = NULL;
+   wxLayoutStyleInfo si;
+   cmd.GetStyle(&si);
 
    int size, sizecount;
    
-   if(lastStylePtr != NULL)
-      last_si = *lastStylePtr;
-   
    html += "<font ";
 
    html +="color=";
-   sprintf(buffer,"\"#%02X%02X%02X\"", si->fg_red,si->fg_green,si->fg_blue);
+   sprintf(buffer,"\"#%02X%02X%02X\"", si.fg_red,si.fg_green,si.fg_blue);
    html += buffer;
 
 
    html += " bgcolor=";
-   sprintf(buffer,"\"#%02X%02X%02X\"", si->bg_red,si->bg_green,si->bg_blue);
+   sprintf(buffer,"\"#%02X%02X%02X\"", si.bg_red,si.bg_green,si.bg_blue);
    html += buffer;
 
-   switch(si->family)
+   switch(si.family)
    {
    case wxSWISS:
    case wxMODERN:
@@ -102,12 +99,12 @@ String wxLayoutExportCmdAsHTML(wxLayoutObjectCmd const & cmd,
    }
 
    size = BASE_SIZE; sizecount = 0;
-   while(size < si->size && sizecount < 5)
+   while(size < si.size && sizecount < 5)
    {
       sizecount ++;
       size = (size*12)/10;
    }
-   while(size > si->size && sizecount > -5)
+   while(size > si.size && sizecount > -5)
    {
       sizecount --;
       size = (size*10)/12;
@@ -118,97 +115,124 @@ String wxLayoutExportCmdAsHTML(wxLayoutObjectCmd const & cmd,
 
    html +=">";
 
-   if(last_si != NULL)
+   if(styleInfo != NULL)
       html ="</font>"+html; // terminate any previous font command
 
-   if((si->weight == wxBOLD) && ( (!last_si) || (last_si->weight != wxBOLD)))
+   if((si.weight == wxBOLD) && ( (!styleInfo) || (styleInfo->weight != wxBOLD)))
       html += "<b>";
    else
-      if(si->weight != wxBOLD && ( last_si && (last_si->weight == wxBOLD)))
+      if(si.weight != wxBOLD && ( styleInfo && (styleInfo->weight == wxBOLD)))
          html += "</b>";
 
-   if(si->style == wxSLANT)
-      si->style = wxITALIC; // the same for html
+   if(si.style == wxSLANT)
+      si.style = wxITALIC; // the same for html
    
-   if((si->style == wxITALIC) && ( (!last_si) || (last_si->style != wxITALIC)))
+   if((si.style == wxITALIC) && ( (!styleInfo) || (styleInfo->style != wxITALIC)))
       html += "<i>";
    else
-      if(si->style != wxITALIC && ( last_si && (last_si->style == wxITALIC)))
+      if(si.style != wxITALIC && ( styleInfo && (styleInfo->style == wxITALIC)))
          html += "</i>";
 
-   if(si->underline && ( (!last_si) || ! last_si->underline))
+   if(si.underline && ( (!styleInfo) || ! styleInfo->underline))
       html += "<u>";
-   else if(si->underline == false && ( last_si && last_si->underline))
+   else if(si.underline == false && ( styleInfo && styleInfo->underline))
       html += "</u>";
+
+   
+   *styleInfo = si; // update last style info
    
-   if(last_si)
-      delete last_si;
-   *lastStylePtr = si;
    return html;
 }
 
 
 
 #define   WXLO_IS_TEXT(type) \
-( (type == WXLO_TYPE_TEXT || type == WXLO_TYPE_LINEBREAK) \
+( type == WXLO_TYPE_TEXT \
   || (type == WXLO_TYPE_CMD \
       && (mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML))
 
 
   
-wxLayoutExportObject *wxLayoutExport(wxLayoutList &list,
-                                     wxLayoutList::iterator &from,
+wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
                                      int mode)
 {
-   if(from == list.end())
-      return NULL;
-   
-   wxLayoutObjectType   type = (*from)->GetType();
-   wxLayoutExportObject     * export = new wxLayoutExportObject();
+   wxASSERT(status);
+   wxLayoutExportObject * export;
 
-   static wxLayoutStyleInfo *s_si = NULL;
+   if(status->m_iterator == NULLIT) // end of line
+   {
+      if(!status->m_line || status->m_line->GetNextLine() == NULL) // reached end of list
+         return NULL;
+      else
+      {
+         status->m_line = status->m_line->GetNextLine();
+         status->m_iterator = status->m_line->GetFirstObject();
+         export = new wxLayoutExportObject();;
+         export->type = ((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
+            ?  WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
+         if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF)
+            export->content.text = new wxString("\r\n");
+         else
+            export->content.text = new wxString("\n");
+         return export;
+      }
+   }
    
+   export = new wxLayoutExportObject();
+   wxLayoutObjectType   type = (** status->m_iterator).GetType();
    if( (mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_OBJECTS || ! WXLO_IS_TEXT(type)) // simple case
    {
       export->type = WXLO_EXPORT_OBJECT;
-      export->content.object = *from;
-      from++;
+      export->content.object = *status->m_iterator;
+      status->m_iterator++;
       return export;
    }
 
-   String *str = new String();
-   
+   // else: must be text
+   wxString *str = new wxString();
    // text must be concatenated
-   while(from != list.end() && WXLO_IS_TEXT(type))
+   do
    {
       switch(type)
       {
       case WXLO_TYPE_TEXT:
-         *str += ((wxLayoutObjectText *)*from)->GetText();
-         break;
-      case WXLO_TYPE_LINEBREAK:
-         if((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
-            *str += "<br>";
-         if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF)
-            *str += "\r\n";
-         else
-            *str += '\n';
+         *str += ((wxLayoutObjectText *)*status->m_iterator)->GetText();
          break;
       case WXLO_TYPE_CMD:
          wxASSERT_MSG( (mode&WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML,
                        "reached cmd object in text mode" );
          
          *str += wxLayoutExportCmdAsHTML(*(wxLayoutObjectCmd const
-                                           *)*from, &s_si);
+                                           *)*status->m_iterator, & status->m_si);
          break;
       default:  // ignore icons
          ;
       }
-      from++;
-      if(from != list.end())
-         type = (*from)->GetType();
+      status->m_iterator++;
+      if(status->m_iterator == NULLIT) // end of line!
+      {
+         if((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
+            *str += "<br>";
+         if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF)
+            *str += "\r\n";
+         else
+            *str += '\n';
+         status->m_line = status->m_line->GetNextLine();
+         if(status->m_line)
+            status->m_iterator = status->m_line->GetFirstObject();
+         else
+            status->m_iterator = NULLIT;
+      }
+      if(status->m_iterator != NULLIT)
+         type = (** status->m_iterator).GetType();
+      else
+         break;
    }
-   export->type = ((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML) ?  WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
+   while(WXLO_IS_TEXT(type));
+
+   export->type = ((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
+      ?  WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
    export->content.text = str;
    return export;
 }
+
index 0f0d2b6a5685843b9c1a4e07c283ca12508c80f4..f0b07c80300dfcf594d60bae35c174d322d482f4 100644 (file)
@@ -41,8 +41,8 @@ struct wxLayoutExportObject
    wxLayoutExportType type;
    union
    {
-      String           *text;
-      wxLayoutObjectBase *object;
+      wxString           *text;
+      wxLayoutObject *object;
    }content;
    ~wxLayoutExportObject()
       {
@@ -51,22 +51,37 @@ struct wxLayoutExportObject
       }
 };
 
+struct wxLayoutExportStatus
+{
+   wxLayoutExportStatus(wxLayoutList *list)
+      {
+         list->GetDefaults()->GetStyle(&m_si);
+         m_line = list->GetFirstLine();
+         m_iterator = m_line->GetFirstObject();
+      }
+   
+   wxLayoutLine      * m_line;
+   wxLOiterator        m_iterator;
+   wxLayoutStyleInfo   m_si;
+};
+
+
 #ifdef OS_WIN
 /// import text into a wxLayoutList (including linefeeds):
-void wxLayoutImportText(wxLayoutList &list, String const &str,
+void wxLayoutImportText(wxLayoutList &list, wxString const &str,
                         int withflag = WXLO_EXPORT_WITH_CRLF);
 
 wxLayoutExportObject *wxLayoutExport(wxLayoutList &list,
-                               wxLayoutList::iterator &from,
                                int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_CRLF); 
 #else
 /// import text into a wxLayoutList (including linefeeds):
-void wxLayoutImportText(wxLayoutList &list, String const &str,
+void wxLayoutImportText(wxLayoutList &list, wxString const &str,
                         int withflag = WXLO_EXPORT_WITH_LF_ONLY);
 
-wxLayoutExportObject *wxLayoutExport(wxLayoutList &list,
-                               wxLayoutList::iterator &from,
-                               int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_LF_ONLY); 
+/// export text in a given format FIXME-MT: not thread safe, uses static variable
+wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
+                                     int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_LF_ONLY
+                                     );
 #endif
 
 #endif //WXLPARSER_H
index 604271964086097e918a98d1a1b06e6f2538d80b..83cbefdc5cca204edb09e9e079f2cd542c877add 100644 (file)
@@ -1,7 +1,7 @@
 /*-*- c++ -*-********************************************************
  * wxLwindow.h : a scrolled Window for displaying/entering rich text*
  *                                                                  *
- * (C) 1998, 1999 by Karsten Ballüder (Ballueder@usa.net)        * 
+ * (C) 1998, 1999 by Karsten Ballüder (Ballueder@usa.net)           
  *                                                                  *
  * $Id$
  *******************************************************************/
@@ -12,7 +12,7 @@
 
 //#include "Mpch.h"
 
-#ifdef M_PREFIX
+#ifdef M_BASEDIR
 #   ifndef USE_PCH
 #     include "Mcommon.h"
 #     include "gui/wxMenuDefs.h"
 #else
 #   ifdef   __WXMSW__
 #       include <windows.h>
-
 #       undef FindWindow
 #       undef GetCharWidth
 #       undef StartDoc
 #   endif
-
 #   include "wxlwindow.h"
-#   define TRACEMESSAGE(x)
 #endif
-#  define   WXL_VAR(x)           { wxString s; s << #x " = " << x; wxLogDebug(s); }
 
 BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
    EVT_PAINT    (wxLayoutWindow::OnPaint)
    EVT_CHAR     (wxLayoutWindow::OnChar)
-
    EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick)
    EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick)
    EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick)
+   EVT_MENU_RANGE(WXLOWIN_MENU_FIRST, WXLOWIN_MENU_LAST, wxLayoutWindow::OnMenu)
+   EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus)
+   EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
+END_EVENT_TABLE()
+   /*
+     
    EVT_MENU(WXLOWIN_MENU_LARGER, wxLayoutWindow::OnMenu)
    EVT_MENU(WXLOWIN_MENU_SMALLER, wxLayoutWindow::OnMenu)
-   EVT_MENU(WXLOWIN_MENU_UNDERLINE, wxLayoutWindow::OnMenu)
-   EVT_MENU(WXLOWIN_MENU_BOLD, wxLayoutWindow::OnMenu)
-   EVT_MENU(WXLOWIN_MENU_ITALICS, wxLayoutWindow::OnMenu)
+   EVT_MENU(WXLOWIN_MENU_UNDERLINE_ON, wxLayoutWindow::OnMenu)
+   EVT_MENU(WXLOWIN_MENU_UNDERLINE_OFF, wxLayoutWindow::OnMenu)
+   EVT_MENU(WXLOWIN_MENU_BOLD_ON, wxLayoutWindow::OnMenu)
+   EVT_MENU(WXLOWIN_MENU_BOLD_OFF, wxLayoutWindow::OnMenu)
+   EVT_MENU(WXLOWIN_MENU_ITALICS_ON, wxLayoutWindow::OnMenu)
+   EVT_MENU(WXLOWIN_MENU_ITALICS_OFF, wxLayoutWindow::OnMenu)
    EVT_MENU(WXLOWIN_MENU_ROMAN, wxLayoutWindow::OnMenu)
    EVT_MENU(WXLOWIN_MENU_TYPEWRITER, wxLayoutWindow::OnMenu)
    EVT_MENU(WXLOWIN_MENU_SANSSERIF, wxLayoutWindow::OnMenu)
-   EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus)
-   EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
-END_EVENT_TABLE()
+   */
 
 wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
    : wxScrolledWindow(parent, -1, wxDefaultPosition, wxDefaultSize,
                       wxHSCROLL | wxVSCROLL | wxBORDER)
 
 {
+   m_Editable = false;
    m_doSendEvents = false;
    m_ViewStartX = 0; m_ViewStartY = 0;
    m_DoPopupMenu = true;
-   m_PopupMenu = NULL;
+   m_PopupMenu = MakeFormatMenu();
    m_memDC = new wxMemoryDC;
    m_bitmap = new wxBitmap(4,4);
    m_bitmapSize = wxPoint(4,4);
-   
-   CoordType
-      max_x, max_y, lineHeight;
-   m_llist.GetSize(&max_x, &max_y, &lineHeight);
-   SetScrollbars(10, lineHeight, max_x/10+1, max_y/lineHeight+1);
+   m_llist = new wxLayoutList();
+   wxPoint max = m_llist->GetSize();
+   SetScrollbars(10, 20 /*lineHeight*/, max.x/10+1, max.y/20+1);
    EnableScrolling(true,true);
-   m_maxx = max_x; m_maxy = max_y; m_lineHeight = lineHeight;
+   m_maxx = max.x; m_maxy = max.y;
+   SetDirty();
 }
 
 wxLayoutWindow::~wxLayoutWindow()
 {
    delete m_memDC; // deletes bitmap automatically (?)
    delete m_bitmap;
-   if(m_PopupMenu) delete m_PopupMenu; 
+   delete m_llist;
+   delete m_PopupMenu; 
 }
 
 #ifdef __WXMSW__
@@ -89,19 +92,6 @@ wxLayoutWindow::MSWGetDlgCode()
 }
 #endif //MSW
 
-void
-wxLayoutWindow::Update(void)
-{
-   if(IsDirty())
-   {
-      UpdateScrollbars();
-      DoPaint();
-   }
-   else
-      DoPaint(true); // only the cursor
-   return;
-}
-
 void
 wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
 {
@@ -116,21 +106,29 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
    findPos.x = dc.DeviceToLogicalX(event.GetX());
    findPos.y = dc.DeviceToLogicalY(event.GetY());
 
-   TRACEMESSAGE(("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)",
-                 event.GetX(), event.GetY(), findPos.x, findPos.y));
+#ifdef WXLAYOUT_DEBUG
+   wxLogDebug("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)",
+              event.GetX(), event.GetY(), findPos.x, findPos.y);
+#endif
 
    m_ClickPosition = findPos;
-   wxLayoutObjectBase *obj = m_llist.Find(findPos);
+   wxLayoutObject *obj = m_llist->FindObject(findPos);
 
+#ifdef WXLAYOUT_DEBUG
+   if(obj)
+      wxLogDebug("wxLayoutWindow::OnMouse: Found object of type %d.",
+                 obj->GetType());
+   else
+      wxLogDebug("wxLayoutWindow::OnMouse: Found no object.");
+#endif
+   
    // only do the menu if activated, editable and not on a clickable object
    if(eventId == WXLOWIN_MENU_RCLICK
-      && m_DoPopupMenu
-      && m_llist.IsEditable()
-      && obj && obj->GetUserData() == NULL)
+      && IsEditable()
+      && (! obj || (obj && obj->GetUserData() == NULL))
+      )
    {
-      // when does this menu get freed?
-      // how do we handle toggling? FIXME
-      PopupMenu(MakeFormatMenu(), event.GetX(), event.GetY());
+      PopupMenu(m_PopupMenu, event.GetX(), event.GetY());
       return;
    }
    // find the object at this position
@@ -143,83 +141,13 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
    }
 }
 
-void
-wxLayoutWindow::DeleteToEndOfLine(void)
-{
-   int help = m_llist.GetLineLength(
-      m_llist.GetCurrentObject())
-      - m_llist.GetCursor().x;
-   m_llist.Delete(help>1 ? help-1 : 1);
-}
-
-void
-wxLayoutWindow::GotoEndOfLine(void)
-{
-   wxPoint p = m_llist.GetCursor();
-   p.x = m_llist.GetLineLength(m_llist.GetCurrentObject());
-   if(p.x > 0) p.x --; // do not count the linebreak
-   m_llist.SetCursor(p);
-}
-
-void
-wxLayoutWindow::GotoBeginOfLine(void)
-{
-   wxPoint p = m_llist.GetCursor();
-   p.x = 0;
-   m_llist.SetCursor(p);
-}
-
-void
-wxLayoutWindow::DeleteLine(void)
-{
-   GotoBeginOfLine();
-   DeleteToEndOfLine();
-   m_llist.Delete(1); // newline
-}
-
-void
-wxLayoutWindow::DeleteToBeginOfLine(void)
-{
-   wxPoint p = m_llist.GetCursor();
-   int count = p.x;
-   if(count > 0)
-   {
-      p.x = 0;
-      m_llist.SetCursor(p);
-      m_llist.Delete(count);
-   }
-}
-
-
-void
-wxLayoutWindow::ScrollToCursor(void)
-{
-   /** Scroll so that cursor is visible! */
-   int x0,y0,x1,y1,ux,uy;
-   ViewStart(&x0,&y0);
-   GetScrollPixelsPerUnit(&ux,&uy);
-   x0*=ux; y0*=uy;
-   GetClientSize(&x1,&y1);
-   
-   wxPoint cc = m_llist.GetCursorCoords();
-   
-   if(cc.x < x0 || cc.y < y0
-      || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10))  // (9*x)/10 ==  90%
-   {
-      int nx, ny;
-      nx = cc.x - (8*x1)/10; if(nx < 0) nx = 0;
-      ny = cc.y - (8*y1)/10; if(ny < 0) ny = 0;
-      Scroll(nx/ux,ny/uy);
-   }
-}
-
 /*
- * some simple keyboard handling
+ * Some simple keyboard handling.
  */
 void
 wxLayoutWindow::OnChar(wxKeyEvent& event)
 {
-   if(! m_llist.IsEditable()) // do nothing
+   if(!IsEditable()) // do nothing
    {
       event.Skip();
       return;
@@ -228,96 +156,96 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
    long keyCode = event.KeyCode();
 
    /* First, handle control keys */
-   if(event.ControlDown())
+   if(event.ControlDown() && ! event.AltDown())
    {
       switch(event.KeyCode())
       {
       case WXK_DELETE :
-      case 'k':
-         DeleteToEndOfLine(); break;
       case 'd':
-         m_llist.Delete(1); break;
+         m_llist->Delete(1);
+         break;
       case 'y':
-         DeleteLine(); break;
+         m_llist->DeleteLines(1);
+         break;
       case 'h': // like backspace
-         if(m_llist.MoveCursor(-1))
-            m_llist.Delete(1);
+         if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
          break;
       case 'u':
-         DeleteToBeginOfLine(); break;
+         m_llist->DeleteToBeginOfLine();
+         break;
+      case 'k':
+         m_llist->DeleteToEndOfLine();
+         break;
       default:
          ;
       }
    }
-   else // no control keys
+   // ALT only:
+   else if( event.AltDown() && ! event.ControlDown() )
+   {
+      switch(event.KeyCode())
+      {
+      case WXK_DELETE:
+      case 'd':
+         m_llist->DeleteWord();
+         break;
+      default:
+         ;
+      }
+   }
+   // no control keys:
+   else if ( ! event.AltDown() && ! event.ControlDown())
    {
       switch(event.KeyCode())
       {
       case WXK_RIGHT:
-         m_llist.MoveCursor(1);
+         m_llist->MoveCursorHorizontally(1);
          break;
       case WXK_LEFT:
-         m_llist.MoveCursor(-1);
+         m_llist->MoveCursorHorizontally(-1);
          break;
       case WXK_UP:
-         m_llist.MoveCursor(0,-1);
+         m_llist->MoveCursorVertically(-1);
          break;
       case WXK_DOWN:
-         m_llist.MoveCursor(0,1);
+         m_llist->MoveCursorVertically(1);
          break;
       case WXK_PRIOR:
-         m_llist.MoveCursor(0,-20);
+         m_llist->MoveCursorVertically(-20);
          break;
       case WXK_NEXT:
-         m_llist.MoveCursor(0,20);
+         m_llist->MoveCursorVertically(20);
          break;
       case WXK_HOME:
-         GotoBeginOfLine();
+         m_llist->MoveCursorToBeginOfLine();
          break;
       case WXK_END:
-         GotoEndOfLine();
+         m_llist->MoveCursorToEndOfLine();
          break;
       case WXK_DELETE :
-         if(event.ControlDown()) // delete to end of line
-            DeleteToEndOfLine();
-         else 
-            m_llist.Delete(1);
+         m_llist->Delete(1);
          break;
       case WXK_BACK: // backspace
-         if(m_llist.MoveCursor(-1)) {
-            m_llist.Delete(1);
-         }
+         if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
          break;
       case WXK_RETURN:
-         m_llist.LineBreak();
+         m_llist->LineBreak();
          break;
-
-#ifdef WXLAYOUT_DEBUG
-      case WXK_F1:
-         m_llist.Debug();
-         break;
-      case WXK_F2:
-         m_llist.WrapLine();
-         break;
-#endif
-      
       default:
          if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
             && (keyCode < 256 && keyCode >= 32)
             )
          {
-            String tmp;
+            wxString tmp;
             tmp += keyCode;
-            m_llist.Insert(tmp);
-            m_llist.WrapLine();
+            m_llist->Insert(tmp);
+////            m_llist->WrapLine();
          }
          break;
       }
    }
-
-   ScrollToCursor();
-   Update();
-   ScrollToCursor();
+   SetDirty();
+   DoPaint(true); // paint and scroll to cursor
 }
 
 void
@@ -327,153 +255,160 @@ wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event))  // or: OnDraw(wxDC& dc)
 }
 
 void
-wxLayoutWindow::DoPaint(bool cursorOnly)  // or: OnDraw(wxDC& dc)
+wxLayoutWindow::DoPaint(bool scrollToCursor)
 {
    wxPaintDC dc( this );
    PrepareDC( dc );
 
-   // wxGTK: wxMemoryDC broken? YES!!
    int x0,y0,x1,y1, dx, dy;
+
+   // Calculate where the top of the visible area is:
    ViewStart(&x0,&y0);
-   GetClientSize(&x1,&y1);                 // this is the size of the visible window
-   wxASSERT(x1 > 0);
-   wxASSERT(y1 > 0);
    GetScrollPixelsPerUnit(&dx, &dy);
    x0 *= dx; y0 *= dy;
-   //FIXME: trying an offset for small border:
-   wxPoint offset(-x0+4,-y0+4);
 
-   //Blit() doesn't work on scrolled window!
-   // So we have to draw the cursor on the memdc.
-   //if(! cursorOnly)
+   // Get the size of the visible window:
+   GetClientSize(&x1,&y1);
+   wxASSERT(x1 > 0);
+
+   wxASSERT(y1 > 0);
+
+   // Maybe we need to change the scrollbar sizes or positions,
+   // so layout the list and check:
+   if(IsDirty() || scrollToCursor)
+      m_llist->Layout(dc);
+   if(IsDirty())
+      ResizeScrollbars();
+   
+   /* Make sure that the scrollbars are at a position so that the
+      cursor is visible if we are editing. */
+      /** Scroll so that cursor is visible! */
+   if(IsEditable() && scrollToCursor)
    {
-      if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
+      wxPoint cc = m_llist->GetCursorScreenPos();
+      if(cc.x < x0 || cc.y < y0
+         || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10))  // (9*x)/10 ==  90%
       {
-         wxASSERT(m_bitmapSize.x > 0);
-         wxASSERT(m_bitmapSize.y > 0);
-
-         m_memDC->SelectObject(wxNullBitmap);
-         delete m_bitmap;
-         m_bitmapSize = wxPoint(x1,y1);
-         m_bitmap = new wxBitmap(x1,y1);
-         m_memDC->SelectObject(*m_bitmap);
+         int nx, ny;
+         nx = cc.x - x1/2; if(nx < 0) nx = 0;
+         ny = cc.y - y1/2; if(ny < 0) ny = 0;
+         Scroll(nx/dx,ny/dy); // new view start
+         x0 = nx; y0 = ny;
       }
-      m_memDC->SetDeviceOrigin(0,0);
-      m_memDC->Clear();
-      if(IsDirty() || m_llist.CursorMoved())
-         m_llist.Layout(dc);
+   }
+   
+   /* Check whether the window has grown, if so, we need to reallocate 
+      the bitmap to be larger. */
+   if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
+   {
+      wxASSERT(m_bitmapSize.x > 0);
+      wxASSERT(m_bitmapSize.y > 0);
       
-      m_llist.EraseAndDraw(*m_memDC,
-                           wxLayoutObjectList::iterator(NULL),offset);
-      m_llist.DrawCursor(*m_memDC,false,offset);
-      dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
+      m_memDC->SelectObject(wxNullBitmap);
+      delete m_bitmap;
+      m_bitmapSize = wxPoint(x1,y1);
+      m_bitmap = new wxBitmap(x1,y1);
+      m_memDC->SelectObject(*m_bitmap);
    }
+   // Device origins on the memDC are suspect, we translate manually
+   // with the translate parameter of Draw().
+   m_memDC->SetDeviceOrigin(0,0);
+   m_memDC->Clear();
 
-   //FIXME obsolete? ResetDirty();
-   UpdateScrollbars();
+   // The +4 give the window a tiny border on the left and top, looks nice.
+   wxPoint offset(-x0+4,-y0+4);
+   m_llist->Draw(*m_memDC,offset);
+   if(IsEditable())
+      m_llist->DrawCursor(*m_memDC,m_HaveFocus,offset);
+   // Now copy everything to the screen:
+   dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
+
+   
+   ResetDirty();
 }
 
 // change the range and position of scroll bars
 void
-wxLayoutWindow::UpdateScrollbars(bool exact)
+wxLayoutWindow::ResizeScrollbars(bool exact)
 {
-   CoordType
-      max_x, max_y, lineHeight;
-   
-   m_llist.GetSize(&max_x, &max_y, &lineHeight);
+   wxPoint max = m_llist->GetSize();
 
-   if(max_x > m_maxx || max_y > m_maxy || exact)
+   if(max.x > m_maxx || max.y > m_maxy
+      || max.x < (7*m_maxx)/10 || max.y << (7*m_maxy)/10
+      || exact)
    {
-      if(! exact)  // add an extra 50% to the sizes to avoid future updates
+      if(! exact)  // add an extra 20% to the sizes to avoid future updates
       {
-         max_x = (3*max_x)/2;
-         max_y = (3*max_y)/2;
+         max.x = (12*max.x)/10;  // 12/20 = 120%
+         max.y = (12*max.y)/10;
       }
       ViewStart(&m_ViewStartX, &m_ViewStartY);
-      SetScrollbars(10, 20, max_x/10+1,max_y/20+1,m_ViewStartX,m_ViewStartY,true);
-      m_maxx = max_x; m_maxy = max_y;
+      SetScrollbars(10, 20, max.x/10+1,max.y/20+1,m_ViewStartX,m_ViewStartY,true);
+      m_maxx = max.x; m_maxy = max.y;
    }
 }
 
-void
-wxLayoutWindow::Print(wxDC &dc)
-{
-   if (dc.Ok() && dc.StartDoc((char *)_("Printing message...")))
-   {
-      //dc.SetUserScale(1.0, 1.0);
-      m_llist.Draw(dc);
-      dc.EndDoc();
-   }
-}
 
 wxMenu *
 wxLayoutWindow::MakeFormatMenu()
 {
-   if(m_PopupMenu)
-      return m_PopupMenu;
-   
-   wxMenu *m = new wxMenu();
+   wxMenu *m = new wxMenu(_("Layout Menu"));
 
    m->Append(WXLOWIN_MENU_LARGER   ,_("&Larger"),_("Switch to larger font."), false);
    m->Append(WXLOWIN_MENU_SMALLER  ,_("&Smaller"),_("Switch to smaller font."), false);
    m->AppendSeparator();
-   m->Append(WXLOWIN_MENU_UNDERLINE,_("&Underline"),_("Toggle underline mode."), true);
-   m->Append(WXLOWIN_MENU_BOLD     ,_("&Bold"),_("Toggle bold mode."), true);
-   m->Append(WXLOWIN_MENU_ITALICS  ,_("&Italics"),_("Toggle italics mode."), true);
+   m->Append(WXLOWIN_MENU_UNDERLINE_ON, _("&Underline on"),_("Activate underline mode."), false);
+   m->Append(WXLOWIN_MENU_UNDERLINE_OFF,_("&Underline off"),_("Deactivate underline mode."), false);
+   m->Append(WXLOWIN_MENU_BOLD_ON      ,_("&Bold on"),_("Activate bold mode."), false);
+   m->Append(WXLOWIN_MENU_BOLD_OFF     ,_("&Bold off"),_("Deactivate bold mode."), false);
+   m->Append(WXLOWIN_MENU_ITALICS_ON   ,_("&Italics on"),_("Activate italics mode."), false);
+   m->Append(WXLOWIN_MENU_ITALICS_OFF  ,_("&Italics off"),_("Deactivate italics mode."), false);
    m->AppendSeparator();
-   m->Append(WXLOWIN_MENU_ROMAN     ,_("&Roman"),_("Toggle underline mode."), false);
-   m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Toggle bold mode."), false);
-   m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Toggle italics mode."), false);
-
-   return m_PopupMenu = m;
+   m->Append(WXLOWIN_MENU_ROMAN     ,_("&Roman"),_("Switch to roman font."), false);
+   m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Switch to typewriter font."), false);
+   m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Switch to sans serif font."), false);
+   return m;
 }
 
 void wxLayoutWindow::OnMenu(wxCommandEvent& event)
 {
-   if(! m_llist.IsEditable())
-      return;
-   
    switch (event.GetId())
    {
    case WXLOWIN_MENU_LARGER:
-      m_llist.SetFontLarger();
-      break;
+      m_llist->SetFontLarger(); break;
    case WXLOWIN_MENU_SMALLER:
-      m_llist.SetFontSmaller();
-      break;
-   case WXLOWIN_MENU_UNDERLINE:
-      m_llist.SetFontUnderline(
-         m_PopupMenu->IsChecked(WXLOWIN_MENU_UNDERLINE) ? false : true
-            );
-         break;
-   case WXLOWIN_MENU_BOLD:
-      m_llist.SetFontWeight(
-         m_PopupMenu->IsChecked(WXLOWIN_MENU_BOLD) ? wxNORMAL : wxBOLD
-            );
-   case WXLOWIN_MENU_ITALICS:
-      m_llist.SetFontStyle(
-         m_PopupMenu->IsChecked(WXLOWIN_MENU_ITALICS) ? wxNORMAL : wxITALIC
-            );
-      break;
+      m_llist->SetFontSmaller(); break;
+   case WXLOWIN_MENU_UNDERLINE_ON:
+      m_llist->SetFontUnderline(true); break;
+   case WXLOWIN_MENU_UNDERLINE_OFF:
+      m_llist->SetFontUnderline(false); break;
+   case WXLOWIN_MENU_BOLD_ON:
+      m_llist->SetFontWeight(wxBOLD); break;
+   case WXLOWIN_MENU_BOLD_OFF:
+      m_llist->SetFontWeight(wxNORMAL); break;
+   case WXLOWIN_MENU_ITALICS_ON:
+      m_llist->SetFontStyle(wxITALIC); break;
+   case WXLOWIN_MENU_ITALICS_OFF:
+      m_llist->SetFontStyle(wxNORMAL); break;
    case WXLOWIN_MENU_ROMAN:
-      m_llist.SetFontFamily(wxROMAN); break;
+      m_llist->SetFontFamily(wxROMAN); break;
    case WXLOWIN_MENU_TYPEWRITER:
-      m_llist.SetFontFamily(wxFIXED); break;
+      m_llist->SetFontFamily(wxFIXED); break;
    case WXLOWIN_MENU_SANSSERIF:
-      m_llist.SetFontFamily(wxSWISS); break;
+      m_llist->SetFontFamily(wxSWISS); break;
    }
 }
 
 void
 wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
 {
-   m_llist.SetBoldCursor(true);
-   DoPaint(true);
+   m_HaveFocus = true;
+   DoPaint(); // to repaint the cursor
 }
 
 void
 wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
 {
-   m_llist.SetBoldCursor(false);
-   Update();
+   m_HaveFocus = true;
+   DoPaint(); // to repaint the cursor
 }
index b31f2c52aaa1999afc0b254c798f14407d82d052..f6f7b6f03e1f5bef9c143db5a02bce53dd60f7e9 100644 (file)
@@ -1,7 +1,7 @@
 /*-*- c++ -*-********************************************************
  * wxLwindow.h : a scrolled Window for displaying/entering rich text*
  *                                                                  *
- * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
+ * (C) 1998,1999 by Karsten Ballüder (Ballueder@usa.net)            *
  *                                                                  *
  * $Id$
  *******************************************************************/
 
 #include   "wxllist.h"
 
+#ifndef WXLOWIN_MENU_FIRST
+#   define WXLOWIN_MENU_FIRST 12000
+#endif
+
 enum
 {
-   WXLOWIN_MENU_LARGER = 12000,
+   WXLOWIN_MENU_LARGER = WXLOWIN_MENU_FIRST,
    WXLOWIN_MENU_SMALLER,
-   WXLOWIN_MENU_UNDERLINE,
-   WXLOWIN_MENU_BOLD,
-   WXLOWIN_MENU_ITALICS,
+   WXLOWIN_MENU_UNDERLINE_ON,
+   WXLOWIN_MENU_UNDERLINE_OFF,
+   WXLOWIN_MENU_BOLD_ON,
+   WXLOWIN_MENU_BOLD_OFF,
+   WXLOWIN_MENU_ITALICS_ON,
+   WXLOWIN_MENU_ITALICS_OFF,
    WXLOWIN_MENU_ROMAN,
    WXLOWIN_MENU_TYPEWRITER,
    WXLOWIN_MENU_SANSSERIF,
    WXLOWIN_MENU_RCLICK,
    WXLOWIN_MENU_LCLICK,
-   WXLOWIN_MENU_DBLCLICK
-   
+   WXLOWIN_MENU_DBLCLICK,
+   WXLOWIN_MENU_LAST = WXLOWIN_MENU_DBLCLICK
 };
 
+/**
+   This class is a rich text editing widget.
+*/
 class wxLayoutWindow : public wxScrolledWindow
 {
 public:
@@ -44,90 +54,90 @@ public:
 
    /// Destructor.
    virtual ~wxLayoutWindow();
-   
-   /* Returns a reference to the wxLayoutList object.
-      @return the list
-   */
-   wxLayoutList & GetLayoutList(void) { return m_llist; }
 
-   // clears the window and sets default parameters:
-   void Clear(int family = wxROMAN, int size=12, int style=wxNORMAL, int weight=wxNORMAL,
-              int underline=0, char const *fg="black", char const
-              *bg="white")
+   /**@name Editing functionality */
+   //@{
+   /// Clears the window and sets default parameters.
+   void Clear(int family = wxROMAN,
+              int size=12,
+              int style=wxNORMAL,
+              int weight=wxNORMAL,
+              int underline=0,
+              char const *fg="black",
+              char const *bg="white")
       {
-         GetLayoutList().Clear(family,size,style,weight,underline,fg,bg);
-         SetBackgroundColour( *GetLayoutList().GetDefaults()->GetBGColour());
-         Update();
-         m_bDirty = FALSE;
+         GetLayoutList()->Clear(family,size,style,weight,underline,fg,bg);
+         SetBackgroundColour(*GetLayoutList()->GetDefaults()->GetBGColour());
+         SetDirty();
+         DoPaint();
       }
 
-   // callbacks
-   // NB: these functions are used as event handlers and must not be virtual
-   void OnPaint(wxPaintEvent &event);
-   void OnLeftMouseClick(wxMouseEvent& event)
-      { OnMouse(WXLOWIN_MENU_LCLICK, event); }
-   void OnRightMouseClick(wxMouseEvent& event)
-      { OnMouse(WXLOWIN_MENU_RCLICK, event); }
-   void OnMouseDblClick(wxMouseEvent& event)
-      { OnMouse(WXLOWIN_MENU_DBLCLICK, event); }
-
-   void OnChar(wxKeyEvent& event);
-   void OnMenu(wxCommandEvent& event);
+   /// Enable or disable editing, i.e. processing of keystrokes.
+   void SetEditable(bool toggle) { m_Editable = toggle; }
+   /// Query whether list can be edited by user.
+   bool IsEditable(void) const { return m_Editable; }
 
+   //@}
+   
    void EnablePopup(bool enable = true) { m_DoPopupMenu = enable; }
-   /// gets called by either Update() or OnPaint()
-   void DoPaint(bool cursoronly = false);
+
+   /** Redraws the window.
+       @param scrollToCursor if true, scroll the window so that the
+       cursor becomes visible
+   */
+   void DoPaint(bool scrollToCursor = false);
 
 #ifdef __WXMSW__
    virtual long MSWGetDlgCode();
 #endif //MSW
 
    /// if exact == false, assume 50% extra size for the future
-   void UpdateScrollbars(bool exact = false);  // don't change this to true!
-   void Print(wxDC &dc);
-   wxMenu * MakeFormatMenu(void);
+   void ResizeScrollbars(bool exact = false);  // don't change this to true!
 
    /// if the flag is true, we send events when user clicks on embedded objects
    inline void SetMouseTracking(bool doIt = true) { m_doSendEvents = doIt; }
 
-   // dirty flag access
-   bool IsDirty() const { return m_llist.IsDirty(); }
-   void ResetDirty()    { m_llist.ResetDirty();     }
+   /* Returns a pointer to the wxLayoutList object.
+      @return the list
+   */
+   wxLayoutList * GetLayoutList(void) { return m_llist; }
 
+   /**@name Callbacks */
+   //@{
+   void OnPaint(wxPaintEvent &event);
+   void OnChar(wxKeyEvent& event);
+   void OnMenu(wxCommandEvent& event);
+   void OnLeftMouseClick(wxMouseEvent& event)  { OnMouse(WXLOWIN_MENU_LCLICK, event); }
+   void OnRightMouseClick(wxMouseEvent& event) { OnMouse(WXLOWIN_MENU_RCLICK, event); }
+   void OnMouseDblClick(wxMouseEvent& event)   { OnMouse(WXLOWIN_MENU_DBLCLICK, event); }
    void OnSetFocus(wxFocusEvent &ev);
    void OnKillFocus(wxFocusEvent &ev);
+   //@}
+
+   /// Creates a wxMenu for use as a format popup.
+   static wxMenu * MakeFormatMenu(void);
+   /// Set dirty flag.
+   void SetDirty(void) { m_Dirty = true; }
 protected:
-   /// Deletes from cursor to end of line.
-   void DeleteToEndOfLine(void);
-   /// Deletes everything left of cursor.
-   void DeleteToBeginOfLine(void);
-   /// Goto end of line.
-   void GotoEndOfLine(void);
-   /// Goto begin of line.
-   void GotoBeginOfLine(void);
-   /// Delete Line
-   void DeleteLine(void);
+   /**@name Dirty flag handling for optimisations. */
+   //@{
+   /// Query whether window needs redrawing.
+   bool IsDirty(void) const { return m_Dirty; }
+   /// Reset dirty flag.
+   void ResetDirty(void) { m_Dirty = false; }
+   //@}
+protected:   
    /// generic function for mouse events processing
    void OnMouse(int eventId, wxMouseEvent& event);
-   /// scroll to cursor
-   void ScrollToCursor(void);
-   
-   /// repaint if needed
-   void Update(void);
 
    /// for sending events
    wxWindow *m_Parent;
+   /// Shall we send events?
    bool m_doSendEvents;
-
-   /// the layout list to be displayed
-   wxLayoutList m_llist;
-
    /// Where does the current view start?
    int m_ViewStartX; int m_ViewStartY;
-   
-   /// do we have unsaved data?
-   bool m_bDirty;
-
+   /// Do we currently have the focus?
+   bool m_HaveFocus;
    /// do we handle clicks of the right mouse button?
    bool m_DoPopupMenu;
    /// the menu
@@ -139,6 +149,13 @@ protected:
    int m_maxy;
    int m_lineHeight;
 private:
+   /// The layout list to be displayed.
+   wxLayoutList *m_llist;
+
+   /// Can user edit the window?
+   bool m_Editable;
+   /// Is list dirty?
+   bool         m_Dirty;
    wxMemoryDC  *m_memDC;
    wxBitmap    *m_bitmap;
    wxPoint      m_bitmapSize;