]> git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxllist.cpp
bad247830333a6f465da4627d01fa7e9db07980b
[wxWidgets.git] / user / wxLayout / wxllist.cpp
1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
3 * *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
5 * *
6 * $Id$
7 *******************************************************************/
8
9 /*
10
11 */
12
13 #ifdef __GNUG__
14 #pragma implementation "wxllist.h"
15 #endif
16
17 #include "wx/wxprec.h"
18 #ifdef __BORLANDC__
19 # pragma hdrstop
20 #endif
21
22 //#include "Mpch.h"
23 #ifdef M_PREFIX
24 # include "gui/wxllist.h"
25 #else
26 # include "wxllist.h"
27 #endif
28
29 #ifndef USE_PCH
30 # include "iostream.h"
31 # include <wx/dc.h>
32 # include <wx/dcps.h>
33 # include <wx/print.h>
34 # include <wx/log.h>
35 #endif
36
37 #include <ctype.h>
38
39 /// This should never really get created
40 #define WXLLIST_TEMPFILE "__wxllist.tmp"
41
42 #ifdef WXLAYOUT_DEBUG
43
44 # define TypewxString(t) g_aTypewxStrings[t]
45 # define WXLO_DEBUG(x) wxLogDebug x
46
47 static const char *g_aTypewxStrings[] =
48 {
49 "invalid", "text", "cmd", "icon"
50 };
51 void
52 wxLayoutObject::Debug(void)
53 {
54 WXLO_DEBUG(("%s",g_aTypewxStrings[GetType()]));
55 }
56 #else
57 # define TypewxString(t) ""
58 # define WXLO_DEBUG(x)
59 #endif
60
61
62 /// Cursors smaller than this disappear in XOR drawing mode
63 #define WXLO_MINIMUM_CURSOR_WIDTH 4
64
65 /// Use this character to estimate a cursor size when none is available.
66 #define WXLO_CURSORCHAR "E"
67 /** @name Helper functions */
68 //@{
69 /// allows me to compare to wxPoints
70 bool operator ==(wxPoint const &p1, wxPoint const &p2)
71 {
72 return p1.x == p2.x && p1.y == p2.y;
73 }
74
75 /// allows me to compare to wxPoints
76 bool operator !=(wxPoint const &p1, wxPoint const &p2)
77 {
78 return p1.x != p2.x || p1.y != p2.y;
79 }
80
81 /// grows a wxRect so that it includes the given point
82
83 static void GrowRect(wxRect &r, const wxPoint & p)
84 {
85 if(r.x > p.x)
86 r.x = p.x;
87 else if(r.x + r.width < p.x)
88 r.width = p.x - r.x;
89
90 if(r.y > p.y)
91 r.y = p.y;
92 else if(r.y + r.height < p.y)
93 r.height = p.y - r.y;
94 }
95 //@}
96
97 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
98
99 wxLayoutObjectText
100
101 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
102
103 wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
104 {
105 m_Text = txt;
106 m_Width = 0;
107 m_Height = 0;
108 m_Top = 0;
109 m_Bottom = 0;
110 }
111
112 wxLayoutObject *
113 wxLayoutObjectText::Copy(void)
114 {
115 wxLayoutObjectText *obj = new wxLayoutObjectText(m_Text);
116 obj->m_Width = m_Width;
117 obj->m_Height = m_Height;
118 obj->m_Top = m_Top;
119 obj->m_Bottom = m_Bottom;
120 obj->SetUserData(m_UserData);
121 return obj;
122 }
123
124 wxPoint
125 wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
126 {
127
128 *top = m_Top; *bottom = m_Bottom;
129 return wxPoint(m_Width, m_Height);
130 }
131
132 void
133 wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords)
134 {
135 dc.DrawText(m_Text, coords.x, coords.y-m_Top);
136 }
137
138 CoordType
139 wxLayoutObjectText::GetOffsetScreen(wxDC &dc, CoordType xpos) const
140 {
141 CoordType
142 offs = 1,
143 maxlen = m_Text.Length();
144 long
145 width = 0,
146 height, descent = 0l;
147
148 if(xpos == 0) return 0; // easy
149
150 while(width < xpos && offs < maxlen)
151 {
152 dc.GetTextExtent(m_Text.substr(0,offs),
153 &width, &height, &descent);
154 offs++;
155 }
156 /* We have to substract 1 to compensate for the offs++, and another
157 one because we don't want to position the cursor behind the
158 object what we clicked on, but before - otherwise it looks
159 funny. */
160 return (xpos > 2) ? offs-2 : 0;
161 }
162
163 void
164 wxLayoutObjectText::Layout(wxDC &dc)
165 {
166 long descent = 0l;
167
168 dc.GetTextExtent(m_Text,&m_Width, &m_Height, &descent);
169 m_Bottom = descent;
170 m_Top = m_Height - m_Bottom;
171 }
172
173 #ifdef WXLAYOUT_DEBUG
174 void
175 wxLayoutObjectText::Debug(void)
176 {
177 wxLayoutObject::Debug();
178 WXLO_DEBUG((" `%s`", m_Text.c_str()));
179 }
180 #endif
181
182 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
183
184 wxLayoutObjectIcon
185
186 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
187
188 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
189 {
190 m_Icon = new wxBitmap(icon);
191 }
192
193 wxLayoutObject *
194 wxLayoutObjectIcon::Copy(void)
195 {
196 wxLayoutObjectIcon *obj = new wxLayoutObjectIcon(new
197 wxBitmap(*m_Icon));
198 obj->SetUserData(m_UserData);
199 return obj;
200 }
201
202 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
203 {
204 m_Icon = icon;
205 }
206
207 void
208 wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords)
209 {
210 dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight(),
211 (m_Icon->GetMask() == NULL) ? FALSE : TRUE);
212 }
213
214 void
215 wxLayoutObjectIcon::Layout(wxDC & /* dc */)
216 {
217 }
218
219 wxPoint
220 wxLayoutObjectIcon::GetSize(CoordType *top, CoordType *bottom) const
221 {
222 *top = m_Icon->GetHeight();
223 *bottom = 0;
224 return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
225 }
226
227
228
229 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
230
231 wxLayoutObjectIcon
232
233 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
234
235 wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
236 weight, bool underline,
237 wxColour const *fg, wxColour const *bg)
238
239 {
240 m_font = new wxFont(size,family,style,weight,underline);
241 m_ColourFG = fg;
242 m_ColourBG = bg;
243 }
244
245 wxLayoutObject *
246 wxLayoutObjectCmd::Copy(void)
247 {
248 wxLayoutStyleInfo si;
249 GetStyle(&si);
250
251 wxLayoutObjectCmd *obj = new wxLayoutObjectCmd(
252 si.size, si.family, si.style, si.weight, si.underline,
253 m_ColourFG, m_ColourBG);
254 obj->SetUserData(m_UserData);
255 return obj;
256 }
257
258
259 wxLayoutObjectCmd::~wxLayoutObjectCmd()
260 {
261 delete m_font;
262 }
263
264 void
265 wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo *si) const
266 {
267 si->size = m_font->GetPointSize();
268 si->family = m_font->GetFamily();
269 si->style = m_font->GetStyle();
270 si->underline = m_font->GetUnderlined();
271 si->weight = m_font->GetWeight();
272
273 si->fg_red = m_ColourFG->Red();
274 si->fg_green = m_ColourFG->Green();
275 si->fg_blue = m_ColourFG->Blue();
276 si->bg_red = m_ColourBG->Red();
277 si->bg_green = m_ColourBG->Green();
278 si->bg_blue = m_ColourBG->Blue();
279 }
280
281 void
282 wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */)
283 {
284 wxASSERT(m_font);
285 dc.SetFont(*m_font);
286 if(m_ColourFG)
287 dc.SetTextForeground(*m_ColourFG);
288 if(m_ColourBG)
289 dc.SetTextBackground(*m_ColourBG);
290 }
291
292 void
293 wxLayoutObjectCmd::Layout(wxDC &dc)
294 {
295 // this get called, so that recalculation uses right font sizes
296 Draw(dc, wxPoint(0,0));
297 }
298
299
300 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
301
302 The wxLayoutLine object
303
304 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305
306 wxLayoutLine::wxLayoutLine(wxLayoutLine *prev)
307 {
308 m_LineNumber = 0;
309 m_Width = m_Height = 0;
310 m_Length = 0;
311 m_Dirty = true;
312 m_Previous = prev;
313 m_Next = NULL;
314 RecalculatePosition();
315 if(m_Previous)
316 {
317 m_LineNumber = m_Previous->GetLineNumber()+1;
318 m_Next = m_Previous->GetNextLine();
319 m_Previous->m_Next = this;
320 m_Height = m_Previous->GetHeight();
321 }
322 if(m_Next)
323 {
324 m_Next->m_Previous = this;
325 m_Next->MoveLines(+1);
326 m_Next->RecalculatePositions(1);
327 }
328 }
329
330 wxLayoutLine::~wxLayoutLine()
331 {
332 // kbList cleans itself
333 }
334
335 wxPoint
336 wxLayoutLine::RecalculatePosition(void)
337 {
338 if(m_Previous)
339 m_Position = m_Previous->GetPosition() +
340 wxPoint(0,m_Previous->GetHeight());
341 else
342 m_Position = wxPoint(0,0);
343 return m_Position;
344 }
345
346 void
347 wxLayoutLine::RecalculatePositions(int recurse)
348 {
349 wxASSERT(recurse >= 0);
350 wxPoint pos = m_Position;
351 CoordType height = m_Height;
352
353 // WXLO_TRACE("RecalculatePositions()");
354 RecalculatePosition();
355 if(m_Next)
356 {
357 if(recurse > 0)
358 {
359 if(m_Next) m_Next->RecalculatePositions(--recurse);
360 }
361 else if(pos != m_Position || m_Height != height)
362 if(m_Next) m_Next->RecalculatePositions();
363 }
364 }
365
366 wxLayoutObjectList::iterator
367 wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const
368 {
369 wxASSERT(xpos >= 0);
370 wxASSERT(offset);
371 wxLayoutObjectList::iterator i;
372 CoordType x = 0, len;
373
374
375 for(i = m_ObjectList.begin(); i != NULLIT; i++)
376 {
377 len = (**i).GetLength();
378 if( x <= xpos && xpos <= x + len )
379 {
380 *offset = xpos-x;
381 return i;
382 }
383 x += (**i).GetLength();
384 }
385 return NULLIT;
386 }
387
388 wxLayoutObjectList::iterator
389 wxLayoutLine::FindObjectScreen(wxDC &dc, CoordType xpos, CoordType *cxpos) const
390 {
391 wxASSERT(cxpos);
392 wxASSERT(cxpos);
393 wxLayoutObjectList::iterator i;
394 CoordType x = 0, cx = 0, width;
395
396 for(i = m_ObjectList.begin(); i != NULLIT; i++)
397 {
398 (**i).Layout(dc);
399 width = (**i).GetWidth();
400 if( x <= xpos && xpos <= x + width )
401 {
402 *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
403 wxLogDebug("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos);
404 return i;
405 }
406 x += (**i).GetWidth();
407 cx += (**i).GetLength();
408 }
409 // behind last object:
410 *cxpos = cx;
411 return m_ObjectList.tail();
412 }
413
414 bool
415 wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
416 {
417 wxASSERT(xpos >= 0);
418 wxASSERT(obj != NULL);
419 CoordType offset;
420 wxLOiterator i = FindObject(xpos, &offset);
421 if(i == NULLIT)
422 {
423 if(xpos == 0 ) // aha, empty line!
424 {
425 m_ObjectList.push_back(obj);
426 m_Length += obj->GetLength();
427 return true;
428 }
429 else
430 return false;
431 }
432
433 CoordType len = (**i).GetLength();
434 if(offset == 0 /*&& i != m_ObjectList.begin()*/) // why?
435 { // insert before this object
436 m_ObjectList.insert(i,obj);
437 m_Length += obj->GetLength();
438 return true;
439 }
440 if(offset == len )
441 {
442 if( i == m_ObjectList.tail()) // last object?
443 m_ObjectList.push_back(obj);
444 else
445 { // insert after current object
446 i++;
447 m_ObjectList.insert(i,obj);
448 }
449 m_Length += obj->GetLength();
450 return true;
451 }
452 /* Otherwise we need to split the current object.
453 Fortunately this can only be a text object. */
454 wxASSERT((**i).GetType() == WXLO_TYPE_TEXT);
455 wxString left, right;
456 wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
457 left = tobj->GetText().substr(0,offset);
458 right = tobj->GetText().substr(offset,len-offset);
459 // current text object gets set to right half
460 tobj->GetText() = right; // set new text
461 // before it we insert the new object
462 m_ObjectList.insert(i,obj);
463 m_Length += obj->GetLength();
464 // and before that we insert the left half
465 m_ObjectList.insert(i,new wxLayoutObjectText(left));
466 return true;
467 }
468
469 bool
470 wxLayoutLine::Insert(CoordType xpos, wxString text)
471 {
472 wxASSERT(xpos >= 0);
473 CoordType offset;
474 wxLOiterator i = FindObject(xpos, &offset);
475 if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
476 {
477 wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
478 tobj->GetText().insert(offset, text);
479 m_Length += text.Length();
480
481 return true;
482 }
483 else
484 return Insert(xpos, new wxLayoutObjectText(text));
485 }
486
487 CoordType
488 wxLayoutLine::Delete(CoordType xpos, CoordType npos)
489 {
490 CoordType offset, len;
491
492 wxASSERT(xpos >= 0);
493 wxASSERT(npos >= 0);
494 wxLOiterator i = FindObject(xpos, &offset);
495 while(npos > 0)
496 {
497 if(i == NULLIT) return npos;
498 // now delete from that object:
499 if((**i).GetType() != WXLO_TYPE_TEXT)
500 {
501 if(offset != 0) // at end of line after a non-text object
502 return npos;
503 // always len == 1:
504 len = (**i).GetLength();
505 m_Length -= len;
506 npos -= len;
507 m_ObjectList.erase(i);
508 }
509 else
510 {
511 // tidy up: remove empty text objects
512 if((**i).GetLength() == 0)
513 {
514 m_ObjectList.erase(i);
515 continue;
516 }
517 // Text object:
518 CoordType max = (**i).GetLength() - offset;
519 if(npos < max) max = npos;
520 if(max == 0)
521 {
522 if(xpos == GetLength())
523 return npos;
524 else
525 { // at the end of an object
526 // move to begin of next object:
527 i++; offset = 0;
528 continue; // start over
529 }
530 }
531 npos -= max;
532 m_Length -= max;
533 if(offset == 0 && max == (**i).GetLength())
534 m_ObjectList.erase(i); // remove the whole object
535 else
536 ((wxLayoutObjectText *)(*i))->GetText().Remove(offset,max);
537 }
538 }
539 return npos;
540 }
541
542 bool
543 wxLayoutLine::DeleteWord(CoordType xpos)
544 {
545 wxASSERT(xpos >= 0);
546 CoordType offset;
547
548 wxLOiterator i = FindObject(xpos, &offset);
549
550 for(;;)
551 {
552 if(i == NULLIT) return false;
553 if((**i).GetType() != WXLO_TYPE_TEXT)
554 {
555 // This should only happen when at end of line, behind a non-text
556 // object:
557 if(offset == (**i).GetLength()) return false;
558 m_Length -= (**i).GetLength(); // -1
559 m_ObjectList.erase(i);
560 return true; // we are done
561 }
562 else
563 { // text object:
564 if(offset == (**i).GetLength()) // at end of object
565 {
566 i++; offset = 0;
567 continue;
568 }
569 wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
570 size_t count = 0;
571 wxString str = tobj->GetText();
572 str = str.substr(offset,str.Length()-offset);
573 // Find out how many positions we need to delete:
574 // 1. eat leading space
575 while(isspace(str.c_str()[count])) count++;
576 // 2. eat the word itself:
577 while(isalnum(str.c_str()[count])) count++;
578 // now delete it:
579 wxASSERT(count+offset <= (size_t) (**i).GetLength());
580 ((wxLayoutObjectText *)*i)->GetText().erase(offset,count);
581 m_Length -= count;
582 return true;
583 }
584 }
585 wxASSERT(0); // we should never arrive here
586 }
587
588 wxLayoutLine *
589 wxLayoutLine::DeleteLine(bool update)
590 {
591 if(m_Next) m_Next->m_Previous = m_Previous;
592 if(m_Previous) m_Previous->m_Next = m_Next;
593 if(update)
594 {
595 m_Next->MoveLines(-1);
596 m_Next->RecalculatePositions(1);
597 }
598 wxLayoutLine *next = m_Next;
599 delete this;
600 return next;
601 }
602
603 void
604 wxLayoutLine::Draw(wxDC &dc, const wxPoint & offset) const
605 {
606 wxLayoutObjectList::iterator i;
607 wxPoint pos = offset;
608 pos = pos + GetPosition();
609
610 pos.y += m_BaseLine;
611
612 for(i = m_ObjectList.begin(); i != NULLIT; i++)
613 {
614 (**i).Draw(dc, pos);
615 pos.x += (**i).GetWidth();
616 }
617 }
618
619 void
620 wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos,
621 wxPoint *cursorSize,
622 int cx)
623 {
624 wxLayoutObjectList::iterator i;
625
626 CoordType
627 oldHeight = m_Height;
628 CoordType
629 topHeight, bottomHeight; // above and below baseline
630 CoordType
631 objHeight = 0,
632 objTopHeight, objBottomHeight;
633 CoordType
634 len, count = 0;
635 m_Height = 0; m_BaseLine = 0;
636 m_Width = 0;
637 topHeight = 0; bottomHeight = 0;
638 wxPoint size;
639 bool cursorFound = false;
640
641 if(cursorPos)
642 {
643 *cursorPos = m_Position;
644 }
645
646 for(i = m_ObjectList.begin(); i != NULLIT; i++)
647 {
648 (**i).Layout(dc);
649 size = (**i).GetSize(&objTopHeight, &objBottomHeight);
650
651 if(cursorPos && ! cursorFound)
652 { // we need to check whether the text cursor is here
653 len = (**i).GetLength();
654 if(count <= cx && count+len > cx)
655 {
656 if((**i).GetType() == WXLO_TYPE_TEXT)
657 {
658 len = cx - count; // pos in object
659 CoordType width, height, descent;
660 dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len),
661 &width, &height, &descent);
662 cursorPos->x += width;
663 cursorPos->y = m_Position.y;
664 wxString str;
665 if(len < (**i).GetLength())
666 str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1);
667 else
668 str = WXLO_CURSORCHAR;
669 dc.GetTextExtent(str, &width, &height, &descent);
670 wxASSERT(cursorSize);
671 // Just in case some joker inserted an empty string object:
672 if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH;
673 if(height == 0) height = objHeight;
674 cursorSize->x = width;
675 cursorSize->y = height;
676 cursorFound = true; // no more checks
677 }
678 else
679 { // on some other object
680 CoordType top, bottom; // unused
681 *cursorSize = (**i).GetSize(&top,&bottom);
682 cursorPos->y = m_Position.y;
683 cursorFound = true; // no more checks
684 }
685 }
686 else
687 {
688 count += len;
689 cursorPos->x += (**i).GetWidth();
690 }
691 } // cursor finding
692 objHeight = size.y;
693 m_Width += size.x;
694 if(objHeight > m_Height) m_Height = objHeight;
695 if(objTopHeight > topHeight) topHeight = objTopHeight;
696 if(objBottomHeight > bottomHeight) bottomHeight = objBottomHeight;
697 }
698 if(topHeight + bottomHeight > m_Height) m_Height =
699 topHeight+bottomHeight;
700 m_BaseLine = topHeight;
701
702 if(m_Height == 0)
703 {
704 if(GetPreviousLine()) // empty line
705 {
706 m_Height = GetPreviousLine()->GetHeight();
707 m_BaseLine = GetPreviousLine()->m_BaseLine;
708 }
709 else
710 {
711 CoordType width, height, descent;
712 dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
713 m_Height = height;
714 m_BaseLine = m_Height - descent;
715 }
716 }
717
718
719 // tell next line about coordinate change
720 if(m_Next && objHeight != oldHeight)
721 m_Next->RecalculatePositions();
722
723 // We need to check whether we found a valid cursor size:
724 if(cursorPos)
725 {
726 // this might be the case if the cursor is at the end of the
727 // line or on a command object:
728 if(cursorSize->y < WXLO_MINIMUM_CURSOR_WIDTH)
729 {
730 if(m_BaseLine > 0)
731 {
732 cursorSize->y = m_BaseLine;
733 if(cursorSize->x < WXLO_MINIMUM_CURSOR_WIDTH) cursorSize->x = WXLO_MINIMUM_CURSOR_WIDTH;
734 }
735 else // empty line
736 {
737 CoordType width, height, descent;
738 dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
739 cursorSize->x = width;
740 cursorSize->y = height;
741 }
742 }
743 if(m_BaseLine >= cursorSize->y) // the normal case anyway
744 cursorPos->y += m_BaseLine-cursorSize->y;
745 }
746 }
747
748
749 wxLayoutLine *
750 wxLayoutLine::Break(CoordType xpos)
751 {
752 wxASSERT(xpos >= 0);
753
754 if(xpos == 0)
755 { // insert an empty line before this one
756 wxLayoutLine *prev = new wxLayoutLine(m_Previous);
757 if(m_Previous == NULL)
758 { // We were in first line, need to link in new empty line
759 // before this.
760 prev->m_Next = this;
761 m_Previous = prev;
762 m_Previous->m_Height = GetHeight(); // this is a wild guess
763 }
764 MoveLines(+1);
765 if(m_Next)
766 m_Next->RecalculatePositions(1);
767 return this;
768 }
769
770 CoordType offset;
771 wxLOiterator i = FindObject(xpos, &offset);
772 if(i == NULLIT)
773 // must be at the end of the line then
774 return new wxLayoutLine(this);
775 // split this line:
776
777 wxLayoutLine *newLine = new wxLayoutLine(this);
778 // split object at i:
779 if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0)
780 {
781 wxString left, right;
782 wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
783 left = tobj->GetText().substr(0,offset);
784 right = tobj->GetText().substr(offset,tobj->GetLength()-offset);
785 // current text object gets set to left half
786 tobj->GetText() = left; // set new text
787 newLine->Append(new wxLayoutObjectText(right));
788 m_Length -= right.Length();
789 i++; // don't move this object to the new list
790 }
791 else
792 if(offset > 0)
793 i++; // move objects from here to new list
794
795 while(i != m_ObjectList.end())
796 {
797 newLine->Append(*i);
798 m_Length -= (**i).GetLength();
799 m_ObjectList.remove(i); // remove without deleting it
800 }
801 if(m_Next)
802 m_Next->RecalculatePositions(2);
803 return newLine;
804 }
805
806
807 void
808 wxLayoutLine::MergeNextLine(void)
809 {
810 wxASSERT(GetNextLine());
811 wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
812 wxLOiterator i;
813
814 for(i = list.begin(); i != list.end();)
815 {
816 Append(*i);
817 list.remove(i); // remove without deleting it
818 }
819 wxASSERT(list.empty());
820 wxLayoutLine *oldnext = GetNextLine();
821 SetNext(GetNextLine()->GetNextLine());
822 delete oldnext;
823 RecalculatePositions(1);
824 }
825
826 CoordType
827 wxLayoutLine::GetWrapPosition(CoordType column)
828 {
829 CoordType offset;
830 wxLOiterator i = FindObject(column, &offset);
831 if(i == NULLIT) return -1; // cannot wrap
832
833 // go backwards through the list and look for space in text objects
834 do
835 {
836 if((**i).GetType() == WXLO_TYPE_TEXT)
837 {
838 do
839 {
840 if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
841 return column;
842 else
843 {
844 offset--;
845 column--;
846 }
847 }while(offset != -1);
848 i--; // move on to previous object
849 }
850 else
851 {
852 column -= (**i).GetLength();
853 i--;
854 }
855 if( i != NULLIT)
856 offset = (**i).GetLength();
857 }while(i != NULLIT);
858 /* If we reached the begin of the list and have more than one
859 object, that one is longer than the margin, so break behind
860 it. */
861 CoordType pos = 0;
862 i = m_ObjectList.begin();
863 while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
864 {
865 pos += (**i).GetLength();
866 i++;
867 }
868 if(i == NULLIT) return -1; //why should this happen?
869 pos += (**i).GetLength();
870 i++;
871 while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
872 {
873 pos += (**i).GetLength();
874 i++;
875 }
876 if(i == NULLIT) return -1; //this is possible, if there is only one text object
877 // now we are at the second text object:
878 pos -= (**i).GetLength();
879 return pos; // in front of it
880 }
881
882
883 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
884
885 The wxLayoutList object
886
887 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
888
889 wxLayoutList::wxLayoutList()
890 {
891 m_DefaultSetting = NULL;
892 m_FirstLine = NULL;
893 InvalidateUpdateRect();
894 Clear();
895 }
896
897 wxLayoutList::~wxLayoutList()
898 {
899 InternalClear();
900 m_FirstLine->DeleteLine(false);
901 }
902
903 void
904 wxLayoutList::Empty(void)
905 {
906 while(m_FirstLine)
907 m_FirstLine = m_FirstLine->DeleteLine(false);
908
909 m_CursorPos = wxPoint(0,0);
910 m_CursorScreenPos = wxPoint(0,0);
911 m_CursorSize = wxPoint(0,0);
912 m_FirstLine = new wxLayoutLine(NULL); // empty first line
913 m_CursorLine = m_FirstLine;
914 }
915
916
917 void
918 wxLayoutList::InternalClear(void)
919 {
920 Empty();
921 if(m_DefaultSetting)
922 {
923 delete m_DefaultSetting;
924 m_DefaultSetting = NULL;
925 }
926 }
927
928 void
929 wxLayoutList::SetFont(int family, int size, int style, int weight,
930 int underline, wxColour const *fg,
931 wxColour const *bg)
932 {
933 if(family != -1) m_FontFamily = family;
934 if(size != -1) m_FontPtSize = size;
935 if(style != -1) m_FontStyle = style;
936 if(weight != -1) m_FontWeight = weight;
937 if(underline != -1) m_FontUnderline = underline != 0;
938
939 if(fg != NULL) m_ColourFG = fg;
940 if(bg != NULL) m_ColourBG = bg;
941
942 Insert(
943 new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
944 m_ColourFG, m_ColourBG));
945 }
946
947 void
948 wxLayoutList::SetFont(int family, int size, int style, int weight,
949 int underline, char const *fg, char const *bg)
950
951 {
952 wxColour const
953 * cfg = NULL,
954 * cbg = NULL;
955
956 if( fg )
957 cfg = wxTheColourDatabase->FindColour(fg);
958 if( bg )
959 cbg = wxTheColourDatabase->FindColour(bg);
960
961 SetFont(family,size,style,weight,underline,cfg,cbg);
962 }
963
964 void
965 wxLayoutList::Clear(int family, int size, int style, int weight,
966 int /* underline */, char const *fg, char const *bg)
967 {
968 InternalClear();
969
970 // set defaults
971 m_FontPtSize = size;
972 m_FontUnderline = false;
973 m_FontFamily = family;
974 m_FontStyle = style;
975 m_FontWeight = weight;
976 m_ColourFG = wxTheColourDatabase->FindColour(fg);
977 m_ColourBG = wxTheColourDatabase->FindColour(bg);
978
979 if(! m_ColourFG) m_ColourFG = wxBLACK;
980 if(! m_ColourBG) m_ColourBG = wxWHITE;
981
982 if(m_DefaultSetting)
983 delete m_DefaultSetting;
984
985 m_DefaultSetting = new
986 wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
987 m_FontWeight,m_FontUnderline,
988 m_ColourFG, m_ColourBG);
989 }
990
991
992
993 bool
994 wxLayoutList::MoveCursorTo(wxPoint const &p)
995 {
996 wxLayoutLine *line = m_FirstLine;
997 while(line && line->GetLineNumber() != p.y)
998 line = line->GetNextLine();
999 if(line && line->GetLineNumber() == p.y) // found it
1000 {
1001 m_CursorPos.y = p.y;
1002 m_CursorLine = line;
1003 CoordType len = line->GetLength();
1004 if(len >= p.x)
1005 {
1006 m_CursorPos.x = p.x;
1007 return true;
1008 }
1009 else
1010 {
1011 m_CursorPos.x = len;
1012 return false;
1013 }
1014 }
1015 return false;
1016 }
1017
1018 bool
1019 wxLayoutList::MoveCursorVertically(int n)
1020 {
1021 if(n < 0) // move up
1022 {
1023 if(m_CursorLine == m_FirstLine) return false;
1024 while(n < 0 && m_CursorLine)
1025 {
1026 m_CursorLine = m_CursorLine->GetPreviousLine();
1027 m_CursorPos.y--;
1028 n++;
1029 }
1030 if(! m_CursorLine)
1031 {
1032 m_CursorLine = m_FirstLine;
1033 m_CursorPos.y = 0;
1034 return false;
1035 }
1036 else
1037 {
1038 if(m_CursorPos.x > m_CursorLine->GetLength())
1039 m_CursorPos.x = m_CursorLine->GetLength();
1040 return true;
1041 }
1042 }
1043 else // move down
1044 {
1045 wxLayoutLine *last = m_CursorLine;
1046 if(! m_CursorLine->GetNextLine()) return false;
1047 while(n > 0 && m_CursorLine)
1048 {
1049 n--;
1050 m_CursorPos.y ++;
1051 m_CursorLine = m_CursorLine->GetNextLine();
1052 }
1053 if(! m_CursorLine)
1054 {
1055 m_CursorLine = last;
1056 m_CursorPos.y ++;
1057 return false;
1058 }
1059 else
1060 {
1061 if(m_CursorPos.x > m_CursorLine->GetLength())
1062 m_CursorPos.x = m_CursorLine->GetLength();
1063 return true;
1064 }
1065 }
1066 }
1067
1068 bool
1069 wxLayoutList::MoveCursorHorizontally(int n)
1070 {
1071 int move;
1072 while(n < 0)
1073 {
1074 if(m_CursorPos.x == 0) // at begin of line
1075 {
1076 if(! MoveCursorVertically(-1))
1077 break;
1078 MoveCursorToEndOfLine();
1079 n++;
1080 continue;
1081 }
1082 move = -n;
1083 if(move > m_CursorPos.x) move = m_CursorPos.x;
1084 m_CursorPos.x -= move; n += move;
1085 }
1086
1087 while(n > 0)
1088 {
1089 int len = m_CursorLine->GetLength();
1090 if(m_CursorPos.x == len) // at end of line
1091 {
1092 if(! MoveCursorVertically(1))
1093 break;
1094 MoveCursorToBeginOfLine();
1095 n--;
1096 continue;
1097 }
1098 move = n;
1099 if( move >= len-m_CursorPos.x) move = len-m_CursorPos.x;
1100 m_CursorPos.x += move;
1101 n -= move;
1102 }
1103 return n == 0;
1104 }
1105
1106 bool
1107 wxLayoutList::Insert(wxString const &text)
1108 {
1109 wxASSERT(m_CursorLine);
1110 m_CursorLine->Insert(m_CursorPos.x, text);
1111 m_CursorPos.x += text.Length();
1112 return true;
1113 }
1114
1115 bool
1116 wxLayoutList::Insert(wxLayoutObject *obj)
1117 {
1118 wxASSERT(m_CursorLine);
1119 m_CursorLine->Insert(m_CursorPos.x, obj);
1120 m_CursorPos.x += obj->GetLength();
1121 return true;
1122 }
1123
1124 bool
1125 wxLayoutList::LineBreak(void)
1126 {
1127 wxASSERT(m_CursorLine);
1128
1129 bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
1130 m_CursorLine = m_CursorLine->Break(m_CursorPos.x);
1131 if(setFirst) // we were at beginning of first line
1132 m_FirstLine = m_CursorLine->GetPreviousLine();
1133 m_CursorPos.y++;
1134 m_CursorPos.x = 0;
1135 return true;
1136 }
1137
1138 bool
1139 wxLayoutList::WrapLine(CoordType column)
1140 {
1141 if(m_CursorPos.x <= column || column < 1)
1142 return false; // do nothing yet
1143 else
1144 {
1145 CoordType xpos = m_CursorLine->GetWrapPosition(column);
1146 if(xpos == -1)
1147 return false; // cannot break line
1148 //else:
1149 CoordType newpos = m_CursorPos.x - xpos - 1;
1150 m_CursorPos.x = xpos;
1151 LineBreak();
1152 Delete(1); // delete the space
1153 m_CursorPos.x = newpos;
1154 return true;
1155 }
1156 }
1157
1158 bool
1159 wxLayoutList::Delete(CoordType npos)
1160 {
1161 wxASSERT(m_CursorLine);
1162 CoordType left;
1163 do
1164 {
1165 left = m_CursorLine->Delete(m_CursorPos.x, npos);
1166 if(left == 0)
1167 return true;
1168 // More to delete, continue on next line.
1169 // First, check if line is empty:
1170 if(m_CursorLine->GetLength() == 0)
1171 { // in this case, updating could probably be optimised
1172 #ifdef WXLO_DEBUG
1173 wxASSERT(DeleteLines(1) == 0);
1174 #else
1175 DeleteLines(1);
1176 #endif
1177
1178 left--;
1179 }
1180 else
1181 {
1182 // Need to join next line
1183 if(! m_CursorLine->GetNextLine())
1184 break; // cannot
1185 else
1186 {
1187 m_CursorLine->MergeNextLine();
1188 left--;
1189 }
1190 }
1191 }
1192 while(left);
1193 return left == 0;
1194 }
1195
1196 int
1197 wxLayoutList::DeleteLines(int n)
1198 {
1199 wxASSERT(m_CursorLine);
1200 wxLayoutLine *line;
1201 while(n > 0)
1202 {
1203 if(!m_CursorLine->GetNextLine())
1204 { // we cannot delete this line, but we can clear it
1205 MoveCursorToBeginOfLine();
1206 DeleteToEndOfLine();
1207 return n-1;
1208 }
1209 //else:
1210 line = m_CursorLine;
1211 m_CursorLine = m_CursorLine->DeleteLine(true);
1212 n--;
1213 if(line == m_FirstLine) m_FirstLine = m_CursorLine;
1214 wxASSERT(m_FirstLine);
1215 wxASSERT(m_CursorLine);
1216 }
1217 m_CursorLine->RecalculatePositions(2);
1218 return n;
1219 }
1220
1221 void
1222 wxLayoutList::Recalculate(wxDC &dc, CoordType bottom) const
1223 {
1224 wxLayoutLine *line = m_FirstLine;
1225
1226 // first, make sure everything is calculated - this might not be
1227 // needed, optimise it later
1228 m_DefaultSetting->Layout(dc);
1229 while(line)
1230 {
1231 line->RecalculatePosition(); // so we don't need to do it all the time
1232 // little condition to speed up redrawing:
1233 if(bottom != -1 && line->GetPosition().y > bottom) break;
1234 line = line->GetNextLine();
1235 }
1236 }
1237
1238 void
1239 wxLayoutList::Layout(wxDC &dc, CoordType bottom) const
1240 {
1241 wxLayoutLine *line = m_FirstLine;
1242
1243 // first, make sure everything is calculated - this might not be
1244 // needed, optimise it later
1245 m_DefaultSetting->Layout(dc);
1246 while(line)
1247 {
1248 if(line == m_CursorLine)
1249 line->Layout(dc, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
1250 else
1251 line->Layout(dc);
1252 // little condition to speed up redrawing:
1253 if(bottom != -1 && line->GetPosition().y > bottom) break;
1254 line = line->GetNextLine();
1255 }
1256
1257 ///FIXME: disabled for now
1258 #if 0
1259 // can only be 0 if we are on the first line and have no next line
1260 wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
1261 m_CursorLine->GetNextLine() == NULL &&
1262 m_CursorLine == m_FirstLine));
1263 #endif
1264 }
1265
1266 void
1267 wxLayoutList::Draw(wxDC &dc, wxPoint const &offset,
1268 CoordType top, CoordType bottom) const
1269 {
1270 wxLayoutLine *line = m_FirstLine;
1271
1272 Layout(dc, bottom);
1273 m_DefaultSetting->Draw(dc, wxPoint(0,0));
1274 wxBrush *brush = new wxBrush(*m_ColourBG, wxSOLID);
1275 dc.SetBrush(*brush);
1276 delete brush;
1277
1278 while(line)
1279 {
1280 // only draw if between top and bottom:
1281 if((top == -1 || line->GetPosition().y >= top))
1282 line->Draw(dc, offset);
1283 // little condition to speed up redrawing:
1284 if(bottom != -1 && line->GetPosition().y + line->GetHeight() > bottom) break;
1285 line = line->GetNextLine();
1286 }
1287 // can only be 0 if we are on the first line and have no next line
1288 wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
1289 m_CursorLine->GetNextLine() == NULL &&
1290 m_CursorLine == m_FirstLine));
1291 }
1292
1293 wxLayoutObject *
1294 wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos, wxPoint *cursorPos)
1295 {
1296 // First, find the right line:
1297 wxLayoutLine *line = m_FirstLine;
1298 wxPoint p;
1299
1300 // we need to run a layout here to get font sizes right :-(
1301 m_DefaultSetting->Layout(dc);
1302 while(line)
1303 {
1304 p = line->GetPosition();
1305 if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
1306 break;
1307 line->Layout(dc);
1308 line = line->GetNextLine();
1309 }
1310 if(line == NULL) return NULL; // not found
1311 if(cursorPos) cursorPos->y = line->GetLineNumber();
1312 // Now, find the object in the line:
1313 wxLOiterator i = line->FindObjectScreen(dc, pos.x, & cursorPos->x);
1314 return (i == NULLIT) ? NULL : *i;
1315
1316 }
1317
1318 wxPoint
1319 wxLayoutList::GetSize(void) const
1320 {
1321 wxLayoutLine
1322 *line = m_FirstLine,
1323 *last = line;
1324 if(! line)
1325 return wxPoint(0,0);
1326
1327 wxPoint maxPoint(0,0);
1328
1329 // find last line:
1330 while(line)
1331 {
1332 if(line->GetWidth() > maxPoint.x)
1333 maxPoint.x = line->GetWidth();
1334 last = line;
1335 line = line->GetNextLine();
1336 }
1337
1338 maxPoint.y = last->GetPosition().y + last->GetHeight();
1339 return maxPoint;
1340 }
1341
1342 void
1343 wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
1344 {
1345 wxPoint coords;
1346 coords = m_CursorScreenPos;
1347 coords.x += translate.x;
1348 coords.y += translate.y;
1349
1350 #ifdef WXLAYOUT_DEBUG
1351 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1352 (long)m_CursorPos.x, (long)m_CursorPos.y,
1353 (long)coords.x, (long)coords.y,
1354 (long)m_CursorSize.x, (long)m_CursorSize.y,
1355 (long)m_CursorLine->GetLineNumber(),
1356 (long)m_CursorLine->GetLength()));
1357 #endif
1358
1359 dc.SetBrush(*wxBLACK_BRUSH);
1360 dc.SetLogicalFunction(wxXOR);
1361 dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
1362 if(active)
1363 dc.DrawRectangle(coords.x, coords.y, m_CursorSize.x,
1364 m_CursorSize.y);
1365 else
1366 dc.DrawLine(coords.x, coords.y+m_CursorSize.y-1,
1367 coords.x+m_CursorSize.x, coords.y+m_CursorSize.y-1);
1368 dc.SetLogicalFunction(wxCOPY);
1369 //dc.SetBrush(wxNullBrush);
1370 }
1371
1372 /** Called by the objects to update the update rectangle.
1373 @param p a point to include in it
1374 */
1375 void
1376 wxLayoutList::SetUpdateRect(const wxPoint &p)
1377 {
1378 if(m_UpdateRectValid)
1379 GrowRect(m_UpdateRect, p);
1380 else
1381 {
1382 m_UpdateRect.x = p.x;
1383 m_UpdateRect.y = p.y;
1384 m_UpdateRect.width = 4; // large enough to avoid surprises from
1385 m_UpdateRect.height = 4;// wxGTK :-)
1386 m_UpdateRectValid = true;
1387 }
1388 }
1389
1390
1391 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1392
1393 wxLayoutPrintout
1394
1395 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1396
1397 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist,
1398 wxString const & title)
1399 :wxPrintout(title)
1400 {
1401 m_llist = llist;
1402 m_title = title;
1403 }
1404
1405 float
1406 wxLayoutPrintout::ScaleDC(wxDC *dc)
1407 {
1408 // The following bit is taken from the printing sample, let's see
1409 // whether it works for us.
1410
1411 /* You might use THIS code to set the printer DC to ROUGHLY reflect
1412 * the screen text size. This page also draws lines of actual length 5cm
1413 * on the page.
1414 */
1415 // Get the logical pixels per inch of screen and printer
1416 int ppiScreenX, ppiScreenY;
1417 GetPPIScreen(&ppiScreenX, &ppiScreenY);
1418 int ppiPrinterX, ppiPrinterY;
1419 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
1420
1421 if(ppiScreenX == 0) // not yet set, need to guess
1422 {
1423 ppiScreenX = 100;
1424 ppiScreenY = 100;
1425 }
1426 if(ppiPrinterX == 0) // not yet set, need to guess
1427 {
1428 ppiPrinterX = 72;
1429 ppiPrinterY = 72;
1430 }
1431
1432 // This scales the DC so that the printout roughly represents the
1433 // the screen scaling. The text point size _should_ be the right size
1434 // but in fact is too small for some reason. This is a detail that will
1435 // need to be addressed at some point but can be fudged for the
1436 // moment.
1437 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
1438
1439 // Now we have to check in case our real page size is reduced
1440 // (e.g. because we're drawing to a print preview memory DC)
1441 int pageWidth, pageHeight;
1442 int w, h;
1443 dc->GetSize(&w, &h);
1444 GetPageSizePixels(&pageWidth, &pageHeight);
1445 if(pageWidth != 0) // doesn't work always
1446 {
1447 // If printer pageWidth == current DC width, then this doesn't
1448 // change. But w might be the preview bitmap width, so scale down.
1449 scale = scale * (float)(w/(float)pageWidth);
1450 }
1451 dc->SetUserScale(scale, scale);
1452 return scale;
1453 }
1454
1455 bool wxLayoutPrintout::OnPrintPage(int page)
1456 {
1457 wxDC *dc = GetDC();
1458
1459 ScaleDC(dc);
1460
1461 if (dc)
1462 {
1463 int top, bottom;
1464 top = (page - 1)*m_PrintoutHeight;
1465 bottom = top + m_PrintoutHeight;
1466 // SetDeviceOrigin() doesn't work here, so we need to manually
1467 // translate all coordinates.
1468 wxPoint translate(m_Offset.x,m_Offset.y-top);
1469 m_llist->Draw(*dc, translate, top, bottom);
1470 return true;
1471 }
1472 else
1473 return false;
1474 }
1475
1476 void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
1477 {
1478 /* We allocate a temporary wxDC for printing, so that we can
1479 determine the correct paper size and scaling. We don't actually
1480 print anything on it. */
1481 #ifdef __WXMSW__
1482 wxPrinterDC psdc("","",WXLLIST_TEMPFILE,false);
1483 #else
1484 wxPostScriptDC psdc(WXLLIST_TEMPFILE,false);
1485 #endif
1486
1487 float scale = ScaleDC(&psdc);
1488
1489 psdc.GetSize(&m_PageWidth, &m_PageHeight);
1490 // This sets a left/top origin of 15% and 20%:
1491 m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20);
1492
1493 // This is the length of the printable area.
1494 m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15);
1495 m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
1496
1497
1498 m_NumOfPages = 1 +
1499 (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));
1500
1501 *minPage = 1;
1502 *maxPage = m_NumOfPages;
1503
1504 *selPageFrom = 1;
1505 *selPageTo = m_NumOfPages;
1506 wxRemoveFile(WXLLIST_TEMPFILE);
1507 }
1508
1509 bool wxLayoutPrintout::HasPage(int pageNum)
1510 {
1511 return pageNum <= m_NumOfPages;
1512 }
1513
1514 /*
1515 Stupid wxWindows doesn't draw proper ellipses, so we comment this
1516 out. It's a waste of paper anyway.
1517 */
1518 #if 0
1519 void
1520 wxLayoutPrintout::DrawHeader(wxDC &dc,
1521 wxPoint topleft, wxPoint bottomright,
1522 int pageno)
1523 {
1524 // make backups of all essential parameters
1525 const wxBrush& brush = dc.GetBrush();
1526 const wxPen& pen = dc.GetPen();
1527 const wxFont& font = dc.GetFont();
1528
1529 dc.SetBrush(*wxWHITE_BRUSH);
1530 dc.SetPen(wxPen(*wxBLACK,0,wxSOLID));
1531 dc.DrawRoundedRectangle(topleft.x,
1532 topleft.y,bottomright.x-topleft.x,
1533 bottomright.y-topleft.y);
1534 dc.SetBrush(*wxBLACK_BRUSH);
1535 wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
1536 wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
1537 dc.SetFont(myfont);
1538
1539 wxString page;
1540 page = "9999/9999 "; // many pages...
1541 long w,h;
1542 dc.GetTextExtent(page,&w,&h);
1543 page.Printf("%d/%d", pageno, (int) m_NumOfPages);
1544 dc.DrawText(page,bottomright.x-w,topleft.y+h/2);
1545 dc.GetTextExtent("XXXX", &w,&h);
1546 dc.DrawText(m_title, topleft.x+w,topleft.y+h/2);
1547
1548 // restore settings
1549 dc.SetPen(pen);
1550 dc.SetBrush(brush);
1551 dc.SetFont(font);
1552 }
1553 #endif
1554
1555