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