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
,
470 underline
= iul
!= 0;
472 m_fg_valid
= fg
!= 0;
473 m_bg_valid
= bg
!= 0;
474 m_fg
= m_fg_valid
? *fg
: *wxBLACK
;
475 m_bg
= m_fg_valid
? *bg
: *wxWHITE
;
478 #define COPY_SI_(what) if(right.what != -1) what = right.what;
481 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
488 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
489 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
493 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
494 weight
, int underline
,
495 wxColour
*fg
, wxColour
*bg
)
498 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
502 wxLayoutObjectCmd::Copy(void)
504 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
509 m_StyleInfo
->underline
,
510 m_StyleInfo
->m_fg_valid
?
511 &m_StyleInfo
->m_fg
: NULL
,
512 m_StyleInfo
->m_bg_valid
?
513 &m_StyleInfo
->m_bg
: NULL
);
514 obj
->SetUserData(m_UserData
);
519 wxLayoutObjectCmd::Write(wxString
&ostr
)
521 ostr
<< WXLO_TYPE_CMD
<< '\n'
522 << m_StyleInfo
->size
<< '\n'
523 << m_StyleInfo
->family
<< '\n'
524 << m_StyleInfo
->style
<< '\n'
525 << m_StyleInfo
->weight
<< '\n'
526 << m_StyleInfo
->underline
<< '\n'
527 << m_StyleInfo
->m_fg_valid
<< '\n'
528 << m_StyleInfo
->m_bg_valid
<< '\n';
529 if(m_StyleInfo
->m_fg_valid
)
531 ostr
<< m_StyleInfo
->m_fg
.Red() << '\n'
532 << m_StyleInfo
->m_fg
.Green() << '\n'
533 << m_StyleInfo
->m_fg
.Blue() << '\n';
535 if(m_StyleInfo
->m_bg_valid
)
537 ostr
<< m_StyleInfo
->m_bg
.Red() << '\n'
538 << m_StyleInfo
->m_bg
.Green() << '\n'
539 << m_StyleInfo
->m_bg
.Blue() << '\n';
544 wxLayoutObjectCmd::Read(wxString
&istr
)
546 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd
;
549 ReadString(tmp
, istr
);
550 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->size
);
551 ReadString(tmp
, istr
);
552 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->family
);
553 ReadString(tmp
, istr
);
554 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->style
);
555 ReadString(tmp
, istr
);
556 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->weight
);
557 ReadString(tmp
, istr
);
558 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->underline
);
559 ReadString(tmp
, istr
);
560 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_fg_valid
);
561 ReadString(tmp
, istr
);
562 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_bg_valid
);
563 if(obj
->m_StyleInfo
->m_fg_valid
)
565 int red
, green
, blue
;
566 ReadString(tmp
, istr
);
567 sscanf(tmp
.c_str(),"%d", &red
);
568 ReadString(tmp
, istr
);
569 sscanf(tmp
.c_str(),"%d", &green
);
570 ReadString(tmp
, istr
);
571 sscanf(tmp
.c_str(),"%d", &blue
);
572 obj
->m_StyleInfo
->m_fg
= wxColour(red
, green
, blue
);
574 if(obj
->m_StyleInfo
->m_bg_valid
)
576 int red
, green
, blue
;
577 ReadString(tmp
, istr
);
578 sscanf(tmp
.c_str(),"%d", &red
);
579 ReadString(tmp
, istr
);
580 sscanf(tmp
.c_str(),"%d", &green
);
581 ReadString(tmp
, istr
);
582 sscanf(tmp
.c_str(),"%d", &blue
);
583 obj
->m_StyleInfo
->m_bg
= wxColour(red
, green
, blue
);
589 wxLayoutObjectCmd::~wxLayoutObjectCmd()
595 wxLayoutObjectCmd::GetStyle(void) const
601 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
602 wxLayoutList
*wxllist
,
603 CoordType begin
, CoordType
/* len */)
605 wxASSERT(m_StyleInfo
);
606 wxllist
->ApplyStyle(*m_StyleInfo
, dc
);
610 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
612 // this get called, so that recalculation uses right font sizes
613 Draw(dc
, wxPoint(0,0), llist
);
617 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
619 The wxLayoutLine object
621 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
623 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
626 m_Width
= m_Height
= 0;
632 RecalculatePosition(llist
);
635 m_LineNumber
= m_Previous
->GetLineNumber()+1;
636 m_Next
= m_Previous
->GetNextLine();
637 m_Previous
->m_Next
= this;
641 m_Next
->m_Previous
= this;
642 m_Next
->MoveLines(+1);
643 m_Next
->RecalculatePositions(1,llist
);
647 wxLayoutLine::~wxLayoutLine()
649 // kbList cleans itself
653 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
655 wxASSERT(m_Previous
|| GetLineNumber() == 0);
657 wxPoint
posOld(m_Position
);
661 m_Position
= m_Previous
->GetPosition();
662 m_Position
.y
+= m_Previous
->GetHeight();
665 m_Position
= wxPoint(0,0);
667 if ( m_Position
!= posOld
)
669 // the whole line moved and must be repainted
670 llist
->SetUpdateRect(m_Position
);
671 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
672 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
673 llist
->SetUpdateRect(posOld
);
674 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
675 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
682 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
684 //FIXME: is this really needed? We run Layout() anyway.
685 // Recursing here, drives computation time up exponentially, as
686 // each line will cause all following lines to be recalculated.
687 // Yes, or linenumbers go wrong.
689 wxASSERT(recurse
>= 0);
690 wxPoint pos
= m_Position
;
691 CoordType height
= m_Height
;
693 // WXLO_TRACE("RecalculatePositions()");
694 RecalculatePosition(llist
);
698 m_Next
->RecalculatePositions(--recurse
, llist
);
699 else if(pos
!= m_Position
|| m_Height
!= height
)
700 m_Next
->RecalculatePositions(0, llist
);
704 wxLayoutObjectList::iterator
705 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
709 wxLayoutObjectList::iterator
712 CoordType x
= 0, len
;
714 /* We search through the objects. As we don't like returning the
715 object that the cursor is behind, we just remember such an
716 object in "found" so we can return it if there is really no
717 further object following it. */
718 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
720 len
= (**i
).GetLength();
721 if( x
<= xpos
&& xpos
<= x
+ len
)
724 if(xpos
== x
+ len
) // is there another object behind?
726 else // we are really inside this object
729 x
+= (**i
).GetLength();
731 return found
; // ==NULL if really none found
734 wxLayoutObjectList::iterator
735 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
736 CoordType xpos
, CoordType
*cxpos
,
741 wxLayoutObjectList::iterator i
;
742 CoordType x
= 0, cx
= 0, width
;
744 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
746 width
= (**i
).GetWidth();
747 if( x
<= xpos
&& xpos
<= x
+ width
)
749 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
750 if(found
) *found
= true;
753 x
+= (**i
).GetWidth();
754 cx
+= (**i
).GetLength();
756 // behind last object:
758 if(found
) *found
= false;
759 return m_ObjectList
.tail();
762 /** Finds text in this line.
763 @param needle the text to find
764 @param xpos the position where to start the search
765 @return the cursoor coord where it was found or -1
768 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
773 wxString
const *text
;
775 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
777 if(cpos
>= xpos
) // search from here!
779 if((**i
).GetType() == WXLO_TYPE_TEXT
)
781 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
782 relpos
= text
->Find(needle
);
783 if(relpos
>= cpos
-xpos
) // -1 if not found
788 cpos
+= (**i
).GetLength();
791 return -1; // not found
795 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
798 wxASSERT(obj
!= NULL
);
802 // If we insert a command object, we need to recalculate all lines
803 // to update their styleinfo structure.
804 if(obj
->GetType() == WXLO_TYPE_CMD
)
808 wxLOiterator i
= FindObject(xpos
, &offset
);
811 if(xpos
== 0 ) // aha, empty line!
813 m_ObjectList
.push_back(obj
);
814 m_Length
+= obj
->GetLength();
821 CoordType len
= (**i
).GetLength();
822 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
823 { // insert before this object
824 m_ObjectList
.insert(i
,obj
);
825 m_Length
+= obj
->GetLength();
830 if( i
== m_ObjectList
.tail()) // last object?
831 m_ObjectList
.push_back(obj
);
833 { // insert after current object
835 m_ObjectList
.insert(i
,obj
);
837 m_Length
+= obj
->GetLength();
840 /* Otherwise we need to split the current object.
841 Fortunately this can only be a text object. */
842 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
843 wxString left
, right
;
844 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
845 left
= tobj
->GetText().substr(0,offset
);
846 right
= tobj
->GetText().substr(offset
,len
-offset
);
847 // current text object gets set to right half
848 tobj
->GetText() = right
; // set new text
849 // before it we insert the new object
850 m_ObjectList
.insert(i
,obj
);
851 m_Length
+= obj
->GetLength();
852 // and before that we insert the left half
853 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
858 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
865 wxLOiterator i
= FindObject(xpos
, &offset
);
866 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
868 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
869 tobj
->GetText().insert(offset
, text
);
870 m_Length
+= text
.Length();
874 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
882 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
884 CoordType offset
, len
;
889 wxLOiterator i
= FindObject(xpos
, &offset
);
892 if(i
== NULLIT
) return npos
;
893 // now delete from that object:
894 if((**i
).GetType() != WXLO_TYPE_TEXT
)
896 if(offset
!= 0) // at end of line after a non-text object
899 len
= (**i
).GetLength();
902 // If we delete a command object, we need to recalculate all lines
903 // to update their styleinfo structure.
904 if((**i
).GetType() == WXLO_TYPE_CMD
)
906 m_ObjectList
.erase(i
);
910 // tidy up: remove empty text objects
911 if((**i
).GetLength() == 0)
913 m_ObjectList
.erase(i
);
917 CoordType max
= (**i
).GetLength() - offset
;
918 if(npos
< max
) max
= npos
;
921 if(xpos
== GetLength())
924 { // at the end of an object
925 // move to begin of next object:
927 continue; // start over
932 if(offset
== 0 && max
== (**i
).GetLength())
933 m_ObjectList
.erase(i
); // remove the whole object
935 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
943 wxLayoutLine::MarkNextDirty(int recurse
)
945 wxLayoutLine
*line
= GetNextLine();
946 while(line
&& (recurse
== -1 || recurse
>= 0))
949 line
= line
->GetNextLine();
950 if(recurse
> 0) recurse
--;
955 wxLayoutLine::DeleteWord(CoordType xpos
)
961 wxLOiterator i
= FindObject(xpos
, &offset
);
965 if(i
== NULLIT
) return false;
966 if((**i
).GetType() != WXLO_TYPE_TEXT
)
968 // This should only happen when at end of line, behind a non-text
970 if(offset
== (**i
).GetLength()) return false;
971 m_Length
-= (**i
).GetLength(); // -1
972 m_ObjectList
.erase(i
);
973 return true; // we are done
977 if(offset
== (**i
).GetLength()) // at end of object
982 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
984 wxString str
= tobj
->GetText();
985 str
= str
.substr(offset
,str
.Length()-offset
);
986 // Find out how many positions we need to delete:
987 // 1. eat leading space
988 while(isspace(str
.c_str()[count
])) count
++;
989 // 2. eat the word itself:
990 while(isalnum(str
.c_str()[count
])) count
++;
992 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
993 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
999 wxFAIL_MSG("unreachable");
1003 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1005 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
1006 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
1009 m_Next
->MoveLines(-1);
1010 m_Next
->RecalculatePositions(1, llist
);
1011 /* We assume that if we have more than one object in the list,
1012 this means that we have a command object, so we need to
1013 update the following lines. */
1014 if(m_ObjectList
.size() > 1 ||
1015 ( m_ObjectList
.begin() != NULLIT
&&
1016 (**m_ObjectList
.begin()).GetType() == WXLO_TYPE_CMD
)
1020 wxLayoutLine
*next
= m_Next
;
1026 wxLayoutLine::Draw(wxDC
&dc
,
1027 wxLayoutList
*llist
,
1028 const wxPoint
& offset
) const
1030 wxLayoutObjectList::iterator i
;
1031 wxPoint pos
= offset
;
1032 pos
= pos
+ GetPosition();
1034 pos
.y
+= m_BaseLine
;
1036 CoordType xpos
= 0; // cursorpos, lenght of line
1038 CoordType from
, to
, tempto
;
1040 int highlight
= llist
->IsSelected(this, &from
, &to
);
1041 // WXLO_DEBUG(("highlight=%d", highlight ));
1042 if(highlight
== 1) // we need to draw the whole line inverted!
1043 llist
->StartHighlighting(dc
);
1045 llist
->EndHighlighting(dc
);
1047 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1049 if(highlight
== -1) // partially highlight line
1051 // parts of the line need highlighting
1052 tempto
= xpos
+(**i
).GetLength();
1053 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1056 (**i
).Draw(dc
, pos
, llist
);
1057 pos
.x
+= (**i
).GetWidth();
1058 xpos
+= (**i
).GetLength();
1063 This function does all the recalculation, that is, it should only be
1064 called from within wxLayoutList::Layout(), as it uses the current
1065 list's styleinfo and updates it.
1068 wxLayoutLine::Layout(wxDC
&dc
,
1069 wxLayoutList
*llist
,
1071 wxPoint
*cursorSize
,
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;
1103 *cursorPos
= m_Position
;
1104 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1107 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1108 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1110 wxLayoutObject
*obj
= *i
;
1111 obj
->Layout(dc
, llist
);
1112 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1114 if(cursorPos
&& ! cursorFound
)
1116 // we need to check whether the text cursor is here
1117 len
= obj
->GetLength();
1118 if(count
<= cx
&& count
+len
> cx
)
1120 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1122 len
= cx
- count
; // pos in object
1123 CoordType width
, height
, descent
;
1124 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1125 &width
, &height
, &descent
);
1126 cursorPos
->x
+= width
;
1127 cursorPos
->y
= m_Position
.y
;
1129 if(len
< obj
->GetLength())
1130 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1132 str
= WXLO_CURSORCHAR
;
1133 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1134 wxASSERT(cursorSize
);
1135 // Just in case some joker inserted an empty string object:
1136 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1137 if(height
== 0) height
= sizeObj
.y
;
1138 cursorSize
->x
= width
;
1139 cursorSize
->y
= height
;
1140 cursorFound
= true; // no more checks
1144 // on some other object
1145 CoordType top
, bottom
; // unused
1146 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1147 cursorPos
->y
= m_Position
.y
;
1148 cursorFound
= true; // no more checks
1154 cursorPos
->x
+= obj
->GetWidth();
1158 m_Width
+= sizeObj
.x
;
1159 if(sizeObj
.y
> m_Height
)
1161 m_Height
= sizeObj
.y
;
1164 if(objTopHeight
> topHeight
)
1165 topHeight
= objTopHeight
;
1166 if(objBottomHeight
> bottomHeight
)
1167 bottomHeight
= objBottomHeight
;
1172 if ( updateHeight
< m_Height
)
1173 updateHeight
= m_Height
;
1174 if ( updateWidth
< m_Width
)
1175 updateWidth
= m_Width
;
1177 // update all line if we don't know where to start from
1178 if ( updateLeft
== -1 )
1181 llist
->SetUpdateRect(updateLeft
, updateTop
);
1182 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1183 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1186 if(topHeight
+ bottomHeight
> m_Height
)
1188 m_Height
= topHeight
+bottomHeight
;
1191 m_BaseLine
= topHeight
;
1195 CoordType width
, height
, descent
;
1196 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1198 m_BaseLine
= m_Height
- descent
;
1201 // tell next line about coordinate change
1202 if(m_Next
&& m_Height
!= heightOld
)
1204 // FIXME isn't this done in RecalculatePositions() below anyhow?
1205 m_Next
->RecalculatePositions(0, llist
);
1208 // We need to check whether we found a valid cursor size:
1211 // this might be the case if the cursor is at the end of the
1212 // line or on a command object:
1213 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1215 CoordType width
, height
, descent
;
1216 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1217 cursorSize
->x
= width
;
1218 cursorSize
->y
= height
;
1220 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1221 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1223 RecalculatePositions(1, llist
);
1229 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1231 wxASSERT(xpos
>= 0);
1235 /* If we are at the begin of a line, we want to move all other
1236 lines down and stay with the cursor where we are. However, if we
1237 are in an empty line, we want to move down with it. */
1238 if(xpos
== 0 && GetLength() > 0)
1239 { // insert an empty line before this one
1240 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1241 if(m_Previous
== NULL
)
1242 { // We were in first line, need to link in new empty line
1244 prev
->m_Next
= this;
1246 m_Previous
->m_Height
= 0; // this is a wild guess
1249 m_Next
->RecalculatePositions(1, llist
);
1254 wxLOiterator i
= FindObject(xpos
, &offset
);
1256 // must be at the end of the line then
1257 return new wxLayoutLine(this, llist
);
1260 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1261 // split object at i:
1262 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1264 wxString left
, right
;
1265 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1266 left
= tobj
->GetText().substr(0,offset
);
1267 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1268 // current text object gets set to left half
1269 tobj
->GetText() = left
; // set new text
1270 newLine
->Append(new wxLayoutObjectText(right
));
1271 m_Length
-= right
.Length();
1272 i
++; // don't move this object to the new list
1277 i
++; // move objects from here to new list
1280 while(i
!= m_ObjectList
.end())
1282 wxLayoutObject
*obj
= *i
;
1283 newLine
->Append(obj
);
1284 m_Length
-= obj
->GetLength();
1286 m_ObjectList
.remove(i
); // remove without deleting it
1289 m_Next
->RecalculatePositions(2, llist
);
1295 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1297 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1298 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1301 MarkDirty(GetWidth());
1303 wxLayoutObject
*last
= NULL
;
1304 for(i
= list
.begin(); i
!= list
.end();)
1306 wxLayoutObject
*current
= *i
;
1308 // merge text objects together for efficiency
1309 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1310 current
->GetType() == WXLO_TYPE_TEXT
)
1312 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1313 wxString
text(textObj
->GetText());
1314 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1315 textObj
->SetText(text
);
1317 list
.erase(i
); // remove and delete it
1321 // just append the object "as was"
1324 list
.remove(i
); // remove without deleting it
1327 wxASSERT(list
.empty());
1329 wxLayoutLine
*oldnext
= GetNextLine();
1330 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1334 nextLine
->MoveLines(-1);
1338 // this is now done in Delete(), but if this function is ever called
1339 // from elsewhere, we might have to move refresh code back here (in
1340 // order not to duplicate it)
1342 wxPoint
pos(oldnext
->GetPosition());
1343 llist
->SetUpdateRect(pos
);
1344 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1345 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1353 wxLayoutLine::GetWrapPosition(CoordType column
)
1356 wxLOiterator i
= FindObject(column
, &offset
);
1357 if(i
== NULLIT
) return -1; // cannot wrap
1359 // go backwards through the list and look for space in text objects
1362 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1366 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1373 }while(offset
!= -1);
1374 i
--; // move on to previous object
1378 column
-= (**i
).GetLength();
1382 offset
= (**i
).GetLength();
1383 }while(i
!= NULLIT
);
1384 /* If we reached the begin of the list and have more than one
1385 object, that one is longer than the margin, so break behind
1388 i
= m_ObjectList
.begin();
1389 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1391 pos
+= (**i
).GetLength();
1394 if(i
== NULLIT
) return -1; //why should this happen?
1395 pos
+= (**i
).GetLength();
1397 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1399 pos
+= (**i
).GetLength();
1402 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1403 // now we are at the second text object:
1404 pos
-= (**i
).GetLength();
1405 return pos
; // in front of it
1409 #ifdef WXLAYOUT_DEBUG
1411 wxLayoutLine::Debug(void)
1414 wxPoint pos
= GetPosition();
1415 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1416 (long int) GetLineNumber(),
1417 (long int) pos
.x
, (long int) pos
.y
,
1418 (long int) GetHeight(),
1419 (long int) m_BaseLine
,
1420 (int) m_StyleInfo
.family
));
1421 if(m_ObjectList
.begin() != NULLIT
)
1422 (**m_ObjectList
.begin()).Debug();
1428 wxLayoutLine::Copy(wxLayoutList
*llist
,
1432 CoordType firstOffset
, lastOffset
;
1434 if(to
== -1) to
= GetLength();
1435 if(from
== to
) return;
1437 wxLOiterator first
= FindObject(from
, &firstOffset
);
1438 wxLOiterator last
= FindObject(to
, &lastOffset
);
1440 // Common special case: only one object
1441 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1443 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1445 llist
->Insert(new wxLayoutObjectText(
1446 ((wxLayoutObjectText
1447 *)*first
)->GetText().substr(firstOffset
,
1448 lastOffset
-firstOffset
))
1452 else // what can we do?
1454 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1455 llist
->Insert( (**first
).Copy() );
1460 // If we reach here, we can safely copy the whole first object from
1461 // the firstOffset position on:
1462 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1464 llist
->Insert(new wxLayoutObjectText(
1465 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1468 else if(firstOffset
== 0)
1469 llist
->Insert( (**first
).Copy() );
1470 // else nothing to copy :-(
1472 // Now we copy all objects before the last one:
1473 wxLOiterator i
= first
; i
++;
1474 for( ; i
!= last
; i
++)
1475 llist
->Insert( (**i
).Copy() );
1477 // And now the last object:
1480 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1482 llist
->Insert(new wxLayoutObjectText(
1483 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1487 llist
->Insert( (**last
).Copy() );
1492 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1494 The wxLayoutList object
1496 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1498 wxLayoutList::wxLayoutList()
1500 #ifdef WXLAYOUT_USE_CARET
1502 #endif // WXLAYOUT_USE_CARET
1505 InvalidateUpdateRect();
1509 wxLayoutList::~wxLayoutList()
1512 m_FirstLine
->DeleteLine(false, this);
1516 wxLayoutList::Empty(void)
1519 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1521 m_CursorPos
= wxPoint(0,0);
1522 m_CursorScreenPos
= wxPoint(0,0);
1523 m_CursorSize
= wxPoint(0,0);
1524 m_movedCursor
= true;
1525 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1526 m_CursorLine
= m_FirstLine
;
1527 InvalidateUpdateRect();
1532 wxLayoutList::InternalClear(void)
1535 m_Selection
.m_selecting
= false;
1536 m_Selection
.m_valid
= false;
1538 m_DefaultStyleInfo
.family
= wxSWISS
;
1539 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1540 m_DefaultStyleInfo
.style
= wxNORMAL
;
1541 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1542 m_DefaultStyleInfo
.underline
= 0;
1543 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1544 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1545 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1546 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1548 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1552 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1553 int underline
, wxColour
*fg
,
1556 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1557 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1558 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1559 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1560 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1561 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1562 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1564 new wxLayoutObjectCmd(
1565 m_CurrentStyleInfo
.family
,
1566 m_CurrentStyleInfo
.size
,
1567 m_CurrentStyleInfo
.style
,
1568 m_CurrentStyleInfo
.weight
,
1569 m_CurrentStyleInfo
.underline
,
1574 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1575 int underline
, char const *fg
, char const *bg
)
1583 cfg
= wxTheColourDatabase
->FindColour(fg
);
1585 cbg
= wxTheColourDatabase
->FindColour(bg
);
1587 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1591 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1592 int underline
, wxColour
*fg
, wxColour
*bg
)
1595 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1597 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1601 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1606 for(line
= m_FirstLine
;
1608 line
= line
->GetNextLine())
1610 if(line
->GetLineNumber() >= cpos
.y
)
1612 xpos
= line
->FindText(needle
,
1613 (line
->GetLineNumber() == cpos
.y
) ?
1616 return wxPoint(xpos
, line
->GetLineNumber());
1619 return wxPoint(-1,-1);
1624 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1626 AddCursorPosToUpdateRect();
1628 wxPoint cursorPosOld
= m_CursorPos
;
1630 wxLayoutLine
*line
= m_FirstLine
;
1631 while(line
&& line
->GetLineNumber() != p
.y
)
1632 line
= line
->GetNextLine();
1633 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1635 m_CursorPos
.y
= p
.y
;
1636 m_CursorLine
= line
;
1637 CoordType len
= line
->GetLength();
1640 m_CursorPos
.x
= p
.x
;
1644 m_CursorPos
.x
= len
;
1648 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1650 return m_CursorPos
== p
;
1654 wxLayoutList::MoveCursorVertically(int n
)
1656 AddCursorPosToUpdateRect();
1658 wxPoint cursorPosOld
= m_CursorPos
;
1661 if(n
< 0) // move up
1663 if(m_CursorLine
== m_FirstLine
) return false;
1664 while(n
< 0 && m_CursorLine
)
1666 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1672 m_CursorLine
= m_FirstLine
;
1678 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1679 m_CursorPos
.x
= m_CursorLine
->GetLength();
1685 wxLayoutLine
*last
= m_CursorLine
;
1686 if(! m_CursorLine
->GetNextLine()) return false;
1687 while(n
> 0 && m_CursorLine
)
1691 m_CursorLine
= m_CursorLine
->GetNextLine();
1695 m_CursorLine
= last
;
1701 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1702 m_CursorPos
.x
= m_CursorLine
->GetLength();
1707 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1713 wxLayoutList::MoveCursorHorizontally(int n
)
1715 AddCursorPosToUpdateRect();
1717 wxPoint cursorPosOld
= m_CursorPos
;
1722 if(m_CursorPos
.x
== 0) // at begin of line
1724 if(! MoveCursorVertically(-1))
1726 MoveCursorToEndOfLine();
1731 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1732 m_CursorPos
.x
-= move
; n
+= move
;
1737 int len
= m_CursorLine
->GetLength();
1738 if(m_CursorPos
.x
== len
) // at end of line
1740 if(! MoveCursorVertically(1))
1742 MoveCursorToBeginOfLine();
1747 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1748 m_CursorPos
.x
+= move
;
1752 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1758 wxLayoutList::MoveCursorWord(int n
)
1760 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1761 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1763 CoordType moveDistance
= 0;
1765 for ( wxLOiterator i
= m_CursorLine
->FindObject(m_CursorPos
.x
, &offset
);
1772 wxLayoutObject
*obj
= *i
;
1773 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1775 // any visible non text objects count as one word
1776 if ( obj
->IsVisibleObject() )
1780 moveDistance
+= obj
->GetLength();
1785 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1787 bool canAdvance
= true;
1789 if ( offset
== tobj
->GetLength() )
1794 // can't move further in this text object
1799 else if ( offset
> 0 )
1801 // offset is off by 1, make it a valid index
1808 const char *start
= tobj
->GetText().c_str();
1809 const char *p
= start
+ offset
;
1811 // to the beginning/end of the next/prev word
1812 while ( isspace(*p
) )
1817 // go to the end/beginning of the word (in a broad sense...)
1818 while ( p
>= start
&& !isspace(*p
) )
1825 // now advance to the beginning of the next word
1826 while ( isspace(*p
) )
1832 moveDistance
= p
- start
- offset
;
1836 // except for the first iteration, offset is 0
1840 MoveCursorHorizontally(moveDistance
);
1846 wxLayoutList::Insert(wxString
const &text
)
1848 wxASSERT(m_CursorLine
);
1849 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1854 AddCursorPosToUpdateRect();
1856 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1859 m_CursorPos
.x
+= text
.Length();
1861 m_movedCursor
= true;
1863 m_CursorLine
->RecalculatePositions(0, this);
1869 wxLayoutList::Insert(wxLayoutObject
*obj
)
1871 wxASSERT(m_CursorLine
);
1874 m_CursorLine
= GetFirstLine();
1876 AddCursorPosToUpdateRect();
1878 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1879 m_CursorPos
.x
+= obj
->GetLength();
1880 m_movedCursor
= true;
1882 m_CursorLine
->RecalculatePositions(0, this);
1888 wxLayoutList::Insert(wxLayoutList
*llist
)
1893 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1895 line
= line
->GetNextLine()
1898 for(wxLOiterator i
= line
->GetFirstObject();
1908 wxLayoutList::LineBreak(void)
1910 wxASSERT(m_CursorLine
);
1911 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1913 AddCursorPosToUpdateRect();
1915 wxPoint
position(m_CursorLine
->GetPosition());
1918 width
= m_CursorLine
->GetWidth(),
1919 height
= m_CursorLine
->GetHeight();
1921 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1922 if(setFirst
) // we were at beginning of first line
1923 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1924 if(m_CursorPos
.x
!= 0)
1928 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
1929 wxCHECK_MSG(prev
, false, "just broke the line, where is the previous one?");
1931 height
+= prev
->GetHeight();
1933 m_movedCursor
= true;
1935 SetUpdateRect(position
);
1936 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
1937 position
.y
+ height
+ MSW_CORRECTION
);
1943 wxLayoutList::WrapLine(CoordType column
)
1945 if(m_CursorPos
.x
<= column
|| column
< 1)
1946 return false; // do nothing yet
1949 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1951 return false; // cannot break line
1953 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1954 m_CursorPos
.x
= xpos
;
1956 AddCursorPosToUpdateRect();
1959 Delete(1); // delete the space
1960 m_CursorPos
.x
= newpos
;
1962 m_CursorLine
->RecalculatePositions(1, this);
1964 m_movedCursor
= true;
1971 wxLayoutList::Delete(CoordType npos
)
1973 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
1978 AddCursorPosToUpdateRect();
1980 // were other lines appended to this one (this is important to know because
1981 // this means that our width _increased_ as the result of deletion)
1982 bool wasMerged
= false;
1984 // the size of the region to update
1985 CoordType totalHeight
= m_CursorLine
->GetHeight(),
1986 totalWidth
= m_CursorLine
->GetWidth();
1991 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1995 // More to delete, continue on next line.
1997 // First, check if line is empty:
1998 if(m_CursorLine
->GetLength() == 0)
2000 // in this case, updating could probably be optimised
2002 wxASSERT(DeleteLines(1) == 0);
2011 // Need to join next line
2012 if(! m_CursorLine
->GetNextLine())
2017 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2020 totalHeight
+= next
->GetHeight();
2021 totalWidth
+= next
->GetWidth();
2023 m_CursorLine
->MergeNextLine(this);
2028 wxFAIL_MSG("can't delete all this");
2038 // we need to update the whole tail of the line and the lines which
2042 wxPoint
position(m_CursorLine
->GetPosition());
2043 SetUpdateRect(position
);
2044 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2045 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2052 wxLayoutList::DeleteLines(int n
)
2054 wxASSERT(m_CursorLine
);
2057 AddCursorPosToUpdateRect();
2061 if(!m_CursorLine
->GetNextLine())
2062 { // we cannot delete this line, but we can clear it
2063 MoveCursorToBeginOfLine();
2064 DeleteToEndOfLine();
2065 m_CursorLine
->RecalculatePositions(2, this);
2069 line
= m_CursorLine
;
2070 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2072 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2073 wxASSERT(m_FirstLine
);
2074 wxASSERT(m_CursorLine
);
2076 m_CursorLine
->RecalculatePositions(2, this);
2081 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2083 wxLayoutLine
*line
= m_FirstLine
;
2085 // first, make sure everything is calculated - this might not be
2086 // needed, optimise it later
2087 ApplyStyle(m_DefaultStyleInfo
, dc
);
2090 line
->RecalculatePosition(this); // so we don't need to do it all the time
2091 // little condition to speed up redrawing:
2092 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2093 line
= line
->GetNextLine();
2098 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
2100 wxCHECK_RET( m_CursorLine
, "no cursor line" );
2102 // we need to save the current style, in case the layout() of the line
2104 wxLayoutStyleInfo SiBackup
= m_CurrentStyleInfo
;
2105 m_CursorLine
->Layout(dc
, this,
2106 &m_CursorScreenPos
, &m_CursorSize
,
2108 true /* suppress update */);
2109 ApplyStyle(SiBackup
, dc
); // restore it
2113 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2115 UpdateCursorScreenPos(dc
);
2117 return m_CursorScreenPos
;
2121 Is called before each Draw(). Now, it will re-layout all lines which
2125 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2126 wxPoint
*cpos
, wxPoint
*csize
)
2128 // first, make sure everything is calculated - this might not be
2129 // needed, optimise it later
2130 ApplyStyle(m_DefaultStyleInfo
, dc
);
2132 // This one we always Layout() to get the current cursor
2133 // coordinates on the screen:
2134 m_CursorLine
->MarkDirty();
2135 bool wasDirty
= false;
2136 wxLayoutLine
*line
= m_FirstLine
;
2140 ApplyStyle(line
->GetStyleInfo(), dc
);
2141 if(forceAll
|| line
->IsDirty()
2142 || (cpos
&& line
->GetLineNumber() == cpos
->y
))
2144 // The following Layout() calls will update our
2145 // m_CurrentStyleInfo if needed.
2146 if(line
== m_CursorLine
)
2147 line
->Layout(dc
, this,
2148 (wxPoint
*)&m_CursorScreenPos
,
2149 (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
2150 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2151 line
->Layout(dc
, this,
2155 line
->Layout(dc
, this);
2156 // little condition to speed up redrawing:
2157 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2161 line
->RecalculatePositions(1, this);
2162 line
= line
->GetNextLine();
2165 // can only be 0 if we are on the first line and have no next line
2166 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2167 m_CursorLine
->GetNextLine() == NULL
&&
2168 m_CursorLine
== m_FirstLine
));
2169 AddCursorPosToUpdateRect();
2173 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
)
2176 Layout(dc
, -1, false, &pos
, csize
);
2181 wxLayoutList::Draw(wxDC
&dc
,
2182 wxPoint
const &offset
,
2186 wxLayoutLine
*line
= m_FirstLine
;
2188 /* We need to re-layout all dirty lines to update styleinfos
2189 etc. However, somehow we don't find all dirty lines... */
2190 Layout(dc
); //,-1,true); //FIXME
2191 ApplyStyle(m_DefaultStyleInfo
, dc
);
2192 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2194 dc
.SetBackgroundMode(wxTRANSPARENT
);
2196 bool style_set
= false;
2199 // only draw if between top and bottom:
2201 line
->GetPosition().y
+ line
->GetHeight() >= top
))
2205 ApplyStyle(line
->GetStyleInfo(), dc
);
2208 line
->Draw(dc
, this, offset
);
2212 line
->Layout(dc
, this);
2214 // little condition to speed up redrawing:
2215 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2216 line
= line
->GetNextLine();
2218 InvalidateUpdateRect();
2220 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2221 m_Selection
.m_valid
? "valid" : "invalid",
2222 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2223 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2227 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2231 // First, find the right line:
2232 wxLayoutLine
*line
= m_FirstLine
;
2235 ApplyStyle(m_DefaultStyleInfo
, dc
);
2238 p
= line
->GetPosition();
2239 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2242 // we need to run a layout here to get font sizes right :-(
2244 // VZ: we can't call Layout() from here because it marks the line as
2245 // clean and it is not refreshed when it's called from wxLayoutList::
2246 // Layout() - if we really need to do this, we should introduce an
2247 // extra argument to Layout() to prevent the line from MarkClean()ing
2249 line
->Layout(dc
, this);
2251 line
= line
->GetNextLine();
2255 if(found
) *found
= false;
2256 return NULL
; // not found
2258 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
2259 // Now, find the object in the line:
2260 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
2261 cursorPos
? & cursorPos
->x
: NULL
,
2263 return (i
== NULLIT
) ? NULL
: *i
;
2268 wxLayoutList::GetSize(void) const
2271 *line
= m_FirstLine
,
2274 return wxPoint(0,0);
2276 wxPoint
maxPoint(0,0);
2281 if(line
->GetWidth() > maxPoint
.x
)
2282 maxPoint
.x
= line
->GetWidth();
2284 line
= line
->GetNextLine();
2287 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2289 // if the line was just added, its height would be 0 and we can't call
2290 // Layout() from here because we don't have a dc and we might be not drawing
2291 // at all, besides... So take the cursor height by default (taking 0 is bad
2292 // because then the scrollbars won't be resized and the new line won't be
2294 if ( last
->IsDirty() )
2296 if ( last
->GetHeight() == 0 )
2297 maxPoint
.y
+= m_CursorSize
.y
;
2298 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2299 maxPoint
.x
= m_CursorSize
.x
;
2307 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2309 if ( m_movedCursor
)
2311 UpdateCursorScreenPos(dc
);
2313 m_movedCursor
= false;
2316 wxPoint
coords(m_CursorScreenPos
);
2317 coords
+= translate
;
2319 #ifdef WXLAYOUT_DEBUG
2320 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2321 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2322 (long)coords
.x
, (long)coords
.y
,
2323 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2324 (long)m_CursorLine
->GetLineNumber(),
2325 (long)m_CursorLine
->GetLength()));
2327 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2330 #ifdef WXLAYOUT_USE_CARET
2331 m_caret
->Move(coords
);
2332 #else // !WXLAYOUT_USE_CARET
2333 dc
.SetBrush(*wxBLACK_BRUSH
);
2334 dc
.SetLogicalFunction(wxXOR
);
2335 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2338 dc
.DrawRectangle(coords
.x
, coords
.y
,
2339 m_CursorSize
.x
, m_CursorSize
.y
);
2340 SetUpdateRect(coords
.x
, coords
.y
);
2341 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2345 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2346 coords
.x
, coords
.y
);
2347 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2348 SetUpdateRect(coords
.x
, coords
.y
);
2350 dc
.SetLogicalFunction(wxCOPY
);
2351 //dc.SetBrush(wxNullBrush);
2352 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2356 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2358 if(m_UpdateRectValid
)
2359 GrowRect(m_UpdateRect
, x
, y
);
2364 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2365 m_UpdateRect
.height
= 4;// wxGTK :-)
2366 m_UpdateRectValid
= true;
2371 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2373 wxPoint
cpos(cposOrig
);
2376 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2377 m_Selection
.m_CursorA
= cpos
;
2378 m_Selection
.m_CursorB
= cpos
;
2379 m_Selection
.m_ScreenA
= spos
;
2380 m_Selection
.m_ScreenB
= spos
;
2381 m_Selection
.m_selecting
= true;
2382 m_Selection
.m_valid
= false;
2386 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2388 wxPoint
cpos(cposOrig
);
2392 wxASSERT(m_Selection
.m_selecting
== true);
2393 wxASSERT(m_Selection
.m_valid
== false);
2394 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2396 if ( m_Selection
.m_CursorB
<= cpos
)
2398 m_Selection
.m_ScreenB
= spos
;
2399 m_Selection
.m_CursorB
= cpos
;
2403 m_Selection
.m_ScreenA
= spos
;
2404 m_Selection
.m_CursorA
= cpos
;
2407 // we always want m_CursorA <= m_CursorB!
2408 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2410 // exchange the start/end points
2411 wxPoint help
= m_Selection
.m_CursorB
;
2412 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2413 m_Selection
.m_CursorA
= help
;
2415 help
= m_Selection
.m_ScreenB
;
2416 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2417 m_Selection
.m_ScreenA
= help
;
2422 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2424 wxPoint
cpos(cposOrig
);
2427 ContinueSelection(cpos
);
2428 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2429 m_Selection
.m_selecting
= false;
2430 m_Selection
.m_valid
= true;
2434 wxLayoutList::DiscardSelection()
2436 if ( !HasSelection() )
2439 m_Selection
.m_valid
=
2440 m_Selection
.m_selecting
= false;
2442 // invalidate the area which was previousle selected - and which is not
2443 // selected any more
2444 if ( m_Selection
.HasValidScreenCoords() )
2446 SetUpdateRect(m_Selection
.m_ScreenA
);
2447 SetUpdateRect(m_Selection
.m_ScreenB
);
2456 wxLayoutList::IsSelecting(void)
2458 return m_Selection
.m_selecting
;
2462 wxLayoutList::IsSelected(const wxPoint
&cursor
)
2464 if ( !HasSelection() )
2467 return m_Selection
.m_CursorA
<= cursor
&& cursor
<= m_Selection
.m_CursorB
;
2471 /** Tests whether this layout line is selected and needs
2473 @param line to test for
2474 @return 0 = not selected, 1 = fully selected, -1 = partially
2478 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2481 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2483 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2486 CoordType y
= line
->GetLineNumber();
2487 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2489 else if(m_Selection
.m_CursorA
.y
== y
)
2491 *from
= m_Selection
.m_CursorA
.x
;
2492 if(m_Selection
.m_CursorB
.y
== y
)
2493 *to
= m_Selection
.m_CursorB
.x
;
2495 *to
= line
->GetLength();
2498 else if(m_Selection
.m_CursorB
.y
== y
)
2500 *to
= m_Selection
.m_CursorB
.x
;
2501 if(m_Selection
.m_CursorA
.y
== y
)
2502 *from
= m_Selection
.m_CursorA
.x
;
2512 wxLayoutList::DeleteSelection(void)
2514 if(! m_Selection
.m_valid
)
2517 m_Selection
.m_valid
= false;
2519 // Only delete part of the current line?
2520 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2522 MoveCursorTo(m_Selection
.m_CursorA
);
2523 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2532 for(firstLine
= m_FirstLine
;
2533 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
2534 firstLine
=firstLine
->GetNextLine())
2536 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
2540 for(lastLine
= m_FirstLine
;
2541 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
2542 lastLine
=lastLine
->GetNextLine())
2544 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
2548 // We now know that the two lines are different:
2550 // First, delete what's left of this line:
2551 MoveCursorTo(m_Selection
.m_CursorA
);
2552 DeleteToEndOfLine();
2554 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
2555 while(nextLine
&& nextLine
!= lastLine
)
2556 nextLine
= nextLine
->DeleteLine(false, this);
2558 // Now nextLine = lastLine;
2559 Delete(1); // This joins firstLine and nextLine
2560 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
2564 firstLine
->RecalculatePositions(1, this);
2567 /// Starts highlighting the selection
2569 wxLayoutList::StartHighlighting(wxDC
&dc
)
2572 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2573 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2574 dc
.SetBackgroundMode(wxSOLID
);
2578 /// Ends highlighting the selection
2580 wxLayoutList::EndHighlighting(wxDC
&dc
)
2583 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2584 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2585 dc
.SetBackgroundMode(wxTRANSPARENT
);
2591 wxLayoutList::Copy(const wxPoint
&from
,
2598 for(firstLine
= m_FirstLine
;
2599 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2600 firstLine
=firstLine
->GetNextLine())
2602 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2605 for(lastLine
= m_FirstLine
;
2606 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2607 lastLine
=lastLine
->GetNextLine())
2609 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2614 wxLayoutLine
*tmp
= firstLine
;
2615 firstLine
= lastLine
;
2619 wxLayoutList
*llist
= new wxLayoutList();
2621 if(firstLine
== lastLine
)
2623 firstLine
->Copy(llist
, from
.x
, to
.x
);
2627 // Extract objects from first line
2628 firstLine
->Copy(llist
, from
.x
);
2630 // Extract all lines between
2631 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2633 line
= line
->GetNextLine())
2638 // Extract objects from last line
2639 lastLine
->Copy(llist
, 0, to
.x
);
2645 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2647 if(! m_Selection
.m_valid
)
2649 if(m_Selection
.m_selecting
)
2655 if(invalidate
) m_Selection
.m_valid
= false;
2657 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2658 m_Selection
.m_CursorB
);
2660 if(llist
&& wxlo
) // export as data object, too
2664 wxLayoutExportObject
*export
;
2665 wxLayoutExportStatus
status(llist
);
2666 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2668 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2669 ; //FIXME missing support for linebreaks in string format
2671 export
->content
.object
->Write(string
);
2675 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2682 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2685 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2687 bool fontChanged
= FALSE
;
2694 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2698 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2699 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2703 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2704 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2709 #ifdef WXLAYOUT_DEBUG
2712 wxLayoutList::Debug(void)
2714 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2715 m_CursorLine
->GetLineNumber(),
2716 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2719 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2728 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2732 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2734 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2735 wxString
const & title
)
2740 // remove any highlighting which could interfere with printing:
2741 m_llist
->StartSelection();
2742 m_llist
->EndSelection();
2745 wxLayoutPrintout::~wxLayoutPrintout()
2750 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2752 // The following bit is taken from the printing sample, let's see
2753 // whether it works for us.
2755 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2756 * the screen text size. This page also draws lines of actual length 5cm
2759 // Get the logical pixels per inch of screen and printer
2760 int ppiScreenX
, ppiScreenY
;
2761 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2762 int ppiPrinterX
, ppiPrinterY
;
2763 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2765 if(ppiScreenX
== 0) // not yet set, need to guess
2770 if(ppiPrinterX
== 0) // not yet set, need to guess
2776 // This scales the DC so that the printout roughly represents the
2777 // the screen scaling. The text point size _should_ be the right size
2778 // but in fact is too small for some reason. This is a detail that will
2779 // need to be addressed at some point but can be fudged for the
2781 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2783 // Now we have to check in case our real page size is reduced
2784 // (e.g. because we're drawing to a print preview memory DC)
2785 int pageWidth
, pageHeight
;
2787 dc
->GetSize(&w
, &h
);
2788 GetPageSizePixels(&pageWidth
, &pageHeight
);
2789 if(pageWidth
!= 0) // doesn't work always
2791 // If printer pageWidth == current DC width, then this doesn't
2792 // change. But w might be the preview bitmap width, so scale down.
2793 scale
= scale
* (float)(w
/(float)pageWidth
);
2795 dc
->SetUserScale(scale
, scale
);
2799 bool wxLayoutPrintout::OnPrintPage(int page
)
2808 top
= (page
- 1)*m_PrintoutHeight
;
2809 bottom
= top
+ m_PrintoutHeight
;
2810 // SetDeviceOrigin() doesn't work here, so we need to manually
2811 // translate all coordinates.
2812 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2813 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2820 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2822 /* We allocate a temporary wxDC for printing, so that we can
2823 determine the correct paper size and scaling. We don't actually
2824 print anything on it. */
2826 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2828 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2831 float scale
= ScaleDC(&psdc
);
2833 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2834 // This sets a left/top origin of 15% and 20%:
2835 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2837 // This is the length of the printable area.
2838 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2839 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2843 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2846 *maxPage
= m_NumOfPages
;
2849 *selPageTo
= m_NumOfPages
;
2850 wxRemoveFile(WXLLIST_TEMPFILE
);
2853 bool wxLayoutPrintout::HasPage(int pageNum
)
2855 return pageNum
<= m_NumOfPages
;
2859 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2860 out. It's a waste of paper anyway.
2864 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2865 wxPoint topleft
, wxPoint bottomright
,
2868 // make backups of all essential parameters
2869 const wxBrush
& brush
= dc
.GetBrush();
2870 const wxPen
& pen
= dc
.GetPen();
2871 const wxFont
& font
= dc
.GetFont();
2873 dc
.SetBrush(*wxWHITE_BRUSH
);
2874 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2875 dc
.DrawRoundedRectangle(topleft
.x
,
2876 topleft
.y
,bottomright
.x
-topleft
.x
,
2877 bottomright
.y
-topleft
.y
);
2878 dc
.SetBrush(*wxBLACK_BRUSH
);
2879 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2880 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2884 page
= "9999/9999 "; // many pages...
2886 dc
.GetTextExtent(page
,&w
,&h
);
2887 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2888 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2889 dc
.GetTextExtent("XXXX", &w
,&h
);
2890 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2901 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2904 for(wxFCEList::iterator i
= m_FontList
.begin();
2905 i
!= m_FontList
.end(); i
++)
2906 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2907 return (**i
).GetFont();
2909 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2911 m_FontList
.push_back(fce
);
2912 return fce
->GetFont();