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
);
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()
377 if(m_font
) delete m_font
;
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 if(m_font
) delete m_font
;
400 m_font
= m_StyleInfo
->GetFont(llist
->GetStyleInfo());
403 // this get called, so that recalculation uses right font sizes
404 Draw(dc
, wxPoint(0,0), llist
);
408 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
410 The wxLayoutLine object
412 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
414 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
417 m_Width
= m_Height
= 0;
422 RecalculatePosition(llist
);
425 m_LineNumber
= m_Previous
->GetLineNumber()+1;
426 m_Next
= m_Previous
->GetNextLine();
427 m_Previous
->m_Next
= this;
428 m_Height
= m_Previous
->GetHeight();
432 m_Next
->m_Previous
= this;
433 m_Next
->MoveLines(+1);
434 m_Next
->RecalculatePositions(1,llist
);
438 wxLayoutLine::~wxLayoutLine()
440 // kbList cleans itself
444 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
446 wxASSERT(m_Previous
|| GetLineNumber() == 0);
450 m_Position
= m_Previous
->GetPosition();
451 m_Position
.y
+= m_Previous
->GetHeight();
454 m_Position
= wxPoint(0,0);
455 llist
->SetUpdateRect(m_Position
);
460 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
462 wxASSERT(recurse
>= 0);
463 wxPoint pos
= m_Position
;
464 CoordType height
= m_Height
;
466 // WXLO_TRACE("RecalculatePositions()");
467 RecalculatePosition(llist
);
471 m_Next
->RecalculatePositions(--recurse
, llist
);
472 else if(pos
!= m_Position
|| m_Height
!= height
)
473 m_Next
->RecalculatePositions(0, llist
);
477 wxLayoutObjectList::iterator
478 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
482 wxLayoutObjectList::iterator
485 CoordType x
= 0, len
;
487 /* We search through the objects. As we don't like returning the
488 object that the cursor is behind, we just remember such an
489 object in "found" so we can return it if there is really no
490 further object following it. */
491 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
493 len
= (**i
).GetLength();
494 if( x
<= xpos
&& xpos
<= x
+ len
)
497 if(xpos
== x
+ len
) // is there another object behind?
499 else // we are really inside this object
502 x
+= (**i
).GetLength();
504 return found
; // ==NULL if really none found
507 wxLayoutObjectList::iterator
508 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
509 CoordType xpos
, CoordType
*cxpos
,
514 wxLayoutObjectList::iterator i
;
515 CoordType x
= 0, cx
= 0, width
;
517 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
519 //FIXME! (**i).Layout(dc, NULL);
520 width
= (**i
).GetWidth();
521 if( x
<= xpos
&& xpos
<= x
+ width
)
523 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
524 // WXLO_DEBUG(("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos));
525 if(found
) *found
= true;
528 x
+= (**i
).GetWidth();
529 cx
+= (**i
).GetLength();
531 // behind last object:
533 if(found
) *found
= false;
534 return m_ObjectList
.tail();
537 /** Finds text in this line.
538 @param needle the text to find
539 @param xpos the position where to start the search
540 @return the cursoor coord where it was found or -1
543 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
= 0) const
548 wxString
const *text
;
550 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
552 if(cpos
>= xpos
) // search from here!
554 if((**i
).GetType() == WXLO_TYPE_TEXT
)
556 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
557 relpos
= text
->Find(needle
);
558 if(relpos
>= cpos
-xpos
) // -1 if not found
563 cpos
+= (**i
).GetLength();
566 return -1; // not found
570 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
573 wxASSERT(obj
!= NULL
);
575 wxLOiterator i
= FindObject(xpos
, &offset
);
578 if(xpos
== 0 ) // aha, empty line!
580 m_ObjectList
.push_back(obj
);
581 m_Length
+= obj
->GetLength();
588 CoordType len
= (**i
).GetLength();
589 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
590 { // insert before this object
591 m_ObjectList
.insert(i
,obj
);
592 m_Length
+= obj
->GetLength();
597 if( i
== m_ObjectList
.tail()) // last object?
598 m_ObjectList
.push_back(obj
);
600 { // insert after current object
602 m_ObjectList
.insert(i
,obj
);
604 m_Length
+= obj
->GetLength();
607 /* Otherwise we need to split the current object.
608 Fortunately this can only be a text object. */
609 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
610 wxString left
, right
;
611 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
612 left
= tobj
->GetText().substr(0,offset
);
613 right
= tobj
->GetText().substr(offset
,len
-offset
);
614 // current text object gets set to right half
615 tobj
->GetText() = right
; // set new text
616 // before it we insert the new object
617 m_ObjectList
.insert(i
,obj
);
618 m_Length
+= obj
->GetLength();
619 // and before that we insert the left half
620 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
625 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
629 wxLOiterator i
= FindObject(xpos
, &offset
);
630 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
632 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
633 tobj
->GetText().insert(offset
, text
);
634 m_Length
+= text
.Length();
639 return Insert(xpos
, new wxLayoutObjectText(text
));
643 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
645 CoordType offset
, len
;
649 wxLOiterator i
= FindObject(xpos
, &offset
);
652 if(i
== NULLIT
) return npos
;
653 // now delete from that object:
654 if((**i
).GetType() != WXLO_TYPE_TEXT
)
656 if(offset
!= 0) // at end of line after a non-text object
659 len
= (**i
).GetLength();
662 m_ObjectList
.erase(i
);
666 // tidy up: remove empty text objects
667 if((**i
).GetLength() == 0)
669 m_ObjectList
.erase(i
);
673 CoordType max
= (**i
).GetLength() - offset
;
674 if(npos
< max
) max
= npos
;
677 if(xpos
== GetLength())
680 { // at the end of an object
681 // move to begin of next object:
683 continue; // start over
688 if(offset
== 0 && max
== (**i
).GetLength())
689 m_ObjectList
.erase(i
); // remove the whole object
691 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
698 wxLayoutLine::DeleteWord(CoordType xpos
)
703 wxLOiterator i
= FindObject(xpos
, &offset
);
707 if(i
== NULLIT
) return false;
708 if((**i
).GetType() != WXLO_TYPE_TEXT
)
710 // This should only happen when at end of line, behind a non-text
712 if(offset
== (**i
).GetLength()) return false;
713 m_Length
-= (**i
).GetLength(); // -1
714 m_ObjectList
.erase(i
);
715 return true; // we are done
719 if(offset
== (**i
).GetLength()) // at end of object
724 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
726 wxString str
= tobj
->GetText();
727 str
= str
.substr(offset
,str
.Length()-offset
);
728 // Find out how many positions we need to delete:
729 // 1. eat leading space
730 while(isspace(str
.c_str()[count
])) count
++;
731 // 2. eat the word itself:
732 while(isalnum(str
.c_str()[count
])) count
++;
734 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
735 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
740 wxASSERT(0); // we should never arrive here
744 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
746 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
747 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
750 m_Next
->MoveLines(-1);
751 m_Next
->RecalculatePositions(1, llist
);
753 wxLayoutLine
*next
= m_Next
;
759 wxLayoutLine::Draw(wxDC
&dc
,
761 const wxPoint
& offset
) const
763 wxLayoutObjectList::iterator i
;
764 wxPoint pos
= offset
;
765 pos
= pos
+ GetPosition();
769 CoordType xpos
= 0; // cursorpos, lenght of line
771 CoordType from
, to
, tempto
;
772 int highlight
= llist
->IsSelected(this, &from
, &to
);
773 // WXLO_DEBUG(("highlight=%d", highlight ));
774 if(highlight
== 1) // we need to draw the whole line inverted!
775 llist
->StartHighlighting(dc
);
777 llist
->EndHighlighting(dc
);
779 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
781 if(highlight
== -1) // partially highlight line
783 // parts of the line need highlighting
784 tempto
= xpos
+(**i
).GetLength();
785 if(tempto
>= from
&& xpos
<= to
)
788 if(tempto
> (**i
).GetLength())
789 tempto
= (**i
).GetLength();
790 CoordType tmp
= from
-xpos
;
792 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, tempto
);
796 llist
->EndHighlighting(dc
); // FIXME! inefficient
797 (**i
).Draw(dc
, pos
, llist
);
801 (**i
).Draw(dc
, pos
, llist
);
802 pos
.x
+= (**i
).GetWidth();
803 xpos
+= (**i
).GetLength();
808 wxLayoutLine::Layout(wxDC
&dc
,
814 wxLayoutObjectList::iterator i
;
817 oldHeight
= m_Height
;
819 topHeight
, bottomHeight
; // above and below baseline
822 objTopHeight
, objBottomHeight
;
825 m_Height
= 0; m_BaseLine
= 0;
827 topHeight
= 0; bottomHeight
= 0;
829 bool cursorFound
= false;
833 *cursorPos
= m_Position
;
834 if(cursorSize
) *cursorSize
= wxPoint(0,0);
837 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
839 (**i
).Layout(dc
, llist
);
840 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
842 if(cursorPos
&& ! cursorFound
)
843 { // we need to check whether the text cursor is here
844 len
= (**i
).GetLength();
845 if(count
<= cx
&& count
+len
> cx
)
847 if((**i
).GetType() == WXLO_TYPE_TEXT
)
849 len
= cx
- count
; // pos in object
850 CoordType width
, height
, descent
;
851 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
852 &width
, &height
, &descent
);
853 cursorPos
->x
+= width
;
854 cursorPos
->y
= m_Position
.y
;
856 if(len
< (**i
).GetLength())
857 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
859 str
= WXLO_CURSORCHAR
;
860 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
861 wxASSERT(cursorSize
);
862 // Just in case some joker inserted an empty string object:
863 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
864 if(height
== 0) height
= objHeight
;
865 cursorSize
->x
= width
;
866 cursorSize
->y
= height
;
867 cursorFound
= true; // no more checks
870 { // on some other object
871 CoordType top
, bottom
; // unused
872 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
873 cursorPos
->y
= m_Position
.y
;
874 cursorFound
= true; // no more checks
880 cursorPos
->x
+= (**i
).GetWidth();
885 if(objHeight
> m_Height
) m_Height
= objHeight
;
886 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
887 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
889 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
890 topHeight
+bottomHeight
;
891 m_BaseLine
= topHeight
;
895 if(GetPreviousLine()) // empty line
897 m_Height
= GetPreviousLine()->GetHeight();
898 m_BaseLine
= GetPreviousLine()->m_BaseLine
;
902 CoordType width
, height
, descent
;
903 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
905 m_BaseLine
= m_Height
- descent
;
910 // tell next line about coordinate change
911 if(m_Next
&& objHeight
!= oldHeight
)
912 m_Next
->RecalculatePositions(0, llist
);
914 // We need to check whether we found a valid cursor size:
917 // this might be the case if the cursor is at the end of the
918 // line or on a command object:
919 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
921 CoordType width
, height
, descent
;
922 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
923 cursorSize
->x
= width
;
924 cursorSize
->y
= height
;
926 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
927 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
933 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
938 { // insert an empty line before this one
939 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
940 if(m_Previous
== NULL
)
941 { // We were in first line, need to link in new empty line
945 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
949 m_Next
->RecalculatePositions(1, llist
);
954 wxLOiterator i
= FindObject(xpos
, &offset
);
956 // must be at the end of the line then
957 return new wxLayoutLine(this, llist
);
960 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
961 // split object at i:
962 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
964 wxString left
, right
;
965 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
966 left
= tobj
->GetText().substr(0,offset
);
967 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
968 // current text object gets set to left half
969 tobj
->GetText() = left
; // set new text
970 newLine
->Append(new wxLayoutObjectText(right
));
971 m_Length
-= right
.Length();
972 i
++; // don't move this object to the new list
976 i
++; // move objects from here to new list
978 while(i
!= m_ObjectList
.end())
981 m_Length
-= (**i
).GetLength();
982 m_ObjectList
.remove(i
); // remove without deleting it
985 m_Next
->RecalculatePositions(2, llist
);
991 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
993 wxASSERT(GetNextLine());
994 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
997 for(i
= list
.begin(); i
!= list
.end();)
1000 list
.remove(i
); // remove without deleting it
1002 wxASSERT(list
.empty());
1003 wxLayoutLine
*oldnext
= GetNextLine();
1004 SetNext(GetNextLine()->GetNextLine());
1006 RecalculatePositions(1, llist
);
1010 wxLayoutLine::GetWrapPosition(CoordType column
)
1013 wxLOiterator i
= FindObject(column
, &offset
);
1014 if(i
== NULLIT
) return -1; // cannot wrap
1016 // go backwards through the list and look for space in text objects
1019 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1023 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1030 }while(offset
!= -1);
1031 i
--; // move on to previous object
1035 column
-= (**i
).GetLength();
1039 offset
= (**i
).GetLength();
1040 }while(i
!= NULLIT
);
1041 /* If we reached the begin of the list and have more than one
1042 object, that one is longer than the margin, so break behind
1045 i
= m_ObjectList
.begin();
1046 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1048 pos
+= (**i
).GetLength();
1051 if(i
== NULLIT
) return -1; //why should this happen?
1052 pos
+= (**i
).GetLength();
1054 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1056 pos
+= (**i
).GetLength();
1059 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1060 // now we are at the second text object:
1061 pos
-= (**i
).GetLength();
1062 return pos
; // in front of it
1066 #ifdef WXLAYOUT_DEBUG
1068 wxLayoutLine::Debug(void)
1071 wxPoint pos
= GetPosition();
1072 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
1073 (long int) GetLineNumber(),
1074 (long int) pos
.x
, (long int) pos
.y
,
1075 (long int) GetHeight()));
1076 if(m_ObjectList
.begin() != NULLIT
)
1077 (**m_ObjectList
.begin()).Debug();
1083 wxLayoutLine::Copy(wxLayoutList
*llist
,
1087 CoordType firstOffset
, lastOffset
;
1089 if(to
== -1) to
= GetLength();
1091 wxLOiterator first
= FindObject(from
, &firstOffset
);
1092 wxLOiterator last
= FindObject(to
, &lastOffset
);
1094 // Common special case: only one object
1095 if( *first
== *last
)
1097 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1099 llist
->Insert(new wxLayoutObjectText(
1100 ((wxLayoutObjectText
1101 *)*first
)->GetText().substr(firstOffset
,
1102 lastOffset
-firstOffset
))
1106 else // what can we do?
1108 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1109 llist
->Insert( (**first
).Copy() );
1114 // If we reach here, we can safely copy the whole first object from
1115 // the firstOffset position on:
1116 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1118 llist
->Insert(new wxLayoutObjectText(
1119 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1122 else if(firstOffset
== 0)
1123 llist
->Insert( (**first
).Copy() );
1124 // else nothing to copy :-(
1126 // Now we copy all objects before the last one:
1127 wxLOiterator i
= first
; i
++;
1128 for( ; i
!= last
; i
++)
1129 llist
->Insert( (**i
).Copy() );
1131 // And now the last object:
1134 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1136 llist
->Insert(new wxLayoutObjectText(
1137 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1141 llist
->Insert( (**last
).Copy() );
1145 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1147 The wxLayoutList object
1149 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1151 wxLayoutList::wxLayoutList()
1153 m_DefaultSetting
= NULL
;
1155 m_ColourFG
= *wxBLACK
;
1156 m_ColourBG
= *wxWHITE
;
1157 InvalidateUpdateRect();
1161 wxLayoutList::~wxLayoutList()
1164 m_FirstLine
->DeleteLine(false, this);
1168 wxLayoutList::Empty(void)
1171 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1173 m_CursorPos
= wxPoint(0,0);
1174 m_CursorScreenPos
= wxPoint(0,0);
1175 m_CursorSize
= wxPoint(0,0);
1176 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1177 m_CursorLine
= m_FirstLine
;
1178 InvalidateUpdateRect();
1183 wxLayoutList::InternalClear(void)
1186 if(m_DefaultSetting
)
1188 delete m_DefaultSetting
;
1189 m_DefaultSetting
= NULL
;
1191 m_Selection
.m_selecting
= false;
1192 m_Selection
.m_valid
= false;
1194 m_CurrentSetting
.family
= wxSWISS
;
1195 m_CurrentSetting
.size
= WXLO_DEFAULTFONTSIZE
;
1196 m_CurrentSetting
.style
= wxNORMAL
;
1197 m_CurrentSetting
.weight
= wxNORMAL
;
1198 m_CurrentSetting
.underline
= 0;
1202 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1203 int underline
, wxColour
*fg
,
1206 if(family
!= -1) m_CurrentSetting
.family
= family
;
1207 if(size
!= -1) m_CurrentSetting
.size
= size
;
1208 if(style
!= -1) m_CurrentSetting
.style
= style
;
1209 if(weight
!= -1) m_CurrentSetting
.weight
= weight
;
1210 if(underline
!= -1) m_CurrentSetting
.underline
= underline
!= 0;
1213 m_CurrentSetting
.fg_valid
= true;
1214 m_CurrentSetting
.fg_red
= fg
->Red();
1215 m_CurrentSetting
.fg_blue
= fg
->Blue();
1216 m_CurrentSetting
.fg_green
= fg
->Green();
1220 m_CurrentSetting
.bg_valid
= true;
1221 m_CurrentSetting
.bg_red
= bg
->Red();
1222 m_CurrentSetting
.bg_blue
= bg
->Blue();
1223 m_CurrentSetting
.bg_green
= bg
->Green();
1226 new wxLayoutObjectCmd(
1227 m_CurrentSetting
.size
,
1228 m_CurrentSetting
.family
,
1229 m_CurrentSetting
.style
,
1230 m_CurrentSetting
.weight
,
1231 m_CurrentSetting
.underline
, fg
, bg
));
1235 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1236 int underline
, char const *fg
, char const *bg
)
1244 cfg
= wxTheColourDatabase
->FindColour(fg
);
1246 cbg
= wxTheColourDatabase
->FindColour(bg
);
1248 SetFont(size
,family
,style
,weight
,underline
,cfg
,cbg
);
1252 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1253 int underline
, wxColour
*fg
, wxColour
*bg
)
1257 if(m_DefaultSetting
)
1258 delete m_DefaultSetting
;
1260 m_DefaultSetting
= new
1261 wxLayoutStyleInfo(family
,size
,style
,weight
,underline
,fg
,bg
);
1265 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1270 for(line
= m_FirstLine
;
1272 line
= line
->GetNextLine())
1274 if(line
->GetLineNumber() >= cpos
.y
)
1276 xpos
= line
->FindText(needle
,
1277 (line
->GetLineNumber() == cpos
.y
) ?
1280 return wxPoint(xpos
, line
->GetLineNumber());
1283 return wxPoint(-1,-1);
1288 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1290 SetUpdateRect(m_CursorScreenPos
);
1291 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1292 wxLayoutLine
*line
= m_FirstLine
;
1293 while(line
&& line
->GetLineNumber() != p
.y
)
1294 line
= line
->GetNextLine();
1295 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1297 m_CursorPos
.y
= p
.y
;
1298 m_CursorLine
= line
;
1299 CoordType len
= line
->GetLength();
1302 m_CursorPos
.x
= p
.x
;
1307 m_CursorPos
.x
= len
;
1315 wxLayoutList::MoveCursorVertically(int n
)
1317 SetUpdateRect(m_CursorScreenPos
);
1318 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1320 if(n
< 0) // move up
1322 if(m_CursorLine
== m_FirstLine
) return false;
1323 while(n
< 0 && m_CursorLine
)
1325 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1331 m_CursorLine
= m_FirstLine
;
1337 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1338 m_CursorPos
.x
= m_CursorLine
->GetLength();
1344 wxLayoutLine
*last
= m_CursorLine
;
1345 if(! m_CursorLine
->GetNextLine()) return false;
1346 while(n
> 0 && m_CursorLine
)
1350 m_CursorLine
= m_CursorLine
->GetNextLine();
1354 m_CursorLine
= last
;
1360 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1361 m_CursorPos
.x
= m_CursorLine
->GetLength();
1369 wxLayoutList::MoveCursorHorizontally(int n
)
1371 SetUpdateRect(m_CursorScreenPos
);
1372 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1376 if(m_CursorPos
.x
== 0) // at begin of line
1378 if(! MoveCursorVertically(-1))
1380 MoveCursorToEndOfLine();
1385 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1386 m_CursorPos
.x
-= move
; n
+= move
;
1391 int len
= m_CursorLine
->GetLength();
1392 if(m_CursorPos
.x
== len
) // at end of line
1394 if(! MoveCursorVertically(1))
1396 MoveCursorToBeginOfLine();
1401 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1402 m_CursorPos
.x
+= move
;
1409 wxLayoutList::Insert(wxString
const &text
)
1411 wxASSERT(m_CursorLine
);
1412 SetUpdateRect(m_CursorScreenPos
);
1413 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1414 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1415 m_CursorPos
.x
+= text
.Length();
1416 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1421 wxLayoutList::Insert(wxLayoutObject
*obj
)
1423 wxASSERT(m_CursorLine
);
1424 SetUpdateRect(m_CursorScreenPos
);
1425 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1426 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1427 m_CursorPos
.x
+= obj
->GetLength();
1428 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1433 wxLayoutList::LineBreak(void)
1435 wxASSERT(m_CursorLine
);
1436 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1437 SetUpdateRect(m_CursorScreenPos
);
1438 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1439 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1440 if(setFirst
) // we were at beginning of first line
1441 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1444 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1449 wxLayoutList::WrapLine(CoordType column
)
1451 if(m_CursorPos
.x
<= column
|| column
< 1)
1452 return false; // do nothing yet
1455 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1457 return false; // cannot break line
1459 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1460 m_CursorPos
.x
= xpos
;
1461 SetUpdateRect(m_CursorScreenPos
);
1462 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1464 Delete(1); // delete the space
1465 m_CursorPos
.x
= newpos
;
1466 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1472 wxLayoutList::Delete(CoordType npos
)
1474 wxASSERT(m_CursorLine
);
1475 SetUpdateRect(m_CursorScreenPos
);
1476 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1480 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1483 // More to delete, continue on next line.
1484 // First, check if line is empty:
1485 if(m_CursorLine
->GetLength() == 0)
1486 { // in this case, updating could probably be optimised
1488 wxASSERT(DeleteLines(1) == 0);
1497 // Need to join next line
1498 if(! m_CursorLine
->GetNextLine())
1502 m_CursorLine
->MergeNextLine(this);
1508 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1513 wxLayoutList::DeleteLines(int n
)
1515 wxASSERT(m_CursorLine
);
1517 SetUpdateRect(m_CursorScreenPos
);
1518 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1521 if(!m_CursorLine
->GetNextLine())
1522 { // we cannot delete this line, but we can clear it
1523 MoveCursorToBeginOfLine();
1524 DeleteToEndOfLine();
1525 m_CursorLine
->RecalculatePositions(2, this);
1529 line
= m_CursorLine
;
1530 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1532 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1533 wxASSERT(m_FirstLine
);
1534 wxASSERT(m_CursorLine
);
1536 m_CursorLine
->RecalculatePositions(2, this);
1541 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1543 wxLayoutLine
*line
= m_FirstLine
;
1545 // first, make sure everything is calculated - this might not be
1546 // needed, optimise it later
1547 ApplyStyle(m_DefaultSetting
, dc
);
1550 line
->RecalculatePosition(this); // so we don't need to do it all the time
1551 // little condition to speed up redrawing:
1552 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1553 line
= line
->GetNextLine();
1558 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1560 wxASSERT(m_CursorLine
);
1561 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1565 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1567 UpdateCursorScreenPos(dc
);
1568 return m_CursorScreenPos
;
1572 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
)
1574 wxLayoutLine
*line
= m_FirstLine
;
1576 // first, make sure everything is calculated - this might not be
1577 // needed, optimise it later
1578 ApplyStyle(m_DefaultSetting
, dc
);
1581 if(line
== m_CursorLine
)
1582 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1584 line
->Layout(dc
, this);
1585 // little condition to speed up redrawing:
1586 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1587 line
= line
->GetNextLine();
1590 ///FIXME: disabled for now
1592 // can only be 0 if we are on the first line and have no next line
1593 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1594 m_CursorLine
->GetNextLine() == NULL
&&
1595 m_CursorLine
== m_FirstLine
));
1597 SetUpdateRect(m_CursorScreenPos
);
1598 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1602 wxLayoutList::Draw(wxDC
&dc
,
1603 wxPoint
const &offset
,
1607 wxLayoutLine
*line
= m_FirstLine
;
1610 ApplyStyle(m_DefaultSetting
, dc
);
1611 wxBrush
brush(m_ColourBG
, wxSOLID
);
1616 // only draw if between top and bottom:
1617 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1618 line
->Draw(dc
, this, offset
);
1619 // little condition to speed up redrawing:
1620 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1621 line
= line
->GetNextLine();
1623 InvalidateUpdateRect();
1625 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
1626 m_Selection
.m_valid
? "valid" : "invalid",
1627 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1628 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
1632 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1636 // First, find the right line:
1637 wxLayoutLine
*line
= m_FirstLine
;
1640 // we need to run a layout here to get font sizes right :-(
1641 ApplyStyle(m_DefaultSetting
, dc
);
1644 p
= line
->GetPosition();
1645 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1647 line
->Layout(dc
, this);
1648 line
= line
->GetNextLine();
1652 if(found
) *found
= false;
1653 return NULL
; // not found
1655 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1656 // Now, find the object in the line:
1657 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1658 cursorPos
? & cursorPos
->x
: NULL
,
1660 return (i
== NULLIT
) ? NULL
: *i
;
1665 wxLayoutList::GetSize(void) const
1668 *line
= m_FirstLine
,
1671 return wxPoint(0,0);
1673 wxPoint
maxPoint(0,0);
1678 if(line
->GetWidth() > maxPoint
.x
)
1679 maxPoint
.x
= line
->GetWidth();
1681 line
= line
->GetNextLine();
1684 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1690 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1693 coords
= m_CursorScreenPos
;
1694 coords
.x
+= translate
.x
;
1695 coords
.y
+= translate
.y
;
1697 #ifdef WXLAYOUT_DEBUG
1698 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1699 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1700 (long)coords
.x
, (long)coords
.y
,
1701 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1702 (long)m_CursorLine
->GetLineNumber(),
1703 (long)m_CursorLine
->GetLength()));
1706 dc
.SetBrush(*wxBLACK_BRUSH
);
1707 dc
.SetLogicalFunction(wxXOR
);
1708 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1711 dc
.DrawRectangle(coords
.x
, coords
.y
,
1712 m_CursorSize
.x
, m_CursorSize
.y
);
1713 SetUpdateRect(coords
.x
, coords
.y
);
1714 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
1718 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1719 coords
.x
, coords
.y
);
1720 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
1721 SetUpdateRect(coords
.x
, coords
.y
);
1723 dc
.SetLogicalFunction(wxCOPY
);
1724 //dc.SetBrush(wxNullBrush);
1728 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1730 if(m_UpdateRectValid
)
1731 GrowRect(m_UpdateRect
, x
, y
);
1736 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1737 m_UpdateRect
.height
= 4;// wxGTK :-)
1738 m_UpdateRectValid
= true;
1743 wxLayoutList::StartSelection(void)
1745 WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1746 m_Selection
.m_CursorA
= m_CursorPos
;
1747 m_Selection
.m_CursorB
= m_CursorPos
;
1748 m_Selection
.m_selecting
= true;
1749 m_Selection
.m_valid
= false;
1753 wxLayoutList::ContinueSelection(void)
1755 wxASSERT(m_Selection
.m_selecting
== true);
1756 wxASSERT(m_Selection
.m_valid
== false);
1757 WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1758 m_Selection
.m_CursorB
= m_CursorPos
;
1759 // We always want m_CursorA <= m_CursorB!
1760 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1762 wxPoint help
= m_Selection
.m_CursorB
;
1763 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1764 m_Selection
.m_CursorA
= help
;
1769 wxLayoutList::EndSelection(void)
1771 ContinueSelection();
1772 WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1773 m_Selection
.m_selecting
= false;
1774 m_Selection
.m_valid
= true;
1779 wxLayoutList::IsSelecting(void)
1781 return m_Selection
.m_selecting
;
1785 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1787 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1789 return m_Selection
.m_CursorA
<= cursor
1790 && cursor
<= m_Selection
.m_CursorB
;
1794 /** Tests whether this layout line is selected and needs
1796 @param line to test for
1797 @return 0 = not selected, 1 = fully selected, -1 = partially
1801 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1804 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1806 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1809 CoordType y
= line
->GetLineNumber();
1810 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1812 else if(m_Selection
.m_CursorA
.y
== y
)
1814 *from
= m_Selection
.m_CursorA
.x
;
1815 if(m_Selection
.m_CursorB
.y
== y
)
1816 *to
= m_Selection
.m_CursorB
.x
;
1818 *to
= line
->GetLength();
1821 else if(m_Selection
.m_CursorB
.y
== y
)
1823 *to
= m_Selection
.m_CursorB
.x
;
1824 if(m_Selection
.m_CursorA
.y
== y
)
1825 *from
= m_Selection
.m_CursorA
.x
;
1835 wxLayoutList::DeleteSelection(void)
1837 if(! m_Selection
.m_valid
)
1840 m_Selection
.m_valid
= false;
1842 // Only delete part of the current line?
1843 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
1845 MoveCursorTo(m_Selection
.m_CursorA
);
1846 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
1855 for(firstLine
= m_FirstLine
;
1856 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
1857 firstLine
=firstLine
->GetNextLine())
1859 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
1863 for(lastLine
= m_FirstLine
;
1864 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
1865 lastLine
=lastLine
->GetNextLine())
1867 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
1871 // We now know that the two lines are different:
1873 // First, delete what's left of this line:
1874 MoveCursorTo(m_Selection
.m_CursorA
);
1875 DeleteToEndOfLine();
1877 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
1878 while(nextLine
&& nextLine
!= lastLine
)
1879 nextLine
= nextLine
->DeleteLine(false, this);
1881 // Now nextLine = lastLine;
1882 Delete(1); // This joins firstLine and nextLine
1883 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
1887 firstLine
->RecalculatePositions(1, this);
1890 /// Starts highlighting the selection
1892 wxLayoutList::StartHighlighting(wxDC
&dc
)
1895 dc
.SetTextForeground(m_ColourBG
);
1896 dc
.SetTextBackground(m_ColourFG
);
1900 /// Ends highlighting the selection
1902 wxLayoutList::EndHighlighting(wxDC
&dc
)
1905 dc
.SetTextForeground(m_ColourFG
);
1906 dc
.SetTextBackground(m_ColourBG
);
1912 wxLayoutList::Copy(const wxPoint
&from
,
1919 for(firstLine
= m_FirstLine
;
1920 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
1921 firstLine
=firstLine
->GetNextLine())
1923 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
1926 for(lastLine
= m_FirstLine
;
1927 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
1928 lastLine
=lastLine
->GetNextLine())
1930 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
1935 wxLayoutLine
*tmp
= firstLine
;
1936 firstLine
= lastLine
;
1940 wxLayoutList
*llist
= new wxLayoutList();
1942 if(firstLine
== lastLine
)
1944 firstLine
->Copy(llist
, from
.x
, to
.x
);
1948 // Extract objects from first line
1949 firstLine
->Copy(llist
, from
.x
);
1951 // Extract all lines between
1952 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
1954 line
= line
->GetNextLine())
1959 // Extract objects from last line
1960 lastLine
->Copy(llist
, 0, to
.x
);
1966 wxLayoutList::GetSelection(void)
1968 if(! m_Selection
.m_valid
)
1970 if(m_Selection
.m_selecting
)
1976 m_Selection
.m_valid
= false;
1977 return Copy( m_Selection
.m_CursorA
, m_Selection
.m_CursorB
);
1982 #define COPY_SI(what) if(si->what != -1) m_CurrentSetting.what = si->what;
1985 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
*si
, wxDC
&dc
)
1996 m_CurrentSetting
.fg_valid
= true;
1997 m_CurrentSetting
.fg_red
= si
->fg_red
;
1998 m_CurrentSetting
.fg_green
= si
->fg_green
;
1999 m_CurrentSetting
.fg_blue
= si
->fg_blue
;
2003 m_CurrentSetting
.bg_valid
= true;
2004 m_CurrentSetting
.bg_red
= si
->bg_red
;
2005 m_CurrentSetting
.bg_green
= si
->bg_green
;
2006 m_CurrentSetting
.bg_blue
= si
->bg_blue
;
2009 m_ColourFG
= wxColour(m_CurrentSetting
.fg_red
,
2010 m_CurrentSetting
.fg_green
,
2011 m_CurrentSetting
.fg_blue
);
2012 m_ColourBG
= wxColour(m_CurrentSetting
.bg_red
,
2013 m_CurrentSetting
.bg_green
,
2014 m_CurrentSetting
.bg_blue
);
2015 dc
.SetTextForeground(m_ColourFG
);
2016 dc
.SetTextBackground(m_ColourBG
);
2020 #ifdef WXLAYOUT_DEBUG
2023 wxLayoutList::Debug(void)
2028 for(line
= m_FirstLine
;
2030 line
= line
->GetNextLine())
2037 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2041 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2043 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2044 wxString
const & title
)
2051 wxLayoutPrintout::~wxLayoutPrintout()
2056 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2058 // The following bit is taken from the printing sample, let's see
2059 // whether it works for us.
2061 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2062 * the screen text size. This page also draws lines of actual length 5cm
2065 // Get the logical pixels per inch of screen and printer
2066 int ppiScreenX
, ppiScreenY
;
2067 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2068 int ppiPrinterX
, ppiPrinterY
;
2069 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2071 if(ppiScreenX
== 0) // not yet set, need to guess
2076 if(ppiPrinterX
== 0) // not yet set, need to guess
2082 // This scales the DC so that the printout roughly represents the
2083 // the screen scaling. The text point size _should_ be the right size
2084 // but in fact is too small for some reason. This is a detail that will
2085 // need to be addressed at some point but can be fudged for the
2087 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2089 // Now we have to check in case our real page size is reduced
2090 // (e.g. because we're drawing to a print preview memory DC)
2091 int pageWidth
, pageHeight
;
2093 dc
->GetSize(&w
, &h
);
2094 GetPageSizePixels(&pageWidth
, &pageHeight
);
2095 if(pageWidth
!= 0) // doesn't work always
2097 // If printer pageWidth == current DC width, then this doesn't
2098 // change. But w might be the preview bitmap width, so scale down.
2099 scale
= scale
* (float)(w
/(float)pageWidth
);
2101 dc
->SetUserScale(scale
, scale
);
2105 bool wxLayoutPrintout::OnPrintPage(int page
)
2114 top
= (page
- 1)*m_PrintoutHeight
;
2115 bottom
= top
+ m_PrintoutHeight
;
2116 // SetDeviceOrigin() doesn't work here, so we need to manually
2117 // translate all coordinates.
2118 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2119 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2126 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2128 /* We allocate a temporary wxDC for printing, so that we can
2129 determine the correct paper size and scaling. We don't actually
2130 print anything on it. */
2132 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2134 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2137 float scale
= ScaleDC(&psdc
);
2139 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2140 // This sets a left/top origin of 15% and 20%:
2141 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2143 // This is the length of the printable area.
2144 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2145 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2149 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2152 *maxPage
= m_NumOfPages
;
2155 *selPageTo
= m_NumOfPages
;
2156 wxRemoveFile(WXLLIST_TEMPFILE
);
2159 bool wxLayoutPrintout::HasPage(int pageNum
)
2161 return pageNum
<= m_NumOfPages
;
2165 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2166 out. It's a waste of paper anyway.
2170 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2171 wxPoint topleft
, wxPoint bottomright
,
2174 // make backups of all essential parameters
2175 const wxBrush
& brush
= dc
.GetBrush();
2176 const wxPen
& pen
= dc
.GetPen();
2177 const wxFont
& font
= dc
.GetFont();
2179 dc
.SetBrush(*wxWHITE_BRUSH
);
2180 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2181 dc
.DrawRoundedRectangle(topleft
.x
,
2182 topleft
.y
,bottomright
.x
-topleft
.x
,
2183 bottomright
.y
-topleft
.y
);
2184 dc
.SetBrush(*wxBLACK_BRUSH
);
2185 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2186 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2190 page
= "9999/9999 "; // many pages...
2192 dc
.GetTextExtent(page
,&w
,&h
);
2193 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2194 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2195 dc
.GetTextExtent("XXXX", &w
,&h
);
2196 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);