From: Karsten Ballüder Date: Sun, 7 Mar 1999 21:38:50 +0000 (+0000) Subject: New, rewritten, wxLayout. Almost complete. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/43e916c33ecf51aac840c1dd640069a2ac0329ab New, rewritten, wxLayout. Almost complete. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1873 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/user/wxLayout/TODO b/user/wxLayout/TODO new file mode 100644 index 0000000000..cd9ff621ec --- /dev/null +++ b/user/wxLayout/TODO @@ -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 + diff --git a/user/wxLayout/kbList.h b/user/wxLayout/kbList.h index 257c6f5528..9f35abb450 100644 --- a/user/wxLayout/kbList.h +++ b/user/wxLayout/kbList.h @@ -311,5 +311,5 @@ protected: \ /// define the most commonly used list type once: KBLIST_DEFINE(kbStringList, String); #endif - +//@} #endif // KBLIST_H diff --git a/user/wxLayout/wxLayout.cpp b/user/wxLayout/wxLayout.cpp index b37f721142..504fef1d1f 100644 --- a/user/wxLayout/wxLayout.cpp +++ b/user/wxLayout/wxLayout.cpp @@ -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(); } diff --git a/user/wxLayout/wxLayout.h b/user/wxLayout/wxLayout.h index 90d4ae3eec..ea811b8c67 100644 --- a/user/wxLayout/wxLayout.h +++ b/user/wxLayout/wxLayout.h @@ -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 ); diff --git a/user/wxLayout/wxllist.cpp b/user/wxLayout/wxllist.cpp index 69083fdeb5..1b92f5cc5d 100644 --- a/user/wxLayout/wxllist.cpp +++ b/user/wxLayout/wxllist.cpp @@ -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" @@ -56,130 +29,142 @@ # include #endif -#define BASELINESTRETCH 12 +#include -// 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("<>"); - 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); -} diff --git a/user/wxLayout/wxllist.h b/user/wxLayout/wxllist.h index c6a91246fc..2ae0e08129 100644 --- a/user/wxLayout/wxllist.h +++ b/user/wxLayout/wxllist.h @@ -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$ *******************************************************************/ @@ -23,104 +23,98 @@ #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 - 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 diff --git a/user/wxLayout/wxlparser.cpp b/user/wxLayout/wxlparser.cpp index db83335f3a..6ebe3a5ce3 100644 --- a/user/wxLayout/wxlparser.cpp +++ b/user/wxLayout/wxlparser.cpp @@ -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 += "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 =""+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 += ""; else - if(si->weight != wxBOLD && ( last_si && (last_si->weight == wxBOLD))) + if(si.weight != wxBOLD && ( styleInfo && (styleInfo->weight == wxBOLD))) html += ""; - 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 += ""; else - if(si->style != wxITALIC && ( last_si && (last_si->style == wxITALIC))) + if(si.style != wxITALIC && ( styleInfo && (styleInfo->style == wxITALIC))) html += ""; - if(si->underline && ( (!last_si) || ! last_si->underline)) + if(si.underline && ( (!styleInfo) || ! styleInfo->underline)) html += ""; - else if(si->underline == false && ( last_si && last_si->underline)) + else if(si.underline == false && ( styleInfo && styleInfo->underline)) html += ""; + + + *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 += "
"; - 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 += "
"; + 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; } + diff --git a/user/wxLayout/wxlparser.h b/user/wxLayout/wxlparser.h index 0f0d2b6a56..f0b07c8030 100644 --- a/user/wxLayout/wxlparser.h +++ b/user/wxLayout/wxlparser.h @@ -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 diff --git a/user/wxLayout/wxlwindow.cpp b/user/wxLayout/wxlwindow.cpp index 6042719640..83cbefdc5c 100644 --- a/user/wxLayout/wxlwindow.cpp +++ b/user/wxLayout/wxlwindow.cpp @@ -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" @@ -22,62 +22,65 @@ #else # ifdef __WXMSW__ # include - # 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 } diff --git a/user/wxLayout/wxlwindow.h b/user/wxLayout/wxlwindow.h index b31f2c52aa..f6f7b6f03e 100644 --- a/user/wxLayout/wxlwindow.h +++ b/user/wxLayout/wxlwindow.h @@ -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$ *******************************************************************/ @@ -18,22 +18,32 @@ #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;