author | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
---|---|---|
committer | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
commit | 15318cad33835e4e2dc620d033e43cd930676cdd (patch) (unidiff) | |
tree | c2fa0399a2c47fda8e2cd0092c73a809d17f68eb /core/settings/citytime/zonemap.cpp | |
download | opie-15318cad33835e4e2dc620d033e43cd930676cdd.zip opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2 |
Initial revision
Diffstat (limited to 'core/settings/citytime/zonemap.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | core/settings/citytime/zonemap.cpp | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/core/settings/citytime/zonemap.cpp b/core/settings/citytime/zonemap.cpp new file mode 100644 index 0000000..337f4d9 --- a/dev/null +++ b/core/settings/citytime/zonemap.cpp | |||
@@ -0,0 +1,670 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | |||
21 | #include "sun.h" | ||
22 | #include "zonemap.h" | ||
23 | |||
24 | #include <qpe/resource.h> | ||
25 | #include <qpe/timestring.h> | ||
26 | #include <qpe/qpeapplication.h> | ||
27 | |||
28 | #include <qdatetime.h> | ||
29 | #include <qfile.h> | ||
30 | #include <qimage.h> | ||
31 | #include <qlabel.h> | ||
32 | #include <qlist.h> | ||
33 | #include <qmessagebox.h> | ||
34 | #include <qpixmap.h> | ||
35 | #include <qpainter.h> | ||
36 | #include <qregexp.h> | ||
37 | #include <qtextstream.h> | ||
38 | #include <qtimer.h> | ||
39 | #include <qtoolbutton.h> | ||
40 | |||
41 | #include <limits.h> | ||
42 | |||
43 | // the map file... | ||
44 | static const char strZONEINFO[] = "/usr/share/zoneinfo/zone.tab"; | ||
45 | static const char strMAP[] = "simple_grid_400"; | ||
46 | |||
47 | // the maximum distance we'll allow the pointer to be away from a city | ||
48 | // and still show the city's time | ||
49 | static const int iTHRESHOLD = 50000; | ||
50 | |||
51 | // The label offset (how far away from pointer) | ||
52 | static const int iLABELOFFSET = 8; | ||
53 | |||
54 | // the size of the dot to draw, and where to start it | ||
55 | static const int iCITYSIZE = 3; | ||
56 | const int iCITYOFFSET = 2; | ||
57 | |||
58 | // the darkening function | ||
59 | static inline void darken( QImage *pImage, int start, int stop, int row ); | ||
60 | static void dayNight( QImage *pImage ); | ||
61 | |||
62 | ZoneField::ZoneField( const QString& strLine ) | ||
63 | { | ||
64 | // make a bunch of RegExp's to match the data from the line | ||
65 | QRegExp regCoord( "[-+][0-9]+" );// the latitude | ||
66 | QRegExp regCountry( "[A-Za-z]+/" ); // the country (not good enough) | ||
67 | QRegExp regCity( "[A-Za-z_-]*" ); // the city | ||
68 | |||
69 | int iStart, | ||
70 | iStop, | ||
71 | iLen, | ||
72 | tmp; | ||
73 | QString strTmp; | ||
74 | // we should be able to assume that the country code is always the first | ||
75 | // two chars, so just grap them and let it go... | ||
76 | strCountryCode = strLine.left( 2 ); | ||
77 | iStart = regCoord.match( strLine, 0, &iLen ); | ||
78 | if ( iStart >= 0 ) { | ||
79 | strTmp = strLine.mid( iStart, iLen ); | ||
80 | tmp = strTmp.toInt(); | ||
81 | // okay, there are two versions of the format, make a decision based on | ||
82 | // the size... | ||
83 | // Oh BTW, we are storing everything in seconds! | ||
84 | if ( iLen < 7 ) { | ||
85 | _y = tmp / 100; | ||
86 | _y *= 60; | ||
87 | _y += tmp % 100; | ||
88 | _y *= 60; | ||
89 | } else { | ||
90 | _y = tmp / 10000; | ||
91 | _y *= 60; | ||
92 | tmp %= 10000; | ||
93 | _y += tmp / 100; | ||
94 | _y *= 60; | ||
95 | tmp %= 100; | ||
96 | _y += tmp; | ||
97 | } | ||
98 | } | ||
99 | iStart = regCoord.match( strLine, iStart + iLen, &iLen ); | ||
100 | if ( iStart >= 0 ) { | ||
101 | strTmp = strLine.mid( iStart, iLen ); | ||
102 | tmp = strTmp.toInt(); | ||
103 | if ( iLen < 8 ) { | ||
104 | _x = tmp / 100; | ||
105 | _x *= 60; | ||
106 | _x += tmp % 100; | ||
107 | _x *= 60; | ||
108 | } else { | ||
109 | _x = tmp / 10000; | ||
110 | _x *= 60; | ||
111 | tmp %= 10000; | ||
112 | _x += tmp / 100; | ||
113 | _x *= 60; | ||
114 | tmp %= 100; | ||
115 | _x += tmp; | ||
116 | } | ||
117 | } | ||
118 | iStart = regCountry.match( strLine, 0, &iLen ); | ||
119 | // help with the shortcoming in 2.x regexp... | ||
120 | iStop = strLine.findRev( '/' ); | ||
121 | if ( iStart >= 0 ) { | ||
122 | iLen = (iStop - iStart) + 1; | ||
123 | strCountry = strLine.mid( iStart, iLen ); | ||
124 | } | ||
125 | // now match the city... | ||
126 | iStart = regCity.match( strLine, iStart + iLen, &iLen ); | ||
127 | if ( iStart >= 0 ) { | ||
128 | strCity = strLine.mid( iStart, iLen ); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | void ZoneField::showStructure( void ) const | ||
133 | { | ||
134 | qDebug( "Country: %s", strCountry.latin1() ); | ||
135 | qDebug( "City: %s", strCity.latin1() ); | ||
136 | qDebug( "x: %d", _x ); | ||
137 | qDebug( "y: %d\n", _y ); | ||
138 | } | ||
139 | |||
140 | ZoneMap::ZoneMap( QWidget *parent, const char* name ) | ||
141 | : QScrollView( parent, name ), | ||
142 | pLast( 0 ), | ||
143 | pRepaint( 0 ), | ||
144 | ox( 0 ), | ||
145 | oy( 0 ), | ||
146 | drawableW( -1 ), | ||
147 | drawableH( -1 ), | ||
148 | bZoom( FALSE ), | ||
149 | bIllum( TRUE ), | ||
150 | cursor( 0 ) | ||
151 | { | ||
152 | viewport()->setFocusPolicy( StrongFocus ); | ||
153 | |||
154 | // set mouse tracking so we can use the mouse move event | ||
155 | zones.setAutoDelete( true ); | ||
156 | // get the map loaded | ||
157 | // just set the current image to point | ||
158 | pixCurr = new QPixmap(); | ||
159 | |||
160 | QPixmap pixZoom = Resource::loadPixmap( "mag" ); | ||
161 | |||
162 | cmdZoom = new QToolButton( this, "Zoom command" ); | ||
163 | cmdZoom->setPixmap( pixZoom ); | ||
164 | cmdZoom->setToggleButton( true ); | ||
165 | |||
166 | cmdZoom->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, | ||
167 | (QSizePolicy::SizeType)0, | ||
168 | cmdZoom->sizePolicy().hasHeightForWidth() ) ); | ||
169 | cmdZoom->setMaximumSize( cmdZoom->sizeHint() ); | ||
170 | // probably don't need this, but just in case... | ||
171 | cmdZoom->move( width() - cmdZoom->width(), height() - cmdZoom->height() ); | ||
172 | |||
173 | |||
174 | lblCity = new QLabel( tr( "CITY" ), this, "City Label" ); | ||
175 | lblCity->setMinimumSize( lblCity->sizeHint() ); | ||
176 | lblCity->setFrameStyle( QFrame::Plain | QFrame::Box ); | ||
177 | lblCity->setBackgroundColor( yellow ); | ||
178 | lblCity->hide(); | ||
179 | |||
180 | // A timer to make sure the label gets hidden | ||
181 | tHide = new QTimer( this, "Label Timer" ); | ||
182 | QObject::connect( tHide, SIGNAL( timeout() ), | ||
183 | lblCity, SLOT( hide() ) ); | ||
184 | QObject::connect( tHide, SIGNAL( timeout() ), | ||
185 | this, SLOT( slotRedraw() ) ); | ||
186 | QTimer *tUpdate = new QTimer( this, "Update Timer" ); | ||
187 | QObject::connect( tUpdate, SIGNAL( timeout() ), | ||
188 | this, SLOT( slotUpdate() ) ); | ||
189 | QObject::connect( qApp, SIGNAL( timeChanged() ), | ||
190 | this, SLOT( slotUpdate() ) ); | ||
191 | QObject::connect( cmdZoom, SIGNAL( toggled( bool ) ), | ||
192 | this, SLOT( slotZoom( bool ) ) ); | ||
193 | QObject::connect( &norm, SIGNAL( signalNewPoint( const QPoint& ) ), | ||
194 | this, SLOT( slotFindCity( const QPoint& ) ) ); | ||
195 | QObject::connect( qApp, SIGNAL( clockChanged( bool ) ), | ||
196 | this, SLOT( changeClock( bool ) ) ); | ||
197 | // update the sun's movement every 5 minutes | ||
198 | tUpdate->start( 5 * 60 * 1000 ); | ||
199 | // May as well read in the timezone information too... | ||
200 | readZones(); | ||
201 | } | ||
202 | |||
203 | ZoneMap::~ZoneMap() | ||
204 | { | ||
205 | } | ||
206 | |||
207 | void ZoneMap::readZones( void ) | ||
208 | { | ||
209 | QFile fZone( strZONEINFO ); | ||
210 | if ( !fZone.open( IO_ReadOnly ) ) { | ||
211 | QMessageBox::warning (this, | ||
212 | tr( "Unable to Find Timezone Info" ), | ||
213 | tr( "<p>Unable to find any timezone information in %1" ) | ||
214 | .arg( strZONEINFO )); | ||
215 | exit(-1); | ||
216 | } else { | ||
217 | QTextStream tZone( &fZone ); | ||
218 | while ( !tZone.atEnd() ) { | ||
219 | QString strLine = tZone.readLine(); | ||
220 | // only pass on lines that aren't comments | ||
221 | if ( strLine[0] != '#' ) { | ||
222 | zones.append( new ZoneField( strLine ) ); | ||
223 | } | ||
224 | } | ||
225 | fZone.close(); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | void ZoneMap::viewportMousePressEvent( QMouseEvent* event ) | ||
230 | { | ||
231 | // add the mouse event into the normalizer, and get the average, | ||
232 | // pass it along | ||
233 | slotRedraw(); | ||
234 | norm.start(); | ||
235 | norm.addEvent( event->pos() ); | ||
236 | } | ||
237 | |||
238 | void ZoneMap::viewportMouseMoveEvent( QMouseEvent* event ) | ||
239 | { | ||
240 | norm.addEvent( event->pos() ); | ||
241 | } | ||
242 | |||
243 | void ZoneMap::viewportMouseReleaseEvent( QMouseEvent* ) | ||
244 | { | ||
245 | // get the averaged points in case a timeout hasn't occurred, | ||
246 | // more for "mouse clicks" | ||
247 | norm.stop(); | ||
248 | if ( pLast != NULL ) { | ||
249 | emit signalTz( pLast->country(), pLast->city() ); | ||
250 | pLast = NULL; | ||
251 | } | ||
252 | tHide->start( 2000, true ); | ||
253 | } | ||
254 | |||
255 | void ZoneMap::keyPressEvent( QKeyEvent *ke ) | ||
256 | { | ||
257 | switch ( ke->key() ) { | ||
258 | case Key_Left: | ||
259 | case Key_Right: | ||
260 | case Key_Up: | ||
261 | case Key_Down: { | ||
262 | tHide->stop(); | ||
263 | if ( !cursor ) | ||
264 | slotFindCity( QPoint( contentsWidth(), contentsHeight() ) / 2 ); | ||
265 | ZoneField *city = findCityNear( cursor, ke->key() ); | ||
266 | if ( city ) { | ||
267 | cursor = city; | ||
268 | int tmpx, tmpy; | ||
269 | zoneToWin( cursor->x(), cursor->y(), tmpx, tmpy ); | ||
270 | ensureVisible( tmpx, tmpy ); | ||
271 | showCity( cursor ); | ||
272 | tHide->start( 3000, true ); | ||
273 | } | ||
274 | } | ||
275 | break; | ||
276 | |||
277 | case Key_Space: | ||
278 | case Key_Enter: | ||
279 | case Key_Return: | ||
280 | if ( cursor ) { | ||
281 | emit signalTz( cursor->country(), cursor->city() ); | ||
282 | tHide->start( 0, true ); | ||
283 | } | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | ZoneField *ZoneMap::findCityNear( ZoneField *city, int key ) | ||
289 | { | ||
290 | ZoneField *pZone; | ||
291 | ZoneField *pClosest = 0; | ||
292 | long ddist = LONG_MAX; | ||
293 | |||
294 | QListIterator<ZoneField> it( zones ); | ||
295 | for (; it.current(); ++it) { | ||
296 | pZone = it.current(); | ||
297 | long dx = (pZone->x() - city->x())/100; | ||
298 | long dy = (pZone->y() - city->y())/100; | ||
299 | switch ( key ) { | ||
300 | case Key_Right: | ||
301 | case Key_Left: | ||
302 | if ( key == Key_Left ) | ||
303 | dx = -dx; | ||
304 | if ( dx > 0 ) { | ||
305 | long dist = QABS(dy)*4 + dx; | ||
306 | if ( dist < ddist ) { | ||
307 | ddist = dist; | ||
308 | pClosest = pZone; | ||
309 | } | ||
310 | } | ||
311 | break; | ||
312 | case Key_Down: | ||
313 | case Key_Up: | ||
314 | if ( key == Key_Down ) | ||
315 | dy = -dy; | ||
316 | if ( dy > 0 ) { | ||
317 | long dist = QABS(dx)*4 + dy; | ||
318 | if ( dist < ddist ) { | ||
319 | ddist = dist; | ||
320 | pClosest = pZone; | ||
321 | } | ||
322 | } | ||
323 | break; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return pClosest; | ||
328 | } | ||
329 | |||
330 | void ZoneMap::slotFindCity( const QPoint &pos ) | ||
331 | { | ||
332 | lblCity->hide(); | ||
333 | // given coordinates on the screen find the closest city and display the | ||
334 | // label close to it | ||
335 | int tmpx, tmpy, x, y; | ||
336 | long lDistance, | ||
337 | lClosest; | ||
338 | ZoneField *pZone, | ||
339 | *pClosest; | ||
340 | |||
341 | if ( tHide->isActive() ) { | ||
342 | tHide->stop(); | ||
343 | } | ||
344 | viewportToContents(pos.x(), pos.y(), tmpx, tmpy); | ||
345 | winToZone( tmpx, tmpy, x, y ); | ||
346 | // Find city alogorithim: start out at an (near) infinite distance away and | ||
347 | // then find the closest city, (similar to the Z-buffer technique, I guess) | ||
348 | // the only problem is that this is all done with doubles, but I don't know | ||
349 | // another way to do it at the moment. Another problem is a linked list is | ||
350 | // used obviously something indexed would help | ||
351 | QListIterator<ZoneField> it( zones ); | ||
352 | pClosest = 0; | ||
353 | lClosest = LONG_MAX; | ||
354 | for (; it.current(); ++it) { | ||
355 | pZone = it.current(); | ||
356 | // use the manhattenLength, a good enough of an appoximation here | ||
357 | lDistance = QABS( x - pZone->x() ) + QABS( y - pZone->y() ); | ||
358 | // first to zero wins! | ||
359 | if ( lDistance < lClosest ) { | ||
360 | lClosest = lDistance; | ||
361 | pClosest = pZone; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | // Okay, we found the closest city, but it might still be too far away. | ||
366 | if ( lClosest <= iTHRESHOLD ) { | ||
367 | showCity( pClosest ); | ||
368 | cursor = pClosest; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | void ZoneMap::showCity( ZoneField *city ) | ||
373 | { | ||
374 | pLast = city; | ||
375 | // we'll use city and country a couple of times, get them to save some | ||
376 | // time | ||
377 | QString strCity = pLast->city(); | ||
378 | QString strCountry = pLast->country(); | ||
379 | // Display the time at this location by setting the environment timezone | ||
380 | // getting the current time [there] and then swapping back the variable | ||
381 | // so no one notices... | ||
382 | QString strSave; | ||
383 | char *p = getenv( "TZ" ); | ||
384 | if ( p ) { | ||
385 | strSave = p; | ||
386 | } | ||
387 | // set the timezone :) | ||
388 | setenv( "TZ", strCountry + strCity, true ); | ||
389 | lblCity->setText( strCity.replace( QRegExp("_"), " ") + "\n" + | ||
390 | TimeString::shortTime( ampm ) ); | ||
391 | lblCity->setMinimumSize( lblCity->sizeHint() ); | ||
392 | // undue our damage... | ||
393 | unsetenv( "TZ" ); | ||
394 | if ( p ) | ||
395 | setenv( "TZ", strSave, true ); | ||
396 | // Now decide where to move the label, x & y can be reused | ||
397 | int tmpx, tmpy, x, y; | ||
398 | zoneToWin( pLast->x(), pLast->y(), tmpx, tmpy ); | ||
399 | contentsToViewport(tmpx, tmpy, x, y); | ||
400 | if ( lblCity->width() > drawableW - x ) { | ||
401 | // oops... try putting it on the right | ||
402 | x = x - lblCity->width() - iLABELOFFSET; | ||
403 | } else { | ||
404 | // the default... | ||
405 | x += iLABELOFFSET; | ||
406 | } | ||
407 | if ( lblCity->height() > drawableH - y ) { | ||
408 | // move it up... | ||
409 | y = y - lblCity->height() - iLABELOFFSET; | ||
410 | } else if ( y < 0 ) { | ||
411 | // the city is actually off the screen... | ||
412 | // this only happens on the a zoom when you are near the top, | ||
413 | // a quick workaround.. | ||
414 | y = iLABELOFFSET; | ||
415 | } else { | ||
416 | // the default | ||
417 | y += iLABELOFFSET; | ||
418 | } | ||
419 | |||
420 | // draw in the city and the label | ||
421 | if ( pRepaint ) { | ||
422 | int repx, | ||
423 | repy; | ||
424 | zoneToWin( pRepaint->x(), pRepaint->y(), repx, repy ); | ||
425 | updateContents( repx - iCITYOFFSET, repy - iCITYOFFSET, | ||
426 | iCITYSIZE, iCITYSIZE ); | ||
427 | } | ||
428 | updateContents( tmpx - iCITYOFFSET, tmpy - iCITYOFFSET, iCITYSIZE, | ||
429 | iCITYSIZE ); | ||
430 | pRepaint = pLast; | ||
431 | |||
432 | lblCity->move( x, y ); | ||
433 | lblCity->show(); | ||
434 | } | ||
435 | |||
436 | void ZoneMap::resizeEvent( QResizeEvent *e ) | ||
437 | { | ||
438 | // keep the zoom button down in the corner | ||
439 | QSize _size = e->size(); | ||
440 | cmdZoom->move( _size.width() - cmdZoom->width(), | ||
441 | _size.height() - cmdZoom->height() ); | ||
442 | if ( !bZoom ) { | ||
443 | drawableW = width() - 2 * frameWidth(); | ||
444 | drawableH = height() - 2 * frameWidth(); | ||
445 | makeMap( drawableW, drawableH ); | ||
446 | resizeContents( drawableW, drawableH ); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | void ZoneMap::showZones( void ) const | ||
451 | { | ||
452 | // go through the zones in the list and just display the values... | ||
453 | QListIterator<ZoneField> itZone( zones ); | ||
454 | for ( itZone.toFirst(); itZone.current(); ++itZone ) { | ||
455 | ZoneField *pZone = itZone.current(); | ||
456 | pZone->showStructure(); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | void ZoneMap::drawCities( QPainter *p ) | ||
461 | { | ||
462 | int x, | ||
463 | y, | ||
464 | j; | ||
465 | // draw in the cities | ||
466 | // for testing only as when you put it | ||
467 | // on the small screen it looks awful and not to mention useless | ||
468 | p->setPen( red ); | ||
469 | QListIterator<ZoneField> itZone( zones ); | ||
470 | for ( itZone.toFirst(), j = 0; itZone.current(); ++itZone, j++ ) { | ||
471 | ZoneField *pZone = itZone.current(); | ||
472 | zoneToWin( pZone->x(), pZone->y(), x, y ); | ||
473 | if ( x > wImg ) | ||
474 | x = x - wImg; | ||
475 | p->drawRect( x - iCITYOFFSET, y - iCITYOFFSET, iCITYSIZE, iCITYSIZE); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | static void dayNight(QImage *pImage) | ||
480 | { | ||
481 | // create a mask the functions from sun.h | ||
482 | double dJulian, | ||
483 | dSunRad, | ||
484 | dSunDecl, | ||
485 | dSunRadius, | ||
486 | dSunLong; | ||
487 | int wImage = pImage->width(), | ||
488 | hImage = pImage->height(), | ||
489 | iStart, | ||
490 | iStop, | ||
491 | iMid, | ||
492 | relw, | ||
493 | i; | ||
494 | short wtab[ wImage ]; | ||
495 | time_t tCurrent; | ||
496 | struct tm *pTm; | ||
497 | |||
498 | // get the position of the sun bassed on our current time... | ||
499 | tCurrent = time( NULL ); | ||
500 | pTm = gmtime( &tCurrent ); | ||
501 | dJulian = jtime( pTm ); | ||
502 | sunpos( dJulian, 0, &dSunRad, &dSunDecl, &dSunRadius, &dSunLong ); | ||
503 | |||
504 | // now get the projected illumination | ||
505 | projillum( wtab, wImage, hImage, dSunDecl ); | ||
506 | relw = wImage - int( wImage * 0.0275 ); | ||
507 | |||
508 | // draw the map, keeping in mind that we may go too far off the map... | ||
509 | iMid = ( relw * ( 24*60 - pTm->tm_hour * 60 - pTm->tm_min ) ) / ( 24*60 ); | ||
510 | |||
511 | for ( i = 0; i < hImage; i++ ) { | ||
512 | if ( wtab[i] > 0 ) { | ||
513 | iStart = iMid - wtab[i]; | ||
514 | iStop = iMid + wtab[i]; | ||
515 | if ( iStart < 0 ) { | ||
516 | darken( pImage, iStop, wImage + iStart, i ); | ||
517 | } else if ( iStop > wImage ) { | ||
518 | darken( pImage, iStop - wImage, iStart, i ); | ||
519 | } else { | ||
520 | darken( pImage, 0, iStart, i ); | ||
521 | darken( pImage, iStop, wImage, i ); | ||
522 | } | ||
523 | } else { | ||
524 | darken( pImage, 0, wImage, i ); | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | |||
529 | static inline void darken( QImage *pImage, int start, int stop, int row ) | ||
530 | { | ||
531 | int colors, | ||
532 | j; | ||
533 | uchar *p; | ||
534 | |||
535 | // assume that the image is similar to the one we have... | ||
536 | colors = pImage->numColors() / 2; | ||
537 | |||
538 | p = pImage->scanLine( row ); | ||
539 | for ( j = start; j <= stop; j++ ) { | ||
540 | if ( p[j] < colors ) | ||
541 | p[j] += colors; | ||
542 | } | ||
543 | } | ||
544 | |||
545 | void ZoneMap::makeMap( int w, int h ) | ||
546 | { | ||
547 | QImage imgOrig = Resource::loadImage( strMAP ); | ||
548 | if ( imgOrig.isNull() ) { | ||
549 | QMessageBox::warning( this, | ||
550 | tr( "Couldn't Find Map" ), | ||
551 | tr( "<p>Couldn't load map: %1, exiting") | ||
552 | .arg( strMAP ) ); | ||
553 | exit(-1); | ||
554 | } | ||
555 | |||
556 | // set up the color table for darkening... | ||
557 | imgOrig = imgOrig.convertDepth( 8 ); | ||
558 | int numColors = imgOrig.numColors(); | ||
559 | // double the colors | ||
560 | imgOrig.setNumColors( 2 * numColors ); | ||
561 | // darken the new ones... | ||
562 | for ( int i = 0; i < numColors; i++ ) { | ||
563 | QRgb rgb = imgOrig.color( i ); | ||
564 | imgOrig.setColor ( i + numColors, qRgb( 2 * qRed( rgb ) / 3, | ||
565 | 2 * qGreen( rgb ) / 3, 2 * qBlue( rgb ) / 3 ) ); | ||
566 | } | ||
567 | |||
568 | // else go one with making the map... | ||
569 | if ( bIllum ) { | ||
570 | // do a daylight mask | ||
571 | dayNight(&imgOrig); | ||
572 | } | ||
573 | // redo the width and height | ||
574 | wImg = w; | ||
575 | hImg = h; | ||
576 | ox = ( wImg / 2 ) - int( wImg * 0.0275 ); | ||
577 | oy = hImg / 2; | ||
578 | pixCurr->convertFromImage( imgOrig.smoothScale(w, h), | ||
579 | QPixmap::ThresholdDither ); | ||
580 | } | ||
581 | |||
582 | void ZoneMap::drawCity( QPainter *p, const ZoneField *pCity ) | ||
583 | { | ||
584 | int x, | ||
585 | y; | ||
586 | |||
587 | p->setPen( red ); | ||
588 | zoneToWin( pCity->x(), pCity->y(), x, y ); | ||
589 | p->drawRect( x - iCITYOFFSET, y - iCITYOFFSET, iCITYSIZE, iCITYSIZE ); | ||
590 | } | ||
591 | |||
592 | void ZoneMap::drawContents( QPainter *p, int cx, int cy, int cw, int ch ) | ||
593 | { | ||
594 | // if there is a need to resize, then do it... | ||
595 | // get our drawable area | ||
596 | drawableW = width() - 2 * frameWidth(); | ||
597 | drawableH = height() - 2 * frameWidth(); | ||
598 | |||
599 | int pixmapW = pixCurr->width(), | ||
600 | pixmapH = pixCurr->height(); | ||
601 | if ( !bZoom && ( ( pixmapW != drawableW ) || | ||
602 | ( pixmapH != drawableH) ) ) { | ||
603 | makeMap( drawableW, drawableH ); | ||
604 | } | ||
605 | |||
606 | // taken from the scrollview example... | ||
607 | int rowheight = pixCurr->height(); | ||
608 | int toprow = cy / rowheight; | ||
609 | int bottomrow = ( cy + ch + rowheight - 1 ) / rowheight; | ||
610 | int colwidth = pixCurr->width(); | ||
611 | int leftcol= cx / colwidth; | ||
612 | int rightcol= ( cx + cw + colwidth - 1 ) / colwidth; | ||
613 | for ( int r = toprow; r <= bottomrow; r++ ) { | ||
614 | int py = r * rowheight; | ||
615 | for ( int c = leftcol; c <= rightcol; c++ ) { | ||
616 | int px = c * colwidth; | ||
617 | p->drawPixmap( px, py, *pixCurr ); | ||
618 | } | ||
619 | } | ||
620 | |||
621 | // Draw that city! | ||
622 | if ( pLast ) | ||
623 | drawCity( p, pLast ); | ||
624 | } | ||
625 | |||
626 | void ZoneMap::slotZoom( bool setZoom ) | ||
627 | { | ||
628 | bZoom = setZoom; | ||
629 | if ( bZoom ) { | ||
630 | makeMap( 2 * wImg , 2 * hImg ); | ||
631 | resizeContents( wImg, hImg ); | ||
632 | } else { | ||
633 | makeMap( drawableW, drawableH ); | ||
634 | resizeContents( drawableW, drawableH ); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | void ZoneMap::slotIllum( bool setIllum ) | ||
639 | { | ||
640 | bIllum = !setIllum; | ||
641 | // make the map... | ||
642 | makeMap( pixCurr->width(), pixCurr->height() ); | ||
643 | updateContents( 0, 0, wImg, hImg ); | ||
644 | } | ||
645 | |||
646 | void ZoneMap::slotUpdate( void ) | ||
647 | { | ||
648 | // recalculate the light, most people will never see this, | ||
649 | // but it is good to be complete | ||
650 | makeMap ( pixCurr->width(), pixCurr->height() ); | ||
651 | updateContents( contentsX(), contentsY(), drawableW, drawableH ); | ||
652 | } | ||
653 | |||
654 | void ZoneMap::slotRedraw( void ) | ||
655 | { | ||
656 | // paint over that pesky city... | ||
657 | int x, | ||
658 | y; | ||
659 | if ( pRepaint ) { | ||
660 | pLast = 0; | ||
661 | zoneToWin(pRepaint->x(), pRepaint->y(), x, y); | ||
662 | updateContents( x - iCITYOFFSET, y - iCITYOFFSET, iCITYSIZE, iCITYSIZE); | ||
663 | pRepaint = 0; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | void ZoneMap::changeClock( bool whichClock ) | ||
668 | { | ||
669 | ampm = whichClock; | ||
670 | } | ||