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>
37 # include "gui/wxllist.h"
38 # include "gui/wxlparser.h"
39 # define SHOW_SELECTIONS 1
42 # include "wxlparser.h"
43 # define SHOW_SELECTIONS 1
47 # include <iostream.h>
51 # include <wx/print.h>
53 # include <wx/filefn.h>
56 #ifdef WXLAYOUT_USE_CARET
57 # include <wx/caret.h>
58 #endif // WXLAYOUT_USE_CARET
62 /// This should never really get created
63 #define WXLLIST_TEMPFILE "__wxllist.tmp"
67 # define TypeString(t) g_aTypeStrings[t]
68 # define WXLO_DEBUG(x) wxLogDebug x
70 static const char *g_aTypeStrings
[] =
72 "invalid", "text", "cmd", "icon"
75 wxLayoutObject::Debug(void)
77 WXLO_DEBUG(("%s",g_aTypeStrings
[GetType()]));
80 # define TypeString(t) ""
81 # define WXLO_DEBUG(x)
84 // FIXME under MSW, this constant is needed to make the thing properly redraw
85 // itself - I don't know where the size calculation error is and I can't
86 // waste time looking for it right now. Search for occurences of
87 // MSW_CORRECTION to find all the places where I did it.
89 static const int MSW_CORRECTION
= 10;
91 static const int MSW_CORRECTION
= 0;
94 /// Cursors smaller than this disappear in XOR drawing mode
95 #define WXLO_MINIMUM_CURSOR_WIDTH 4
97 /// Use this character to estimate a cursor size when none is available.
98 #define WXLO_CURSORCHAR "E"
99 /** @name Helper functions */
101 /// allows me to compare to wxPoints
102 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
104 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
108 The following STAY HERE until we have a working wxGTK again!!!
110 #ifndef wxWANTS_CHARS
111 /// allows me to compare to wxPoints
112 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
114 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
117 /// allows me to compare to wxPoints
118 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
120 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
123 wxPoint
& operator += (wxPoint
&p1
, wxPoint
const &p2
)
131 /// allows me to compare to wxPoints
132 bool operator>(wxPoint
const &p1
, wxPoint
const &p2
)
137 /// grows a wxRect so that it includes the given point
140 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
144 else if(r
.x
+ r
.width
< x
)
149 else if(r
.y
+ r
.height
< y
)
155 /// returns true if the point is in the rectangle
157 bool Contains(const wxRect
&r
, const wxPoint
&p
)
159 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
167 void ReadString(wxString
&to
, wxString
&from
)
170 const char *cptr
= from
.c_str();
171 while(*cptr
&& *cptr
!= '\n')
177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
181 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
185 wxLayoutObject::Read(wxString
&istr
)
188 ReadString(tmp
, istr
);
190 sscanf(tmp
.c_str(),"%d", &type
);
195 return wxLayoutObjectText::Read(istr
);
197 return wxLayoutObjectCmd::Read(istr
);
199 return wxLayoutObjectIcon::Read(istr
);
205 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
209 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
211 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
221 wxLayoutObjectText::Copy(void)
223 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
224 obj
->m_Width
= m_Width
;
225 obj
->m_Height
= m_Height
;
227 obj
->m_Bottom
= m_Bottom
;
228 obj
->SetUserData(m_UserData
);
234 wxLayoutObjectText::Write(wxString
&ostr
)
236 ostr
<< (int) WXLO_TYPE_TEXT
<< '\n'
241 wxLayoutObjectText::Read(wxString
&istr
)
244 ReadString(text
, istr
);
246 return new wxLayoutObjectText(text
);
250 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
253 *top
= m_Top
; *bottom
= m_Bottom
;
254 return wxPoint(m_Width
, m_Height
);
258 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
259 wxLayoutList
*wxllist
,
260 CoordType begin
, CoordType end
)
264 // draw the whole object normally
265 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
269 // highlight the bit between begin and len
272 ypos
= coords
.y
-m_Top
;
273 long width
, height
, descent
;
275 if(begin
< 0) begin
= 0;
276 if( end
> (signed)m_Text
.Length() )
277 end
= m_Text
.Length();
279 wxString str
= m_Text
.Mid(0, begin
);
280 dc
.DrawText(str
, xpos
, ypos
);
281 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
283 wxllist
->StartHighlighting(dc
);
284 str
= m_Text
.Mid(begin
, end
-begin
);
285 dc
.DrawText(str
, xpos
, ypos
);
286 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
288 wxllist
->EndHighlighting(dc
);
289 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
290 dc
.DrawText(str
, xpos
, ypos
);
295 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
299 maxlen
= m_Text
.Length();
302 height
, descent
= 0l;
304 if(xpos
== 0) return 0; // easy
306 while(width
< xpos
&& offs
< maxlen
)
308 dc
.GetTextExtent(m_Text
.substr(0,offs
),
309 &width
, &height
, &descent
);
312 /* We have to substract 1 to compensate for the offs++, and another
313 one because we don't want to position the cursor behind the
314 object what we clicked on, but before - otherwise it looks
316 return (xpos
> 2) ? offs
-2 : 0;
320 wxLayoutObjectText::Layout(wxDC
&dc
, class wxLayoutList
*llist
)
324 // now this is done in wxLayoutLine::Layout(), but this code might be
325 // reenabled later - in principle, it's more efficient
327 CoordType widthOld
= m_Width
,
328 heightOld
= m_Height
;
331 dc
.GetTextExtent(m_Text
, &m_Width
, &m_Height
, &descent
);
334 if ( widthOld
!= m_Width
|| heightOld
!= m_Height
)
336 // as the text length changed, it must be refreshed
337 wxLayoutLine
*line
= GetLine();
339 wxCHECK_RET( line
, "wxLayoutObjectText can't refresh itself" );
341 // as our size changed, we need to repaint the part which was appended
342 wxPoint
position(line
->GetPosition());
344 // this is not the most efficient way (we repaint the whole line), but
345 // it's not too slow and is *simple*
346 if ( widthOld
< m_Width
)
348 if ( heightOld
< m_Height
)
349 heightOld
= m_Height
;
351 llist
->SetUpdateRect(position
.x
+ widthOld
+ MSW_CORRECTION
,
352 position
.y
+ heightOld
+ MSW_CORRECTION
);
357 m_Top
= m_Height
- m_Bottom
;
361 #ifdef WXLAYOUT_DEBUG
363 wxLayoutObjectText::Debug(void)
365 wxLayoutObject::Debug();
366 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
370 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
374 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
376 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
378 m_Icon
= new wxBitmap(icon
);
383 wxLayoutObjectIcon::Write(wxString
&ostr
)
385 /* Exports icon through a temporary file. */
387 wxString file
= wxGetTempFileName("wxloexport");
389 ostr
<< WXLO_TYPE_ICON
<< '\n'
391 m_Icon
->SaveFile(file
, WXLO_BITMAP_FORMAT
);
395 wxLayoutObjectIcon::Read(wxString
&istr
)
398 ReadString(file
, istr
);
400 if(! wxFileExists(file
))
402 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon
;
404 if(!obj
->m_Icon
->LoadFile(file
, WXLO_BITMAP_FORMAT
))
414 wxLayoutObjectIcon::Copy(void)
416 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
418 obj
->SetUserData(m_UserData
);
422 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
428 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
429 wxLayoutList
*wxllist
,
430 CoordType begin
, CoordType
/* len */)
432 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
433 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
437 wxLayoutObjectIcon::Layout(wxDC
& /* dc */, class wxLayoutList
* )
442 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
444 *top
= m_Icon
->GetHeight();
446 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
451 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
455 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
458 wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily
,
466 family
= ifamily
; size
= isize
;
467 style
= istyle
; weight
= iweight
;
468 underline
= iul
!= 0;
485 #define COPY_SI_(what) if(right.what != -1) what = right.what;
488 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
495 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
496 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
500 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
501 weight
, int underline
,
502 wxColour
*fg
, wxColour
*bg
)
505 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
509 wxLayoutObjectCmd::Copy(void)
511 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
516 m_StyleInfo
->underline
,
517 m_StyleInfo
->m_fg_valid
?
518 &m_StyleInfo
->m_fg
: NULL
,
519 m_StyleInfo
->m_bg_valid
?
520 &m_StyleInfo
->m_bg
: NULL
);
521 obj
->SetUserData(m_UserData
);
526 wxLayoutObjectCmd::Write(wxString
&ostr
)
528 ostr
<< WXLO_TYPE_CMD
<< '\n'
529 << m_StyleInfo
->size
<< '\n'
530 << m_StyleInfo
->family
<< '\n'
531 << m_StyleInfo
->style
<< '\n'
532 << m_StyleInfo
->weight
<< '\n'
533 << m_StyleInfo
->underline
<< '\n'
534 << m_StyleInfo
->m_fg_valid
<< '\n'
535 << m_StyleInfo
->m_bg_valid
<< '\n';
536 if(m_StyleInfo
->m_fg_valid
)
538 ostr
<< m_StyleInfo
->m_fg
.Red() << '\n'
539 << m_StyleInfo
->m_fg
.Green() << '\n'
540 << m_StyleInfo
->m_fg
.Blue() << '\n';
542 if(m_StyleInfo
->m_bg_valid
)
544 ostr
<< m_StyleInfo
->m_bg
.Red() << '\n'
545 << m_StyleInfo
->m_bg
.Green() << '\n'
546 << m_StyleInfo
->m_bg
.Blue() << '\n';
551 wxLayoutObjectCmd::Read(wxString
&istr
)
553 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd
;
556 ReadString(tmp
, istr
);
557 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->size
);
558 ReadString(tmp
, istr
);
559 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->family
);
560 ReadString(tmp
, istr
);
561 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->style
);
562 ReadString(tmp
, istr
);
563 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->weight
);
564 ReadString(tmp
, istr
);
565 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->underline
);
566 ReadString(tmp
, istr
);
567 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_fg_valid
);
568 ReadString(tmp
, istr
);
569 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_bg_valid
);
570 if(obj
->m_StyleInfo
->m_fg_valid
)
572 int red
, green
, blue
;
573 ReadString(tmp
, istr
);
574 sscanf(tmp
.c_str(),"%d", &red
);
575 ReadString(tmp
, istr
);
576 sscanf(tmp
.c_str(),"%d", &green
);
577 ReadString(tmp
, istr
);
578 sscanf(tmp
.c_str(),"%d", &blue
);
579 obj
->m_StyleInfo
->m_fg
= wxColour(red
, green
, blue
);
581 if(obj
->m_StyleInfo
->m_bg_valid
)
583 int red
, green
, blue
;
584 ReadString(tmp
, istr
);
585 sscanf(tmp
.c_str(),"%d", &red
);
586 ReadString(tmp
, istr
);
587 sscanf(tmp
.c_str(),"%d", &green
);
588 ReadString(tmp
, istr
);
589 sscanf(tmp
.c_str(),"%d", &blue
);
590 obj
->m_StyleInfo
->m_bg
= wxColour(red
, green
, blue
);
596 wxLayoutObjectCmd::~wxLayoutObjectCmd()
602 wxLayoutObjectCmd::GetStyle(void) const
608 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
609 wxLayoutList
*wxllist
,
610 CoordType begin
, CoordType
/* len */)
612 wxASSERT(m_StyleInfo
);
613 wxllist
->ApplyStyle(*m_StyleInfo
, dc
);
617 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
619 // this get called, so that recalculation uses right font sizes
620 Draw(dc
, wxPoint(0,0), llist
);
624 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
626 The wxLayoutLine object
628 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
630 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
633 m_Width
= m_Height
= 0;
638 RecalculatePosition(llist
);
641 m_LineNumber
= m_Previous
->GetLineNumber()+1;
642 m_Next
= m_Previous
->GetNextLine();
643 m_Previous
->m_Next
= this;
647 m_Next
->m_Previous
= this;
648 m_Next
->MoveLines(+1);
649 m_Next
->RecalculatePositions(1,llist
);
653 wxLayoutLine::~wxLayoutLine()
655 // kbList cleans itself
659 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
661 wxASSERT(m_Previous
|| GetLineNumber() == 0);
663 wxPoint
posOld(m_Position
);
667 m_Position
= m_Previous
->GetPosition();
668 m_Position
.y
+= m_Previous
->GetHeight();
671 m_Position
= wxPoint(0,0);
673 if ( m_Position
!= posOld
)
675 // the whole line moved and must be repainted
676 llist
->SetUpdateRect(m_Position
);
677 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
678 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
679 llist
->SetUpdateRect(posOld
);
680 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
681 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
688 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
690 //FIXME: is this really needed? We run Layout() anyway.
691 // Recursing here, drives computation time up exponentially, as
692 // each line will cause all following lines to be recalculated.
693 // Yes, or linenumbers go wrong.
695 wxASSERT(recurse
>= 0);
696 wxPoint pos
= m_Position
;
697 CoordType height
= m_Height
;
699 // WXLO_TRACE("RecalculatePositions()");
700 RecalculatePosition(llist
);
704 m_Next
->RecalculatePositions(--recurse
, llist
);
705 else if(pos
!= m_Position
|| m_Height
!= height
)
706 m_Next
->RecalculatePositions(0, llist
);
710 wxLayoutObjectList::iterator
711 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
715 wxLayoutObjectList::iterator
718 CoordType x
= 0, len
;
720 /* We search through the objects. As we don't like returning the
721 object that the cursor is behind, we just remember such an
722 object in "found" so we can return it if there is really no
723 further object following it. */
724 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
726 len
= (**i
).GetLength();
727 if( x
<= xpos
&& xpos
<= x
+ len
)
730 if(xpos
== x
+ len
) // is there another object behind?
732 else // we are really inside this object
735 x
+= (**i
).GetLength();
737 return found
; // ==NULL if really none found
740 wxLayoutObjectList::iterator
741 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
742 CoordType xpos
, CoordType
*cxpos
,
747 wxLayoutObjectList::iterator i
;
748 CoordType x
= 0, cx
= 0, width
;
750 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
752 width
= (**i
).GetWidth();
753 if( x
<= xpos
&& xpos
<= x
+ width
)
755 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
756 if(found
) *found
= true;
759 x
+= (**i
).GetWidth();
760 cx
+= (**i
).GetLength();
762 // behind last object:
764 if(found
) *found
= false;
765 return m_ObjectList
.tail();
768 /** Finds text in this line.
769 @param needle the text to find
770 @param xpos the position where to start the search
771 @return the cursoor coord where it was found or -1
774 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
779 wxString
const *text
;
781 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
783 if(cpos
>= xpos
) // search from here!
785 if((**i
).GetType() == WXLO_TYPE_TEXT
)
787 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
788 relpos
= text
->Find(needle
);
789 if(relpos
>= cpos
-xpos
) // -1 if not found
794 cpos
+= (**i
).GetLength();
797 return -1; // not found
801 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
804 wxASSERT(obj
!= NULL
);
808 // If we insert a command object, we need to recalculate all lines
809 // to update their styleinfo structure.
810 if(obj
->GetType() == WXLO_TYPE_CMD
)
814 wxLOiterator i
= FindObject(xpos
, &offset
);
817 if(xpos
== 0 ) // aha, empty line!
819 m_ObjectList
.push_back(obj
);
820 m_Length
+= obj
->GetLength();
827 CoordType len
= (**i
).GetLength();
828 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
829 { // insert before this object
830 m_ObjectList
.insert(i
,obj
);
831 m_Length
+= obj
->GetLength();
836 if( i
== m_ObjectList
.tail()) // last object?
837 m_ObjectList
.push_back(obj
);
839 { // insert after current object
841 m_ObjectList
.insert(i
,obj
);
843 m_Length
+= obj
->GetLength();
846 /* Otherwise we need to split the current object.
847 Fortunately this can only be a text object. */
848 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
849 wxString left
, right
;
850 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
851 left
= tobj
->GetText().substr(0,offset
);
852 right
= tobj
->GetText().substr(offset
,len
-offset
);
853 // current text object gets set to right half
854 tobj
->GetText() = right
; // set new text
855 // before it we insert the new object
856 m_ObjectList
.insert(i
,obj
);
857 m_Length
+= obj
->GetLength();
858 // and before that we insert the left half
859 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
864 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
871 wxLOiterator i
= FindObject(xpos
, &offset
);
872 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
874 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
875 tobj
->GetText().insert(offset
, text
);
876 m_Length
+= text
.Length();
880 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
888 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
890 CoordType offset
, len
;
895 wxLOiterator i
= FindObject(xpos
, &offset
);
898 if(i
== NULLIT
) return npos
;
899 // now delete from that object:
900 if((**i
).GetType() != WXLO_TYPE_TEXT
)
902 if(offset
!= 0) // at end of line after a non-text object
905 len
= (**i
).GetLength();
908 // If we delete a command object, we need to recalculate all lines
909 // to update their styleinfo structure.
910 if((**i
).GetType() == WXLO_TYPE_CMD
)
912 m_ObjectList
.erase(i
);
916 // tidy up: remove empty text objects
917 if((**i
).GetLength() == 0)
919 m_ObjectList
.erase(i
);
923 CoordType max
= (**i
).GetLength() - offset
;
924 if(npos
< max
) max
= npos
;
927 if(xpos
== GetLength())
930 { // at the end of an object
931 // move to begin of next object:
933 continue; // start over
938 if(offset
== 0 && max
== (**i
).GetLength())
939 m_ObjectList
.erase(i
); // remove the whole object
941 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
949 wxLayoutLine::MarkNextDirty(int recurse
)
951 wxLayoutLine
*line
= GetNextLine();
952 while(line
&& (recurse
== -1 || recurse
>= 0))
955 line
= line
->GetNextLine();
956 if(recurse
> 0) recurse
--;
961 wxLayoutLine::DeleteWord(CoordType xpos
)
967 wxLOiterator i
= FindObject(xpos
, &offset
);
971 if(i
== NULLIT
) return false;
972 if((**i
).GetType() != WXLO_TYPE_TEXT
)
974 // This should only happen when at end of line, behind a non-text
976 if(offset
== (**i
).GetLength()) return false;
977 m_Length
-= (**i
).GetLength(); // -1
978 m_ObjectList
.erase(i
);
979 return true; // we are done
983 if(offset
== (**i
).GetLength()) // at end of object
988 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
990 wxString str
= tobj
->GetText();
991 str
= str
.substr(offset
,str
.Length()-offset
);
992 // Find out how many positions we need to delete:
993 // 1. eat leading space
994 while(isspace(str
.c_str()[count
])) count
++;
995 // 2. eat the word itself:
996 while(isalnum(str
.c_str()[count
])) count
++;
998 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
999 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
1005 wxFAIL_MSG("unreachable");
1009 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1011 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
1012 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
1015 m_Next
->MoveLines(-1);
1016 m_Next
->RecalculatePositions(1, llist
);
1017 /* We assume that if we have more than one object in the list,
1018 this means that we have a command object, so we need to
1019 update the following lines. */
1020 if(m_ObjectList
.size() > 1 ||
1021 ( m_ObjectList
.begin() != NULLIT
&&
1022 (**m_ObjectList
.begin()).GetType() == WXLO_TYPE_CMD
)
1026 wxLayoutLine
*next
= m_Next
;
1032 wxLayoutLine::Draw(wxDC
&dc
,
1033 wxLayoutList
*llist
,
1034 const wxPoint
& offset
) const
1036 wxLayoutObjectList::iterator i
;
1037 wxPoint pos
= offset
;
1038 pos
= pos
+ GetPosition();
1040 pos
.y
+= m_BaseLine
;
1042 CoordType xpos
= 0; // cursorpos, lenght of line
1044 CoordType from
, to
, tempto
;
1046 int highlight
= llist
->IsSelected(this, &from
, &to
);
1047 // WXLO_DEBUG(("highlight=%d", highlight ));
1048 if(highlight
== 1) // we need to draw the whole line inverted!
1049 llist
->StartHighlighting(dc
);
1051 llist
->EndHighlighting(dc
);
1053 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1055 if(highlight
== -1) // partially highlight line
1057 // parts of the line need highlighting
1058 tempto
= xpos
+(**i
).GetLength();
1059 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1062 (**i
).Draw(dc
, pos
, llist
);
1063 pos
.x
+= (**i
).GetWidth();
1064 xpos
+= (**i
).GetLength();
1069 This function does all the recalculation, that is, it should only be
1070 called from within wxLayoutList::Layout(), as it uses the current
1071 list's styleinfo and updates it.
1074 wxLayoutLine::Layout(wxDC
&dc
,
1075 wxLayoutList
*llist
,
1077 wxPoint
*cursorSize
,
1079 bool suppressSIupdate
)
1081 wxLayoutObjectList::iterator i
;
1083 // when a line becomes dirty, we redraw it from the place where it was
1084 // changed till the end of line (because the following wxLayoutObjects are
1085 // moved when the preceding one changes) - calculate the update rectangle.
1086 CoordType updateTop
= m_Position
.y
,
1088 updateWidth
= m_Width
,
1089 updateHeight
= m_Height
;
1093 bottomHeight
= 0; // above and below baseline
1095 objTopHeight
, objBottomHeight
; // above and below baseline
1099 CoordType heightOld
= m_Height
;
1105 bool cursorFound
= false;
1109 *cursorPos
= m_Position
;
1110 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1113 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1114 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1116 wxLayoutObject
*obj
= *i
;
1117 obj
->Layout(dc
, llist
);
1118 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1120 if(cursorPos
&& ! cursorFound
)
1122 // we need to check whether the text cursor is here
1123 len
= obj
->GetLength();
1124 if(count
<= cx
&& count
+len
> cx
)
1126 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1128 len
= cx
- count
; // pos in object
1129 CoordType width
, height
, descent
;
1130 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1131 &width
, &height
, &descent
);
1132 cursorPos
->x
+= width
;
1133 cursorPos
->y
= m_Position
.y
;
1135 if(len
< obj
->GetLength())
1136 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1138 str
= WXLO_CURSORCHAR
;
1139 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1140 wxASSERT(cursorSize
);
1141 // Just in case some joker inserted an empty string object:
1142 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1143 if(height
== 0) height
= sizeObj
.y
;
1144 cursorSize
->x
= width
;
1145 cursorSize
->y
= height
;
1146 cursorFound
= true; // no more checks
1150 // on some other object
1151 CoordType top
, bottom
; // unused
1152 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1153 cursorPos
->y
= m_Position
.y
;
1154 cursorFound
= true; // no more checks
1160 cursorPos
->x
+= obj
->GetWidth();
1164 m_Width
+= sizeObj
.x
;
1165 if(sizeObj
.y
> m_Height
)
1167 m_Height
= sizeObj
.y
;
1170 if(objTopHeight
> topHeight
)
1171 topHeight
= objTopHeight
;
1172 if(objBottomHeight
> bottomHeight
)
1173 bottomHeight
= objBottomHeight
;
1178 if ( updateHeight
< m_Height
)
1179 updateHeight
= m_Height
;
1180 if ( updateWidth
< m_Width
)
1181 updateWidth
= m_Width
;
1183 // update all line if we don't know where to start from
1184 if ( updateLeft
== -1 )
1187 llist
->SetUpdateRect(updateLeft
, updateTop
);
1188 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1189 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1192 if(topHeight
+ bottomHeight
> m_Height
)
1194 m_Height
= topHeight
+bottomHeight
;
1197 m_BaseLine
= topHeight
;
1201 CoordType width
, height
, descent
;
1202 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1204 m_BaseLine
= m_Height
- descent
;
1207 // tell next line about coordinate change
1208 if(m_Next
&& m_Height
!= heightOld
)
1210 // FIXME isn't this done in RecalculatePositions() below anyhow?
1211 m_Next
->RecalculatePositions(0, llist
);
1214 // We need to check whether we found a valid cursor size:
1217 // this might be the case if the cursor is at the end of the
1218 // line or on a command object:
1219 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1221 CoordType width
, height
, descent
;
1222 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1223 cursorSize
->x
= width
;
1224 cursorSize
->y
= height
;
1226 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1227 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1229 RecalculatePositions(1, llist
);
1235 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1237 wxASSERT(xpos
>= 0);
1241 /* If we are at the begin of a line, we want to move all other
1242 lines down and stay with the cursor where we are. However, if we
1243 are in an empty line, we want to move down with it. */
1244 if(xpos
== 0 && GetLength() > 0)
1245 { // insert an empty line before this one
1246 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1247 if(m_Previous
== NULL
)
1248 { // We were in first line, need to link in new empty line
1250 prev
->m_Next
= this;
1252 m_Previous
->m_Height
= 0; // this is a wild guess
1255 m_Next
->RecalculatePositions(1, llist
);
1260 wxLOiterator i
= FindObject(xpos
, &offset
);
1262 // must be at the end of the line then
1263 return new wxLayoutLine(this, llist
);
1266 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1267 // split object at i:
1268 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1270 wxString left
, right
;
1271 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1272 left
= tobj
->GetText().substr(0,offset
);
1273 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1274 // current text object gets set to left half
1275 tobj
->GetText() = left
; // set new text
1276 newLine
->Append(new wxLayoutObjectText(right
));
1277 m_Length
-= right
.Length();
1278 i
++; // don't move this object to the new list
1283 i
++; // move objects from here to new list
1286 while(i
!= m_ObjectList
.end())
1288 wxLayoutObject
*obj
= *i
;
1289 newLine
->Append(obj
);
1290 m_Length
-= obj
->GetLength();
1292 m_ObjectList
.remove(i
); // remove without deleting it
1295 m_Next
->RecalculatePositions(2, llist
);
1301 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1303 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1304 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1307 MarkDirty(GetWidth());
1309 wxLayoutObject
*last
= NULL
;
1310 for(i
= list
.begin(); i
!= list
.end();)
1312 wxLayoutObject
*current
= *i
;
1314 // merge text objects together for efficiency
1315 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1316 current
->GetType() == WXLO_TYPE_TEXT
)
1318 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1319 wxString
text(textObj
->GetText());
1320 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1321 textObj
->SetText(text
);
1323 list
.erase(i
); // remove and delete it
1327 // just append the object "as was"
1330 list
.remove(i
); // remove without deleting it
1333 wxASSERT(list
.empty());
1335 wxLayoutLine
*oldnext
= GetNextLine();
1336 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1340 nextLine
->MoveLines(-1);
1344 // this is now done in Delete(), but if this function is ever called
1345 // from elsewhere, we might have to move refresh code back here (in
1346 // order not to duplicate it)
1348 wxPoint
pos(oldnext
->GetPosition());
1349 llist
->SetUpdateRect(pos
);
1350 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1351 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1359 wxLayoutLine::GetWrapPosition(CoordType column
)
1362 wxLOiterator i
= FindObject(column
, &offset
);
1363 if(i
== NULLIT
) return -1; // cannot wrap
1365 // go backwards through the list and look for space in text objects
1368 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1372 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1379 }while(offset
!= -1);
1380 i
--; // move on to previous object
1384 column
-= (**i
).GetLength();
1388 offset
= (**i
).GetLength();
1389 }while(i
!= NULLIT
);
1390 /* If we reached the begin of the list and have more than one
1391 object, that one is longer than the margin, so break behind
1394 i
= m_ObjectList
.begin();
1395 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1397 pos
+= (**i
).GetLength();
1400 if(i
== NULLIT
) return -1; //why should this happen?
1401 pos
+= (**i
).GetLength();
1403 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1405 pos
+= (**i
).GetLength();
1408 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1409 // now we are at the second text object:
1410 pos
-= (**i
).GetLength();
1411 return pos
; // in front of it
1415 #ifdef WXLAYOUT_DEBUG
1417 wxLayoutLine::Debug(void)
1420 wxPoint pos
= GetPosition();
1421 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1422 (long int) GetLineNumber(),
1423 (long int) pos
.x
, (long int) pos
.y
,
1424 (long int) GetHeight(),
1425 (long int) m_BaseLine
,
1426 (int) m_StyleInfo
.family
));
1427 if(m_ObjectList
.begin() != NULLIT
)
1428 (**m_ObjectList
.begin()).Debug();
1434 wxLayoutLine::Copy(wxLayoutList
*llist
,
1438 CoordType firstOffset
, lastOffset
;
1440 if(to
== -1) to
= GetLength();
1441 if(from
== to
) return;
1443 wxLOiterator first
= FindObject(from
, &firstOffset
);
1444 wxLOiterator last
= FindObject(to
, &lastOffset
);
1446 // Common special case: only one object
1447 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1449 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1451 llist
->Insert(new wxLayoutObjectText(
1452 ((wxLayoutObjectText
1453 *)*first
)->GetText().substr(firstOffset
,
1454 lastOffset
-firstOffset
))
1458 else // what can we do?
1460 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1461 llist
->Insert( (**first
).Copy() );
1466 // If we reach here, we can safely copy the whole first object from
1467 // the firstOffset position on:
1468 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1470 llist
->Insert(new wxLayoutObjectText(
1471 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1474 else if(firstOffset
== 0)
1475 llist
->Insert( (**first
).Copy() );
1476 // else nothing to copy :-(
1478 // Now we copy all objects before the last one:
1479 wxLOiterator i
= first
; i
++;
1480 for( ; i
!= last
; i
++)
1481 llist
->Insert( (**i
).Copy() );
1483 // And now the last object:
1486 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1488 llist
->Insert(new wxLayoutObjectText(
1489 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1493 llist
->Insert( (**last
).Copy() );
1498 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1500 The wxLayoutList object
1502 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1504 wxLayoutList::wxLayoutList()
1506 #ifdef WXLAYOUT_USE_CARET
1508 #endif // WXLAYOUT_USE_CARET
1511 InvalidateUpdateRect();
1515 wxLayoutList::~wxLayoutList()
1518 m_FirstLine
->DeleteLine(false, this);
1522 wxLayoutList::Empty(void)
1525 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1527 m_CursorPos
= wxPoint(0,0);
1528 m_CursorScreenPos
= wxPoint(0,0);
1529 m_CursorSize
= wxPoint(0,0);
1530 m_movedCursor
= true;
1531 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1532 m_CursorLine
= m_FirstLine
;
1533 InvalidateUpdateRect();
1538 wxLayoutList::InternalClear(void)
1541 m_Selection
.m_selecting
= false;
1542 m_Selection
.m_valid
= false;
1544 m_DefaultStyleInfo
.family
= wxSWISS
;
1545 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1546 m_DefaultStyleInfo
.style
= wxNORMAL
;
1547 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1548 m_DefaultStyleInfo
.underline
= 0;
1549 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1550 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1551 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1552 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1554 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1558 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1559 int underline
, wxColour
*fg
,
1562 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1563 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1564 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1565 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1566 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1567 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1568 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1570 new wxLayoutObjectCmd(
1571 m_CurrentStyleInfo
.family
,
1572 m_CurrentStyleInfo
.size
,
1573 m_CurrentStyleInfo
.style
,
1574 m_CurrentStyleInfo
.weight
,
1575 m_CurrentStyleInfo
.underline
,
1580 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1581 int underline
, char const *fg
, char const *bg
)
1589 cfg
= wxTheColourDatabase
->FindColour(fg
);
1591 cbg
= wxTheColourDatabase
->FindColour(bg
);
1593 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1597 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1598 int underline
, wxColour
*fg
, wxColour
*bg
)
1601 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1603 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1607 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1612 for(line
= m_FirstLine
;
1614 line
= line
->GetNextLine())
1616 if(line
->GetLineNumber() >= cpos
.y
)
1618 xpos
= line
->FindText(needle
,
1619 (line
->GetLineNumber() == cpos
.y
) ?
1622 return wxPoint(xpos
, line
->GetLineNumber());
1625 return wxPoint(-1,-1);
1630 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1632 AddCursorPosToUpdateRect();
1634 wxPoint cursorPosOld
= m_CursorPos
;
1636 wxLayoutLine
*line
= m_FirstLine
;
1637 while(line
&& line
->GetLineNumber() != p
.y
)
1638 line
= line
->GetNextLine();
1639 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1641 m_CursorPos
.y
= p
.y
;
1642 m_CursorLine
= line
;
1643 CoordType len
= line
->GetLength();
1646 m_CursorPos
.x
= p
.x
;
1650 m_CursorPos
.x
= len
;
1654 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1656 return m_CursorPos
== p
;
1660 wxLayoutList::MoveCursorVertically(int n
)
1662 AddCursorPosToUpdateRect();
1664 wxPoint cursorPosOld
= m_CursorPos
;
1667 if(n
< 0) // move up
1669 if(m_CursorLine
== m_FirstLine
) return false;
1670 while(n
< 0 && m_CursorLine
)
1672 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1678 m_CursorLine
= m_FirstLine
;
1684 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1685 m_CursorPos
.x
= m_CursorLine
->GetLength();
1691 wxLayoutLine
*last
= m_CursorLine
;
1692 if(! m_CursorLine
->GetNextLine()) return false;
1693 while(n
> 0 && m_CursorLine
)
1697 m_CursorLine
= m_CursorLine
->GetNextLine();
1701 m_CursorLine
= last
;
1707 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1708 m_CursorPos
.x
= m_CursorLine
->GetLength();
1713 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1719 wxLayoutList::MoveCursorHorizontally(int n
)
1721 AddCursorPosToUpdateRect();
1723 wxPoint cursorPosOld
= m_CursorPos
;
1728 if(m_CursorPos
.x
== 0) // at begin of line
1730 if(! MoveCursorVertically(-1))
1732 MoveCursorToEndOfLine();
1737 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1738 m_CursorPos
.x
-= move
; n
+= move
;
1743 int len
= m_CursorLine
->GetLength();
1744 if(m_CursorPos
.x
== len
) // at end of line
1746 if(! MoveCursorVertically(1))
1748 MoveCursorToBeginOfLine();
1753 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1754 m_CursorPos
.x
+= move
;
1758 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1764 wxLayoutList::MoveCursorWord(int n
)
1766 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1767 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1769 CoordType moveDistance
= 0;
1771 for ( wxLOiterator i
= m_CursorLine
->FindObject(m_CursorPos
.x
, &offset
);
1778 wxLayoutObject
*obj
= *i
;
1779 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1781 // any non text objects count as one word
1784 moveDistance
+= obj
->GetLength();
1789 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1791 if ( offset
== tobj
->GetLength() )
1798 const char *start
= tobj
->GetText().c_str();
1799 const char *p
= start
+ offset
;
1801 // to the beginning/end of the next/prev word
1802 while ( isspace(*p
) )
1807 // go to the end/beginning of the word (in a broad sense...)
1808 while ( p
>= start
&& !isspace(*p
) )
1815 // now advance to the beginning of the next word
1816 while ( isspace(*p
) )
1822 moveDistance
= p
- start
- offset
;
1826 // except for the first iteration, offset is 0
1830 MoveCursorHorizontally(moveDistance
);
1836 wxLayoutList::Insert(wxString
const &text
)
1838 wxASSERT(m_CursorLine
);
1839 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1844 AddCursorPosToUpdateRect();
1846 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1849 m_CursorPos
.x
+= text
.Length();
1851 m_movedCursor
= true;
1853 m_CursorLine
->RecalculatePositions(0, this);
1859 wxLayoutList::Insert(wxLayoutObject
*obj
)
1861 wxASSERT(m_CursorLine
);
1864 m_CursorLine
= GetFirstLine();
1866 AddCursorPosToUpdateRect();
1868 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1869 m_CursorPos
.x
+= obj
->GetLength();
1870 m_movedCursor
= true;
1872 m_CursorLine
->RecalculatePositions(0, this);
1878 wxLayoutList::Insert(wxLayoutList
*llist
)
1883 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1885 line
= line
->GetNextLine()
1888 for(wxLOiterator i
= line
->GetFirstObject();
1898 wxLayoutList::LineBreak(void)
1900 wxASSERT(m_CursorLine
);
1901 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1903 AddCursorPosToUpdateRect();
1905 wxPoint
position(m_CursorLine
->GetPosition());
1908 width
= m_CursorLine
->GetWidth(),
1909 height
= m_CursorLine
->GetHeight();
1911 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1912 if(setFirst
) // we were at beginning of first line
1913 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1914 if(m_CursorPos
.x
!= 0)
1918 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
1919 wxCHECK_MSG(prev
, false, "just broke the line, where is the previous one?");
1921 height
+= prev
->GetHeight();
1923 m_movedCursor
= true;
1925 SetUpdateRect(position
);
1926 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
1927 position
.y
+ height
+ MSW_CORRECTION
);
1933 wxLayoutList::WrapLine(CoordType column
)
1935 if(m_CursorPos
.x
<= column
|| column
< 1)
1936 return false; // do nothing yet
1939 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1941 return false; // cannot break line
1943 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1944 m_CursorPos
.x
= xpos
;
1946 AddCursorPosToUpdateRect();
1949 Delete(1); // delete the space
1950 m_CursorPos
.x
= newpos
;
1952 m_CursorLine
->RecalculatePositions(1, this);
1954 m_movedCursor
= true;
1961 wxLayoutList::Delete(CoordType npos
)
1963 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
1968 AddCursorPosToUpdateRect();
1970 // were other lines appended to this one (this is important to know because
1971 // this means that our width _increased_ as the result of deletion)
1972 bool wasMerged
= false;
1974 // the size of the region to update
1975 CoordType totalHeight
= m_CursorLine
->GetHeight(),
1976 totalWidth
= m_CursorLine
->GetWidth();
1981 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1985 // More to delete, continue on next line.
1987 // First, check if line is empty:
1988 if(m_CursorLine
->GetLength() == 0)
1990 // in this case, updating could probably be optimised
1992 wxASSERT(DeleteLines(1) == 0);
2001 // Need to join next line
2002 if(! m_CursorLine
->GetNextLine())
2007 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2010 totalHeight
+= next
->GetHeight();
2011 totalWidth
+= next
->GetWidth();
2013 m_CursorLine
->MergeNextLine(this);
2018 wxFAIL_MSG("can't delete all this");
2028 // we need to update the whole tail of the line and the lines which
2032 wxPoint
position(m_CursorLine
->GetPosition());
2033 SetUpdateRect(position
);
2034 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2035 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2042 wxLayoutList::DeleteLines(int n
)
2044 wxASSERT(m_CursorLine
);
2047 AddCursorPosToUpdateRect();
2051 if(!m_CursorLine
->GetNextLine())
2052 { // we cannot delete this line, but we can clear it
2053 MoveCursorToBeginOfLine();
2054 DeleteToEndOfLine();
2055 m_CursorLine
->RecalculatePositions(2, this);
2059 line
= m_CursorLine
;
2060 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2062 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2063 wxASSERT(m_FirstLine
);
2064 wxASSERT(m_CursorLine
);
2066 m_CursorLine
->RecalculatePositions(2, this);
2071 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2073 wxLayoutLine
*line
= m_FirstLine
;
2075 // first, make sure everything is calculated - this might not be
2076 // needed, optimise it later
2077 ApplyStyle(m_DefaultStyleInfo
, dc
);
2080 line
->RecalculatePosition(this); // so we don't need to do it all the time
2081 // little condition to speed up redrawing:
2082 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2083 line
= line
->GetNextLine();
2088 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
,
2089 bool resetCursorMovedFlag
,
2090 const wxPoint
& translate
)
2092 wxCHECK_RET( m_CursorLine
, "no cursor line" );
2094 if ( m_movedCursor
)
2096 // we need to save the current style, in case the layout() of
2097 // the line changes it
2098 wxLayoutStyleInfo SiBackup
= m_CurrentStyleInfo
;
2099 m_CursorLine
->Layout(dc
, this,
2100 &m_CursorScreenPos
, &m_CursorSize
,
2102 /* suppress update */ true);
2103 ApplyStyle(SiBackup
, dc
); // restore it
2105 if ( resetCursorMovedFlag
)
2107 #ifdef WXLAYOUT_USE_CARET
2108 // adjust the caret position
2109 wxPoint
coords(m_CursorScreenPos
);
2110 coords
+= translate
;
2113 m_caret
->Move(coords
);
2114 #endif // WXLAYOUT_USE_CARET
2116 m_movedCursor
= false;
2122 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2124 // this function is called with wxMemoryDC argument from ScrollToCursor(),
2125 // for example, so it shouldn't clear "cursor moved" flag - or else the
2126 // cursor won't be moved when UpdateCursorScreenPos() is called with the
2127 // "real" (i.e. the one used for drawing) wxDC.
2128 UpdateCursorScreenPos(dc
, false /* don't reset the flag */);
2130 return m_CursorScreenPos
;
2134 Is called before each Draw(). Now, it will re-layout all lines which
2138 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2139 wxPoint
*cpos
= NULL
,
2140 wxPoint
*csize
= NULL
)
2142 // first, make sure everything is calculated - this might not be
2143 // needed, optimise it later
2144 ApplyStyle(m_DefaultStyleInfo
, dc
);
2146 // This one we always Layout() to get the current cursor
2147 // coordinates on the screen:
2148 m_CursorLine
->MarkDirty();
2149 bool wasDirty
= false;
2150 wxLayoutLine
*line
= m_FirstLine
;
2154 ApplyStyle(line
->GetStyleInfo(), dc
);
2155 if(forceAll
|| line
->IsDirty()
2156 || (cpos
&& line
->GetLineNumber() == cpos
->y
))
2158 // The following Layout() calls will update our
2159 // m_CurrentStyleInfo if needed.
2160 if(line
== m_CursorLine
)
2161 line
->Layout(dc
, this,
2162 (wxPoint
*)&m_CursorScreenPos
,
2163 (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
2164 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2165 line
->Layout(dc
, this,
2169 line
->Layout(dc
, this);
2170 // little condition to speed up redrawing:
2171 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2175 line
->RecalculatePositions(1, this);
2176 line
= line
->GetNextLine();
2179 // can only be 0 if we are on the first line and have no next line
2180 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2181 m_CursorLine
->GetNextLine() == NULL
&&
2182 m_CursorLine
== m_FirstLine
));
2183 AddCursorPosToUpdateRect();
2187 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
= NULL
)
2190 Layout(dc
, -1, false, &pos
, csize
);
2195 wxLayoutList::Draw(wxDC
&dc
,
2196 wxPoint
const &offset
,
2200 wxLayoutLine
*line
= m_FirstLine
;
2202 /* We need to re-layout all dirty lines to update styleinfos
2203 etc. However, somehow we don't find all dirty lines... */
2204 Layout(dc
); //,-1,true); //FIXME
2205 ApplyStyle(m_DefaultStyleInfo
, dc
);
2206 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2208 dc
.SetBackgroundMode(wxTRANSPARENT
);
2210 bool style_set
= false;
2213 // only draw if between top and bottom:
2215 line
->GetPosition().y
+ line
->GetHeight() >= top
))
2219 ApplyStyle(line
->GetStyleInfo(), dc
);
2222 line
->Draw(dc
, this, offset
);
2226 line
->Layout(dc
, this);
2228 // little condition to speed up redrawing:
2229 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2230 line
= line
->GetNextLine();
2232 InvalidateUpdateRect();
2234 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2235 m_Selection
.m_valid
? "valid" : "invalid",
2236 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2237 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2241 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2245 // First, find the right line:
2246 wxLayoutLine
*line
= m_FirstLine
;
2249 ApplyStyle(m_DefaultStyleInfo
, dc
);
2252 p
= line
->GetPosition();
2253 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2256 // we need to run a layout here to get font sizes right :-(
2258 // VZ: we can't call Layout() from here because it marks the line as
2259 // clean and it is not refreshed when it's called from wxLayoutList::
2260 // Layout() - if we really need to do this, we should introduce an
2261 // extra argument to Layout() to prevent the line from MarkClean()ing
2263 line
->Layout(dc
, this);
2265 line
= line
->GetNextLine();
2269 if(found
) *found
= false;
2270 return NULL
; // not found
2272 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
2273 // Now, find the object in the line:
2274 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
2275 cursorPos
? & cursorPos
->x
: NULL
,
2277 return (i
== NULLIT
) ? NULL
: *i
;
2282 wxLayoutList::GetSize(void) const
2285 *line
= m_FirstLine
,
2288 return wxPoint(0,0);
2290 wxPoint
maxPoint(0,0);
2295 if(line
->GetWidth() > maxPoint
.x
)
2296 maxPoint
.x
= line
->GetWidth();
2298 line
= line
->GetNextLine();
2301 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2303 // if the line was just added, its height would be 0 and we can't call
2304 // Layout() from here because we don't have a dc and we might be not drawing
2305 // at all, besides... So take the cursor height by default (taking 0 is bad
2306 // because then the scrollbars won't be resized and the new line won't be
2308 if ( last
->IsDirty() )
2310 if ( last
->GetHeight() == 0 )
2311 maxPoint
.y
+= m_CursorSize
.y
;
2312 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2313 maxPoint
.x
= m_CursorSize
.x
;
2321 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2323 wxPoint
coords(m_CursorScreenPos
);
2324 coords
+= translate
;
2326 #ifdef WXLAYOUT_DEBUG
2327 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2328 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2329 (long)coords
.x
, (long)coords
.y
,
2330 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2331 (long)m_CursorLine
->GetLineNumber(),
2332 (long)m_CursorLine
->GetLength()));
2334 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2337 #ifndef WXLAYOUT_USE_CARET
2338 dc
.SetBrush(*wxBLACK_BRUSH
);
2339 dc
.SetLogicalFunction(wxXOR
);
2340 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2343 dc
.DrawRectangle(coords
.x
, coords
.y
,
2344 m_CursorSize
.x
, m_CursorSize
.y
);
2345 SetUpdateRect(coords
.x
, coords
.y
);
2346 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2350 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2351 coords
.x
, coords
.y
);
2352 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2353 SetUpdateRect(coords
.x
, coords
.y
);
2355 dc
.SetLogicalFunction(wxCOPY
);
2356 //dc.SetBrush(wxNullBrush);
2357 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2361 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2363 if(m_UpdateRectValid
)
2364 GrowRect(m_UpdateRect
, x
, y
);
2369 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2370 m_UpdateRect
.height
= 4;// wxGTK :-)
2371 m_UpdateRectValid
= true;
2376 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2378 wxPoint
cpos(cposOrig
);
2381 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2382 m_Selection
.m_CursorA
= cpos
;
2383 m_Selection
.m_CursorB
= cpos
;
2384 m_Selection
.m_ScreenA
= spos
;
2385 m_Selection
.m_ScreenB
= spos
;
2386 m_Selection
.m_selecting
= true;
2387 m_Selection
.m_valid
= false;
2391 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2393 wxPoint
cpos(cposOrig
);
2397 wxASSERT(m_Selection
.m_selecting
== true);
2398 wxASSERT(m_Selection
.m_valid
== false);
2399 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2401 if ( m_Selection
.m_CursorB
<= cpos
)
2403 m_Selection
.m_ScreenB
= spos
;
2404 m_Selection
.m_CursorB
= cpos
;
2408 m_Selection
.m_ScreenA
= spos
;
2409 m_Selection
.m_CursorA
= cpos
;
2412 // we always want m_CursorA <= m_CursorB!
2413 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2415 // exchange the start/end points
2416 wxPoint help
= m_Selection
.m_CursorB
;
2417 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2418 m_Selection
.m_CursorA
= help
;
2420 help
= m_Selection
.m_ScreenB
;
2421 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2422 m_Selection
.m_ScreenA
= help
;
2427 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2429 wxPoint
cpos(cposOrig
);
2432 ContinueSelection(cpos
);
2433 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2434 m_Selection
.m_selecting
= false;
2435 m_Selection
.m_valid
= true;
2439 wxLayoutList::DiscardSelection()
2441 if ( !HasSelection() )
2444 m_Selection
.m_valid
=
2445 m_Selection
.m_selecting
= false;
2447 // invalidate the area which was previousle selected - and which is not
2448 // selected any more
2449 if ( m_Selection
.HasValidScreenCoords() )
2451 SetUpdateRect(m_Selection
.m_ScreenA
);
2452 SetUpdateRect(m_Selection
.m_ScreenB
);
2461 wxLayoutList::IsSelecting(void)
2463 return m_Selection
.m_selecting
;
2467 wxLayoutList::IsSelected(const wxPoint
&cursor
)
2469 if ( !HasSelection() )
2472 return m_Selection
.m_CursorA
<= cursor
&& cursor
<= m_Selection
.m_CursorB
;
2476 /** Tests whether this layout line is selected and needs
2478 @param line to test for
2479 @return 0 = not selected, 1 = fully selected, -1 = partially
2483 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2486 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2488 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2491 CoordType y
= line
->GetLineNumber();
2492 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2494 else if(m_Selection
.m_CursorA
.y
== y
)
2496 *from
= m_Selection
.m_CursorA
.x
;
2497 if(m_Selection
.m_CursorB
.y
== y
)
2498 *to
= m_Selection
.m_CursorB
.x
;
2500 *to
= line
->GetLength();
2503 else if(m_Selection
.m_CursorB
.y
== y
)
2505 *to
= m_Selection
.m_CursorB
.x
;
2506 if(m_Selection
.m_CursorA
.y
== y
)
2507 *from
= m_Selection
.m_CursorA
.x
;
2517 wxLayoutList::DeleteSelection(void)
2519 if(! m_Selection
.m_valid
)
2522 m_Selection
.m_valid
= false;
2524 // Only delete part of the current line?
2525 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2527 MoveCursorTo(m_Selection
.m_CursorA
);
2528 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2537 for(firstLine
= m_FirstLine
;
2538 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
2539 firstLine
=firstLine
->GetNextLine())
2541 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
2545 for(lastLine
= m_FirstLine
;
2546 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
2547 lastLine
=lastLine
->GetNextLine())
2549 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
2553 // We now know that the two lines are different:
2555 // First, delete what's left of this line:
2556 MoveCursorTo(m_Selection
.m_CursorA
);
2557 DeleteToEndOfLine();
2559 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
2560 while(nextLine
&& nextLine
!= lastLine
)
2561 nextLine
= nextLine
->DeleteLine(false, this);
2563 // Now nextLine = lastLine;
2564 Delete(1); // This joins firstLine and nextLine
2565 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
2569 firstLine
->RecalculatePositions(1, this);
2572 /// Starts highlighting the selection
2574 wxLayoutList::StartHighlighting(wxDC
&dc
)
2577 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2578 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2579 dc
.SetBackgroundMode(wxSOLID
);
2583 /// Ends highlighting the selection
2585 wxLayoutList::EndHighlighting(wxDC
&dc
)
2588 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2589 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2590 dc
.SetBackgroundMode(wxTRANSPARENT
);
2596 wxLayoutList::Copy(const wxPoint
&from
,
2603 for(firstLine
= m_FirstLine
;
2604 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2605 firstLine
=firstLine
->GetNextLine())
2607 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2610 for(lastLine
= m_FirstLine
;
2611 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2612 lastLine
=lastLine
->GetNextLine())
2614 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2619 wxLayoutLine
*tmp
= firstLine
;
2620 firstLine
= lastLine
;
2624 wxLayoutList
*llist
= new wxLayoutList();
2626 if(firstLine
== lastLine
)
2628 firstLine
->Copy(llist
, from
.x
, to
.x
);
2632 // Extract objects from first line
2633 firstLine
->Copy(llist
, from
.x
);
2635 // Extract all lines between
2636 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2638 line
= line
->GetNextLine())
2643 // Extract objects from last line
2644 lastLine
->Copy(llist
, 0, to
.x
);
2650 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2652 if(! m_Selection
.m_valid
)
2654 if(m_Selection
.m_selecting
)
2660 if(invalidate
) m_Selection
.m_valid
= false;
2662 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2663 m_Selection
.m_CursorB
);
2665 if(llist
&& wxlo
) // export as data object, too
2669 wxLayoutExportObject
*export
;
2670 wxLayoutExportStatus
status(llist
);
2671 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2673 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2674 ; //FIXME missing support for linebreaks in string format
2676 export
->content
.object
->Write(string
);
2680 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2687 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2690 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2692 bool fontChanged
= FALSE
;
2699 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2703 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2704 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2708 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2709 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2714 #ifdef WXLAYOUT_DEBUG
2717 wxLayoutList::Debug(void)
2719 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2720 m_CursorLine
->GetLineNumber(),
2721 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2724 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2733 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2737 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2739 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2740 wxString
const & title
)
2745 // remove any highlighting which could interfere with printing:
2746 m_llist
->StartSelection();
2747 m_llist
->EndSelection();
2750 wxLayoutPrintout::~wxLayoutPrintout()
2755 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2757 // The following bit is taken from the printing sample, let's see
2758 // whether it works for us.
2760 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2761 * the screen text size. This page also draws lines of actual length 5cm
2764 // Get the logical pixels per inch of screen and printer
2765 int ppiScreenX
, ppiScreenY
;
2766 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2767 int ppiPrinterX
, ppiPrinterY
;
2768 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2770 if(ppiScreenX
== 0) // not yet set, need to guess
2775 if(ppiPrinterX
== 0) // not yet set, need to guess
2781 // This scales the DC so that the printout roughly represents the
2782 // the screen scaling. The text point size _should_ be the right size
2783 // but in fact is too small for some reason. This is a detail that will
2784 // need to be addressed at some point but can be fudged for the
2786 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2788 // Now we have to check in case our real page size is reduced
2789 // (e.g. because we're drawing to a print preview memory DC)
2790 int pageWidth
, pageHeight
;
2792 dc
->GetSize(&w
, &h
);
2793 GetPageSizePixels(&pageWidth
, &pageHeight
);
2794 if(pageWidth
!= 0) // doesn't work always
2796 // If printer pageWidth == current DC width, then this doesn't
2797 // change. But w might be the preview bitmap width, so scale down.
2798 scale
= scale
* (float)(w
/(float)pageWidth
);
2800 dc
->SetUserScale(scale
, scale
);
2804 bool wxLayoutPrintout::OnPrintPage(int page
)
2813 top
= (page
- 1)*m_PrintoutHeight
;
2814 bottom
= top
+ m_PrintoutHeight
;
2815 // SetDeviceOrigin() doesn't work here, so we need to manually
2816 // translate all coordinates.
2817 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2818 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2825 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2827 /* We allocate a temporary wxDC for printing, so that we can
2828 determine the correct paper size and scaling. We don't actually
2829 print anything on it. */
2831 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2833 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2836 float scale
= ScaleDC(&psdc
);
2838 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2839 // This sets a left/top origin of 15% and 20%:
2840 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2842 // This is the length of the printable area.
2843 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2844 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2848 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2851 *maxPage
= m_NumOfPages
;
2854 *selPageTo
= m_NumOfPages
;
2855 wxRemoveFile(WXLLIST_TEMPFILE
);
2858 bool wxLayoutPrintout::HasPage(int pageNum
)
2860 return pageNum
<= m_NumOfPages
;
2864 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2865 out. It's a waste of paper anyway.
2869 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2870 wxPoint topleft
, wxPoint bottomright
,
2873 // make backups of all essential parameters
2874 const wxBrush
& brush
= dc
.GetBrush();
2875 const wxPen
& pen
= dc
.GetPen();
2876 const wxFont
& font
= dc
.GetFont();
2878 dc
.SetBrush(*wxWHITE_BRUSH
);
2879 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2880 dc
.DrawRoundedRectangle(topleft
.x
,
2881 topleft
.y
,bottomright
.x
-topleft
.x
,
2882 bottomright
.y
-topleft
.y
);
2883 dc
.SetBrush(*wxBLACK_BRUSH
);
2884 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2885 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2889 page
= "9999/9999 "; // many pages...
2891 dc
.GetTextExtent(page
,&w
,&h
);
2892 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2893 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2894 dc
.GetTextExtent("XXXX", &w
,&h
);
2895 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2906 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2909 for(wxFCEList::iterator i
= m_FontList
.begin();
2910 i
!= m_FontList
.end(); i
++)
2911 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2912 return (**i
).GetFont();
2914 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2916 m_FontList
.push_back(fce
);
2917 return fce
->GetFont();