]> git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxllist.cpp
New scrolling for GTK
[wxWidgets.git] / user / wxLayout / wxllist.cpp
1 /*-*- c++ -*-********************************************************
2 * wxFTCanvas: a canvas for editing formatted text *
3 * *
4 * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
5 * *
6 * $Id$ *
7 *******************************************************************/
8
9 /*
10 - each Object knows its size and how to draw itself
11 - the list is responsible for calculating positions
12 - the draw coordinates for each object are the top left corner
13 - coordinates only get calculated when things get redrawn
14 - during redraw each line gets iterated over twice, first just
15 calculating baselines and positions, second to actually draw it
16 - the cursor position is the position before an object, i.e. if the
17 buffer starts with a text-object, cursor 0,0 is just before the
18 first character
19 */
20
21 #ifdef __GNUG__
22 #pragma implementation "wxllist.h"
23 #endif
24
25 // these two lines are for use in M:
26 //#include "Mpch.h"
27 //#include "gui/wxllist.h"
28
29 #include "wxllist.h"
30
31 #ifndef USE_PCH
32 # include "iostream.h"
33
34 # include <wx/dc.h>
35 # include <wx/postscrp.h>
36 # include <wx/print.h>
37 # include <wx/log.h>
38 #endif
39
40 #define BASELINESTRETCH 12
41
42 #ifdef WXLAYOUT_DEBUG
43 static const char *g_aTypeStrings[] =
44 {
45 "invalid", "text", "cmd", "icon", "linebreak"
46 };
47
48 # define wxLayoutDebug wxLogDebug
49 # define WXL_VAR(x) cerr << #x " = " << x ;
50 # define WXL_DBG_POINT(p) wxLogDebug(#p ": (%d, %d)", p.x, p.y)
51 # define WXL_TRACE(f) wxLogDebug(#f ": ")
52 # define TypeString(t) g_aTypeStrings[t]
53
54 void
55 wxLayoutObjectBase::Debug(void)
56 {
57 CoordType bl = 0;
58 wxLogDebug("%s: size = %dx%d, bl = %d",
59 TypeString(GetType()), GetSize(&bl).x, GetSize(&bl).y, bl);
60 }
61
62 #else
63 # define WXL_VAR(x)
64 # define WXL_DBG_POINT(p)
65 # define WXL_TRACE(f)
66 # define ShowCurrentObject()
67 # define TypeString(t) ""
68 inline void wxLayoutDebug(const char *, ...) { }
69 #endif
70
71
72 //-------------------------- wxLayoutObjectText
73
74 wxLayoutObjectText::wxLayoutObjectText(const String &txt)
75 {
76 m_Text = txt;
77 m_Width = 0;
78 m_Height = 0;
79 }
80
81
82 wxPoint
83 wxLayoutObjectText::GetSize(CoordType *baseLine) const
84 {
85 if(baseLine) *baseLine = m_BaseLine;
86 return wxPoint(m_Width, m_Height);
87 }
88
89 void
90 wxLayoutObjectText::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
91 bool draw)
92 {
93 long descent = 0l;
94 dc.GetTextExtent(Str(m_Text),&m_Width, &m_Height, &descent);
95 //FIXME: wxGTK does not set descent to a descent value yet.
96 if(descent == 0)
97 descent = (2*m_Height)/10; // crude fix
98 m_BaseLine = m_Height - descent;
99 position.y += baseLine-m_BaseLine;
100 if(draw)
101 dc.DrawText(Str(m_Text),position.x,position.y);
102 // Don't remove this, important help for debugging layout.
103 # ifdef WXLAYOUT_DEBUG
104 // dc.DrawRectangle(position.x, position.y, m_Width, m_Height);
105 # endif
106 }
107
108 #ifdef WXLAYOUT_DEBUG
109 void
110 wxLayoutObjectText::Debug(void)
111 {
112 wxLayoutObjectBase::Debug();
113 wxLogDebug(" `%s`", m_Text.c_str());
114 }
115 #endif
116
117 //-------------------------- wxLayoutObjectIcon
118
119 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
120 : m_Icon(icon)
121 {
122 }
123
124 void
125 wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
126 bool draw)
127 {
128 position.y += baseLine - m_Icon->GetHeight();
129 if(draw)
130 dc.DrawIcon(m_Icon,position.x,position.y);
131 }
132
133 wxPoint
134 wxLayoutObjectIcon::GetSize(CoordType *baseLine) const
135 {
136 wxASSERT(baseLine);
137 *baseLine = m_Icon->GetHeight();
138 return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
139 }
140
141 //-------------------------- wxLayoutObjectCmd
142
143
144 wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
145 weight, bool underline,
146 wxColour const *fg, wxColour const *bg)
147
148 {
149 m_font = new wxFont(size,family,style,weight,underline);
150 m_ColourFG = fg;
151 m_ColourBG = bg;
152 }
153
154 wxLayoutObjectCmd::~wxLayoutObjectCmd()
155 {
156 delete m_font;
157 }
158
159 wxLayoutStyleInfo *
160 wxLayoutObjectCmd::GetStyle(void) const
161 {
162 wxLayoutStyleInfo *si = new wxLayoutStyleInfo();
163
164
165 si->size = m_font->GetPointSize();
166 si->family = m_font->GetFamily();
167 si->style = m_font->GetStyle();
168 si->underline = m_font->GetUnderlined();
169 si->weight = m_font->GetWeight();
170
171 si->fg_red = m_ColourFG->Red();
172 si->fg_green = m_ColourFG->Green();
173 si->fg_blue = m_ColourFG->Blue();
174 si->bg_red = m_ColourBG->Red();
175 si->bg_green = m_ColourBG->Green();
176 si->bg_blue = m_ColourBG->Blue();
177
178 return si;
179 }
180
181 void
182 wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint position, CoordType lineHeight,
183 bool draw)
184 {
185 wxASSERT(m_font);
186 // this get called even when draw==false, so that recalculation
187 // uses right font sizes
188 dc.SetFont(m_font);
189 if(m_ColourFG)
190 dc.SetTextForeground(*m_ColourFG);
191 if(m_ColourBG)
192 dc.SetTextBackground(*m_ColourBG);
193 }
194
195 //-------------------------- wxwxLayoutList
196
197 wxLayoutList::wxLayoutList()
198 {
199 m_DefaultSetting = NULL;
200 Clear();
201 }
202
203 wxLayoutList::~wxLayoutList()
204 {
205 if(m_DefaultSetting)
206 delete m_DefaultSetting;
207 // no deletion of objects, they are owned by the list
208 }
209
210 void
211 wxLayoutList::LineBreak(void)
212 {
213 Insert(new wxLayoutObjectLineBreak);
214 m_CursorPosition.x = 0; m_CursorPosition.y++;
215 }
216
217 void
218 wxLayoutList::SetFont(int family, int size, int style, int weight,
219 int underline, wxColour const *fg,
220 wxColour const *bg)
221 {
222 if(family != -1) m_FontFamily = family;
223 if(size != -1) m_FontPtSize = size;
224 if(style != -1) m_FontStyle = style;
225 if(weight != -1) m_FontWeight = weight;
226 if(underline != -1) m_FontUnderline = underline != 0;
227
228 if(fg != NULL) m_ColourFG = fg;
229 if(bg != NULL) m_ColourBG = bg;
230
231 Insert(
232 new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
233 m_ColourFG, m_ColourBG));
234 }
235
236 void
237 wxLayoutList::SetFont(int family, int size, int style, int weight,
238 int underline, char const *fg, char const *bg)
239
240 {
241 wxColour const
242 * cfg = NULL,
243 * cbg = NULL;
244
245 if( fg )
246 cfg = wxTheColourDatabase->FindColour(fg);
247 if( bg )
248 cbg = wxTheColourDatabase->FindColour(bg);
249
250 SetFont(family,size,style,weight,underline,cfg,cbg);
251 }
252
253
254 /// for access by wxLayoutWindow:
255 void
256 wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y,
257 CoordType *lineHeight)
258 {
259
260 if(max_x) *max_x = m_MaxX;
261 if(max_y) *max_y = m_MaxY;
262 if(lineHeight) *lineHeight = m_LineHeight;
263 }
264
265 wxLayoutObjectBase *
266 wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const
267 &findCoords, int pageNo, bool reallyDraw)
268 {
269 wxLayoutObjectList::iterator i;
270
271 // in case we need to look for an object
272 wxLayoutObjectBase *foundObject = NULL;
273
274 // first object in current line
275 wxLayoutObjectList::iterator headOfLine;
276
277 // do we need to recalculate current line?
278 bool recalculate = false;
279
280 // do we calculate or draw? Either true or false.
281 bool draw = false;
282 // drawing parameters:
283 wxPoint position = wxPoint(0,0);
284 wxPoint position_HeadOfLine;
285 CoordType baseLine = m_FontPtSize;
286 CoordType baseLineSkip = (BASELINESTRETCH * baseLine)/10;
287
288 // where to draw the cursor
289 wxPoint
290 cursorPosition = wxPoint(0,0),
291 cursorSize = wxPoint(1,baseLineSkip);
292
293 // the cursor position inside the object
294 CoordType cursorOffset = 0;
295 // object under cursor
296 wxLayoutObjectList::iterator cursorObject = FindCurrentObject(&cursorOffset);
297
298 // queried from each object:
299 wxPoint size = wxPoint(0,0);
300 CoordType objBaseLine = baseLine;
301 wxLayoutObjectType type;
302
303 // used temporarily
304 wxLayoutObjectText *tobj = NULL;
305
306
307 // this is needed for printing to a printer:
308 // only interesting for printer/PS output
309 int pageWidth, pageHeight; //GetSize() still needs int at the moment
310 struct
311 {
312 int top, bottom, left, right;
313 } margins;
314
315 int currentPage = 1;
316
317 if(pageNo > 0)
318 {
319 dc.GetSize(&pageWidth, &pageHeight);
320 WXL_VAR(pageHeight);
321 margins.top = 0; //(1*pageHeight)/10; // 10%
322 margins.bottom = pageHeight;// (9*pageHeight)/10; // 90%
323 margins.left = 0; //(1*pageWidth)/10;
324 margins.right = pageWidth; //(9*pageWidth)/10;
325 }
326 else
327 {
328 margins.top = 0; margins.left = 0;
329 margins.right = -1;
330 margins.bottom = -1;
331 }
332 position.y = margins.top;
333 position.x = margins.left;
334
335 // if the cursorobject is a cmd, we need to find the first
336 // printable object:
337 while(cursorObject != end()
338 && (*cursorObject)->GetType() == WXLO_TYPE_CMD)
339 cursorObject++;
340
341 headOfLine = begin();
342 position_HeadOfLine = position;
343
344 // setting up the default:
345 dc.SetTextForeground( *wxBLACK );
346 dc.SetTextBackground( *wxWHITE );
347 dc.SetBackgroundMode( wxSOLID ); // to enable setting of text background
348 dc.SetFont( *wxNORMAL_FONT );
349
350
351 //FIXME: who frees the brush, how long does it need to exist?
352 if(m_DefaultSetting)
353 m_DefaultSetting->Draw(dc,wxPoint(0,0),0,true);
354
355 // we calculate everything for drawing a line, then rewind to the
356 // begin of line and actually draw it
357 i = begin();
358 for(;;)
359 {
360 recalculate = false;
361
362 if(i == end())
363 break;
364 type = (*i)->GetType();
365
366 // to initialise sizes of objects, we need to call Draw
367 if(draw && (pageNo == -1 || pageNo == currentPage))
368 {
369 (*i)->Draw(dc, position, baseLine, draw);
370 #ifdef WXLAYOUT_DEBUG
371 if(i == begin())
372 wxLogDebug("first position = (%d,%d)",(int) position.x, (int)position.y);
373 #endif
374 }
375 // update coordinates for next object:
376 size = (*i)->GetSize(&objBaseLine);
377 if(findObject && draw) // we need to look for an object
378 {
379 if(findCoords.y >= position.y
380 && findCoords.y <= position.y+size.y
381 && findCoords.x >= position.x
382 && findCoords.x <= position.x+size.x)
383 {
384 foundObject = *i;
385 findObject = false; // speeds things up
386 }
387 }
388 // draw the cursor
389 if(m_Editable && draw && i == cursorObject)
390 {
391 WXL_VAR((**cursorObject).GetType());
392 WXL_VAR(m_CursorPosition.x); WXL_VAR(m_CursorPosition.y);
393 if(type == WXLO_TYPE_TEXT) // special treatment
394 {
395 long descent = 0l; long width, height;
396 tobj = (wxLayoutObjectText *)*i;
397 String str = tobj->GetText();
398 WXL_VAR(m_CursorPosition.x);
399 str = str.substr(0, cursorOffset);
400 dc.GetTextExtent(Str(str), &width,&height, &descent);
401 cursorPosition = wxPoint(position.x+width,
402 position.y+(baseLineSkip-height));
403 cursorSize = wxPoint(1, height);
404 }
405 else if(type == WXLO_TYPE_LINEBREAK)
406 {
407 WXL_VAR(cursorOffset);
408 if(cursorOffset)
409 cursorPosition = wxPoint(0, position.y+baseLineSkip);
410 else
411 cursorPosition = wxPoint(0, position.y);
412 cursorSize = wxPoint(1,baseLineSkip);
413
414 }
415 else
416 {
417 // this is not necessarily the most "beautiful" solution:
418 //cursorPosition = wxPoint(position.x, position.y);
419 //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
420 cursorPosition = wxPoint(position.x+size.x, position.y+(size.y-baseLineSkip));
421 cursorSize = wxPoint(1, baseLineSkip);
422 }
423 }
424
425 // calculate next object's position:
426 position.x += size.x;
427 if(position.x > m_MaxX)
428 m_MaxX = position.x;
429
430 // do we need to increase the line's height?
431 if(size.y > baseLineSkip)
432 {
433 baseLineSkip = size.y;
434 recalculate = true;
435 }
436 if(objBaseLine > baseLine)
437 {
438 baseLine = objBaseLine;
439 recalculate = true;
440 }
441
442 // now check whether we have finished handling this line:
443 if(type == WXLO_TYPE_LINEBREAK || i == tail())
444 {
445 if(recalculate) // do this line again
446 {
447 position.x = position_HeadOfLine.x;
448 i = headOfLine;
449 continue;
450 }
451
452 if(! draw) // finished calculating sizes
453 {
454 // if the this line needs to go onto a new page, we need
455 // to change pages before drawing it:
456 if(pageNo > 0 && position.y > margins.bottom)
457 {
458 currentPage++;
459 position_HeadOfLine.y = margins.top;
460 }
461 if(reallyDraw && (pageNo == -1 || pageNo == currentPage))
462 {
463 // do this line again, this time drawing it
464 position = position_HeadOfLine;
465 draw = true;
466 i = headOfLine;
467 continue;
468 }
469 }
470 else // we have drawn a line, so continue calculating next one
471 draw = false;
472 }
473
474 // is it a linebreak?
475 if(type == WXLO_TYPE_LINEBREAK || i == tail())
476 {
477 position.x = margins.left;
478 position.y += baseLineSkip;
479 baseLine = m_FontPtSize;
480 objBaseLine = baseLine; // not all objects set it
481 baseLineSkip = (BASELINESTRETCH * baseLine)/10;
482 headOfLine = i;
483 headOfLine++;
484 position_HeadOfLine = position;
485 }
486 i++;
487 }
488 // draw the cursor
489 if(m_Editable)
490 {
491 dc.DrawRectangle(cursorPosition.x, cursorPosition.y,
492 cursorSize.x, cursorSize.y);
493 }
494 m_MaxY = position.y;
495 return foundObject;
496 }
497
498 #ifdef WXLAYOUT_DEBUG
499 void
500 wxLayoutList::Debug(void)
501 {
502 CoordType offs;
503 wxLayoutObjectList::iterator i;
504
505 wxLogDebug("------------------------debug start-------------------------");
506 for(i = begin(); i != end(); i++)
507 (*i)->Debug();
508 wxLogDebug("-----------------------debug end----------------------------");
509
510 // show current object:
511 ShowCurrentObject();
512 i = FindCurrentObject(&offs);
513 wxLogDebug(" line length: %l", (long int) GetLineLength(i,offs));
514 if(i == end())
515 {
516 wxLogDebug("<<no object found>>");
517 return; // FIXME we should set cursor position to maximum allowed
518 // value then
519 }
520 if((*i)->GetType() == WXLO_TYPE_TEXT)
521 wxLogDebug(" \"%s\", offs=%d",((wxLayoutObjectText *)(*i))->GetText().c_str(), (int) offs);
522 else
523 wxLogDebug(g_aTypeStrings[(*i)->GetType()]);
524
525 }
526
527 void
528 wxLayoutList::ShowCurrentObject()
529 {
530 CoordType offs;
531 wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
532
533 wxLayoutDebug("Cursor is at (%d, %d)",
534 m_CursorPosition.x, m_CursorPosition.y);
535
536 i = FindCurrentObject(&offs);
537 wxLogDebug(" Line length: %d", GetLineLength(i));
538
539 if(i == end())
540 {
541 wxLogDebug("<<no object found>>");
542 return; // FIXME we should set cursor position to maximum allowed
543 // value then
544 }
545 if((*i)->GetType() == WXLO_TYPE_TEXT)
546 wxLogDebug(" \"%s\", offs: %d",
547 ((wxLayoutObjectText *)(*i))->GetText().c_str(), offs);
548 else
549 wxLogDebug(" %s", TypeString((*i)->GetType()));
550 }
551
552 #endif
553
554 /******************** editing stuff ********************/
555
556 // don't change this, I know how to optimise this and will do it real
557 // soon (KB)
558
559 /*
560 * FindObjectCursor:
561 * Finds the object belonging to a given cursor position cpos and
562 * returns an iterator to that object and stores the relative cursor
563 * position in offset.
564 *
565 * For linebreaks, the offset can be 0=before or 1=after.
566 *
567 * If the cpos coordinates don't exist, they are modified.
568 */
569
570 wxLayoutObjectList::iterator
571 wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
572 {
573 wxPoint object = wxPoint(0,0); // runs along the objects
574 CoordType width;
575 wxLayoutObjectList::iterator i;
576
577 #ifdef WXLAYOUT_DEBUG
578 wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
579 #endif
580 for(i = begin(); i != end() && object.y <= cpos->y; i++)
581 {
582 width = (**i).CountPositions();
583 if(cpos->y == object.y) // a possible candidate
584 {
585 if((**i).GetType() ==WXLO_TYPE_LINEBREAK)
586 {
587 if(cpos->x == object.x)
588 {
589 if(offset) *offset = 0;
590 return i;
591 }
592 if(offset) *offset=1;
593 cpos->x = object.x;
594 return i;
595 }
596 if(cpos->x >= object.x && cpos->x <= object.x+width) // overlap
597 {
598 if(offset) *offset = cpos->x-object.x;
599 #ifdef WXLAYOUT_DEBUG
600 wxLayoutDebug(" found object at (%d, %d), type: %s",
601 object.x, object.y, TypeString((*i)->GetType()));
602 #endif
603 return i;
604 }
605 }
606 // no overlap, increment coordinates
607 object.x += width;
608 if((**i).GetType() == WXLO_TYPE_LINEBREAK)
609 {
610 object.x = 0;
611 object.y++;
612 }
613 }
614 #ifdef WXLAYOUT_DEBUG
615 wxLayoutDebug(" not found");
616 #endif
617 // return last object, coordinates of that one:
618 i = tail();
619 if(i == end())
620 return i;
621 if((**i).GetType()==WXLO_TYPE_LINEBREAK)
622 {
623 if(offset)
624 *offset = 1;
625 return i;
626 }
627 cpos->x = object.x; // would be the coordinate of next object
628 cpos->y = object.y;
629 cpos->x += width; // last object's width
630 if(*offset) *offset = cpos->x-object.x;
631 return i; // not found
632 }
633
634 wxLayoutObjectList::iterator
635 wxLayoutList::FindCurrentObject(CoordType *offset)
636 {
637 wxLayoutObjectList::iterator obj = end();
638
639 obj = FindObjectCursor(&m_CursorPosition, offset);
640 if(obj == end()) // not ideal yet
641 {
642 obj = tail();
643 if(obj != end()) // tail really exists
644 *offset = (*obj)->CountPositions(); // at the end of it
645 }
646 return obj;
647 }
648
649 bool
650 wxLayoutList::MoveCursor(int dx, int dy)
651 {
652 CoordType offs, lineLength;
653 wxLayoutObjectList::iterator i;
654
655 bool rc = true; // have we moved?
656
657 if(dy > 0 && m_CursorPosition.y < m_MaxLine)
658 m_CursorPosition.y += dy;
659 else if(dy < 0 && m_CursorPosition.y > 0)
660 m_CursorPosition.y += dy; // dy is negative
661 if(m_CursorPosition.y < 0)
662 {
663 m_CursorPosition.y = 0;
664 rc = false;
665 }
666 else if (m_CursorPosition.y > m_MaxLine)
667 {
668 m_CursorPosition.y = m_MaxLine;
669 rc = false;
670 }
671
672 while(dx > 0)
673 {
674 i = FindCurrentObject(&offs);
675 lineLength = GetLineLength(i,offs);
676 if(m_CursorPosition.x < lineLength)
677 {
678 m_CursorPosition.x ++;
679 dx--;
680 continue;
681 }
682 else
683 {
684 if(m_CursorPosition.y < m_MaxLine)
685 {
686 m_CursorPosition.y++;
687 m_CursorPosition.x = 0;
688 dx--;
689 }
690 else
691 {
692 rc = false;
693 break; // cannot move there
694 }
695 }
696 }
697 while(dx < 0)
698 {
699 if(m_CursorPosition.x > 0)
700 {
701 m_CursorPosition.x --;
702 dx++;
703 }
704 else
705 {
706 if(m_CursorPosition.y > 0)
707 {
708 m_CursorPosition.y --;
709 m_CursorPosition.x = 0;
710 i = FindCurrentObject(&offs);
711 lineLength = GetLineLength(i,offs);
712 m_CursorPosition.x = lineLength;
713 dx++;
714 continue;
715 }
716 else
717 {
718 rc = false;
719 break; // cannot move left any more
720 }
721 }
722 }
723 // final adjustment:
724 i = FindCurrentObject(&offs);
725 lineLength = GetLineLength(i,offs);
726 if(m_CursorPosition.x > lineLength)
727 {
728 m_CursorPosition.x = lineLength;
729 rc = false;
730 }
731 #ifdef WXLAYOUT_DEBUG
732 ShowCurrentObject();
733 #endif
734 return rc;
735 }
736
737 void
738 wxLayoutList::Delete(CoordType count)
739 {
740 WXL_TRACE(Delete);
741
742 if(!m_Editable)
743 return;
744
745 WXL_VAR(count);
746
747 CoordType offs;
748 wxLayoutObjectList::iterator i;
749
750 do
751 {
752 i = FindCurrentObject(&offs);
753 startover: // ugly, but easiest way to do it
754 if(i == end())
755 return; // we cannot delete anything more
756
757 /* Here we need to treat linebreaks differently.
758 If offs==0 we are before the linebreak, otherwise behind. */
759 if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
760 {
761 if(offs == 0)
762 {
763 m_MaxLine--;
764 erase(i);
765 count--;
766 continue; // we're done
767 }
768 else // delete the object behind the linebreak
769 {
770 i++; // we increment and continue as normal
771 offs=0;
772 goto startover;
773 }
774 }
775 else if((*i)->GetType() == WXLO_TYPE_TEXT)
776 {
777 wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
778 CoordType len = tobj->CountPositions();
779 // If we find the end of a text object, this means that we
780 // have to delete from the object following it.
781 if(len == offs)
782 {
783 i++;
784 offs = 0;
785 goto startover;
786 }
787 else if(len <= count) // delete this object
788 {
789 count -= len;
790 erase(i);
791 continue;
792 }
793 else
794 {
795 len = count;
796 tobj->GetText().erase(offs,len);
797 return; // we are done
798 }
799 }
800 else// all other objects: delete the object
801 // this only works as expected if the non-text object has 0/1
802 // as offset values. Not tested with "longer" objects.
803 {
804 CoordType len = (*i)->CountPositions();
805 if(offs == 0)
806 {
807 count = count > len ? count -= len : 0;
808 erase(i); // after this, i is the iterator for the following object
809 continue;
810 }
811 else // delete the following object
812 {
813 i++; // we increment and continue as normal
814 offs=0;
815 goto startover;
816 }
817 }
818 }
819 while(count && i != end());
820 }
821
822 void
823 wxLayoutList::Insert(wxLayoutObjectBase *obj)
824 {
825 wxASSERT(obj);
826 CoordType offs;
827 wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
828
829 WXL_TRACE(Insert(obj));
830
831 if(i == end())
832 push_back(obj);
833 else if(offs == 0)
834 insert(i,obj);
835 // do we have to split a text object?
836 else if((*i)->GetType() == WXLO_TYPE_TEXT && offs != (*i)->CountPositions())
837 {
838 wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
839 #ifdef WXLAYOUT_DEBUG
840 wxLayoutDebug("text: %s", tobj->GetText().c_str());
841 WXL_VAR(offs);
842 #endif
843 String left = tobj->GetText().substr(0,offs); // get part before cursor
844 WXL_VAR(left.c_str());
845 tobj->GetText() = tobj->GetText().substr(offs,(*i)->CountPositions()-offs); // keeps the right half
846 WXL_VAR(tobj->GetText().c_str());
847 insert(i,obj);
848 insert(i,new wxLayoutObjectText(left)); // inserts before
849 }
850 else
851 {
852 // all other cases, append after object:
853 wxLayoutObjectList::iterator j = i; // we want to apend after this object
854 j++;
855 if(j != end())
856 insert(j, obj);
857 else
858 push_back(obj);
859 }
860
861 m_CursorPosition.x += obj->CountPositions();
862 if(obj->GetType() == WXLO_TYPE_LINEBREAK)
863 m_MaxLine++;
864 }
865
866 void
867 wxLayoutList::Insert(String const &text)
868 {
869 wxLayoutObjectText *tobj = NULL;
870 wxLayoutObjectList::iterator j;
871
872 WXL_TRACE(Insert(text));
873
874 if(! m_Editable)
875 return;
876
877 CoordType offs;
878 wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
879
880 if(i == end())
881 {
882 Insert(new wxLayoutObjectText(text));
883 return;
884 }
885
886 switch((**i).GetType())
887 {
888 case WXLO_TYPE_TEXT:
889 // insert into an existing text object:
890 WXL_TRACE(inserting into existing object);
891 tobj = (wxLayoutObjectText *)*i ;
892 wxASSERT(tobj);
893 tobj->GetText().insert(offs,text);
894 break;
895 case WXLO_TYPE_LINEBREAK:
896 default:
897 j = i;
898 if(offs == 0) // try to append to previous object
899 {
900 j--;
901 if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
902 {
903 tobj = (wxLayoutObjectText *)*j;
904 tobj->GetText()+=text;
905 }
906 else
907 insert(i,new wxLayoutObjectText(text));
908 }
909 else // cursor after linebreak
910 {
911 j++;
912 if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
913 {
914 tobj = (wxLayoutObjectText *)*j;
915 tobj->GetText()=text+tobj->GetText();
916 }
917 else
918 {
919 if(j == end())
920 push_back(new wxLayoutObjectText(text));
921 else
922 insert(j,new wxLayoutObjectText(text));
923 }
924 }
925 break;
926 #if 0
927 default:
928 j = i; j--;
929 WXL_TRACE(checking previous object);
930 if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
931 {
932 tobj = (wxLayoutObjectText *)*j;
933 tobj->GetText()+=text;
934 }
935 else // insert a new text object
936 {
937 WXL_TRACE(creating new object);
938 Insert(new wxLayoutObjectText(text)); //FIXME not too optimal, slow
939 return; // position gets incremented in Insert(obj)
940 }
941 #endif
942 }
943 m_CursorPosition.x += strlen(text.c_str());
944 }
945
946 CoordType
947 wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs)
948 {
949 if(i == end())
950 return 0;
951
952 CoordType len = 0;
953
954 if(offs == 0 && (**i).GetType() == WXLO_TYPE_LINEBREAK)
955 // we are before a linebrak
956 return 0;
957 // search backwards for beginning of line:
958 while(i != begin() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
959 i--;
960 if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
961 i++;
962 // now we can start counting:
963 while(i != end() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
964 {
965 len += (*i)->CountPositions();
966 i++;
967 }
968 return len;
969 }
970
971 void
972 wxLayoutList::Clear(int family, int size, int style, int weight,
973 int underline, char const *fg, char const *bg)
974 {
975 wxLayoutObjectList::iterator i = begin();
976
977 while(i != end()) // == while valid
978 erase(i);
979
980 // set defaults
981 m_FontPtSize = size;
982 m_FontUnderline = false;
983 m_FontFamily = family;
984 m_FontStyle = style;
985 m_FontWeight = weight;
986 m_ColourFG = wxTheColourDatabase->FindColour(fg);
987 m_ColourBG = wxTheColourDatabase->FindColour(bg);
988
989 if(! m_ColourFG) m_ColourFG = wxBLACK;
990 if(! m_ColourBG) m_ColourBG = wxWHITE;
991
992 m_Position = wxPoint(0,0);
993 m_CursorPosition = wxPoint(0,0);
994 m_MaxLine = 0;
995 m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10;
996 m_MaxX = 0; m_MaxY = 0;
997
998
999 if(m_DefaultSetting)
1000 delete m_DefaultSetting;
1001 m_DefaultSetting = new
1002 wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
1003 m_FontWeight,m_FontUnderline,
1004 m_ColourFG, m_ColourBG);
1005 }
1006
1007
1008
1009 /******************** printing stuff ********************/
1010
1011 bool wxLayoutPrintout::OnPrintPage(int page)
1012 {
1013 wxDC *dc = GetDC();
1014 if (dc)
1015 {
1016 m_llist->Draw(*dc,false,wxPoint(0,0),page);
1017 return TRUE;
1018 }
1019 else
1020 return FALSE;
1021 }
1022
1023 bool wxLayoutPrintout::OnBeginDocument(int startPage, int endPage)
1024 {
1025 if (!wxPrintout::OnBeginDocument(startPage, endPage))
1026 return FALSE;
1027
1028 return TRUE;
1029 }
1030
1031 void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
1032 {
1033
1034 // This code doesn't work, because we don't have a DC yet.
1035 // How on earth are we supposed to calculate the number of pages then?
1036 *minPage = 0; // set this to 0 to disable editing of page numbers
1037 *maxPage = 100;
1038
1039 *selPageFrom = 0; // set this to 0 to hide page number controls
1040 *selPageTo = 100;
1041
1042 // *minPage = 1;
1043 // *maxPage = 32000;
1044
1045 // *selPageFrom = 1;
1046 // *selPageTo = 1;
1047
1048 #if 0
1049 CoordType height;
1050 int pageWidth, pageHeight;
1051
1052 wxDC *dc = GetDC();
1053 wxASSERT(dc);
1054
1055 dc->GetSize(&pageWidth, &pageHeight);
1056 // don't draw but just recalculate sizes:
1057 m_llist->Draw(*dc,false,wxPoint(0,0),-1,false);
1058 m_llist->GetSize(NULL,&height,NULL);
1059
1060 *minPage = 1;
1061 *maxPage = height/pageHeight+1;
1062
1063 *selPageFrom = 1;
1064 *selPageTo = *maxPage;
1065 m_maxPage = *maxPage;
1066 #endif
1067
1068 }
1069
1070 bool wxLayoutPrintout::HasPage(int pageNum)
1071 {
1072 return pageNum <= 5; // for testing
1073 // return m_maxPage >= pageNum;
1074 }
1075
1076
1077 wxLayoutPrintout *
1078 wxLayoutList::MakePrintout(wxString const &name)
1079 {
1080 return new wxLayoutPrintout(*this,name);
1081 }