1 /*
2 Copyright (C) 2005 Matthias Braun <matze@braunis.de>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
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.
13 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 
19 /**
20  * @file Window.cpp
21  * @author Matthias Braun
22  */
23 
24 #include <config.h>
25 
26 #include "Window.hpp"
27 
28 #include <sstream>
29 #include <stdexcept>
30 #include <iostream>
31 #include <assert.h>
32 
33 #include "callback/Callback.hpp"
34 #include "ComponentFactory.hpp"
35 #include "ComponentLoader.hpp"
36 #include "XmlReader.hpp"
37 #include "Painter.hpp"
38 #include "Button.hpp"
39 #include "Event.hpp"
40 #include "Desktop.hpp"
41 
Window()42 Window::Window()
43     : border(1), titlesize(0), dragging(false)
44 {
45 }
46 
~Window()47 Window::~Window()
48 {
49 }
50 
51 /**
52  * Parse a given XmlReader objest that represents the map.
53  *
54  * @param reader Reference to a XmlReader object representing a given XML file.
55  */
56 void
parse(XmlReader & reader)57 Window::parse(XmlReader& reader)
58 {
59     // parse attributes...
60     XmlReader::AttributeIterator iter(reader);
61     while(iter.next()) {
62         const char* name = (const char*) iter.getName();
63         const char* value = (const char*) iter.getValue();
64 
65         if(parseAttribute(name, value)) {
66             continue;
67         } else if(strcmp(name, "width") == 0) {
68             if(sscanf(value, "%f", &width) != 1) {
69                 std::stringstream msg;
70                 msg << "Couldn't parse width attribute (" << value << ").";
71                 throw std::runtime_error(msg.str());
72             }
73         } else if(strcmp(name, "height") == 0) {
74             if(sscanf(value, "%f", &height) != 1) {
75                 std::stringstream msg;
76                 msg << "Couldn't parse height attribute (" << value << ").";
77                 throw std::runtime_error(msg.str());
78             }
79         } else if(strcmp(name, "border") == 0) {
80             if(sscanf(value, "%f", &border) != 1) {
81                 std::stringstream msg;
82                 msg << "Couldn't parse border attribute (" << value << ").";
83                 throw std::runtime_error(msg.str());
84             }
85         } else if(strcmp(name, "titlesize") == 0) {
86             if(sscanf(value, "%f", &titlesize) != 1) {
87                 std::stringstream msg;
88                 msg << "Couldn't parse titlesize attribute (" << value << ").";
89                 throw std::runtime_error(msg.str());
90             }
91         } else {
92             std::cerr << "Unknown attribute '" << name << "' skipped.\n";
93         }
94     }
95     if(width <= 0 || height <= 0)
96         throw std::runtime_error("Width or Height invalid");
97 
98     childs.assign(5, Child());
99 
100     int depth = reader.getDepth();
101     while(reader.read() && reader.getDepth() > depth) {
102         if(reader.getNodeType() == XML_READER_TYPE_ELEMENT) {
103             std::string element = (const char*) reader.getName();
104             if(element == "title") {
105                 resetChild(title(), parseEmbeddedComponent(reader));
106             } else if(element == "closebutton") {
107                 std::auto_ptr<Button> button (new Button());
108                 button->parse(reader);
109                 resetChild(closeButton(), button.release());
110             } else if(element == "contents") {
111                 resetChild(contents(), parseEmbeddedComponent(reader));
112             } else if(element == "background") {
113                 resetChild(background(), parseEmbeddedComponent(reader));
114             } else if(element == "title-background") {
115                 resetChild(title_background(), parseEmbeddedComponent(reader));
116             } else {
117                 std::cerr << "Skipping unknown element '"
118                     << element << "'.\n";
119                 reader.nextNode();
120             }
121         }
122     }
123 
124     // layout
125     float closeButtonHeight = 0;
126     float closeButtonWidth = 0;
127     float closeButtonBorder = 0;
128     if(closeButton().getComponent() != 0) {
129         closeButtonHeight = closeButton().getComponent()->getHeight();
130         if(titlesize < closeButtonHeight) {
131             titlesize = closeButtonHeight;
132         }
133 
134         closeButtonWidth = closeButton().getComponent()->getWidth();
135         closeButtonBorder = (titlesize - closeButtonHeight) / 2;
136         closeButtonWidth += 2*closeButtonBorder;
137         closeButtonHeight += 2*closeButtonBorder;
138     }
139 
140     float compWidth = width - 2*border;
141     float compHeight = height - 2*border;
142     title().setPos(Vector2(border, border));
143     title().getComponent()->resize(compWidth - closeButtonWidth, titlesize);
144     if(title_background().getComponent() != 0) {
145         title_background().setPos(title().getPos());
146         title_background().getComponent()->resize(
147                 compWidth - closeButtonWidth, titlesize);
148     }
149     if(closeButton().getComponent() != 0) {
150         closeButton().setPos(Vector2(
151                     border + compWidth - closeButtonWidth + closeButtonBorder,
152                     border + closeButtonBorder));
153     }
154     contents().setPos(Vector2(border, border + titlesize));
155     contents().getComponent()->resize(compWidth, compHeight - titlesize);
156     if(background().getComponent() != 0) {
157         background().setPos(Vector2(0, 0));
158         background().getComponent()->resize(width, height);
159     }
160 
161     // connect signals...
162     if(closeButton().getComponent() != 0) {
163         Button* button = (Button*) closeButton().getComponent();
164         button->clicked.connect(
165                 makeCallback(*this, &Window::closeButtonClicked));
166     }
167 }
168 
169 /**
170  * Draw the map.
171  *
172  * @param painter Reference to a Painter object.
173  */
174 void
draw(Painter & painter)175 Window::draw(Painter& painter)
176 {
177     Component::draw(painter);
178 
179     painter.setLineColor(Color(0, 0, 0, 0xff));
180     painter.drawRectangle(Rect2D(0, 0, width, height));
181 }
182 
183 void
event(const Event & event)184 Window::event(const Event& event)
185 {
186     switch(event.type) {
187         case Event::MOUSEBUTTONDOWN:
188             if(event.inside && title().inside(event.mousepos)) {
189                 dragging = true;
190                 dragOffset = event.mousepos - title().getPos();
191             }
192             break;
193 
194         case Event::MOUSEBUTTONUP:
195             if(dragging) {
196                 dragging = false;
197             }
198             break;
199 
200         case Event::MOUSEMOTION: {
201             if(!dragging)
202                 break;
203 
204             Desktop* desktop = dynamic_cast<Desktop*> (getParent());
205             assert(desktop != 0);
206             if(!desktop)
207                 return;
208 
209             // try to move window...
210             Vector2 newpos = desktop->getPos(this) +
211                 event.mousepos - dragOffset;
212             desktop->move(this, newpos);
213             break;
214         }
215 
216         default:
217             break;
218     }
219 
220     // distribute event to child components...
221     Component::event(event);
222 }
223 
224 void
closeButtonClicked(Button *)225 Window::closeButtonClicked(Button* )
226 {
227     Desktop* desktop = dynamic_cast<Desktop*> (getParent());
228     assert(desktop != 0);
229     if(!desktop)
230         return;
231 
232     desktop->remove(this);
233 }
234 
235 IMPLEMENT_COMPONENT_FACTORY(Window)
236