1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
14 #pragma implementation "wxllist.h"
20 #include "wx/wxprec.h"
26 # include "gui/wxllist.h"
27 # define SHOW_SELECTIONS 1
30 # include "wxlparser.h"
31 # define SHOW_SELECTIONS 1
35 # include "iostream.h"
38 # include <wx/print.h>
44 /// This should never really get created
45 #define WXLLIST_TEMPFILE "__wxllist.tmp"
49 # define TypewxString(t) g_aTypewxStrings[t]
50 # define WXLO_DEBUG(x) wxLogDebug x
52 static const char *g_aTypewxStrings
[] =
54 "invalid", "text", "cmd", "icon"
57 wxLayoutObject::Debug(void)
59 WXLO_DEBUG(("%s",g_aTypewxStrings
[GetType()]));
62 # define TypewxString(t) ""
63 # define WXLO_DEBUG(x)
67 /// Cursors smaller than this disappear in XOR drawing mode
68 #define WXLO_MINIMUM_CURSOR_WIDTH 4
70 /// Use this character to estimate a cursor size when none is available.
71 #define WXLO_CURSORCHAR "E"
72 /** @name Helper functions */
74 /// allows me to compare to wxPoints
75 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
77 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
80 /// allows me to compare to wxPoints
81 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
83 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
86 /// allows me to compare to wxPoints
87 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
89 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
92 /// grows a wxRect so that it includes the given point
95 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
99 else if(r
.x
+ r
.width
< x
)
104 else if(r
.y
+ r
.height
< y
)
110 /// returns true if the point is in the rectangle
112 bool Contains(const wxRect
&r
, const wxPoint
&p
)
114 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
121 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
125 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
127 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
137 wxLayoutObjectText::Copy(void)
139 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
140 obj
->m_Width
= m_Width
;
141 obj
->m_Height
= m_Height
;
143 obj
->m_Bottom
= m_Bottom
;
144 obj
->SetUserData(m_UserData
);
149 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
152 *top
= m_Top
; *bottom
= m_Bottom
;
153 return wxPoint(m_Width
, m_Height
);
157 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
158 wxLayoutList
*wxllist
,
159 CoordType begin
, CoordType end
)
162 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
165 // highlight the bit between begin and len
169 ypos
= coords
.y
-m_Top
;
170 long width
, height
, descent
;
172 str
= m_Text
.Mid(0, begin
);
173 dc
.DrawText(str
, xpos
, ypos
);
174 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
176 wxllist
->StartHighlighting(dc
);
177 str
= m_Text
.Mid(begin
, end
-begin
);
178 dc
.DrawText(str
, xpos
, ypos
);
179 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
181 wxllist
->EndHighlighting(dc
);
182 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
183 dc
.DrawText(str
, xpos
, ypos
);
188 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
192 maxlen
= m_Text
.Length();
195 height
, descent
= 0l;
197 if(xpos
== 0) return 0; // easy
199 while(width
< xpos
&& offs
< maxlen
)
201 dc
.GetTextExtent(m_Text
.substr(0,offs
),
202 &width
, &height
, &descent
);
205 /* We have to substract 1 to compensate for the offs++, and another
206 one because we don't want to position the cursor behind the
207 object what we clicked on, but before - otherwise it looks
209 return (xpos
> 2) ? offs
-2 : 0;
213 wxLayoutObjectText::Layout(wxDC
&dc
, class wxLayoutList
* )
217 dc
.GetTextExtent(m_Text
,&m_Width
, &m_Height
, &descent
);
219 m_Top
= m_Height
- m_Bottom
;
222 #ifdef WXLAYOUT_DEBUG
224 wxLayoutObjectText::Debug(void)
226 wxLayoutObject::Debug();
227 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
231 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
235 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
237 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
239 m_Icon
= new wxBitmap(icon
);
243 wxLayoutObjectIcon::Copy(void)
245 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
247 obj
->SetUserData(m_UserData
);
251 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
257 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
258 wxLayoutList
*wxllist
,
259 CoordType begin
, CoordType
/* len */)
261 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
262 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
266 wxLayoutObjectIcon::Layout(wxDC
& /* dc */, class wxLayoutList
* )
271 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
273 *top
= m_Icon
->GetHeight();
275 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
280 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
284 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
287 wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily
,
295 family
= ifamily
; size
= isize
;
296 style
= istyle
; weight
= iweight
;
314 #define COPY_SI_(what) if(right.what != -1) what = right.what;
317 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
324 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
325 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
329 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
330 weight
, int underline
,
331 wxColour
*fg
, wxColour
*bg
)
334 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
338 wxLayoutObjectCmd::Copy(void)
340 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
345 m_StyleInfo
->underline
,
346 m_StyleInfo
->m_fg_valid
?
347 &m_StyleInfo
->m_fg
: NULL
,
348 m_StyleInfo
->m_bg_valid
?
349 &m_StyleInfo
->m_bg
: NULL
);
350 obj
->SetUserData(m_UserData
);
355 wxLayoutObjectCmd::~wxLayoutObjectCmd()
361 wxLayoutObjectCmd::GetStyle(void) const
367 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
368 wxLayoutList
*wxllist
,
369 CoordType begin
, CoordType
/* len */)
371 wxASSERT(m_StyleInfo
);
372 wxllist
->ApplyStyle(m_StyleInfo
, dc
);
376 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
378 // this get called, so that recalculation uses right font sizes
379 Draw(dc
, wxPoint(0,0), llist
);
383 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
385 The wxLayoutLine object
387 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
389 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
392 m_Width
= m_Height
= 0;
397 RecalculatePosition(llist
);
400 m_LineNumber
= m_Previous
->GetLineNumber()+1;
401 m_Next
= m_Previous
->GetNextLine();
402 m_Previous
->m_Next
= this;
406 m_Next
->m_Previous
= this;
407 m_Next
->MoveLines(+1);
408 m_Next
->RecalculatePositions(1,llist
);
412 wxLayoutLine::~wxLayoutLine()
414 // kbList cleans itself
418 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
420 wxASSERT(m_Previous
|| GetLineNumber() == 0);
424 m_Position
= m_Previous
->GetPosition();
425 m_Position
.y
+= m_Previous
->GetHeight();
428 m_Position
= wxPoint(0,0);
429 llist
->SetUpdateRect(m_Position
);
434 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
436 wxASSERT(recurse
>= 0);
437 wxPoint pos
= m_Position
;
438 CoordType height
= m_Height
;
440 // WXLO_TRACE("RecalculatePositions()");
441 RecalculatePosition(llist
);
445 m_Next
->RecalculatePositions(--recurse
, llist
);
446 else if(pos
!= m_Position
|| m_Height
!= height
)
447 m_Next
->RecalculatePositions(0, llist
);
451 wxLayoutObjectList::iterator
452 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
456 wxLayoutObjectList::iterator
459 CoordType x
= 0, len
;
461 /* We search through the objects. As we don't like returning the
462 object that the cursor is behind, we just remember such an
463 object in "found" so we can return it if there is really no
464 further object following it. */
465 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
467 len
= (**i
).GetLength();
468 if( x
<= xpos
&& xpos
<= x
+ len
)
471 if(xpos
== x
+ len
) // is there another object behind?
473 else // we are really inside this object
476 x
+= (**i
).GetLength();
478 return found
; // ==NULL if really none found
481 wxLayoutObjectList::iterator
482 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
483 CoordType xpos
, CoordType
*cxpos
,
488 wxLayoutObjectList::iterator i
;
489 CoordType x
= 0, cx
= 0, width
;
491 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
493 width
= (**i
).GetWidth();
494 if( x
<= xpos
&& xpos
<= x
+ width
)
496 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
497 if(found
) *found
= true;
500 x
+= (**i
).GetWidth();
501 cx
+= (**i
).GetLength();
503 // behind last object:
505 if(found
) *found
= false;
506 return m_ObjectList
.tail();
509 /** Finds text in this line.
510 @param needle the text to find
511 @param xpos the position where to start the search
512 @return the cursoor coord where it was found or -1
515 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
520 wxString
const *text
;
522 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
524 if(cpos
>= xpos
) // search from here!
526 if((**i
).GetType() == WXLO_TYPE_TEXT
)
528 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
529 relpos
= text
->Find(needle
);
530 if(relpos
>= cpos
-xpos
) // -1 if not found
535 cpos
+= (**i
).GetLength();
538 return -1; // not found
542 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
545 wxASSERT(obj
!= NULL
);
546 //FIXME: this could be optimised, for now be prudent:
549 wxLOiterator i
= FindObject(xpos
, &offset
);
552 if(xpos
== 0 ) // aha, empty line!
554 m_ObjectList
.push_back(obj
);
555 m_Length
+= obj
->GetLength();
562 CoordType len
= (**i
).GetLength();
563 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
564 { // insert before this object
565 m_ObjectList
.insert(i
,obj
);
566 m_Length
+= obj
->GetLength();
571 if( i
== m_ObjectList
.tail()) // last object?
572 m_ObjectList
.push_back(obj
);
574 { // insert after current object
576 m_ObjectList
.insert(i
,obj
);
578 m_Length
+= obj
->GetLength();
581 /* Otherwise we need to split the current object.
582 Fortunately this can only be a text object. */
583 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
584 wxString left
, right
;
585 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
586 left
= tobj
->GetText().substr(0,offset
);
587 right
= tobj
->GetText().substr(offset
,len
-offset
);
588 // current text object gets set to right half
589 tobj
->GetText() = right
; // set new text
590 // before it we insert the new object
591 m_ObjectList
.insert(i
,obj
);
592 m_Length
+= obj
->GetLength();
593 // and before that we insert the left half
594 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
599 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
602 //FIXME: this could be optimised, for now be prudent:
605 wxLOiterator i
= FindObject(xpos
, &offset
);
606 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
608 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
609 tobj
->GetText().insert(offset
, text
);
610 m_Length
+= text
.Length();
615 return Insert(xpos
, new wxLayoutObjectText(text
));
619 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
621 CoordType offset
, len
;
625 //FIXME: this could be optimised, for now be prudent:
627 wxLOiterator i
= FindObject(xpos
, &offset
);
630 if(i
== NULLIT
) return npos
;
631 // now delete from that object:
632 if((**i
).GetType() != WXLO_TYPE_TEXT
)
634 if(offset
!= 0) // at end of line after a non-text object
637 len
= (**i
).GetLength();
640 m_ObjectList
.erase(i
);
644 // tidy up: remove empty text objects
645 if((**i
).GetLength() == 0)
647 m_ObjectList
.erase(i
);
651 CoordType max
= (**i
).GetLength() - offset
;
652 if(npos
< max
) max
= npos
;
655 if(xpos
== GetLength())
658 { // at the end of an object
659 // move to begin of next object:
661 continue; // start over
666 if(offset
== 0 && max
== (**i
).GetLength())
667 m_ObjectList
.erase(i
); // remove the whole object
669 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
676 wxLayoutLine::DeleteWord(CoordType xpos
)
680 //FIXME: this could be optimised, for now be prudent:
683 wxLOiterator i
= FindObject(xpos
, &offset
);
687 if(i
== NULLIT
) return false;
688 if((**i
).GetType() != WXLO_TYPE_TEXT
)
690 // This should only happen when at end of line, behind a non-text
692 if(offset
== (**i
).GetLength()) return false;
693 m_Length
-= (**i
).GetLength(); // -1
694 m_ObjectList
.erase(i
);
695 return true; // we are done
699 if(offset
== (**i
).GetLength()) // at end of object
704 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
706 wxString str
= tobj
->GetText();
707 str
= str
.substr(offset
,str
.Length()-offset
);
708 // Find out how many positions we need to delete:
709 // 1. eat leading space
710 while(isspace(str
.c_str()[count
])) count
++;
711 // 2. eat the word itself:
712 while(isalnum(str
.c_str()[count
])) count
++;
714 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
715 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
720 wxASSERT(0); // we should never arrive here
724 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
726 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
727 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
730 m_Next
->MoveLines(-1);
731 m_Next
->RecalculatePositions(1, llist
);
733 wxLayoutLine
*next
= m_Next
;
739 wxLayoutLine::Draw(wxDC
&dc
,
741 const wxPoint
& offset
) const
743 wxLayoutObjectList::iterator i
;
744 wxPoint pos
= offset
;
745 pos
= pos
+ GetPosition();
749 CoordType xpos
= 0; // cursorpos, lenght of line
751 CoordType from
, to
, tempto
;
752 //FIXME This doesn't work yet, needs updating afterr default
753 //settings for list or a wxLayoutObjectCmd have changed:
754 //llist->ApplyStyle(&((wxLayoutLine *)this)->m_StyleInfo, dc);
755 int highlight
= llist
->IsSelected(this, &from
, &to
);
756 // WXLO_DEBUG(("highlight=%d", highlight ));
757 if(highlight
== 1) // we need to draw the whole line inverted!
758 llist
->StartHighlighting(dc
);
760 llist
->EndHighlighting(dc
);
762 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
764 if(highlight
== -1) // partially highlight line
766 // parts of the line need highlighting
767 tempto
= xpos
+(**i
).GetLength();
768 if(tempto
>= from
&& xpos
<= to
)
771 if(tempto
> (**i
).GetLength())
772 tempto
= (**i
).GetLength();
773 CoordType tmp
= from
-xpos
;
775 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, tempto
);
779 llist
->EndHighlighting(dc
); // FIXME! inefficient
780 (**i
).Draw(dc
, pos
, llist
);
784 (**i
).Draw(dc
, pos
, llist
);
785 pos
.x
+= (**i
).GetWidth();
786 xpos
+= (**i
).GetLength();
791 wxLayoutLine::Layout(wxDC
&dc
,
797 wxLayoutObjectList::iterator i
;
800 oldHeight
= m_Height
;
802 topHeight
, bottomHeight
; // above and below baseline
805 objTopHeight
, objBottomHeight
;
808 m_Height
= 0; m_BaseLine
= 0;
810 topHeight
= 0; bottomHeight
= 0;
812 bool cursorFound
= false;
818 *cursorPos
= m_Position
;
819 if(cursorSize
) *cursorSize
= wxPoint(0,0);
822 //FIXME This doesn't work yet, needs updating afterr default
823 //settings for list or a wxLayoutObjectCmd have changed:
824 //llist->ApplyStyle(&m_StyleInfo, dc);
825 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
827 (**i
).Layout(dc
, llist
);
828 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
830 if(cursorPos
&& ! cursorFound
)
831 { // we need to check whether the text cursor is here
832 len
= (**i
).GetLength();
833 if(count
<= cx
&& count
+len
> cx
)
835 if((**i
).GetType() == WXLO_TYPE_TEXT
)
837 len
= cx
- count
; // pos in object
838 CoordType width
, height
, descent
;
839 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
840 &width
, &height
, &descent
);
841 cursorPos
->x
+= width
;
842 cursorPos
->y
= m_Position
.y
;
844 if(len
< (**i
).GetLength())
845 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
847 str
= WXLO_CURSORCHAR
;
848 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
849 wxASSERT(cursorSize
);
850 // Just in case some joker inserted an empty string object:
851 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
852 if(height
== 0) height
= objHeight
;
853 cursorSize
->x
= width
;
854 cursorSize
->y
= height
;
855 cursorFound
= true; // no more checks
858 { // on some other object
859 CoordType top
, bottom
; // unused
860 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
861 cursorPos
->y
= m_Position
.y
;
862 cursorFound
= true; // no more checks
868 cursorPos
->x
+= (**i
).GetWidth();
873 if(objHeight
> m_Height
) m_Height
= objHeight
;
874 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
875 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
877 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
878 topHeight
+bottomHeight
;
879 m_BaseLine
= topHeight
;
883 CoordType width
, height
, descent
;
884 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
886 m_BaseLine
= m_Height
- descent
;
890 // tell next line about coordinate change
891 if(m_Next
&& objHeight
!= oldHeight
)
892 m_Next
->RecalculatePositions(0, llist
);
894 // We need to check whether we found a valid cursor size:
897 // this might be the case if the cursor is at the end of the
898 // line or on a command object:
899 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
901 CoordType width
, height
, descent
;
902 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
903 cursorSize
->x
= width
;
904 cursorSize
->y
= height
;
906 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
907 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
909 RecalculatePositions(1, llist
);
914 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
917 //FIXME: this could be optimised, for now be prudent:
921 { // insert an empty line before this one
922 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
923 if(m_Previous
== NULL
)
924 { // We were in first line, need to link in new empty line
928 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
932 m_Next
->RecalculatePositions(1, llist
);
937 wxLOiterator i
= FindObject(xpos
, &offset
);
939 // must be at the end of the line then
940 return new wxLayoutLine(this, llist
);
943 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
944 // split object at i:
945 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
947 wxString left
, right
;
948 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
949 left
= tobj
->GetText().substr(0,offset
);
950 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
951 // current text object gets set to left half
952 tobj
->GetText() = left
; // set new text
953 newLine
->Append(new wxLayoutObjectText(right
));
954 m_Length
-= right
.Length();
955 i
++; // don't move this object to the new list
959 i
++; // move objects from here to new list
961 while(i
!= m_ObjectList
.end())
964 m_Length
-= (**i
).GetLength();
965 m_ObjectList
.remove(i
); // remove without deleting it
968 m_Next
->RecalculatePositions(2, llist
);
974 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
976 wxASSERT(GetNextLine());
977 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
979 //FIXME: this could be optimised, for now be prudent:
982 for(i
= list
.begin(); i
!= list
.end();)
985 list
.remove(i
); // remove without deleting it
987 wxASSERT(list
.empty());
988 wxLayoutLine
*oldnext
= GetNextLine();
989 SetNext(GetNextLine()->GetNextLine());
991 RecalculatePositions(1, llist
);
995 wxLayoutLine::GetWrapPosition(CoordType column
)
998 wxLOiterator i
= FindObject(column
, &offset
);
999 if(i
== NULLIT
) return -1; // cannot wrap
1001 // go backwards through the list and look for space in text objects
1004 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1008 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1015 }while(offset
!= -1);
1016 i
--; // move on to previous object
1020 column
-= (**i
).GetLength();
1024 offset
= (**i
).GetLength();
1025 }while(i
!= NULLIT
);
1026 /* If we reached the begin of the list and have more than one
1027 object, that one is longer than the margin, so break behind
1030 i
= m_ObjectList
.begin();
1031 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1033 pos
+= (**i
).GetLength();
1036 if(i
== NULLIT
) return -1; //why should this happen?
1037 pos
+= (**i
).GetLength();
1039 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1041 pos
+= (**i
).GetLength();
1044 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1045 // now we are at the second text object:
1046 pos
-= (**i
).GetLength();
1047 return pos
; // in front of it
1051 #ifdef WXLAYOUT_DEBUG
1053 wxLayoutLine::Debug(void)
1056 wxPoint pos
= GetPosition();
1057 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
1058 (long int) GetLineNumber(),
1059 (long int) pos
.x
, (long int) pos
.y
,
1060 (long int) GetHeight()));
1061 if(m_ObjectList
.begin() != NULLIT
)
1062 (**m_ObjectList
.begin()).Debug();
1068 wxLayoutLine::Copy(wxLayoutList
*llist
,
1072 CoordType firstOffset
, lastOffset
;
1074 if(to
== -1) to
= GetLength();
1076 wxLOiterator first
= FindObject(from
, &firstOffset
);
1077 wxLOiterator last
= FindObject(to
, &lastOffset
);
1079 // Common special case: only one object
1080 if( *first
== *last
)
1082 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1084 llist
->Insert(new wxLayoutObjectText(
1085 ((wxLayoutObjectText
1086 *)*first
)->GetText().substr(firstOffset
,
1087 lastOffset
-firstOffset
))
1091 else // what can we do?
1093 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1094 llist
->Insert( (**first
).Copy() );
1099 // If we reach here, we can safely copy the whole first object from
1100 // the firstOffset position on:
1101 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1103 llist
->Insert(new wxLayoutObjectText(
1104 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1107 else if(firstOffset
== 0)
1108 llist
->Insert( (**first
).Copy() );
1109 // else nothing to copy :-(
1111 // Now we copy all objects before the last one:
1112 wxLOiterator i
= first
; i
++;
1113 for( ; i
!= last
; i
++)
1114 llist
->Insert( (**i
).Copy() );
1116 // And now the last object:
1119 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1121 llist
->Insert(new wxLayoutObjectText(
1122 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1126 llist
->Insert( (**last
).Copy() );
1130 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1132 The wxLayoutList object
1134 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1136 wxLayoutList::wxLayoutList()
1139 InvalidateUpdateRect();
1143 wxLayoutList::~wxLayoutList()
1146 m_FirstLine
->DeleteLine(false, this);
1150 wxLayoutList::Empty(void)
1153 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1155 m_CursorPos
= wxPoint(0,0);
1156 m_CursorScreenPos
= wxPoint(0,0);
1157 m_CursorSize
= wxPoint(0,0);
1158 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1159 m_CursorLine
= m_FirstLine
;
1160 InvalidateUpdateRect();
1165 wxLayoutList::InternalClear(void)
1168 m_Selection
.m_selecting
= false;
1169 m_Selection
.m_valid
= false;
1171 m_DefaultSetting
.family
= wxSWISS
;
1172 m_DefaultSetting
.size
= WXLO_DEFAULTFONTSIZE
;
1173 m_DefaultSetting
.style
= wxNORMAL
;
1174 m_DefaultSetting
.weight
= wxNORMAL
;
1175 m_DefaultSetting
.underline
= 0;
1176 m_DefaultSetting
.m_fg_valid
= TRUE
;
1177 m_DefaultSetting
.m_fg
= *wxBLACK
;
1178 m_DefaultSetting
.m_bg_valid
= TRUE
;
1179 m_DefaultSetting
.m_bg
= *wxWHITE
;
1181 m_CurrentSetting
= m_DefaultSetting
;
1185 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1186 int underline
, wxColour
*fg
,
1189 if(family
!= -1) m_CurrentSetting
.family
= family
;
1190 if(size
!= -1) m_CurrentSetting
.size
= size
;
1191 if(style
!= -1) m_CurrentSetting
.style
= style
;
1192 if(weight
!= -1) m_CurrentSetting
.weight
= weight
;
1193 if(underline
!= -1) m_CurrentSetting
.underline
= underline
!= 0;
1194 if(fg
) m_CurrentSetting
.m_fg
= *fg
;
1195 if(bg
) m_CurrentSetting
.m_bg
= *bg
;
1197 new wxLayoutObjectCmd(
1198 m_CurrentSetting
.family
,
1199 m_CurrentSetting
.size
,
1200 m_CurrentSetting
.style
,
1201 m_CurrentSetting
.weight
,
1202 m_CurrentSetting
.underline
,
1207 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1208 int underline
, char const *fg
, char const *bg
)
1216 cfg
= wxTheColourDatabase
->FindColour(fg
);
1218 cbg
= wxTheColourDatabase
->FindColour(bg
);
1220 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1224 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1225 int underline
, wxColour
*fg
, wxColour
*bg
)
1228 m_DefaultSetting
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1230 m_CurrentSetting
= m_DefaultSetting
;
1234 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1239 for(line
= m_FirstLine
;
1241 line
= line
->GetNextLine())
1243 if(line
->GetLineNumber() >= cpos
.y
)
1245 xpos
= line
->FindText(needle
,
1246 (line
->GetLineNumber() == cpos
.y
) ?
1249 return wxPoint(xpos
, line
->GetLineNumber());
1252 return wxPoint(-1,-1);
1257 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1259 SetUpdateRect(m_CursorScreenPos
);
1260 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1261 wxLayoutLine
*line
= m_FirstLine
;
1262 while(line
&& line
->GetLineNumber() != p
.y
)
1263 line
= line
->GetNextLine();
1264 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1266 m_CursorPos
.y
= p
.y
;
1267 m_CursorLine
= line
;
1268 CoordType len
= line
->GetLength();
1271 m_CursorPos
.x
= p
.x
;
1276 m_CursorPos
.x
= len
;
1284 wxLayoutList::MoveCursorVertically(int n
)
1286 SetUpdateRect(m_CursorScreenPos
);
1287 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1289 if(n
< 0) // move up
1291 if(m_CursorLine
== m_FirstLine
) return false;
1292 while(n
< 0 && m_CursorLine
)
1294 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1300 m_CursorLine
= m_FirstLine
;
1306 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1307 m_CursorPos
.x
= m_CursorLine
->GetLength();
1313 wxLayoutLine
*last
= m_CursorLine
;
1314 if(! m_CursorLine
->GetNextLine()) return false;
1315 while(n
> 0 && m_CursorLine
)
1319 m_CursorLine
= m_CursorLine
->GetNextLine();
1323 m_CursorLine
= last
;
1329 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1330 m_CursorPos
.x
= m_CursorLine
->GetLength();
1338 wxLayoutList::MoveCursorHorizontally(int n
)
1340 SetUpdateRect(m_CursorScreenPos
);
1341 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1345 if(m_CursorPos
.x
== 0) // at begin of line
1347 if(! MoveCursorVertically(-1))
1349 MoveCursorToEndOfLine();
1354 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1355 m_CursorPos
.x
-= move
; n
+= move
;
1360 int len
= m_CursorLine
->GetLength();
1361 if(m_CursorPos
.x
== len
) // at end of line
1363 if(! MoveCursorVertically(1))
1365 MoveCursorToBeginOfLine();
1370 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1371 m_CursorPos
.x
+= move
;
1378 wxLayoutList::Insert(wxString
const &text
)
1380 wxASSERT(m_CursorLine
);
1381 SetUpdateRect(m_CursorScreenPos
);
1382 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1383 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1384 m_CursorPos
.x
+= text
.Length();
1385 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1390 wxLayoutList::Insert(wxLayoutObject
*obj
)
1392 wxASSERT(m_CursorLine
);
1393 SetUpdateRect(m_CursorScreenPos
);
1394 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1395 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1396 m_CursorPos
.x
+= obj
->GetLength();
1397 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1402 wxLayoutList::LineBreak(void)
1404 wxASSERT(m_CursorLine
);
1405 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1406 SetUpdateRect(m_CursorScreenPos
);
1407 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1408 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1409 if(setFirst
) // we were at beginning of first line
1410 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1413 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1418 wxLayoutList::WrapLine(CoordType column
)
1420 if(m_CursorPos
.x
<= column
|| column
< 1)
1421 return false; // do nothing yet
1424 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1426 return false; // cannot break line
1428 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1429 m_CursorPos
.x
= xpos
;
1430 SetUpdateRect(m_CursorScreenPos
);
1431 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1433 Delete(1); // delete the space
1434 m_CursorPos
.x
= newpos
;
1435 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1441 wxLayoutList::Delete(CoordType npos
)
1443 wxASSERT(m_CursorLine
);
1444 SetUpdateRect(m_CursorScreenPos
);
1445 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1449 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1452 // More to delete, continue on next line.
1453 // First, check if line is empty:
1454 if(m_CursorLine
->GetLength() == 0)
1455 { // in this case, updating could probably be optimised
1457 wxASSERT(DeleteLines(1) == 0);
1466 // Need to join next line
1467 if(! m_CursorLine
->GetNextLine())
1471 m_CursorLine
->MergeNextLine(this);
1477 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1482 wxLayoutList::DeleteLines(int n
)
1484 wxASSERT(m_CursorLine
);
1486 SetUpdateRect(m_CursorScreenPos
);
1487 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1490 if(!m_CursorLine
->GetNextLine())
1491 { // we cannot delete this line, but we can clear it
1492 MoveCursorToBeginOfLine();
1493 DeleteToEndOfLine();
1494 m_CursorLine
->RecalculatePositions(2, this);
1498 line
= m_CursorLine
;
1499 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1501 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1502 wxASSERT(m_FirstLine
);
1503 wxASSERT(m_CursorLine
);
1505 m_CursorLine
->RecalculatePositions(2, this);
1510 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1512 wxLayoutLine
*line
= m_FirstLine
;
1514 // first, make sure everything is calculated - this might not be
1515 // needed, optimise it later
1516 ApplyStyle(&m_DefaultSetting
, dc
);
1519 line
->RecalculatePosition(this); // so we don't need to do it all the time
1520 // little condition to speed up redrawing:
1521 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1522 line
= line
->GetNextLine();
1527 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1529 wxASSERT(m_CursorLine
);
1530 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1534 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1536 UpdateCursorScreenPos(dc
);
1537 return m_CursorScreenPos
;
1541 Is called before each Draw(). Now, it will re-layout all lines which
1545 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
)
1547 wxLayoutLine
*line
= m_FirstLine
;
1549 // first, make sure everything is calculated - this might not be
1550 // needed, optimise it later
1551 ApplyStyle(&m_DefaultSetting
, dc
);
1554 if(forceAll
|| line
->IsDirty())
1556 line
->GetStyleInfo() = m_CurrentSetting
;
1557 if(line
== m_CursorLine
)
1558 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
,
1559 (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1561 line
->Layout(dc
, this);
1562 line
->RecalculatePosition(this);
1563 // little condition to speed up redrawing:
1564 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1566 line
= line
->GetNextLine();
1569 ///FIXME: disabled for now
1571 // can only be 0 if we are on the first line and have no next line
1572 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1573 m_CursorLine
->GetNextLine() == NULL
&&
1574 m_CursorLine
== m_FirstLine
));
1576 SetUpdateRect(m_CursorScreenPos
);
1577 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1581 wxLayoutList::Draw(wxDC
&dc
,
1582 wxPoint
const &offset
,
1586 wxLayoutLine
*line
= m_FirstLine
;
1589 ApplyStyle(&m_DefaultSetting
, dc
);
1590 wxBrush
brush(m_CurrentSetting
.m_bg
, wxSOLID
);
1595 // only draw if between top and bottom:
1596 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1597 line
->Draw(dc
, this, offset
);
1598 // little condition to speed up redrawing:
1599 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1600 line
= line
->GetNextLine();
1602 InvalidateUpdateRect();
1604 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
1605 m_Selection
.m_valid
? "valid" : "invalid",
1606 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1607 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
1611 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1615 // First, find the right line:
1616 wxLayoutLine
*line
= m_FirstLine
;
1619 // we need to run a layout here to get font sizes right :-(
1620 ApplyStyle(&m_DefaultSetting
, dc
);
1623 p
= line
->GetPosition();
1624 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1626 line
->Layout(dc
, this);
1627 line
= line
->GetNextLine();
1631 if(found
) *found
= false;
1632 return NULL
; // not found
1634 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1635 // Now, find the object in the line:
1636 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1637 cursorPos
? & cursorPos
->x
: NULL
,
1639 return (i
== NULLIT
) ? NULL
: *i
;
1644 wxLayoutList::GetSize(void) const
1647 *line
= m_FirstLine
,
1650 return wxPoint(0,0);
1652 wxPoint
maxPoint(0,0);
1657 if(line
->GetWidth() > maxPoint
.x
)
1658 maxPoint
.x
= line
->GetWidth();
1660 line
= line
->GetNextLine();
1663 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1669 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1672 coords
= m_CursorScreenPos
;
1673 coords
.x
+= translate
.x
;
1674 coords
.y
+= translate
.y
;
1676 #ifdef WXLAYOUT_DEBUG
1677 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1678 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1679 (long)coords
.x
, (long)coords
.y
,
1680 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1681 (long)m_CursorLine
->GetLineNumber(),
1682 (long)m_CursorLine
->GetLength()));
1685 dc
.SetBrush(*wxBLACK_BRUSH
);
1686 dc
.SetLogicalFunction(wxXOR
);
1687 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1690 dc
.DrawRectangle(coords
.x
, coords
.y
,
1691 m_CursorSize
.x
, m_CursorSize
.y
);
1692 SetUpdateRect(coords
.x
, coords
.y
);
1693 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
1697 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1698 coords
.x
, coords
.y
);
1699 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
1700 SetUpdateRect(coords
.x
, coords
.y
);
1702 dc
.SetLogicalFunction(wxCOPY
);
1703 //dc.SetBrush(wxNullBrush);
1707 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1709 if(m_UpdateRectValid
)
1710 GrowRect(m_UpdateRect
, x
, y
);
1715 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1716 m_UpdateRect
.height
= 4;// wxGTK :-)
1717 m_UpdateRectValid
= true;
1722 wxLayoutList::StartSelection(void)
1724 WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1725 m_Selection
.m_CursorA
= m_CursorPos
;
1726 m_Selection
.m_CursorB
= m_CursorPos
;
1727 m_Selection
.m_selecting
= true;
1728 m_Selection
.m_valid
= false;
1732 wxLayoutList::ContinueSelection(void)
1734 wxASSERT(m_Selection
.m_selecting
== true);
1735 wxASSERT(m_Selection
.m_valid
== false);
1736 WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1737 m_Selection
.m_CursorB
= m_CursorPos
;
1738 // We always want m_CursorA <= m_CursorB!
1739 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1741 wxPoint help
= m_Selection
.m_CursorB
;
1742 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1743 m_Selection
.m_CursorA
= help
;
1748 wxLayoutList::EndSelection(void)
1750 ContinueSelection();
1751 WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1752 m_Selection
.m_selecting
= false;
1753 m_Selection
.m_valid
= true;
1758 wxLayoutList::IsSelecting(void)
1760 return m_Selection
.m_selecting
;
1764 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1766 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1768 return m_Selection
.m_CursorA
<= cursor
1769 && cursor
<= m_Selection
.m_CursorB
;
1773 /** Tests whether this layout line is selected and needs
1775 @param line to test for
1776 @return 0 = not selected, 1 = fully selected, -1 = partially
1780 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1783 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1785 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1788 CoordType y
= line
->GetLineNumber();
1789 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1791 else if(m_Selection
.m_CursorA
.y
== y
)
1793 *from
= m_Selection
.m_CursorA
.x
;
1794 if(m_Selection
.m_CursorB
.y
== y
)
1795 *to
= m_Selection
.m_CursorB
.x
;
1797 *to
= line
->GetLength();
1800 else if(m_Selection
.m_CursorB
.y
== y
)
1802 *to
= m_Selection
.m_CursorB
.x
;
1803 if(m_Selection
.m_CursorA
.y
== y
)
1804 *from
= m_Selection
.m_CursorA
.x
;
1814 wxLayoutList::DeleteSelection(void)
1816 if(! m_Selection
.m_valid
)
1819 m_Selection
.m_valid
= false;
1821 // Only delete part of the current line?
1822 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
1824 MoveCursorTo(m_Selection
.m_CursorA
);
1825 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
1834 for(firstLine
= m_FirstLine
;
1835 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
1836 firstLine
=firstLine
->GetNextLine())
1838 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
1842 for(lastLine
= m_FirstLine
;
1843 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
1844 lastLine
=lastLine
->GetNextLine())
1846 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
1850 // We now know that the two lines are different:
1852 // First, delete what's left of this line:
1853 MoveCursorTo(m_Selection
.m_CursorA
);
1854 DeleteToEndOfLine();
1856 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
1857 while(nextLine
&& nextLine
!= lastLine
)
1858 nextLine
= nextLine
->DeleteLine(false, this);
1860 // Now nextLine = lastLine;
1861 Delete(1); // This joins firstLine and nextLine
1862 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
1866 firstLine
->RecalculatePositions(1, this);
1869 /// Starts highlighting the selection
1871 wxLayoutList::StartHighlighting(wxDC
&dc
)
1874 dc
.SetTextForeground(m_CurrentSetting
.m_bg
);
1875 dc
.SetTextBackground(m_CurrentSetting
.m_fg
);
1879 /// Ends highlighting the selection
1881 wxLayoutList::EndHighlighting(wxDC
&dc
)
1884 dc
.SetTextForeground(m_CurrentSetting
.m_fg
);
1885 dc
.SetTextBackground(m_CurrentSetting
.m_bg
);
1891 wxLayoutList::Copy(const wxPoint
&from
,
1898 for(firstLine
= m_FirstLine
;
1899 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
1900 firstLine
=firstLine
->GetNextLine())
1902 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
1905 for(lastLine
= m_FirstLine
;
1906 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
1907 lastLine
=lastLine
->GetNextLine())
1909 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
1914 wxLayoutLine
*tmp
= firstLine
;
1915 firstLine
= lastLine
;
1919 wxLayoutList
*llist
= new wxLayoutList();
1921 if(firstLine
== lastLine
)
1923 firstLine
->Copy(llist
, from
.x
, to
.x
);
1927 // Extract objects from first line
1928 firstLine
->Copy(llist
, from
.x
);
1930 // Extract all lines between
1931 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
1933 line
= line
->GetNextLine())
1938 // Extract objects from last line
1939 lastLine
->Copy(llist
, 0, to
.x
);
1945 wxLayoutList::GetSelection(void)
1947 if(! m_Selection
.m_valid
)
1949 if(m_Selection
.m_selecting
)
1955 m_Selection
.m_valid
= false;
1956 return Copy( m_Selection
.m_CursorA
, m_Selection
.m_CursorB
);
1961 #define COPY_SI(what) if(si->what != -1) { m_CurrentSetting.what = si->what; fontChanged = TRUE; }
1964 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
*si
, wxDC
&dc
)
1966 bool fontChanged
= FALSE
;
1973 dc
.SetFont( m_FontCache
.GetFont(m_CurrentSetting
) );
1977 m_CurrentSetting
.m_fg
= si
->m_fg
;
1978 dc
.SetTextForeground(m_CurrentSetting
.m_fg
);
1982 m_CurrentSetting
.m_bg
= si
->m_bg
;
1983 dc
.SetTextBackground(m_CurrentSetting
.m_bg
);
1988 #ifdef WXLAYOUT_DEBUG
1991 wxLayoutList::Debug(void)
1996 for(line
= m_FirstLine
;
1998 line
= line
->GetNextLine())
2005 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2009 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2012 wxString
const & title
)
2019 wxLayoutPrintout::~wxLayoutPrintout()
2024 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2026 // The following bit is taken from the printing sample, let's see
2027 // whether it works for us.
2029 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2030 * the screen text size. This page also draws lines of actual length 5cm
2033 // Get the logical pixels per inch of screen and printer
2034 int ppiScreenX
, ppiScreenY
;
2035 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2036 int ppiPrinterX
, ppiPrinterY
;
2037 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2039 if(ppiScreenX
== 0) // not yet set, need to guess
2044 if(ppiPrinterX
== 0) // not yet set, need to guess
2050 // This scales the DC so that the printout roughly represents the
2051 // the screen scaling. The text point size _should_ be the right size
2052 // but in fact is too small for some reason. This is a detail that will
2053 // need to be addressed at some point but can be fudged for the
2055 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2057 // Now we have to check in case our real page size is reduced
2058 // (e.g. because we're drawing to a print preview memory DC)
2059 int pageWidth
, pageHeight
;
2061 dc
->GetSize(&w
, &h
);
2062 GetPageSizePixels(&pageWidth
, &pageHeight
);
2063 if(pageWidth
!= 0) // doesn't work always
2065 // If printer pageWidth == current DC width, then this doesn't
2066 // change. But w might be the preview bitmap width, so scale down.
2067 scale
= scale
* (float)(w
/(float)pageWidth
);
2069 dc
->SetUserScale(scale
, scale
);
2073 bool wxLayoutPrintout::OnPrintPage(int page
)
2082 top
= (page
- 1)*m_PrintoutHeight
;
2083 bottom
= top
+ m_PrintoutHeight
;
2084 // SetDeviceOrigin() doesn't work here, so we need to manually
2085 // translate all coordinates.
2086 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2087 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2094 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2096 /* We allocate a temporary wxDC for printing, so that we can
2097 determine the correct paper size and scaling. We don't actually
2098 print anything on it. */
2100 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2102 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2105 float scale
= ScaleDC(&psdc
);
2107 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2108 // This sets a left/top origin of 15% and 20%:
2109 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2111 // This is the length of the printable area.
2112 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2113 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2117 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2120 *maxPage
= m_NumOfPages
;
2123 *selPageTo
= m_NumOfPages
;
2124 wxRemoveFile(WXLLIST_TEMPFILE
);
2127 bool wxLayoutPrintout::HasPage(int pageNum
)
2129 return pageNum
<= m_NumOfPages
;
2133 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2134 out. It's a waste of paper anyway.
2138 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2139 wxPoint topleft
, wxPoint bottomright
,
2142 // make backups of all essential parameters
2143 const wxBrush
& brush
= dc
.GetBrush();
2144 const wxPen
& pen
= dc
.GetPen();
2145 const wxFont
& font
= dc
.GetFont();
2147 dc
.SetBrush(*wxWHITE_BRUSH
);
2148 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2149 dc
.DrawRoundedRectangle(topleft
.x
,
2150 topleft
.y
,bottomright
.x
-topleft
.x
,
2151 bottomright
.y
-topleft
.y
);
2152 dc
.SetBrush(*wxBLACK_BRUSH
);
2153 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2154 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2158 page
= "9999/9999 "; // many pages...
2160 dc
.GetTextExtent(page
,&w
,&h
);
2161 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2162 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2163 dc
.GetTextExtent("XXXX", &w
,&h
);
2164 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2175 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2178 for(wxFCEList::iterator i
= m_FontList
.begin();
2179 i
!= m_FontList
.end(); i
++)
2180 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2181 return (**i
).GetFont();
2183 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2185 m_FontList
.push_back(fce
);
2186 return fce
->GetFont();