X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/00e0d52a92c9cd868eacfad163b3443d4216ac05..11765138636bade99a104fa6a72ef5ced752b22d:/user/wxLayout/wxllist.cpp diff --git a/user/wxLayout/wxllist.cpp b/user/wxLayout/wxllist.cpp index 6303a07005..69083fdeb5 100644 --- a/user/wxLayout/wxllist.cpp +++ b/user/wxLayout/wxllist.cpp @@ -1,9 +1,9 @@ /*-*- c++ -*-******************************************************** - * wxFTCanvas: a canvas for editing formatted text * + * wxllist: wxLayoutList, a layout engine for text and graphics * * * * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) * * * - * $Id$ * + * $Id$ *******************************************************************/ /* @@ -11,43 +11,88 @@ - the list is responsible for calculating positions - the draw coordinates for each object are the top left corner - coordinates only get calculated when things get redrawn - - during redraw each line gets iterated over twice, first just - calculating baselines and positions, second to actually draw it - - the cursor position is the position before an object, i.e. if the + - The cursor position is the position before an object, i.e. if the buffer starts with a text-object, cursor 0,0 is just before the - first character + first character. For all non-text objects, the cursor positions + are 0==before or 1==behind. So that all non-text objects count as + one cursor position. + - Linebreaks are at the end of a line, that is a line like "abc\n" + is four cursor positions long. This makes sure that cursor + positions are "as expected", i.e. in "abc\ndef" the 'd' would be + at positions (x=0,y=1). + + + The 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" #endif -#include "wxllist.h" -#include "iostream.h" +//#include "Mpch.h" +#ifdef M_PREFIX +# include "gui/wxllist.h" +#else +# include "wxllist.h" +#endif -#include -#include -#include +#ifndef USE_PCH +# include "iostream.h" +# include +# include +# include +# include +#endif #define BASELINESTRETCH 12 -#define VAR(x) cerr << #x"=" << x << endl; -#define DBG_POINT(p) cerr << #p << ": " << p.x << ',' << p.y << endl -#define TRACE(f) cerr << #f":" << endl; +// This should never really get created +#define WXLLIST_TEMPFILE "__wxllist.tmp" #ifdef WXLAYOUT_DEBUG -static const char *_t[] = { "invalid", "text", "cmd", "icon", - "linebreak"}; +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; - cerr << _t[GetType()] << ": size=" << GetSize(&bl).x << "," - << GetSize(&bl).y << " bl=" << bl; + wxLayoutDebug("%s: size = %dx%d, pos=%d,%d, bl = %d", + TypeString(GetType()), GetSize(&bl).x, + GetSize(&bl).y, + GetPosition().x, GetPosition().y, bl); } + +#else +# define WXL_VAR(x) +# define WXL_DBG_POINT(p) +# define WXL_TRACE(f) +# define ShowCurrentObject() +# define TypeString(t) "" +inline void wxLayoutDebug(const char *, ...) { } #endif + //-------------------------- wxLayoutObjectText wxLayoutObjectText::wxLayoutObjectText(const String &txt) @@ -55,6 +100,7 @@ wxLayoutObjectText::wxLayoutObjectText(const String &txt) m_Text = txt; m_Width = 0; m_Height = 0; + m_Position = wxPoint(-1,-1); } @@ -66,21 +112,26 @@ wxLayoutObjectText::GetSize(CoordType *baseLine) const } void -wxLayoutObjectText::Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw) +wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &translate) +{ + dc.DrawText(Str(m_Text), m_Position.x + translate.x, m_Position.y+translate.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); -# 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 @@ -88,31 +139,41 @@ void wxLayoutObjectText::Debug(void) { wxLayoutObjectBase::Debug(); - cerr << " `" << m_Text << '\''; + wxLayoutDebug(" `%s`", m_Text.c_str()); } #endif //-------------------------- wxLayoutObjectIcon +wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon const &icon) +{ + m_Position = wxPoint(-1,-1); + m_Icon = new wxIcon(icon); +} + wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon) { m_Icon = icon; } void -wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint position, CoordType baseLine, - bool draw) +wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &translate) { - position.y += baseLine - m_Icon->GetHeight(); - if(draw) - dc.DrawIcon(m_Icon,position.x,position.y); + dc.DrawIcon(*m_Icon,m_Position.x+translate.x, m_Position.y+translate.y); +} + +void +wxLayoutObjectIcon::Layout(wxDC &dc, wxPoint position, CoordType baseLine) +{ + 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()); } @@ -157,24 +218,32 @@ wxLayoutObjectCmd::GetStyle(void) const } void -wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint position, CoordType lineHeight, - bool draw) +wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const &translate) { wxASSERT(m_font); - // this get called even when draw==false, so that recalculation - // uses right font sizes - dc.SetFont(m_font); + 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,wxPoint(0,0)); +} -//-------------------------- wxwxLayoutList +//-------------------------- wxLayoutList wxLayoutList::wxLayoutList() { m_DefaultSetting = NULL; + m_WrapMargin = -1; + m_Editable = FALSE; + m_boldCursor = FALSE; + Clear(); } @@ -182,14 +251,13 @@ wxLayoutList::~wxLayoutList() { if(m_DefaultSetting) delete m_DefaultSetting; + // no deletion of objects, they are owned by the list } - void wxLayoutList::LineBreak(void) { Insert(new wxLayoutObjectLineBreak); - m_CursorPosition.x = 0; m_CursorPosition.y++; } void @@ -201,7 +269,7 @@ wxLayoutList::SetFont(int family, int size, int style, int weight, if(size != -1) m_FontPtSize = size; if(style != -1) m_FontStyle = style; if(weight != -1) m_FontWeight = weight; - if(underline != -1) m_FontUnderline = underline; + if(underline != -1) m_FontUnderline = underline != 0; if(fg != NULL) m_ColourFG = fg; if(bg != NULL) m_ColourBG = bg; @@ -214,6 +282,7 @@ wxLayoutList::SetFont(int family, int size, int style, int weight, void wxLayoutList::SetFont(int family, int size, int style, int weight, int underline, char const *fg, char const *bg) + { wxColour const * cfg = NULL, @@ -233,228 +302,100 @@ void wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y, CoordType *lineHeight) { - wxASSERT(max_x); wxASSERT(max_y); wxASSERT(lineHeight); - *max_x = m_MaxX; - *max_y = m_MaxY; - *lineHeight = m_LineHeight; + + if(max_x) *max_x = m_MaxX; + if(max_y) *max_y = m_MaxY; + if(lineHeight) *lineHeight = m_LineHeight; } -wxLayoutObjectBase * -wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords) +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,wxPoint(0,0)); +} + +void +wxLayoutList::Layout(wxDC &dc, wxLayoutMargins *margins) +{ + 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; - - // we trace the objects' cursor positions so we can draw the cursor - wxPoint cursor = wxPoint(0,0); - // the cursor position inside the object - CoordType cursorOffset = 0; - // object under cursor - wxLayoutObjectList::iterator cursorObject = FindCurrentObject(&cursorOffset); - - // queried from each object: - wxPoint size = wxPoint(0,0); - CoordType objBaseLine = baseLine; + 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; - - if( -#ifdef __WXMSW__ - dc.IsKindOf(CLASSINFO(wxPrinterDC)) || -#endif - dc.IsKindOf(CLASSINFO(wxPostScriptDC))) + + // we need to count cursor positions + wxPoint cursorPos = wxPoint(0,0); + + if(margins) { - VAR(wxThePrintSetupData); - - dc.GetSize(&pageWidth, &pageHeight); - dc.StartDoc(_("Printing...")); - dc.StartPage(); - margins.top = (1*pageHeight)/10; // 10% - margins.bottom = (9*pageHeight)/10; // 90% - margins.left = (1*pageWidth)/10; - margins.right = (9*pageWidth)/10; + position.y = margins->top; + position.x = margins->left; } else { - margins.top = 0; margins.left = 0; - margins.right = -1; - margins.bottom = -1; + position.y = 0; + position.x = 0; } - position.y = margins.right; - position.x = margins.left; - VAR(findObject); VAR(findCoords.x); VAR(findCoords.y); - // 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(); - 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); - dc.SetBackground( wxBrush(* m_DefaultSetting->GetBGColour(),wxSOLID)); - } - else - dc.SetBackground( wxBrush(wxColour("White"), wxSOLID) ); - - dc.Clear(); - - + ResetSettings(dc); - // we calculate everything for drawing a line, then rewind to the - // begin of line and actually draw it i = begin(); - for(;;) - { - recalculate = false; + headOfLine = i; + position_HeadOfLine = position; + do + { if(i == end()) - break; + return; + type = (*i)->GetType(); - - // to initialise sizes of objects, we need to call Draw - (*i)->Draw(dc, position, baseLine, draw); - - // 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) - { - if(type == WXLO_TYPE_TEXT) // special treatment - { - long descent = 0l; long width, height; - tobj = (wxLayoutObjectText *)*i; - String str = tobj->GetText(); - VAR(m_CursorPosition.x); VAR(cursor.x); - str = str.substr(0, cursorOffset); - VAR(str); - dc.GetTextExtent(Str(str), &width,&height, &descent); - VAR(height); - VAR(width); VAR(descent); - dc.DrawLine(position.x+width, - position.y+(baseLineSkip-height), - position.x+width, position.y+baseLineSkip); - } - else - { - if(type == WXLO_TYPE_LINEBREAK) - dc.DrawLine(0, position.y+baseLineSkip, 0, position.y+2*baseLineSkip); - else - { - if(size.x == 0) - { - if(size.y == 0) - dc.DrawLine(position.x, position.y, position.x, position.y+baseLineSkip); - else - dc.DrawLine(position.x, position.y, position.x, position.y+size.y); - } - else - dc.DrawRectangle(position.x, position.y, size.x, size.y); - } - } - } - // calculate next object's position: position.x += size.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(margins.bottom != -1 && position.y > margins.bottom) - { - dc.EndPage(); - position_HeadOfLine.y = margins.top; - dc.StartPage(); - } - // 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 ++; } - - if(position.x+size.x > m_MaxX) - m_MaxX = position.x+size.x; - // 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.x = margins ? margins->left : 0; position.y += baseLineSkip; baseLine = m_FontPtSize; objBaseLine = baseLine; // not all objects set it @@ -463,379 +404,736 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords) headOfLine++; position_HeadOfLine = position; } + if(i == m_CursorObject) + CalculateCursor(dc); i++; } - dc.EndDoc(); - m_MaxY = position.y; - return foundObject; + while(i != end()); + m_MaxY = position.y + baseLineSkip; } -#ifdef WXLAYOUT_DEBUG void -wxLayoutList::Debug(void) +wxLayoutList::Draw(wxDC &dc, + CoordType fromLine, CoordType toLine, + iterator start, + wxPoint const &translate) { - CoordType offs; - wxLayoutObjectList::iterator i; + //Layout(dc); // FIXME just for now - cerr << - "------------------------debug start-------------------------" << endl; - for(i = begin(); i != end(); i++) + ResetSettings(dc); + + wxLayoutObjectList::iterator i; + + if(start == iterator(NULL)) + start = begin(); + else // we need to restore font settings { - (*i)->Debug(); - cerr << endl; + for( i = begin() ; i != start; i++) + if((**i).GetType() == WXLO_TYPE_CMD) + (**i).Draw(dc,translate); // apply font settings } - cerr << - "-----------------------debug end----------------------------" - << endl; - // show current object: - cerr << "Cursor: " - << m_CursorPosition.x << ',' - << m_CursorPosition.y; + + while( start != end() && (**start).GetPosition().y < fromLine) + { + if((**start).GetType() == WXLO_TYPE_CMD) + (**start).Draw(dc,translate); // apply font settings + start++; + } + for( i = start ; + i != end() && (toLine == -1 || (**i).GetPosition().y < toLine) ; + i++ ) + (*i)->Draw(dc,translate); +} + +/** Erase at least to end of line */ +void +wxLayoutList::EraseAndDraw(wxDC &dc, iterator start, wxPoint const &translate) +{ + //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; - i = FindCurrentObject(&offs); - cerr << " line length: " << GetLineLength(i) << " "; - if(i == end()) + wxPoint p = (**start).GetPosition(); + + //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()); +} + + +void +wxLayoutList::CalculateCursor(wxDC &dc) +{ + if(! m_CursorMoved) + return; + + CoordType width, height, descent; + CoordType baseLineSkip = 20; //FIXME + + int cursorWidth = m_boldCursor ? 4 : 2; + + if( m_CursorObject == iterator(NULL)) // empty list { - cerr << "<>" << endl; - return; // FIXME we should set cursor position to maximum allowed - // value then + m_CursorCoords = wxPoint(0,0); + m_CursorSize = wxPoint(cursorWidth,baseLineSkip); + m_CursorMoved = false; // coords are valid + return; } - if((*i)->GetType() == WXLO_TYPE_TEXT) + wxLayoutObjectBase &obj = **m_CursorObject; + + m_CursorCoords = obj.GetPosition(); + if(obj.GetType() == WXLO_TYPE_TEXT) { - cerr << " \"" << ((wxLayoutObjectText *)(*i))->GetText() << "\", offs: " - << offs << endl; + 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) + { + if(m_CursorOffset == 1) // behind linebreak + m_CursorCoords = wxPoint(0, m_CursorCoords.y + baseLineSkip); + //m_CursorCoords = wxPoint(0, m_CursorCoords.y); + m_CursorSize = wxPoint(cursorWidth,baseLineSkip); } else - cerr << ' ' << _t[(*i)->GetType()] << endl; - + { + // 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_CursorMoved = false; // coords are valid } + +void +wxLayoutList::DrawCursor(wxDC &dc, bool erase, wxPoint const &translate) +{ + if(! m_Editable) + return; + + 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 + { + // 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); + } +} -/******************** editing stuff ********************/ -wxLayoutObjectList::iterator -wxLayoutList::FindObjectCursor(wxPoint const &cpos, CoordType *offset) + + + + + +#ifdef WXLAYOUT_DEBUG +void +wxLayoutList::Debug(void) { - wxPoint cursor = wxPoint(0,0); // runs along the objects - CoordType width; wxLayoutObjectList::iterator i; -#ifdef WXLAYOUT_DEBUG - cerr << "Looking for object at " << cpos.x << ',' << cpos.y << - endl; + wxLayoutDebug("------------------------ debug start ------------------------"); + for(i = begin(); i != end(); i++) + (*i)->Debug(); + wxLayoutDebug("-------------------------- list end -------------------------"); + + // show current object: + ShowCurrentObject(); + wxLayoutDebug("------------------------- debug end -------------------------"); +} + +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((*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())); + } + wxLayoutDebug("Line length: %d", GetLineLength(m_CursorObject)); + +} + #endif - for(i = begin(); i != end() && cursor.y <= cpos.y; i++) + +/******************** 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; ) { - width = 0; - if((*i)->GetType() == WXLO_TYPE_LINEBREAK) + width = (**i).CountPositions(); + if(cpos->y == object.y) // a possible candidate { - if(cpos.y == cursor.y) + if((**i).GetType() ==WXLO_TYPE_LINEBREAK) { - --i; - if(offset) - *offset = (*i)->CountPositions(); - return i; + if(cpos->x == object.x) + { + if(offset) *offset = 0; + return m_FoundIterator = i; + } + if(offset) *offset=1; + cpos->x = object.x; + 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 m_FoundIterator = i; } - cursor.x = 0; cursor.y ++; } - else - cursor.x += (width = (*i)->CountPositions()); - if(cursor.y == cpos.y && (cursor.x > cpos.x || - ((*i)->GetType() != WXLO_TYPE_CMD && cursor.x == cpos.x)) - ) // found it ? + // no overlap, increment coordinates + object.x += width; + if((**i).GetType() == WXLO_TYPE_LINEBREAK) { - if(offset) - *offset = cpos.x-(cursor.x-width); // 0==cursor before - // the object -#ifdef WXLAYOUT_DEBUG - cerr << " found object at " << cursor.x-width << ',' << - cursor.y << ", type:" << _t[(*i)->GetType()] <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 } -wxLayoutObjectList::iterator -wxLayoutList::FindCurrentObject(CoordType *offset) +bool +wxLayoutList::MoveCursor(int dx, int dy) { - wxLayoutObjectList::iterator obj = end(); + CoordType diff; - obj = FindObjectCursor(m_CursorPosition, offset); - if(obj == end()) // not ideal yet + 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; + + if(newPos.y > m_CursorPos.y || + newPos.y == m_CursorPos.y && + newPos.x >= m_CursorPos.x) + direction = down; + else + direction = up; + + if ( !m_CursorObject ) { - obj = tail(); - if(obj != end()) // tail really exists - *offset = (*obj)->CountPositions(); // at the end of it + // list is empty + return FALSE; } - return obj; -} - -void -wxLayoutList::MoveCursor(int dx, int dy) -{ - CoordType offs, lineLength; - wxLayoutObjectList::iterator i; + // now move cursor forwards until at the new position: - if(dy > 0 && m_CursorPosition.y < m_MaxLine) - m_CursorPosition.y += dy; - else if(dy < 0 && m_CursorPosition.y > 0) - m_CursorPosition.y += dy; // dy is negative - if(m_CursorPosition.y < 0) - m_CursorPosition.y = 0; - else if (m_CursorPosition.y > m_MaxLine) - m_CursorPosition.y = m_MaxLine; - - while(dx > 0) + // first, go to the right line: + while(newPos.y != m_CursorPos.y) { - i = FindCurrentObject(&offs); - lineLength = GetLineLength(i); - if(m_CursorPosition.x < lineLength) + if(direction == down) { - m_CursorPosition.x ++; - dx--; - continue; + m_CursorPos.x += + (**m_CursorObject).CountPositions() - m_CursorOffset; + if(m_CursorObject == tail()) + break; // can't go any further + if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK + && m_CursorOffset == 0) + { + m_CursorPos.y++; m_CursorPos.x = 0; + } + m_CursorObject ++; m_CursorOffset = 0; } - else + else // up { - if(m_CursorPosition.y < m_MaxLine) + if(m_CursorObject == begin()) + break; // can't go any further + + if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK && + m_CursorOffset == 1) { - m_CursorPosition.y++; - m_CursorPosition.x = 0; - dx--; + m_CursorPos.y--; + m_CursorPos.x = GetLineLength(m_CursorObject); } - else - break; // cannot move there + m_CursorPos.x -= m_CursorOffset; + m_CursorObject --; m_CursorOffset = (**m_CursorObject).CountPositions(); } } - while(dx < 0) + if(newPos.y != m_CursorPos.y) // reached begin/end of list, + newPos.y = m_CursorPos.y; // exited by break + + // now line is right, go to right column: + if(dx == 0) // we are moving up or down only { - if(m_CursorPosition.x > 0) + int max_x = GetLineLength(m_CursorObject); + if(max_x <= newPos.x) // ... so we don't want to cross linebreaks + newPos.x = max_x-1; // but just go to the right column + } + direction = newPos.x >= m_CursorPos.x ? down : up; + while(newPos.x != m_CursorPos.x) + { + if(direction == down) { - m_CursorPosition.x --; - dx++; + diff = newPos.x - m_CursorPos.x; + if(diff > (**m_CursorObject).CountPositions()-m_CursorOffset) + { + m_CursorPos.x += + (**m_CursorObject).CountPositions()-m_CursorOffset; + if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK && + m_CursorOffset == 0) + m_CursorPos = wxPoint(0, m_CursorPos.y+1); + if(m_CursorObject == tail()) + break; // cannot go further + m_CursorObject++; m_CursorOffset = 0; + } + else + { + if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK) + { + newPos.y++; newPos.x -= m_CursorPos.x+1; + m_CursorPos = wxPoint(0,m_CursorPos.y+1); + } + else + m_CursorPos.x += diff; + m_CursorOffset += diff; + } } - else + else // up { - if(m_CursorPosition.y > 0) + if(m_CursorPos.x == 0 && m_CursorOffset == 1 && + (**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK) // can we go further up? { - m_CursorPosition.y --; - m_CursorPosition.x = 0; - i = FindCurrentObject(&offs); - lineLength = GetLineLength(i); - m_CursorPosition.x = lineLength; - dx++; + m_CursorPos.y--; + newPos.y--; + m_CursorOffset = 0; + m_CursorPos.x = GetLineLength(m_CursorObject)-1; + newPos.x += m_CursorPos.x+1; continue; } + diff = m_CursorPos.x - newPos.x; + if(diff >= m_CursorOffset) + { + if(m_CursorObject == begin()) + { + m_CursorOffset = 0; + m_CursorPos.x = 0; + break; // cannot go further + } + m_CursorObject--; + m_CursorPos.x -= m_CursorOffset; + m_CursorOffset = (**m_CursorObject).CountPositions(); + } else - break; // cannot move left any more + { + m_CursorPos.x -= diff; + m_CursorOffset -= diff; + } } } - // final adjustment: - i = FindCurrentObject(&offs); - lineLength = GetLineLength(i); - if(m_CursorPosition.x > lineLength) - m_CursorPosition.x = lineLength; - -#ifdef WXLAYOUT_DEBUG - i = FindCurrentObject(&offs); - cerr << "Cursor: " - << m_CursorPosition.x << ',' - << m_CursorPosition.y; - if(i == end()) - { - cerr << "<>" << endl; - return; // FIXME we should set cursor position to maximum allowed - // value then - } - if((*i)->GetType() == WXLO_TYPE_TEXT) - { - cerr << " \"" << ((wxLayoutObjectText *)(*i))->GetText() << "\", offs: " - << offs << endl; - } - else - cerr << ' ' << _t[(*i)->GetType()] << endl; -#endif + return true; // FIXME: when return what? +} +void +wxLayoutList::SetCursor(wxPoint const &p) +{ + m_CursorPos = p; + m_CursorObject = FindObjectCursor(&m_CursorPos, &m_CursorOffset); + m_CursorMoved = true; } void wxLayoutList::Delete(CoordType count) { - TRACE(Delete); + WXL_TRACE(Delete); if(!m_Editable) return; - VAR(count); - - CoordType offs, len; + m_bModified = true; + + CoordType offs = 0; wxLayoutObjectList::iterator i; do { - i = FindCurrentObject(&offs); + i = m_CursorObject; + startover: // ugly, but easiest way to do it if(i == end()) - return; -#ifdef WXLAYOUT_DEBUG - cerr << "trying to delete: " << _t[(*i)->GetType()] << endl; -#endif + 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) - m_MaxLine--; - if((*i)->GetType() == WXLO_TYPE_TEXT) + { + 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; - 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(offs == len) + 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++; - if((*i)->GetType() == WXLO_TYPE_TEXT) - { - offs = 0; // delete from begin of next string - tobj = (wxLayoutObjectText *)*i; - len = tobj->CountPositions(); - } - else + m_CursorOffset = 0; + goto startover; + } + else + { + if(m_CursorOffset == 0 && len <= count) // delete this object { + count -= len; erase(i); - return; + 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 } - if(len <= count) // delete this object + } + 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 -= len; - erase(i); + 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 + else // delete the following object { - len = count; - VAR(offs); VAR(len); - tobj->GetText().erase(offs,len); - return; // we are done + i++; // we increment and continue as normal + m_CursorOffset=0; + goto startover; } } - else // delete the object - { - len = (*i)->CountPositions(); - erase(i); // after this, i is the iterator for the following object - if(count > len) - count -= len; - else - count = 0; - } } while(count && i != end()); } + void wxLayoutList::Insert(wxLayoutObjectBase *obj) { - wxASSERT(obj); - CoordType offs; - wxLayoutObjectList::iterator i = FindCurrentObject(&offs); + wxCHECK_RET( obj, "no object to insert" ); + + m_bModified = true; - TRACE(Insert(obj)); + wxLayoutObjectList::iterator i = m_CursorObject; + if(i != iterator(NULL) && (*obj).GetType() == WXLO_TYPE_LINEBREAK) + { + m_CursorPos.x = 0; m_CursorPos.y ++; + } + if(i == end()) + { push_back(obj); + m_CursorObject = tail(); + } + else if(m_CursorOffset == 0) + { + insert(i,obj); + m_CursorObject = i; + } + // do we have to split a text object? + else if((*i)->GetType() == WXLO_TYPE_TEXT && m_CursorOffset != (*i)->CountPositions()) + { + wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i; + String left = tobj->GetText().substr(0,m_CursorOffset); // get part before cursor + tobj->GetText() = tobj->GetText().substr(m_CursorOffset,(*i)->CountPositions()-m_CursorOffset); // keeps the right half + insert(i,obj); + m_CursorObject = i; // == obj + insert(i,new wxLayoutObjectText(left)); // inserts before + } else - { - // do we have to split a text object? - if((*i)->GetType() == WXLO_TYPE_TEXT && offs != 0 && offs != (*i)->CountPositions()) + { + // all other cases, append after object: + wxLayoutObjectList::iterator j = i; // we want to apend after this object + j++; + if(j != end()) { - wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i; -#ifdef WXLAYOUT_DEBUG - cerr << "text: '" << tobj->GetText() << "'" << endl; - VAR(offs); -#endif - String left = tobj->GetText().substr(0,offs); // get part before cursor - VAR(left); - tobj->GetText() = tobj->GetText().substr(offs,(*i)->CountPositions()-offs); // keeps the right half - VAR(tobj->GetText()); - insert(i,obj); - insert(i,new wxLayoutObjectText(left)); // inserts before + insert(j, obj); + m_CursorObject = j; } else { - wxLayoutObjectList::iterator j = i; // we want to apend after this object - j++; - if(j != end()) - insert(j, obj); - else - push_back(obj); - } + push_back(obj); + m_CursorObject = tail(); + } } - m_CursorPosition.x += obj->CountPositions(); + + 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) { wxLayoutObjectText *tobj = NULL; - TRACE(Insert(text)); + wxLayoutObjectList::iterator j; + +// WXL_TRACE(Insert(text)); if(! m_Editable) return; - CoordType offs; - wxLayoutObjectList::iterator i = FindCurrentObject(&offs); + m_bModified = true; - if(i != end() && (*i)->GetType() == WXLO_TYPE_TEXT) - { // insert into an existing text object: - TRACE(inserting into existing object); - tobj = (wxLayoutObjectText *)*i ; - wxASSERT(tobj); - tobj->GetText().insert(offs,text); + wxLayoutObjectList::iterator i = m_CursorObject; + + if(i == end()) + { + Insert(new wxLayoutObjectText(text)); + return; } - else // check whether the previous object is text: + + switch((**i).GetType()) { - wxLayoutObjectList::iterator j = i; - j--; - TRACE(checking previous object); - if(0 && j != end() && (*j)->GetType() == WXLO_TYPE_TEXT) + 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 { - tobj = (wxLayoutObjectText *)*i; - wxASSERT(tobj); - tobj->GetText()+=text; + j--; + if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT) + { + tobj = (wxLayoutObjectText *)*j; + tobj->GetText()+=text; + m_CursorObject = j; + m_CursorOffset = (**j).CountPositions(); + m_CursorPos.x += text.length(); + } + else + { + insert(i,new wxLayoutObjectText(text)); + m_CursorObject = i; + m_CursorOffset = (**i).CountPositions(); + m_CursorPos.x += m_CursorOffset; + } } - else // insert a new text object + else // offset == 1 : cursor after linebreak { - TRACE(creating new object); - Insert(new wxLayoutObjectText(text)); //FIXME not too optimal, slow - return; // position gets incremented in Insert(obj) + j++; + m_CursorObject = j; + m_CursorOffset = 0; + if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT) + { + tobj = (wxLayoutObjectText *)*j; + tobj->GetText()=text+tobj->GetText(); + m_CursorOffset = text.length(); + m_CursorPos.x += m_CursorOffset; + } + else + { + if(j == end()) + { + push_back(new wxLayoutObjectText(text)); + m_CursorObject = tail(); + m_CursorOffset = (**m_CursorObject).CountPositions(); + m_CursorPos.x += text.length(); + } + else + { + insert(j,new wxLayoutObjectText(text)); + m_CursorObject = j; + m_CursorOffset = (**j).CountPositions(); + m_CursorPos.x += text.length(); + } + } } + break; } - m_CursorPosition.x += strlen(text.c_str()); + m_CursorMoved = true; } CoordType -wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i) +wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs) { if(i == end()) return 0; CoordType len = 0; - // search backwards for beginning of line: + 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: +// now we can start counting: while(i != end() && (*i)->GetType() != WXLO_TYPE_LINEBREAK) { len += (*i)->CountPositions(); i++; } + len++; // one extra for the linebreak return len; } @@ -843,8 +1141,14 @@ 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(4,4); + m_CursorMemDC.SelectObject(bm); + while(i != end()) // == while valid erase(i); @@ -857,17 +1161,245 @@ wxLayoutList::Clear(int family, int size, int style, int weight, m_ColourFG = wxTheColourDatabase->FindColour(fg); m_ColourBG = wxTheColourDatabase->FindColour(bg); + if(! m_ColourFG) m_ColourFG = wxBLACK; + if(! m_ColourBG) m_ColourBG = wxWHITE; + m_Position = wxPoint(0,0); - m_CursorPosition = wxPoint(0,0); + m_CursorPos = wxPoint(0,0); + m_CursorObject = iterator(NULL); + m_CursorOffset = 0; + m_CursorSize = wxPoint(2,(BASELINESTRETCH*m_FontPtSize)/10); + m_MaxLine = 0; m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10; m_MaxX = 0; m_MaxY = 0; + + 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, m_ColourFG, m_ColourBG); } + + +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; +} + + +void +wxLayoutList::SetWrapMargin(long n) +{ + m_WrapMargin = n; +} + +void +wxLayoutList::WrapLine(void) +{ + wxASSERT(m_CursorObject); + + iterator i = m_CursorObject; + + if(!DoWordWrap() || !i ) // empty list + return; + int cursorpos = m_CursorPos.x, cpos, offset; + + if(cursorpos < m_WrapMargin) + return; + + // else: break line + + // find the right object to break: + // is it the current one? + + i = m_CursorObject; + cpos = cursorpos-m_CursorOffset; + while(i != begin() && cpos >= m_WrapMargin) + { + i--; + cpos -= (**i).CountPositions(); + } + // now i is the object to break and cpos its position + + offset = m_WrapMargin - cpos; + wxASSERT(offset <= (**i).CountPositions()); + + // split it + if((**i).GetType() == WXLO_TYPE_TEXT) + { + wxLayoutObjectText &t = *(wxLayoutObjectText *)*i; + for(; offset > 0; offset--) + if(t.GetText().c_str()[offset] == ' ' || t.GetText().c_str()[offset] == '\t') + { + String left = t.GetText().substr(0,offset); // get part before cursor + t.GetText() = t.GetText().substr(offset+1,t.CountPositions()-offset-1); // keeps the right halve + insert(i,new wxLayoutObjectLineBreak); + insert(i,new wxLayoutObjectText(left)); // inserts before + break; + } + if(offset == 0) + { + // only insert a line break if there isn't already one + iterator j = i; j--; + if(j && j != begin() && (**j).GetType() != WXLO_TYPE_LINEBREAK) + insert(i,new wxLayoutObjectLineBreak); + else + return; // do nothing + } + } + else + insert(i,new wxLayoutObjectLineBreak); + m_MaxLine++; + m_CursorPos.y++; + m_CursorPos.x -= offset; + m_CursorOffset -= offset; +} +/******************** printing stuff ********************/ + +wxLayoutPrintout::wxLayoutPrintout(wxLayoutList &llist, + wxString const & title) +:wxPrintout(title) +{ + m_llist = &llist; + m_title = title; +} + +bool wxLayoutPrintout::OnPrintPage(int page) +{ + wxDC *dc = GetDC(); + 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); + 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 +#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; + + // 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; + + m_NumOfPages = (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight) + 0.5); + *minPage = 1; + *maxPage = m_NumOfPages; + + *selPageFrom = 1; + *selPageTo = m_NumOfPages; + wxRemoveFile(WXLLIST_TEMPFILE); +} + +bool wxLayoutPrintout::HasPage(int pageNum) +{ + return pageNum <= m_NumOfPages; +} + + +void +wxLayoutPrintout::DrawHeader(wxDC &dc, + wxPoint topleft, wxPoint bottomright, + int pageno) +{ + // make backups of all essential parameters + const wxBrush& brush = dc.GetBrush(); + const wxPen& pen = dc.GetPen(); + const wxFont& font = dc.GetFont(); + + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(wxPen(*wxBLACK,0,wxSOLID)); + dc.DrawRoundedRectangle(topleft.x, + topleft.y,bottomright.x-topleft.x, + bottomright.y-topleft.y); + dc.SetBrush(*wxBLACK_BRUSH); + wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10, + wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica"); + dc.SetFont(myfont); + + wxString page; + page = "9999/9999 "; // many pages... + long w,h; + dc.GetTextExtent(page,&w,&h); + page.Printf("%d/%d", pageno, (int) m_NumOfPages); + dc.DrawText(page,bottomright.x-w,topleft.y+h/2); + dc.GetTextExtent("XXXX", &w,&h); + dc.DrawText(m_title, topleft.x+w,topleft.y+h/2); + + // restore settings + dc.SetPen(pen); + dc.SetBrush(brush); + dc.SetFont(font); +} + + +wxLayoutPrintout * +wxLayoutList::MakePrintout(wxString const &name) +{ + return new wxLayoutPrintout(*this,name); +}