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_bg_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
);
646 m_StyleInfo
= llist
->GetDefaultStyleInfo();
649 wxLayoutLine::~wxLayoutLine()
651 // kbList cleans itself
655 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
657 wxASSERT(m_Previous
|| GetLineNumber() == 0);
659 wxPoint
posOld(m_Position
);
663 m_Position
= m_Previous
->GetPosition();
664 m_Position
.y
+= m_Previous
->GetHeight();
667 m_Position
= wxPoint(0,0);
669 if ( m_Position
!= posOld
)
671 // the whole line moved and must be repainted
672 llist
->SetUpdateRect(m_Position
);
673 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
674 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
675 llist
->SetUpdateRect(posOld
);
676 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
677 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
684 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
686 //FIXME: is this really needed? We run Layout() anyway.
687 // Recursing here, drives computation time up exponentially, as
688 // each line will cause all following lines to be recalculated.
689 // Yes, or linenumbers go wrong.
691 wxASSERT(recurse
>= 0);
692 wxPoint pos
= m_Position
;
693 CoordType height
= m_Height
;
695 // WXLO_TRACE("RecalculatePositions()");
696 RecalculatePosition(llist
);
700 m_Next
->RecalculatePositions(--recurse
, llist
);
701 else if(pos
!= m_Position
|| m_Height
!= height
)
702 m_Next
->RecalculatePositions(0, llist
);
706 wxLayoutObjectList::iterator
707 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
711 wxLayoutObjectList::iterator
714 CoordType x
= 0, len
;
716 /* We search through the objects. As we don't like returning the
717 object that the cursor is behind, we just remember such an
718 object in "found" so we can return it if there is really no
719 further object following it. */
720 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
722 len
= (**i
).GetLength();
723 if( x
<= xpos
&& xpos
<= x
+ len
)
726 if(xpos
== x
+ len
) // is there another object behind?
728 else // we are really inside this object
731 x
+= (**i
).GetLength();
733 return found
; // ==NULL if really none found
736 wxLayoutObjectList::iterator
737 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
738 CoordType xpos
, CoordType
*cxpos
,
743 wxLayoutObjectList::iterator i
;
744 CoordType x
= 0, cx
= 0, width
;
746 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
748 width
= (**i
).GetWidth();
749 if( x
<= xpos
&& xpos
<= x
+ width
)
751 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
752 if(found
) *found
= true;
755 x
+= (**i
).GetWidth();
756 cx
+= (**i
).GetLength();
758 // behind last object:
760 if(found
) *found
= false;
761 return m_ObjectList
.tail();
764 /** Finds text in this line.
765 @param needle the text to find
766 @param xpos the position where to start the search
767 @return the cursoor coord where it was found or -1
770 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
775 wxString
const *text
;
777 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
779 if(cpos
>= xpos
) // search from here!
781 if((**i
).GetType() == WXLO_TYPE_TEXT
)
783 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
784 relpos
= text
->Find(needle
);
785 if(relpos
>= cpos
-xpos
) // -1 if not found
790 cpos
+= (**i
).GetLength();
793 return -1; // not found
797 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
800 wxASSERT(obj
!= NULL
);
804 // If we insert a command object, we need to recalculate all lines
805 // to update their styleinfo structure.
806 if(obj
->GetType() == WXLO_TYPE_CMD
)
810 wxLOiterator i
= FindObject(xpos
, &offset
);
813 if(xpos
== 0 ) // aha, empty line!
815 m_ObjectList
.push_back(obj
);
816 m_Length
+= obj
->GetLength();
823 CoordType len
= (**i
).GetLength();
824 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
825 { // insert before this object
826 m_ObjectList
.insert(i
,obj
);
827 m_Length
+= obj
->GetLength();
832 if( i
== m_ObjectList
.tail()) // last object?
833 m_ObjectList
.push_back(obj
);
835 { // insert after current object
837 m_ObjectList
.insert(i
,obj
);
839 m_Length
+= obj
->GetLength();
842 /* Otherwise we need to split the current object.
843 Fortunately this can only be a text object. */
844 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
845 wxString left
, right
;
846 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
847 left
= tobj
->GetText().substr(0,offset
);
848 right
= tobj
->GetText().substr(offset
,len
-offset
);
849 // current text object gets set to right half
850 tobj
->GetText() = right
; // set new text
851 // before it we insert the new object
852 m_ObjectList
.insert(i
,obj
);
853 m_Length
+= obj
->GetLength();
854 // and before that we insert the left half
855 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
860 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
867 wxLOiterator i
= FindObject(xpos
, &offset
);
868 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
870 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
871 tobj
->GetText().insert(offset
, text
);
872 m_Length
+= text
.Length();
876 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
884 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
886 CoordType offset
, len
;
891 wxLOiterator i
= FindObject(xpos
, &offset
);
894 if(i
== NULLIT
) return npos
;
895 // now delete from that object:
896 if((**i
).GetType() != WXLO_TYPE_TEXT
)
898 if(offset
!= 0) // at end of line after a non-text object
901 len
= (**i
).GetLength();
904 // If we delete a command object, we need to recalculate all lines
905 // to update their styleinfo structure.
906 if((**i
).GetType() == WXLO_TYPE_CMD
)
908 m_ObjectList
.erase(i
);
912 // tidy up: remove empty text objects
913 if((**i
).GetLength() == 0)
915 m_ObjectList
.erase(i
);
919 CoordType max
= (**i
).GetLength() - offset
;
920 if(npos
< max
) max
= npos
;
923 if(xpos
== GetLength())
926 { // at the end of an object
927 // move to begin of next object:
929 continue; // start over
934 if(offset
== 0 && max
== (**i
).GetLength())
935 m_ObjectList
.erase(i
); // remove the whole object
937 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
945 wxLayoutLine::MarkNextDirty(int recurse
)
947 wxLayoutLine
*line
= GetNextLine();
948 while(line
&& (recurse
== -1 || recurse
>= 0))
951 line
= line
->GetNextLine();
952 if(recurse
> 0) recurse
--;
957 wxLayoutLine::DeleteWord(CoordType xpos
)
963 wxLOiterator i
= FindObject(xpos
, &offset
);
967 if(i
== NULLIT
) return false;
968 if((**i
).GetType() != WXLO_TYPE_TEXT
)
970 // This should only happen when at end of line, behind a non-text
972 if(offset
== (**i
).GetLength()) return false;
973 m_Length
-= (**i
).GetLength(); // -1
974 m_ObjectList
.erase(i
);
975 return true; // we are done
979 if(offset
== (**i
).GetLength()) // at end of object
984 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
986 wxString str
= tobj
->GetText();
987 str
= str
.substr(offset
,str
.Length()-offset
);
988 // Find out how many positions we need to delete:
989 // 1. eat leading space
990 while(isspace(str
.c_str()[count
])) count
++;
991 // 2. eat the word itself:
992 while(isalnum(str
.c_str()[count
])) count
++;
994 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
995 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
1001 wxFAIL_MSG("unreachable");
1005 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1007 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
1008 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
1011 m_Next
->MoveLines(-1);
1012 m_Next
->RecalculatePositions(1, llist
);
1013 /* We assume that if we have more than one object in the list,
1014 this means that we have a command object, so we need to
1015 update the following lines. */
1016 if(m_ObjectList
.size() > 1 ||
1017 ( m_ObjectList
.begin() != NULLIT
&&
1018 (**m_ObjectList
.begin()).GetType() == WXLO_TYPE_CMD
)
1022 wxLayoutLine
*next
= m_Next
;
1028 wxLayoutLine::Draw(wxDC
&dc
,
1029 wxLayoutList
*llist
,
1030 const wxPoint
& offset
) const
1032 wxLayoutObjectList::iterator i
;
1033 wxPoint pos
= offset
;
1034 pos
= pos
+ GetPosition();
1036 pos
.y
+= m_BaseLine
;
1038 CoordType xpos
= 0; // cursorpos, lenght of line
1040 CoordType from
, to
, tempto
;
1042 int highlight
= llist
->IsSelected(this, &from
, &to
);
1043 // WXLO_DEBUG(("highlight=%d", highlight ));
1044 if(highlight
== 1) // we need to draw the whole line inverted!
1045 llist
->StartHighlighting(dc
);
1047 llist
->EndHighlighting(dc
);
1049 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1051 if(highlight
== -1) // partially highlight line
1053 // parts of the line need highlighting
1054 tempto
= xpos
+(**i
).GetLength();
1055 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1058 (**i
).Draw(dc
, pos
, llist
);
1059 pos
.x
+= (**i
).GetWidth();
1060 xpos
+= (**i
).GetLength();
1065 This function does all the recalculation, that is, it should only be
1066 called from within wxLayoutList::Layout(), as it uses the current
1067 list's styleinfo and updates it.
1070 wxLayoutLine::Layout(wxDC
&dc
,
1071 wxLayoutList
*llist
,
1073 wxPoint
*cursorSize
,
1074 wxLayoutStyleInfo
*cursorStyle
,
1076 bool suppressSIupdate
)
1078 wxLayoutObjectList::iterator i
;
1080 // when a line becomes dirty, we redraw it from the place where it was
1081 // changed till the end of line (because the following wxLayoutObjects are
1082 // moved when the preceding one changes) - calculate the update rectangle.
1083 CoordType updateTop
= m_Position
.y
,
1085 updateWidth
= m_Width
,
1086 updateHeight
= m_Height
;
1090 bottomHeight
= 0; // above and below baseline
1092 objTopHeight
, objBottomHeight
; // above and below baseline
1096 CoordType heightOld
= m_Height
;
1102 bool cursorFound
= false;
1106 *cursorPos
= m_Position
;
1107 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1110 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1111 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1113 wxLayoutObject
*obj
= *i
;
1114 obj
->Layout(dc
, llist
);
1115 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1117 if(cursorPos
&& ! cursorFound
)
1119 // we need to check whether the text cursor is here
1120 len
= obj
->GetLength();
1121 if(count
<= cx
&& count
+len
> cx
)
1123 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1125 len
= cx
- count
; // pos in object
1126 CoordType width
, height
, descent
;
1127 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1128 &width
, &height
, &descent
);
1129 cursorPos
->x
+= width
;
1130 cursorPos
->y
= m_Position
.y
;
1132 if(len
< obj
->GetLength())
1133 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1135 str
= WXLO_CURSORCHAR
;
1136 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1138 if(cursorStyle
) // set style info
1139 *cursorStyle
= llist
->GetStyleInfo();
1142 // Just in case some joker inserted an empty string object:
1144 width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1147 cursorSize
->x
= width
;
1148 cursorSize
->y
= height
;
1151 cursorFound
= true; // no more checks
1155 // on some other object
1156 CoordType top
, bottom
; // unused
1158 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1159 cursorPos
->y
= m_Position
.y
;
1160 cursorFound
= true; // no more checks
1166 cursorPos
->x
+= obj
->GetWidth();
1170 m_Width
+= sizeObj
.x
;
1171 if(sizeObj
.y
> m_Height
)
1173 m_Height
= sizeObj
.y
;
1176 if(objTopHeight
> topHeight
)
1177 topHeight
= objTopHeight
;
1178 if(objBottomHeight
> bottomHeight
)
1179 bottomHeight
= objBottomHeight
;
1184 if ( updateHeight
< m_Height
)
1185 updateHeight
= m_Height
;
1186 if ( updateWidth
< m_Width
)
1187 updateWidth
= m_Width
;
1189 // update all line if we don't know where to start from
1190 if ( updateLeft
== -1 )
1193 llist
->SetUpdateRect(updateLeft
, updateTop
);
1194 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1195 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1198 if(topHeight
+ bottomHeight
> m_Height
)
1200 m_Height
= topHeight
+bottomHeight
;
1203 m_BaseLine
= topHeight
;
1207 CoordType width
, height
, descent
;
1208 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1210 m_BaseLine
= m_Height
- descent
;
1213 // tell next line about coordinate change
1214 if(m_Next
&& m_Height
!= heightOld
)
1216 // FIXME isn't this done in RecalculatePositions() below anyhow?
1217 m_Next
->RecalculatePositions(0, llist
);
1220 // We need to check whether we found a valid cursor size:
1221 if(cursorPos
&& cursorSize
)
1223 // this might be the case if the cursor is at the end of the
1224 // line or on a command object:
1225 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1227 CoordType width
, height
, descent
;
1228 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1229 cursorSize
->x
= width
;
1230 cursorSize
->y
= height
;
1232 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1233 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1235 RecalculatePositions(1, llist
);
1241 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1243 wxASSERT(xpos
>= 0);
1247 /* If we are at the begin of a line, we want to move all other
1248 lines down and stay with the cursor where we are. However, if we
1249 are in an empty line, we want to move down with it. */
1250 if(xpos
== 0 && GetLength() > 0)
1251 { // insert an empty line before this one
1252 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1253 if(m_Previous
== NULL
)
1254 { // We were in first line, need to link in new empty line
1256 prev
->m_Next
= this;
1258 m_Previous
->m_Height
= 0; // this is a wild guess
1261 m_Next
->RecalculatePositions(1, llist
);
1266 wxLOiterator i
= FindObject(xpos
, &offset
);
1268 // must be at the end of the line then
1269 return new wxLayoutLine(this, llist
);
1272 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1273 // split object at i:
1274 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1276 wxString left
, right
;
1277 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1278 left
= tobj
->GetText().substr(0,offset
);
1279 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1280 // current text object gets set to left half
1281 tobj
->GetText() = left
; // set new text
1282 newLine
->Append(new wxLayoutObjectText(right
));
1283 m_Length
-= right
.Length();
1284 i
++; // don't move this object to the new list
1289 i
++; // move objects from here to new list
1292 while(i
!= m_ObjectList
.end())
1294 wxLayoutObject
*obj
= *i
;
1295 newLine
->Append(obj
);
1296 m_Length
-= obj
->GetLength();
1298 m_ObjectList
.remove(i
); // remove without deleting it
1301 m_Next
->RecalculatePositions(2, llist
);
1307 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1309 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1310 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1313 MarkDirty(GetWidth());
1315 wxLayoutObject
*last
= NULL
;
1316 for(i
= list
.begin(); i
!= list
.end();)
1318 wxLayoutObject
*current
= *i
;
1320 // merge text objects together for efficiency
1321 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1322 current
->GetType() == WXLO_TYPE_TEXT
)
1324 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1325 wxString
text(textObj
->GetText());
1326 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1327 textObj
->SetText(text
);
1329 list
.erase(i
); // remove and delete it
1333 // just append the object "as was"
1336 list
.remove(i
); // remove without deleting it
1339 wxASSERT(list
.empty());
1341 wxLayoutLine
*oldnext
= GetNextLine();
1342 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1346 nextLine
->MoveLines(-1);
1350 // this is now done in Delete(), but if this function is ever called
1351 // from elsewhere, we might have to move refresh code back here (in
1352 // order not to duplicate it)
1354 wxPoint
pos(oldnext
->GetPosition());
1355 llist
->SetUpdateRect(pos
);
1356 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1357 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1365 wxLayoutLine::GetWrapPosition(CoordType column
)
1368 wxLOiterator i
= FindObject(column
, &offset
);
1369 if(i
== NULLIT
) return -1; // cannot wrap
1371 // go backwards through the list and look for space in text objects
1374 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1378 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1385 }while(offset
!= -1);
1386 i
--; // move on to previous object
1390 column
-= (**i
).GetLength();
1394 offset
= (**i
).GetLength();
1395 }while(i
!= NULLIT
);
1396 /* If we reached the begin of the list and have more than one
1397 object, that one is longer than the margin, so break behind
1400 i
= m_ObjectList
.begin();
1401 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1403 pos
+= (**i
).GetLength();
1406 if(i
== NULLIT
) return -1; //why should this happen?
1407 pos
+= (**i
).GetLength();
1409 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1411 pos
+= (**i
).GetLength();
1414 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1415 // now we are at the second text object:
1416 pos
-= (**i
).GetLength();
1417 return pos
; // in front of it
1421 #ifdef WXLAYOUT_DEBUG
1423 wxLayoutLine::Debug(void)
1426 wxPoint pos
= GetPosition();
1427 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1428 (long int) GetLineNumber(),
1429 (long int) pos
.x
, (long int) pos
.y
,
1430 (long int) GetHeight(),
1431 (long int) m_BaseLine
,
1432 (int) m_StyleInfo
.family
));
1433 if(m_ObjectList
.begin() != NULLIT
)
1434 (**m_ObjectList
.begin()).Debug();
1440 wxLayoutLine::Copy(wxLayoutList
*llist
,
1444 CoordType firstOffset
, lastOffset
;
1446 if(to
== -1) to
= GetLength();
1447 if(from
== to
) return;
1449 wxLOiterator first
= FindObject(from
, &firstOffset
);
1450 wxLOiterator last
= FindObject(to
, &lastOffset
);
1452 // Common special case: only one object
1453 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1455 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1457 llist
->Insert(new wxLayoutObjectText(
1458 ((wxLayoutObjectText
1459 *)*first
)->GetText().substr(firstOffset
,
1460 lastOffset
-firstOffset
))
1464 else // what can we do?
1466 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1467 llist
->Insert( (**first
).Copy() );
1472 // If we reach here, we can safely copy the whole first object from
1473 // the firstOffset position on:
1474 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1476 llist
->Insert(new wxLayoutObjectText(
1477 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1480 else if(firstOffset
== 0)
1481 llist
->Insert( (**first
).Copy() );
1482 // else nothing to copy :-(
1484 // Now we copy all objects before the last one:
1485 wxLOiterator i
= first
; i
++;
1486 for( ; i
!= last
; i
++)
1487 llist
->Insert( (**i
).Copy() );
1489 // And now the last object:
1492 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1494 llist
->Insert(new wxLayoutObjectText(
1495 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1499 llist
->Insert( (**last
).Copy() );
1504 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1506 The wxLayoutList object
1508 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1510 wxLayoutList::wxLayoutList()
1512 #ifdef WXLAYOUT_USE_CARET
1514 #endif // WXLAYOUT_USE_CARET
1517 InvalidateUpdateRect();
1521 wxLayoutList::~wxLayoutList()
1524 m_FirstLine
->DeleteLine(false, this);
1528 wxLayoutList::Empty(void)
1531 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1533 m_CursorPos
= wxPoint(0,0);
1534 m_CursorScreenPos
= wxPoint(0,0);
1535 m_CursorSize
= wxPoint(0,0);
1536 m_movedCursor
= true;
1537 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1538 m_CursorLine
= m_FirstLine
;
1539 InvalidateUpdateRect();
1544 wxLayoutList::InternalClear(void)
1547 m_Selection
.m_selecting
= false;
1548 m_Selection
.m_valid
= false;
1550 m_DefaultStyleInfo
.family
= wxSWISS
;
1551 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1552 m_DefaultStyleInfo
.style
= wxNORMAL
;
1553 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1554 m_DefaultStyleInfo
.underline
= 0;
1555 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1556 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1557 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1558 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1560 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1561 m_CursorStyleInfo
= m_DefaultStyleInfo
;
1565 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1566 int underline
, wxColour
*fg
,
1569 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1570 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1571 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1572 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1573 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1574 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1575 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1577 new wxLayoutObjectCmd(
1578 m_CurrentStyleInfo
.family
,
1579 m_CurrentStyleInfo
.size
,
1580 m_CurrentStyleInfo
.style
,
1581 m_CurrentStyleInfo
.weight
,
1582 m_CurrentStyleInfo
.underline
,
1587 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1588 int underline
, char const *fg
, char const *bg
)
1596 cfg
= wxTheColourDatabase
->FindColour(fg
);
1598 cbg
= wxTheColourDatabase
->FindColour(bg
);
1600 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1604 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1605 int underline
, wxColour
*fg
, wxColour
*bg
)
1608 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1610 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1614 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1619 for(line
= m_FirstLine
;
1621 line
= line
->GetNextLine())
1623 if(line
->GetLineNumber() >= cpos
.y
)
1625 xpos
= line
->FindText(needle
,
1626 (line
->GetLineNumber() == cpos
.y
) ?
1629 return wxPoint(xpos
, line
->GetLineNumber());
1632 return wxPoint(-1,-1);
1637 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1639 AddCursorPosToUpdateRect();
1641 wxPoint cursorPosOld
= m_CursorPos
;
1643 wxLayoutLine
*line
= m_FirstLine
;
1644 while(line
&& line
->GetLineNumber() != p
.y
)
1645 line
= line
->GetNextLine();
1646 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1648 m_CursorPos
.y
= p
.y
;
1649 m_CursorLine
= line
;
1650 CoordType len
= line
->GetLength();
1653 m_CursorPos
.x
= p
.x
;
1657 m_CursorPos
.x
= len
;
1661 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1663 return m_CursorPos
== p
;
1667 wxLayoutList::MoveCursorVertically(int n
)
1669 AddCursorPosToUpdateRect();
1671 wxPoint cursorPosOld
= m_CursorPos
;
1674 if(n
< 0) // move up
1676 if(m_CursorLine
== m_FirstLine
) return false;
1677 while(n
< 0 && m_CursorLine
)
1679 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1685 m_CursorLine
= m_FirstLine
;
1691 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1692 m_CursorPos
.x
= m_CursorLine
->GetLength();
1698 wxLayoutLine
*last
= m_CursorLine
;
1699 if(! m_CursorLine
->GetNextLine()) return false;
1700 while(n
> 0 && m_CursorLine
)
1704 m_CursorLine
= m_CursorLine
->GetNextLine();
1708 m_CursorLine
= last
;
1714 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1715 m_CursorPos
.x
= m_CursorLine
->GetLength();
1720 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1726 wxLayoutList::MoveCursorHorizontally(int n
)
1728 AddCursorPosToUpdateRect();
1730 wxPoint cursorPosOld
= m_CursorPos
;
1735 if(m_CursorPos
.x
== 0) // at begin of line
1737 if(! MoveCursorVertically(-1))
1739 MoveCursorToEndOfLine();
1744 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1745 m_CursorPos
.x
-= move
; n
+= move
;
1750 int len
= m_CursorLine
->GetLength();
1751 if(m_CursorPos
.x
== len
) // at end of line
1753 if(! MoveCursorVertically(1))
1755 MoveCursorToBeginOfLine();
1760 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1761 m_CursorPos
.x
+= move
;
1765 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1771 wxLayoutList::MoveCursorWord(int n
, bool untilNext
)
1773 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1774 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1776 CoordType moveDistance
= 0;
1778 for ( wxLOiterator i
= m_CursorLine
->FindObject(m_CursorPos
.x
, &offset
);
1785 wxLayoutObject
*obj
= *i
;
1786 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1788 // any visible non text objects count as one word
1789 if ( obj
->IsVisibleObject() )
1793 moveDistance
+= obj
->GetLength();
1798 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1800 bool canAdvance
= true;
1802 if ( offset
== tobj
->GetLength() )
1807 // can't move further in this text object
1812 else if ( offset
> 0 )
1814 // offset is off by 1, make it a valid index
1821 const wxString
& text
= tobj
->GetText();
1822 const char *start
= text
.c_str();
1823 const char *end
= start
+ text
.length();
1824 const char *p
= start
+ offset
;
1832 // to the beginning/end of the next/prev word
1833 while ( p
>= start
&& p
< end
&& isspace(*p
) )
1838 // go to the end/beginning of the word (in a broad sense...)
1839 while ( p
>= start
&& p
< end
&& !isspace(*p
) )
1848 // now advance to the beginning of the next word
1849 while ( isspace(*p
) && p
< end
)
1861 moveDistance
= p
- start
- offset
;
1865 // except for the first iteration, offset is 0
1869 MoveCursorHorizontally(moveDistance
);
1875 wxLayoutList::Insert(wxString
const &text
)
1877 wxASSERT(m_CursorLine
);
1878 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1883 AddCursorPosToUpdateRect();
1885 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1888 m_CursorPos
.x
+= text
.Length();
1890 m_movedCursor
= true;
1892 m_CursorLine
->RecalculatePositions(0, this);
1898 wxLayoutList::Insert(wxLayoutObject
*obj
)
1900 wxASSERT(m_CursorLine
);
1903 m_CursorLine
= GetFirstLine();
1905 AddCursorPosToUpdateRect();
1907 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1908 m_CursorPos
.x
+= obj
->GetLength();
1909 m_movedCursor
= true;
1911 m_CursorLine
->RecalculatePositions(0, this);
1917 wxLayoutList::Insert(wxLayoutList
*llist
)
1922 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1924 line
= line
->GetNextLine()
1927 for(wxLOiterator i
= line
->GetFirstObject();
1937 wxLayoutList::LineBreak(void)
1939 wxASSERT(m_CursorLine
);
1940 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1942 AddCursorPosToUpdateRect();
1944 wxPoint
position(m_CursorLine
->GetPosition());
1947 width
= m_CursorLine
->GetWidth(),
1948 height
= m_CursorLine
->GetHeight();
1950 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1951 if(setFirst
) // we were at beginning of first line
1952 m_FirstLine
= m_CursorLine
;
1953 wxASSERT(m_FirstLine
);
1954 if(m_CursorPos
.x
!= 0)
1959 // The following code will produce a height which is guaranteed to
1960 // be too high: old lineheight + the height of both new lines.
1961 // We can probably drop the old line height and start with height =
1963 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
1965 height
+= prev
->GetHeight();
1966 height
+= m_CursorLine
->GetHeight();
1968 m_movedCursor
= true;
1970 SetUpdateRect(position
);
1971 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
1972 position
.y
+ height
+ MSW_CORRECTION
);
1978 wxLayoutList::WrapLine(CoordType column
)
1980 if(m_CursorPos
.x
<= column
|| column
< 1)
1981 return false; // do nothing yet
1984 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1986 return false; // cannot break line
1988 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1989 m_CursorPos
.x
= xpos
;
1991 AddCursorPosToUpdateRect();
1994 Delete(1); // delete the space
1995 m_CursorPos
.x
= newpos
;
1997 m_CursorLine
->RecalculatePositions(1, this);
1999 m_movedCursor
= true;
2006 wxLayoutList::Delete(CoordType npos
)
2008 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
2013 AddCursorPosToUpdateRect();
2015 // were other lines appended to this one (this is important to know because
2016 // this means that our width _increased_ as the result of deletion)
2017 bool wasMerged
= false;
2019 // the size of the region to update
2020 CoordType totalHeight
= m_CursorLine
->GetHeight(),
2021 totalWidth
= m_CursorLine
->GetWidth();
2026 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
2030 // More to delete, continue on next line.
2032 // First, check if line is empty:
2033 if(m_CursorLine
->GetLength() == 0)
2035 // in this case, updating could probably be optimised
2037 wxASSERT(DeleteLines(1) == 0);
2046 // Need to join next line
2047 if(! m_CursorLine
->GetNextLine())
2052 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2055 totalHeight
+= next
->GetHeight();
2056 totalWidth
+= next
->GetWidth();
2058 m_CursorLine
->MergeNextLine(this);
2063 wxFAIL_MSG("can't delete all this");
2073 // we need to update the whole tail of the line and the lines which
2077 wxPoint
position(m_CursorLine
->GetPosition());
2078 SetUpdateRect(position
);
2079 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2080 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2087 wxLayoutList::DeleteLines(int n
)
2089 wxASSERT(m_CursorLine
);
2092 AddCursorPosToUpdateRect();
2096 if(!m_CursorLine
->GetNextLine())
2097 { // we cannot delete this line, but we can clear it
2098 MoveCursorToBeginOfLine();
2099 DeleteToEndOfLine();
2100 m_CursorLine
->RecalculatePositions(2, this);
2104 line
= m_CursorLine
;
2105 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2107 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2108 wxASSERT(m_FirstLine
);
2109 wxASSERT(m_CursorLine
);
2111 m_CursorLine
->RecalculatePositions(2, this);
2116 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2118 wxLayoutLine
*line
= m_FirstLine
;
2120 // first, make sure everything is calculated - this might not be
2121 // needed, optimise it later
2122 ApplyStyle(m_DefaultStyleInfo
, dc
);
2125 line
->RecalculatePosition(this); // so we don't need to do it all the time
2126 // little condition to speed up redrawing:
2127 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2128 line
= line
->GetNextLine();
2133 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2135 return m_CursorScreenPos
;
2139 Is called before each Draw(). Now, it will re-layout all lines which
2143 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2144 wxPoint
*cpos
, wxPoint
*csize
)
2146 // first, make sure everything is calculated - this might not be
2147 // needed, optimise it later
2148 ApplyStyle(m_DefaultStyleInfo
, dc
);
2150 // This one we always Layout() to get the current cursor
2151 // coordinates on the screen:
2152 m_CursorLine
->MarkDirty();
2153 bool wasDirty
= false;
2154 wxLayoutLine
*line
= m_FirstLine
;
2158 ApplyStyle(line
->GetStyleInfo(), dc
);
2159 if(forceAll
|| line
->IsDirty()
2160 || (cpos
&& line
->GetLineNumber() == cpos
->y
))
2162 // The following Layout() calls will update our
2163 // m_CurrentStyleInfo if needed.
2164 if(line
== m_CursorLine
)
2166 line
->Layout(dc
, this,
2167 (wxPoint
*)&m_CursorScreenPos
,
2168 (wxPoint
*)&m_CursorSize
,
2171 // we cannot layout the line twice, so copy the coords:
2172 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2174 *cpos
= m_CursorScreenPos
;
2175 *csize
= m_CursorSize
;
2179 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2180 line
->Layout(dc
, this,
2182 csize
, NULL
, cpos
->x
);
2184 line
->Layout(dc
, this);
2185 // little condition to speed up redrawing:
2186 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2190 line
->RecalculatePositions(1, this);
2191 line
= line
->GetNextLine();
2194 // can only be 0 if we are on the first line and have no next line
2195 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2196 m_CursorLine
->GetNextLine() == NULL
&&
2197 m_CursorLine
== m_FirstLine
));
2198 AddCursorPosToUpdateRect();
2202 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
)
2205 Layout(dc
, -1, false, &pos
, csize
);
2210 wxLayoutList::Draw(wxDC
&dc
,
2211 wxPoint
const &offset
,
2215 wxLayoutLine
*line
= m_FirstLine
;
2217 if ( m_Selection
.m_discarded
)
2219 // calculate them if we don't have them already
2220 if ( !m_Selection
.HasValidScreenCoords() )
2222 m_Selection
.m_ScreenA
= GetScreenPos(dc
, m_Selection
.m_CursorA
);
2223 m_Selection
.m_ScreenB
= GetScreenPos(dc
, m_Selection
.m_CursorB
);
2226 // invalidate the area which was previousle selected - and which is not
2227 // selected any more
2228 SetUpdateRect(m_Selection
.m_ScreenA
);
2229 SetUpdateRect(m_Selection
.m_ScreenB
);
2231 m_Selection
.m_discarded
= false;
2234 /* We need to re-layout all dirty lines to update styleinfos
2235 etc. However, somehow we don't find all dirty lines... */
2236 Layout(dc
); //,-1,true); //FIXME
2237 ApplyStyle(m_DefaultStyleInfo
, dc
);
2238 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2240 dc
.SetBackgroundMode(wxTRANSPARENT
);
2242 bool style_set
= false;
2245 // only draw if between top and bottom:
2247 line
->GetPosition().y
+ line
->GetHeight() >= top
))
2251 ApplyStyle(line
->GetStyleInfo(), dc
);
2254 line
->Draw(dc
, this, offset
);
2256 // little condition to speed up redrawing:
2257 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2258 line
= line
->GetNextLine();
2260 InvalidateUpdateRect();
2262 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2263 m_Selection
.m_valid
? "valid" : "invalid",
2264 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2265 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2269 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2273 // First, find the right line:
2274 wxLayoutLine
*line
= m_FirstLine
;
2277 ApplyStyle(m_DefaultStyleInfo
, dc
);
2280 p
= line
->GetPosition();
2281 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2284 // we need to run a layout here to get font sizes right :-(
2286 // VZ: we can't call Layout() from here because it marks the line as
2287 // clean and it is not refreshed when it's called from wxLayoutList::
2288 // Layout() - if we really need to do this, we should introduce an
2289 // extra argument to Layout() to prevent the line from MarkClean()ing
2291 line
->Layout(dc
, this);
2293 line
= line
->GetNextLine();
2297 if(found
) *found
= false;
2298 return NULL
; // not found
2300 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
2301 // Now, find the object in the line:
2302 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
2303 cursorPos
? & cursorPos
->x
: NULL
,
2305 return (i
== NULLIT
) ? NULL
: *i
;
2310 wxLayoutList::GetSize(void) const
2313 *line
= m_FirstLine
,
2316 return wxPoint(0,0);
2318 wxPoint
maxPoint(0,0);
2323 if(line
->GetWidth() > maxPoint
.x
)
2324 maxPoint
.x
= line
->GetWidth();
2326 line
= line
->GetNextLine();
2329 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2331 // if the line was just added, its height would be 0 and we can't call
2332 // Layout() from here because we don't have a dc and we might be not drawing
2333 // at all, besides... So take the cursor height by default (taking 0 is bad
2334 // because then the scrollbars won't be resized and the new line won't be
2336 if ( last
->IsDirty() )
2338 if ( last
->GetHeight() == 0 )
2339 maxPoint
.y
+= m_CursorSize
.y
;
2340 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2341 maxPoint
.x
= m_CursorSize
.x
;
2349 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2351 if ( m_movedCursor
)
2352 m_movedCursor
= false;
2354 wxPoint
coords(m_CursorScreenPos
);
2355 coords
+= translate
;
2357 #ifdef WXLAYOUT_DEBUG
2358 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2359 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2360 (long)coords
.x
, (long)coords
.y
,
2361 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2362 (long)m_CursorLine
->GetLineNumber(),
2363 (long)m_CursorLine
->GetLength()));
2365 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2368 #ifdef WXLAYOUT_USE_CARET
2369 m_caret
->Move(coords
);
2370 #else // !WXLAYOUT_USE_CARET
2371 dc
.SetBrush(*wxWHITE_BRUSH
);
2372 //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
2373 dc
.SetLogicalFunction(wxXOR
);
2374 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2377 dc
.DrawRectangle(coords
.x
, coords
.y
,
2378 m_CursorSize
.x
, m_CursorSize
.y
);
2379 SetUpdateRect(coords
.x
, coords
.y
);
2380 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2384 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2385 coords
.x
, coords
.y
);
2386 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2387 SetUpdateRect(coords
.x
, coords
.y
);
2389 dc
.SetLogicalFunction(wxCOPY
);
2390 //dc.SetBrush(wxNullBrush);
2391 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2395 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2397 if(m_UpdateRectValid
)
2398 GrowRect(m_UpdateRect
, x
, y
);
2403 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2404 m_UpdateRect
.height
= 4;// wxGTK :-)
2405 m_UpdateRectValid
= true;
2410 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2412 wxPoint
cpos(cposOrig
);
2415 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2416 m_Selection
.m_CursorA
= cpos
;
2417 m_Selection
.m_CursorB
= cpos
;
2418 m_Selection
.m_ScreenA
= spos
;
2419 m_Selection
.m_ScreenB
= spos
;
2420 m_Selection
.m_selecting
= true;
2421 m_Selection
.m_valid
= false;
2425 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2427 wxPoint
cpos(cposOrig
);
2431 wxASSERT(m_Selection
.m_selecting
== true);
2432 wxASSERT(m_Selection
.m_valid
== false);
2433 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2435 if ( m_Selection
.m_CursorB
<= cpos
)
2437 m_Selection
.m_ScreenB
= spos
;
2438 m_Selection
.m_CursorB
= cpos
;
2442 m_Selection
.m_ScreenA
= spos
;
2443 m_Selection
.m_CursorA
= cpos
;
2446 // we always want m_CursorA <= m_CursorB!
2447 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2449 // exchange the start/end points
2450 wxPoint help
= m_Selection
.m_CursorB
;
2451 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2452 m_Selection
.m_CursorA
= help
;
2454 help
= m_Selection
.m_ScreenB
;
2455 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2456 m_Selection
.m_ScreenA
= help
;
2461 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2463 wxPoint
cpos(cposOrig
);
2466 ContinueSelection(cpos
);
2467 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2468 m_Selection
.m_selecting
= false;
2469 m_Selection
.m_valid
= true;
2473 wxLayoutList::DiscardSelection()
2475 if ( !HasSelection() )
2478 m_Selection
.m_valid
=
2479 m_Selection
.m_selecting
= false;
2480 m_Selection
.m_discarded
= true;
2484 wxLayoutList::IsSelecting(void) const
2486 return m_Selection
.m_selecting
;
2490 wxLayoutList::IsSelected(const wxPoint
&cursor
) const
2492 if ( !HasSelection() )
2495 return m_Selection
.m_CursorA
<= cursor
&& cursor
<= m_Selection
.m_CursorB
;
2499 /** Tests whether this layout line is selected and needs
2501 @param line to test for
2502 @return 0 = not selected, 1 = fully selected, -1 = partially
2506 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2509 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2511 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2514 CoordType y
= line
->GetLineNumber();
2515 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2517 else if(m_Selection
.m_CursorA
.y
== y
)
2519 *from
= m_Selection
.m_CursorA
.x
;
2520 if(m_Selection
.m_CursorB
.y
== y
)
2521 *to
= m_Selection
.m_CursorB
.x
;
2523 *to
= line
->GetLength();
2526 else if(m_Selection
.m_CursorB
.y
== y
)
2528 *to
= m_Selection
.m_CursorB
.x
;
2529 if(m_Selection
.m_CursorA
.y
== y
)
2530 *from
= m_Selection
.m_CursorA
.x
;
2540 wxLayoutList::DeleteSelection(void)
2542 if(! m_Selection
.m_valid
)
2545 m_Selection
.m_valid
= false;
2547 // Only delete part of the current line?
2548 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2550 MoveCursorTo(m_Selection
.m_CursorA
);
2551 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2560 for(firstLine
= m_FirstLine
;
2561 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
2562 firstLine
=firstLine
->GetNextLine())
2564 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
2568 for(lastLine
= m_FirstLine
;
2569 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
2570 lastLine
=lastLine
->GetNextLine())
2572 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
2576 // We now know that the two lines are different:
2578 // First, delete what's left of this line:
2579 MoveCursorTo(m_Selection
.m_CursorA
);
2580 DeleteToEndOfLine();
2582 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
2583 while(nextLine
&& nextLine
!= lastLine
)
2584 nextLine
= nextLine
->DeleteLine(false, this);
2586 // Now nextLine = lastLine;
2587 Delete(1); // This joins firstLine and nextLine
2588 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
2592 firstLine
->RecalculatePositions(1, this);
2595 /// Starts highlighting the selection
2597 wxLayoutList::StartHighlighting(wxDC
&dc
)
2600 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2601 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2602 dc
.SetBackgroundMode(wxSOLID
);
2606 /// Ends highlighting the selection
2608 wxLayoutList::EndHighlighting(wxDC
&dc
)
2611 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2612 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2613 dc
.SetBackgroundMode(wxTRANSPARENT
);
2619 wxLayoutList::Copy(const wxPoint
&from
,
2626 for(firstLine
= m_FirstLine
;
2627 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2628 firstLine
=firstLine
->GetNextLine())
2630 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2633 for(lastLine
= m_FirstLine
;
2634 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2635 lastLine
=lastLine
->GetNextLine())
2637 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2642 wxLayoutLine
*tmp
= firstLine
;
2643 firstLine
= lastLine
;
2647 wxLayoutList
*llist
= new wxLayoutList();
2649 if(firstLine
== lastLine
)
2651 firstLine
->Copy(llist
, from
.x
, to
.x
);
2655 // Extract objects from first line
2656 firstLine
->Copy(llist
, from
.x
);
2658 // Extract all lines between
2659 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2661 line
= line
->GetNextLine())
2666 // Extract objects from last line
2667 lastLine
->Copy(llist
, 0, to
.x
);
2673 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2675 if(! m_Selection
.m_valid
)
2677 if(m_Selection
.m_selecting
)
2683 if(invalidate
) m_Selection
.m_valid
= false;
2685 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2686 m_Selection
.m_CursorB
);
2688 if(llist
&& wxlo
) // export as data object, too
2692 wxLayoutExportObject
*export
;
2693 wxLayoutExportStatus
status(llist
);
2694 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2696 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2697 ; //FIXME missing support for linebreaks in string format
2699 export
->content
.object
->Write(string
);
2703 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2710 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2713 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2715 bool fontChanged
= FALSE
;
2722 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2726 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2727 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2731 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2732 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2737 #ifdef WXLAYOUT_DEBUG
2740 wxLayoutList::Debug(void)
2742 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2743 m_CursorLine
->GetLineNumber(),
2744 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2747 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2756 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2760 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2762 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2763 wxString
const & title
)
2768 // remove any highlighting which could interfere with printing:
2769 m_llist
->StartSelection();
2770 m_llist
->EndSelection();
2773 wxLayoutPrintout::~wxLayoutPrintout()
2778 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2780 // The following bit is taken from the printing sample, let's see
2781 // whether it works for us.
2783 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2784 * the screen text size. This page also draws lines of actual length 5cm
2787 // Get the logical pixels per inch of screen and printer
2788 int ppiScreenX
, ppiScreenY
;
2789 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2790 int ppiPrinterX
, ppiPrinterY
;
2791 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2793 if(ppiScreenX
== 0) // not yet set, need to guess
2798 if(ppiPrinterX
== 0) // not yet set, need to guess
2804 // This scales the DC so that the printout roughly represents the
2805 // the screen scaling. The text point size _should_ be the right size
2806 // but in fact is too small for some reason. This is a detail that will
2807 // need to be addressed at some point but can be fudged for the
2809 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2811 // Now we have to check in case our real page size is reduced
2812 // (e.g. because we're drawing to a print preview memory DC)
2813 int pageWidth
, pageHeight
;
2815 dc
->GetSize(&w
, &h
);
2816 GetPageSizePixels(&pageWidth
, &pageHeight
);
2817 if(pageWidth
!= 0) // doesn't work always
2819 // If printer pageWidth == current DC width, then this doesn't
2820 // change. But w might be the preview bitmap width, so scale down.
2821 scale
= scale
* (float)(w
/(float)pageWidth
);
2823 dc
->SetUserScale(scale
, scale
);
2827 bool wxLayoutPrintout::OnPrintPage(int page
)
2836 top
= (page
- 1)*m_PrintoutHeight
;
2837 bottom
= top
+ m_PrintoutHeight
;
2838 // SetDeviceOrigin() doesn't work here, so we need to manually
2839 // translate all coordinates.
2840 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2841 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2848 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2850 /* We allocate a temporary wxDC for printing, so that we can
2851 determine the correct paper size and scaling. We don't actually
2852 print anything on it. */
2854 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2856 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2859 float scale
= ScaleDC(&psdc
);
2861 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2862 // This sets a left/top origin of 15% and 20%:
2863 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2865 // This is the length of the printable area.
2866 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2867 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2871 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2874 *maxPage
= m_NumOfPages
;
2877 *selPageTo
= m_NumOfPages
;
2878 wxRemoveFile(WXLLIST_TEMPFILE
);
2881 bool wxLayoutPrintout::HasPage(int pageNum
)
2883 return pageNum
<= m_NumOfPages
;
2887 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2888 out. It's a waste of paper anyway.
2892 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2893 wxPoint topleft
, wxPoint bottomright
,
2896 // make backups of all essential parameters
2897 const wxBrush
& brush
= dc
.GetBrush();
2898 const wxPen
& pen
= dc
.GetPen();
2899 const wxFont
& font
= dc
.GetFont();
2901 dc
.SetBrush(*wxWHITE_BRUSH
);
2902 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2903 dc
.DrawRoundedRectangle(topleft
.x
,
2904 topleft
.y
,bottomright
.x
-topleft
.x
,
2905 bottomright
.y
-topleft
.y
);
2906 dc
.SetBrush(*wxBLACK_BRUSH
);
2907 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2908 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2912 page
= "9999/9999 "; // many pages...
2914 dc
.GetTextExtent(page
,&w
,&h
);
2915 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2916 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2917 dc
.GetTextExtent("XXXX", &w
,&h
);
2918 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2929 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2932 for(wxFCEList::iterator i
= m_FontList
.begin();
2933 i
!= m_FontList
.end(); i
++)
2934 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2935 return (**i
).GetFont();
2937 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2939 m_FontList
.push_back(fce
);
2940 return fce
->GetFont();