factored out the EFFv2 saving into EFFImporter
[gemrb.git] / gemrb / core / GUI / Window.cpp
blobed1395aaff2ca80a6885cfb9c0284d05a6976f8c
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 "GUI/Window.h"
23 #include "GUI/Button.h"
24 #include "GUI/Control.h"
25 #include "GUI/MapControl.h"
26 #include "GUI/Progressbar.h"
27 #include "GUI/Slider.h"
29 #include "win32def.h"
31 #include "Interface.h"
32 #include "Video.h"
34 Window::Window(unsigned short WindowID, unsigned short XPos,
35 unsigned short YPos, unsigned short Width, unsigned short Height)
37 this->WindowID = WindowID;
38 this->XPos = XPos;
39 this->YPos = YPos;
40 this->Width = Width;
41 this->Height = Height;
42 this->BackGround = NULL;
43 lastC = NULL;
44 lastFocus = NULL;
45 lastMouseFocus = NULL;
46 lastOver = NULL;
47 Visible = WINDOW_INVISIBLE;
48 Flags = WF_CHANGED;
49 Cursor = IE_CURSOR_NORMAL;
50 DefaultControl[0] = -1;
51 DefaultControl[1] = -1;
52 ScrollControl = -1;
55 Window::~Window()
57 std::vector< Control*>::iterator m = Controls.begin();
58 while (Controls.size() != 0) {
59 Control* ctrl = ( *m );
60 delete ctrl;
61 Controls.erase( m );
62 m = Controls.begin();
64 core->GetVideoDriver()->FreeSprite( BackGround );
65 BackGround = NULL;
67 /** Add a Control in the Window */
68 void Window::AddControl(Control* ctrl)
70 if (ctrl == NULL) {
71 return;
73 ctrl->Owner = this;
74 for (size_t i = 0; i < Controls.size(); i++) {
75 if (Controls[i]->ControlID == ctrl->ControlID) {
76 delete( Controls[i] );
77 Controls[i] = ctrl;
78 Invalidate();
79 return;
82 Controls.push_back( ctrl );
83 Invalidate();
85 /** Set the Window's BackGround Image. If 'img' is NULL, no background will be set. If the 'clean' parameter is true (default is false) the old background image will be deleted. */
86 void Window::SetBackGround(Sprite2D* img, bool clean)
88 if (clean && BackGround) {
89 core->GetVideoDriver()->FreeSprite( this->BackGround );
91 BackGround = img;
92 Invalidate();
94 /** This function Draws the Window on the Output Screen */
95 void Window::DrawWindow()
97 Video* video = core->GetVideoDriver();
98 Region clip( XPos, YPos, Width, Height );
99 //Frame && Changed
100 if ( (Flags & (WF_FRAME|WF_CHANGED) )== (WF_FRAME|WF_CHANGED) ) {
101 Region screen( 0, 0, core->Width, core->Height );
102 video->SetClipRect( NULL );
103 //removed this?
104 Color black = { 0, 0, 0, 255 };
105 video->DrawRect( screen, black );
106 if (core->WindowFrames[0])
107 video->BlitSprite( core->WindowFrames[0], 0, 0, true );
108 if (core->WindowFrames[1])
109 video->BlitSprite( core->WindowFrames[1], core->Width - core->WindowFrames[1]->Width, 0, true );
110 if (core->WindowFrames[2])
111 video->BlitSprite( core->WindowFrames[2], (core->Width - core->WindowFrames[2]->Width) / 2, 0, true );
112 if (core->WindowFrames[3])
113 video->BlitSprite( core->WindowFrames[3], (core->Width - core->WindowFrames[3]->Width) / 2, core->Height - core->WindowFrames[3]->Height, true );
114 } else if (clip_regions.size()) {
115 // clip drawing (we only do Background right now) for InvalidateForControl
116 for (unsigned int i = 0; i < clip_regions.size(); i++) {
117 Region to_clip = clip_regions[i];
118 to_clip.x += XPos;
119 to_clip.y += YPos;
120 video->SetClipRect(&to_clip);
121 if (BackGround) {
122 video->BlitSprite( BackGround, XPos, YPos, true );
126 clip_regions.clear();
127 video->SetClipRect( &clip );
128 //Float || Changed
129 if (BackGround && (Flags & (WF_FLOAT|WF_CHANGED) ) ) {
130 video->BlitSprite( BackGround, XPos, YPos, true );
132 std::vector< Control*>::iterator m;
133 for (m = Controls.begin(); m != Controls.end(); ++m) {
134 ( *m )->Draw( XPos, YPos );
136 if ( (Flags&WF_CHANGED) && (Visible == WINDOW_GRAYED) ) {
137 Color black = { 0, 0, 0, 128 };
138 video->DrawRect(clip, black);
140 video->SetClipRect( NULL );
141 Flags &= ~WF_CHANGED;
144 /** Set window frame used to fill screen on higher resolutions*/
145 void Window::SetFrame()
147 if ( (Width < core->Width) || (Height < core->Height) ) {
148 Flags|=WF_FRAME;
150 Invalidate();
153 /** Returns the Control at X,Y Coordinates */
154 Control* Window::GetControl(unsigned short x, unsigned short y, bool ignore)
156 Control* ctrl = NULL;
158 //Check if we are still on the last control
159 if (( lastC != NULL )) {
160 if (( XPos + lastC->XPos <= x )
161 && ( YPos + lastC->YPos <= y )
162 && ( XPos + lastC->XPos + lastC->Width >= x )
163 && ( YPos + lastC->YPos + lastC->Height >= y )
164 && ! lastC->IsPixelTransparent (x - XPos - lastC->XPos, y - YPos - lastC->YPos)) {
165 //Yes, we are on the last returned Control
166 return lastC;
169 std::vector< Control*>::const_iterator m;
170 for (m = Controls.begin(); m != Controls.end(); m++) {
171 if (ignore && (*m)->ControlID&IGNORE_CONTROL) {
172 continue;
174 if (( XPos + ( *m )->XPos <= x )
175 && ( YPos + ( *m )->YPos <= y )
176 && ( XPos + ( *m )->XPos + ( *m )->Width >= x )
177 && ( YPos + ( *m )->YPos + ( *m )->Height >= y )
178 && ! ( *m )->IsPixelTransparent (x - XPos - ( *m )->XPos, y - YPos - ( *m )->YPos)) {
179 ctrl = *m;
180 break;
183 lastC = ctrl;
184 return ctrl;
187 Control* Window::GetOver() const
189 return lastOver;
192 Control* Window::GetFocus() const
194 return lastFocus;
197 Control* Window::GetMouseFocus() const
199 return lastMouseFocus;
202 /** Sets 'ctrl' as Focused */
203 void Window::SetFocused(Control* ctrl)
205 if (lastFocus != NULL) {
206 lastFocus->hasFocus = false;
207 lastFocus->Changed = true;
209 lastFocus = ctrl;
210 if (ctrl != NULL) {
211 lastFocus->hasFocus = true;
212 lastFocus->Changed = true;
216 /** Sets 'ctrl' as Mouse Focused */
217 void Window::SetMouseFocused(Control* ctrl)
219 if (lastMouseFocus != NULL) {
220 lastMouseFocus->Changed = true;
222 lastMouseFocus = ctrl;
223 if (ctrl != NULL) {
224 lastMouseFocus->Changed = true;
228 unsigned int Window::GetControlCount() const
230 return Controls.size();
233 Control* Window::GetControl(unsigned short i) const
235 if (i < Controls.size()) {
236 return Controls[i];
238 return NULL;
241 bool Window::IsValidControl(unsigned short ID, Control *ctrl) const
243 size_t i = Controls.size();
244 while (i--) {
245 if (Controls[i]==ctrl) {
246 return ctrl->ControlID==ID;
249 return false;
252 void Window::DelControl(unsigned short i)
254 if (i < Controls.size() ) {
255 Control *ctrl = Controls[i];
256 if (ctrl==lastC) {
257 lastC=NULL;
259 if (ctrl==lastOver) {
260 lastOver=NULL;
262 if (ctrl==lastFocus) {
263 lastFocus=NULL;
265 if (ctrl==lastMouseFocus) {
266 lastMouseFocus=NULL;
268 delete ctrl;
269 Controls.erase(Controls.begin()+i);
271 Invalidate();
274 Control* Window::GetDefaultControl(unsigned int ctrltype) const
276 if (!Controls.size()) {
277 return NULL;
279 if (ctrltype>=2) {
280 return NULL;
282 return GetControl( (ieWord) DefaultControl[ctrltype] );
285 Control* Window::GetScrollControl() const
287 if (!Controls.size()) {
288 return NULL;
290 return GetControl( (ieWord) ScrollControl );
293 void Window::release(void)
295 Visible = WINDOW_INVALID;
296 lastC = NULL;
297 lastFocus = NULL;
298 lastMouseFocus = NULL;
299 lastOver = NULL;
302 /** Redraw all the Window */
303 void Window::Invalidate()
305 DefaultControl[0] = -1;
306 DefaultControl[1] = -1;
307 ScrollControl = -1;
308 for (unsigned int i = 0; i < Controls.size(); i++) {
309 if (!Controls[i]) {
310 continue;
312 Controls[i]->Changed = true;
313 switch (Controls[i]->ControlType) {
314 case IE_GUI_SCROLLBAR:
315 if ((ScrollControl == -1) || (Controls[i]->Flags & IE_GUI_SCROLLBAR_DEFAULT))
316 ScrollControl = i;
317 break;
318 case IE_GUI_BUTTON:
319 if (( Controls[i]->Flags & IE_GUI_BUTTON_DEFAULT )) {
320 DefaultControl[0] = i;
322 if (( Controls[i]->Flags & IE_GUI_BUTTON_CANCEL )) {
323 DefaultControl[1] = i;
325 break;
326 //falling through
327 case IE_GUI_GAMECONTROL:
328 DefaultControl[0] = i;
329 DefaultControl[1] = i;
330 break;
331 default: ;
334 Flags |= WF_CHANGED;
337 /** Redraw enough to update the specified Control */
338 void Window::InvalidateForControl(Control *ctrl) {
339 // TODO: for this to be general-purpose, we should mark anything inside this
340 // region with Changed, and also do mass Invalidate() if we overlap with
341 // another window, but for now this just clips the *background*, see DrawWindow()
342 clip_regions.push_back( Region(ctrl->XPos, ctrl->YPos, ctrl->Width, ctrl->Height) );
345 void Window::RedrawControls(const char* VarName, unsigned int Sum)
347 for (unsigned int i = 0; i < Controls.size(); i++) {
348 switch (Controls[i]->ControlType) {
349 case IE_GUI_MAP:
351 MapControl *mc = ( MapControl* ) (Controls[i]);
352 mc->RedrawMapControl( VarName, Sum );
353 break;
355 case IE_GUI_BUTTON:
357 Button* bt = ( Button* ) ( Controls[i] );
358 bt->RedrawButton( VarName, Sum );
359 break;
361 case IE_GUI_TEXTAREA:
363 TextArea* pb = ( TextArea* ) ( Controls[i] );
364 pb->RedrawTextArea( VarName, Sum );
365 break;
367 case IE_GUI_PROGRESSBAR:
369 Progressbar* pb = ( Progressbar* ) ( Controls[i] );
370 pb->RedrawProgressbar( VarName, Sum );
371 break;
373 case IE_GUI_SLIDER:
375 Slider* sl = ( Slider* ) ( Controls[i] );
376 sl->RedrawSlider( VarName, Sum );
377 break;
379 case IE_GUI_SCROLLBAR:
381 ScrollBar* sb = ( ScrollBar* ) ( Controls[i] );
382 sb->RedrawScrollBar( VarName, Sum );
383 break;
389 /** Searches for a ScrollBar and a TextArea to link them */
390 void Window::Link(unsigned short SBID, unsigned short TAID)
392 ScrollBar* sb = NULL;
393 TextArea* ta = NULL;
394 std::vector< Control*>::iterator m;
395 for (m = Controls.begin(); m != Controls.end(); m++) {
396 if (( *m )->Owner != this)
397 continue;
398 if (( *m )->ControlType == IE_GUI_SCROLLBAR) {
399 if (( *m )->ControlID == SBID) {
400 sb = ( ScrollBar * ) ( *m );
401 if (ta != NULL)
402 break;
404 } else if (( *m )->ControlType == IE_GUI_TEXTAREA) {
405 if (( *m )->ControlID == TAID) {
406 ta = ( TextArea * ) ( *m );
407 if (sb != NULL)
408 break;
412 if (sb && ta) {
413 sb->ta = ta;
414 ta->SetScrollBar( sb );
418 void Window::OnMouseEnter(unsigned short x, unsigned short y, Control *ctrl)
420 lastOver = ctrl;
421 if (!lastOver) {
422 return;
424 lastOver->OnMouseEnter( x - XPos - lastOver->XPos, y - YPos - lastOver->YPos );
427 void Window::OnMouseLeave(unsigned short x, unsigned short y)
429 if (!lastOver) {
430 return;
432 lastOver->OnMouseLeave( x - XPos - lastOver->XPos, y - YPos - lastOver->YPos );
433 lastOver = NULL;
436 void Window::OnMouseOver(unsigned short x, unsigned short y)
438 if (!lastOver) {
439 return;
441 lastOver->OnMouseOver( x - XPos - lastOver->XPos, y - YPos - lastOver->YPos );