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"
17 #include <wx/wxprec.h>
26 # include "gui/wxllist.h"
27 # include "gui/wxlparser.h"
28 # define SHOW_SELECTIONS 1
31 # include "wxlparser.h"
32 # define SHOW_SELECTIONS 1
36 # include <iostream.h>
40 # include <wx/print.h>
42 # include <wx/filefn.h>
45 #ifdef WXLAYOUT_USE_CARET
46 # include <wx/caret.h>
47 #endif // WXLAYOUT_USE_CARET
51 /// This should never really get created
52 #define WXLLIST_TEMPFILE "__wxllist.tmp"
56 # define TypeString(t) g_aTypeStrings[t]
57 # define WXLO_DEBUG(x) wxLogDebug x
59 static const char *g_aTypeStrings
[] =
61 "invalid", "text", "cmd", "icon"
64 wxLayoutObject::Debug(void)
66 WXLO_DEBUG(("%s",g_aTypeStrings
[GetType()]));
69 # define TypeString(t) ""
70 # define WXLO_DEBUG(x)
73 // FIXME under MSW, this constant is needed to make the thing properly redraw
74 // itself - I don't know where the size calculation error is and I can't
75 // waste time looking for it right now. Search for occurences of
76 // MSW_CORRECTION to find all the places where I did it.
78 static const int MSW_CORRECTION
= 10;
80 static const int MSW_CORRECTION
= 0;
83 /// Cursors smaller than this disappear in XOR drawing mode
84 #define WXLO_MINIMUM_CURSOR_WIDTH 4
86 /// Use this character to estimate a cursor size when none is available.
87 #define WXLO_CURSORCHAR "E"
88 /** @name Helper functions */
90 /// allows me to compare to wxPoints
91 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
93 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
96 /// grows a wxRect so that it includes the given point
99 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
103 else if(r
.x
+ r
.width
< x
)
108 else if(r
.y
+ r
.height
< y
)
114 /// returns true if the point is in the rectangle
116 bool Contains(const wxRect
&r
, const wxPoint
&p
)
118 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
126 void ReadString(wxString
&to
, wxString
&from
)
129 const char *cptr
= from
.c_str();
130 while(*cptr
&& *cptr
!= '\n')
136 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
140 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
144 wxLayoutObject::Read(wxString
&istr
)
147 ReadString(tmp
, istr
);
149 sscanf(tmp
.c_str(),"%d", &type
);
154 return wxLayoutObjectText::Read(istr
);
156 return wxLayoutObjectCmd::Read(istr
);
158 return wxLayoutObjectIcon::Read(istr
);
164 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
168 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
170 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
180 wxLayoutObjectText::Copy(void)
182 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
183 obj
->m_Width
= m_Width
;
184 obj
->m_Height
= m_Height
;
186 obj
->m_Bottom
= m_Bottom
;
187 obj
->SetUserData(m_UserData
);
193 wxLayoutObjectText::Write(wxString
&ostr
)
195 ostr
<< (int) WXLO_TYPE_TEXT
<< '\n'
200 wxLayoutObjectText::Read(wxString
&istr
)
203 ReadString(text
, istr
);
205 return new wxLayoutObjectText(text
);
209 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
212 *top
= m_Top
; *bottom
= m_Bottom
;
213 return wxPoint(m_Width
, m_Height
);
217 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
218 wxLayoutList
*wxllist
,
219 CoordType begin
, CoordType end
)
222 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
225 // highlight the bit between begin and len
229 ypos
= coords
.y
-m_Top
;
230 long width
, height
, descent
;
232 if(begin
< 0) begin
= 0;
233 if( end
> (signed)m_Text
.Length() )
234 end
= m_Text
.Length();
236 str
= m_Text
.Mid(0, begin
);
237 dc
.DrawText(str
, xpos
, ypos
);
238 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
240 wxllist
->StartHighlighting(dc
);
241 str
= m_Text
.Mid(begin
, end
-begin
);
242 dc
.DrawText(str
, xpos
, ypos
);
243 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
245 wxllist
->EndHighlighting(dc
);
246 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
247 dc
.DrawText(str
, xpos
, ypos
);
252 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
256 maxlen
= m_Text
.Length();
259 height
, descent
= 0l;
261 if(xpos
== 0) return 0; // easy
263 while(width
< xpos
&& offs
< maxlen
)
265 dc
.GetTextExtent(m_Text
.substr(0,offs
),
266 &width
, &height
, &descent
);
269 /* We have to substract 1 to compensate for the offs++, and another
270 one because we don't want to position the cursor behind the
271 object what we clicked on, but before - otherwise it looks
273 return (xpos
> 2) ? offs
-2 : 0;
277 wxLayoutObjectText::Layout(wxDC
&dc
, class wxLayoutList
*llist
)
281 // now this is done in wxLayoutLine::Layout(), but this code might be
282 // reenabled later - in principle, it's more efficient
284 CoordType widthOld
= m_Width
,
285 heightOld
= m_Height
;
288 dc
.GetTextExtent(m_Text
, &m_Width
, &m_Height
, &descent
);
291 if ( widthOld
!= m_Width
|| heightOld
!= m_Height
)
293 // as the text length changed, it must be refreshed
294 wxLayoutLine
*line
= GetLine();
296 wxCHECK_RET( line
, "wxLayoutObjectText can't refresh itself" );
298 // as our size changed, we need to repaint the part which was appended
299 wxPoint
position(line
->GetPosition());
301 // this is not the most efficient way (we repaint the whole line), but
302 // it's not too slow and is *simple*
303 if ( widthOld
< m_Width
)
305 if ( heightOld
< m_Height
)
306 heightOld
= m_Height
;
308 llist
->SetUpdateRect(position
.x
+ widthOld
+ MSW_CORRECTION
,
309 position
.y
+ heightOld
+ MSW_CORRECTION
);
314 m_Top
= m_Height
- m_Bottom
;
318 #ifdef WXLAYOUT_DEBUG
320 wxLayoutObjectText::Debug(void)
322 wxLayoutObject::Debug();
323 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
327 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
331 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
333 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
335 m_Icon
= new wxBitmap(icon
);
340 wxLayoutObjectIcon::Write(wxString
&ostr
)
342 /* Exports icon through a temporary file. */
344 wxString file
= wxGetTempFileName("wxloexport");
346 ostr
<< WXLO_TYPE_ICON
<< '\n'
348 m_Icon
->SaveFile(file
, WXLO_BITMAP_FORMAT
);
352 wxLayoutObjectIcon::Read(wxString
&istr
)
355 ReadString(file
, istr
);
357 if(! wxFileExists(file
))
359 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon
;
361 if(!obj
->m_Icon
->LoadFile(file
, WXLO_BITMAP_FORMAT
))
371 wxLayoutObjectIcon::Copy(void)
373 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
375 obj
->SetUserData(m_UserData
);
379 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
385 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
386 wxLayoutList
*wxllist
,
387 CoordType begin
, CoordType
/* len */)
389 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
390 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
394 wxLayoutObjectIcon::Layout(wxDC
& /* dc */, class wxLayoutList
* )
399 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
401 *top
= m_Icon
->GetHeight();
403 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
408 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
412 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
415 wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily
,
423 family
= ifamily
; size
= isize
;
424 style
= istyle
; weight
= iweight
;
425 underline
= iul
!= 0;
442 #define COPY_SI_(what) if(right.what != -1) what = right.what;
445 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
452 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
453 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
457 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
458 weight
, int underline
,
459 wxColour
*fg
, wxColour
*bg
)
462 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
466 wxLayoutObjectCmd::Copy(void)
468 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
473 m_StyleInfo
->underline
,
474 m_StyleInfo
->m_fg_valid
?
475 &m_StyleInfo
->m_fg
: NULL
,
476 m_StyleInfo
->m_bg_valid
?
477 &m_StyleInfo
->m_bg
: NULL
);
478 obj
->SetUserData(m_UserData
);
483 wxLayoutObjectCmd::Write(wxString
&ostr
)
485 ostr
<< WXLO_TYPE_CMD
<< '\n'
486 << m_StyleInfo
->size
<< '\n'
487 << m_StyleInfo
->family
<< '\n'
488 << m_StyleInfo
->style
<< '\n'
489 << m_StyleInfo
->weight
<< '\n'
490 << m_StyleInfo
->underline
<< '\n'
491 << m_StyleInfo
->m_fg_valid
<< '\n'
492 << m_StyleInfo
->m_bg_valid
<< '\n';
493 if(m_StyleInfo
->m_fg_valid
)
495 ostr
<< m_StyleInfo
->m_fg
.Red() << '\n'
496 << m_StyleInfo
->m_fg
.Green() << '\n'
497 << m_StyleInfo
->m_fg
.Blue() << '\n';
499 if(m_StyleInfo
->m_bg_valid
)
501 ostr
<< m_StyleInfo
->m_bg
.Red() << '\n'
502 << m_StyleInfo
->m_bg
.Green() << '\n'
503 << m_StyleInfo
->m_bg
.Blue() << '\n';
508 wxLayoutObjectCmd::Read(wxString
&istr
)
510 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd
;
513 ReadString(tmp
, istr
);
514 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->size
);
515 ReadString(tmp
, istr
);
516 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->family
);
517 ReadString(tmp
, istr
);
518 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->style
);
519 ReadString(tmp
, istr
);
520 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->weight
);
521 ReadString(tmp
, istr
);
522 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->underline
);
523 ReadString(tmp
, istr
);
524 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_fg_valid
);
525 ReadString(tmp
, istr
);
526 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_bg_valid
);
527 if(obj
->m_StyleInfo
->m_fg_valid
)
529 int red
, green
, blue
;
530 ReadString(tmp
, istr
);
531 sscanf(tmp
.c_str(),"%d", &red
);
532 ReadString(tmp
, istr
);
533 sscanf(tmp
.c_str(),"%d", &green
);
534 ReadString(tmp
, istr
);
535 sscanf(tmp
.c_str(),"%d", &blue
);
536 obj
->m_StyleInfo
->m_fg
= wxColour(red
, green
, blue
);
538 if(obj
->m_StyleInfo
->m_bg_valid
)
540 int red
, green
, blue
;
541 ReadString(tmp
, istr
);
542 sscanf(tmp
.c_str(),"%d", &red
);
543 ReadString(tmp
, istr
);
544 sscanf(tmp
.c_str(),"%d", &green
);
545 ReadString(tmp
, istr
);
546 sscanf(tmp
.c_str(),"%d", &blue
);
547 obj
->m_StyleInfo
->m_bg
= wxColour(red
, green
, blue
);
553 wxLayoutObjectCmd::~wxLayoutObjectCmd()
559 wxLayoutObjectCmd::GetStyle(void) const
565 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
566 wxLayoutList
*wxllist
,
567 CoordType begin
, CoordType
/* len */)
569 wxASSERT(m_StyleInfo
);
570 wxllist
->ApplyStyle(m_StyleInfo
, dc
);
574 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
576 // this get called, so that recalculation uses right font sizes
577 Draw(dc
, wxPoint(0,0), llist
);
581 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
583 The wxLayoutLine object
585 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
587 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
590 m_Width
= m_Height
= 0;
595 RecalculatePosition(llist
);
598 m_LineNumber
= m_Previous
->GetLineNumber()+1;
599 m_Next
= m_Previous
->GetNextLine();
600 m_Previous
->m_Next
= this;
604 m_Next
->m_Previous
= this;
605 m_Next
->MoveLines(+1);
606 m_Next
->RecalculatePositions(1,llist
);
610 wxLayoutLine::~wxLayoutLine()
612 // kbList cleans itself
616 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
618 wxASSERT(m_Previous
|| GetLineNumber() == 0);
620 wxPoint
posOld(m_Position
);
624 m_Position
= m_Previous
->GetPosition();
625 m_Position
.y
+= m_Previous
->GetHeight();
628 m_Position
= wxPoint(0,0);
630 if ( m_Position
!= posOld
)
632 // the whole line moved and must be repainted
633 llist
->SetUpdateRect(m_Position
);
634 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
635 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
636 llist
->SetUpdateRect(posOld
);
637 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
638 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
645 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
647 //FIXME: is this really needed? We run Layout() anyway.
648 // Recursing here, drives computation time up exponentially, as
649 // each line will cause all following lines to be recalculated.
650 // Yes, or linenumbers go wrong.
652 wxASSERT(recurse
>= 0);
653 wxPoint pos
= m_Position
;
654 CoordType height
= m_Height
;
656 // WXLO_TRACE("RecalculatePositions()");
657 RecalculatePosition(llist
);
661 m_Next
->RecalculatePositions(--recurse
, llist
);
662 else if(pos
!= m_Position
|| m_Height
!= height
)
663 m_Next
->RecalculatePositions(0, llist
);
667 wxLayoutObjectList::iterator
668 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
672 wxLayoutObjectList::iterator
675 CoordType x
= 0, len
;
677 /* We search through the objects. As we don't like returning the
678 object that the cursor is behind, we just remember such an
679 object in "found" so we can return it if there is really no
680 further object following it. */
681 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
683 len
= (**i
).GetLength();
684 if( x
<= xpos
&& xpos
<= x
+ len
)
687 if(xpos
== x
+ len
) // is there another object behind?
689 else // we are really inside this object
692 x
+= (**i
).GetLength();
694 return found
; // ==NULL if really none found
697 wxLayoutObjectList::iterator
698 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
699 CoordType xpos
, CoordType
*cxpos
,
704 wxLayoutObjectList::iterator i
;
705 CoordType x
= 0, cx
= 0, width
;
707 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
709 width
= (**i
).GetWidth();
710 if( x
<= xpos
&& xpos
<= x
+ width
)
712 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
713 if(found
) *found
= true;
716 x
+= (**i
).GetWidth();
717 cx
+= (**i
).GetLength();
719 // behind last object:
721 if(found
) *found
= false;
722 return m_ObjectList
.tail();
725 /** Finds text in this line.
726 @param needle the text to find
727 @param xpos the position where to start the search
728 @return the cursoor coord where it was found or -1
731 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
736 wxString
const *text
;
738 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
740 if(cpos
>= xpos
) // search from here!
742 if((**i
).GetType() == WXLO_TYPE_TEXT
)
744 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
745 relpos
= text
->Find(needle
);
746 if(relpos
>= cpos
-xpos
) // -1 if not found
751 cpos
+= (**i
).GetLength();
754 return -1; // not found
758 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
761 wxASSERT(obj
!= NULL
);
766 wxLOiterator i
= FindObject(xpos
, &offset
);
769 if(xpos
== 0 ) // aha, empty line!
771 m_ObjectList
.push_back(obj
);
772 m_Length
+= obj
->GetLength();
779 CoordType len
= (**i
).GetLength();
780 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
781 { // insert before this object
782 m_ObjectList
.insert(i
,obj
);
783 m_Length
+= obj
->GetLength();
788 if( i
== m_ObjectList
.tail()) // last object?
789 m_ObjectList
.push_back(obj
);
791 { // insert after current object
793 m_ObjectList
.insert(i
,obj
);
795 m_Length
+= obj
->GetLength();
798 /* Otherwise we need to split the current object.
799 Fortunately this can only be a text object. */
800 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
801 wxString left
, right
;
802 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
803 left
= tobj
->GetText().substr(0,offset
);
804 right
= tobj
->GetText().substr(offset
,len
-offset
);
805 // current text object gets set to right half
806 tobj
->GetText() = right
; // set new text
807 // before it we insert the new object
808 m_ObjectList
.insert(i
,obj
);
809 m_Length
+= obj
->GetLength();
810 // and before that we insert the left half
811 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
816 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
823 wxLOiterator i
= FindObject(xpos
, &offset
);
824 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
826 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
827 tobj
->GetText().insert(offset
, text
);
828 m_Length
+= text
.Length();
832 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
840 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
842 CoordType offset
, len
;
847 wxLOiterator i
= FindObject(xpos
, &offset
);
850 if(i
== NULLIT
) return npos
;
851 // now delete from that object:
852 if((**i
).GetType() != WXLO_TYPE_TEXT
)
854 if(offset
!= 0) // at end of line after a non-text object
857 len
= (**i
).GetLength();
860 m_ObjectList
.erase(i
);
864 // tidy up: remove empty text objects
865 if((**i
).GetLength() == 0)
867 m_ObjectList
.erase(i
);
871 CoordType max
= (**i
).GetLength() - offset
;
872 if(npos
< max
) max
= npos
;
875 if(xpos
== GetLength())
878 { // at the end of an object
879 // move to begin of next object:
881 continue; // start over
886 if(offset
== 0 && max
== (**i
).GetLength())
887 m_ObjectList
.erase(i
); // remove the whole object
889 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
897 wxLayoutLine::DeleteWord(CoordType xpos
)
903 wxLOiterator i
= FindObject(xpos
, &offset
);
907 if(i
== NULLIT
) return false;
908 if((**i
).GetType() != WXLO_TYPE_TEXT
)
910 // This should only happen when at end of line, behind a non-text
912 if(offset
== (**i
).GetLength()) return false;
913 m_Length
-= (**i
).GetLength(); // -1
914 m_ObjectList
.erase(i
);
915 return true; // we are done
919 if(offset
== (**i
).GetLength()) // at end of object
924 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
926 wxString str
= tobj
->GetText();
927 str
= str
.substr(offset
,str
.Length()-offset
);
928 // Find out how many positions we need to delete:
929 // 1. eat leading space
930 while(isspace(str
.c_str()[count
])) count
++;
931 // 2. eat the word itself:
932 while(isalnum(str
.c_str()[count
])) count
++;
934 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
935 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
941 wxFAIL_MSG("unreachable");
945 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
947 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
948 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
951 m_Next
->MoveLines(-1);
952 m_Next
->RecalculatePositions(1, llist
);
954 wxLayoutLine
*next
= m_Next
;
960 wxLayoutLine::Draw(wxDC
&dc
,
962 const wxPoint
& offset
) const
964 wxLayoutObjectList::iterator i
;
965 wxPoint pos
= offset
;
966 pos
= pos
+ GetPosition();
970 CoordType xpos
= 0; // cursorpos, lenght of line
972 CoordType from
, to
, tempto
;
973 //FIXME This doesn't work yet, needs updating afterr default
974 //settings for list or a wxLayoutObjectCmd have changed:
975 //llist->ApplyStyle(&((wxLayoutLine *)this)->m_StyleInfo, dc);
976 int highlight
= llist
->IsSelected(this, &from
, &to
);
977 // WXLO_DEBUG(("highlight=%d", highlight ));
978 if(highlight
== 1) // we need to draw the whole line inverted!
979 llist
->StartHighlighting(dc
);
981 llist
->EndHighlighting(dc
);
983 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
985 if(highlight
== -1) // partially highlight line
987 // parts of the line need highlighting
988 tempto
= xpos
+(**i
).GetLength();
989 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
992 (**i
).Draw(dc
, pos
, llist
);
993 pos
.x
+= (**i
).GetWidth();
994 xpos
+= (**i
).GetLength();
999 wxLayoutLine::Layout(wxDC
&dc
,
1000 wxLayoutList
*llist
,
1002 wxPoint
*cursorSize
,
1005 wxLayoutObjectList::iterator i
;
1007 // when a line becomes dirty, we redraw it from the place where it was
1008 // changed till the end of line (because the following wxLayoutObjects are
1009 // moved when the preceding one changes) - calculate the update rectangle.
1010 CoordType updateTop
= m_Position
.y
,
1012 updateWidth
= m_Width
,
1013 updateHeight
= m_Height
;
1017 bottomHeight
= 0; // above and below baseline
1019 objTopHeight
, objBottomHeight
; // above and below baseline
1023 CoordType heightOld
= m_Height
;
1029 bool cursorFound
= false;
1033 *cursorPos
= m_Position
;
1034 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1037 //FIXME This doesn't work yet, needs updating afterr default
1038 //settings for list or a wxLayoutObjectCmd have changed:
1039 //llist->ApplyStyle(&m_StyleInfo, dc);
1040 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1042 wxLayoutObject
*obj
= *i
;
1043 obj
->Layout(dc
, llist
);
1044 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1046 if(cursorPos
&& ! cursorFound
)
1048 // we need to check whether the text cursor is here
1049 len
= obj
->GetLength();
1050 if(count
<= cx
&& count
+len
> cx
)
1052 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1054 len
= cx
- count
; // pos in object
1055 CoordType width
, height
, descent
;
1056 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1057 &width
, &height
, &descent
);
1058 cursorPos
->x
+= width
;
1059 cursorPos
->y
= m_Position
.y
;
1061 if(len
< obj
->GetLength())
1062 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1064 str
= WXLO_CURSORCHAR
;
1065 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1066 wxASSERT(cursorSize
);
1067 // Just in case some joker inserted an empty string object:
1068 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1069 if(height
== 0) height
= sizeObj
.y
;
1070 cursorSize
->x
= width
;
1071 cursorSize
->y
= height
;
1072 cursorFound
= true; // no more checks
1076 // on some other object
1077 CoordType top
, bottom
; // unused
1078 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1079 cursorPos
->y
= m_Position
.y
;
1080 cursorFound
= true; // no more checks
1086 cursorPos
->x
+= obj
->GetWidth();
1090 m_Width
+= sizeObj
.x
;
1091 if(sizeObj
.y
> m_Height
)
1093 m_Height
= sizeObj
.y
;
1096 if(objTopHeight
> topHeight
)
1097 topHeight
= objTopHeight
;
1098 if(objBottomHeight
> bottomHeight
)
1099 bottomHeight
= objBottomHeight
;
1104 if ( updateHeight
< m_Height
)
1105 updateHeight
= m_Height
;
1106 if ( updateWidth
< m_Width
)
1107 updateWidth
= m_Width
;
1109 // update all line if we don't know where to start from
1110 if ( updateLeft
== -1 )
1113 llist
->SetUpdateRect(updateLeft
, updateTop
);
1114 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1115 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1118 if(topHeight
+ bottomHeight
> m_Height
)
1120 m_Height
= topHeight
+bottomHeight
;
1123 m_BaseLine
= topHeight
;
1127 CoordType width
, height
, descent
;
1128 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1130 m_BaseLine
= m_Height
- descent
;
1133 // tell next line about coordinate change
1134 if(m_Next
&& m_Height
!= heightOld
)
1136 // FIXME isn't this done in RecalculatePositions() below anyhow?
1137 m_Next
->RecalculatePositions(0, llist
);
1140 // We need to check whether we found a valid cursor size:
1143 // this might be the case if the cursor is at the end of the
1144 // line or on a command object:
1145 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1147 CoordType width
, height
, descent
;
1148 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1149 cursorSize
->x
= width
;
1150 cursorSize
->y
= height
;
1152 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1153 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1156 RecalculatePositions(1, llist
);
1163 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1165 wxASSERT(xpos
>= 0);
1169 /* If we are at the begin of a line, we want to move all other
1170 lines down and stay with the cursor where we are. However, if we
1171 are in an empty line, we want to move down with it. */
1172 if(xpos
== 0 && GetLength() > 0)
1173 { // insert an empty line before this one
1174 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1175 if(m_Previous
== NULL
)
1176 { // We were in first line, need to link in new empty line
1178 prev
->m_Next
= this;
1180 m_Previous
->m_Height
= 0; // this is a wild guess
1183 m_Next
->RecalculatePositions(1, llist
);
1188 wxLOiterator i
= FindObject(xpos
, &offset
);
1190 // must be at the end of the line then
1191 return new wxLayoutLine(this, llist
);
1194 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1195 // split object at i:
1196 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1198 wxString left
, right
;
1199 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1200 left
= tobj
->GetText().substr(0,offset
);
1201 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1202 // current text object gets set to left half
1203 tobj
->GetText() = left
; // set new text
1204 newLine
->Append(new wxLayoutObjectText(right
));
1205 m_Length
-= right
.Length();
1206 i
++; // don't move this object to the new list
1211 i
++; // move objects from here to new list
1214 while(i
!= m_ObjectList
.end())
1216 wxLayoutObject
*obj
= *i
;
1217 newLine
->Append(obj
);
1218 m_Length
-= obj
->GetLength();
1220 m_ObjectList
.remove(i
); // remove without deleting it
1223 m_Next
->RecalculatePositions(2, llist
);
1229 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1231 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1232 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1235 MarkDirty(GetWidth());
1237 wxLayoutObject
*last
= NULL
;
1238 for(i
= list
.begin(); i
!= list
.end();)
1240 wxLayoutObject
*current
= *i
;
1242 // merge text objects together for efficiency
1243 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1244 current
->GetType() == WXLO_TYPE_TEXT
)
1246 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1247 wxString
text(textObj
->GetText());
1248 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1249 textObj
->SetText(text
);
1251 list
.erase(i
); // remove and delete it
1255 // just append the object "as was"
1258 list
.remove(i
); // remove without deleting it
1261 wxASSERT(list
.empty());
1263 wxLayoutLine
*oldnext
= GetNextLine();
1264 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1268 nextLine
->MoveLines(-1);
1272 // this is now done in Delete(), but if this function is ever called
1273 // from elsewhere, we might have to move refresh code back here (in
1274 // order not to duplicate it)
1276 wxPoint
pos(oldnext
->GetPosition());
1277 llist
->SetUpdateRect(pos
);
1278 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1279 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1287 wxLayoutLine::GetWrapPosition(CoordType column
)
1290 wxLOiterator i
= FindObject(column
, &offset
);
1291 if(i
== NULLIT
) return -1; // cannot wrap
1293 // go backwards through the list and look for space in text objects
1296 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1300 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1307 }while(offset
!= -1);
1308 i
--; // move on to previous object
1312 column
-= (**i
).GetLength();
1316 offset
= (**i
).GetLength();
1317 }while(i
!= NULLIT
);
1318 /* If we reached the begin of the list and have more than one
1319 object, that one is longer than the margin, so break behind
1322 i
= m_ObjectList
.begin();
1323 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1325 pos
+= (**i
).GetLength();
1328 if(i
== NULLIT
) return -1; //why should this happen?
1329 pos
+= (**i
).GetLength();
1331 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1333 pos
+= (**i
).GetLength();
1336 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1337 // now we are at the second text object:
1338 pos
-= (**i
).GetLength();
1339 return pos
; // in front of it
1343 #ifdef WXLAYOUT_DEBUG
1345 wxLayoutLine::Debug(void)
1348 wxPoint pos
= GetPosition();
1349 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
1350 (long int) GetLineNumber(),
1351 (long int) pos
.x
, (long int) pos
.y
,
1352 (long int) GetHeight()));
1353 if(m_ObjectList
.begin() != NULLIT
)
1354 (**m_ObjectList
.begin()).Debug();
1360 wxLayoutLine::Copy(wxLayoutList
*llist
,
1364 CoordType firstOffset
, lastOffset
;
1366 if(to
== -1) to
= GetLength();
1367 if(from
== to
) return;
1369 wxLOiterator first
= FindObject(from
, &firstOffset
);
1370 wxLOiterator last
= FindObject(to
, &lastOffset
);
1372 // Common special case: only one object
1373 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1375 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1377 llist
->Insert(new wxLayoutObjectText(
1378 ((wxLayoutObjectText
1379 *)*first
)->GetText().substr(firstOffset
,
1380 lastOffset
-firstOffset
))
1384 else // what can we do?
1386 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1387 llist
->Insert( (**first
).Copy() );
1392 // If we reach here, we can safely copy the whole first object from
1393 // the firstOffset position on:
1394 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1396 llist
->Insert(new wxLayoutObjectText(
1397 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1400 else if(firstOffset
== 0)
1401 llist
->Insert( (**first
).Copy() );
1402 // else nothing to copy :-(
1404 // Now we copy all objects before the last one:
1405 wxLOiterator i
= first
; i
++;
1406 for( ; i
!= last
; i
++)
1407 llist
->Insert( (**i
).Copy() );
1409 // And now the last object:
1412 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1414 llist
->Insert(new wxLayoutObjectText(
1415 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1419 llist
->Insert( (**last
).Copy() );
1424 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1426 The wxLayoutList object
1428 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1430 wxLayoutList::wxLayoutList()
1432 #ifdef WXLAYOUT_USE_CARET
1434 #endif // WXLAYOUT_USE_CARET
1437 InvalidateUpdateRect();
1441 wxLayoutList::~wxLayoutList()
1444 m_FirstLine
->DeleteLine(false, this);
1448 wxLayoutList::Empty(void)
1451 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1453 m_CursorPos
= wxPoint(0,0);
1454 m_CursorScreenPos
= wxPoint(0,0);
1455 m_CursorSize
= wxPoint(0,0);
1456 m_movedCursor
= true;
1457 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1458 m_CursorLine
= m_FirstLine
;
1459 InvalidateUpdateRect();
1464 wxLayoutList::InternalClear(void)
1467 m_Selection
.m_selecting
= false;
1468 m_Selection
.m_valid
= false;
1470 m_DefaultSetting
.family
= wxSWISS
;
1471 m_DefaultSetting
.size
= WXLO_DEFAULTFONTSIZE
;
1472 m_DefaultSetting
.style
= wxNORMAL
;
1473 m_DefaultSetting
.weight
= wxNORMAL
;
1474 m_DefaultSetting
.underline
= 0;
1475 m_DefaultSetting
.m_fg_valid
= TRUE
;
1476 m_DefaultSetting
.m_fg
= *wxBLACK
;
1477 m_DefaultSetting
.m_bg_valid
= TRUE
;
1478 m_DefaultSetting
.m_bg
= *wxWHITE
;
1480 m_CurrentSetting
= m_DefaultSetting
;
1484 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1485 int underline
, wxColour
*fg
,
1488 if(family
!= -1) m_CurrentSetting
.family
= family
;
1489 if(size
!= -1) m_CurrentSetting
.size
= size
;
1490 if(style
!= -1) m_CurrentSetting
.style
= style
;
1491 if(weight
!= -1) m_CurrentSetting
.weight
= weight
;
1492 if(underline
!= -1) m_CurrentSetting
.underline
= underline
!= 0;
1493 if(fg
) m_CurrentSetting
.m_fg
= *fg
;
1494 if(bg
) m_CurrentSetting
.m_bg
= *bg
;
1496 new wxLayoutObjectCmd(
1497 m_CurrentSetting
.family
,
1498 m_CurrentSetting
.size
,
1499 m_CurrentSetting
.style
,
1500 m_CurrentSetting
.weight
,
1501 m_CurrentSetting
.underline
,
1506 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1507 int underline
, char const *fg
, char const *bg
)
1515 cfg
= wxTheColourDatabase
->FindColour(fg
);
1517 cbg
= wxTheColourDatabase
->FindColour(bg
);
1519 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1523 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1524 int underline
, wxColour
*fg
, wxColour
*bg
)
1527 m_DefaultSetting
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1529 m_CurrentSetting
= m_DefaultSetting
;
1533 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1538 for(line
= m_FirstLine
;
1540 line
= line
->GetNextLine())
1542 if(line
->GetLineNumber() >= cpos
.y
)
1544 xpos
= line
->FindText(needle
,
1545 (line
->GetLineNumber() == cpos
.y
) ?
1548 return wxPoint(xpos
, line
->GetLineNumber());
1551 return wxPoint(-1,-1);
1556 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1558 AddCursorPosToUpdateRect();
1560 wxPoint cursorPosOld
= m_CursorPos
;
1562 wxLayoutLine
*line
= m_FirstLine
;
1563 while(line
&& line
->GetLineNumber() != p
.y
)
1564 line
= line
->GetNextLine();
1565 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1567 m_CursorPos
.y
= p
.y
;
1568 m_CursorLine
= line
;
1569 CoordType len
= line
->GetLength();
1572 m_CursorPos
.x
= p
.x
;
1576 m_CursorPos
.x
= len
;
1580 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1582 return m_CursorPos
== p
;
1586 wxLayoutList::MoveCursorVertically(int n
)
1588 AddCursorPosToUpdateRect();
1590 wxPoint cursorPosOld
= m_CursorPos
;
1593 if(n
< 0) // move up
1595 if(m_CursorLine
== m_FirstLine
) return false;
1596 while(n
< 0 && m_CursorLine
)
1598 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1604 m_CursorLine
= m_FirstLine
;
1610 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1611 m_CursorPos
.x
= m_CursorLine
->GetLength();
1617 wxLayoutLine
*last
= m_CursorLine
;
1618 if(! m_CursorLine
->GetNextLine()) return false;
1619 while(n
> 0 && m_CursorLine
)
1623 m_CursorLine
= m_CursorLine
->GetNextLine();
1627 m_CursorLine
= last
;
1633 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1634 m_CursorPos
.x
= m_CursorLine
->GetLength();
1639 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1645 wxLayoutList::MoveCursorHorizontally(int n
)
1647 AddCursorPosToUpdateRect();
1649 wxPoint cursorPosOld
= m_CursorPos
;
1654 if(m_CursorPos
.x
== 0) // at begin of line
1656 if(! MoveCursorVertically(-1))
1658 MoveCursorToEndOfLine();
1663 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1664 m_CursorPos
.x
-= move
; n
+= move
;
1669 int len
= m_CursorLine
->GetLength();
1670 if(m_CursorPos
.x
== len
) // at end of line
1672 if(! MoveCursorVertically(1))
1674 MoveCursorToBeginOfLine();
1679 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1680 m_CursorPos
.x
+= move
;
1684 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1690 wxLayoutList::MoveCursorWord(int n
)
1692 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1693 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1695 CoordType moveDistance
= 0;
1697 for ( wxLOiterator i
= m_CursorLine
->FindObject(m_CursorPos
.x
, &offset
);
1704 wxLayoutObject
*obj
= *i
;
1705 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1707 // any non text objects count as one word
1710 moveDistance
+= obj
->GetLength();
1715 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1717 if ( offset
== tobj
->GetLength() )
1724 const char *start
= tobj
->GetText().c_str();
1725 const char *p
= start
+ offset
;
1727 // to the beginning/end of the next/prev word
1728 while ( isspace(*p
) )
1733 // go to the end/beginning of the word (in a broad sense...)
1734 while ( p
>= start
&& !isspace(*p
) )
1741 // now advance to the beginning of the next word
1742 while ( isspace(*p
) )
1748 moveDistance
= p
- start
- offset
;
1752 // except for the first iteration, offset is 0
1756 MoveCursorHorizontally(moveDistance
);
1762 wxLayoutList::Insert(wxString
const &text
)
1764 wxASSERT(m_CursorLine
);
1765 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1770 AddCursorPosToUpdateRect();
1772 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1775 m_CursorPos
.x
+= text
.Length();
1777 m_movedCursor
= true;
1779 m_CursorLine
->RecalculatePositions(0, this);
1785 wxLayoutList::Insert(wxLayoutObject
*obj
)
1787 wxASSERT(m_CursorLine
);
1790 m_CursorLine
= GetFirstLine();
1792 AddCursorPosToUpdateRect();
1794 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1795 m_CursorPos
.x
+= obj
->GetLength();
1796 m_movedCursor
= true;
1798 m_CursorLine
->RecalculatePositions(0, this);
1804 wxLayoutList::Insert(wxLayoutList
*llist
)
1809 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1811 line
= line
->GetNextLine()
1814 for(wxLOiterator i
= line
->GetFirstObject();
1824 wxLayoutList::LineBreak(void)
1826 wxASSERT(m_CursorLine
);
1827 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1829 AddCursorPosToUpdateRect();
1831 wxPoint
position(m_CursorLine
->GetPosition());
1833 wxCoord width
= m_CursorLine
->GetWidth(),
1834 height
= m_CursorLine
->GetHeight();
1836 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1837 if(setFirst
) // we were at beginning of first line
1838 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1839 if(m_CursorPos
.x
!= 0)
1843 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
1844 wxCHECK_MSG(prev
, false, "just broke the line, where is the previous one?");
1846 height
+= prev
->GetHeight();
1848 m_movedCursor
= true;
1850 SetUpdateRect(position
);
1851 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
1852 position
.y
+ height
+ MSW_CORRECTION
);
1858 wxLayoutList::WrapLine(CoordType column
)
1860 if(m_CursorPos
.x
<= column
|| column
< 1)
1861 return false; // do nothing yet
1864 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1866 return false; // cannot break line
1868 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1869 m_CursorPos
.x
= xpos
;
1871 AddCursorPosToUpdateRect();
1874 Delete(1); // delete the space
1875 m_CursorPos
.x
= newpos
;
1877 m_CursorLine
->RecalculatePositions(1, this);
1879 m_movedCursor
= true;
1886 wxLayoutList::Delete(CoordType npos
)
1888 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
1893 AddCursorPosToUpdateRect();
1895 // were other lines appended to this one (this is important to know because
1896 // this means that our width _increased_ as the result of deletion)
1897 bool wasMerged
= false;
1899 // the size of the region to update
1900 CoordType totalHeight
= m_CursorLine
->GetHeight(),
1901 totalWidth
= m_CursorLine
->GetWidth();
1906 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1910 // More to delete, continue on next line.
1912 // First, check if line is empty:
1913 if(m_CursorLine
->GetLength() == 0)
1915 // in this case, updating could probably be optimised
1917 wxASSERT(DeleteLines(1) == 0);
1926 // Need to join next line
1927 if(! m_CursorLine
->GetNextLine())
1932 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
1935 totalHeight
+= next
->GetHeight();
1936 totalWidth
+= next
->GetWidth();
1938 m_CursorLine
->MergeNextLine(this);
1943 wxFAIL_MSG("can't delete all this");
1953 // we need to update the whole tail of the line and the lines which
1957 wxPoint
position(m_CursorLine
->GetPosition());
1958 SetUpdateRect(position
);
1959 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
1960 position
.y
+ totalHeight
+ MSW_CORRECTION
);
1967 wxLayoutList::DeleteLines(int n
)
1969 wxASSERT(m_CursorLine
);
1972 AddCursorPosToUpdateRect();
1976 if(!m_CursorLine
->GetNextLine())
1977 { // we cannot delete this line, but we can clear it
1978 MoveCursorToBeginOfLine();
1979 DeleteToEndOfLine();
1980 m_CursorLine
->RecalculatePositions(2, this);
1984 line
= m_CursorLine
;
1985 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1987 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1988 wxASSERT(m_FirstLine
);
1989 wxASSERT(m_CursorLine
);
1991 m_CursorLine
->RecalculatePositions(2, this);
1996 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1998 wxLayoutLine
*line
= m_FirstLine
;
2000 // first, make sure everything is calculated - this might not be
2001 // needed, optimise it later
2002 ApplyStyle(&m_DefaultSetting
, dc
);
2005 line
->RecalculatePosition(this); // so we don't need to do it all the time
2006 // little condition to speed up redrawing:
2007 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2008 line
= line
->GetNextLine();
2013 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
,
2014 bool resetCursorMovedFlag
,
2015 const wxPoint
& translate
)
2017 wxCHECK_RET( m_CursorLine
, "no cursor line" );
2019 if ( m_movedCursor
)
2021 m_CursorLine
->Layout(dc
, this,
2022 &m_CursorScreenPos
, &m_CursorSize
,
2025 if ( resetCursorMovedFlag
)
2027 #ifdef WXLAYOUT_USE_CARET
2028 // adjust the caret position
2029 wxPoint
coords(m_CursorScreenPos
);
2030 coords
+= translate
;
2033 m_caret
->Move(coords
);
2034 #endif // WXLAYOUT_USE_CARET
2036 m_movedCursor
= false;
2042 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2044 // this function is called with wxMemoryDC argument from ScrollToCursor(),
2045 // for example, so it shouldn't clear "cursor moved" flag - or else the
2046 // cursor won't be moved when UpdateCursorScreenPos() is called with the
2047 // "real" (i.e. the one used for drawing) wxDC.
2048 UpdateCursorScreenPos(dc
, false /* don't reset the flag */);
2050 return m_CursorScreenPos
;
2054 Is called before each Draw(). Now, it will re-layout all lines which
2058 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
)
2060 // first, make sure everything is calculated - this might not be
2061 // needed, optimise it later
2062 ApplyStyle(&m_DefaultSetting
, dc
);
2064 // FIXME this is completely wrong - we should start by first *visible* line
2065 // (and stop on the last one) instead of looping over all lines!!
2066 wxLayoutLine
*line
= m_FirstLine
;
2069 if(forceAll
|| line
->IsDirty())
2071 line
->GetStyleInfo() = m_CurrentSetting
;
2072 if(line
== m_CursorLine
)
2073 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
,
2074 (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
2076 line
->Layout(dc
, this);
2078 // little condition to speed up redrawing:
2079 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2083 line
->RecalculatePositions(1, this);
2084 line
= line
->GetNextLine();
2087 ///FIXME: disabled for now
2089 // can only be 0 if we are on the first line and have no next line
2090 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2091 m_CursorLine
->GetNextLine() == NULL
&&
2092 m_CursorLine
== m_FirstLine
));
2094 AddCursorPosToUpdateRect();
2098 wxLayoutList::Draw(wxDC
&dc
,
2099 wxPoint
const &offset
,
2103 wxLayoutLine
*line
= m_FirstLine
;
2106 ApplyStyle(&m_DefaultSetting
, dc
);
2107 wxBrush
brush(m_CurrentSetting
.m_bg
, wxSOLID
);
2109 dc
.SetBackgroundMode(wxTRANSPARENT
);
2113 // only draw if between top and bottom:
2114 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
2115 line
->Draw(dc
, this, offset
);
2117 line
->Layout(dc
, this);
2118 // little condition to speed up redrawing:
2119 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2120 line
= line
->GetNextLine();
2122 InvalidateUpdateRect();
2124 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2125 m_Selection
.m_valid
? "valid" : "invalid",
2126 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2127 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2131 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2135 // First, find the right line:
2136 wxLayoutLine
*line
= m_FirstLine
;
2139 ApplyStyle(&m_DefaultSetting
, dc
);
2142 p
= line
->GetPosition();
2143 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2146 // we need to run a layout here to get font sizes right :-(
2148 // VZ: we can't call Layout() from here because it marks the line as
2149 // clean and it is not refreshed when it's called from wxLayoutList::
2150 // Layout() - if we really need to do this, we should introduce an
2151 // extra argument to Layout() to prevent the line from MarkClean()ing
2153 line
->Layout(dc
, this);
2155 line
= line
->GetNextLine();
2159 if(found
) *found
= false;
2160 return NULL
; // not found
2162 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
2163 // Now, find the object in the line:
2164 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
2165 cursorPos
? & cursorPos
->x
: NULL
,
2167 return (i
== NULLIT
) ? NULL
: *i
;
2172 wxLayoutList::GetSize(void) const
2175 *line
= m_FirstLine
,
2178 return wxPoint(0,0);
2180 wxPoint
maxPoint(0,0);
2185 if(line
->GetWidth() > maxPoint
.x
)
2186 maxPoint
.x
= line
->GetWidth();
2188 line
= line
->GetNextLine();
2191 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2193 // if the line was just added, its height would be 0 and we can't call
2194 // Layout() from here because we don't have a dc and we might be not drawing
2195 // at all, besides... So take the cursor height by default (taking 0 is bad
2196 // because then the scrollbars won't be resized and the new line won't be
2198 if ( last
->IsDirty() )
2200 if ( last
->GetHeight() == 0 )
2201 maxPoint
.y
+= m_CursorSize
.y
;
2202 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2203 maxPoint
.x
= m_CursorSize
.x
;
2211 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2213 wxPoint
coords(m_CursorScreenPos
);
2214 coords
+= translate
;
2216 #ifdef WXLAYOUT_DEBUG
2217 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2218 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2219 (long)coords
.x
, (long)coords
.y
,
2220 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2221 (long)m_CursorLine
->GetLineNumber(),
2222 (long)m_CursorLine
->GetLength()));
2224 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2227 #ifndef WXLAYOUT_USE_CARET
2228 dc
.SetBrush(*wxBLACK_BRUSH
);
2229 dc
.SetLogicalFunction(wxXOR
);
2230 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2233 dc
.DrawRectangle(coords
.x
, coords
.y
,
2234 m_CursorSize
.x
, m_CursorSize
.y
);
2235 SetUpdateRect(coords
.x
, coords
.y
);
2236 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2240 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2241 coords
.x
, coords
.y
);
2242 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2243 SetUpdateRect(coords
.x
, coords
.y
);
2245 dc
.SetLogicalFunction(wxCOPY
);
2246 //dc.SetBrush(wxNullBrush);
2247 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2251 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2253 if(m_UpdateRectValid
)
2254 GrowRect(m_UpdateRect
, x
, y
);
2259 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2260 m_UpdateRect
.height
= 4;// wxGTK :-)
2261 m_UpdateRectValid
= true;
2266 wxLayoutList::StartSelection(wxPoint cpos
)
2270 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2271 m_Selection
.m_CursorA
= cpos
;
2272 m_Selection
.m_CursorB
= cpos
;
2273 m_Selection
.m_selecting
= true;
2274 m_Selection
.m_valid
= false;
2278 wxLayoutList::ContinueSelection(wxPoint cpos
)
2282 wxASSERT(m_Selection
.m_selecting
== true);
2283 wxASSERT(m_Selection
.m_valid
== false);
2284 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2285 if(m_Selection
.m_CursorB
<= cpos
)
2286 m_Selection
.m_CursorB
= cpos
;
2288 m_Selection
.m_CursorA
= cpos
;
2289 // We always want m_CursorA <= m_CursorB!
2290 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
2292 wxPoint help
= m_Selection
.m_CursorB
;
2293 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2294 m_Selection
.m_CursorA
= help
;
2299 wxLayoutList::EndSelection(wxPoint cpos
)
2303 ContinueSelection(cpos
);
2304 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2305 m_Selection
.m_selecting
= false;
2306 m_Selection
.m_valid
= true;
2311 wxLayoutList::IsSelecting(void)
2313 return m_Selection
.m_selecting
;
2317 wxLayoutList::IsSelected(const wxPoint
&cursor
)
2319 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2321 return m_Selection
.m_CursorA
<= cursor
2322 && cursor
<= m_Selection
.m_CursorB
;
2326 /** Tests whether this layout line is selected and needs
2328 @param line to test for
2329 @return 0 = not selected, 1 = fully selected, -1 = partially
2333 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2336 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2338 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2341 CoordType y
= line
->GetLineNumber();
2342 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2344 else if(m_Selection
.m_CursorA
.y
== y
)
2346 *from
= m_Selection
.m_CursorA
.x
;
2347 if(m_Selection
.m_CursorB
.y
== y
)
2348 *to
= m_Selection
.m_CursorB
.x
;
2350 *to
= line
->GetLength();
2353 else if(m_Selection
.m_CursorB
.y
== y
)
2355 *to
= m_Selection
.m_CursorB
.x
;
2356 if(m_Selection
.m_CursorA
.y
== y
)
2357 *from
= m_Selection
.m_CursorA
.x
;
2367 wxLayoutList::DeleteSelection(void)
2369 if(! m_Selection
.m_valid
)
2372 m_Selection
.m_valid
= false;
2374 // Only delete part of the current line?
2375 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2377 MoveCursorTo(m_Selection
.m_CursorA
);
2378 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2387 for(firstLine
= m_FirstLine
;
2388 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
2389 firstLine
=firstLine
->GetNextLine())
2391 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
2395 for(lastLine
= m_FirstLine
;
2396 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
2397 lastLine
=lastLine
->GetNextLine())
2399 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
2403 // We now know that the two lines are different:
2405 // First, delete what's left of this line:
2406 MoveCursorTo(m_Selection
.m_CursorA
);
2407 DeleteToEndOfLine();
2409 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
2410 while(nextLine
&& nextLine
!= lastLine
)
2411 nextLine
= nextLine
->DeleteLine(false, this);
2413 // Now nextLine = lastLine;
2414 Delete(1); // This joins firstLine and nextLine
2415 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
2419 firstLine
->RecalculatePositions(1, this);
2422 /// Starts highlighting the selection
2424 wxLayoutList::StartHighlighting(wxDC
&dc
)
2427 dc
.SetTextForeground(m_CurrentSetting
.m_bg
);
2428 dc
.SetTextBackground(m_CurrentSetting
.m_fg
);
2429 dc
.SetBackgroundMode(wxSOLID
);
2433 /// Ends highlighting the selection
2435 wxLayoutList::EndHighlighting(wxDC
&dc
)
2438 dc
.SetTextForeground(m_CurrentSetting
.m_fg
);
2439 dc
.SetTextBackground(m_CurrentSetting
.m_bg
);
2440 dc
.SetBackgroundMode(wxTRANSPARENT
);
2446 wxLayoutList::Copy(const wxPoint
&from
,
2453 for(firstLine
= m_FirstLine
;
2454 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2455 firstLine
=firstLine
->GetNextLine())
2457 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2460 for(lastLine
= m_FirstLine
;
2461 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2462 lastLine
=lastLine
->GetNextLine())
2464 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2469 wxLayoutLine
*tmp
= firstLine
;
2470 firstLine
= lastLine
;
2474 wxLayoutList
*llist
= new wxLayoutList();
2476 if(firstLine
== lastLine
)
2478 firstLine
->Copy(llist
, from
.x
, to
.x
);
2482 // Extract objects from first line
2483 firstLine
->Copy(llist
, from
.x
);
2485 // Extract all lines between
2486 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2488 line
= line
->GetNextLine())
2493 // Extract objects from last line
2494 lastLine
->Copy(llist
, 0, to
.x
);
2500 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2502 if(! m_Selection
.m_valid
)
2504 if(m_Selection
.m_selecting
)
2510 if(invalidate
) m_Selection
.m_valid
= false;
2512 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2513 m_Selection
.m_CursorB
);
2515 if(llist
&& wxlo
) // export as data object, too
2519 wxLayoutExportObject
*export
;
2520 wxLayoutExportStatus
status(llist
);
2521 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2523 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2524 ; //FIXME missing support for linebreaks in string format
2526 export
->content
.object
->Write(string
);
2530 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2537 #define COPY_SI(what) if(si->what != -1) { m_CurrentSetting.what = si->what; fontChanged = TRUE; }
2540 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
*si
, wxDC
&dc
)
2542 bool fontChanged
= FALSE
;
2549 dc
.SetFont( m_FontCache
.GetFont(m_CurrentSetting
) );
2553 m_CurrentSetting
.m_fg
= si
->m_fg
;
2554 dc
.SetTextForeground(m_CurrentSetting
.m_fg
);
2558 m_CurrentSetting
.m_bg
= si
->m_bg
;
2559 dc
.SetTextBackground(m_CurrentSetting
.m_bg
);
2564 #ifdef WXLAYOUT_DEBUG
2567 wxLayoutList::Debug(void)
2572 for(line
= m_FirstLine
;
2574 line
= line
->GetNextLine())
2581 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2585 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2587 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2588 wxString
const & title
)
2593 // remove any highlighting which could interfere with printing:
2594 m_llist
->StartSelection();
2595 m_llist
->EndSelection();
2598 wxLayoutPrintout::~wxLayoutPrintout()
2603 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2605 // The following bit is taken from the printing sample, let's see
2606 // whether it works for us.
2608 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2609 * the screen text size. This page also draws lines of actual length 5cm
2612 // Get the logical pixels per inch of screen and printer
2613 int ppiScreenX
, ppiScreenY
;
2614 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2615 int ppiPrinterX
, ppiPrinterY
;
2616 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2618 if(ppiScreenX
== 0) // not yet set, need to guess
2623 if(ppiPrinterX
== 0) // not yet set, need to guess
2629 // This scales the DC so that the printout roughly represents the
2630 // the screen scaling. The text point size _should_ be the right size
2631 // but in fact is too small for some reason. This is a detail that will
2632 // need to be addressed at some point but can be fudged for the
2634 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2636 // Now we have to check in case our real page size is reduced
2637 // (e.g. because we're drawing to a print preview memory DC)
2638 int pageWidth
, pageHeight
;
2640 dc
->GetSize(&w
, &h
);
2641 GetPageSizePixels(&pageWidth
, &pageHeight
);
2642 if(pageWidth
!= 0) // doesn't work always
2644 // If printer pageWidth == current DC width, then this doesn't
2645 // change. But w might be the preview bitmap width, so scale down.
2646 scale
= scale
* (float)(w
/(float)pageWidth
);
2648 dc
->SetUserScale(scale
, scale
);
2652 bool wxLayoutPrintout::OnPrintPage(int page
)
2661 top
= (page
- 1)*m_PrintoutHeight
;
2662 bottom
= top
+ m_PrintoutHeight
;
2663 // SetDeviceOrigin() doesn't work here, so we need to manually
2664 // translate all coordinates.
2665 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2666 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2673 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2675 /* We allocate a temporary wxDC for printing, so that we can
2676 determine the correct paper size and scaling. We don't actually
2677 print anything on it. */
2679 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2681 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2684 float scale
= ScaleDC(&psdc
);
2686 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2687 // This sets a left/top origin of 15% and 20%:
2688 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2690 // This is the length of the printable area.
2691 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2692 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2696 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2699 *maxPage
= m_NumOfPages
;
2702 *selPageTo
= m_NumOfPages
;
2703 wxRemoveFile(WXLLIST_TEMPFILE
);
2706 bool wxLayoutPrintout::HasPage(int pageNum
)
2708 return pageNum
<= m_NumOfPages
;
2712 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2713 out. It's a waste of paper anyway.
2717 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2718 wxPoint topleft
, wxPoint bottomright
,
2721 // make backups of all essential parameters
2722 const wxBrush
& brush
= dc
.GetBrush();
2723 const wxPen
& pen
= dc
.GetPen();
2724 const wxFont
& font
= dc
.GetFont();
2726 dc
.SetBrush(*wxWHITE_BRUSH
);
2727 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2728 dc
.DrawRoundedRectangle(topleft
.x
,
2729 topleft
.y
,bottomright
.x
-topleft
.x
,
2730 bottomright
.y
-topleft
.y
);
2731 dc
.SetBrush(*wxBLACK_BRUSH
);
2732 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2733 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2737 page
= "9999/9999 "; // many pages...
2739 dc
.GetTextExtent(page
,&w
,&h
);
2740 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2741 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2742 dc
.GetTextExtent("XXXX", &w
,&h
);
2743 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2754 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2757 for(wxFCEList::iterator i
= m_FontList
.begin();
2758 i
!= m_FontList
.end(); i
++)
2759 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2760 return (**i
).GetFont();
2762 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2764 m_FontList
.push_back(fce
);
2765 return fce
->GetFont();