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