1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
13 Layout() recalculates the objects, sizes, etc.
14 Draw() just draws them with the current settings, without
15 re-layout()ing them again
17 Each line has its own wxLayoutStyleInfo structure which gets updated
18 from within Layout(). Thanks to this, we don't need to re-layout all
19 lines if we want to draw one, but can just use its styleinfo to set
25 # pragma implementation "wxllist.h"
28 #include <wx/wxprec.h>
38 # include "gui/wxllist.h"
39 # include "gui/wxlparser.h"
40 # define SHOW_SELECTIONS 1
43 # include "wxlparser.h"
44 # define SHOW_SELECTIONS 1
48 # include <iostream.h>
52 # include <wx/print.h>
54 # include <wx/filefn.h>
57 #ifdef WXLAYOUT_USE_CARET
58 # include <wx/caret.h>
59 #endif // WXLAYOUT_USE_CARET
63 /// This should never really get created
64 #define WXLLIST_TEMPFILE "__wxllist.tmp"
68 # define TypeString(t) g_aTypeStrings[t]
69 # define WXLO_DEBUG(x) wxLogDebug x
71 static const char *g_aTypeStrings
[] =
73 "invalid", "text", "cmd", "icon"
76 wxLayoutObject::Debug(void)
78 WXLO_DEBUG(("%s",g_aTypeStrings
[GetType()]));
81 # define TypeString(t) ""
82 # define WXLO_DEBUG(x)
85 // FIXME under MSW, this constant is needed to make the thing properly redraw
86 // itself - I don't know where the size calculation error is and I can't
87 // waste time looking for it right now. Search for occurences of
88 // MSW_CORRECTION to find all the places where I did it.
90 static const int MSW_CORRECTION
= 10;
92 static const int MSW_CORRECTION
= 0;
95 /// Cursors smaller than this disappear in XOR drawing mode
96 #define WXLO_MINIMUM_CURSOR_WIDTH 4
98 /// Use this character to estimate a cursor size when none is available.
99 #define WXLO_CURSORCHAR "E"
100 /** @name Helper functions */
102 /// allows me to compare to wxPoints
103 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
105 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
109 The following STAY HERE until we have a working wxGTK again!!!
111 #ifndef wxWANTS_CHARS
112 /// allows me to compare to wxPoints
113 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
115 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
118 /// allows me to compare to wxPoints
119 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
121 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
124 wxPoint
& operator += (wxPoint
&p1
, wxPoint
const &p2
)
132 /// allows me to compare to wxPoints
133 bool operator>(wxPoint
const &p1
, wxPoint
const &p2
)
138 /// grows a wxRect so that it includes the given point
141 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
145 else if(r
.x
+ r
.width
< x
)
150 else if(r
.y
+ r
.height
< y
)
156 /// returns true if the point is in the rectangle
158 bool Contains(const wxRect
&r
, const wxPoint
&p
)
160 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
168 void ReadString(wxString
&to
, wxString
&from
)
171 const char *cptr
= from
.c_str();
172 while(*cptr
&& *cptr
!= '\n')
178 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
182 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
186 wxLayoutObject::Read(wxString
&istr
)
189 ReadString(tmp
, istr
);
191 sscanf(tmp
.c_str(),"%d", &type
);
196 return wxLayoutObjectText::Read(istr
);
198 return wxLayoutObjectCmd::Read(istr
);
200 return wxLayoutObjectIcon::Read(istr
);
206 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
210 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
212 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
222 wxLayoutObjectText::Copy(void)
224 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
225 obj
->m_Width
= m_Width
;
226 obj
->m_Height
= m_Height
;
228 obj
->m_Bottom
= m_Bottom
;
229 obj
->SetUserData(m_UserData
);
235 wxLayoutObjectText::Write(wxString
&ostr
)
237 ostr
<< (int) WXLO_TYPE_TEXT
<< '\n'
242 wxLayoutObjectText::Read(wxString
&istr
)
245 ReadString(text
, istr
);
247 return new wxLayoutObjectText(text
);
251 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
254 *top
= m_Top
; *bottom
= m_Bottom
;
255 return wxPoint(m_Width
, m_Height
);
259 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
260 wxLayoutList
*wxllist
,
261 CoordType begin
, CoordType end
)
265 // draw the whole object normally
266 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
270 // highlight the bit between begin and len
273 ypos
= coords
.y
-m_Top
;
274 long width
, height
, descent
;
276 if(begin
< 0) begin
= 0;
277 if( end
> (signed)m_Text
.Length() )
278 end
= m_Text
.Length();
280 wxString str
= m_Text
.Mid(0, begin
);
281 dc
.DrawText(str
, xpos
, ypos
);
282 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
284 wxllist
->StartHighlighting(dc
);
285 str
= m_Text
.Mid(begin
, end
-begin
);
286 dc
.DrawText(str
, xpos
, ypos
);
287 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
289 wxllist
->EndHighlighting(dc
);
290 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
291 dc
.DrawText(str
, xpos
, ypos
);
296 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
300 maxlen
= m_Text
.Length();
303 height
, descent
= 0l;
305 if(xpos
== 0) return 0; // easy
307 while(width
< xpos
&& offs
< maxlen
)
309 dc
.GetTextExtent(m_Text
.substr(0,offs
),
310 &width
, &height
, &descent
);
313 /* We have to substract 1 to compensate for the offs++, and another
314 one because we don't want to position the cursor behind the
315 object what we clicked on, but before - otherwise it looks
317 return (xpos
> 2) ? offs
-2 : 0;
321 wxLayoutObjectText::Layout(wxDC
&dc
, class wxLayoutList
*llist
)
325 // now this is done in wxLayoutLine::Layout(), but this code might be
326 // reenabled later - in principle, it's more efficient
328 CoordType widthOld
= m_Width
,
329 heightOld
= m_Height
;
333 CoordType a
,b
,c
,d
,e
,f
;
334 dc
.GetTextExtent("test ", &a
, &b
, &c
);
335 dc
.GetTextExtent("test", &d
, &e
, &f
);
339 dc
.GetTextExtent(" ", &d
, &e
, &f
);
342 dc
.GetTextExtent(m_Text
, &m_Width
, &m_Height
, &descent
);
345 if ( widthOld
!= m_Width
|| heightOld
!= m_Height
)
347 // as the text length changed, it must be refreshed
348 wxLayoutLine
*line
= GetLine();
350 wxCHECK_RET( line
, "wxLayoutObjectText can't refresh itself" );
352 // as our size changed, we need to repaint the part which was appended
353 wxPoint
position(line
->GetPosition());
355 // this is not the most efficient way (we repaint the whole line), but
356 // it's not too slow and is *simple*
357 if ( widthOld
< m_Width
)
359 if ( heightOld
< m_Height
)
360 heightOld
= m_Height
;
362 llist
->SetUpdateRect(position
.x
+ widthOld
+ MSW_CORRECTION
,
363 position
.y
+ heightOld
+ MSW_CORRECTION
);
368 m_Top
= m_Height
- m_Bottom
;
372 #ifdef WXLAYOUT_DEBUG
374 wxLayoutObjectText::Debug(void)
376 wxLayoutObject::Debug();
377 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
381 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
385 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
387 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
391 wxFAIL_MSG("invalid icon");
399 // FIXME ugly, ugly, ugly - but the only way to avoid slicing
400 m_Icon
= icon
.GetHBITMAP() ? new wxBitmap(icon
)
401 : new wxBitmap(wxBitmap((const wxBitmap
&)icon
));
403 m_Icon
= new wxBitmap(icon
);
409 wxLayoutObjectIcon::Write(wxString
&ostr
)
411 /* Exports icon through a temporary file. */
413 wxString file
= wxGetTempFileName("wxloexport");
415 ostr
<< WXLO_TYPE_ICON
<< '\n'
417 m_Icon
->SaveFile(file
, WXLO_BITMAP_FORMAT
);
421 wxLayoutObjectIcon::Read(wxString
&istr
)
424 ReadString(file
, istr
);
426 if(! wxFileExists(file
))
428 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon
;
430 if(!obj
->m_Icon
->LoadFile(file
, WXLO_BITMAP_FORMAT
))
440 wxLayoutObjectIcon::Copy(void)
442 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
444 obj
->SetUserData(m_UserData
);
448 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
454 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
455 wxLayoutList
*wxllist
,
456 CoordType begin
, CoordType
/* len */)
458 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
459 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
463 wxLayoutObjectIcon::Layout(wxDC
& /* dc */, class wxLayoutList
* )
468 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
470 *top
= m_Icon
->GetHeight();
472 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
477 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
481 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
484 wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily
,
496 underline
= iul
!= 0;
498 m_fg_valid
= fg
!= 0;
499 m_bg_valid
= bg
!= 0;
500 m_fg
= m_fg_valid
? *fg
: *wxBLACK
;
501 m_bg
= m_bg_valid
? *bg
: *wxWHITE
;
504 #define COPY_SI_(what) if(right.what != -1) what = right.what;
507 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
514 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
515 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
519 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
520 weight
, int underline
,
521 wxColour
*fg
, wxColour
*bg
)
524 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
528 wxLayoutObjectCmd::Copy(void)
530 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
535 m_StyleInfo
->underline
,
536 m_StyleInfo
->m_fg_valid
?
537 &m_StyleInfo
->m_fg
: NULL
,
538 m_StyleInfo
->m_bg_valid
?
539 &m_StyleInfo
->m_bg
: NULL
);
540 obj
->SetUserData(m_UserData
);
545 wxLayoutObjectCmd::Write(wxString
&ostr
)
547 ostr
<< WXLO_TYPE_CMD
<< '\n'
548 << m_StyleInfo
->size
<< '\n'
549 << m_StyleInfo
->family
<< '\n'
550 << m_StyleInfo
->style
<< '\n'
551 << m_StyleInfo
->weight
<< '\n'
552 << m_StyleInfo
->underline
<< '\n'
553 << m_StyleInfo
->m_fg_valid
<< '\n'
554 << m_StyleInfo
->m_bg_valid
<< '\n';
555 if(m_StyleInfo
->m_fg_valid
)
557 ostr
<< m_StyleInfo
->m_fg
.Red() << '\n'
558 << m_StyleInfo
->m_fg
.Green() << '\n'
559 << m_StyleInfo
->m_fg
.Blue() << '\n';
561 if(m_StyleInfo
->m_bg_valid
)
563 ostr
<< m_StyleInfo
->m_bg
.Red() << '\n'
564 << m_StyleInfo
->m_bg
.Green() << '\n'
565 << m_StyleInfo
->m_bg
.Blue() << '\n';
570 wxLayoutObjectCmd::Read(wxString
&istr
)
572 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd
;
575 ReadString(tmp
, istr
);
576 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->size
);
577 ReadString(tmp
, istr
);
578 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->family
);
579 ReadString(tmp
, istr
);
580 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->style
);
581 ReadString(tmp
, istr
);
582 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->weight
);
583 ReadString(tmp
, istr
);
584 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->underline
);
585 ReadString(tmp
, istr
);
586 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_fg_valid
);
587 ReadString(tmp
, istr
);
588 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_bg_valid
);
589 if(obj
->m_StyleInfo
->m_fg_valid
)
591 int red
, green
, blue
;
592 ReadString(tmp
, istr
);
593 sscanf(tmp
.c_str(),"%d", &red
);
594 ReadString(tmp
, istr
);
595 sscanf(tmp
.c_str(),"%d", &green
);
596 ReadString(tmp
, istr
);
597 sscanf(tmp
.c_str(),"%d", &blue
);
598 obj
->m_StyleInfo
->m_fg
= wxColour(red
, green
, blue
);
600 if(obj
->m_StyleInfo
->m_bg_valid
)
602 int red
, green
, blue
;
603 ReadString(tmp
, istr
);
604 sscanf(tmp
.c_str(),"%d", &red
);
605 ReadString(tmp
, istr
);
606 sscanf(tmp
.c_str(),"%d", &green
);
607 ReadString(tmp
, istr
);
608 sscanf(tmp
.c_str(),"%d", &blue
);
609 obj
->m_StyleInfo
->m_bg
= wxColour(red
, green
, blue
);
615 wxLayoutObjectCmd::~wxLayoutObjectCmd()
621 wxLayoutObjectCmd::GetStyle(void) const
627 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
628 wxLayoutList
*wxllist
,
629 CoordType begin
, CoordType
/* len */)
631 wxASSERT(m_StyleInfo
);
632 wxllist
->ApplyStyle(*m_StyleInfo
, dc
);
636 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
638 // this get called, so that recalculation uses right font sizes
639 Draw(dc
, wxPoint(0,0), llist
);
643 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
645 The wxLayoutLine object
647 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
649 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
651 m_Width
= m_Height
= 0;
661 RecalculatePosition(llist
);
666 m_LineNumber
= m_Previous
->GetLineNumber() + 1;
667 m_Next
= m_Previous
->GetNextLine();
668 m_Previous
->m_Next
= this;
673 m_Next
->m_Previous
= this;
677 m_StyleInfo
= llist
->GetDefaultStyleInfo();
679 llist
->IncNumLines();
682 wxLayoutLine::~wxLayoutLine()
684 // kbList cleans itself
688 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
690 wxASSERT(m_Previous
|| GetLineNumber() == 0);
692 wxPoint
posOld(m_Position
);
696 m_Position
= m_Previous
->GetPosition();
697 m_Position
.y
+= m_Previous
->GetHeight();
700 m_Position
= wxPoint(0,0);
702 if ( m_Position
!= posOld
)
704 // the whole line moved and must be repainted
705 llist
->SetUpdateRect(m_Position
);
706 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
707 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
708 llist
->SetUpdateRect(posOld
);
709 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
710 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
717 wxLayoutObjectList::iterator
718 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
722 wxLayoutObjectList::iterator
725 CoordType x
= 0, len
;
727 /* We search through the objects. As we don't like returning the
728 object that the cursor is behind, we just remember such an
729 object in "found" so we can return it if there is really no
730 further object following it. */
731 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
733 len
= (**i
).GetLength();
734 if( x
<= xpos
&& xpos
<= x
+ len
)
737 if(xpos
== x
+ len
) // is there another object behind?
739 else // we are really inside this object
742 x
+= (**i
).GetLength();
744 return found
; // ==NULL if really none found
747 wxLayoutObjectList::iterator
748 wxLayoutLine::FindObjectScreen(wxDC
&dc
, wxLayoutList
*llist
,
749 CoordType xpos
, CoordType
*cxpos
,
754 llist
->ApplyStyle(GetStyleInfo(), dc
);
756 wxLayoutObjectList::iterator i
;
757 CoordType x
= 0, cx
= 0, width
;
759 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
761 wxLayoutObject
*obj
= *i
;
762 if ( obj
->GetType() == WXLO_TYPE_CMD
)
764 // this will set the correct font for the objects which follow
765 obj
->Layout(dc
, llist
);
768 width
= obj
->GetWidth();
769 if( x
<= xpos
&& xpos
<= x
+ width
)
771 *cxpos
= cx
+ obj
->GetOffsetScreen(dc
, xpos
-x
);
778 x
+= obj
->GetWidth();
779 cx
+= obj
->GetLength();
782 // behind last object:
787 return m_ObjectList
.tail();
790 /** Finds text in this line.
791 @param needle the text to find
792 @param xpos the position where to start the search
793 @return the cursoor coord where it was found or -1
796 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
801 wxString
const *text
;
803 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
805 if(cpos
>= xpos
) // search from here!
807 if((**i
).GetType() == WXLO_TYPE_TEXT
)
809 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
810 relpos
= text
->Find(needle
);
811 if(relpos
>= cpos
-xpos
) // -1 if not found
816 cpos
+= (**i
).GetLength();
819 return -1; // not found
823 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
826 wxASSERT(obj
!= NULL
);
831 wxLOiterator i
= FindObject(xpos
, &offset
);
834 if(xpos
== 0 ) // aha, empty line!
836 m_ObjectList
.push_back(obj
);
837 m_Length
+= obj
->GetLength();
844 CoordType len
= (**i
).GetLength();
845 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
846 { // insert before this object
847 m_ObjectList
.insert(i
,obj
);
848 m_Length
+= obj
->GetLength();
853 if( i
== m_ObjectList
.tail()) // last object?
854 m_ObjectList
.push_back(obj
);
856 { // insert after current object
858 m_ObjectList
.insert(i
,obj
);
860 m_Length
+= obj
->GetLength();
863 /* Otherwise we need to split the current object.
864 Fortunately this can only be a text object. */
865 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
866 wxString left
, right
;
867 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
868 left
= tobj
->GetText().substr(0,offset
);
869 right
= tobj
->GetText().substr(offset
,len
-offset
);
870 // current text object gets set to right half
871 tobj
->GetText() = right
; // set new text
872 // before it we insert the new object
873 m_ObjectList
.insert(i
,obj
);
874 m_Length
+= obj
->GetLength();
875 // and before that we insert the left half
876 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
881 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
888 wxLOiterator i
= FindObject(xpos
, &offset
);
889 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
891 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
892 tobj
->GetText().insert(offset
, text
);
893 m_Length
+= text
.Length();
897 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
905 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
907 CoordType offset
, len
;
912 wxLOiterator i
= FindObject(xpos
, &offset
);
915 if(i
== NULLIT
) return npos
;
916 // now delete from that object:
917 if((**i
).GetType() != WXLO_TYPE_TEXT
)
919 if(offset
!= 0) // at end of line after a non-text object
922 len
= (**i
).GetLength();
925 m_ObjectList
.erase(i
);
929 // tidy up: remove empty text objects
930 if((**i
).GetLength() == 0)
932 m_ObjectList
.erase(i
);
936 CoordType max
= (**i
).GetLength() - offset
;
937 if(npos
< max
) max
= npos
;
940 if(xpos
== GetLength())
943 { // at the end of an object
944 // move to begin of next object:
946 continue; // start over
951 if(offset
== 0 && max
== (**i
).GetLength())
952 m_ObjectList
.erase(i
); // remove the whole object
954 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
962 wxLayoutLine::DeleteWord(CoordType xpos
)
968 wxLOiterator i
= FindObject(xpos
, &offset
);
972 if(i
== NULLIT
) return false;
973 if((**i
).GetType() != WXLO_TYPE_TEXT
)
975 // This should only happen when at end of line, behind a non-text
977 if(offset
== (**i
).GetLength()) return false;
978 m_Length
-= (**i
).GetLength(); // -1
979 m_ObjectList
.erase(i
);
980 return true; // we are done
984 if(offset
== (**i
).GetLength()) // at end of object
989 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
991 wxString str
= tobj
->GetText();
992 str
= str
.substr(offset
,str
.Length()-offset
);
993 // Find out how many positions we need to delete:
994 // 1. eat leading space
995 while(isspace(str
.c_str()[count
])) count
++;
996 // 2. eat the word itself:
997 while(isalnum(str
.c_str()[count
])) count
++;
999 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
1000 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
1006 wxFAIL_MSG("unreachable");
1010 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1012 // maintain linked list integrity
1014 m_Next
->m_Previous
= m_Previous
;
1016 m_Previous
->m_Next
= m_Next
;
1018 // get the line numbers right again
1019 if ( update
&& m_Next
)
1024 // we can't use m_Next after "delete this", so we must save this pointer
1026 wxLayoutLine
*next
= m_Next
;
1029 llist
->DecNumLines();
1035 wxLayoutLine::Draw(wxDC
&dc
,
1036 wxLayoutList
*llist
,
1037 const wxPoint
& offset
) const
1039 wxLayoutObjectList::iterator i
;
1040 wxPoint pos
= offset
;
1041 pos
= pos
+ GetPosition();
1043 pos
.y
+= m_BaseLine
;
1045 CoordType xpos
= 0; // cursorpos, lenght of line
1047 CoordType from
, to
, tempto
;
1049 int highlight
= llist
->IsSelected(this, &from
, &to
);
1050 // WXLO_DEBUG(("highlight=%d", highlight ));
1051 if(highlight
== 1) // we need to draw the whole line inverted!
1052 llist
->StartHighlighting(dc
);
1054 llist
->EndHighlighting(dc
);
1056 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1058 if(highlight
== -1) // partially highlight line
1060 // parts of the line need highlighting
1061 tempto
= xpos
+(**i
).GetLength();
1062 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1065 (**i
).Draw(dc
, pos
, llist
);
1066 pos
.x
+= (**i
).GetWidth();
1067 xpos
+= (**i
).GetLength();
1072 This function does all the recalculation, that is, it should only be
1073 called from within wxLayoutList::Layout(), as it uses the current
1074 list's styleinfo and updates it.
1077 wxLayoutLine::Layout(wxDC
&dc
,
1078 wxLayoutList
*llist
,
1080 wxPoint
*cursorSize
,
1081 wxLayoutStyleInfo
*cursorStyle
,
1083 bool suppressSIupdate
)
1085 wxLayoutObjectList::iterator i
;
1087 // when a line becomes dirty, we redraw it from the place where it was
1088 // changed till the end of line (because the following wxLayoutObjects are
1089 // moved when the preceding one changes) - calculate the update rectangle.
1090 CoordType updateTop
= m_Position
.y
,
1092 updateWidth
= m_Width
,
1093 updateHeight
= m_Height
;
1097 bottomHeight
= 0; // above and below baseline
1099 objTopHeight
, objBottomHeight
; // above and below baseline
1103 CoordType heightOld
= m_Height
;
1109 bool cursorFound
= false;
1111 RecalculatePosition(llist
);
1115 *cursorPos
= m_Position
;
1116 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1119 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1120 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1122 wxLayoutObject
*obj
= *i
;
1123 obj
->Layout(dc
, llist
);
1124 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1126 if(cursorPos
&& ! cursorFound
)
1128 // we need to check whether the text cursor is here
1129 len
= obj
->GetLength();
1130 if(count
<= cx
&& count
+len
> cx
)
1132 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1134 len
= cx
- count
; // pos in object
1135 CoordType width
, height
, descent
;
1136 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1137 &width
, &height
, &descent
);
1138 cursorPos
->x
+= width
;
1139 cursorPos
->y
= m_Position
.y
;
1141 if(len
< obj
->GetLength())
1142 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1144 str
= WXLO_CURSORCHAR
;
1145 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1147 if(cursorStyle
) // set style info
1148 *cursorStyle
= llist
->GetStyleInfo();
1151 // Just in case some joker inserted an empty string object:
1153 width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1156 cursorSize
->x
= width
;
1157 cursorSize
->y
= height
;
1160 cursorFound
= true; // no more checks
1164 // on some other object
1165 CoordType top
, bottom
; // unused
1167 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1168 cursorPos
->y
= m_Position
.y
;
1169 cursorFound
= true; // no more checks
1175 cursorPos
->x
+= obj
->GetWidth();
1179 m_Width
+= sizeObj
.x
;
1180 if(sizeObj
.y
> m_Height
)
1182 m_Height
= sizeObj
.y
;
1185 if(objTopHeight
> topHeight
)
1186 topHeight
= objTopHeight
;
1187 if(objBottomHeight
> bottomHeight
)
1188 bottomHeight
= objBottomHeight
;
1193 if ( updateHeight
< m_Height
)
1194 updateHeight
= m_Height
;
1195 if ( updateWidth
< m_Width
)
1196 updateWidth
= m_Width
;
1198 // update all line if we don't know where to start from
1199 if ( updateLeft
== -1 )
1202 llist
->SetUpdateRect(updateLeft
, updateTop
);
1203 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1204 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1207 if(topHeight
+ bottomHeight
> m_Height
)
1209 m_Height
= topHeight
+bottomHeight
;
1212 m_BaseLine
= topHeight
;
1216 CoordType width
, height
, descent
;
1217 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1219 m_BaseLine
= m_Height
- descent
;
1222 // tell next line about coordinate change
1223 if(m_Next
&& m_Height
!= heightOld
)
1225 m_Next
->MarkDirty();
1228 // We need to check whether we found a valid cursor size:
1229 if(cursorPos
&& cursorSize
)
1231 // this might be the case if the cursor is at the end of the
1232 // line or on a command object:
1233 if(cursorSize
->x
< WXLO_MINIMUM_CURSOR_WIDTH
)
1235 CoordType width
, height
, descent
;
1236 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1237 cursorSize
->x
= width
;
1238 cursorSize
->y
= height
;
1240 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1241 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1248 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1250 wxASSERT(xpos
>= 0);
1255 wxLOiterator i
= FindObject(xpos
, &offset
);
1257 // must be at the end of the line then
1258 return new wxLayoutLine(this, llist
);
1261 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1262 // split object at i:
1263 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1265 wxString left
, right
;
1266 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1267 left
= tobj
->GetText().substr(0,offset
);
1268 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1269 // current text object gets set to left half
1270 tobj
->GetText() = left
; // set new text
1271 newLine
->Append(new wxLayoutObjectText(right
));
1272 m_Length
-= right
.Length();
1273 i
++; // don't move this object to the new list
1278 i
++; // move objects from here to new list
1281 while(i
!= m_ObjectList
.end())
1283 wxLayoutObject
*obj
= *i
;
1284 newLine
->Append(obj
);
1285 m_Length
-= obj
->GetLength();
1287 m_ObjectList
.remove(i
); // remove without deleting it
1290 m_Next
->MarkDirty();
1295 wxLayoutLine::ReNumber(void)
1297 CoordType lineNo
= m_Previous
? m_Previous
->m_LineNumber
+1 : 0;
1298 m_LineNumber
= lineNo
++;
1300 for(wxLayoutLine
*next
= GetNextLine();
1301 next
; next
= next
->GetNextLine())
1302 next
->m_LineNumber
= lineNo
++;
1306 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1308 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1309 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1312 MarkDirty(GetWidth());
1314 wxLayoutObject
*last
= NULL
;
1315 for(i
= list
.begin(); i
!= list
.end();)
1317 wxLayoutObject
*current
= *i
;
1319 // merge text objects together for efficiency
1320 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1321 current
->GetType() == WXLO_TYPE_TEXT
)
1323 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1324 wxString
text(textObj
->GetText());
1325 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1326 textObj
->SetText(text
);
1328 list
.erase(i
); // remove and delete it
1332 // just append the object "as was"
1335 list
.remove(i
); // remove without deleting it
1338 wxASSERT(list
.empty());
1340 wxLayoutLine
*oldnext
= GetNextLine();
1341 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1345 nextLine
->ReNumber();
1349 // this is now done in Delete(), but if this function is ever called
1350 // from elsewhere, we might have to move refresh code back here (in
1351 // order not to duplicate it)
1353 wxPoint
pos(oldnext
->GetPosition());
1354 llist
->SetUpdateRect(pos
);
1355 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1356 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1360 llist
->DecNumLines();
1366 wxLayoutLine::GetWrapPosition(CoordType column
)
1369 wxLOiterator i
= FindObject(column
, &offset
);
1370 if(i
== NULLIT
) return -1; // cannot wrap
1372 // go backwards through the list and look for space in text objects
1375 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1379 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1386 }while(offset
!= -1);
1387 i
--; // move on to previous object
1391 column
-= (**i
).GetLength();
1395 offset
= (**i
).GetLength();
1396 }while(i
!= NULLIT
);
1397 /* If we reached the begin of the list and have more than one
1398 object, that one is longer than the margin, so break behind
1401 i
= m_ObjectList
.begin();
1402 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1404 pos
+= (**i
).GetLength();
1407 if(i
== NULLIT
) return -1; //why should this happen?
1408 pos
+= (**i
).GetLength();
1410 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1412 pos
+= (**i
).GetLength();
1415 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1416 // now we are at the second text object:
1417 pos
-= (**i
).GetLength();
1418 return pos
; // in front of it
1422 #ifdef WXLAYOUT_DEBUG
1424 wxLayoutLine::Debug(void)
1427 wxPoint pos
= GetPosition();
1428 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1429 (long int) GetLineNumber(),
1430 (long int) pos
.x
, (long int) pos
.y
,
1431 (long int) GetHeight(),
1432 (long int) m_BaseLine
,
1433 (int) m_StyleInfo
.family
));
1434 if(m_ObjectList
.begin() != NULLIT
)
1435 (**m_ObjectList
.begin()).Debug();
1441 wxLayoutLine::Copy(wxLayoutList
*llist
,
1445 CoordType firstOffset
, lastOffset
;
1447 if(to
== -1) to
= GetLength();
1448 if(from
== to
) return;
1450 wxLOiterator first
= FindObject(from
, &firstOffset
);
1451 wxLOiterator last
= FindObject(to
, &lastOffset
);
1453 // Common special case: only one object
1454 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1456 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1458 llist
->Insert(new wxLayoutObjectText(
1459 ((wxLayoutObjectText
1460 *)*first
)->GetText().substr(firstOffset
,
1461 lastOffset
-firstOffset
))
1465 else // what can we do?
1467 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1468 llist
->Insert( (**first
).Copy() );
1473 // If we reach here, we can safely copy the whole first object from
1474 // the firstOffset position on:
1475 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1477 llist
->Insert(new wxLayoutObjectText(
1478 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1481 else if(firstOffset
== 0)
1482 llist
->Insert( (**first
).Copy() );
1483 // else nothing to copy :-(
1485 // Now we copy all objects before the last one:
1486 wxLOiterator i
= first
; i
++;
1487 for( ; i
!= last
; i
++)
1488 llist
->Insert( (**i
).Copy() );
1490 // And now the last object:
1493 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1495 llist
->Insert(new wxLayoutObjectText(
1496 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1500 llist
->Insert( (**last
).Copy() );
1505 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1507 The wxLayoutList object
1509 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1511 wxLayoutList::wxLayoutList()
1513 #ifdef WXLAYOUT_USE_CARET
1515 #endif // WXLAYOUT_USE_CARET
1519 SetAutoFormatting(TRUE
);
1520 ForceTotalLayout(TRUE
); // for the first time, do all
1521 InvalidateUpdateRect();
1525 wxLayoutList::~wxLayoutList()
1527 SetAutoFormatting(FALSE
);
1530 m_FirstLine
->DeleteLine(false, this);
1532 wxASSERT_MSG( m_numLines
== 0, "line count calculation broken" );
1536 wxLayoutList::Empty(void)
1539 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1541 m_CursorPos
= wxPoint(0,0);
1542 m_CursorScreenPos
= wxPoint(0,0);
1543 m_CursorSize
= wxPoint(0,0);
1544 m_movedCursor
= true;
1545 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1546 m_CursorLine
= m_FirstLine
;
1547 InvalidateUpdateRect();
1552 wxLayoutList::InternalClear(void)
1554 m_Selection
.m_selecting
= false;
1555 m_Selection
.m_valid
= false;
1557 m_DefaultStyleInfo
.family
= wxSWISS
;
1558 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1559 m_DefaultStyleInfo
.style
= wxNORMAL
;
1560 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1561 m_DefaultStyleInfo
.underline
= 0;
1562 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1563 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1564 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1565 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1567 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1568 m_CursorStyleInfo
= m_DefaultStyleInfo
;
1572 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1573 int underline
, wxColour
*fg
,
1576 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1577 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1578 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1579 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1580 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1581 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1582 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1584 new wxLayoutObjectCmd(
1585 m_CurrentStyleInfo
.family
,
1586 m_CurrentStyleInfo
.size
,
1587 m_CurrentStyleInfo
.style
,
1588 m_CurrentStyleInfo
.weight
,
1589 m_CurrentStyleInfo
.underline
,
1594 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1595 int underline
, char const *fg
, char const *bg
)
1603 cfg
= wxTheColourDatabase
->FindColour(fg
);
1605 cbg
= wxTheColourDatabase
->FindColour(bg
);
1607 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1611 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1612 int underline
, wxColour
*fg
, wxColour
*bg
)
1615 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1617 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1619 // Empty() should be called after we set m_DefaultStyleInfo because
1620 // otherwise the style info for the first line (created in Empty()) would be
1626 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1631 for(line
= m_FirstLine
;
1633 line
= line
->GetNextLine())
1635 if(line
->GetLineNumber() >= cpos
.y
)
1637 xpos
= line
->FindText(needle
,
1638 (line
->GetLineNumber() == cpos
.y
) ?
1641 return wxPoint(xpos
, line
->GetLineNumber());
1644 return wxPoint(-1,-1);
1649 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1651 AddCursorPosToUpdateRect();
1653 wxPoint cursorPosOld
= m_CursorPos
;
1655 wxLayoutLine
*line
= m_FirstLine
;
1656 while(line
&& line
->GetLineNumber() != p
.y
)
1657 line
= line
->GetNextLine();
1658 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1660 m_CursorPos
.y
= p
.y
;
1661 m_CursorLine
= line
;
1662 CoordType len
= line
->GetLength();
1665 m_CursorPos
.x
= p
.x
;
1669 m_CursorPos
.x
= len
;
1673 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1675 return m_CursorPos
== p
;
1679 wxLayoutList::MoveCursorVertically(int n
)
1681 AddCursorPosToUpdateRect();
1683 wxPoint cursorPosOld
= m_CursorPos
;
1686 if(n
< 0) // move up
1688 if(m_CursorLine
== m_FirstLine
) return false;
1689 while(n
< 0 && m_CursorLine
)
1691 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1697 m_CursorLine
= m_FirstLine
;
1703 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1704 m_CursorPos
.x
= m_CursorLine
->GetLength();
1710 wxLayoutLine
*last
= m_CursorLine
;
1711 if(! m_CursorLine
->GetNextLine()) return false;
1712 while(n
> 0 && m_CursorLine
)
1716 m_CursorLine
= m_CursorLine
->GetNextLine();
1720 m_CursorLine
= last
;
1726 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1727 m_CursorPos
.x
= m_CursorLine
->GetLength();
1732 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1738 wxLayoutList::MoveCursorHorizontally(int n
)
1740 AddCursorPosToUpdateRect();
1742 wxPoint cursorPosOld
= m_CursorPos
;
1747 if(m_CursorPos
.x
== 0) // at begin of line
1749 if(! MoveCursorVertically(-1))
1751 MoveCursorToEndOfLine();
1756 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1757 m_CursorPos
.x
-= move
; n
+= move
;
1762 int len
= m_CursorLine
->GetLength();
1763 if(m_CursorPos
.x
== len
) // at end of line
1765 if(! MoveCursorVertically(1))
1767 MoveCursorToBeginOfLine();
1772 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1773 m_CursorPos
.x
+= move
;
1777 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1783 wxLayoutList::MoveCursorWord(int n
, bool untilNext
)
1785 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1786 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1788 CoordType moveDistance
= 0;
1790 wxLayoutLine
*lineCur
= m_CursorLine
;
1791 for ( wxLOiterator i
= lineCur
->FindObject(m_CursorPos
.x
, &offset
);
1799 // moving forward, pass to the first object of the next line
1801 lineCur
= lineCur
->GetNextLine();
1803 i
= lineCur
->GetFirstObject();
1807 // moving backwards, pass to the last object of the prev line
1809 lineCur
= lineCur
->GetPreviousLine();
1811 i
= lineCur
->GetLastObject();
1816 // moved to the end/beginning of text
1823 wxLayoutObject
*obj
= *i
;
1827 // calculate offset: we are either at the very beginning or the very
1828 // end of the object, so it isn't very difficult (the only time when
1829 // offset is != -1 is for the very first iteration when its value is
1830 // returned by FindObject)
1834 offset
= obj
->GetLength();
1837 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1839 // any visible non text objects count as one word
1840 if ( obj
->IsVisibleObject() )
1844 moveDistance
+= obj
->GetLength();
1849 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1851 bool canAdvance
= true;
1853 if ( offset
== tobj
->GetLength() )
1858 // can't move further in this text object
1861 // still should move over the object border
1865 else if ( offset
> 0 )
1867 // offset is off by 1, make it a valid index
1874 const wxString
& text
= tobj
->GetText();
1875 const char *start
= text
.c_str();
1876 const char *end
= start
+ text
.length();
1877 const char *p
= start
+ offset
;
1885 // to the beginning/end of the next/prev word
1886 while ( p
>= start
&& p
< end
&& isspace(*p
) )
1891 // go to the end/beginning of the word (in a broad sense...)
1892 while ( p
>= start
&& p
< end
&& !isspace(*p
) )
1901 // now advance to the beginning of the next word
1902 while ( isspace(*p
) && p
< end
)
1908 // in these 2 cases we took 1 char too much
1909 if ( (p
< start
) || isspace(*p
) )
1915 CoordType moveDelta
= p
- start
- offset
;
1916 if ( (n
< 0) && (offset
== tobj
->GetLength() - 1) )
1918 // because we substracted 1 from offset in this case above, now
1919 // compensate for it
1923 if ( moveDelta
!= 0 )
1925 moveDistance
+= moveDelta
;
1932 // except for the first iteration, offset is calculated in the beginning
1937 MoveCursorHorizontally(moveDistance
);
1943 wxLayoutList::Insert(wxString
const &text
)
1945 wxASSERT(m_CursorLine
);
1946 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1951 AddCursorPosToUpdateRect();
1953 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1956 m_CursorPos
.x
+= text
.Length();
1958 m_movedCursor
= true;
1961 m_CursorLine
->MarkDirty();
1967 wxLayoutList::Insert(wxLayoutObject
*obj
)
1969 wxASSERT(m_CursorLine
);
1972 m_CursorLine
= GetFirstLine();
1974 AddCursorPosToUpdateRect();
1976 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1977 m_CursorPos
.x
+= obj
->GetLength();
1978 m_movedCursor
= true;
1981 m_CursorLine
->MarkDirty();
1987 wxLayoutList::Insert(wxLayoutList
*llist
)
1992 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1994 line
= line
->GetNextLine()
1997 for(wxLOiterator i
= line
->GetFirstObject();
2007 wxLayoutList::LineBreak(void)
2009 wxASSERT(m_CursorLine
);
2011 AddCursorPosToUpdateRect();
2013 wxPoint
position(m_CursorLine
->GetPosition());
2016 width
= m_CursorLine
->GetWidth(),
2017 height
= m_CursorLine
->GetHeight();
2019 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
2020 if(m_CursorLine
->GetPreviousLine() == NULL
)
2021 m_FirstLine
= m_CursorLine
;
2025 // The following code will produce a height which is guaranteed to
2026 // be too high: old lineheight + the height of both new lines.
2027 // We can probably drop the old line height and start with height =
2029 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
2031 height
+= prev
->GetHeight();
2032 height
+= m_CursorLine
->GetHeight();
2034 m_movedCursor
= true;
2036 SetUpdateRect(position
);
2037 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
2038 position
.y
+ height
+ MSW_CORRECTION
);
2044 wxLayoutList::WrapLine(CoordType column
)
2046 if(m_CursorPos
.x
<= column
|| column
< 1)
2047 return false; // do nothing yet
2050 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
2052 return false; // cannot break line
2054 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
2055 m_CursorPos
.x
= xpos
;
2057 AddCursorPosToUpdateRect();
2060 Delete(1); // delete the space
2061 m_CursorPos
.x
= newpos
;
2063 m_CursorLine
->MarkDirty();
2065 m_movedCursor
= true;
2072 wxLayoutList::Delete(CoordType npos
)
2074 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
2079 AddCursorPosToUpdateRect();
2081 // were other lines appended to this one (this is important to know because
2082 // this means that our width _increased_ as the result of deletion)
2083 bool wasMerged
= false;
2085 // the size of the region to update
2086 CoordType totalHeight
= m_CursorLine
->GetHeight(),
2087 totalWidth
= m_CursorLine
->GetWidth();
2092 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
2096 // More to delete, continue on next line.
2098 // First, check if line is empty:
2099 if(m_CursorLine
->GetLength() == 0)
2101 // in this case, updating could probably be optimised
2103 wxASSERT(DeleteLines(1) == 0);
2112 // Need to join next line
2113 if(! m_CursorLine
->GetNextLine())
2118 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2121 totalHeight
+= next
->GetHeight();
2122 totalWidth
+= next
->GetWidth();
2124 m_CursorLine
->MergeNextLine(this);
2129 wxFAIL_MSG("can't delete all this");
2139 // we need to update the whole tail of the line and the lines which
2143 wxPoint
position(m_CursorLine
->GetPosition());
2144 SetUpdateRect(position
);
2145 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2146 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2153 wxLayoutList::DeleteLines(int n
)
2155 wxASSERT(m_CursorLine
);
2158 AddCursorPosToUpdateRect();
2162 if(!m_CursorLine
->GetNextLine())
2163 { // we cannot delete this line, but we can clear it
2164 MoveCursorToBeginOfLine();
2165 DeleteToEndOfLine();
2167 m_CursorLine
->MarkDirty();
2171 line
= m_CursorLine
;
2172 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2174 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2175 wxASSERT(m_FirstLine
);
2176 wxASSERT(m_CursorLine
);
2179 m_CursorLine
->MarkDirty();
2184 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2188 wxLayoutLine
*line
= m_FirstLine
;
2190 // first, make sure everything is calculated - this might not be
2191 // needed, optimise it later
2192 ApplyStyle(m_DefaultStyleInfo
, dc
);
2195 line
->RecalculatePosition(this); // so we don't need to do it all the time
2196 // little condition to speed up redrawing:
2197 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2198 line
= line
->GetNextLine();
2203 wxLayoutList::GetCursorScreenPos(void) const
2205 return m_CursorScreenPos
;
2209 Is called before each Draw(). Now, it will re-layout all lines which
2213 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2214 wxPoint
*cpos
, wxPoint
*csize
)
2216 // first, make sure everything is calculated - this might not be
2217 // needed, optimise it later
2218 ApplyStyle(m_DefaultStyleInfo
, dc
);
2226 ForceTotalLayout(FALSE
);
2229 // If one line was dirty, we need to re-calculate all
2230 // following lines, too.
2231 bool wasDirty
= forceAll
;
2232 wxLayoutLine
*line
= m_FirstLine
;
2236 ApplyStyle(line
->GetStyleInfo(), dc
);
2238 // if any previous line was dirty, we need to layout all
2241 // layout dirty lines:
2243 // always layout the cursor line toupdate the cursor
2244 // position and size:
2245 || line
== m_CursorLine
2246 // or if it's the line we are asked to look for:
2247 || (cpos
&& line
->GetLineNumber() == cpos
->y
)
2253 // The following Layout() calls will update our
2254 // m_CurrentStyleInfo if needed.
2255 if(line
== m_CursorLine
)
2257 line
->Layout(dc
, this,
2258 (wxPoint
*)&m_CursorScreenPos
,
2259 (wxPoint
*)&m_CursorSize
,
2262 // we cannot layout the line twice, so copy the coords:
2263 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2265 *cpos
= m_CursorScreenPos
;
2267 *csize
= m_CursorSize
;
2271 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2272 line
->Layout(dc
, this,
2274 csize
, NULL
, cpos
->x
);
2276 line
->Layout(dc
, this);
2277 // little condition to speed up redrawing:
2278 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2281 line
= line
->GetNextLine();
2284 #ifndef WXLAYOUT_USE_CARET
2285 // can only be 0 if we are on the first line and have no next line
2286 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2287 m_CursorLine
->GetNextLine() == NULL
&&
2288 m_CursorLine
== m_FirstLine
));
2289 #endif // WXLAYOUT_USE_CARET
2290 AddCursorPosToUpdateRect();
2294 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
)
2297 Layout(dc
, -1, false, &pos
, csize
);
2302 wxLayoutList::Draw(wxDC
&dc
,
2303 wxPoint
const &offset
,
2308 wxLayoutLine
*line
= m_FirstLine
;
2310 if ( m_Selection
.m_discarded
)
2312 // calculate them if we don't have them already
2313 if ( !m_Selection
.HasValidScreenCoords() )
2315 m_Selection
.m_ScreenA
= GetScreenPos(dc
, m_Selection
.m_CursorA
);
2316 m_Selection
.m_ScreenB
= GetScreenPos(dc
, m_Selection
.m_CursorB
);
2319 // invalidate the area which was previousle selected - and which is not
2320 // selected any more
2321 SetUpdateRect(m_Selection
.m_ScreenA
);
2322 SetUpdateRect(m_Selection
.m_ScreenB
);
2324 m_Selection
.m_discarded
= false;
2327 /* This call to Layout() will re-calculate and update all lines
2332 ApplyStyle(m_DefaultStyleInfo
, dc
);
2333 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2335 dc
.SetBackgroundMode(wxTRANSPARENT
);
2339 // only draw if between top and bottom:
2341 line
->GetPosition().y
+ line
->GetHeight() > top
))
2343 ApplyStyle(line
->GetStyleInfo(), dc
);
2344 // little condition to speed up redrawing:
2346 && line
->GetPosition().y
2347 +(clipStrictly
? line
->GetHeight() : 0) >= bottom
)
2349 line
->Draw(dc
, this, offset
);
2351 line
= line
->GetNextLine();
2353 InvalidateUpdateRect();
2356 if ( m_Selection
.m_valid
)
2358 WXLO_DEBUG(("Selection is %s : %ld,%ld/%ld,%ld",
2359 m_Selection
.m_valid
? "valid" : "invalid",
2360 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2361 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2367 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2371 // First, find the right line:
2373 *line
= m_FirstLine
,
2374 *lastline
= m_FirstLine
;
2377 ApplyStyle(m_DefaultStyleInfo
, dc
);
2380 p
= line
->GetPosition();
2381 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2384 line
= line
->GetNextLine();
2387 bool didFind
= line
!= NULL
;
2391 // use the last line:
2396 cursorPos
->y
= line
->GetLineNumber();
2398 bool foundinline
= true;
2401 // Now, find the object in the line:
2406 i
= line
->FindObjectScreen(dc
, this,
2413 i
= line
->FindObjectScreen(dc
, this,
2418 *found
= didFind
&& foundinline
;
2420 return (i
== NULLIT
) ? NULL
: *i
;
2425 wxLayoutList::GetSize(void) const
2428 *line
= m_FirstLine
,
2431 return wxPoint(0,0);
2433 wxPoint
maxPoint(0,0);
2438 if(line
->GetWidth() > maxPoint
.x
)
2439 maxPoint
.x
= line
->GetWidth();
2441 line
= line
->GetNextLine();
2444 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2446 // if the line was just added, its height would be 0 and we can't call
2447 // Layout() from here because we don't have a dc and we might be not drawing
2448 // at all, besides... So take the cursor height by default (taking 0 is bad
2449 // because then the scrollbars won't be resized and the new line won't be
2451 if ( last
->IsDirty() )
2453 if ( last
->GetHeight() == 0 )
2454 maxPoint
.y
+= m_CursorSize
.y
;
2455 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2456 maxPoint
.x
= m_CursorSize
.x
;
2464 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2466 if ( m_movedCursor
)
2467 m_movedCursor
= false;
2469 wxPoint
coords(m_CursorScreenPos
);
2470 coords
+= translate
;
2472 #ifdef WXLAYOUT_DEBUG
2473 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2474 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2475 (long)coords
.x
, (long)coords
.y
,
2476 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2477 (long)m_CursorLine
->GetLineNumber(),
2478 (long)m_CursorLine
->GetLength()));
2480 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2483 #ifdef WXLAYOUT_USE_CARET
2484 m_caret
->Move(coords
);
2485 #else // !WXLAYOUT_USE_CARET
2487 wxASSERT(m_CursorSize
.x
>= WXLO_MINIMUM_CURSOR_WIDTH
);
2488 dc
.SetBrush(*wxWHITE_BRUSH
);
2489 //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
2490 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2493 dc
.SetLogicalFunction(wxXOR
);
2494 dc
.DrawRectangle(coords
.x
, coords
.y
,
2495 m_CursorSize
.x
, m_CursorSize
.y
);
2496 SetUpdateRect(coords
.x
, coords
.y
);
2497 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2501 dc
.SetLogicalFunction(wxCOPY
);
2502 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2503 coords
.x
, coords
.y
);
2504 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2505 SetUpdateRect(coords
.x
, coords
.y
);
2507 dc
.SetLogicalFunction(wxCOPY
);
2508 //dc.SetBrush(wxNullBrush);
2509 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2513 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2515 if(m_UpdateRectValid
)
2516 GrowRect(m_UpdateRect
, x
, y
);
2521 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2522 m_UpdateRect
.height
= 4;// wxGTK :-)
2523 m_UpdateRectValid
= true;
2528 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2530 wxPoint
cpos(cposOrig
);
2533 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2534 m_Selection
.m_CursorA
= cpos
;
2535 m_Selection
.m_CursorB
= cpos
;
2536 m_Selection
.m_ScreenA
= spos
;
2537 m_Selection
.m_ScreenB
= spos
;
2538 m_Selection
.m_selecting
= true;
2539 m_Selection
.m_valid
= false;
2543 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2545 wxPoint
cpos(cposOrig
);
2549 wxASSERT(m_Selection
.m_selecting
== true);
2550 wxASSERT(m_Selection
.m_valid
== false);
2551 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2553 m_Selection
.m_ScreenB
= spos
;
2554 m_Selection
.m_CursorB
= cpos
;
2558 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2560 wxPoint
cpos(cposOrig
);
2561 if(cpos
.x
== -1) cpos
= m_CursorPos
;
2562 ContinueSelection(cpos
, spos
);
2563 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2564 // we always want m_CursorA <= m_CursorB!
2565 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2567 // exchange the start/end points
2568 wxPoint help
= m_Selection
.m_CursorB
;
2569 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2570 m_Selection
.m_CursorA
= help
;
2572 help
= m_Selection
.m_ScreenB
;
2573 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2574 m_Selection
.m_ScreenA
= help
;
2576 m_Selection
.m_selecting
= false;
2577 m_Selection
.m_valid
= true;
2578 /// In case we just clicked somewhere, the selection will have zero
2579 /// size, so we discard it immediately.
2580 if(m_Selection
.m_CursorA
== m_Selection
.m_CursorB
)
2585 wxLayoutList::DiscardSelection()
2587 if ( !HasSelection() )
2590 m_Selection
.m_valid
=
2591 m_Selection
.m_selecting
= false;
2592 m_Selection
.m_discarded
= true;
2596 wxLayoutList::IsSelecting(void) const
2598 return m_Selection
.m_selecting
;
2602 wxLayoutList::IsSelected(const wxPoint
&cursor
) const
2604 if ( !HasSelection() )
2608 (m_Selection
.m_CursorA
<= cursor
2609 && cursor
<= m_Selection
.m_CursorB
)
2610 || (m_Selection
.m_CursorB
<= cursor
2611 && cursor
<= m_Selection
.m_CursorA
)
2616 /** Tests whether this layout line is selected and needs
2618 @param line to test for
2619 @return 0 = not selected, 1 = fully selected, -1 = partially
2623 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2626 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2628 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2631 CoordType y
= line
->GetLineNumber();
2633 (m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2634 || (m_Selection
.m_CursorB
.y
< y
&& m_Selection
.m_CursorA
.y
> y
)
2637 else if(m_Selection
.m_CursorA
.y
== y
)
2639 *from
= m_Selection
.m_CursorA
.x
;
2640 if(m_Selection
.m_CursorB
.y
== y
)
2641 *to
= m_Selection
.m_CursorB
.x
;
2644 if(m_Selection
.m_CursorB
> m_Selection
.m_CursorA
)
2645 *to
= line
->GetLength();
2651 CoordType help
= *to
;
2657 else if(m_Selection
.m_CursorB
.y
== y
)
2659 *to
= m_Selection
.m_CursorB
.x
;
2660 if(m_Selection
.m_CursorA
.y
== y
)
2661 *from
= m_Selection
.m_CursorA
.x
;
2664 if(m_Selection
.m_CursorB
> m_Selection
.m_CursorA
)
2667 *from
= line
->GetLength();
2671 CoordType help
= *to
;
2682 wxLayoutList::DeleteSelection(void)
2684 if(! m_Selection
.m_valid
)
2687 m_Selection
.m_valid
= false;
2689 // Only delete part of the current line?
2690 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2692 MoveCursorTo(m_Selection
.m_CursorA
);
2693 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2697 // We now know that the two lines are different:
2700 * firstLine
= GetLine(m_Selection
.m_CursorA
.y
),
2701 * lastLine
= GetLine(m_Selection
.m_CursorB
.y
);
2702 // be a bit paranoid:
2703 if(! firstLine
|| ! lastLine
)
2706 // First, delete what's left of this line:
2707 MoveCursorTo(m_Selection
.m_CursorA
);
2708 DeleteToEndOfLine();
2710 wxLayoutLine
*prevLine
= firstLine
->GetPreviousLine(),
2711 *nextLine
= firstLine
->GetNextLine();
2712 while(nextLine
&& nextLine
!= lastLine
)
2713 nextLine
= nextLine
->DeleteLine(false, this);
2715 // Now nextLine = lastLine;
2716 Delete(1); // This joins firstLine and nextLine
2717 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x positions
2719 // Recalculate the line positions and numbers but notice that firstLine
2720 // might not exist any more - it could be deleted by Delete(1) above
2721 wxLayoutLine
*firstLine2
= prevLine
? prevLine
->GetNextLine() : m_FirstLine
;
2722 firstLine2
->MarkDirty();
2725 /// Starts highlighting the selection
2727 wxLayoutList::StartHighlighting(wxDC
&dc
)
2730 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2731 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2732 dc
.SetBackgroundMode(wxSOLID
);
2736 /// Ends highlighting the selection
2738 wxLayoutList::EndHighlighting(wxDC
&dc
)
2741 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2742 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2743 dc
.SetBackgroundMode(wxTRANSPARENT
);
2749 wxLayoutList::GetLine(CoordType index
) const
2751 wxASSERT_MSG( (0 <= index
) && (index
< (CoordType
)m_numLines
),
2755 CoordType n
= index
;
2757 CoordType lineNo
= 0;
2760 for ( line
= m_FirstLine
; line
&& n
-- > 0; line
=
2761 line
->GetNextLine() )
2764 wxASSERT(line
->GetLineNumber() == lineNo
);
2771 // should be the right one
2772 wxASSERT( line
->GetLineNumber() == index
);
2780 wxLayoutList::Copy(const wxPoint
&from
,
2787 for(firstLine
= m_FirstLine
;
2788 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2789 firstLine
=firstLine
->GetNextLine())
2791 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2794 for(lastLine
= m_FirstLine
;
2795 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2796 lastLine
=lastLine
->GetNextLine())
2798 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2803 wxLayoutLine
*tmp
= firstLine
;
2804 firstLine
= lastLine
;
2808 wxLayoutList
*llist
= new wxLayoutList();
2810 if(firstLine
== lastLine
)
2812 firstLine
->Copy(llist
, from
.x
, to
.x
);
2816 // Extract objects from first line
2817 firstLine
->Copy(llist
, from
.x
);
2819 // Extract all lines between
2820 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2822 line
= line
->GetNextLine())
2827 // Extract objects from last line
2828 lastLine
->Copy(llist
, 0, to
.x
);
2834 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2836 if(! m_Selection
.m_valid
)
2838 if(m_Selection
.m_selecting
)
2844 if(invalidate
) m_Selection
.m_valid
= false;
2846 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2847 m_Selection
.m_CursorB
);
2849 if(llist
&& wxlo
) // export as data object, too
2853 wxLayoutExportObject
*exp
;
2854 wxLayoutExportStatus
status(llist
);
2855 while((exp
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2857 if(exp
->type
== WXLO_EXPORT_EMPTYLINE
)
2858 ; //FIXME missing support for linebreaks in string format
2860 exp
->content
.object
->Write(string
);
2864 wxlo
->SetLayoutData(string
);
2871 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2874 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2876 bool fontChanged
= FALSE
;
2883 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2887 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2888 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2892 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2893 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2898 #ifdef WXLAYOUT_DEBUG
2901 wxLayoutList::Debug(void)
2903 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2904 m_CursorLine
->GetLineNumber(),
2905 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2908 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2917 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2921 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2923 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2924 wxString
const & title
)
2929 // remove any highlighting which could interfere with printing:
2930 m_llist
->StartSelection();
2931 m_llist
->EndSelection();
2932 // force a full layout of the list:
2933 m_llist
->ForceTotalLayout();
2934 // layout is called in ScaleDC() when we have a DC
2937 wxLayoutPrintout::~wxLayoutPrintout()
2942 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2944 // The following bit is taken from the printing sample, let's see
2945 // whether it works for us.
2947 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2948 * the screen text size. This page also draws lines of actual length 5cm
2951 // Get the logical pixels per inch of screen and printer
2952 int ppiScreenX
, ppiScreenY
;
2953 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2954 int ppiPrinterX
, ppiPrinterY
;
2955 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2957 if(ppiScreenX
== 0) // not yet set, need to guess
2962 if(ppiPrinterX
== 0) // not yet set, need to guess
2968 // This scales the DC so that the printout roughly represents the
2969 // the screen scaling. The text point size _should_ be the right size
2970 // but in fact is too small for some reason. This is a detail that will
2971 // need to be addressed at some point but can be fudged for the
2973 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2975 // Now we have to check in case our real page size is reduced
2976 // (e.g. because we're drawing to a print preview memory DC)
2977 int pageWidth
, pageHeight
;
2979 dc
->GetSize(&w
, &h
);
2980 GetPageSizePixels(&pageWidth
, &pageHeight
);
2981 if(pageWidth
!= 0) // doesn't work always
2983 // If printer pageWidth == current DC width, then this doesn't
2984 // change. But w might be the preview bitmap width, so scale down.
2985 scale
= scale
* (float)(w
/(float)pageWidth
);
2987 dc
->SetUserScale(scale
, scale
);
2991 bool wxLayoutPrintout::OnPrintPage(int page
)
3000 top
= (page
- 1)*m_PrintoutHeight
;
3001 bottom
= top
+ m_PrintoutHeight
;
3003 WXLO_DEBUG(("OnPrintPage(%d) printing from %d to %d", page
, top
,
3005 // SetDeviceOrigin() doesn't work here, so we need to manually
3006 // translate all coordinates.
3007 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
3008 m_llist
->Draw(*dc
, translate
, top
, bottom
, TRUE
/* clip strictly
3016 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
3018 /* We allocate a temporary wxDC for printing, so that we can
3019 determine the correct paper size and scaling. We don't actually
3020 print anything on it. */
3022 wxPrinterDC
*psdc
= new wxPrinterDC("","",WXLLIST_TEMPFILE
,false);
3024 wxPostScriptDC
*psdc
= new wxPostScriptDC(WXLLIST_TEMPFILE
,false);
3027 psdc
->StartDoc(m_title
);
3028 // before we draw anything, me must make sure the list is properly
3030 m_llist
->Layout(*psdc
);
3032 float scale
= ScaleDC(psdc
);
3034 psdc
->GetSize(&m_PageWidth
, &m_PageHeight
);
3036 // This sets a left/top origin of 15% and 5%:
3037 m_Offset
= wxPoint((15*m_PageWidth
)/100, (5*m_PageHeight
)/100);
3039 // This is the length of the printable area.
3040 m_PrintoutHeight
= m_PageHeight
- 2*m_Offset
.y
;
3041 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
3044 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
3047 *maxPage
= m_NumOfPages
;
3050 *selPageTo
= m_NumOfPages
;
3053 wxRemoveFile(WXLLIST_TEMPFILE
);
3056 bool wxLayoutPrintout::HasPage(int pageNum
)
3058 return pageNum
<= m_NumOfPages
;
3062 Stupid wxWindows doesn't draw proper ellipses, so we comment this
3063 out. It's a waste of paper anyway.
3067 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
3068 wxPoint topleft
, wxPoint bottomright
,
3071 // make backups of all essential parameters
3072 const wxBrush
& brush
= dc
.GetBrush();
3073 const wxPen
& pen
= dc
.GetPen();
3074 const wxFont
& font
= dc
.GetFont();
3076 dc
.SetBrush(*wxWHITE_BRUSH
);
3077 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
3078 dc
.DrawRoundedRectangle(topleft
.x
,
3079 topleft
.y
,bottomright
.x
-topleft
.x
,
3080 bottomright
.y
-topleft
.y
);
3081 dc
.SetBrush(*wxBLACK_BRUSH
);
3082 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
3083 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
3087 page
= "9999/9999 "; // many pages...
3089 dc
.GetTextExtent(page
,&w
,&h
);
3090 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
3091 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
3092 dc
.GetTextExtent("XXXX", &w
,&h
);
3093 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
3104 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
3107 for(wxFCEList::iterator i
= m_FontList
.begin();
3108 i
!= m_FontList
.end(); i
++)
3109 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
3110 return (**i
).GetFont();
3112 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
3114 m_FontList
.push_back(fce
);
3115 return fce
->GetFont();