~ubuntu-branches/ubuntu/precise/widelands/precise-backports

« back to all changes in this revision

Viewing changes to src/watchwindow.cc

  • Committer: Bazaar Package Importer
  • Author(s): Martin Quinson
  • Date: 2005-02-14 10:41:12 UTC
  • Revision ID: james.westby@ubuntu.com-20050214104112-6v08iux9fptxpva9
Tags: upstream-build9
Import upstream version build9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2002, 2004 by The Widelands Development Team
 
3
 *
 
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.
 
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., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 *
 
18
 */
 
19
 
 
20
#include "interactive_player.h"
 
21
#include "bob.h"
 
22
#include "game.h"
 
23
#include "map.h"
 
24
#include "mapview.h"
 
25
#include "ui_button.h"
 
26
#include "ui_signal.h"
 
27
#include "ui_window.h"
 
28
#include "watchwindow.h"
 
29
#include "options.h"
 
30
#include <vector>
 
31
 
 
32
#define NUM_VIEWS 5
 
33
#define REFRESH_TIME 5000
 
34
 
 
35
/*
 
36
==============================================================================
 
37
 
 
38
WatchWindow
 
39
 
 
40
==============================================================================
 
41
*/
 
42
//Holds information for a view
 
43
struct WatchWindowView {
 
44
        Point view_point;
 
45
        Interactive_Player *parent;
 
46
        Object_Ptr tracking;            // if non-null, we're tracking a Bob
 
47
};
 
48
 
 
49
class WatchWindow : public UIWindow {
 
50
public:
 
51
        WatchWindow(Interactive_Player *parent, int x, int y, int w, int h, Coords coords, bool single_window=false);
 
52
        ~WatchWindow();
 
53
        
 
54
        UISignal1<Point> warp_mainview;
 
55
 
 
56
        void start_tracking(Point pos);
 
57
        void toggle_tracking();
 
58
        void act_mainview_goto();
 
59
        
 
60
        void add_view(Coords coords);
 
61
        void next_view(bool first=false);
 
62
        void show_view(bool first=false);
 
63
        Point calc_coords(Coords coords);
 
64
        void save_coords();
 
65
        void set_view(int index);
 
66
        void close_cur_view();
 
67
        void toggle_buttons();
 
68
                
 
69
protected:
 
70
        virtual void think();
 
71
        void stop_tracking_by_drag(int x, int y);
 
72
 
 
73
private:
 
74
        Game*                           m_game;
 
75
        Map_View*               m_mapview;
 
76
        bool m_single_window;
 
77
        uint last_visit;
 
78
        int m_cur_index;
 
79
        std::vector<WatchWindowView> m_views;
 
80
        UIButton* m_view_btns[NUM_VIEWS];
 
81
};
 
82
 
 
83
 
 
84
static WatchWindow *g_watch_window = NULL;
 
85
 
 
86
/*
 
87
===============
 
88
WatchWindow::WatchWindow
 
89
 
 
90
Initialize a watch window.
 
91
===============
 
92
*/
 
93
WatchWindow::WatchWindow(Interactive_Player *parent, int x, int y, int w, int h, Coords coords, bool single_window)
 
94
        : UIWindow(parent, x, y, w, h, "Watch")
 
95
{
 
96
        UIButton* btn;
 
97
        
 
98
        m_game = parent->get_game();
 
99
        last_visit = m_game->get_gametime();
 
100
        m_single_window = single_window;
 
101
        
 
102
        // UIButtons
 
103
        btn = new UIButton(this, 0, h - 34, 34, 34, 20);
 
104
        btn->set_pic(g_gr->get_picture(PicMod_UI, "pics/menu_watch_follow.png", true));
 
105
        btn->clicked.set(this, &WatchWindow::toggle_tracking);
 
106
 
 
107
        btn = new UIButton(this, 34, h - 34, 34, 34, 21);
 
108
        btn->set_pic(g_gr->get_picture(PicMod_UI, "pics/menu_goto.png", true));
 
109
        btn->clicked.set(this, &WatchWindow::act_mainview_goto);
 
110
        
 
111
        if (m_single_window) {
 
112
                for (int i=0;i<NUM_VIEWS;i++) {
 
113
                        btn = new UIButton(this, 74 + (17 * i), 200 - 34, 17, 34, 0, i);
 
114
                        btn->set_title("-");
 
115
                        btn->clickedid.set(this, &WatchWindow::set_view);
 
116
                        m_view_btns[i] = btn;
 
117
                }
 
118
                
 
119
                btn = new UIButton(this, w-34, h - 34, 34, 34, 22);
 
120
                btn->set_pic(g_gr->get_picture(PicMod_UI, "pics/menu_abort.png", true));
 
121
                btn->clicked.set(this, &WatchWindow::close_cur_view);
 
122
        }
 
123
        m_mapview = new Map_View(this, 0, 0, 200, 166, parent);
 
124
        m_mapview->fieldclicked.set(parent, &Interactive_Player::field_action);
 
125
        m_mapview->warpview.set(this, &WatchWindow::stop_tracking_by_drag);
 
126
        warp_mainview.set(parent, &Interactive_Base::move_view_to_point);
 
127
        
 
128
        add_view(coords);
 
129
        next_view(true);
 
130
        set_cache(false);
 
131
}
 
132
 
 
133
//Add a view to a watchwindow, if there is space left
 
134
void WatchWindow::add_view(Coords coords) {
 
135
        if (m_views.size() >= NUM_VIEWS)
 
136
                return;
 
137
        WatchWindowView view;
 
138
        
 
139
        view.tracking = 0;
 
140
        view.view_point = calc_coords(coords);
 
141
        
 
142
        m_views.push_back(view);
 
143
        if (m_single_window)
 
144
                toggle_buttons();
 
145
}
 
146
 
 
147
//Calc point on map from coords
 
148
Point WatchWindow::calc_coords(Coords coords) {
 
149
        // Initial positioning
 
150
        int vx = MULTIPLY_WITH_FIELD_WIDTH(coords.x);
 
151
        int vy = MULTIPLY_WITH_HALF_FIELD_HEIGHT(coords.y);
 
152
                
 
153
        Point p (vx - m_mapview->get_w()/2, vy - m_mapview->get_h()/2);
 
154
        return p;
 
155
}
 
156
 
 
157
//Switch to next view 
 
158
void WatchWindow::next_view(bool first) {
 
159
        if (!first && m_views.size() == 1)
 
160
                return;
 
161
        if (!first)
 
162
                save_coords();
 
163
        if (first || (static_cast<uint>(m_cur_index) == m_views.size()-1 && m_cur_index != 0))
 
164
                m_cur_index = 0;
 
165
        else if (static_cast<uint>(m_cur_index) < m_views.size()-1)
 
166
                m_cur_index++;
 
167
        show_view(first);
 
168
}
 
169
 
 
170
//Sets the current view to index and resets timeout
 
171
void WatchWindow::set_view(int index) {
 
172
        save_coords();
 
173
        m_cur_index = index;
 
174
        last_visit = m_game->get_gametime();
 
175
        show_view();
 
176
}
 
177
 
 
178
//Saves the coordinates of a view if it was already shown (and possibly moved)
 
179
void WatchWindow::save_coords() {
 
180
        m_views[m_cur_index].view_point = m_mapview->get_viewpoint();
 
181
}
 
182
 
 
183
//Closes current view and disables button
 
184
void WatchWindow::close_cur_view() {
 
185
        if (m_views.size() == 1) {
 
186
                delete this;
 
187
                return;
 
188
        }
 
189
        
 
190
        int old_index = m_cur_index;
 
191
        next_view();
 
192
        
 
193
        std::vector<WatchWindowView>::iterator view_it = m_views.begin();
 
194
        
 
195
        for (int i=0;i<old_index;i++)
 
196
                view_it++;
 
197
        
 
198
        m_view_btns[m_cur_index]->set_enabled(false);
 
199
        m_views.erase(view_it);
 
200
        toggle_buttons();
 
201
}
 
202
 
 
203
//Enables/Disables buttons for views
 
204
void WatchWindow::toggle_buttons() {
 
205
        for (uint i=0;i<NUM_VIEWS;i++) {
 
206
                if (i<m_views.size()) {
 
207
                        char buf[32];
 
208
                        snprintf(buf, sizeof(buf), "%i", i+1);
 
209
                        m_view_btns[i]->set_title(buf);
 
210
                        m_view_btns[i]->set_enabled(true);
 
211
                }
 
212
                else {
 
213
                        m_view_btns[i]->set_title("-");
 
214
                        m_view_btns[i]->set_enabled(false);
 
215
                }
 
216
        }
 
217
}
 
218
 
 
219
//Draws the current view
 
220
void WatchWindow::show_view(bool first) {
 
221
        m_mapview->set_viewpoint(m_views[m_cur_index].view_point);
 
222
        //Tracking turned of by default
 
223
        //start_tracking(m_views[m_cur_index].view_point);
 
224
}
 
225
 
 
226
WatchWindow::~WatchWindow() {
 
227
        g_watch_window = NULL;
 
228
}
 
229
 
 
230
/*
 
231
===============
 
232
WatchWindow::start_tracking
 
233
 
 
234
Find the nearest bob. Other objects cannot move and are therefore not of
 
235
interest.
 
236
 
 
237
point is *not* a coordinate, but a map-global position in pixels.
 
238
===============
 
239
*/
 
240
void WatchWindow::start_tracking(Point pos)
 
241
{
 
242
        Map* map = m_game->get_map();
 
243
        std::vector<Bob*> bobs;
 
244
        Coords center;
 
245
        int radius;
 
246
 
 
247
        map->normalize_pix(&pos);
 
248
        center = map->calc_coords(pos);
 
249
 
 
250
        // Scan progressively larger circles around the given position for suitable bobs
 
251
        for(radius = 2; radius <= 32; radius <<= 1) {
 
252
                if (map->find_bobs(center, radius, &bobs))
 
253
                        break;
 
254
        }
 
255
 
 
256
        // Find the bob closest to us
 
257
        int closest_dist = -1;
 
258
        Bob* closest = 0;
 
259
 
 
260
        for(uint i = 0; i < bobs.size(); i++) {
 
261
                Bob* bob = bobs[i];
 
262
                Point p;
 
263
                int dist;
 
264
 
 
265
                map->get_pix(bob->get_position(), &p.x, &p.y);
 
266
                bob->calc_drawpos(m_game, p, &p);
 
267
 
 
268
                dist = map->calc_pix_distance(p, pos);
 
269
 
 
270
                if (!closest || closest_dist > dist) {
 
271
                        closest = bob;
 
272
                        closest_dist = dist;
 
273
                }
 
274
        }
 
275
        m_views[m_cur_index].tracking = closest;
 
276
}
 
277
 
 
278
 
 
279
/*
 
280
===============
 
281
WatchWindow::toggle_tracking
 
282
 
 
283
If we're currently tracking, stop tracking.
 
284
Otherwise, start tracking the nearest bob from our current position.
 
285
===============
 
286
*/
 
287
void WatchWindow::toggle_tracking()
 
288
{
 
289
        
 
290
        Map_Object* obj = m_views[m_cur_index].tracking.get(m_game);
 
291
 
 
292
        if (obj)
 
293
                m_views[m_cur_index].tracking = 0;
 
294
        else {
 
295
                start_tracking(m_mapview->get_viewpoint() +
 
296
                                        Point(m_mapview->get_w()/2, m_mapview->get_h()/2));
 
297
        }
 
298
}
 
299
 
 
300
 
 
301
/*
 
302
===============
 
303
WatchWindow::act_mainview_goto
 
304
 
 
305
Cause the main mapview to jump to our current position.
 
306
===============
 
307
*/
 
308
void WatchWindow::act_mainview_goto()
 
309
{
 
310
        Point p = m_mapview->get_viewpoint() + Point(m_mapview->get_w()/2, m_mapview->get_h()/2);
 
311
 
 
312
        warp_mainview.call(p);
 
313
}
 
314
 
 
315
 
 
316
/*
 
317
===============
 
318
WatchWindow::think
 
319
 
 
320
Update the mapview if we're tracking something.
 
321
===============
 
322
*/
 
323
void WatchWindow::think()
 
324
{
 
325
        UIWindow::think();
 
326
        
 
327
        Map_Object* obj = m_views[m_cur_index].tracking.get(m_game);
 
328
 
 
329
        if ((m_game->get_gametime() - last_visit) > REFRESH_TIME) {
 
330
                last_visit = m_game->get_gametime();
 
331
                next_view();
 
332
                return;
 
333
        }
 
334
        
 
335
        if (obj) {
 
336
                Bob* bob = (Bob*)obj;
 
337
                Point pos;
 
338
 
 
339
                assert(obj->get_type() == Map_Object::BOB);
 
340
 
 
341
                m_game->get_map()->get_pix(bob->get_position(), &pos.x, &pos.y);
 
342
                bob->calc_drawpos(m_game, pos, &pos);
 
343
 
 
344
                m_mapview->set_viewpoint(pos - Point(m_mapview->get_w()/2, m_mapview->get_h()/2));
 
345
        }
 
346
}
 
347
 
 
348
 
 
349
/*
 
350
===============
 
351
WatchWindow::stop_tracking_by_drag
 
352
 
 
353
When the user drags the mapview, we stop tracking.
 
354
===============
 
355
*/
 
356
void WatchWindow::stop_tracking_by_drag(int x, int y)
 
357
{
 
358
        //Disable switching while dragging
 
359
        if (m_mapview->is_dragging()) {
 
360
                last_visit = m_game->get_gametime();
 
361
                m_views[m_cur_index].tracking = 0;
 
362
        }
 
363
}
 
364
 
 
365
 
 
366
/*
 
367
===============
 
368
show_watch_window
 
369
 
 
370
Open a watch window.
 
371
===============
 
372
*/
 
373
void show_watch_window(Interactive_Player *parent, Coords coords)
 
374
{
 
375
        Section *s = g_options.pull_section("global");
 
376
        if (s->get_bool("single_watchwin",false)) {
 
377
                if (g_watch_window != NULL)
 
378
                        g_watch_window->add_view(coords);
 
379
                else
 
380
                        g_watch_window = new WatchWindow(parent, 250, 150, 200, 200, coords,true);
 
381
        }
 
382
        else
 
383
                new WatchWindow(parent, 250, 150, 200, 200, coords,false);
 
384
}