1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
13 Layout() recalculates the objects, sizes, etc.
14 Draw() just draws them with the current settings, without
15 re-layout()ing them again
17 Each line has its own wxLayoutStyleInfo structure which gets updated
18 from within Layout(). Thanks to this, we don't need to re-layout all
19 lines if we want to draw one, but can just use its styleinfo to set
25 # pragma implementation "wxllist.h"
28 #include <wx/wxprec.h>
38 # include "gui/wxllist.h"
39 # include "gui/wxlparser.h"
40 # define SHOW_SELECTIONS 1
43 # include "wxlparser.h"
44 # define SHOW_SELECTIONS 1
48 # include <iostream.h>
52 # include <wx/print.h>
54 # include <wx/filefn.h>
57 #ifdef WXLAYOUT_USE_CARET
58 # include <wx/caret.h>
59 #endif // WXLAYOUT_USE_CARET
63 /// This should never really get created
64 #define WXLLIST_TEMPFILE "__wxllist.tmp"
68 # define TypeString(t) g_aTypeStrings[t]
69 # define WXLO_DEBUG(x) wxLogDebug x
71 static const char *g_aTypeStrings
[] =
73 "invalid", "text", "cmd", "icon"
76 wxLayoutObject::Debug(void)
78 WXLO_DEBUG(("%s",g_aTypeStrings
[GetType()]));
81 # define TypeString(t) ""
82 # define WXLO_DEBUG(x)
85 // FIXME under MSW, this constant is needed to make the thing properly redraw
86 // itself - I don't know where the size calculation error is and I can't
87 // waste time looking for it right now. Search for occurences of
88 // MSW_CORRECTION to find all the places where I did it.
90 static const int MSW_CORRECTION
= 10;
92 static const int MSW_CORRECTION
= 0;
95 /// Cursors smaller than this disappear in XOR drawing mode
96 #define WXLO_MINIMUM_CURSOR_WIDTH 4
98 /// Use this character to estimate a cursor size when none is available.
99 #define WXLO_CURSORCHAR "E"
100 /** @name Helper functions */
102 /// allows me to compare to wxPoints
103 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
105 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
109 The following STAY HERE until we have a working wxGTK again!!!
111 #ifndef wxWANTS_CHARS
112 /// allows me to compare to wxPoints
113 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
115 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
118 /// allows me to compare to wxPoints
119 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
121 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
124 wxPoint
& operator += (wxPoint
&p1
, wxPoint
const &p2
)
132 /// allows me to compare to wxPoints
133 bool operator>(wxPoint
const &p1
, wxPoint
const &p2
)
138 /// grows a wxRect so that it includes the given point
141 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
145 else if(r
.x
+ r
.width
< x
)
150 else if(r
.y
+ r
.height
< y
)
156 /// returns true if the point is in the rectangle
158 bool Contains(const wxRect
&r
, const wxPoint
&p
)
160 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
168 void ReadString(wxString
&to
, wxString
&from
)
171 const char *cptr
= from
.c_str();
172 while(*cptr
&& *cptr
!= '\n')
178 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
182 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
186 wxLayoutObject::Read(wxString
&istr
)
189 ReadString(tmp
, istr
);
191 sscanf(tmp
.c_str(),"%d", &type
);
196 return wxLayoutObjectText::Read(istr
);
198 return wxLayoutObjectCmd::Read(istr
);
200 return wxLayoutObjectIcon::Read(istr
);
206 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
210 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
212 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
222 wxLayoutObjectText::Copy(void)
224 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
225 obj
->m_Width
= m_Width
;
226 obj
->m_Height
= m_Height
;
228 obj
->m_Bottom
= m_Bottom
;
229 obj
->SetUserData(m_UserData
);
235 wxLayoutObjectText::Write(wxString
&ostr
)
237 ostr
<< (int) WXLO_TYPE_TEXT
<< '\n'
242 wxLayoutObjectText::Read(wxString
&istr
)
245 ReadString(text
, istr
);
247 return new wxLayoutObjectText(text
);
251 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
254 *top
= m_Top
; *bottom
= m_Bottom
;
255 return wxPoint(m_Width
, m_Height
);
259 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
260 wxLayoutList
*wxllist
,
261 CoordType begin
, CoordType end
)
265 // draw the whole object normally
266 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
270 // highlight the bit between begin and len
273 ypos
= coords
.y
-m_Top
;
274 long width
, height
, descent
;
276 if(begin
< 0) begin
= 0;
277 if( end
> (signed)m_Text
.Length() )
278 end
= m_Text
.Length();
280 wxString str
= m_Text
.Mid(0, begin
);
281 dc
.DrawText(str
, xpos
, ypos
);
282 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
284 wxllist
->StartHighlighting(dc
);
285 str
= m_Text
.Mid(begin
, end
-begin
);
286 dc
.DrawText(str
, xpos
, ypos
);
287 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
289 wxllist
->EndHighlighting(dc
);
290 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
291 dc
.DrawText(str
, xpos
, ypos
);
296 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
300 maxlen
= m_Text
.Length();
303 height
, descent
= 0l;
305 if(xpos
== 0) return 0; // easy
307 while(width
< xpos
&& offs
< maxlen
)
309 dc
.GetTextExtent(m_Text
.substr(0,offs
),
310 &width
, &height
, &descent
);
313 /* We have to substract 1 to compensate for the offs++, and another
314 one because we don't want to position the cursor behind the
315 object what we clicked on, but before - otherwise it looks
317 return (xpos
> 2) ? offs
-2 : 0;
321 wxLayoutObjectText::Layout(wxDC
&dc
, class wxLayoutList
*llist
)
325 // now this is done in wxLayoutLine::Layout(), but this code might be
326 // reenabled later - in principle, it's more efficient
328 CoordType widthOld
= m_Width
,
329 heightOld
= m_Height
;
332 dc
.GetTextExtent(m_Text
, &m_Width
, &m_Height
, &descent
);
335 if ( widthOld
!= m_Width
|| heightOld
!= m_Height
)
337 // as the text length changed, it must be refreshed
338 wxLayoutLine
*line
= GetLine();
340 wxCHECK_RET( line
, "wxLayoutObjectText can't refresh itself" );
342 // as our size changed, we need to repaint the part which was appended
343 wxPoint
position(line
->GetPosition());
345 // this is not the most efficient way (we repaint the whole line), but
346 // it's not too slow and is *simple*
347 if ( widthOld
< m_Width
)
349 if ( heightOld
< m_Height
)
350 heightOld
= m_Height
;
352 llist
->SetUpdateRect(position
.x
+ widthOld
+ MSW_CORRECTION
,
353 position
.y
+ heightOld
+ MSW_CORRECTION
);
358 m_Top
= m_Height
- m_Bottom
;
362 #ifdef WXLAYOUT_DEBUG
364 wxLayoutObjectText::Debug(void)
366 wxLayoutObject::Debug();
367 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
371 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
375 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
377 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
381 wxFAIL_MSG("invalid icon");
389 // FIXME ugly, ugly, ugly - but the only way to avoid slicing
390 m_Icon
= icon
.GetHBITMAP() ? new wxBitmap(icon
)
391 : new wxBitmap(wxBitmap((const wxBitmap
&)icon
));
393 m_Icon
= new wxBitmap(icon
);
399 wxLayoutObjectIcon::Write(wxString
&ostr
)
401 /* Exports icon through a temporary file. */
403 wxString file
= wxGetTempFileName("wxloexport");
405 ostr
<< WXLO_TYPE_ICON
<< '\n'
407 m_Icon
->SaveFile(file
, WXLO_BITMAP_FORMAT
);
411 wxLayoutObjectIcon::Read(wxString
&istr
)
414 ReadString(file
, istr
);
416 if(! wxFileExists(file
))
418 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon
;
420 if(!obj
->m_Icon
->LoadFile(file
, WXLO_BITMAP_FORMAT
))
430 wxLayoutObjectIcon::Copy(void)
432 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
434 obj
->SetUserData(m_UserData
);
438 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
444 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
445 wxLayoutList
*wxllist
,
446 CoordType begin
, CoordType
/* len */)
448 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
449 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
453 wxLayoutObjectIcon::Layout(wxDC
& /* dc */, class wxLayoutList
* )
458 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
460 *top
= m_Icon
->GetHeight();
462 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
467 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
471 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
474 wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily
,
486 underline
= iul
!= 0;
488 m_fg_valid
= fg
!= 0;
489 m_bg_valid
= bg
!= 0;
490 m_fg
= m_fg_valid
? *fg
: *wxBLACK
;
491 m_bg
= m_bg_valid
? *bg
: *wxWHITE
;
494 #define COPY_SI_(what) if(right.what != -1) what = right.what;
497 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
504 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
505 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
509 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
510 weight
, int underline
,
511 wxColour
*fg
, wxColour
*bg
)
514 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
518 wxLayoutObjectCmd::Copy(void)
520 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
525 m_StyleInfo
->underline
,
526 m_StyleInfo
->m_fg_valid
?
527 &m_StyleInfo
->m_fg
: NULL
,
528 m_StyleInfo
->m_bg_valid
?
529 &m_StyleInfo
->m_bg
: NULL
);
530 obj
->SetUserData(m_UserData
);
535 wxLayoutObjectCmd::Write(wxString
&ostr
)
537 ostr
<< WXLO_TYPE_CMD
<< '\n'
538 << m_StyleInfo
->size
<< '\n'
539 << m_StyleInfo
->family
<< '\n'
540 << m_StyleInfo
->style
<< '\n'
541 << m_StyleInfo
->weight
<< '\n'
542 << m_StyleInfo
->underline
<< '\n'
543 << m_StyleInfo
->m_fg_valid
<< '\n'
544 << m_StyleInfo
->m_bg_valid
<< '\n';
545 if(m_StyleInfo
->m_fg_valid
)
547 ostr
<< m_StyleInfo
->m_fg
.Red() << '\n'
548 << m_StyleInfo
->m_fg
.Green() << '\n'
549 << m_StyleInfo
->m_fg
.Blue() << '\n';
551 if(m_StyleInfo
->m_bg_valid
)
553 ostr
<< m_StyleInfo
->m_bg
.Red() << '\n'
554 << m_StyleInfo
->m_bg
.Green() << '\n'
555 << m_StyleInfo
->m_bg
.Blue() << '\n';
560 wxLayoutObjectCmd::Read(wxString
&istr
)
562 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd
;
565 ReadString(tmp
, istr
);
566 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->size
);
567 ReadString(tmp
, istr
);
568 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->family
);
569 ReadString(tmp
, istr
);
570 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->style
);
571 ReadString(tmp
, istr
);
572 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->weight
);
573 ReadString(tmp
, istr
);
574 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->underline
);
575 ReadString(tmp
, istr
);
576 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_fg_valid
);
577 ReadString(tmp
, istr
);
578 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_bg_valid
);
579 if(obj
->m_StyleInfo
->m_fg_valid
)
581 int red
, green
, blue
;
582 ReadString(tmp
, istr
);
583 sscanf(tmp
.c_str(),"%d", &red
);
584 ReadString(tmp
, istr
);
585 sscanf(tmp
.c_str(),"%d", &green
);
586 ReadString(tmp
, istr
);
587 sscanf(tmp
.c_str(),"%d", &blue
);
588 obj
->m_StyleInfo
->m_fg
= wxColour(red
, green
, blue
);
590 if(obj
->m_StyleInfo
->m_bg_valid
)
592 int red
, green
, blue
;
593 ReadString(tmp
, istr
);
594 sscanf(tmp
.c_str(),"%d", &red
);
595 ReadString(tmp
, istr
);
596 sscanf(tmp
.c_str(),"%d", &green
);
597 ReadString(tmp
, istr
);
598 sscanf(tmp
.c_str(),"%d", &blue
);
599 obj
->m_StyleInfo
->m_bg
= wxColour(red
, green
, blue
);
605 wxLayoutObjectCmd::~wxLayoutObjectCmd()
611 wxLayoutObjectCmd::GetStyle(void) const
617 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
618 wxLayoutList
*wxllist
,
619 CoordType begin
, CoordType
/* len */)
621 wxASSERT(m_StyleInfo
);
622 wxllist
->ApplyStyle(*m_StyleInfo
, dc
);
626 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
628 // this get called, so that recalculation uses right font sizes
629 Draw(dc
, wxPoint(0,0), llist
);
633 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
635 The wxLayoutLine object
637 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
639 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
641 m_Width
= m_Height
= 0;
651 RecalculatePosition(llist
);
656 m_LineNumber
= m_Previous
->GetLineNumber() + 1;
657 m_Next
= m_Previous
->GetNextLine();
658 m_Previous
->m_Next
= this;
663 m_Next
->m_Previous
= this;
667 m_StyleInfo
= llist
->GetDefaultStyleInfo();
669 llist
->IncNumLines();
672 wxLayoutLine::~wxLayoutLine()
674 // kbList cleans itself
678 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
680 wxASSERT(m_Previous
|| GetLineNumber() == 0);
682 wxPoint
posOld(m_Position
);
686 m_Position
= m_Previous
->GetPosition();
687 m_Position
.y
+= m_Previous
->GetHeight();
690 m_Position
= wxPoint(0,0);
692 if ( m_Position
!= posOld
)
694 // the whole line moved and must be repainted
695 llist
->SetUpdateRect(m_Position
);
696 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
697 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
698 llist
->SetUpdateRect(posOld
);
699 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
700 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
707 wxLayoutObjectList::iterator
708 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
712 wxLayoutObjectList::iterator
715 CoordType x
= 0, len
;
717 /* We search through the objects. As we don't like returning the
718 object that the cursor is behind, we just remember such an
719 object in "found" so we can return it if there is really no
720 further object following it. */
721 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
723 len
= (**i
).GetLength();
724 if( x
<= xpos
&& xpos
<= x
+ len
)
727 if(xpos
== x
+ len
) // is there another object behind?
729 else // we are really inside this object
732 x
+= (**i
).GetLength();
734 return found
; // ==NULL if really none found
737 wxLayoutObjectList::iterator
738 wxLayoutLine::FindObjectScreen(wxDC
&dc
, wxLayoutList
*llist
,
739 CoordType xpos
, CoordType
*cxpos
,
744 llist
->ApplyStyle(GetStyleInfo(), dc
);
746 wxLayoutObjectList::iterator i
;
747 CoordType x
= 0, cx
= 0, width
;
749 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
751 wxLayoutObject
*obj
= *i
;
752 if ( obj
->GetType() == WXLO_TYPE_CMD
)
754 // this will set the correct font for the objects which follow
755 obj
->Layout(dc
, llist
);
758 width
= obj
->GetWidth();
759 if( x
<= xpos
&& xpos
<= x
+ width
)
761 *cxpos
= cx
+ obj
->GetOffsetScreen(dc
, xpos
-x
);
768 x
+= obj
->GetWidth();
769 cx
+= obj
->GetLength();
772 // behind last object:
777 return m_ObjectList
.tail();
780 /** Finds text in this line.
781 @param needle the text to find
782 @param xpos the position where to start the search
783 @return the cursoor coord where it was found or -1
786 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
791 wxString
const *text
;
793 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
795 if(cpos
>= xpos
) // search from here!
797 if((**i
).GetType() == WXLO_TYPE_TEXT
)
799 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
800 relpos
= text
->Find(needle
);
801 if(relpos
>= cpos
-xpos
) // -1 if not found
806 cpos
+= (**i
).GetLength();
809 return -1; // not found
813 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
816 wxASSERT(obj
!= NULL
);
821 wxLOiterator i
= FindObject(xpos
, &offset
);
824 if(xpos
== 0 ) // aha, empty line!
826 m_ObjectList
.push_back(obj
);
827 m_Length
+= obj
->GetLength();
834 CoordType len
= (**i
).GetLength();
835 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
836 { // insert before this object
837 m_ObjectList
.insert(i
,obj
);
838 m_Length
+= obj
->GetLength();
843 if( i
== m_ObjectList
.tail()) // last object?
844 m_ObjectList
.push_back(obj
);
846 { // insert after current object
848 m_ObjectList
.insert(i
,obj
);
850 m_Length
+= obj
->GetLength();
853 /* Otherwise we need to split the current object.
854 Fortunately this can only be a text object. */
855 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
856 wxString left
, right
;
857 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
858 left
= tobj
->GetText().substr(0,offset
);
859 right
= tobj
->GetText().substr(offset
,len
-offset
);
860 // current text object gets set to right half
861 tobj
->GetText() = right
; // set new text
862 // before it we insert the new object
863 m_ObjectList
.insert(i
,obj
);
864 m_Length
+= obj
->GetLength();
865 // and before that we insert the left half
866 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
871 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
878 wxLOiterator i
= FindObject(xpos
, &offset
);
879 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
881 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
882 tobj
->GetText().insert(offset
, text
);
883 m_Length
+= text
.Length();
887 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
895 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
897 CoordType offset
, len
;
902 wxLOiterator i
= FindObject(xpos
, &offset
);
905 if(i
== NULLIT
) return npos
;
906 // now delete from that object:
907 if((**i
).GetType() != WXLO_TYPE_TEXT
)
909 if(offset
!= 0) // at end of line after a non-text object
912 len
= (**i
).GetLength();
915 m_ObjectList
.erase(i
);
919 // tidy up: remove empty text objects
920 if((**i
).GetLength() == 0)
922 m_ObjectList
.erase(i
);
926 CoordType max
= (**i
).GetLength() - offset
;
927 if(npos
< max
) max
= npos
;
930 if(xpos
== GetLength())
933 { // at the end of an object
934 // move to begin of next object:
936 continue; // start over
941 if(offset
== 0 && max
== (**i
).GetLength())
942 m_ObjectList
.erase(i
); // remove the whole object
944 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
952 wxLayoutLine::DeleteWord(CoordType xpos
)
958 wxLOiterator i
= FindObject(xpos
, &offset
);
962 if(i
== NULLIT
) return false;
963 if((**i
).GetType() != WXLO_TYPE_TEXT
)
965 // This should only happen when at end of line, behind a non-text
967 if(offset
== (**i
).GetLength()) return false;
968 m_Length
-= (**i
).GetLength(); // -1
969 m_ObjectList
.erase(i
);
970 return true; // we are done
974 if(offset
== (**i
).GetLength()) // at end of object
979 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
981 wxString str
= tobj
->GetText();
982 str
= str
.substr(offset
,str
.Length()-offset
);
983 // Find out how many positions we need to delete:
984 // 1. eat leading space
985 while(isspace(str
.c_str()[count
])) count
++;
986 // 2. eat the word itself:
987 while(isalnum(str
.c_str()[count
])) count
++;
989 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
990 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
996 wxFAIL_MSG("unreachable");
1000 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1002 // maintain linked list integrity
1004 m_Next
->m_Previous
= m_Previous
;
1006 m_Previous
->m_Next
= m_Next
;
1008 // get the line numbers right again
1009 if ( update
&& m_Next
)
1014 // we can't use m_Next after "delete this", so we must save this pointer
1016 wxLayoutLine
*next
= m_Next
;
1019 llist
->DecNumLines();
1025 wxLayoutLine::Draw(wxDC
&dc
,
1026 wxLayoutList
*llist
,
1027 const wxPoint
& offset
) const
1029 wxLayoutObjectList::iterator i
;
1030 wxPoint pos
= offset
;
1031 pos
= pos
+ GetPosition();
1033 pos
.y
+= m_BaseLine
;
1035 CoordType xpos
= 0; // cursorpos, lenght of line
1037 CoordType from
, to
, tempto
;
1039 int highlight
= llist
->IsSelected(this, &from
, &to
);
1040 // WXLO_DEBUG(("highlight=%d", highlight ));
1041 if(highlight
== 1) // we need to draw the whole line inverted!
1042 llist
->StartHighlighting(dc
);
1044 llist
->EndHighlighting(dc
);
1046 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1048 if(highlight
== -1) // partially highlight line
1050 // parts of the line need highlighting
1051 tempto
= xpos
+(**i
).GetLength();
1052 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1055 (**i
).Draw(dc
, pos
, llist
);
1056 pos
.x
+= (**i
).GetWidth();
1057 xpos
+= (**i
).GetLength();
1062 This function does all the recalculation, that is, it should only be
1063 called from within wxLayoutList::Layout(), as it uses the current
1064 list's styleinfo and updates it.
1067 wxLayoutLine::Layout(wxDC
&dc
,
1068 wxLayoutList
*llist
,
1070 wxPoint
*cursorSize
,
1071 wxLayoutStyleInfo
*cursorStyle
,
1073 bool suppressSIupdate
)
1075 wxLayoutObjectList::iterator i
;
1077 // when a line becomes dirty, we redraw it from the place where it was
1078 // changed till the end of line (because the following wxLayoutObjects are
1079 // moved when the preceding one changes) - calculate the update rectangle.
1080 CoordType updateTop
= m_Position
.y
,
1082 updateWidth
= m_Width
,
1083 updateHeight
= m_Height
;
1087 bottomHeight
= 0; // above and below baseline
1089 objTopHeight
, objBottomHeight
; // above and below baseline
1093 CoordType heightOld
= m_Height
;
1099 bool cursorFound
= false;
1101 RecalculatePosition(llist
);
1105 *cursorPos
= m_Position
;
1106 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1109 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1110 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1112 wxLayoutObject
*obj
= *i
;
1113 obj
->Layout(dc
, llist
);
1114 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1116 if(cursorPos
&& ! cursorFound
)
1118 // we need to check whether the text cursor is here
1119 len
= obj
->GetLength();
1120 if(count
<= cx
&& count
+len
> cx
)
1122 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1124 len
= cx
- count
; // pos in object
1125 CoordType width
, height
, descent
;
1126 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1127 &width
, &height
, &descent
);
1128 cursorPos
->x
+= width
;
1129 cursorPos
->y
= m_Position
.y
;
1131 if(len
< obj
->GetLength())
1132 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1134 str
= WXLO_CURSORCHAR
;
1135 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1137 if(cursorStyle
) // set style info
1138 *cursorStyle
= llist
->GetStyleInfo();
1141 // Just in case some joker inserted an empty string object:
1143 width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1146 cursorSize
->x
= width
;
1147 cursorSize
->y
= height
;
1150 cursorFound
= true; // no more checks
1154 // on some other object
1155 CoordType top
, bottom
; // unused
1157 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1158 cursorPos
->y
= m_Position
.y
;
1159 cursorFound
= true; // no more checks
1165 cursorPos
->x
+= obj
->GetWidth();
1169 m_Width
+= sizeObj
.x
;
1170 if(sizeObj
.y
> m_Height
)
1172 m_Height
= sizeObj
.y
;
1175 if(objTopHeight
> topHeight
)
1176 topHeight
= objTopHeight
;
1177 if(objBottomHeight
> bottomHeight
)
1178 bottomHeight
= objBottomHeight
;
1183 if ( updateHeight
< m_Height
)
1184 updateHeight
= m_Height
;
1185 if ( updateWidth
< m_Width
)
1186 updateWidth
= m_Width
;
1188 // update all line if we don't know where to start from
1189 if ( updateLeft
== -1 )
1192 llist
->SetUpdateRect(updateLeft
, updateTop
);
1193 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1194 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1197 if(topHeight
+ bottomHeight
> m_Height
)
1199 m_Height
= topHeight
+bottomHeight
;
1202 m_BaseLine
= topHeight
;
1206 CoordType width
, height
, descent
;
1207 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1209 m_BaseLine
= m_Height
- descent
;
1212 // tell next line about coordinate change
1213 if(m_Next
&& m_Height
!= heightOld
)
1215 m_Next
->MarkDirty();
1218 // We need to check whether we found a valid cursor size:
1219 if(cursorPos
&& cursorSize
)
1221 // this might be the case if the cursor is at the end of the
1222 // line or on a command object:
1223 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1225 CoordType width
, height
, descent
;
1226 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1227 cursorSize
->x
= width
;
1228 cursorSize
->y
= height
;
1230 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1231 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1238 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1240 wxASSERT(xpos
>= 0);
1245 wxLOiterator i
= FindObject(xpos
, &offset
);
1247 // must be at the end of the line then
1248 return new wxLayoutLine(this, llist
);
1251 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1252 // split object at i:
1253 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1255 wxString left
, right
;
1256 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1257 left
= tobj
->GetText().substr(0,offset
);
1258 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1259 // current text object gets set to left half
1260 tobj
->GetText() = left
; // set new text
1261 newLine
->Append(new wxLayoutObjectText(right
));
1262 m_Length
-= right
.Length();
1263 i
++; // don't move this object to the new list
1268 i
++; // move objects from here to new list
1271 while(i
!= m_ObjectList
.end())
1273 wxLayoutObject
*obj
= *i
;
1274 newLine
->Append(obj
);
1275 m_Length
-= obj
->GetLength();
1277 m_ObjectList
.remove(i
); // remove without deleting it
1280 m_Next
->MarkDirty();
1285 wxLayoutLine::ReNumber(void)
1287 CoordType lineNo
= m_Previous
? m_Previous
->m_LineNumber
+1 : 0;
1288 m_LineNumber
= lineNo
++;
1290 for(wxLayoutLine
*next
= GetNextLine();
1291 next
; next
= next
->GetNextLine())
1292 next
->m_LineNumber
= lineNo
++;
1296 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1298 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1299 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1302 MarkDirty(GetWidth());
1304 wxLayoutObject
*last
= NULL
;
1305 for(i
= list
.begin(); i
!= list
.end();)
1307 wxLayoutObject
*current
= *i
;
1309 // merge text objects together for efficiency
1310 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1311 current
->GetType() == WXLO_TYPE_TEXT
)
1313 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1314 wxString
text(textObj
->GetText());
1315 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1316 textObj
->SetText(text
);
1318 list
.erase(i
); // remove and delete it
1322 // just append the object "as was"
1325 list
.remove(i
); // remove without deleting it
1328 wxASSERT(list
.empty());
1330 wxLayoutLine
*oldnext
= GetNextLine();
1331 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1335 nextLine
->ReNumber();
1339 // this is now done in Delete(), but if this function is ever called
1340 // from elsewhere, we might have to move refresh code back here (in
1341 // order not to duplicate it)
1343 wxPoint
pos(oldnext
->GetPosition());
1344 llist
->SetUpdateRect(pos
);
1345 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1346 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1350 llist
->DecNumLines();
1356 wxLayoutLine::GetWrapPosition(CoordType column
)
1359 wxLOiterator i
= FindObject(column
, &offset
);
1360 if(i
== NULLIT
) return -1; // cannot wrap
1362 // go backwards through the list and look for space in text objects
1365 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1369 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1376 }while(offset
!= -1);
1377 i
--; // move on to previous object
1381 column
-= (**i
).GetLength();
1385 offset
= (**i
).GetLength();
1386 }while(i
!= NULLIT
);
1387 /* If we reached the begin of the list and have more than one
1388 object, that one is longer than the margin, so break behind
1391 i
= m_ObjectList
.begin();
1392 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1394 pos
+= (**i
).GetLength();
1397 if(i
== NULLIT
) return -1; //why should this happen?
1398 pos
+= (**i
).GetLength();
1400 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1402 pos
+= (**i
).GetLength();
1405 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1406 // now we are at the second text object:
1407 pos
-= (**i
).GetLength();
1408 return pos
; // in front of it
1412 #ifdef WXLAYOUT_DEBUG
1414 wxLayoutLine::Debug(void)
1417 wxPoint pos
= GetPosition();
1418 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1419 (long int) GetLineNumber(),
1420 (long int) pos
.x
, (long int) pos
.y
,
1421 (long int) GetHeight(),
1422 (long int) m_BaseLine
,
1423 (int) m_StyleInfo
.family
));
1424 if(m_ObjectList
.begin() != NULLIT
)
1425 (**m_ObjectList
.begin()).Debug();
1431 wxLayoutLine::Copy(wxLayoutList
*llist
,
1435 CoordType firstOffset
, lastOffset
;
1437 if(to
== -1) to
= GetLength();
1438 if(from
== to
) return;
1440 wxLOiterator first
= FindObject(from
, &firstOffset
);
1441 wxLOiterator last
= FindObject(to
, &lastOffset
);
1443 // Common special case: only one object
1444 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1446 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1448 llist
->Insert(new wxLayoutObjectText(
1449 ((wxLayoutObjectText
1450 *)*first
)->GetText().substr(firstOffset
,
1451 lastOffset
-firstOffset
))
1455 else // what can we do?
1457 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1458 llist
->Insert( (**first
).Copy() );
1463 // If we reach here, we can safely copy the whole first object from
1464 // the firstOffset position on:
1465 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1467 llist
->Insert(new wxLayoutObjectText(
1468 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1471 else if(firstOffset
== 0)
1472 llist
->Insert( (**first
).Copy() );
1473 // else nothing to copy :-(
1475 // Now we copy all objects before the last one:
1476 wxLOiterator i
= first
; i
++;
1477 for( ; i
!= last
; i
++)
1478 llist
->Insert( (**i
).Copy() );
1480 // And now the last object:
1483 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1485 llist
->Insert(new wxLayoutObjectText(
1486 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1490 llist
->Insert( (**last
).Copy() );
1495 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1497 The wxLayoutList object
1499 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1501 wxLayoutList::wxLayoutList()
1503 #ifdef WXLAYOUT_USE_CARET
1505 #endif // WXLAYOUT_USE_CARET
1509 SetAutoFormatting(TRUE
);
1510 ForceTotalLayout(TRUE
); // for the first time, do all
1511 InvalidateUpdateRect();
1515 wxLayoutList::~wxLayoutList()
1517 SetAutoFormatting(FALSE
);
1520 m_FirstLine
->DeleteLine(false, this);
1522 wxASSERT_MSG( m_numLines
== 0, "line count calculation broken" );
1526 wxLayoutList::Empty(void)
1529 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1531 m_CursorPos
= wxPoint(0,0);
1532 m_CursorScreenPos
= wxPoint(0,0);
1533 m_CursorSize
= wxPoint(0,0);
1534 m_movedCursor
= true;
1535 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1536 m_CursorLine
= m_FirstLine
;
1537 InvalidateUpdateRect();
1542 wxLayoutList::InternalClear(void)
1544 m_Selection
.m_selecting
= false;
1545 m_Selection
.m_valid
= false;
1547 m_DefaultStyleInfo
.family
= wxSWISS
;
1548 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1549 m_DefaultStyleInfo
.style
= wxNORMAL
;
1550 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1551 m_DefaultStyleInfo
.underline
= 0;
1552 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1553 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1554 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1555 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1557 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1558 m_CursorStyleInfo
= m_DefaultStyleInfo
;
1562 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1563 int underline
, wxColour
*fg
,
1566 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1567 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1568 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1569 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1570 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1571 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1572 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1574 new wxLayoutObjectCmd(
1575 m_CurrentStyleInfo
.family
,
1576 m_CurrentStyleInfo
.size
,
1577 m_CurrentStyleInfo
.style
,
1578 m_CurrentStyleInfo
.weight
,
1579 m_CurrentStyleInfo
.underline
,
1584 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1585 int underline
, char const *fg
, char const *bg
)
1593 cfg
= wxTheColourDatabase
->FindColour(fg
);
1595 cbg
= wxTheColourDatabase
->FindColour(bg
);
1597 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1601 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1602 int underline
, wxColour
*fg
, wxColour
*bg
)
1605 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1607 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1609 // Empty() should be called after we set m_DefaultStyleInfo because
1610 // otherwise the style info for the first line (created in Empty()) would be
1616 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1621 for(line
= m_FirstLine
;
1623 line
= line
->GetNextLine())
1625 if(line
->GetLineNumber() >= cpos
.y
)
1627 xpos
= line
->FindText(needle
,
1628 (line
->GetLineNumber() == cpos
.y
) ?
1631 return wxPoint(xpos
, line
->GetLineNumber());
1634 return wxPoint(-1,-1);
1639 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1641 AddCursorPosToUpdateRect();
1643 wxPoint cursorPosOld
= m_CursorPos
;
1645 wxLayoutLine
*line
= m_FirstLine
;
1646 while(line
&& line
->GetLineNumber() != p
.y
)
1647 line
= line
->GetNextLine();
1648 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1650 m_CursorPos
.y
= p
.y
;
1651 m_CursorLine
= line
;
1652 CoordType len
= line
->GetLength();
1655 m_CursorPos
.x
= p
.x
;
1659 m_CursorPos
.x
= len
;
1663 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1665 return m_CursorPos
== p
;
1669 wxLayoutList::MoveCursorVertically(int n
)
1671 AddCursorPosToUpdateRect();
1673 wxPoint cursorPosOld
= m_CursorPos
;
1676 if(n
< 0) // move up
1678 if(m_CursorLine
== m_FirstLine
) return false;
1679 while(n
< 0 && m_CursorLine
)
1681 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1687 m_CursorLine
= m_FirstLine
;
1693 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1694 m_CursorPos
.x
= m_CursorLine
->GetLength();
1700 wxLayoutLine
*last
= m_CursorLine
;
1701 if(! m_CursorLine
->GetNextLine()) return false;
1702 while(n
> 0 && m_CursorLine
)
1706 m_CursorLine
= m_CursorLine
->GetNextLine();
1710 m_CursorLine
= last
;
1716 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1717 m_CursorPos
.x
= m_CursorLine
->GetLength();
1722 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1728 wxLayoutList::MoveCursorHorizontally(int n
)
1730 AddCursorPosToUpdateRect();
1732 wxPoint cursorPosOld
= m_CursorPos
;
1737 if(m_CursorPos
.x
== 0) // at begin of line
1739 if(! MoveCursorVertically(-1))
1741 MoveCursorToEndOfLine();
1746 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1747 m_CursorPos
.x
-= move
; n
+= move
;
1752 int len
= m_CursorLine
->GetLength();
1753 if(m_CursorPos
.x
== len
) // at end of line
1755 if(! MoveCursorVertically(1))
1757 MoveCursorToBeginOfLine();
1762 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1763 m_CursorPos
.x
+= move
;
1767 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1773 wxLayoutList::MoveCursorWord(int n
, bool untilNext
)
1775 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1776 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1778 CoordType moveDistance
= 0;
1780 wxLayoutLine
*lineCur
= m_CursorLine
;
1781 for ( wxLOiterator i
= lineCur
->FindObject(m_CursorPos
.x
, &offset
);
1789 // moving forward, pass to the first object of the next line
1791 lineCur
= lineCur
->GetNextLine();
1793 i
= lineCur
->GetFirstObject();
1797 // moving backwards, pass to the last object of the prev line
1799 lineCur
= lineCur
->GetPreviousLine();
1801 i
= lineCur
->GetLastObject();
1806 // moved to the end/beginning of text
1813 wxLayoutObject
*obj
= *i
;
1817 // calculate offset: we are either at the very beginning or the very
1818 // end of the object, so it isn't very difficult (the only time when
1819 // offset is != -1 is for the very first iteration when its value is
1820 // returned by FindObject)
1824 offset
= obj
->GetLength();
1827 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1829 // any visible non text objects count as one word
1830 if ( obj
->IsVisibleObject() )
1834 moveDistance
+= obj
->GetLength();
1839 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1841 bool canAdvance
= true;
1843 if ( offset
== tobj
->GetLength() )
1848 // can't move further in this text object
1851 // still should move over the object border
1855 else if ( offset
> 0 )
1857 // offset is off by 1, make it a valid index
1864 const wxString
& text
= tobj
->GetText();
1865 const char *start
= text
.c_str();
1866 const char *end
= start
+ text
.length();
1867 const char *p
= start
+ offset
;
1875 // to the beginning/end of the next/prev word
1876 while ( p
>= start
&& p
< end
&& isspace(*p
) )
1881 // go to the end/beginning of the word (in a broad sense...)
1882 while ( p
>= start
&& p
< end
&& !isspace(*p
) )
1891 // now advance to the beginning of the next word
1892 while ( isspace(*p
) && p
< end
)
1898 // in these 2 cases we took 1 char too much
1899 if ( (p
< start
) || isspace(*p
) )
1905 CoordType moveDelta
= p
- start
- offset
;
1906 if ( (n
< 0) && (offset
== tobj
->GetLength() - 1) )
1908 // because we substracted 1 from offset in this case above, now
1909 // compensate for it
1913 if ( moveDelta
!= 0 )
1915 moveDistance
+= moveDelta
;
1922 // except for the first iteration, offset is calculated in the beginning
1927 MoveCursorHorizontally(moveDistance
);
1933 wxLayoutList::Insert(wxString
const &text
)
1935 wxASSERT(m_CursorLine
);
1936 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1941 AddCursorPosToUpdateRect();
1943 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1946 m_CursorPos
.x
+= text
.Length();
1948 m_movedCursor
= true;
1951 m_CursorLine
->MarkDirty();
1957 wxLayoutList::Insert(wxLayoutObject
*obj
)
1959 wxASSERT(m_CursorLine
);
1962 m_CursorLine
= GetFirstLine();
1964 AddCursorPosToUpdateRect();
1966 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1967 m_CursorPos
.x
+= obj
->GetLength();
1968 m_movedCursor
= true;
1971 m_CursorLine
->MarkDirty();
1977 wxLayoutList::Insert(wxLayoutList
*llist
)
1982 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1984 line
= line
->GetNextLine()
1987 for(wxLOiterator i
= line
->GetFirstObject();
1997 wxLayoutList::LineBreak(void)
1999 wxASSERT(m_CursorLine
);
2001 AddCursorPosToUpdateRect();
2003 wxPoint
position(m_CursorLine
->GetPosition());
2006 width
= m_CursorLine
->GetWidth(),
2007 height
= m_CursorLine
->GetHeight();
2009 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
2010 if(m_CursorLine
->GetPreviousLine() == NULL
)
2011 m_FirstLine
= m_CursorLine
;
2012 if(m_CursorPos
.x
> 0)
2016 // The following code will produce a height which is guaranteed to
2017 // be too high: old lineheight + the height of both new lines.
2018 // We can probably drop the old line height and start with height =
2020 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
2022 height
+= prev
->GetHeight();
2023 height
+= m_CursorLine
->GetHeight();
2025 m_movedCursor
= true;
2027 SetUpdateRect(position
);
2028 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
2029 position
.y
+ height
+ MSW_CORRECTION
);
2035 wxLayoutList::WrapLine(CoordType column
)
2037 if(m_CursorPos
.x
<= column
|| column
< 1)
2038 return false; // do nothing yet
2041 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
2043 return false; // cannot break line
2045 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
2046 m_CursorPos
.x
= xpos
;
2048 AddCursorPosToUpdateRect();
2051 Delete(1); // delete the space
2052 m_CursorPos
.x
= newpos
;
2054 m_CursorLine
->MarkDirty();
2056 m_movedCursor
= true;
2063 wxLayoutList::Delete(CoordType npos
)
2065 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
2070 AddCursorPosToUpdateRect();
2072 // were other lines appended to this one (this is important to know because
2073 // this means that our width _increased_ as the result of deletion)
2074 bool wasMerged
= false;
2076 // the size of the region to update
2077 CoordType totalHeight
= m_CursorLine
->GetHeight(),
2078 totalWidth
= m_CursorLine
->GetWidth();
2083 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
2087 // More to delete, continue on next line.
2089 // First, check if line is empty:
2090 if(m_CursorLine
->GetLength() == 0)
2092 // in this case, updating could probably be optimised
2094 wxASSERT(DeleteLines(1) == 0);
2103 // Need to join next line
2104 if(! m_CursorLine
->GetNextLine())
2109 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2112 totalHeight
+= next
->GetHeight();
2113 totalWidth
+= next
->GetWidth();
2115 m_CursorLine
->MergeNextLine(this);
2120 wxFAIL_MSG("can't delete all this");
2130 // we need to update the whole tail of the line and the lines which
2134 wxPoint
position(m_CursorLine
->GetPosition());
2135 SetUpdateRect(position
);
2136 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2137 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2144 wxLayoutList::DeleteLines(int n
)
2146 wxASSERT(m_CursorLine
);
2149 AddCursorPosToUpdateRect();
2153 if(!m_CursorLine
->GetNextLine())
2154 { // we cannot delete this line, but we can clear it
2155 MoveCursorToBeginOfLine();
2156 DeleteToEndOfLine();
2158 m_CursorLine
->MarkDirty();
2162 line
= m_CursorLine
;
2163 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2165 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2166 wxASSERT(m_FirstLine
);
2167 wxASSERT(m_CursorLine
);
2170 m_CursorLine
->MarkDirty();
2175 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2179 wxLayoutLine
*line
= m_FirstLine
;
2181 // first, make sure everything is calculated - this might not be
2182 // needed, optimise it later
2183 ApplyStyle(m_DefaultStyleInfo
, dc
);
2186 line
->RecalculatePosition(this); // so we don't need to do it all the time
2187 // little condition to speed up redrawing:
2188 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2189 line
= line
->GetNextLine();
2194 wxLayoutList::GetCursorScreenPos(void) const
2196 return m_CursorScreenPos
;
2200 Is called before each Draw(). Now, it will re-layout all lines which
2204 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2205 wxPoint
*cpos
, wxPoint
*csize
)
2207 // first, make sure everything is calculated - this might not be
2208 // needed, optimise it later
2209 ApplyStyle(m_DefaultStyleInfo
, dc
);
2217 ForceTotalLayout(FALSE
);
2220 // If one line was dirty, we need to re-calculate all
2221 // following lines, too.
2222 bool wasDirty
= forceAll
;
2223 wxLayoutLine
*line
= m_FirstLine
;
2227 ApplyStyle(line
->GetStyleInfo(), dc
);
2229 // if any previous line was dirty, we need to layout all
2232 // layout dirty lines:
2234 // always layout the cursor line toupdate the cursor
2235 // position and size:
2236 || line
== m_CursorLine
2237 // or if it's the line we are asked to look for:
2238 || (cpos
&& line
->GetLineNumber() == cpos
->y
)
2244 // The following Layout() calls will update our
2245 // m_CurrentStyleInfo if needed.
2246 if(line
== m_CursorLine
)
2248 line
->Layout(dc
, this,
2249 (wxPoint
*)&m_CursorScreenPos
,
2250 (wxPoint
*)&m_CursorSize
,
2253 // we cannot layout the line twice, so copy the coords:
2254 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2256 *cpos
= m_CursorScreenPos
;
2258 *csize
= m_CursorSize
;
2262 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2263 line
->Layout(dc
, this,
2265 csize
, NULL
, cpos
->x
);
2267 line
->Layout(dc
, this);
2268 // little condition to speed up redrawing:
2269 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2272 line
= line
->GetNextLine();
2275 #ifndef WXLAYOUT_USE_CARET
2276 // can only be 0 if we are on the first line and have no next line
2277 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2278 m_CursorLine
->GetNextLine() == NULL
&&
2279 m_CursorLine
== m_FirstLine
));
2280 #endif // WXLAYOUT_USE_CARET
2281 AddCursorPosToUpdateRect();
2285 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
)
2288 Layout(dc
, -1, false, &pos
, csize
);
2293 wxLayoutList::Draw(wxDC
&dc
,
2294 wxPoint
const &offset
,
2299 wxLayoutLine
*line
= m_FirstLine
;
2301 if ( m_Selection
.m_discarded
)
2303 // calculate them if we don't have them already
2304 if ( !m_Selection
.HasValidScreenCoords() )
2306 m_Selection
.m_ScreenA
= GetScreenPos(dc
, m_Selection
.m_CursorA
);
2307 m_Selection
.m_ScreenB
= GetScreenPos(dc
, m_Selection
.m_CursorB
);
2310 // invalidate the area which was previousle selected - and which is not
2311 // selected any more
2312 SetUpdateRect(m_Selection
.m_ScreenA
);
2313 SetUpdateRect(m_Selection
.m_ScreenB
);
2315 m_Selection
.m_discarded
= false;
2318 /* This call to Layout() will re-calculate and update all lines
2323 ApplyStyle(m_DefaultStyleInfo
, dc
);
2324 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2326 dc
.SetBackgroundMode(wxTRANSPARENT
);
2330 // only draw if between top and bottom:
2332 line
->GetPosition().y
+ line
->GetHeight() > top
))
2334 ApplyStyle(line
->GetStyleInfo(), dc
);
2335 // little condition to speed up redrawing:
2337 && line
->GetPosition().y
2338 +(clipStrictly
? line
->GetHeight() : 0) >= bottom
)
2340 line
->Draw(dc
, this, offset
);
2342 line
= line
->GetNextLine();
2344 InvalidateUpdateRect();
2346 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2347 m_Selection
.m_valid
? "valid" : "invalid",
2348 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2349 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2353 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2357 // First, find the right line:
2359 *line
= m_FirstLine
,
2360 *lastline
= m_FirstLine
;
2363 ApplyStyle(m_DefaultStyleInfo
, dc
);
2366 p
= line
->GetPosition();
2367 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2370 line
= line
->GetNextLine();
2373 bool didFind
= line
!= NULL
;
2377 // use the last line:
2382 cursorPos
->y
= line
->GetLineNumber();
2384 bool foundinline
= true;
2387 // Now, find the object in the line:
2392 i
= line
->FindObjectScreen(dc
, this,
2399 i
= line
->FindObjectScreen(dc
, this,
2404 *found
= didFind
&& foundinline
;
2406 return (i
== NULLIT
) ? NULL
: *i
;
2411 wxLayoutList::GetSize(void) const
2414 *line
= m_FirstLine
,
2417 return wxPoint(0,0);
2419 wxPoint
maxPoint(0,0);
2424 if(line
->GetWidth() > maxPoint
.x
)
2425 maxPoint
.x
= line
->GetWidth();
2427 line
= line
->GetNextLine();
2430 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2432 // if the line was just added, its height would be 0 and we can't call
2433 // Layout() from here because we don't have a dc and we might be not drawing
2434 // at all, besides... So take the cursor height by default (taking 0 is bad
2435 // because then the scrollbars won't be resized and the new line won't be
2437 if ( last
->IsDirty() )
2439 if ( last
->GetHeight() == 0 )
2440 maxPoint
.y
+= m_CursorSize
.y
;
2441 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2442 maxPoint
.x
= m_CursorSize
.x
;
2450 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2452 if ( m_movedCursor
)
2453 m_movedCursor
= false;
2455 wxPoint
coords(m_CursorScreenPos
);
2456 coords
+= translate
;
2458 #ifdef WXLAYOUT_DEBUG
2459 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2460 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2461 (long)coords
.x
, (long)coords
.y
,
2462 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2463 (long)m_CursorLine
->GetLineNumber(),
2464 (long)m_CursorLine
->GetLength()));
2466 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2469 #ifdef WXLAYOUT_USE_CARET
2470 m_caret
->Move(coords
);
2471 #else // !WXLAYOUT_USE_CARET
2472 dc
.SetBrush(*wxWHITE_BRUSH
);
2473 //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
2474 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2477 dc
.SetLogicalFunction(wxXOR
);
2478 dc
.DrawRectangle(coords
.x
, coords
.y
,
2479 m_CursorSize
.x
, m_CursorSize
.y
);
2480 SetUpdateRect(coords
.x
, coords
.y
);
2481 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2485 dc
.SetLogicalFunction(wxCOPY
);
2486 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2487 coords
.x
, coords
.y
);
2488 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2489 SetUpdateRect(coords
.x
, coords
.y
);
2491 dc
.SetLogicalFunction(wxCOPY
);
2492 //dc.SetBrush(wxNullBrush);
2493 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2497 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2499 if(m_UpdateRectValid
)
2500 GrowRect(m_UpdateRect
, x
, y
);
2505 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2506 m_UpdateRect
.height
= 4;// wxGTK :-)
2507 m_UpdateRectValid
= true;
2512 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2514 wxPoint
cpos(cposOrig
);
2517 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2518 m_Selection
.m_CursorA
= cpos
;
2519 m_Selection
.m_CursorB
= cpos
;
2520 m_Selection
.m_ScreenA
= spos
;
2521 m_Selection
.m_ScreenB
= spos
;
2522 m_Selection
.m_selecting
= true;
2523 m_Selection
.m_valid
= false;
2527 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2529 wxPoint
cpos(cposOrig
);
2533 wxASSERT(m_Selection
.m_selecting
== true);
2534 wxASSERT(m_Selection
.m_valid
== false);
2535 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2537 m_Selection
.m_ScreenB
= spos
;
2538 m_Selection
.m_CursorB
= cpos
;}
2541 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2543 wxPoint
cpos(cposOrig
);
2546 ContinueSelection(cpos
);
2547 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2548 // we always want m_CursorA <= m_CursorB!
2549 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2551 // exchange the start/end points
2552 wxPoint help
= m_Selection
.m_CursorB
;
2553 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2554 m_Selection
.m_CursorA
= help
;
2556 help
= m_Selection
.m_ScreenB
;
2557 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2558 m_Selection
.m_ScreenA
= help
;
2560 m_Selection
.m_selecting
= false;
2561 m_Selection
.m_valid
= true;
2562 /// In case we just clicked somewhere, the selection will have zero
2563 /// size, so we discard it immediately.
2564 if(m_Selection
.m_CursorA
== m_Selection
.m_CursorB
)
2569 wxLayoutList::DiscardSelection()
2571 if ( !HasSelection() )
2574 m_Selection
.m_valid
=
2575 m_Selection
.m_selecting
= false;
2576 m_Selection
.m_discarded
= true;
2580 wxLayoutList::IsSelecting(void) const
2582 return m_Selection
.m_selecting
;
2586 wxLayoutList::IsSelected(const wxPoint
&cursor
) const
2588 if ( !HasSelection() )
2592 (m_Selection
.m_CursorA
<= cursor
2593 && cursor
<= m_Selection
.m_CursorB
)
2594 || (m_Selection
.m_CursorB
<= cursor
2595 && cursor
<= m_Selection
.m_CursorA
)
2600 /** Tests whether this layout line is selected and needs
2602 @param line to test for
2603 @return 0 = not selected, 1 = fully selected, -1 = partially
2607 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2610 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2612 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2615 CoordType y
= line
->GetLineNumber();
2617 (m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2618 || (m_Selection
.m_CursorB
.y
< y
&& m_Selection
.m_CursorA
.y
> y
)
2621 else if(m_Selection
.m_CursorA
.y
== y
)
2623 *from
= m_Selection
.m_CursorA
.x
;
2624 if(m_Selection
.m_CursorB
.y
== y
)
2625 *to
= m_Selection
.m_CursorB
.x
;
2628 if(m_Selection
.m_CursorB
> m_Selection
.m_CursorA
)
2629 *to
= line
->GetLength();
2635 CoordType help
= *to
;
2641 else if(m_Selection
.m_CursorB
.y
== y
)
2643 *to
= m_Selection
.m_CursorB
.x
;
2644 if(m_Selection
.m_CursorA
.y
== y
)
2645 *from
= m_Selection
.m_CursorA
.x
;
2648 if(m_Selection
.m_CursorB
> m_Selection
.m_CursorA
)
2651 *from
= line
->GetLength();
2655 CoordType help
= *to
;
2666 wxLayoutList::DeleteSelection(void)
2668 if(! m_Selection
.m_valid
)
2671 m_Selection
.m_valid
= false;
2673 // Only delete part of the current line?
2674 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2676 MoveCursorTo(m_Selection
.m_CursorA
);
2677 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2681 // We now know that the two lines are different:
2684 * firstLine
= GetLine(m_Selection
.m_CursorA
.y
),
2685 * lastLine
= GetLine(m_Selection
.m_CursorB
.y
);
2686 // be a bit paranoid:
2687 if(! firstLine
|| ! lastLine
)
2690 // First, delete what's left of this line:
2691 MoveCursorTo(m_Selection
.m_CursorA
);
2692 DeleteToEndOfLine();
2694 wxLayoutLine
*prevLine
= firstLine
->GetPreviousLine(),
2695 *nextLine
= firstLine
->GetNextLine();
2696 while(nextLine
&& nextLine
!= lastLine
)
2697 nextLine
= nextLine
->DeleteLine(false, this);
2699 // Now nextLine = lastLine;
2700 Delete(1); // This joins firstLine and nextLine
2701 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x positions
2703 // Recalculate the line positions and numbers but notice that firstLine
2704 // might not exist any more - it could be deleted by Delete(1) above
2705 wxLayoutLine
*firstLine2
= prevLine
? prevLine
->GetNextLine() : m_FirstLine
;
2706 firstLine2
->MarkDirty();
2709 /// Starts highlighting the selection
2711 wxLayoutList::StartHighlighting(wxDC
&dc
)
2714 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2715 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2716 dc
.SetBackgroundMode(wxSOLID
);
2720 /// Ends highlighting the selection
2722 wxLayoutList::EndHighlighting(wxDC
&dc
)
2725 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2726 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2727 dc
.SetBackgroundMode(wxTRANSPARENT
);
2733 wxLayoutList::GetLine(CoordType index
) const
2735 wxASSERT_MSG( (0 <= index
) && (index
< (CoordType
)m_numLines
),
2739 CoordType n
= index
;
2741 CoordType lineNo
= 0;
2744 for ( line
= m_FirstLine
; line
&& n
-- > 0; line
=
2745 line
->GetNextLine() )
2748 wxASSERT(line
->GetLineNumber() == lineNo
);
2755 // should be the right one
2756 wxASSERT( line
->GetLineNumber() == index
);
2764 wxLayoutList::Copy(const wxPoint
&from
,
2771 for(firstLine
= m_FirstLine
;
2772 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2773 firstLine
=firstLine
->GetNextLine())
2775 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2778 for(lastLine
= m_FirstLine
;
2779 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2780 lastLine
=lastLine
->GetNextLine())
2782 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2787 wxLayoutLine
*tmp
= firstLine
;
2788 firstLine
= lastLine
;
2792 wxLayoutList
*llist
= new wxLayoutList();
2794 if(firstLine
== lastLine
)
2796 firstLine
->Copy(llist
, from
.x
, to
.x
);
2800 // Extract objects from first line
2801 firstLine
->Copy(llist
, from
.x
);
2803 // Extract all lines between
2804 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2806 line
= line
->GetNextLine())
2811 // Extract objects from last line
2812 lastLine
->Copy(llist
, 0, to
.x
);
2818 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2820 if(! m_Selection
.m_valid
)
2822 if(m_Selection
.m_selecting
)
2828 if(invalidate
) m_Selection
.m_valid
= false;
2830 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2831 m_Selection
.m_CursorB
);
2833 if(llist
&& wxlo
) // export as data object, too
2837 wxLayoutExportObject
*exp
;
2838 wxLayoutExportStatus
status(llist
);
2839 while((exp
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2841 if(exp
->type
== WXLO_EXPORT_EMPTYLINE
)
2842 ; //FIXME missing support for linebreaks in string format
2844 exp
->content
.object
->Write(string
);
2847 #if 0 // FIXME: DnD/Clipboard API has changed, what should this be?
2848 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2856 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2859 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2861 bool fontChanged
= FALSE
;
2868 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2872 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2873 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2877 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2878 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2883 #ifdef WXLAYOUT_DEBUG
2886 wxLayoutList::Debug(void)
2888 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2889 m_CursorLine
->GetLineNumber(),
2890 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2893 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2902 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2906 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2908 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2909 wxString
const & title
)
2914 // remove any highlighting which could interfere with printing:
2915 m_llist
->StartSelection();
2916 m_llist
->EndSelection();
2917 // force a full layout of the list:
2918 m_llist
->ForceTotalLayout();
2919 // layout is called in ScaleDC() when we have a DC
2922 wxLayoutPrintout::~wxLayoutPrintout()
2927 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2929 // The following bit is taken from the printing sample, let's see
2930 // whether it works for us.
2932 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2933 * the screen text size. This page also draws lines of actual length 5cm
2936 // Get the logical pixels per inch of screen and printer
2937 int ppiScreenX
, ppiScreenY
;
2938 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2939 int ppiPrinterX
, ppiPrinterY
;
2940 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2942 if(ppiScreenX
== 0) // not yet set, need to guess
2947 if(ppiPrinterX
== 0) // not yet set, need to guess
2953 // This scales the DC so that the printout roughly represents the
2954 // the screen scaling. The text point size _should_ be the right size
2955 // but in fact is too small for some reason. This is a detail that will
2956 // need to be addressed at some point but can be fudged for the
2958 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2960 // Now we have to check in case our real page size is reduced
2961 // (e.g. because we're drawing to a print preview memory DC)
2962 int pageWidth
, pageHeight
;
2964 dc
->GetSize(&w
, &h
);
2965 GetPageSizePixels(&pageWidth
, &pageHeight
);
2966 if(pageWidth
!= 0) // doesn't work always
2968 // If printer pageWidth == current DC width, then this doesn't
2969 // change. But w might be the preview bitmap width, so scale down.
2970 scale
= scale
* (float)(w
/(float)pageWidth
);
2972 dc
->SetUserScale(scale
, scale
);
2976 bool wxLayoutPrintout::OnPrintPage(int page
)
2985 top
= (page
- 1)*m_PrintoutHeight
;
2986 bottom
= top
+ m_PrintoutHeight
;
2988 WXLO_DEBUG(("OnPrintPage(%d) printing from %d to %d", page
, top
,
2990 // SetDeviceOrigin() doesn't work here, so we need to manually
2991 // translate all coordinates.
2992 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2993 m_llist
->Draw(*dc
, translate
, top
, bottom
, TRUE
/* clip strictly
3001 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
3003 /* We allocate a temporary wxDC for printing, so that we can
3004 determine the correct paper size and scaling. We don't actually
3005 print anything on it. */
3007 wxPrinterDC
*psdc
= new wxPrinterDC("","",WXLLIST_TEMPFILE
,false);
3009 wxPostScriptDC
*psdc
= new wxPostScriptDC(WXLLIST_TEMPFILE
,false);
3012 psdc
->StartDoc(m_title
);
3013 // before we draw anything, me must make sure the list is properly
3015 m_llist
->Layout(*psdc
);
3017 float scale
= ScaleDC(psdc
);
3019 psdc
->GetSize(&m_PageWidth
, &m_PageHeight
);
3021 // This sets a left/top origin of 15% and 5%:
3022 m_Offset
= wxPoint((15*m_PageWidth
)/100, (5*m_PageHeight
)/100);
3024 // This is the length of the printable area.
3025 m_PrintoutHeight
= m_PageHeight
- 2*m_Offset
.y
;
3026 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
3029 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
3032 *maxPage
= m_NumOfPages
;
3035 *selPageTo
= m_NumOfPages
;
3038 wxRemoveFile(WXLLIST_TEMPFILE
);
3041 bool wxLayoutPrintout::HasPage(int pageNum
)
3043 return pageNum
<= m_NumOfPages
;
3047 Stupid wxWindows doesn't draw proper ellipses, so we comment this
3048 out. It's a waste of paper anyway.
3052 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
3053 wxPoint topleft
, wxPoint bottomright
,
3056 // make backups of all essential parameters
3057 const wxBrush
& brush
= dc
.GetBrush();
3058 const wxPen
& pen
= dc
.GetPen();
3059 const wxFont
& font
= dc
.GetFont();
3061 dc
.SetBrush(*wxWHITE_BRUSH
);
3062 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
3063 dc
.DrawRoundedRectangle(topleft
.x
,
3064 topleft
.y
,bottomright
.x
-topleft
.x
,
3065 bottomright
.y
-topleft
.y
);
3066 dc
.SetBrush(*wxBLACK_BRUSH
);
3067 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
3068 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
3072 page
= "9999/9999 "; // many pages...
3074 dc
.GetTextExtent(page
,&w
,&h
);
3075 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
3076 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
3077 dc
.GetTextExtent("XXXX", &w
,&h
);
3078 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
3089 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
3092 for(wxFCEList::iterator i
= m_FontList
.begin();
3093 i
!= m_FontList
.end(); i
++)
3094 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
3095 return (**i
).GetFont();
3097 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
3099 m_FontList
.push_back(fce
);
3100 return fce
->GetFont();