1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
14 #pragma implementation "wxllist.h"
20 #include "wx/wxprec.h"
26 # include "gui/wxllist.h"
32 # include "iostream.h"
35 # include <wx/print.h>
41 /// This should never really get created
42 #define WXLLIST_TEMPFILE "__wxllist.tmp"
46 # define TypewxString(t) g_aTypewxStrings[t]
47 # define WXLO_DEBUG(x) wxLogDebug x
49 static const char *g_aTypewxStrings
[] =
51 "invalid", "text", "cmd", "icon"
54 wxLayoutObject::Debug(void)
56 WXLO_DEBUG(("%s",g_aTypewxStrings
[GetType()]));
59 # define TypewxString(t) ""
60 # define WXLO_DEBUG(x)
64 /// Cursors smaller than this disappear in XOR drawing mode
65 #define WXLO_MINIMUM_CURSOR_WIDTH 4
67 /// Use this character to estimate a cursor size when none is available.
68 #define WXLO_CURSORCHAR "E"
69 /** @name Helper functions */
71 /// allows me to compare to wxPoints
72 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
74 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
77 /// allows me to compare to wxPoints
78 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
80 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
83 /// allows me to compare to wxPoints
84 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
86 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
89 /// grows a wxRect so that it includes the given point
92 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
96 else if(r
.x
+ r
.width
< x
)
101 else if(r
.y
+ r
.height
< y
)
105 /// returns true if the point is in the rectangle
107 bool Contains(const wxRect
&r
, const wxPoint
&p
)
109 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
115 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
119 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
121 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
131 wxLayoutObjectText::Copy(void)
133 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
134 obj
->m_Width
= m_Width
;
135 obj
->m_Height
= m_Height
;
137 obj
->m_Bottom
= m_Bottom
;
138 obj
->SetUserData(m_UserData
);
143 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
146 *top
= m_Top
; *bottom
= m_Bottom
;
147 return wxPoint(m_Width
, m_Height
);
151 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
152 wxLayoutList
*wxllist
,
153 CoordType begin
, CoordType end
)
156 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
159 // highlight the bit between begin and len
163 ypos
= coords
.y
-m_Top
;
164 long width
, height
, descent
;
166 str
= m_Text
.Mid(0, begin
);
167 dc
.DrawText(str
, xpos
, ypos
);
168 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
170 wxllist
->StartHighlighting(dc
);
171 str
= m_Text
.Mid(begin
, end
-begin
);
172 dc
.DrawText(str
, xpos
, ypos
);
173 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
175 wxllist
->EndHighlighting(dc
);
176 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
177 dc
.DrawText(str
, xpos
, ypos
);
182 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
186 maxlen
= m_Text
.Length();
189 height
, descent
= 0l;
191 if(xpos
== 0) return 0; // easy
193 while(width
< xpos
&& offs
< maxlen
)
195 dc
.GetTextExtent(m_Text
.substr(0,offs
),
196 &width
, &height
, &descent
);
199 /* We have to substract 1 to compensate for the offs++, and another
200 one because we don't want to position the cursor behind the
201 object what we clicked on, but before - otherwise it looks
203 return (xpos
> 2) ? offs
-2 : 0;
207 wxLayoutObjectText::Layout(wxDC
&dc
)
211 dc
.GetTextExtent(m_Text
,&m_Width
, &m_Height
, &descent
);
213 m_Top
= m_Height
- m_Bottom
;
216 #ifdef WXLAYOUT_DEBUG
218 wxLayoutObjectText::Debug(void)
220 wxLayoutObject::Debug();
221 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
225 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
229 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
231 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
233 m_Icon
= new wxBitmap(icon
);
237 wxLayoutObjectIcon::Copy(void)
239 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
241 obj
->SetUserData(m_UserData
);
245 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
251 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
252 wxLayoutList
*wxllist
,
253 CoordType begin
, CoordType
/* len */)
255 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
256 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
260 wxLayoutObjectIcon::Layout(wxDC
& /* dc */)
265 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
267 *top
= m_Icon
->GetHeight();
269 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
274 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
278 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
280 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
281 weight
, bool underline
,
282 wxColour
&fg
, wxColour
&bg
)
285 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
291 wxLayoutObjectCmd::Copy(void)
293 wxLayoutStyleInfo si
;
296 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
297 si
.size
, si
.family
, si
.style
, si
.weight
, si
.underline
,
298 m_ColourFG
, m_ColourBG
);
299 obj
->SetUserData(m_UserData
);
304 wxLayoutObjectCmd::~wxLayoutObjectCmd()
310 wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo
*si
) const
312 si
->size
= m_font
->GetPointSize();
313 si
->family
= m_font
->GetFamily();
314 si
->style
= m_font
->GetStyle();
315 si
->underline
= m_font
->GetUnderlined();
316 si
->weight
= m_font
->GetWeight();
318 si
->fg_red
= m_ColourFG
.Red();
319 si
->fg_green
= m_ColourFG
.Green();
320 si
->fg_blue
= m_ColourFG
.Blue();
321 si
->bg_red
= m_ColourBG
.Red();
322 si
->bg_green
= m_ColourBG
.Green();
323 si
->bg_blue
= m_ColourBG
.Blue();
327 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
328 wxLayoutList
*wxllist
,
329 CoordType begin
, CoordType
/* len */)
333 dc
.SetTextForeground(m_ColourFG
);
334 dc
.SetTextBackground(m_ColourBG
);
338 wxLayoutObjectCmd::Layout(wxDC
&dc
)
340 // this get called, so that recalculation uses right font sizes
341 Draw(dc
, wxPoint(0,0), NULL
);
345 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
347 The wxLayoutLine object
349 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
351 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
354 m_Width
= m_Height
= 0;
359 RecalculatePosition(llist
);
362 m_LineNumber
= m_Previous
->GetLineNumber()+1;
363 m_Next
= m_Previous
->GetNextLine();
364 m_Previous
->m_Next
= this;
365 m_Height
= m_Previous
->GetHeight();
369 m_Next
->m_Previous
= this;
370 m_Next
->MoveLines(+1);
371 m_Next
->RecalculatePositions(1,llist
);
375 wxLayoutLine::~wxLayoutLine()
377 // kbList cleans itself
381 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
384 m_Position
= m_Previous
->GetPosition() +
385 wxPoint(0,m_Previous
->GetHeight());
387 m_Position
= wxPoint(0,0);
388 llist
->SetUpdateRect(m_Position
);
393 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
395 wxASSERT(recurse
>= 0);
396 wxPoint pos
= m_Position
;
397 CoordType height
= m_Height
;
399 // WXLO_TRACE("RecalculatePositions()");
400 RecalculatePosition(llist
);
404 m_Next
->RecalculatePositions(--recurse
, llist
);
405 else if(pos
!= m_Position
|| m_Height
!= height
)
406 m_Next
->RecalculatePositions(0, llist
);
410 wxLayoutObjectList::iterator
411 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
415 wxLayoutObjectList::iterator
418 CoordType x
= 0, len
;
420 /* We search through the objects. As we don't like returning the
421 object that the cursor is behind, we just remember such an
422 object in "found" so we can return it if there is really no
423 further object following it. */
424 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
426 len
= (**i
).GetLength();
427 if( x
<= xpos
&& xpos
<= x
+ len
)
430 if(xpos
== x
+ len
) // is there another object behind?
432 else // we are really inside this object
435 x
+= (**i
).GetLength();
437 return found
; // ==NULL if really none found
440 wxLayoutObjectList::iterator
441 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
442 CoordType xpos
, CoordType
*cxpos
,
447 wxLayoutObjectList::iterator i
;
448 CoordType x
= 0, cx
= 0, width
;
450 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
453 width
= (**i
).GetWidth();
454 if( x
<= xpos
&& xpos
<= x
+ width
)
456 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
457 wxLogDebug("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos
);
458 if(found
) *found
= true;
461 x
+= (**i
).GetWidth();
462 cx
+= (**i
).GetLength();
464 // behind last object:
466 if(found
) *found
= false;
467 return m_ObjectList
.tail();
471 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
474 wxASSERT(obj
!= NULL
);
476 wxLOiterator i
= FindObject(xpos
, &offset
);
479 if(xpos
== 0 ) // aha, empty line!
481 m_ObjectList
.push_back(obj
);
482 m_Length
+= obj
->GetLength();
489 CoordType len
= (**i
).GetLength();
490 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
491 { // insert before this object
492 m_ObjectList
.insert(i
,obj
);
493 m_Length
+= obj
->GetLength();
498 if( i
== m_ObjectList
.tail()) // last object?
499 m_ObjectList
.push_back(obj
);
501 { // insert after current object
503 m_ObjectList
.insert(i
,obj
);
505 m_Length
+= obj
->GetLength();
508 /* Otherwise we need to split the current object.
509 Fortunately this can only be a text object. */
510 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
511 wxString left
, right
;
512 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
513 left
= tobj
->GetText().substr(0,offset
);
514 right
= tobj
->GetText().substr(offset
,len
-offset
);
515 // current text object gets set to right half
516 tobj
->GetText() = right
; // set new text
517 // before it we insert the new object
518 m_ObjectList
.insert(i
,obj
);
519 m_Length
+= obj
->GetLength();
520 // and before that we insert the left half
521 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
526 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
530 wxLOiterator i
= FindObject(xpos
, &offset
);
531 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
533 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
534 tobj
->GetText().insert(offset
, text
);
535 m_Length
+= text
.Length();
540 return Insert(xpos
, new wxLayoutObjectText(text
));
544 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
546 CoordType offset
, len
;
550 wxLOiterator i
= FindObject(xpos
, &offset
);
553 if(i
== NULLIT
) return npos
;
554 // now delete from that object:
555 if((**i
).GetType() != WXLO_TYPE_TEXT
)
557 if(offset
!= 0) // at end of line after a non-text object
560 len
= (**i
).GetLength();
563 m_ObjectList
.erase(i
);
567 // tidy up: remove empty text objects
568 if((**i
).GetLength() == 0)
570 m_ObjectList
.erase(i
);
574 CoordType max
= (**i
).GetLength() - offset
;
575 if(npos
< max
) max
= npos
;
578 if(xpos
== GetLength())
581 { // at the end of an object
582 // move to begin of next object:
584 continue; // start over
589 if(offset
== 0 && max
== (**i
).GetLength())
590 m_ObjectList
.erase(i
); // remove the whole object
592 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
599 wxLayoutLine::DeleteWord(CoordType xpos
)
604 wxLOiterator i
= FindObject(xpos
, &offset
);
608 if(i
== NULLIT
) return false;
609 if((**i
).GetType() != WXLO_TYPE_TEXT
)
611 // This should only happen when at end of line, behind a non-text
613 if(offset
== (**i
).GetLength()) return false;
614 m_Length
-= (**i
).GetLength(); // -1
615 m_ObjectList
.erase(i
);
616 return true; // we are done
620 if(offset
== (**i
).GetLength()) // at end of object
625 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
627 wxString str
= tobj
->GetText();
628 str
= str
.substr(offset
,str
.Length()-offset
);
629 // Find out how many positions we need to delete:
630 // 1. eat leading space
631 while(isspace(str
.c_str()[count
])) count
++;
632 // 2. eat the word itself:
633 while(isalnum(str
.c_str()[count
])) count
++;
635 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
636 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
641 wxASSERT(0); // we should never arrive here
645 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
647 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
648 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
651 m_Next
->MoveLines(-1);
652 m_Next
->RecalculatePositions(1, llist
);
654 wxLayoutLine
*next
= m_Next
;
660 wxLayoutLine::Draw(wxDC
&dc
,
662 const wxPoint
& offset
) const
664 wxLayoutObjectList::iterator i
;
665 wxPoint pos
= offset
;
666 pos
= pos
+ GetPosition();
670 CoordType xpos
= 0; // cursorpos, lenght of line
672 CoordType from
, to
, tempto
;
673 int highlight
= llist
->IsSelected(this, &from
, &to
);
674 if(highlight
== 1) // we need to draw the whole line inverted!
675 llist
->StartHighlighting(dc
);
677 llist
->EndHighlighting(dc
);
679 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
681 if(highlight
== -1) // partially highlight line
683 // parts of the line need highlighting
684 tempto
= xpos
+(**i
).GetLength();
685 if(tempto
>= from
&& xpos
<= to
)
688 if(tempto
> (**i
).GetLength())
689 tempto
= (**i
).GetLength();
690 CoordType tmp
= from
-xpos
;
692 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
);
696 llist
->EndHighlighting(dc
); // FIXME! inefficient
697 (**i
).Draw(dc
, pos
, llist
);
701 (**i
).Draw(dc
, pos
, llist
);
702 pos
.x
+= (**i
).GetWidth();
703 xpos
+= (**i
).GetLength();
708 wxLayoutLine::Layout(wxDC
&dc
,
714 wxLayoutObjectList::iterator i
;
717 oldHeight
= m_Height
;
719 topHeight
, bottomHeight
; // above and below baseline
722 objTopHeight
, objBottomHeight
;
725 m_Height
= 0; m_BaseLine
= 0;
727 topHeight
= 0; bottomHeight
= 0;
729 bool cursorFound
= false;
733 *cursorPos
= m_Position
;
734 if(cursorSize
) *cursorSize
= wxPoint(0,0);
737 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
740 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
742 if(cursorPos
&& ! cursorFound
)
743 { // we need to check whether the text cursor is here
744 len
= (**i
).GetLength();
745 if(count
<= cx
&& count
+len
> cx
)
747 if((**i
).GetType() == WXLO_TYPE_TEXT
)
749 len
= cx
- count
; // pos in object
750 CoordType width
, height
, descent
;
751 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
752 &width
, &height
, &descent
);
753 cursorPos
->x
+= width
;
754 cursorPos
->y
= m_Position
.y
;
756 if(len
< (**i
).GetLength())
757 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
759 str
= WXLO_CURSORCHAR
;
760 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
761 wxASSERT(cursorSize
);
762 // Just in case some joker inserted an empty string object:
763 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
764 if(height
== 0) height
= objHeight
;
765 cursorSize
->x
= width
;
766 cursorSize
->y
= height
;
767 cursorFound
= true; // no more checks
770 { // on some other object
771 CoordType top
, bottom
; // unused
772 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
773 cursorPos
->y
= m_Position
.y
;
774 cursorFound
= true; // no more checks
780 cursorPos
->x
+= (**i
).GetWidth();
785 if(objHeight
> m_Height
) m_Height
= objHeight
;
786 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
787 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
789 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
790 topHeight
+bottomHeight
;
791 m_BaseLine
= topHeight
;
795 if(GetPreviousLine()) // empty line
797 m_Height
= GetPreviousLine()->GetHeight();
798 m_BaseLine
= GetPreviousLine()->m_BaseLine
;
802 CoordType width
, height
, descent
;
803 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
805 m_BaseLine
= m_Height
- descent
;
810 // tell next line about coordinate change
811 if(m_Next
&& objHeight
!= oldHeight
)
812 m_Next
->RecalculatePositions(0, llist
);
814 // We need to check whether we found a valid cursor size:
817 // this might be the case if the cursor is at the end of the
818 // line or on a command object:
819 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
821 CoordType width
, height
, descent
;
822 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
823 cursorSize
->x
= width
;
824 cursorSize
->y
= height
;
826 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
827 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
833 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
838 { // insert an empty line before this one
839 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
840 if(m_Previous
== NULL
)
841 { // We were in first line, need to link in new empty line
845 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
849 m_Next
->RecalculatePositions(1, llist
);
854 wxLOiterator i
= FindObject(xpos
, &offset
);
856 // must be at the end of the line then
857 return new wxLayoutLine(this, llist
);
860 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
861 // split object at i:
862 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
864 wxString left
, right
;
865 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
866 left
= tobj
->GetText().substr(0,offset
);
867 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
868 // current text object gets set to left half
869 tobj
->GetText() = left
; // set new text
870 newLine
->Append(new wxLayoutObjectText(right
));
871 m_Length
-= right
.Length();
872 i
++; // don't move this object to the new list
876 i
++; // move objects from here to new list
878 while(i
!= m_ObjectList
.end())
881 m_Length
-= (**i
).GetLength();
882 m_ObjectList
.remove(i
); // remove without deleting it
885 m_Next
->RecalculatePositions(2, llist
);
891 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
893 wxASSERT(GetNextLine());
894 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
897 for(i
= list
.begin(); i
!= list
.end();)
900 list
.remove(i
); // remove without deleting it
902 wxASSERT(list
.empty());
903 wxLayoutLine
*oldnext
= GetNextLine();
904 SetNext(GetNextLine()->GetNextLine());
906 RecalculatePositions(1, llist
);
910 wxLayoutLine::GetWrapPosition(CoordType column
)
913 wxLOiterator i
= FindObject(column
, &offset
);
914 if(i
== NULLIT
) return -1; // cannot wrap
916 // go backwards through the list and look for space in text objects
919 if((**i
).GetType() == WXLO_TYPE_TEXT
)
923 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
930 }while(offset
!= -1);
931 i
--; // move on to previous object
935 column
-= (**i
).GetLength();
939 offset
= (**i
).GetLength();
941 /* If we reached the begin of the list and have more than one
942 object, that one is longer than the margin, so break behind
945 i
= m_ObjectList
.begin();
946 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
948 pos
+= (**i
).GetLength();
951 if(i
== NULLIT
) return -1; //why should this happen?
952 pos
+= (**i
).GetLength();
954 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
956 pos
+= (**i
).GetLength();
959 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
960 // now we are at the second text object:
961 pos
-= (**i
).GetLength();
962 return pos
; // in front of it
966 #ifdef WXLAYOUT_DEBUG
968 wxLayoutLine::Debug(void)
971 wxPoint pos
= GetPosition();
972 tmp
.Printf("Line %ld, Pos (%ld,%ld), Height %ld",
973 (long int) GetLineNumber(),
974 (long int) pos
.x
, (long int) pos
.y
,
975 (long int) GetHeight());
981 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
983 The wxLayoutList object
985 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
987 wxLayoutList::wxLayoutList()
989 m_DefaultSetting
= NULL
;
991 m_ColourFG
= *wxBLACK
;
992 m_ColourBG
= *wxWHITE
;
993 InvalidateUpdateRect();
997 wxLayoutList::~wxLayoutList()
1000 m_FirstLine
->DeleteLine(false, this);
1004 wxLayoutList::Empty(void)
1007 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1009 m_CursorPos
= wxPoint(0,0);
1010 m_CursorScreenPos
= wxPoint(0,0);
1011 m_CursorSize
= wxPoint(0,0);
1012 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1013 m_CursorLine
= m_FirstLine
;
1014 InvalidateUpdateRect();
1019 wxLayoutList::InternalClear(void)
1022 if(m_DefaultSetting
)
1024 delete m_DefaultSetting
;
1025 m_DefaultSetting
= NULL
;
1030 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1031 int underline
, wxColour
*fg
,
1034 if(family
!= -1) m_FontFamily
= family
;
1035 if(size
!= -1) m_FontPtSize
= size
;
1036 if(style
!= -1) m_FontStyle
= style
;
1037 if(weight
!= -1) m_FontWeight
= weight
;
1038 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
1040 if(fg
!= NULL
) m_ColourFG
= *fg
;
1041 if(bg
!= NULL
) m_ColourBG
= *bg
;
1044 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
1045 m_ColourFG
, m_ColourBG
));
1049 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1050 int underline
, char const *fg
, char const *bg
)
1058 cfg
= wxTheColourDatabase
->FindColour(fg
);
1060 cbg
= wxTheColourDatabase
->FindColour(bg
);
1062 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1066 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1067 int /* underline */, wxColour
*fg
, wxColour
*bg
)
1072 m_FontPtSize
= size
;
1073 m_FontUnderline
= false;
1074 m_FontFamily
= family
;
1075 m_FontStyle
= style
;
1076 m_FontWeight
= weight
;
1077 if(fg
) m_ColourFG
= *fg
;
1078 if(bg
) m_ColourBG
= *bg
;
1080 m_ColourFG
= *wxBLACK
;
1081 m_ColourBG
= *wxWHITE
;
1083 if(m_DefaultSetting
)
1084 delete m_DefaultSetting
;
1086 m_DefaultSetting
= new
1087 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1088 m_FontWeight
,m_FontUnderline
,
1089 m_ColourFG
, m_ColourBG
);
1095 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1097 SetUpdateRect(m_CursorScreenPos
);
1098 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1099 wxLayoutLine
*line
= m_FirstLine
;
1100 while(line
&& line
->GetLineNumber() != p
.y
)
1101 line
= line
->GetNextLine();
1102 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1104 m_CursorPos
.y
= p
.y
;
1105 m_CursorLine
= line
;
1106 CoordType len
= line
->GetLength();
1109 m_CursorPos
.x
= p
.x
;
1114 m_CursorPos
.x
= len
;
1122 wxLayoutList::MoveCursorVertically(int n
)
1124 SetUpdateRect(m_CursorScreenPos
);
1125 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1127 if(n
< 0) // move up
1129 if(m_CursorLine
== m_FirstLine
) return false;
1130 while(n
< 0 && m_CursorLine
)
1132 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1138 m_CursorLine
= m_FirstLine
;
1144 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1145 m_CursorPos
.x
= m_CursorLine
->GetLength();
1151 wxLayoutLine
*last
= m_CursorLine
;
1152 if(! m_CursorLine
->GetNextLine()) return false;
1153 while(n
> 0 && m_CursorLine
)
1157 m_CursorLine
= m_CursorLine
->GetNextLine();
1161 m_CursorLine
= last
;
1167 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1168 m_CursorPos
.x
= m_CursorLine
->GetLength();
1176 wxLayoutList::MoveCursorHorizontally(int n
)
1178 SetUpdateRect(m_CursorScreenPos
);
1179 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1183 if(m_CursorPos
.x
== 0) // at begin of line
1185 if(! MoveCursorVertically(-1))
1187 MoveCursorToEndOfLine();
1192 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1193 m_CursorPos
.x
-= move
; n
+= move
;
1198 int len
= m_CursorLine
->GetLength();
1199 if(m_CursorPos
.x
== len
) // at end of line
1201 if(! MoveCursorVertically(1))
1203 MoveCursorToBeginOfLine();
1208 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1209 m_CursorPos
.x
+= move
;
1216 wxLayoutList::Insert(wxString
const &text
)
1218 wxASSERT(m_CursorLine
);
1219 SetUpdateRect(m_CursorScreenPos
);
1220 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1221 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1222 m_CursorPos
.x
+= text
.Length();
1227 wxLayoutList::Insert(wxLayoutObject
*obj
)
1229 wxASSERT(m_CursorLine
);
1230 SetUpdateRect(m_CursorScreenPos
);
1231 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1232 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1233 m_CursorPos
.x
+= obj
->GetLength();
1238 wxLayoutList::LineBreak(void)
1240 wxASSERT(m_CursorLine
);
1241 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1242 SetUpdateRect(m_CursorScreenPos
);
1243 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1244 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1245 if(setFirst
) // we were at beginning of first line
1246 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1253 wxLayoutList::WrapLine(CoordType column
)
1255 if(m_CursorPos
.x
<= column
|| column
< 1)
1256 return false; // do nothing yet
1259 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1261 return false; // cannot break line
1263 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1264 m_CursorPos
.x
= xpos
;
1265 SetUpdateRect(m_CursorScreenPos
);
1266 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1268 Delete(1); // delete the space
1269 m_CursorPos
.x
= newpos
;
1275 wxLayoutList::Delete(CoordType npos
)
1277 wxASSERT(m_CursorLine
);
1278 SetUpdateRect(m_CursorScreenPos
);
1279 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1283 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1286 // More to delete, continue on next line.
1287 // First, check if line is empty:
1288 if(m_CursorLine
->GetLength() == 0)
1289 { // in this case, updating could probably be optimised
1291 wxASSERT(DeleteLines(1) == 0);
1300 // Need to join next line
1301 if(! m_CursorLine
->GetNextLine())
1305 m_CursorLine
->MergeNextLine(this);
1315 wxLayoutList::DeleteLines(int n
)
1317 wxASSERT(m_CursorLine
);
1319 SetUpdateRect(m_CursorScreenPos
);
1320 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1323 if(!m_CursorLine
->GetNextLine())
1324 { // we cannot delete this line, but we can clear it
1325 MoveCursorToBeginOfLine();
1326 DeleteToEndOfLine();
1330 line
= m_CursorLine
;
1331 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1333 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1334 wxASSERT(m_FirstLine
);
1335 wxASSERT(m_CursorLine
);
1337 m_CursorLine
->RecalculatePositions(2, this);
1342 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1344 wxLayoutLine
*line
= m_FirstLine
;
1346 // first, make sure everything is calculated - this might not be
1347 // needed, optimise it later
1348 m_DefaultSetting
->Layout(dc
);
1351 line
->RecalculatePosition(this); // so we don't need to do it all the time
1352 // little condition to speed up redrawing:
1353 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1354 line
= line
->GetNextLine();
1359 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1361 wxASSERT(m_CursorLine
);
1362 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1366 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1368 UpdateCursorScreenPos(dc
);
1369 return m_CursorScreenPos
;
1373 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
)
1375 wxLayoutLine
*line
= m_FirstLine
;
1377 // first, make sure everything is calculated - this might not be
1378 // needed, optimise it later
1379 m_DefaultSetting
->Layout(dc
);
1382 if(line
== m_CursorLine
)
1383 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1385 line
->Layout(dc
, this);
1386 // little condition to speed up redrawing:
1387 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1388 line
= line
->GetNextLine();
1391 ///FIXME: disabled for now
1393 // can only be 0 if we are on the first line and have no next line
1394 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1395 m_CursorLine
->GetNextLine() == NULL
&&
1396 m_CursorLine
== m_FirstLine
));
1398 SetUpdateRect(m_CursorScreenPos
);
1399 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1403 wxLayoutList::Draw(wxDC
&dc
,
1404 wxPoint
const &offset
,
1408 wxLayoutLine
*line
= m_FirstLine
;
1411 m_DefaultSetting
->Draw(dc
, wxPoint(0,0), this);
1412 wxBrush
brush(m_ColourBG
, wxSOLID
);
1417 // only draw if between top and bottom:
1418 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1419 line
->Draw(dc
, this, offset
);
1420 // little condition to speed up redrawing:
1421 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1422 line
= line
->GetNextLine();
1424 // can only be 0 if we are on the first line and have no next line
1425 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1426 m_CursorLine
->GetNextLine() == NULL
&&
1427 m_CursorLine
== m_FirstLine
));
1428 InvalidateUpdateRect();
1430 wxLogDebug("Selection is %s : l%d,%ld/%ld,%ld",
1431 m_Selection
.m_valid
? "valid" : "invalid",
1432 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1433 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
);
1437 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1441 // First, find the right line:
1442 wxLayoutLine
*line
= m_FirstLine
;
1445 // we need to run a layout here to get font sizes right :-(
1446 m_DefaultSetting
->Layout(dc
);
1449 p
= line
->GetPosition();
1450 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1452 line
->Layout(dc
, this);
1453 line
= line
->GetNextLine();
1457 if(found
) *found
= false;
1458 return NULL
; // not found
1460 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1461 // Now, find the object in the line:
1462 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1463 cursorPos
? & cursorPos
->x
: NULL
,
1465 return (i
== NULLIT
) ? NULL
: *i
;
1470 wxLayoutList::GetSize(void) const
1473 *line
= m_FirstLine
,
1476 return wxPoint(0,0);
1478 wxPoint
maxPoint(0,0);
1483 if(line
->GetWidth() > maxPoint
.x
)
1484 maxPoint
.x
= line
->GetWidth();
1486 line
= line
->GetNextLine();
1489 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1494 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1497 coords
= m_CursorScreenPos
;
1498 coords
.x
+= translate
.x
;
1499 coords
.y
+= translate
.y
;
1501 #ifdef WXLAYOUT_DEBUG
1502 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1503 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1504 (long)coords
.x
, (long)coords
.y
,
1505 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1506 (long)m_CursorLine
->GetLineNumber(),
1507 (long)m_CursorLine
->GetLength()));
1510 dc
.SetBrush(*wxBLACK_BRUSH
);
1511 dc
.SetLogicalFunction(wxXOR
);
1512 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1514 dc
.DrawRectangle(coords
.x
, coords
.y
, m_CursorSize
.x
,
1517 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1518 coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
-1);
1519 dc
.SetLogicalFunction(wxCOPY
);
1520 //dc.SetBrush(wxNullBrush);
1524 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1526 if(m_UpdateRectValid
)
1527 GrowRect(m_UpdateRect
, x
, y
);
1532 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1533 m_UpdateRect
.height
= 4;// wxGTK :-)
1534 m_UpdateRectValid
= true;
1539 wxLayoutList::StartSelection(void)
1541 wxLogDebug("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
);
1542 m_Selection
.m_CursorA
= m_CursorPos
;
1543 m_Selection
.m_selecting
= true;
1544 m_Selection
.m_valid
= false;
1548 wxLayoutList::ContinueSelection(void)
1550 wxASSERT(m_Selection
.m_selecting
== true);
1551 wxASSERT(m_Selection
.m_valid
== false);
1552 wxLogDebug("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
);
1553 m_Selection
.m_CursorB
= m_CursorPos
;
1554 // We always want m_CursorA <= m_CursorB!
1555 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1557 wxPoint help
= m_Selection
.m_CursorB
;
1558 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1559 m_Selection
.m_CursorA
= help
;
1564 wxLayoutList::EndSelection(void)
1566 ContinueSelection();
1567 wxLogDebug("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
);
1568 m_Selection
.m_selecting
= false;
1569 m_Selection
.m_valid
= true;
1574 wxLayoutList::IsSelecting(void)
1576 return m_Selection
.m_selecting
;
1580 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1582 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1584 return m_Selection
.m_CursorA
<= cursor
1585 && cursor
<= m_Selection
.m_CursorB
;
1589 /** Tests whether this layout line is selected and needs
1591 @param line to test for
1592 @return 0 = not selected, 1 = fully selected, -1 = partially
1596 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1599 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1601 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1604 CoordType y
= line
->GetLineNumber();
1605 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1607 else if(m_Selection
.m_CursorA
.y
== y
)
1609 *from
= m_Selection
.m_CursorA
.x
;
1610 if(m_Selection
.m_CursorB
.y
== y
)
1611 *to
= m_Selection
.m_CursorB
.x
;
1613 *to
= line
->GetLength();
1616 else if(m_Selection
.m_CursorB
.y
== y
)
1618 *to
= m_Selection
.m_CursorB
.x
;
1619 if(m_Selection
.m_CursorA
.y
== y
)
1620 *from
= m_Selection
.m_CursorA
.x
;
1630 /// Starts highlighting the selection
1632 wxLayoutList::StartHighlighting(wxDC
&dc
)
1634 dc
.SetTextForeground(m_ColourBG
);
1635 dc
.SetTextBackground(m_ColourFG
);
1638 /// Ends highlighting the selection
1640 wxLayoutList::EndHighlighting(wxDC
&dc
)
1642 dc
.SetTextForeground(m_ColourFG
);
1643 dc
.SetTextBackground(m_ColourBG
);
1647 #ifdef WXLAYOUT_DEBUG
1650 wxLayoutList::Debug(void)
1655 for(line
= m_FirstLine
;
1657 line
= line
->GetNextLine())
1664 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1668 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1670 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
1671 wxString
const & title
)
1678 wxLayoutPrintout::~wxLayoutPrintout()
1683 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
1685 // The following bit is taken from the printing sample, let's see
1686 // whether it works for us.
1688 /* You might use THIS code to set the printer DC to ROUGHLY reflect
1689 * the screen text size. This page also draws lines of actual length 5cm
1692 // Get the logical pixels per inch of screen and printer
1693 int ppiScreenX
, ppiScreenY
;
1694 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
1695 int ppiPrinterX
, ppiPrinterY
;
1696 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
1698 if(ppiScreenX
== 0) // not yet set, need to guess
1703 if(ppiPrinterX
== 0) // not yet set, need to guess
1709 // This scales the DC so that the printout roughly represents the
1710 // the screen scaling. The text point size _should_ be the right size
1711 // but in fact is too small for some reason. This is a detail that will
1712 // need to be addressed at some point but can be fudged for the
1714 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
1716 // Now we have to check in case our real page size is reduced
1717 // (e.g. because we're drawing to a print preview memory DC)
1718 int pageWidth
, pageHeight
;
1720 dc
->GetSize(&w
, &h
);
1721 GetPageSizePixels(&pageWidth
, &pageHeight
);
1722 if(pageWidth
!= 0) // doesn't work always
1724 // If printer pageWidth == current DC width, then this doesn't
1725 // change. But w might be the preview bitmap width, so scale down.
1726 scale
= scale
* (float)(w
/(float)pageWidth
);
1728 dc
->SetUserScale(scale
, scale
);
1732 bool wxLayoutPrintout::OnPrintPage(int page
)
1741 top
= (page
- 1)*m_PrintoutHeight
;
1742 bottom
= top
+ m_PrintoutHeight
;
1743 // SetDeviceOrigin() doesn't work here, so we need to manually
1744 // translate all coordinates.
1745 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
1746 m_llist
->Draw(*dc
, translate
, top
, bottom
);
1753 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1755 /* We allocate a temporary wxDC for printing, so that we can
1756 determine the correct paper size and scaling. We don't actually
1757 print anything on it. */
1759 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
1761 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1764 float scale
= ScaleDC(&psdc
);
1766 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
1767 // This sets a left/top origin of 15% and 20%:
1768 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
1770 // This is the length of the printable area.
1771 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1772 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
1776 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
1779 *maxPage
= m_NumOfPages
;
1782 *selPageTo
= m_NumOfPages
;
1783 wxRemoveFile(WXLLIST_TEMPFILE
);
1786 bool wxLayoutPrintout::HasPage(int pageNum
)
1788 return pageNum
<= m_NumOfPages
;
1792 Stupid wxWindows doesn't draw proper ellipses, so we comment this
1793 out. It's a waste of paper anyway.
1797 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1798 wxPoint topleft
, wxPoint bottomright
,
1801 // make backups of all essential parameters
1802 const wxBrush
& brush
= dc
.GetBrush();
1803 const wxPen
& pen
= dc
.GetPen();
1804 const wxFont
& font
= dc
.GetFont();
1806 dc
.SetBrush(*wxWHITE_BRUSH
);
1807 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1808 dc
.DrawRoundedRectangle(topleft
.x
,
1809 topleft
.y
,bottomright
.x
-topleft
.x
,
1810 bottomright
.y
-topleft
.y
);
1811 dc
.SetBrush(*wxBLACK_BRUSH
);
1812 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
1813 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1817 page
= "9999/9999 "; // many pages...
1819 dc
.GetTextExtent(page
,&w
,&h
);
1820 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1821 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1822 dc
.GetTextExtent("XXXX", &w
,&h
);
1823 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);