Control: Change controls to use new callback infrastrucure.
[gemrb.git] / gemrb / core / Button.cpp
blob823a0b0191923a4719a661c8586ba6a7ee0bde96
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "Button.h"
23 #include "defsounds.h"
24 #include "win32def.h"
26 #include "GameData.h"
27 #include "Interface.h"
28 #include "Palette.h"
29 #include "Variables.h"
30 #include "Video.h"
32 Button::Button()
34 Unpressed = Pressed = Selected = Disabled = NULL;
35 State = IE_GUI_BUTTON_UNPRESSED;
36 ResetEventHandler( ButtonOnPress );
37 ResetEventHandler( ButtonOnDoublePress );
38 ResetEventHandler( ButtonOnShiftPress );
39 ResetEventHandler( ButtonOnRightPress );
40 ResetEventHandler( ButtonOnDragDrop );
41 ResetEventHandler( ButtonOnDrag );
42 ResetEventHandler( MouseEnterButton );
43 ResetEventHandler( MouseLeaveButton );
44 ResetEventHandler( MouseOverButton );
45 //Text = ( char * ) calloc( 64, sizeof(char) );
46 Text = NULL;
47 hasText = false;
48 font = core->GetButtonFont();
49 normal_palette = NULL;
50 disabled_palette = font->GetPalette()->Copy();
51 for (int i = 0; i < 256; i++) {
52 disabled_palette->col[i].r = ( disabled_palette->col[i].r * 2 ) / 3;
53 disabled_palette->col[i].g = ( disabled_palette->col[i].g * 2 ) / 3;
54 disabled_palette->col[i].b = ( disabled_palette->col[i].b * 2 ) / 3;
56 Flags = IE_GUI_BUTTON_NORMAL;
57 ToggleState = false;
58 Picture = NULL;
59 Clipping = 1.0;
60 memset(&SourceRGB,0,sizeof(SourceRGB));
61 memset(&DestRGB,0,sizeof(DestRGB));
62 memset( borders, 0, sizeof( borders ));
63 starttime = 0;
65 Button::~Button()
67 Video* video = core->GetVideoDriver();
68 video->FreeSprite( Disabled );
69 video->FreeSprite( Selected );
70 video->FreeSprite( Pressed );
71 video->FreeSprite( Unpressed );
72 video->FreeSprite( Picture );
73 ClearPictureList();
74 if (Text) {
75 free( Text );
77 gamedata->FreePalette( normal_palette);
78 gamedata->FreePalette( disabled_palette);
80 /** Sets the 'type' Image of the Button to 'img'.
81 'type' may assume the following values:
82 - IE_GUI_BUTTON_UNPRESSED
83 - IE_GUI_BUTTON_PRESSED
84 - IE_GUI_BUTTON_SELECTED
85 - IE_GUI_BUTTON_DISABLED */
86 void Button::SetImage(unsigned char type, Sprite2D* img)
88 switch (type) {
89 case IE_GUI_BUTTON_UNPRESSED:
90 case IE_GUI_BUTTON_LOCKED:
91 case IE_GUI_BUTTON_LOCKED_PRESSED:
92 core->GetVideoDriver()->FreeSprite( Unpressed );
93 Unpressed = img;
94 break;
96 case IE_GUI_BUTTON_SECOND:
97 case IE_GUI_BUTTON_PRESSED:
98 core->GetVideoDriver()->FreeSprite( Pressed );
99 Pressed = img;
100 break;
102 case IE_GUI_BUTTON_SELECTED:
103 core->GetVideoDriver()->FreeSprite( Selected );
104 Selected = img;
105 break;
107 case IE_GUI_BUTTON_DISABLED:
108 case IE_GUI_BUTTON_THIRD:
109 core->GetVideoDriver()->FreeSprite( Disabled );
110 Disabled = img;
111 break;
113 Changed = true;
116 /** make SourceRGB go closer to DestRGB */
117 void Button::CloseUpColor()
119 if (!starttime) return;
120 //using the realtime timer, because i don't want to
121 //handle Game at this point
122 unsigned long newtime;
124 Changed = true;
125 GetTime( newtime );
126 if (newtime<starttime) {
127 return;
129 SourceRGB.r = (SourceRGB.r + DestRGB.r) / 2;
130 SourceRGB.g = (SourceRGB.g + DestRGB.g) / 2;
131 SourceRGB.b = (SourceRGB.b + DestRGB.b) / 2;
132 SourceRGB.a = (SourceRGB.a + DestRGB.a) / 2;
133 if (SourceRGB.r == DestRGB.r &&
134 SourceRGB.g == DestRGB.g &&
135 SourceRGB.b == DestRGB.b &&
136 SourceRGB.a == DestRGB.a) {
137 starttime = 0;
138 return;
140 starttime = newtime + 40;
143 /** Draws the Control on the Output Display */
144 void Button::Draw(unsigned short x, unsigned short y)
146 if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
147 return;
149 Changed = false;
150 if (XPos == 65535 || Width == 0) {
151 return;
154 Video * video = core->GetVideoDriver();
156 // Button image
157 if (!( Flags & IE_GUI_BUTTON_NO_IMAGE )) {
158 Sprite2D* Image = NULL;
160 switch (State) {
161 case IE_GUI_BUTTON_UNPRESSED:
162 case IE_GUI_BUTTON_LOCKED:
163 case IE_GUI_BUTTON_LOCKED_PRESSED:
164 Image = Unpressed;
165 break;
167 case IE_GUI_BUTTON_SECOND:
168 case IE_GUI_BUTTON_PRESSED:
169 Image = Pressed;
170 if (! Image)
171 Image = Unpressed;
172 break;
174 case IE_GUI_BUTTON_SELECTED:
175 Image = Selected;
176 if (! Image)
177 Image = Unpressed;
178 break;
180 case IE_GUI_BUTTON_DISABLED:
181 case IE_GUI_BUTTON_THIRD:
182 Image = Disabled;
183 if (! Image)
184 Image = Unpressed;
185 break;
187 if (Image) {
188 // FIXME: maybe it's useless...
189 int xOffs = ( Width / 2 ) - ( Image->Width / 2 );
190 int yOffs = ( Height / 2 ) - ( Image->Height / 2 );
192 video->BlitSprite( Image, x + XPos + xOffs, y + YPos + yOffs, true );
196 if (State == IE_GUI_BUTTON_PRESSED) {
197 //shift the writing/border a bit
198 x+= 2;
199 y+= 2;
202 // Button picture
203 if (Picture && (Flags & IE_GUI_BUTTON_PICTURE) ) {
204 // Picture is drawn centered
205 int xOffs = ( Width / 2 ) - ( Picture->Width / 2 );
206 int yOffs = ( Height / 2 ) - ( Picture->Height / 2 );
207 if (Flags & IE_GUI_BUTTON_HORIZONTAL) {
208 xOffs += x + XPos + Picture->XPos;
209 yOffs += y + YPos + Picture->YPos;
210 video->BlitSprite( Picture, xOffs, yOffs, true );
211 Region r = Region( xOffs, yOffs + (int) (Picture->Height * Clipping), Picture->Width, (int) (Picture->Height*(1.0 - Clipping)) );
212 video->DrawRect( r, SourceRGB, true );
213 CloseUpColor();
215 else {
216 Region r( x + XPos + xOffs, y + YPos + yOffs, (int)(Picture->Width * Clipping), Picture->Height );
217 video->BlitSprite( Picture, x + XPos + xOffs + Picture->XPos, y + YPos + yOffs + Picture->YPos, true, &r );
221 // Composite pictures (paperdolls/description icons)
222 if (!PictureList.empty() && (Flags & IE_GUI_BUTTON_PICTURE) ) {
223 std::list<Sprite2D*>::iterator iter = PictureList.begin();
224 int xOffs = 0, yOffs = 0;
225 if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) {
226 // Center the hotspots of all pictures
227 xOffs = Width/2;
228 yOffs = Height/2;
229 } else if (Flags & IE_GUI_BUTTON_BG1_PAPERDOLL) {
230 // Display as-is
231 xOffs = 0;
232 yOffs = 0;
233 } else {
234 // Center the first picture, and align the rest to that
235 xOffs = Width/2 - (*iter)->Width/2 + (*iter)->XPos;
236 yOffs = Height/2 - (*iter)->Height/2 + (*iter)->YPos;
239 for (; iter != PictureList.end(); ++iter) {
240 video->BlitSprite( *iter, x + XPos + xOffs, y + YPos + yOffs, true );
244 // Button picture
245 if (AnimPicture) {
246 int xOffs = ( Width / 2 ) - ( AnimPicture->Width / 2 );
247 int yOffs = ( Height / 2 ) - ( AnimPicture->Height / 2 );
248 Region r( x + XPos + xOffs, y + YPos + yOffs, (int)(AnimPicture->Width * Clipping), AnimPicture->Height );
250 if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) {
251 video->BlitSprite( AnimPicture, x + XPos + xOffs + AnimPicture->XPos, y + YPos + yOffs + AnimPicture->YPos, true, &r );
252 } else {
253 video->BlitSprite( AnimPicture, x + XPos + xOffs, y + YPos + yOffs, true, &r );
257 // Button label
258 if (hasText && ! ( Flags & IE_GUI_BUTTON_NO_TEXT )) {
259 Palette* ppoi = normal_palette;
260 int align = 0;
262 if (State == IE_GUI_BUTTON_DISABLED)
263 ppoi = disabled_palette;
264 // FIXME: hopefully there's no button which sinks when selected
265 // AND has text label
266 //else if (State == IE_GUI_BUTTON_PRESSED || State == IE_GUI_BUTTON_SELECTED) {
268 if (Flags & IE_GUI_BUTTON_ALIGN_LEFT)
269 align |= IE_FONT_ALIGN_LEFT;
270 else if (Flags & IE_GUI_BUTTON_ALIGN_RIGHT)
271 align |= IE_FONT_ALIGN_RIGHT;
272 else
273 align |= IE_FONT_ALIGN_CENTER;
275 if (Flags & IE_GUI_BUTTON_ALIGN_TOP)
276 align |= IE_FONT_ALIGN_TOP;
277 else if (Flags & IE_GUI_BUTTON_ALIGN_BOTTOM)
278 align |= IE_FONT_ALIGN_BOTTOM;
279 else
280 align |= IE_FONT_ALIGN_MIDDLE;
282 if (! (Flags & IE_GUI_BUTTON_MULTILINE)) {
283 align |= IE_FONT_SINGLE_LINE;
285 font->Print( Region( x + XPos, y + YPos, Width - 2, Height - 2),
286 ( unsigned char * ) Text, ppoi,
287 (ieByte) align, true );
290 if (! (Flags&IE_GUI_BUTTON_NO_IMAGE)) {
291 for (int i = 0; i < MAX_NUM_BORDERS; i++) {
292 ButtonBorder *fr = &borders[i];
293 if (! fr->enabled) continue;
295 Region r = Region( x + XPos + fr->dx1, y + YPos + fr->dy1, Width - (fr->dx1 + fr->dx2 + 1), Height - (fr->dy1 + fr->dy2 + 1) );
296 video->DrawRect( r, fr->color, fr->filled );
300 /** Sets the Button State */
301 void Button::SetState(unsigned char state)
303 if (state > IE_GUI_BUTTON_LOCKED_PRESSED) {// If wrong value inserted
304 return;
306 if (State != state) {
307 Changed = true;
308 State = state;
311 void Button::SetBorder(int index, int dx1, int dy1, int dx2, int dy2, const Color &color, bool enabled, bool filled)
313 if (index >= MAX_NUM_BORDERS)
314 return;
316 ButtonBorder *fr = &borders[index];
317 fr->dx1 = dx1;
318 fr->dy1 = dy1;
319 fr->dx2 = dx2;
320 fr->dy2 = dy2;
321 fr->color = color;
322 fr->enabled = enabled;
323 fr->filled = filled;
324 Changed = true;
327 void Button::EnableBorder(int index, bool enabled)
329 if (index >= MAX_NUM_BORDERS)
330 return;
332 if (borders[index].enabled != enabled) {
333 borders[index].enabled = enabled;
334 Changed = true;
338 void Button::SetFont(Font* newfont)
340 font = newfont;
342 /** Handling The default button (enter) */
343 void Button::OnSpecialKeyPress(unsigned char Key)
345 if (State != IE_GUI_BUTTON_DISABLED && State != IE_GUI_BUTTON_LOCKED) {
346 if (Key == GEM_RETURN) {
347 if (Flags & IE_GUI_BUTTON_DEFAULT ) {
348 RunEventHandler( ButtonOnPress );
349 return;
352 else if (Key == GEM_ESCAPE) {
353 if (Flags & IE_GUI_BUTTON_CANCEL ) {
354 RunEventHandler( ButtonOnPress );
355 return;
359 Control::OnSpecialKeyPress(Key);
362 /** Mouse Button Down */
363 void Button::OnMouseDown(unsigned short x, unsigned short y,
364 unsigned short Button, unsigned short Mod)
366 if (State == IE_GUI_BUTTON_DISABLED) {
367 Control::OnMouseDown(x,y,Button,Mod);
368 return;
371 if (core->GetDraggedItem () && !ButtonOnDragDrop) {
372 Control::OnMouseDown(x,y,Button,Mod);
373 return;
376 ScrollBar* scrlbr = (ScrollBar*) sb;
377 if (!scrlbr) {
378 Control *ctrl = Owner->GetScrollControl();
379 if (ctrl && (ctrl->ControlType == IE_GUI_SCROLLBAR)) {
380 scrlbr = (ScrollBar *) ctrl;
384 //Button == 1 means Left Mouse Button
385 switch(Button&GEM_MB_NORMAL) {
386 case GEM_MB_ACTION:
387 // We use absolute screen position here, so drag_start
388 // remains valid even after window/control is moved
389 drag_start.x = Owner->XPos + XPos + x;
390 drag_start.y = Owner->YPos + YPos + y;
392 if (State == IE_GUI_BUTTON_LOCKED) {
393 SetState( IE_GUI_BUTTON_LOCKED_PRESSED );
394 return;
396 SetState( IE_GUI_BUTTON_PRESSED );
397 if (Flags & IE_GUI_BUTTON_SOUND) {
398 core->PlaySound( DS_BUTTON_PRESSED );
400 if ((Button & GEM_MB_DOUBLECLICK) && ButtonOnDoublePress) {
401 RunEventHandler( ButtonOnDoublePress );
402 printMessage("Button","Doubleclick detected\n",GREEN);
404 break;
405 case GEM_MB_SCRLUP:
406 if (scrlbr) {
407 scrlbr->ScrollUp();
408 core->RedrawAll();
410 break;
411 case GEM_MB_SCRLDOWN:
412 if (scrlbr) {
413 scrlbr->ScrollDown();
414 core->RedrawAll();
416 break;
419 /** Mouse Button Up */
420 void Button::OnMouseUp(unsigned short x, unsigned short y,
421 unsigned short Button, unsigned short Mod)
423 if (State == IE_GUI_BUTTON_DISABLED) {
424 return;
427 //what was just dropped?
428 int dragtype = 0;
429 if (core->GetDraggedItem ()) dragtype=1;
430 if (core->GetDraggedPortrait ()) dragtype=2;
432 //if something was dropped, but it isn't handled here: it didn't happen
433 if (dragtype && !ButtonOnDragDrop)
434 return;
436 switch (State) {
437 case IE_GUI_BUTTON_PRESSED:
438 if (ToggleState) {
439 SetState( IE_GUI_BUTTON_SELECTED );
440 } else {
441 SetState( IE_GUI_BUTTON_UNPRESSED );
443 break;
444 case IE_GUI_BUTTON_LOCKED_PRESSED:
445 SetState( IE_GUI_BUTTON_LOCKED );
446 break;
449 //in case of dragged/dropped portraits, allow the event to happen even
450 //when we are out of bound
451 if (dragtype!=2) {
452 if (( x >= Width ) || ( y >= Height )) {
453 return;
456 if (Flags & IE_GUI_BUTTON_CHECKBOX) {
457 //checkbox
458 ToggleState = !ToggleState;
459 if (ToggleState)
460 SetState( IE_GUI_BUTTON_SELECTED );
461 else
462 SetState( IE_GUI_BUTTON_UNPRESSED );
463 if (VarName[0] != 0) {
464 ieDword tmp = 0;
465 core->GetDictionary()->Lookup( VarName, tmp );
466 tmp ^= Value;
467 core->GetDictionary()->SetAt( VarName, tmp );
468 Owner->RedrawControls( VarName, tmp );
470 } else {
471 if (Flags & IE_GUI_BUTTON_RADIOBUTTON) {
472 //radio button
473 ToggleState = true;
474 SetState( IE_GUI_BUTTON_SELECTED );
476 if (VarName[0] != 0) {
477 core->GetDictionary()->SetAt( VarName, Value );
478 Owner->RedrawControls( VarName, Value );
482 switch (dragtype) {
483 case 1:
484 RunEventHandler( ButtonOnDragDrop );
485 return;
486 case 2:
487 RunEventHandler( ButtonOnDragDropPortrait );
488 return;
491 if ((Button&GEM_MB_NORMAL) == GEM_MB_ACTION) {
492 if ((Mod & GEM_MOD_SHIFT) && ButtonOnShiftPress)
493 RunEventHandler( ButtonOnShiftPress );
494 else
495 RunEventHandler( ButtonOnPress );
496 } else {
497 if (Button == GEM_MB_MENU && ButtonOnRightPress)
498 RunEventHandler( ButtonOnRightPress );
502 void Button::OnMouseOver(unsigned short x, unsigned short y)
504 if (State == IE_GUI_BUTTON_DISABLED) {
505 return;
508 if ( RunEventHandler( MouseOverButton )) {
509 //event handler destructed this object
510 return;
513 if (State == IE_GUI_BUTTON_LOCKED) {
514 return;
517 Owner->Cursor = IE_CURSOR_NORMAL;
519 //portrait buttons are draggable and locked
520 if ((Flags & IE_GUI_BUTTON_DRAGGABLE) &&
521 (State == IE_GUI_BUTTON_PRESSED || State ==IE_GUI_BUTTON_LOCKED_PRESSED)) {
522 // We use absolute screen position here, so drag_start
523 // remains valid even after window/control is moved
524 int dx = Owner->XPos + XPos + x - drag_start.x;
525 int dy = Owner->YPos + YPos + y - drag_start.y;
526 core->GetDictionary()->SetAt( "DragX", dx );
527 core->GetDictionary()->SetAt( "DragY", dy );
528 drag_start.x = (ieWord) (drag_start.x + dx);
529 drag_start.y = (ieWord) (drag_start.y + dy);
530 RunEventHandler( ButtonOnDrag );
534 void Button::OnMouseEnter(unsigned short /*x*/, unsigned short /*y*/)
536 if (State == IE_GUI_BUTTON_DISABLED) {
537 return;
540 if (MouseEnterButton !=0 && VarName[0] != 0) {
541 core->GetDictionary()->SetAt( VarName, Value );
544 RunEventHandler( MouseEnterButton );
547 void Button::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
549 if (State == IE_GUI_BUTTON_DISABLED) {
550 return;
553 if (MouseLeaveButton !=0 && VarName[0] != 0) {
554 core->GetDictionary()->SetAt( VarName, Value );
557 RunEventHandler( MouseLeaveButton );
561 /** Sets the Text of the current control */
562 int Button::SetText(const char* string, int /*pos*/)
564 free(Text);
565 Text = NULL;
566 if (string == NULL) {
567 hasText = false;
568 } else if (string[0] == 0) {
569 hasText = false;
570 } else {
571 Text = strndup( string, 255 );
572 if (Flags&IE_GUI_BUTTON_LOWERCASE)
573 strlwr( Text );
574 else if (Flags&IE_GUI_BUTTON_CAPS)
575 strupr( Text );
576 hasText = true;
578 Changed = true;
579 return 0;
582 /** Set Event Handler */
583 bool Button::SetEvent(int eventType, EventHandler handler)
585 Changed = true;
587 switch (eventType) {
588 case IE_GUI_BUTTON_ON_PRESS:
589 ButtonOnPress = handler;
590 break;
591 case IE_GUI_MOUSE_OVER_BUTTON:
592 MouseOverButton = handler;
593 break;
594 case IE_GUI_MOUSE_ENTER_BUTTON:
595 MouseEnterButton = handler;
596 break;
597 case IE_GUI_MOUSE_LEAVE_BUTTON:
598 MouseLeaveButton = handler;
599 break;
600 case IE_GUI_BUTTON_ON_SHIFT_PRESS:
601 ButtonOnShiftPress = handler;
602 break;
603 case IE_GUI_BUTTON_ON_RIGHT_PRESS:
604 ButtonOnRightPress = handler;
605 break;
606 case IE_GUI_BUTTON_ON_DRAG_DROP:
607 ButtonOnDragDrop = handler;
608 break;
609 case IE_GUI_BUTTON_ON_DRAG_DROP_PORTRAIT:
610 ButtonOnDragDropPortrait = handler;
611 break;
612 case IE_GUI_BUTTON_ON_DRAG:
613 ButtonOnDrag = handler;
614 break;
615 case IE_GUI_BUTTON_ON_DOUBLE_PRESS:
616 ButtonOnDoublePress = handler;
617 break;
618 default:
619 return false;
622 return true;
625 /** Redraws a button from a given radio button group */
626 void Button::RedrawButton(const char* VariableName, unsigned int Sum)
628 if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
629 return;
631 if (State == IE_GUI_BUTTON_DISABLED) {
632 return;
634 if (Flags & IE_GUI_BUTTON_RADIOBUTTON) {
635 ToggleState = ( Sum == Value );
636 } //radio button, exact value
637 else if (Flags & IE_GUI_BUTTON_CHECKBOX) {
638 ToggleState = !!( Sum & Value );
639 } //checkbox, bitvalue
640 else {
641 return;
642 } //other buttons, nothing to redraw
643 if (ToggleState) {
644 SetState(IE_GUI_BUTTON_SELECTED);
645 } else {
646 SetState(IE_GUI_BUTTON_UNPRESSED);
649 /** Sets the Picture */
650 void Button::SetPicture(Sprite2D* newpic)
652 core->GetVideoDriver()->FreeSprite( Picture );
653 ClearPictureList();
654 Picture = newpic;
655 Changed = true;
656 Flags |= IE_GUI_BUTTON_PICTURE;
657 Owner->Invalidate();
660 /** Clears the list of Pictures */
661 void Button::ClearPictureList()
663 Video* video = core->GetVideoDriver();
664 for (std::list<Sprite2D*>::iterator iter = PictureList.begin();
665 iter != PictureList.end(); ++iter)
666 video->FreeSprite( *iter );
667 PictureList.clear();
668 Changed = true;
669 Owner->Invalidate();
672 /** Add picture to the end of the list of Pictures */
673 void Button::StackPicture(Sprite2D* Picture)
675 PictureList.push_back(Picture);
676 Changed = true;
677 Flags |= IE_GUI_BUTTON_PICTURE;
678 Owner->Invalidate();
681 bool Button::IsPixelTransparent(unsigned short x, unsigned short y)
683 // some buttons have hollow Image frame filled w/ Picture
684 // some buttons in BG2 are text only (if BAM == 'GUICTRL')
685 if (Picture || PictureList.size() || ! Unpressed) return false;
686 return Unpressed->IsPixelTransparent(x, y);
689 // Set palette used for drawing button label in normal state
690 void Button::SetTextColor(const Color &fore, const Color &back)
692 gamedata->FreePalette( normal_palette );
693 normal_palette = core->CreatePalette( fore, back );
694 Changed = true;
697 void Button::SetHorizontalOverlay(double clip, const Color &src, const Color &dest)
699 if ((Clipping>clip) || !(Flags&IE_GUI_BUTTON_HORIZONTAL) ) {
700 Flags |= IE_GUI_BUTTON_HORIZONTAL;
701 SourceRGB=src;
702 DestRGB=dest;
703 GetTime( starttime );
704 starttime += 40;
706 Clipping = clip;
707 Changed = true;