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
;
302 fg_blue
= fg
->Blue();
303 fg_green
= fg
->Green();
311 bg_blue
= bg
->Blue();
312 bg_green
= bg
->Green();
318 #define SET_SI(what) tmp.what = (what != -1) ? what : ( si ? si->what : wxNORMAL);
322 wxLayoutStyleInfo::GetFont(wxLayoutStyleInfo
*si
)
324 wxLayoutStyleInfo tmp
;
332 return new wxFont(tmp
.size
,tmp
.family
,tmp
.style
,tmp
.weight
,tmp
.underline
);
336 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
337 weight
, int underline
,
338 wxColour
*fg
, wxColour
*bg
)
342 wxLayoutStyleInfo(size
,family
,style
,weight
,underline
,fg
,bg
);
343 m_font
= m_StyleInfo
->GetFont(NULL
);
347 wxLayoutObjectCmd::Copy(void)
352 if(m_StyleInfo
->fg_valid
)
354 wxColour(m_StyleInfo
->fg_red
,m_StyleInfo
->fg_green
,m_StyleInfo
->fg_blue
);
355 if(m_StyleInfo
->bg_valid
)
357 wxColour(m_StyleInfo
->bg_red
,m_StyleInfo
->bg_green
,m_StyleInfo
->bg_blue
);
359 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
364 m_StyleInfo
->underline
,
366 obj
->SetUserData(m_UserData
);
374 wxLayoutObjectCmd::~wxLayoutObjectCmd()
381 wxLayoutObjectCmd::GetStyle(void) const
387 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
388 wxLayoutList
*wxllist
,
389 CoordType begin
, CoordType
/* len */)
391 wxASSERT(m_StyleInfo
);
393 wxllist
->ApplyStyle(m_StyleInfo
, dc
);
397 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
399 // this get called, so that recalculation uses right font sizes
400 Draw(dc
, wxPoint(0,0), llist
);
404 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
406 The wxLayoutLine object
408 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
410 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
413 m_Width
= m_Height
= 0;
418 RecalculatePosition(llist
);
421 m_LineNumber
= m_Previous
->GetLineNumber()+1;
422 m_Next
= m_Previous
->GetNextLine();
423 m_Previous
->m_Next
= this;
424 m_Height
= m_Previous
->GetHeight();
428 m_Next
->m_Previous
= this;
429 m_Next
->MoveLines(+1);
430 m_Next
->RecalculatePositions(1,llist
);
434 wxLayoutLine::~wxLayoutLine()
436 // kbList cleans itself
440 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
442 wxASSERT(m_Previous
|| GetLineNumber() == 0);
446 m_Position
= m_Previous
->GetPosition();
447 m_Position
.y
+= m_Previous
->GetHeight();
450 m_Position
= wxPoint(0,0);
451 llist
->SetUpdateRect(m_Position
);
456 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
458 wxASSERT(recurse
>= 0);
459 wxPoint pos
= m_Position
;
460 CoordType height
= m_Height
;
462 // WXLO_TRACE("RecalculatePositions()");
463 RecalculatePosition(llist
);
467 m_Next
->RecalculatePositions(--recurse
, llist
);
468 else if(pos
!= m_Position
|| m_Height
!= height
)
469 m_Next
->RecalculatePositions(0, llist
);
473 wxLayoutObjectList::iterator
474 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
478 wxLayoutObjectList::iterator
481 CoordType x
= 0, len
;
483 /* We search through the objects. As we don't like returning the
484 object that the cursor is behind, we just remember such an
485 object in "found" so we can return it if there is really no
486 further object following it. */
487 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
489 len
= (**i
).GetLength();
490 if( x
<= xpos
&& xpos
<= x
+ len
)
493 if(xpos
== x
+ len
) // is there another object behind?
495 else // we are really inside this object
498 x
+= (**i
).GetLength();
500 return found
; // ==NULL if really none found
503 wxLayoutObjectList::iterator
504 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
505 CoordType xpos
, CoordType
*cxpos
,
510 wxLayoutObjectList::iterator i
;
511 CoordType x
= 0, cx
= 0, width
;
513 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
515 //FIXME! (**i).Layout(dc, NULL);
516 width
= (**i
).GetWidth();
517 if( x
<= xpos
&& xpos
<= x
+ width
)
519 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
520 // WXLO_DEBUG(("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos));
521 if(found
) *found
= true;
524 x
+= (**i
).GetWidth();
525 cx
+= (**i
).GetLength();
527 // behind last object:
529 if(found
) *found
= false;
530 return m_ObjectList
.tail();
533 /** Finds text in this line.
534 @param needle the text to find
535 @param xpos the position where to start the search
536 @return the cursoor coord where it was found or -1
539 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
= 0) const
544 wxString
const *text
;
546 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
548 if(cpos
>= xpos
) // search from here!
550 if((**i
).GetType() == WXLO_TYPE_TEXT
)
552 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
553 relpos
= text
->Find(needle
);
554 if(relpos
>= cpos
-xpos
) // -1 if not found
559 cpos
+= (**i
).GetLength();
562 return -1; // not found
566 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
569 wxASSERT(obj
!= NULL
);
571 wxLOiterator i
= FindObject(xpos
, &offset
);
574 if(xpos
== 0 ) // aha, empty line!
576 m_ObjectList
.push_back(obj
);
577 m_Length
+= obj
->GetLength();
584 CoordType len
= (**i
).GetLength();
585 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
586 { // insert before this object
587 m_ObjectList
.insert(i
,obj
);
588 m_Length
+= obj
->GetLength();
593 if( i
== m_ObjectList
.tail()) // last object?
594 m_ObjectList
.push_back(obj
);
596 { // insert after current object
598 m_ObjectList
.insert(i
,obj
);
600 m_Length
+= obj
->GetLength();
603 /* Otherwise we need to split the current object.
604 Fortunately this can only be a text object. */
605 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
606 wxString left
, right
;
607 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
608 left
= tobj
->GetText().substr(0,offset
);
609 right
= tobj
->GetText().substr(offset
,len
-offset
);
610 // current text object gets set to right half
611 tobj
->GetText() = right
; // set new text
612 // before it we insert the new object
613 m_ObjectList
.insert(i
,obj
);
614 m_Length
+= obj
->GetLength();
615 // and before that we insert the left half
616 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
621 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
625 wxLOiterator i
= FindObject(xpos
, &offset
);
626 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
628 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
629 tobj
->GetText().insert(offset
, text
);
630 m_Length
+= text
.Length();
635 return Insert(xpos
, new wxLayoutObjectText(text
));
639 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
641 CoordType offset
, len
;
645 wxLOiterator i
= FindObject(xpos
, &offset
);
648 if(i
== NULLIT
) return npos
;
649 // now delete from that object:
650 if((**i
).GetType() != WXLO_TYPE_TEXT
)
652 if(offset
!= 0) // at end of line after a non-text object
655 len
= (**i
).GetLength();
658 m_ObjectList
.erase(i
);
662 // tidy up: remove empty text objects
663 if((**i
).GetLength() == 0)
665 m_ObjectList
.erase(i
);
669 CoordType max
= (**i
).GetLength() - offset
;
670 if(npos
< max
) max
= npos
;
673 if(xpos
== GetLength())
676 { // at the end of an object
677 // move to begin of next object:
679 continue; // start over
684 if(offset
== 0 && max
== (**i
).GetLength())
685 m_ObjectList
.erase(i
); // remove the whole object
687 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
694 wxLayoutLine::DeleteWord(CoordType xpos
)
699 wxLOiterator i
= FindObject(xpos
, &offset
);
703 if(i
== NULLIT
) return false;
704 if((**i
).GetType() != WXLO_TYPE_TEXT
)
706 // This should only happen when at end of line, behind a non-text
708 if(offset
== (**i
).GetLength()) return false;
709 m_Length
-= (**i
).GetLength(); // -1
710 m_ObjectList
.erase(i
);
711 return true; // we are done
715 if(offset
== (**i
).GetLength()) // at end of object
720 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
722 wxString str
= tobj
->GetText();
723 str
= str
.substr(offset
,str
.Length()-offset
);
724 // Find out how many positions we need to delete:
725 // 1. eat leading space
726 while(isspace(str
.c_str()[count
])) count
++;
727 // 2. eat the word itself:
728 while(isalnum(str
.c_str()[count
])) count
++;
730 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
731 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
736 wxASSERT(0); // we should never arrive here
740 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
742 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
743 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
746 m_Next
->MoveLines(-1);
747 m_Next
->RecalculatePositions(1, llist
);
749 wxLayoutLine
*next
= m_Next
;
755 wxLayoutLine::Draw(wxDC
&dc
,
757 const wxPoint
& offset
) const
759 wxLayoutObjectList::iterator i
;
760 wxPoint pos
= offset
;
761 pos
= pos
+ GetPosition();
765 CoordType xpos
= 0; // cursorpos, lenght of line
767 CoordType from
, to
, tempto
;
768 int highlight
= llist
->IsSelected(this, &from
, &to
);
769 // WXLO_DEBUG(("highlight=%d", highlight ));
770 if(highlight
== 1) // we need to draw the whole line inverted!
771 llist
->StartHighlighting(dc
);
773 llist
->EndHighlighting(dc
);
775 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
777 if(highlight
== -1) // partially highlight line
779 // parts of the line need highlighting
780 tempto
= xpos
+(**i
).GetLength();
781 if(tempto
>= from
&& xpos
<= to
)
784 if(tempto
> (**i
).GetLength())
785 tempto
= (**i
).GetLength();
786 CoordType tmp
= from
-xpos
;
788 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, tempto
);
792 llist
->EndHighlighting(dc
); // FIXME! inefficient
793 (**i
).Draw(dc
, pos
, llist
);
797 (**i
).Draw(dc
, pos
, llist
);
798 pos
.x
+= (**i
).GetWidth();
799 xpos
+= (**i
).GetLength();
804 wxLayoutLine::Layout(wxDC
&dc
,
810 wxLayoutObjectList::iterator i
;
813 oldHeight
= m_Height
;
815 topHeight
, bottomHeight
; // above and below baseline
818 objTopHeight
, objBottomHeight
;
821 m_Height
= 0; m_BaseLine
= 0;
823 topHeight
= 0; bottomHeight
= 0;
825 bool cursorFound
= false;
829 *cursorPos
= m_Position
;
830 if(cursorSize
) *cursorSize
= wxPoint(0,0);
833 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
835 (**i
).Layout(dc
, llist
);
836 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
838 if(cursorPos
&& ! cursorFound
)
839 { // we need to check whether the text cursor is here
840 len
= (**i
).GetLength();
841 if(count
<= cx
&& count
+len
> cx
)
843 if((**i
).GetType() == WXLO_TYPE_TEXT
)
845 len
= cx
- count
; // pos in object
846 CoordType width
, height
, descent
;
847 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
848 &width
, &height
, &descent
);
849 cursorPos
->x
+= width
;
850 cursorPos
->y
= m_Position
.y
;
852 if(len
< (**i
).GetLength())
853 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
855 str
= WXLO_CURSORCHAR
;
856 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
857 wxASSERT(cursorSize
);
858 // Just in case some joker inserted an empty string object:
859 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
860 if(height
== 0) height
= objHeight
;
861 cursorSize
->x
= width
;
862 cursorSize
->y
= height
;
863 cursorFound
= true; // no more checks
866 { // on some other object
867 CoordType top
, bottom
; // unused
868 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
869 cursorPos
->y
= m_Position
.y
;
870 cursorFound
= true; // no more checks
876 cursorPos
->x
+= (**i
).GetWidth();
881 if(objHeight
> m_Height
) m_Height
= objHeight
;
882 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
883 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
885 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
886 topHeight
+bottomHeight
;
887 m_BaseLine
= topHeight
;
891 if(GetPreviousLine()) // empty line
893 m_Height
= GetPreviousLine()->GetHeight();
894 m_BaseLine
= GetPreviousLine()->m_BaseLine
;
898 CoordType width
, height
, descent
;
899 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
901 m_BaseLine
= m_Height
- descent
;
906 // tell next line about coordinate change
907 if(m_Next
&& objHeight
!= oldHeight
)
908 m_Next
->RecalculatePositions(0, llist
);
910 // We need to check whether we found a valid cursor size:
913 // this might be the case if the cursor is at the end of the
914 // line or on a command object:
915 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
917 CoordType width
, height
, descent
;
918 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
919 cursorSize
->x
= width
;
920 cursorSize
->y
= height
;
922 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
923 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
929 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
934 { // insert an empty line before this one
935 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
936 if(m_Previous
== NULL
)
937 { // We were in first line, need to link in new empty line
941 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
945 m_Next
->RecalculatePositions(1, llist
);
950 wxLOiterator i
= FindObject(xpos
, &offset
);
952 // must be at the end of the line then
953 return new wxLayoutLine(this, llist
);
956 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
957 // split object at i:
958 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
960 wxString left
, right
;
961 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
962 left
= tobj
->GetText().substr(0,offset
);
963 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
964 // current text object gets set to left half
965 tobj
->GetText() = left
; // set new text
966 newLine
->Append(new wxLayoutObjectText(right
));
967 m_Length
-= right
.Length();
968 i
++; // don't move this object to the new list
972 i
++; // move objects from here to new list
974 while(i
!= m_ObjectList
.end())
977 m_Length
-= (**i
).GetLength();
978 m_ObjectList
.remove(i
); // remove without deleting it
981 m_Next
->RecalculatePositions(2, llist
);
987 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
989 wxASSERT(GetNextLine());
990 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
993 for(i
= list
.begin(); i
!= list
.end();)
996 list
.remove(i
); // remove without deleting it
998 wxASSERT(list
.empty());
999 wxLayoutLine
*oldnext
= GetNextLine();
1000 SetNext(GetNextLine()->GetNextLine());
1002 RecalculatePositions(1, llist
);
1006 wxLayoutLine::GetWrapPosition(CoordType column
)
1009 wxLOiterator i
= FindObject(column
, &offset
);
1010 if(i
== NULLIT
) return -1; // cannot wrap
1012 // go backwards through the list and look for space in text objects
1015 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1019 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1026 }while(offset
!= -1);
1027 i
--; // move on to previous object
1031 column
-= (**i
).GetLength();
1035 offset
= (**i
).GetLength();
1036 }while(i
!= NULLIT
);
1037 /* If we reached the begin of the list and have more than one
1038 object, that one is longer than the margin, so break behind
1041 i
= m_ObjectList
.begin();
1042 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1044 pos
+= (**i
).GetLength();
1047 if(i
== NULLIT
) return -1; //why should this happen?
1048 pos
+= (**i
).GetLength();
1050 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1052 pos
+= (**i
).GetLength();
1055 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1056 // now we are at the second text object:
1057 pos
-= (**i
).GetLength();
1058 return pos
; // in front of it
1062 #ifdef WXLAYOUT_DEBUG
1064 wxLayoutLine::Debug(void)
1067 wxPoint pos
= GetPosition();
1068 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
1069 (long int) GetLineNumber(),
1070 (long int) pos
.x
, (long int) pos
.y
,
1071 (long int) GetHeight()));
1072 if(m_ObjectList
.begin() != NULLIT
)
1073 (**m_ObjectList
.begin()).Debug();
1079 wxLayoutLine::Copy(wxLayoutList
*llist
,
1083 CoordType firstOffset
, lastOffset
;
1085 if(to
== -1) to
= GetLength();
1087 wxLOiterator first
= FindObject(from
, &firstOffset
);
1088 wxLOiterator last
= FindObject(to
, &lastOffset
);
1090 // Common special case: only one object
1091 if( *first
== *last
)
1093 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1095 llist
->Insert(new wxLayoutObjectText(
1096 ((wxLayoutObjectText
1097 *)*first
)->GetText().substr(firstOffset
,
1098 lastOffset
-firstOffset
))
1102 else // what can we do?
1104 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1105 llist
->Insert( (**first
).Copy() );
1110 // If we reach here, we can safely copy the whole first object from
1111 // the firstOffset position on:
1112 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1114 llist
->Insert(new wxLayoutObjectText(
1115 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1118 else if(firstOffset
== 0)
1119 llist
->Insert( (**first
).Copy() );
1120 // else nothing to copy :-(
1122 // Now we copy all objects before the last one:
1123 wxLOiterator i
= first
; i
++;
1124 for( ; i
!= last
; i
++)
1125 llist
->Insert( (**i
).Copy() );
1127 // And now the last object:
1130 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1132 llist
->Insert(new wxLayoutObjectText(
1133 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1137 llist
->Insert( (**last
).Copy() );
1141 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1143 The wxLayoutList object
1145 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1147 wxLayoutList::wxLayoutList()
1149 m_DefaultSetting
= NULL
;
1151 m_ColourFG
= *wxBLACK
;
1152 m_ColourBG
= *wxWHITE
;
1153 InvalidateUpdateRect();
1157 wxLayoutList::~wxLayoutList()
1160 m_FirstLine
->DeleteLine(false, this);
1164 wxLayoutList::Empty(void)
1167 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1169 m_CursorPos
= wxPoint(0,0);
1170 m_CursorScreenPos
= wxPoint(0,0);
1171 m_CursorSize
= wxPoint(0,0);
1172 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1173 m_CursorLine
= m_FirstLine
;
1174 InvalidateUpdateRect();
1179 wxLayoutList::InternalClear(void)
1182 if(m_DefaultSetting
)
1184 delete m_DefaultSetting
;
1185 m_DefaultSetting
= NULL
;
1187 m_Selection
.m_selecting
= false;
1188 m_Selection
.m_valid
= false;
1190 m_CurrentSetting
.family
= wxSWISS
;
1191 m_CurrentSetting
.size
= WXLO_DEFAULTFONTSIZE
;
1192 m_CurrentSetting
.style
= wxNORMAL
;
1193 m_CurrentSetting
.weight
= wxNORMAL
;
1194 m_CurrentSetting
.underline
= 0;
1198 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1199 int underline
, wxColour
*fg
,
1202 if(family
!= -1) m_FontFamily
= family
;
1203 if(size
!= -1) m_FontPtSize
= size
;
1204 if(style
!= -1) m_FontStyle
= style
;
1205 if(weight
!= -1) m_FontWeight
= weight
;
1206 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
1208 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
1213 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1214 int underline
, char const *fg
, char const *bg
)
1222 cfg
= wxTheColourDatabase
->FindColour(fg
);
1224 cbg
= wxTheColourDatabase
->FindColour(bg
);
1226 SetFont(size
,family
,style
,weight
,underline
,cfg
,cbg
);
1230 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1231 int underline
, wxColour
*fg
, wxColour
*bg
)
1235 if(m_DefaultSetting
)
1236 delete m_DefaultSetting
;
1238 m_DefaultSetting
= new
1239 wxLayoutStyleInfo(family
,size
,style
,weight
,underline
,fg
,bg
);
1243 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1248 for(line
= m_FirstLine
;
1250 line
= line
->GetNextLine())
1252 if(line
->GetLineNumber() >= cpos
.y
)
1254 xpos
= line
->FindText(needle
,
1255 (line
->GetLineNumber() == cpos
.y
) ?
1258 return wxPoint(xpos
, line
->GetLineNumber());
1261 return wxPoint(-1,-1);
1266 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1268 SetUpdateRect(m_CursorScreenPos
);
1269 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1270 wxLayoutLine
*line
= m_FirstLine
;
1271 while(line
&& line
->GetLineNumber() != p
.y
)
1272 line
= line
->GetNextLine();
1273 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1275 m_CursorPos
.y
= p
.y
;
1276 m_CursorLine
= line
;
1277 CoordType len
= line
->GetLength();
1280 m_CursorPos
.x
= p
.x
;
1285 m_CursorPos
.x
= len
;
1293 wxLayoutList::MoveCursorVertically(int n
)
1295 SetUpdateRect(m_CursorScreenPos
);
1296 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1298 if(n
< 0) // move up
1300 if(m_CursorLine
== m_FirstLine
) return false;
1301 while(n
< 0 && m_CursorLine
)
1303 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1309 m_CursorLine
= m_FirstLine
;
1315 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1316 m_CursorPos
.x
= m_CursorLine
->GetLength();
1322 wxLayoutLine
*last
= m_CursorLine
;
1323 if(! m_CursorLine
->GetNextLine()) return false;
1324 while(n
> 0 && m_CursorLine
)
1328 m_CursorLine
= m_CursorLine
->GetNextLine();
1332 m_CursorLine
= last
;
1338 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1339 m_CursorPos
.x
= m_CursorLine
->GetLength();
1347 wxLayoutList::MoveCursorHorizontally(int n
)
1349 SetUpdateRect(m_CursorScreenPos
);
1350 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1354 if(m_CursorPos
.x
== 0) // at begin of line
1356 if(! MoveCursorVertically(-1))
1358 MoveCursorToEndOfLine();
1363 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1364 m_CursorPos
.x
-= move
; n
+= move
;
1369 int len
= m_CursorLine
->GetLength();
1370 if(m_CursorPos
.x
== len
) // at end of line
1372 if(! MoveCursorVertically(1))
1374 MoveCursorToBeginOfLine();
1379 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1380 m_CursorPos
.x
+= move
;
1387 wxLayoutList::Insert(wxString
const &text
)
1389 wxASSERT(m_CursorLine
);
1390 SetUpdateRect(m_CursorScreenPos
);
1391 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1392 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1393 m_CursorPos
.x
+= text
.Length();
1394 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1399 wxLayoutList::Insert(wxLayoutObject
*obj
)
1401 wxASSERT(m_CursorLine
);
1402 SetUpdateRect(m_CursorScreenPos
);
1403 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1404 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1405 m_CursorPos
.x
+= obj
->GetLength();
1406 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1411 wxLayoutList::LineBreak(void)
1413 wxASSERT(m_CursorLine
);
1414 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1415 SetUpdateRect(m_CursorScreenPos
);
1416 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1417 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1418 if(setFirst
) // we were at beginning of first line
1419 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1422 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1427 wxLayoutList::WrapLine(CoordType column
)
1429 if(m_CursorPos
.x
<= column
|| column
< 1)
1430 return false; // do nothing yet
1433 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1435 return false; // cannot break line
1437 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1438 m_CursorPos
.x
= xpos
;
1439 SetUpdateRect(m_CursorScreenPos
);
1440 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1442 Delete(1); // delete the space
1443 m_CursorPos
.x
= newpos
;
1444 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1450 wxLayoutList::Delete(CoordType npos
)
1452 wxASSERT(m_CursorLine
);
1453 SetUpdateRect(m_CursorScreenPos
);
1454 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1458 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1461 // More to delete, continue on next line.
1462 // First, check if line is empty:
1463 if(m_CursorLine
->GetLength() == 0)
1464 { // in this case, updating could probably be optimised
1466 wxASSERT(DeleteLines(1) == 0);
1475 // Need to join next line
1476 if(! m_CursorLine
->GetNextLine())
1480 m_CursorLine
->MergeNextLine(this);
1486 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1491 wxLayoutList::DeleteLines(int n
)
1493 wxASSERT(m_CursorLine
);
1495 SetUpdateRect(m_CursorScreenPos
);
1496 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1499 if(!m_CursorLine
->GetNextLine())
1500 { // we cannot delete this line, but we can clear it
1501 MoveCursorToBeginOfLine();
1502 DeleteToEndOfLine();
1503 m_CursorLine
->RecalculatePositions(2, this);
1507 line
= m_CursorLine
;
1508 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1510 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1511 wxASSERT(m_FirstLine
);
1512 wxASSERT(m_CursorLine
);
1514 m_CursorLine
->RecalculatePositions(2, this);
1519 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1521 wxLayoutLine
*line
= m_FirstLine
;
1523 // first, make sure everything is calculated - this might not be
1524 // needed, optimise it later
1525 ApplyStyle(m_DefaultSetting
, dc
);
1528 line
->RecalculatePosition(this); // so we don't need to do it all the time
1529 // little condition to speed up redrawing:
1530 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1531 line
= line
->GetNextLine();
1536 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1538 wxASSERT(m_CursorLine
);
1539 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1543 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1545 UpdateCursorScreenPos(dc
);
1546 return m_CursorScreenPos
;
1550 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
)
1552 wxLayoutLine
*line
= m_FirstLine
;
1554 // first, make sure everything is calculated - this might not be
1555 // needed, optimise it later
1556 ApplyStyle(m_DefaultSetting
, dc
);
1559 if(line
== m_CursorLine
)
1560 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1562 line
->Layout(dc
, this);
1563 // little condition to speed up redrawing:
1564 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1565 line
= line
->GetNextLine();
1568 ///FIXME: disabled for now
1570 // can only be 0 if we are on the first line and have no next line
1571 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1572 m_CursorLine
->GetNextLine() == NULL
&&
1573 m_CursorLine
== m_FirstLine
));
1575 SetUpdateRect(m_CursorScreenPos
);
1576 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1580 wxLayoutList::Draw(wxDC
&dc
,
1581 wxPoint
const &offset
,
1585 wxLayoutLine
*line
= m_FirstLine
;
1588 ApplyStyle(m_DefaultSetting
, dc
);
1589 wxBrush
brush(m_ColourBG
, wxSOLID
);
1594 // only draw if between top and bottom:
1595 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1596 line
->Draw(dc
, this, offset
);
1597 // little condition to speed up redrawing:
1598 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1599 line
= line
->GetNextLine();
1601 // can only be 0 if we are on the first line and have no next line
1602 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1603 m_CursorLine
->GetNextLine() == NULL
&&
1604 m_CursorLine
== m_FirstLine
));
1605 InvalidateUpdateRect();
1607 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
1608 m_Selection
.m_valid
? "valid" : "invalid",
1609 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1610 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
1614 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1618 // First, find the right line:
1619 wxLayoutLine
*line
= m_FirstLine
;
1622 // we need to run a layout here to get font sizes right :-(
1623 ApplyStyle(m_DefaultSetting
, dc
);
1626 p
= line
->GetPosition();
1627 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1629 line
->Layout(dc
, this);
1630 line
= line
->GetNextLine();
1634 if(found
) *found
= false;
1635 return NULL
; // not found
1637 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1638 // Now, find the object in the line:
1639 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1640 cursorPos
? & cursorPos
->x
: NULL
,
1642 return (i
== NULLIT
) ? NULL
: *i
;
1647 wxLayoutList::GetSize(void) const
1650 *line
= m_FirstLine
,
1653 return wxPoint(0,0);
1655 wxPoint
maxPoint(0,0);
1660 if(line
->GetWidth() > maxPoint
.x
)
1661 maxPoint
.x
= line
->GetWidth();
1663 line
= line
->GetNextLine();
1666 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1672 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1675 coords
= m_CursorScreenPos
;
1676 coords
.x
+= translate
.x
;
1677 coords
.y
+= translate
.y
;
1679 #ifdef WXLAYOUT_DEBUG
1680 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1681 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1682 (long)coords
.x
, (long)coords
.y
,
1683 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1684 (long)m_CursorLine
->GetLineNumber(),
1685 (long)m_CursorLine
->GetLength()));
1688 dc
.SetBrush(*wxBLACK_BRUSH
);
1689 dc
.SetLogicalFunction(wxXOR
);
1690 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1693 dc
.DrawRectangle(coords
.x
, coords
.y
,
1694 m_CursorSize
.x
, m_CursorSize
.y
);
1695 SetUpdateRect(coords
.x
, coords
.y
);
1696 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
1700 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1701 coords
.x
, coords
.y
);
1702 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
1703 SetUpdateRect(coords
.x
, coords
.y
);
1705 dc
.SetLogicalFunction(wxCOPY
);
1706 //dc.SetBrush(wxNullBrush);
1710 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1712 if(m_UpdateRectValid
)
1713 GrowRect(m_UpdateRect
, x
, y
);
1718 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1719 m_UpdateRect
.height
= 4;// wxGTK :-)
1720 m_UpdateRectValid
= true;
1725 wxLayoutList::StartSelection(void)
1727 WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1728 m_Selection
.m_CursorA
= m_CursorPos
;
1729 m_Selection
.m_CursorB
= m_CursorPos
;
1730 m_Selection
.m_selecting
= true;
1731 m_Selection
.m_valid
= false;
1735 wxLayoutList::ContinueSelection(void)
1737 wxASSERT(m_Selection
.m_selecting
== true);
1738 wxASSERT(m_Selection
.m_valid
== false);
1739 WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1740 m_Selection
.m_CursorB
= m_CursorPos
;
1741 // We always want m_CursorA <= m_CursorB!
1742 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1744 wxPoint help
= m_Selection
.m_CursorB
;
1745 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1746 m_Selection
.m_CursorA
= help
;
1751 wxLayoutList::EndSelection(void)
1753 ContinueSelection();
1754 WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1755 m_Selection
.m_selecting
= false;
1756 m_Selection
.m_valid
= true;
1761 wxLayoutList::IsSelecting(void)
1763 return m_Selection
.m_selecting
;
1767 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1769 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1771 return m_Selection
.m_CursorA
<= cursor
1772 && cursor
<= m_Selection
.m_CursorB
;
1776 /** Tests whether this layout line is selected and needs
1778 @param line to test for
1779 @return 0 = not selected, 1 = fully selected, -1 = partially
1783 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1786 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1788 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1791 CoordType y
= line
->GetLineNumber();
1792 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1794 else if(m_Selection
.m_CursorA
.y
== y
)
1796 *from
= m_Selection
.m_CursorA
.x
;
1797 if(m_Selection
.m_CursorB
.y
== y
)
1798 *to
= m_Selection
.m_CursorB
.x
;
1800 *to
= line
->GetLength();
1803 else if(m_Selection
.m_CursorB
.y
== y
)
1805 *to
= m_Selection
.m_CursorB
.x
;
1806 if(m_Selection
.m_CursorA
.y
== y
)
1807 *from
= m_Selection
.m_CursorA
.x
;
1817 wxLayoutList::DeleteSelection(void)
1819 if(! m_Selection
.m_valid
)
1822 m_Selection
.m_valid
= false;
1824 // Only delete part of the current line?
1825 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
1827 MoveCursorTo(m_Selection
.m_CursorA
);
1828 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
1837 for(firstLine
= m_FirstLine
;
1838 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
1839 firstLine
=firstLine
->GetNextLine())
1841 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
1845 for(lastLine
= m_FirstLine
;
1846 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
1847 lastLine
=lastLine
->GetNextLine())
1849 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
1853 // We now know that the two lines are different:
1855 // First, delete what's left of this line:
1856 MoveCursorTo(m_Selection
.m_CursorA
);
1857 DeleteToEndOfLine();
1859 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
1860 while(nextLine
&& nextLine
!= lastLine
)
1861 nextLine
= nextLine
->DeleteLine(false, this);
1863 // Now nextLine = lastLine;
1864 Delete(1); // This joins firstLine and nextLine
1865 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
1869 firstLine
->RecalculatePositions(1, this);
1872 /// Starts highlighting the selection
1874 wxLayoutList::StartHighlighting(wxDC
&dc
)
1877 dc
.SetTextForeground(m_ColourBG
);
1878 dc
.SetTextBackground(m_ColourFG
);
1882 /// Ends highlighting the selection
1884 wxLayoutList::EndHighlighting(wxDC
&dc
)
1887 dc
.SetTextForeground(m_ColourFG
);
1888 dc
.SetTextBackground(m_ColourBG
);
1894 wxLayoutList::Copy(const wxPoint
&from
,
1901 for(firstLine
= m_FirstLine
;
1902 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
1903 firstLine
=firstLine
->GetNextLine())
1905 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
1908 for(lastLine
= m_FirstLine
;
1909 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
1910 lastLine
=lastLine
->GetNextLine())
1912 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
1917 wxLayoutLine
*tmp
= firstLine
;
1918 firstLine
= lastLine
;
1922 wxLayoutList
*llist
= new wxLayoutList();
1924 if(firstLine
== lastLine
)
1926 firstLine
->Copy(llist
, from
.x
, to
.x
);
1930 // Extract objects from first line
1931 firstLine
->Copy(llist
, from
.x
);
1933 // Extract all lines between
1934 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
1936 line
= line
->GetNextLine())
1941 // Extract objects from last line
1942 lastLine
->Copy(llist
, 0, to
.x
);
1948 wxLayoutList::GetSelection(void)
1950 if(! m_Selection
.m_valid
)
1952 if(m_Selection
.m_selecting
)
1958 m_Selection
.m_valid
= false;
1959 return Copy( m_Selection
.m_CursorA
, m_Selection
.m_CursorB
);
1964 #define COPY_SI(what) if(si->what != -1) m_CurrentSetting.what = si->what;
1967 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
*si
, wxDC
&dc
)
1978 m_CurrentSetting
.fg_valid
= true;
1979 m_CurrentSetting
.fg_red
= si
->fg_red
;
1980 m_CurrentSetting
.fg_green
= si
->fg_green
;
1981 m_CurrentSetting
.fg_blue
= si
->fg_blue
;
1985 m_CurrentSetting
.bg_valid
= true;
1986 m_CurrentSetting
.bg_red
= si
->bg_red
;
1987 m_CurrentSetting
.bg_green
= si
->bg_green
;
1988 m_CurrentSetting
.bg_blue
= si
->bg_blue
;
1991 m_ColourFG
= wxColour(m_CurrentSetting
.fg_red
,
1992 m_CurrentSetting
.fg_green
,
1993 m_CurrentSetting
.fg_blue
);
1994 m_ColourBG
= wxColour(m_CurrentSetting
.bg_red
,
1995 m_CurrentSetting
.bg_green
,
1996 m_CurrentSetting
.bg_blue
);
1997 dc
.SetTextForeground(m_ColourFG
);
1998 dc
.SetTextBackground(m_ColourBG
);
2002 #ifdef WXLAYOUT_DEBUG
2005 wxLayoutList::Debug(void)
2010 for(line
= m_FirstLine
;
2012 line
= line
->GetNextLine())
2019 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2023 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2025 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2026 wxString
const & title
)
2033 wxLayoutPrintout::~wxLayoutPrintout()
2038 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2040 // The following bit is taken from the printing sample, let's see
2041 // whether it works for us.
2043 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2044 * the screen text size. This page also draws lines of actual length 5cm
2047 // Get the logical pixels per inch of screen and printer
2048 int ppiScreenX
, ppiScreenY
;
2049 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2050 int ppiPrinterX
, ppiPrinterY
;
2051 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2053 if(ppiScreenX
== 0) // not yet set, need to guess
2058 if(ppiPrinterX
== 0) // not yet set, need to guess
2064 // This scales the DC so that the printout roughly represents the
2065 // the screen scaling. The text point size _should_ be the right size
2066 // but in fact is too small for some reason. This is a detail that will
2067 // need to be addressed at some point but can be fudged for the
2069 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2071 // Now we have to check in case our real page size is reduced
2072 // (e.g. because we're drawing to a print preview memory DC)
2073 int pageWidth
, pageHeight
;
2075 dc
->GetSize(&w
, &h
);
2076 GetPageSizePixels(&pageWidth
, &pageHeight
);
2077 if(pageWidth
!= 0) // doesn't work always
2079 // If printer pageWidth == current DC width, then this doesn't
2080 // change. But w might be the preview bitmap width, so scale down.
2081 scale
= scale
* (float)(w
/(float)pageWidth
);
2083 dc
->SetUserScale(scale
, scale
);
2087 bool wxLayoutPrintout::OnPrintPage(int page
)
2096 top
= (page
- 1)*m_PrintoutHeight
;
2097 bottom
= top
+ m_PrintoutHeight
;
2098 // SetDeviceOrigin() doesn't work here, so we need to manually
2099 // translate all coordinates.
2100 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2101 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2108 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2110 /* We allocate a temporary wxDC for printing, so that we can
2111 determine the correct paper size and scaling. We don't actually
2112 print anything on it. */
2114 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2116 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2119 float scale
= ScaleDC(&psdc
);
2121 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2122 // This sets a left/top origin of 15% and 20%:
2123 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2125 // This is the length of the printable area.
2126 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2127 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2131 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2134 *maxPage
= m_NumOfPages
;
2137 *selPageTo
= m_NumOfPages
;
2138 wxRemoveFile(WXLLIST_TEMPFILE
);
2141 bool wxLayoutPrintout::HasPage(int pageNum
)
2143 return pageNum
<= m_NumOfPages
;
2147 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2148 out. It's a waste of paper anyway.
2152 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2153 wxPoint topleft
, wxPoint bottomright
,
2156 // make backups of all essential parameters
2157 const wxBrush
& brush
= dc
.GetBrush();
2158 const wxPen
& pen
= dc
.GetPen();
2159 const wxFont
& font
= dc
.GetFont();
2161 dc
.SetBrush(*wxWHITE_BRUSH
);
2162 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2163 dc
.DrawRoundedRectangle(topleft
.x
,
2164 topleft
.y
,bottomright
.x
-topleft
.x
,
2165 bottomright
.y
-topleft
.y
);
2166 dc
.SetBrush(*wxBLACK_BRUSH
);
2167 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2168 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2172 page
= "9999/9999 "; // many pages...
2174 dc
.GetTextExtent(page
,&w
,&h
);
2175 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2176 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2177 dc
.GetTextExtent("XXXX", &w
,&h
);
2178 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);