From: Karsten Ballüder Date: Sat, 24 Oct 1998 18:08:20 +0000 (+0000) Subject: Rewrite. Cursor handling better, split Layout() and Draw(), faster. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/0e6c619a1aff67b336fceb7c51f10c119ee504ec Rewrite. Cursor handling better, split Layout() and Draw(), faster. Printing almost works. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@906 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/user/wxLayout/wxLayout.cpp b/user/wxLayout/wxLayout.cpp index e9b644ff09..bf18ebeae0 100644 --- a/user/wxLayout/wxLayout.cpp +++ b/user/wxLayout/wxLayout.cpp @@ -54,25 +54,16 @@ IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame ) END_EVENT_TABLE() - - - - int orientation = wxPORTRAIT; - - - - - - MyFrame::MyFrame(void) : +MyFrame::MyFrame(void) : wxFrame( (wxFrame *) NULL, -1, (char *) "wxLayout", wxPoint(20,20), wxSize(600,360) ) { CreateStatusBar( 1 ); SetStatusText( "wxLayout by Karsten Ballüder." ); - wxMenu *file_menu = new wxMenu( "Menu 1" ); + wxMenu *file_menu = new wxMenu; file_menu->Append( ID_CLEAR, "Clear"); file_menu->Append( ID_ADD_SAMPLE, "Example"); file_menu->Append( ID_EDIT, "Edit"); @@ -104,7 +95,7 @@ int orientation = wxPORTRAIT; SetMenuBar( menu_bar ); m_lwin = new wxLayoutWindow(this); - m_lwin->SetEventId(ID_CLICK); + m_lwin->SetMouseTracking(true); m_lwin->GetLayoutList().SetEditable(true); m_lwin->Clear(wxROMAN,16,wxNORMAL,wxNORMAL, false); m_lwin->SetFocus(); @@ -113,9 +104,11 @@ int orientation = wxPORTRAIT; void 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 "); @@ -203,7 +196,7 @@ MyFrame::Clear(void) void MyFrame::Edit(void) { wxLayoutList & llist = m_lwin->GetLayoutList(); - m_lwin->SetEventId(ID_CLICK); + //m_lwin->SetEventId(ID_CLICK); llist.MoveCursor(0); llist.MoveCursor(5); @@ -307,8 +300,10 @@ void MyFrame::OnPrint(wxCommandEvent& WXUNUSED(event)) #endif wxPrinter printer; wxLayoutPrintout printout( m_lwin->GetLayoutList(),"My printout"); - if (!printer.Print(this, &printout, TRUE)) - wxMessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wxOK); + 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)) @@ -331,7 +326,9 @@ void MyFrame::OnPrintPreview(wxCommandEvent& WXUNUSED(event)) 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); + wxPrintPreview *preview = new wxPrintPreview(new + wxLayoutPrintout( + m_lwin->GetLayoutList()), new wxLayoutPrintout( m_lwin->GetLayoutList()), & printData); if (!preview->Ok()) { delete preview; @@ -443,7 +440,7 @@ bool MyApp::OnInit(void) { wxFrame *frame = new MyFrame(); frame->Show( TRUE ); - wxSetAFMPath("/usr/local/src/wxWindows/misc/afm/"); +// wxSetAFMPath("/usr/local/src/wxWindows/misc/afm/"); return TRUE; }; diff --git a/user/wxLayout/wxllist.cpp b/user/wxLayout/wxllist.cpp index 551321b13c..708a92153b 100644 --- a/user/wxLayout/wxllist.cpp +++ b/user/wxLayout/wxllist.cpp @@ -3,7 +3,7 @@ * * * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) * * * - * $Id$ * + * $Id$ *******************************************************************/ /* @@ -16,25 +16,34 @@ - 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 + + - the cursor position and size must be decided at layout/draw time + or the fonts will be wrong +*/ + +/* + Known wxGTK bugs: + - MaxX()/MaxY() don't get set */ + #ifdef __GNUG__ #pragma implementation "wxllist.h" #endif -// these two lines are for use in M: //#include "Mpch.h" -//#include "gui/wxllist.h" - -#include "wxllist.h" +#ifdef M_BASEDIR +# include "gui/wxllist.h" +#else +# include "wxllist.h" +#endif #ifndef USE_PCH -# include "iostream.h" - -# include -# include -# include -# include +# include "iostream.h" +# include +# include +# include +# include #endif #define BASELINESTRETCH 12 @@ -46,7 +55,7 @@ static const char *g_aTypeStrings[] = }; # define wxLayoutDebug wxLogDebug -# define WXL_VAR(x) cerr << #x " = " << x ; +# define WXL_VAR(x) cerr << #x " = " << x << endl; # define WXL_DBG_POINT(p) wxLogDebug(#p ": (%d, %d)", p.x, p.y) # define WXL_TRACE(f) wxLogDebug(#f ": ") # define TypeString(t) g_aTypeStrings[t] @@ -76,6 +85,7 @@ wxLayoutObjectText::wxLayoutObjectText(const String &txt) m_Text = txt; m_Width = 0; m_Height = 0; + m_Position = wxPoint(-1,-1); } @@ -87,22 +97,26 @@ wxLayoutObjectText::GetSize(CoordType *baseLine) const } void -wxLayoutObjectText::Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw) +wxLayoutObjectText::Draw(wxDC &dc) +{ + dc.DrawText(Str(m_Text), m_Position.x, m_Position.y); + m_IsDirty = false; +} + + +void +wxLayoutObjectText::Layout(wxDC &dc, wxPoint position, CoordType baseLine) { long descent = 0l; + + if(m_Position.x != position.x || m_Position.y != position.y) + m_IsDirty = true; + + m_Position = position; dc.GetTextExtent(Str(m_Text),&m_Width, &m_Height, &descent); - //FIXME: wxGTK does not set descent to a descent value yet. - if(descent == 0) - descent = (2*m_Height)/10; // crude fix m_BaseLine = m_Height - descent; - position.y += baseLine-m_BaseLine; - if(draw) - dc.DrawText(Str(m_Text),position.x,position.y); - // Don't remove this, important help for debugging layout. -# ifdef WXLAYOUT_DEBUG -// dc.DrawRectangle(position.x, position.y, m_Width, m_Height); -# endif + if(m_Position.x != position.x || m_Position.y != position.y) + m_IsDirty = true; } #ifdef WXLAYOUT_DEBUG @@ -116,25 +130,35 @@ wxLayoutObjectText::Debug(void) //-------------------------- wxLayoutObjectIcon +wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon const &icon) +{ + m_Position = wxPoint(-1,-1); + m_Icon = new wxIcon(icon); +} + wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon) - : m_Icon(icon) { + m_Icon = icon; +} + +void +wxLayoutObjectIcon::Draw(wxDC &dc) +{ + dc.DrawIcon(m_Icon,m_Position.x, m_Position.y); } void -wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw) +wxLayoutObjectIcon::Layout(wxDC &dc, wxPoint position, CoordType baseLine) { - position.y += baseLine - m_Icon->GetHeight(); - if(draw) - dc.DrawIcon(m_Icon,position.x,position.y); + if(m_Position.x != position.x || m_Position.y != position.y) + m_IsDirty = true; + m_Position = position; } wxPoint wxLayoutObjectIcon::GetSize(CoordType *baseLine) const { - wxASSERT(baseLine); - *baseLine = m_Icon->GetHeight(); + if(baseLine) *baseLine = m_Icon->GetHeight(); return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight()); } @@ -179,20 +203,24 @@ wxLayoutObjectCmd::GetStyle(void) const } void -wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint position, CoordType lineHeight, - bool draw) +wxLayoutObjectCmd::Draw(wxDC &dc) { wxASSERT(m_font); - // this get called even when draw==false, so that recalculation - // uses right font sizes dc.SetFont(m_font); if(m_ColourFG) dc.SetTextForeground(*m_ColourFG); if(m_ColourBG) dc.SetTextBackground(*m_ColourBG); } +void +wxLayoutObjectCmd::Layout(wxDC &dc, wxPoint p, CoordType baseline) +{ + m_Position = p; // required so we can find the right object for cursor + // this get called, so that recalculation uses right font sizes + Draw(dc); +} -//-------------------------- wxwxLayoutList +//-------------------------- wxLayoutList wxLayoutList::wxLayoutList() { @@ -262,217 +290,95 @@ wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y, if(lineHeight) *lineHeight = m_LineHeight; } -wxLayoutObjectBase * -wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const - &findCoords, int pageNo, bool reallyDraw) +void +wxLayoutList::ResetSettings(wxDC &dc) { - wxLayoutObjectList::iterator i; + // setting up the default: + dc.SetTextForeground( *wxBLACK ); + dc.SetTextBackground( *wxWHITE ); + dc.SetBackgroundMode( wxSOLID ); // to enable setting of text background + dc.SetFont( *wxNORMAL_FONT ); + if(m_DefaultSetting) + m_DefaultSetting->Draw(dc); +} + +void +wxLayoutList::Layout(wxDC &dc) +{ + iterator i; - // in case we need to look for an object - wxLayoutObjectBase *foundObject = NULL; - // first object in current line wxLayoutObjectList::iterator headOfLine; - - // do we need to recalculate current line? - bool recalculate = false; - - // do we calculate or draw? Either true or false. - bool draw = false; - // drawing parameters: - wxPoint position = wxPoint(0,0); - wxPoint position_HeadOfLine; + // where we draw next + wxPoint position, position_HeadOfLine; + // size of last object + wxPoint size; CoordType baseLine = m_FontPtSize; CoordType baseLineSkip = (BASELINESTRETCH * baseLine)/10; - - // where to draw the cursor - wxPoint - cursorPosition = wxPoint(0,0), - cursorSize = wxPoint(1,baseLineSkip); + CoordType objBaseLine = baseLine; + wxLayoutObjectType type; - // the cursor position inside the object - CoordType cursorOffset = 0; - // object under cursor - wxLayoutObjectList::iterator cursorObject = FindCurrentObject(&cursorOffset); + // we need to count cursor positions + wxPoint cursorPos = wxPoint(0,0); + + wxLayoutObjectBase *cursorObject = NULL; // let's find it again - // queried from each object: - wxPoint size = wxPoint(0,0); - CoordType objBaseLine = baseLine; - wxLayoutObjectType type; - - // used temporarily - wxLayoutObjectText *tobj = NULL; - - - // this is needed for printing to a printer: - // only interesting for printer/PS output - int pageWidth, pageHeight; //GetSize() still needs int at the moment struct { int top, bottom, left, right; } margins; - int currentPage = 1; + margins.top = 0; margins.left = 0; + margins.right = -1; + margins.bottom = -1; - if(pageNo > 0) - { - dc.GetSize(&pageWidth, &pageHeight); - WXL_VAR(pageHeight); - margins.top = 0; //(1*pageHeight)/10; // 10% - margins.bottom = pageHeight;// (9*pageHeight)/10; // 90% - margins.left = 0; //(1*pageWidth)/10; - margins.right = pageWidth; //(9*pageWidth)/10; - } - else - { - margins.top = 0; margins.left = 0; - margins.right = -1; - margins.bottom = -1; - } position.y = margins.top; position.x = margins.left; - - // if the cursorobject is a cmd, we need to find the first - // printable object: - while(cursorObject != end() - && (*cursorObject)->GetType() == WXLO_TYPE_CMD) - cursorObject++; - headOfLine = begin(); + ResetSettings(dc); + + i = begin(); + headOfLine = i; position_HeadOfLine = position; - // setting up the default: - dc.SetTextForeground( *wxBLACK ); - dc.SetTextBackground( *wxWHITE ); - dc.SetBackgroundMode( wxSOLID ); // to enable setting of text background - dc.SetFont( *wxNORMAL_FONT ); - - - //FIXME: who frees the brush, how long does it need to exist? - if(m_DefaultSetting) - m_DefaultSetting->Draw(dc,wxPoint(0,0),0,true); - - // we calculate everything for drawing a line, then rewind to the - // begin of line and actually draw it - i = begin(); - for(;;) + do { - recalculate = false; - if(i == end()) - break; + return; + type = (*i)->GetType(); - - // to initialise sizes of objects, we need to call Draw - if(draw && (pageNo == -1 || pageNo == currentPage)) - { - (*i)->Draw(dc, position, baseLine, draw); -#ifdef WXLAYOUT_DEBUG - if(i == begin()) - wxLogDebug("first position = (%d,%d)",(int) position.x, (int)position.y); -#endif - } - // update coordinates for next object: + (*i)->Layout(dc, position, baseLine); size = (*i)->GetSize(&objBaseLine); - if(findObject && draw) // we need to look for an object - { - if(findCoords.y >= position.y - && findCoords.y <= position.y+size.y - && findCoords.x >= position.x - && findCoords.x <= position.x+size.x) - { - foundObject = *i; - findObject = false; // speeds things up - } - } - // draw the cursor - if(m_Editable && draw && i == cursorObject) - { - WXL_VAR((**cursorObject).GetType()); - WXL_VAR(m_CursorPosition.x); WXL_VAR(m_CursorPosition.y); - if(type == WXLO_TYPE_TEXT) // special treatment - { - long descent = 0l; long width, height; - tobj = (wxLayoutObjectText *)*i; - String str = tobj->GetText(); - WXL_VAR(m_CursorPosition.x); - str = str.substr(0, cursorOffset); - dc.GetTextExtent(Str(str), &width,&height, &descent); - cursorPosition = wxPoint(position.x+width, - position.y+(baseLineSkip-height)); - cursorSize = wxPoint(1, height); - } - else if(type == WXLO_TYPE_LINEBREAK) - { - WXL_VAR(cursorOffset); - if(cursorOffset) - cursorPosition = wxPoint(0, position.y+baseLineSkip); - else - cursorPosition = wxPoint(0, position.y); - cursorSize = wxPoint(1,baseLineSkip); - - } - else - { - // this is not necessarily the most "beautiful" solution: - //cursorPosition = wxPoint(position.x, position.y); - //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip); - cursorPosition = wxPoint(position.x+size.x, position.y+(size.y-baseLineSkip)); - cursorSize = wxPoint(1, baseLineSkip); - } - } - // calculate next object's position: position.x += size.x; - if(position.x > m_MaxX) - m_MaxX = position.x; - + // do we need to increase the line's height? if(size.y > baseLineSkip) { baseLineSkip = size.y; - recalculate = true; + i = headOfLine; position = position_HeadOfLine; + continue; } if(objBaseLine > baseLine) { baseLine = objBaseLine; - recalculate = true; + i = headOfLine; position = position_HeadOfLine; + continue; } - // now check whether we have finished handling this line: - if(type == WXLO_TYPE_LINEBREAK || i == tail()) + // when we reach here, the coordinates are valid, this part of + // the loop gets run only once per object + if(position.x > m_MaxX) + m_MaxX = position.x; + if(type == WXLO_TYPE_LINEBREAK) { - if(recalculate) // do this line again - { - position.x = position_HeadOfLine.x; - i = headOfLine; - continue; - } - - if(! draw) // finished calculating sizes - { - // if the this line needs to go onto a new page, we need - // to change pages before drawing it: - if(pageNo > 0 && position.y > margins.bottom) - { - currentPage++; - position_HeadOfLine.y = margins.top; - } - if(reallyDraw && (pageNo == -1 || pageNo == currentPage)) - { - // do this line again, this time drawing it - position = position_HeadOfLine; - draw = true; - i = headOfLine; - continue; - } - } - else // we have drawn a line, so continue calculating next one - draw = false; + cursorPos.x = 0; cursorPos.y ++; } - - // is it a linebreak? - if(type == WXLO_TYPE_LINEBREAK || i == tail()) + else + cursorPos.x += (**i).CountPositions(); + + // now check whether we have finished handling this line: + if(type == WXLO_TYPE_LINEBREAK && i != tail()) { position.x = margins.left; position.y += baseLineSkip; @@ -483,18 +389,150 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const headOfLine++; position_HeadOfLine = position; } + if(cursorObject == NULL && cursorPos.y == m_CursorPosition.y) // look for cursor + { + if(cursorPos.x >= m_CursorPosition.x && + m_CursorPosition.x-cursorPos.x+(**i).CountPositions()) // cursor is in current object + { + cursorObject = *i; + CalculateCursor(dc); + } + } + i++; + } + while(i != end()); + m_MaxY = position.y + baseLineSkip; +} + +void +wxLayoutList::Draw(wxDC &dc, + CoordType fromLine, CoordType toLine, + iterator start) +{ + Layout(dc); // FIXME just for now + + ResetSettings(dc); + + wxLayoutObjectList::iterator i; + if(start == iterator(NULL)) + start = begin(); + + while( i != end() && (**i).GetPosition().y < fromLine) i++; + for( i = start ; + i != end() && (toLine == -1 || (**i).GetPosition().y < toLine) ; + i++ ) + (*i)->Draw(dc); +} + +/** Erase at least to end of line */ +void +wxLayoutList::EraseAndDraw(wxDC &dc, iterator start) +{ + //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(); + + WXL_VAR(p.x);WXL_VAR(p.y); + //FIXME: wxGTK: MaxX()/MaxY() broken + //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY()); + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(wxPen(*wxWHITE,0,wxTRANSPARENT)); + dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY()); + Draw(dc,-1,-1,start); + //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY()); +} + + +void +wxLayoutList::CalculateCursor(wxDC &dc) +{ + CoordType width, height, descent; + CoordType baseLineSkip = 20; //FIXME + + CoordType offset; + wxLayoutObjectBase &obj = **FindCurrentObject(&offset); + + WXL_VAR(offset); + DrawCursor(dc,true); // erase it + m_CursorCoords = obj.GetPosition(); + WXL_VAR(m_CursorCoords.x); + if(obj.GetType() == WXLO_TYPE_TEXT) + { + wxLayoutObjectText *tobj = (wxLayoutObjectText *)&obj; + String & str = tobj->GetText(); + String sstr = str.substr(0,offset); + WXL_VAR(sstr); + dc.GetTextExtent(sstr,&width,&height,&descent); + WXL_VAR(width); + m_CursorCoords = wxPoint(m_CursorCoords.x+width, + m_CursorCoords.y); + m_CursorSize = wxPoint(2,height); } - // draw the cursor - if(m_Editable) + else if(obj.GetType() == WXLO_TYPE_LINEBREAK) { - dc.DrawRectangle(cursorPosition.x, cursorPosition.y, - cursorSize.x, cursorSize.y); + m_CursorCoords = wxPoint(0, m_CursorCoords.y); + m_CursorSize = wxPoint(2,baseLineSkip); + } + else + { + // this is not necessarily the most "beautiful" solution: + //cursorPosition = wxPoint(position.x, position.y); + //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip); + m_CursorCoords = wxPoint(m_CursorCoords.x+obj.GetSize().x, m_CursorCoords.y); + m_CursorSize = wxPoint(2, obj.GetSize().y); + if(m_CursorSize.y < 1) m_CursorSize.y = baseLineSkip; + } + WXL_VAR(m_CursorCoords.x); + m_CursorMoved = false; // coords are valid +} + +void +wxLayoutList::DrawCursor(wxDC &dc, bool erase) +{ + + if(erase) + { + //dc.SetBrush(*wxWHITE_BRUSH); + //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID)); + //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y); + dc.Blit(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, + m_CursorSize.y, &m_CursorMemDC, + 0, 0, 0, 0); + } + else + { + if(IsDirty() || CursorMoved()) + { + DrawCursor(dc,true); + Layout(dc); + } + // Save background: + wxBitmap bm(m_CursorSize.x,m_CursorSize.y); + m_CursorMemDC.SelectObject(bm); + m_CursorMemDC.Blit(0, 0, m_CursorSize.x, m_CursorSize.y, + &dc, m_CursorCoords.x, + m_CursorCoords.y, 0, 0); + dc.SetBrush(*wxBLACK_BRUSH); + dc.SetPen(wxPen(*wxBLACK,1,wxSOLID)); + dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, + m_CursorSize.x, m_CursorSize.y); } - m_MaxY = position.y; - return foundObject; } + + + + + + #ifdef WXLAYOUT_DEBUG void wxLayoutList::Debug(void) @@ -571,13 +609,27 @@ wxLayoutObjectList::iterator wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset) { wxPoint object = wxPoint(0,0); // runs along the objects - CoordType width; - wxLayoutObjectList::iterator i; - -#ifdef WXLAYOUT_DEBUG - wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y); -#endif - for(i = begin(); i != end() && object.y <= cpos->y; i++) + CoordType width = 0; + wxLayoutObjectList::iterator i, begin_it; + int go_up; + +//#ifdef WXLAYOUT_DEBUG +// wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y); +//#endif + + // optimisation: compare to last looked at object: + if(cpos->y > m_FoundCursor.y || (cpos->y == m_FoundCursor.y && + cpos->x >= m_FoundCursor.x)) + go_up = 1; + else + go_up = 0; + + //broken at the moment + //begin_it = m_FoundIterator; + //m_FoundCursor = *cpos; + begin_it = begin(); + go_up = 1; + for(i = begin_it; i != end() && object.y <= cpos->y; ) { width = (**i).CountPositions(); if(cpos->y == object.y) // a possible candidate @@ -587,48 +639,52 @@ wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset) if(cpos->x == object.x) { if(offset) *offset = 0; - return i; + return m_FoundIterator = i; } if(offset) *offset=1; cpos->x = object.x; - return i; + return m_FoundIterator = i; } if(cpos->x >= object.x && cpos->x <= object.x+width) // overlap { if(offset) *offset = cpos->x-object.x; -#ifdef WXLAYOUT_DEBUG - wxLayoutDebug(" found object at (%d, %d), type: %s", - object.x, object.y, TypeString((*i)->GetType())); -#endif - return i; +//#ifdef WXLAYOUT_DEBUG +// wxLayoutDebug(" found object at (%d, %d), type: %s", +// object.x, object.y, TypeString((*i)->GetType())); +//#endif + return m_FoundIterator = i; } } -// no overlap, increment coordinates + // no overlap, increment coordinates object.x += width; if((**i).GetType() == WXLO_TYPE_LINEBREAK) { object.x = 0; object.y++; } - } -#ifdef WXLAYOUT_DEBUG - wxLayoutDebug(" not found"); -#endif + if(go_up) + i++; + else + i--; + }//for +//#ifdef WXLAYOUT_DEBUG +// wxLayoutDebug(" not found"); +//#endif // return last object, coordinates of that one: i = tail(); if(i == end()) - return i; + return m_FoundIterator = i; if((**i).GetType()==WXLO_TYPE_LINEBREAK) { if(offset) *offset = 1; - return i; + return m_FoundIterator = i; } cpos->x = object.x; // would be the coordinate of next object cpos->y = object.y; cpos->x += width; // last object's width if(*offset) *offset = cpos->x-object.x; - return i; // not found + return m_FoundIterator = i; // not found } wxLayoutObjectList::iterator @@ -652,6 +708,8 @@ wxLayoutList::MoveCursor(int dx, int dy) CoordType offs, lineLength; wxLayoutObjectList::iterator i; + m_CursorMoved = true; + bool rc = true; // have we moved? if(dy > 0 && m_CursorPosition.y < m_MaxLine) @@ -744,6 +802,8 @@ wxLayoutList::Delete(CoordType count) WXL_VAR(count); + m_bModified = true; + CoordType offs; wxLayoutObjectList::iterator i; @@ -822,11 +882,14 @@ wxLayoutList::Delete(CoordType count) void wxLayoutList::Insert(wxLayoutObjectBase *obj) { - wxASSERT(obj); + wxCHECK_RET( obj, "no object to insert" ); + + m_bModified = true; + CoordType offs; wxLayoutObjectList::iterator i = FindCurrentObject(&offs); - WXL_TRACE(Insert(obj)); +// WXL_TRACE(Insert(obj)); if(i == end()) push_back(obj); @@ -861,6 +924,7 @@ wxLayoutList::Insert(wxLayoutObjectBase *obj) m_CursorPosition.x += obj->CountPositions(); if(obj->GetType() == WXLO_TYPE_LINEBREAK) m_MaxLine++; + m_CursorMoved = true; } void @@ -869,11 +933,13 @@ wxLayoutList::Insert(String const &text) wxLayoutObjectText *tobj = NULL; wxLayoutObjectList::iterator j; - WXL_TRACE(Insert(text)); +// WXL_TRACE(Insert(text)); if(! m_Editable) return; + m_bModified = true; + CoordType offs; wxLayoutObjectList::iterator i = FindCurrentObject(&offs); @@ -923,24 +989,9 @@ wxLayoutList::Insert(String const &text) } } break; -#if 0 - default: - j = i; j--; - WXL_TRACE(checking previous object); - if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT) - { - tobj = (wxLayoutObjectText *)*j; - tobj->GetText()+=text; - } - else // insert a new text object - { - WXL_TRACE(creating new object); - Insert(new wxLayoutObjectText(text)); //FIXME not too optimal, slow - return; // position gets incremented in Insert(obj) - } -#endif } m_CursorPosition.x += strlen(text.c_str()); + m_CursorMoved = true; } CoordType @@ -972,12 +1023,18 @@ void wxLayoutList::Clear(int family, int size, int style, int weight, int underline, char const *fg, char const *bg) { + m_bModified = true; + m_CursorMoved = true; + m_dirty = true; // force redraw/recalc wxLayoutObjectList::iterator i = begin(); + wxBitmap bm(1,1); + m_CursorMemDC.SelectObject(bm); + while(i != end()) // == while valid erase(i); -// set defaults + // set defaults m_FontPtSize = size; m_FontUnderline = false; m_FontFamily = family; @@ -995,9 +1052,13 @@ wxLayoutList::Clear(int family, int size, int style, int weight, m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10; m_MaxX = 0; m_MaxY = 0; + + m_FoundCursor = wxPoint(0,0); + m_FoundIterator = begin(); if(m_DefaultSetting) delete m_DefaultSetting; + m_DefaultSetting = new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle, m_FontWeight,m_FontUnderline, @@ -1005,72 +1066,94 @@ wxLayoutList::Clear(int family, int size, int style, int weight, } +wxLayoutObjectBase * +wxLayoutList::Find(wxPoint coords) const +{ + wxLayoutObjectList::iterator i = begin(); + + wxPoint topleft, bottomright; + + while(i != end()) // == while valid + { + wxLayoutObjectBase *object = *i; + topleft = object->GetPosition(); + if(coords.y >= topleft.y && coords.x >= topleft.x) + { + bottomright = topleft; + bottomright.x += object->GetSize().x; + bottomright.y += object->GetSize().y; + if(coords.x <= bottomright.x && coords.y <= bottomright.y) + return *i; + } + i++; + } + return NULL; +} + /******************** printing stuff ********************/ bool wxLayoutPrintout::OnPrintPage(int page) { - wxDC *dc = GetDC(); - if (dc) - { - m_llist->Draw(*dc,false,wxPoint(0,0),page); - return TRUE; - } - else - return FALSE; + wxDC *dc = GetDC(); + int top, bottom,width,height; + if (dc) + { + dc->GetSize(&width, &height); + + top = (page - 1) * (9*height)/10; + bottom = top + (9*height)/10; + + if( top >= m_llist->GetSize().y) + return false; + m_llist->Draw(*dc,top,bottom); + return true; + } + else + return false; } bool wxLayoutPrintout::OnBeginDocument(int startPage, int endPage) { if (!wxPrintout::OnBeginDocument(startPage, endPage)) - return FALSE; + return false; - return TRUE; + return true; } -void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) +void +wxLayoutPrintout::OnPreparePrinting(void) { + +} + +void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) +{ + // ugly hack to get number of pages + wxPostScriptDC psdc("tmp.ps",false); + int width,height; + psdc.GetSize(&width, &height); // that's all we need it for + + // This code doesn't work, because we don't have a DC yet. // How on earth are we supposed to calculate the number of pages then? - *minPage = 0; // set this to 0 to disable editing of page numbers - *maxPage = 100; - - *selPageFrom = 0; // set this to 0 to hide page number controls - *selPageTo = 100; - -// *minPage = 1; -// *maxPage = 32000; - -// *selPageFrom = 1; -// *selPageTo = 1; -#if 0 - CoordType height; - int pageWidth, pageHeight; - - wxDC *dc = GetDC(); - wxASSERT(dc); - - dc->GetSize(&pageWidth, &pageHeight); -// don't draw but just recalculate sizes: - m_llist->Draw(*dc,false,wxPoint(0,0),-1,false); - m_llist->GetSize(NULL,&height,NULL); - - *minPage = 1; - *maxPage = height/pageHeight+1; + *minPage = 0; + *maxPage = (int)( m_llist->GetSize().y / (float)(0.9*height) + 0.5); *selPageFrom = 1; *selPageTo = *maxPage; + m_maxPage = *maxPage; -#endif } bool wxLayoutPrintout::HasPage(int pageNum) { - return pageNum <= 5; // for testing -// return m_maxPage >= pageNum; + if(m_maxPage != -1) + return pageNum <= m_maxPage; + return true; } diff --git a/user/wxLayout/wxllist.h b/user/wxLayout/wxllist.h index 4916b960b4..512b9117df 100644 --- a/user/wxLayout/wxllist.h +++ b/user/wxLayout/wxllist.h @@ -15,10 +15,10 @@ #include "kbList.h" #include "wx/wx.h" -#include "wx/print.h" -#include "wx/printdlg.h" -#include "wx/generic/printps.h" -#include "wx/generic/prntdlgg.h" +#include "wx/print.h" +#include "wx/printdlg.h" +#include "wx/generic/printps.h" +#include "wx/generic/prntdlgg.h" // skip the following defines if embedded in M application #ifdef M_BASEDIR @@ -30,6 +30,9 @@ # define WXLAYOUT_DEBUG // The wxLayout classes can be compiled with std::string instead of wxString //# define USE_STD_STRING +# define WXMENU_LAYOUT_LCLICK 1111 +# define WXMENU_LAYOUT_RCLICK 1112 +# define WXMENU_LAYOUT_DBLCLICK 1113 #endif #ifdef USE_STD_STRING @@ -62,46 +65,68 @@ class wxFont; class wxLayoutObjectBase { public: + struct UserData + { + virtual ~UserData() { } + }; + /// return the type of this object virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_INVALID; } ; - /** Draws an object. + /** Calculates the position etc 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 - @draw if set to false, do not draw but just calculate sizes */ - virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw = true) {}; + virtual void Layout(wxDC & dc, + wxPoint position, + CoordType baseLine) {} + + /** Draws an object. + @param dc the wxDC to draw on + */ + virtual void Draw(wxDC & dc) {} - /** Calculates and returns the size of the object. May need to be - called twice to work. + /** 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) @return the size of the object's box in pixels */ - virtual wxPoint GetSize(CoordType *baseLine) const { return - wxPoint(0,0); }; + 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; } + /// returns the number of cursor positions occupied by this object virtual CoordType CountPositions(void) const { return 1; } /// constructor wxLayoutObjectBase() { m_UserData = NULL; } - /// note: any user data will be freed at the time the object is deleted - virtual ~wxLayoutObjectBase() { if(m_UserData) delete m_UserData; } + /// delete the user data + virtual ~wxLayoutObjectBase() { 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. */ - void SetUserData(void *data) { m_UserData = data; } + void SetUserData(UserData *data) { m_UserData = data; } /** Return the user data. */ void * GetUserData(void) const { return m_UserData; } + private: /// optional data for application's use - void * m_UserData; + UserData *m_UserData; +protected: + wxPoint m_Position; }; /// Define a list type of wxLayoutObjectBase pointers. @@ -112,44 +137,58 @@ KBLIST_DEFINE(wxLayoutObjectList, wxLayoutObjectBase); class wxLayoutObjectText : public wxLayoutObjectBase { public: + wxLayoutObjectText(const String &txt); + virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_TEXT; } - virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw = true); + virtual void Layout(wxDC &dc, wxPoint position, CoordType baseLine); + virtual void Draw(wxDC &dc); /** 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 wxPoint GetSize(CoordType *baseLine) const; + virtual wxPoint GetSize(CoordType *baseLine = NULL) const; + #ifdef WXLAYOUT_DEBUG virtual void Debug(void); #endif - wxLayoutObjectText(const String &txt); virtual CoordType CountPositions(void) const { return strlen(m_Text.c_str()); } + virtual bool IsDirty(void) const { return m_IsDirty; } // for editing: String & GetText(void) { return m_Text; } void SetText(String const &text) { m_Text = text; } + private: String 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; }; /// icon/pictures: class wxLayoutObjectIcon : public wxLayoutObjectBase { public: - virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_ICON; } - virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw = true); - virtual wxPoint GetSize(CoordType *baseLine) const; wxLayoutObjectIcon(wxIcon *icon); + wxLayoutObjectIcon(wxIcon 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); + + virtual wxPoint GetSize(CoordType *baseLine = NULL) const; + virtual bool IsDirty(void) const { return m_IsDirty; } private: wxIcon *m_Icon; + /// coordinates have changed + bool m_IsDirty; }; /// for export to html: @@ -166,8 +205,8 @@ class wxLayoutObjectCmd : public wxLayoutObjectBase { public: virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_CMD; } - virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw = true); + virtual void Draw(wxDC &dc); + virtual void Layout(wxDC &dc, wxPoint position, CoordType baseLine); wxLayoutObjectCmd(int size, int family, int style, int weight, bool underline, wxColour const *fg, wxColour const *bg); @@ -212,44 +251,76 @@ public: /// adds an object: void AddObject(wxLayoutObjectBase *obj); + /// adds a text object void AddText(String const &txt); - + /// adds a line break void LineBreak(void); + /// sets font parameters void SetFont(int family, int size, int style, int weight, int underline, wxColour const *fg, wxColour const *bg); + /// sets font parameters, colours by name void SetFont(int family=-1, int size = -1, int style=-1, int weight=-1, int underline = -1, - char const *fg = (const char *) NULL, - char const *bg = (const char *) NULL); + char const *fg = NULL, + char const *bg = NULL); + /// set font family inline void SetFontFamily(int family) { SetFont(family); } + /// set font size inline void SetFontSize(int size) { SetFont(-1,size); } + /// set font style inline void SetFontStyle(int style) { SetFont(-1,-1,style); } + /// set font weight inline void SetFontWeight(int weight) { SetFont(-1,-1,-1,weight); } + /// toggle underline flag inline void SetFontUnderline(bool ul) { SetFont(-1,-1,-1,-1,(int)ul); } - inline void SetFontColour(char const *fg, char const *bg = (const char *) NULL) { SetFont(-1,-1,-1,-1,-1,fg,bg); } + /// set font colours by name + inline void SetFontColour(char const *fg, char const *bg = NULL) { SetFont(-1,-1,-1,-1,-1,fg,bg); } - /** Draw the list on a given DC. + /** Re-layouts the list on a DC. @param findObject if true, return the object occupying the position specified by coords @param coords position where to find the object - @pageNo if > 0, print only that page of a document (for + @param pageNo if > 0, print only that page of a document (for printing) - @reallyDraw set this to false if you don't want to draw but just calculate the coordinates + @param reallyDraw set this to false if you don't want to draw but + just calculate the coordinates + @param hasDrawn set to true if a page has been printed @return if findObject == true, the object or NULL */ - wxLayoutObjectBase *Draw(wxDC &dc, bool findObject = false, - wxPoint const &coords = wxPoint(0,0), - int pageNo = -1, bool reallyDraw = true); + void Layout(wxDC &dc); + + /** Draw the list on a given DC. + @param pageNo if > 0, print only that page of a document (for + printing) + */ + void Draw(wxDC &dc, + CoordType fromLine = -1, + CoordType toLine = -1, + iterator start = iterator(NULL)); + /** Deletes at least to the end of line and redraws */ + void EraseAndDraw(wxDC &dc, iterator start = iterator(NULL)); + + /** Finds the object occupying a certain screen position. + @return pointer to wxLayoutObjectBase or NULL if not found + */ + wxLayoutObjectBase *Find(wxPoint coords) const; + #ifdef WXLAYOUT_DEBUG void Debug(void); void ShowCurrentObject(); #endif - + /// dirty? + bool IsDirty() const { return m_bModified; } + bool CursorMoved(void) const { return m_CursorMoved; } + + /// called after the contents is saved, for example + void ResetDirty() { m_bModified = FALSE; } + /// for access by wxLayoutWindow: void GetSize(CoordType *max_x, CoordType *max_y, CoordType *lineHeight); @@ -264,7 +335,13 @@ public: /// 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) { m_CursorPosition = p; } + void DrawCursor(wxDC &dc, bool erase = false); + + /// Get current cursor position cursor coords wxPoint GetCursor(void) const { return m_CursorPosition; } + /// Gets graphical coordinates of cursor + wxPoint GetCursorCoords(void) const { return m_CursorCoords; } + /// delete one or more cursor positions void Delete(CoordType count = 1); void Insert(String const &text); @@ -275,13 +352,15 @@ public: /// return a pointer to the default settings: wxLayoutObjectCmd const *GetDefaults(void) const { return m_DefaultSetting ; } - wxLayoutObjectList::iterator FindCurrentObject(CoordType *offset = (CoordType *) NULL); + wxLayoutObjectList::iterator FindCurrentObject(CoordType *offset = NULL); // 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); } //@} protected: /// font parameters: @@ -296,6 +375,11 @@ protected: /// 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: @@ -308,28 +392,46 @@ protected: CoordType m_MaxY; //---- this is needed for editing: - /// where is the text cursor: + /// where is the text cursor (column,line): wxPoint m_CursorPosition; + /// where to draw the cursor + wxPoint m_CursorCoords; + /// how large to draw it + wxPoint m_CursorSize; + + /// 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 = (CoordType *) NULL); - + wxLayoutObjectList::iterator FindObjectCursor(wxPoint *cpos, CoordType *offset = NULL); +private: + /// Resets the font settings etc to default values + void ResetSettings(wxDC &dc); + /// calculates current cursor coordinates, called in Layout() + void CalculateCursor(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; }; class wxLayoutPrintout: public wxPrintout { public: - wxLayoutPrintout(wxLayoutList &llist, wxString const & title = "My printout"):wxPrintout(title) + wxLayoutPrintout(wxLayoutList &llist, wxString const & title = "My printout") + :wxPrintout(title) { m_llist = &llist; m_maxPage = 0; } - bool OnPrintPage(int page); - bool HasPage(int page); - bool OnBeginDocument(int startPage, int endPage); + bool OnPrintPage(int page); + bool HasPage(int page); + bool OnBeginDocument(int startPage, int endPage); void GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo); + void OnPreparePrinting(void); private: wxLayoutList *m_llist; int m_maxPage; diff --git a/user/wxLayout/wxlparser.cpp b/user/wxLayout/wxlparser.cpp index 2e3f9f54c4..1790088517 100644 --- a/user/wxLayout/wxlparser.cpp +++ b/user/wxLayout/wxlparser.cpp @@ -10,11 +10,28 @@ # pragma implementation "wxlparser.h" #endif -#include "wxllist.h" -#include "wxlparser.h" +//#include "Mpch.h" +#ifdef M_BASEDIR +# include "gui/wxllist.h" +# include "gui/wxlparser.h" +#else +# include "wxllist.h" +# include "wxlparser.h" +#endif #define BASE_SIZE 12 +inline static bool IsEndOfLine(const char *p) +{ + // in addition to Unix EOL convention we also (but not instead) understand + // the DOS one under Windows + return +#ifdef OS_WIN + ((*p == '\r') && (*(p + 1) == '\n')) || +#endif + (*p == '\n'); +} + void wxLayoutImportText(wxLayoutList &list, String const &str) { char * cptr = (char *)str.c_str(); // string gets changed only temporarily @@ -23,15 +40,22 @@ void wxLayoutImportText(wxLayoutList &list, String const &str) for(;;) { - begin = cptr++; - while(*cptr && *cptr != '\n') + begin = cptr; + while( *cptr && !IsEndOfLine(cptr) ) cptr++; backup = *cptr; *cptr = '\0'; list.Insert(begin); *cptr = backup; - if(backup == '\n') + + // check if it's the end of this line + if ( IsEndOfLine(cptr) ) + { + // if it was "\r\n", skip the following '\n' + if ( *cptr == '\r' ) + cptr++; list.LineBreak(); + } else if(backup == '\0') // reached end of string break; cptr++; @@ -168,8 +192,9 @@ String wxLayoutExportCmdAsHTML(wxLayoutObjectCmd const & cmd, *str += '\n'; break; case WXLO_TYPE_CMD: - //wxASSERT(mode == WXLO_EXPORT_AS_HTML,"reached cmd object in text mode") - assert(mode == WXLO_EXPORT_AS_HTML); + wxASSERT_MSG( mode == WXLO_EXPORT_AS_HTML, + "reached cmd object in text mode" ); + *str += wxLayoutExportCmdAsHTML(*(wxLayoutObjectCmd const *)*from, &s_si); break; diff --git a/user/wxLayout/wxlwindow.cpp b/user/wxLayout/wxlwindow.cpp index 57af29d32c..f7f158e334 100644 --- a/user/wxLayout/wxlwindow.cpp +++ b/user/wxLayout/wxlwindow.cpp @@ -10,14 +10,27 @@ # pragma implementation "wxlwindow.h" #endif -#include "wxlwindow.h" +//#include "Mpch.h" -#define VAR(x) cout << #x"=" << x << endl; +#ifdef M_BASEDIR +# ifndef USE_PCH +# include "Mcommon.h" +# include "gui/wxMenuDefs.h" +# endif // USE_PCH +# include "gui/wxlwindow.h" +#else +# include "wxlwindow.h" +# define TRACEMESSAGE(x) +#endif +# define WXL_VAR(x) cerr << #x " = " << x ; BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow) EVT_PAINT (wxLayoutWindow::OnPaint) EVT_CHAR (wxLayoutWindow::OnChar) - EVT_LEFT_DOWN(wxLayoutWindow::OnMouse) + + EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick) + EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick) + EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick) END_EVENT_TABLE() wxLayoutWindow::wxLayoutWindow(wxWindow *parent) @@ -26,7 +39,15 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent) { m_ScrollbarsSet = false; - m_EventId = -1; + m_doSendEvents = false; + m_ViewStartX = 0; m_ViewStartY = 0; + + + 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); + EnableScrolling(true,true); } #ifdef __WXMSW__ @@ -38,34 +59,45 @@ wxLayoutWindow::MSWGetDlgCode() } #endif //MSW +void +wxLayoutWindow::Update(void) +{ + wxClientDC dc(this); + PrepareDC(dc); + if(IsDirty()) + { + DoPaint(dc); + UpdateScrollbars(); + ResetDirty(); + } + m_llist.DrawCursor(dc); +} void -wxLayoutWindow::OnMouse(wxMouseEvent& event) +wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) { + if(!m_doSendEvents) // nothing to do + return; + + wxPaintDC dc( this ); + PrepareDC( dc ); SetFocus(); - if(m_EventId == -1) // nothing to do - return; - - m_FindPos.x = event.GetX(); - m_FindPos.y = event.GetY(); - m_FoundObject = (wxLayoutObjectBase *) NULL; + wxPoint findPos; + findPos.x = dc.DeviceToLogicalX(event.GetX()); + findPos.y = dc.DeviceToLogicalY(event.GetY()); -#ifdef WXLAYOUT_DEBUG - //doesn't work, undefined functions - //wxLogTrace("OnMouse: (%d, %d)", m_FindPos.x, m_FindPos.y); -#endif - Refresh(); - if(m_FoundObject) + TRACEMESSAGE(("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)", + event.GetX(), event.GetY(), findPos.x, findPos.y)); + + // find the object at this position + wxLayoutObjectBase *obj = m_llist.Find(findPos); + if(obj) { - if(m_EventId != -1) - { - wxCommandEvent commandEvent(wxEVENT_TYPE_MENU_COMMAND, m_EventId); - commandEvent.SetEventObject( this ); - commandEvent.SetClientData((char *)m_FoundObject); - m_ClickPosition = wxPoint(event.GetX(), event.GetY()); - GetEventHandler()->ProcessEvent(commandEvent); - } + wxCommandEvent commandEvent(wxEVENT_TYPE_MENU_COMMAND, eventId); + commandEvent.SetEventObject( this ); + commandEvent.SetClientData((char *)obj); + GetEventHandler()->ProcessEvent(commandEvent); } } @@ -112,14 +144,14 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) break; case WXK_END: p = m_llist.GetCursor(); - p.x = m_llist.GetLineLength(m_llist.FindCurrentObject((CoordType *) NULL)); + p.x = m_llist.GetLineLength(m_llist.FindCurrentObject(NULL)); m_llist.SetCursor(p); break; case WXK_DELETE : if(event.ControlDown()) // delete to end of line { help = m_llist.GetLineLength( - m_llist.FindCurrentObject((CoordType *) NULL)) + m_llist.FindCurrentObject(NULL)) - m_llist.GetCursor().x; m_llist.Delete(help ? help : 1); } @@ -127,17 +159,20 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) m_llist.Delete(1); break; case WXK_BACK: // backspace - if(m_llist.MoveCursor(-1)) + if(m_llist.MoveCursor(-1)) { m_llist.Delete(1); + } break; case WXK_RETURN: m_llist.LineBreak(); break; -#ifdef WXLAYOUT_DEBUG + +#ifdef WXLAYOUT_DEBUG case WXK_F1: m_llist.Debug(); break; -#endif +#endif + default: if(keyCode < 256 && keyCode >= 32) { @@ -147,20 +182,75 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) } break; } - Refresh(); - UpdateScrollbars(); + + /** 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(); + int nx = x0, ny = y0; + // when within 10% of borders, scroll to center + if(cc.y > y0+(9*y1)/10) + ny = cc.y - y1/5; + else if (cc.y < y0+y1/10) + { + ny = cc.y-y1/2; + if(ny < 0) ny = 0; + } + if(cc.x > x0+(9*x1)/10) + nx = cc.x - x1/5; + else if (cc.x < x0+x1/10) + { + nx = cc.x-x1/2; + if(nx < 0) nx = 0; + } + Scroll(nx,ny); + + Update(); } void -wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)w) // or: OnDraw(wxDC& dc) +wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc) { - wxPaintDC dc( this ); // only when used as OnPaint for OnDraw we - PrepareDC( dc ); // can skip the first two lines + wxPaintDC dc( this ); + PrepareDC( dc ); + + DoPaint(dc); + +// wxGTK: wxMemoryDC broken? +#if 0 + int x0,y0,x1,y1; + ViewStart(&x0,&y0); + GetSize(&x1,&y1); + WXL_VAR(x0); WXL_VAR(y0); + WXL_VAR(x1); WXL_VAR(y1); + + wxMemoryDC(memdc); + wxBitmap bm(x1,y1); + memdc.SelectObject(bm); + + // make temporary copy and edit this + memdc.SetDeviceOrigin(x0,y0); + memdc.Blit(x0,y0,x1,y1,&dc,x0,y0,wxCOPY,FALSE); + DoPaint(memdc); + // blit it back + dc.Blit(x0,y0,x1,y1,&memdc,x0,y0,wxCOPY,FALSE); +#endif + +} + +// does the actual painting +void +wxLayoutWindow::DoPaint(wxDC &dc) +{ + m_llist.EraseAndDraw(dc); + m_llist.DrawCursor(dc); + // FIXME: not strictly correct, this does only work for changes behind + // the cursor position, not complete redraws - if(m_EventId != -1) // look for keyclicks - m_FoundObject = m_llist.Draw(dc,true,m_FindPos); - else - m_llist.Draw(dc); if(! m_ScrollbarsSet) { m_ScrollbarsSet = true; // avoid recursion @@ -173,17 +263,17 @@ wxLayoutWindow::UpdateScrollbars(void) { CoordType max_x, max_y, lineHeight; - + + ViewStart(&m_ViewStartX, &m_ViewStartY); m_llist.GetSize(&max_x, &max_y, &lineHeight); - SetScrollbars(10, lineHeight, max_x/10+1, max_y/lineHeight+1); - EnableScrolling(true,true); + SetScrollbars(10, lineHeight, max_x/10+1, max_y/lineHeight+1,m_ViewStartX,m_ViewStartY,true); + //EnableScrolling(true,true); + //Scroll(m_ViewStartX, m_ViewStartY); } void wxLayoutWindow::Print(void) { - VAR(wxThePrintSetupData); - wxPostScriptDC dc("layout.ps",true,this); if (dc.Ok() && dc.StartDoc((char *)_("Printing message..."))) { diff --git a/user/wxLayout/wxlwindow.h b/user/wxLayout/wxlwindow.h index 48111825df..0f5c60611f 100644 --- a/user/wxLayout/wxlwindow.h +++ b/user/wxLayout/wxlwindow.h @@ -21,8 +21,14 @@ class wxLayoutWindow : public wxScrolledWindow { public: + /** Constructor. + @param parent parent window to display this panel in + */ wxLayoutWindow(wxWindow *parent); + /* Returns a reference to the wxLayoutList object. + @return the list + */ wxLayoutList & GetLayoutList(void) { return m_llist; } // clears the window and sets default parameters: @@ -32,38 +38,66 @@ public: { GetLayoutList().Clear(family,size,style,weight,underline,fg,bg); SetBackgroundColour( *GetLayoutList().GetDefaults()->GetBGColour()); + + m_bDirty = FALSE; } // callbacks // NB: these functions are used as event handlers and must not be virtual - //void OnDraw(wxDC &dc); - void OnPaint(wxPaintEvent &WXUNUSED(event)); - void OnMouse(wxMouseEvent& event); + void OnPaint(wxPaintEvent &event); + + void OnLeftMouseClick(wxMouseEvent& event) + { OnMouse(WXMENU_LAYOUT_LCLICK, event); } + void OnRightMouseClick(wxMouseEvent& event) + { OnMouse(WXMENU_LAYOUT_RCLICK, event); } + void OnMouseDblClick(wxMouseEvent& event) + { OnMouse(WXMENU_LAYOUT_DBLCLICK, event); } + void OnChar(wxKeyEvent& event); + /// gets called by either Update() or OnPaint() + void DoPaint(wxDC &dc); + #ifdef __WXMSW__ virtual long MSWGetDlgCode(); #endif //MSW void UpdateScrollbars(void); void Print(void); - void SetEventId(int id) { m_EventId = id; } - // what for? Caller doesn't even know object's positions in window - //wxPoint const &GetClickPosition(void) const { return m_ClickPosition; } - virtual ~wxLayoutWindow() {} -private: + + /// if the flag is true, we send events when user clicks on embedded objects + inline void SetMouseTracking(bool doIt = true) { m_doSendEvents = doIt; } + + virtual ~wxLayoutWindow() { } + + // dirty flag access + bool IsDirty() const { return m_llist.IsDirty(); } + void ResetDirty() { m_llist.ResetDirty(); } + + +protected: + /// generic function for mouse events processing + void OnMouse(int eventId, wxMouseEvent& event); + + /// repaint if needed + void Update(void); + /// for sending events wxWindow *m_Parent; - int m_EventId; + bool m_doSendEvents; + /// the layout list to be displayed wxLayoutList m_llist; + /// have we already set the scrollbars? bool m_ScrollbarsSet; - /// if we want to find an object: - wxPoint m_FindPos; - wxLayoutObjectBase *m_FoundObject; - wxPoint m_ClickPosition; + /// Where does the current view start? + int m_ViewStartX; int m_ViewStartY; + + /// do we have unsaved data? + bool m_bDirty; +private: DECLARE_EVENT_TABLE() };