source: calamares/trunk/fuentes/src/modules/locale/timezonewidget/timezonewidget.cpp @ 7538

Last change on this file since 7538 was 7538, checked in by kbut, 13 months ago

sync with github

File size: 8.8 KB
Line 
1/* === This file is part of Calamares - <https://github.com/calamares> ===
2 *
3 *   Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
4 *   Copyright 2017, Adriaan de Groot <groot@kde.org>
5 *
6 *   Originally from the Manjaro Installation Framework
7 *   by Roland Singer <roland@manjaro.org>
8 *   Copyright (C) 2007 Free Software Foundation, Inc.
9 *
10 *   Calamares is free software: you can redistribute it and/or modify
11 *   it under the terms of the GNU General Public License as published by
12 *   the Free Software Foundation, either version 3 of the License, or
13 *   (at your option) any later version.
14 *
15 *   Calamares is distributed in the hope that it will be useful,
16 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 *   GNU General Public License for more details.
19 *
20 *   You should have received a copy of the GNU General Public License
21 *   along with Calamares. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include <cmath>
25
26#include "utils/Logger.h"
27
28#include "timezonewidget.h"
29
30
31static constexpr double MAP_Y_OFFSET = 0.125;
32static constexpr double MAP_X_OFFSET = -0.0370;
33constexpr static double MATH_PI = 3.14159265;
34
35#ifdef DEBUG_TIMEZONES
36// Adds a label to the timezone with this name
37constexpr static QLatin1Literal ZONE_NAME( "zone" );
38#endif
39
40TimeZoneWidget::TimeZoneWidget( QWidget* parent ) :
41    QWidget( parent )
42{
43    setMouseTracking( false );
44    setCursor( Qt::PointingHandCursor );
45
46    // Font
47    font.setPointSize( 12 );
48    font.setBold( false );
49
50    // Images
51    background = QImage( ":/images/bg.png" ).scaled( X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
52    pin = QImage( ":/images/pin.png" );
53
54    // Set size
55    setMinimumSize( background.size() );
56    setMaximumSize( background.size() );
57
58    // Zone images
59    QStringList zones = QString( ZONES ).split( " ", QString::SkipEmptyParts );
60    for ( int i = 0; i < zones.size(); ++i )
61    {
62        timeZoneImages.append( QImage( ":/images/timezone_" + zones.at( i ) + ".png" ).scaled( X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
63#ifdef DEBUG_TIMEZONES
64        timeZoneImages.last().setText( ZONE_NAME, zones.at( i ) );
65#endif
66    }
67}
68
69
70void TimeZoneWidget::setCurrentLocation( QString region, QString zone )
71{
72    QHash<QString, QList<LocaleGlobal::Location> > hash = LocaleGlobal::getLocations();
73
74    if ( !hash.contains( region ) )
75        return;
76
77    QList<LocaleGlobal::Location> locations = hash.value( region );
78    for ( int i = 0; i < locations.size(); ++i )
79    {
80        if ( locations.at( i ).zone == zone )
81        {
82            setCurrentLocation( locations.at( i ) );
83            break;
84        }
85    }
86}
87
88
89void TimeZoneWidget::setCurrentLocation( LocaleGlobal::Location location )
90{
91    currentLocation = location;
92
93    // Set zone
94    QPoint pos = getLocationPosition( currentLocation.longitude, currentLocation.latitude );
95
96#ifdef DEBUG_TIMEZONES
97    cDebug() << "Setting location" << location.region << location.zone << location.country;
98    cDebug() << " .. long" << location.longitude << "lat" << location.latitude;
99    cDebug() << " .. x" << pos.x() << "y" << pos.y();
100
101    bool found = false;
102#endif
103
104
105    for ( int i = 0; i < timeZoneImages.size(); ++i )
106    {
107        QImage zone = timeZoneImages[i];
108
109        // If not transparent set as current
110        if ( zone.pixel( pos ) != RGB_TRANSPARENT )
111        {
112#ifdef DEBUG_TIMEZONES
113            // Log *all* the zones that contain this point,
114            // but only pick the first.
115            if ( !found )
116            {
117                currentZoneImage = zone;
118                found = true;
119                cDebug() << " .. First zone found" << i << zone.text( ZONE_NAME );
120            }
121            else
122                cDebug() << " .. Also in zone" << i << zone.text( ZONE_NAME );
123#else
124            currentZoneImage = zone;
125            break;
126#endif
127        }
128    }
129
130    // Repaint widget
131    repaint();
132}
133
134
135
136//###
137//### Private
138//###
139
140
141QPoint TimeZoneWidget::getLocationPosition( double longitude, double latitude )
142{
143    const int width = this->width();
144    const int height = this->height();
145
146    double x = ( width / 2.0 + ( width / 2.0 ) * longitude / 180.0 ) + MAP_X_OFFSET * width;
147    double y = ( height / 2.0 - ( height / 2.0 ) * latitude / 90.0 ) + MAP_Y_OFFSET * height;
148
149    // Far north, the MAP_Y_OFFSET no longer holds, cancel the Y offset; it's noticeable
150    // from 62 degrees north, so scale those 28 degrees as if the world is flat south
151    // of there, and we have a funny "rounded" top of the world. In practice the locations
152    // of the different cities / regions looks ok -- at least Thule ends up in the right
153    // country, and Inuvik isn't in the ocean.
154    if ( latitude > 70.0 )
155        y -= sin( MATH_PI * ( latitude - 70.0 ) / 56.0 ) * MAP_Y_OFFSET * height * 0.8;
156    if ( latitude > 74.0 )
157        y += 4;
158    if ( latitude > 69.0 )
159        y -= 2;
160    if ( latitude > 59.0 )
161        y -= 4 * int( ( latitude - 54.0 ) / 5.0 );
162    if ( latitude > 54.0 )
163        y -= 2;
164    if ( latitude > 49.0 )
165        y -= int ( (latitude - 44.0) / 5.0 );
166    // Far south, some stretching occurs as well, but it is less pronounced.
167    // Move down by 1 pixel per 5 degrees past 10 south
168    if ( latitude < 0 )
169        y += int( (-latitude) / 5.0 );
170    // Antarctica isn't shown on the map, but you could try clicking there
171    if ( latitude < -60 )
172        y = height - 1;
173
174    if ( x < 0 )
175        x = width+x;
176    if ( x >= width )
177        x -= width;
178    if ( y < 0 )
179        y = height+y;
180    if ( y >= height )
181        y -= height;
182
183    return QPoint( int(x), int(y) );
184}
185
186
187void TimeZoneWidget::paintEvent( QPaintEvent* )
188{
189    const int width = this->width();
190    const int height = this->height();
191    QFontMetrics fontMetrics( font );
192    QPainter painter( this );
193
194    painter.setRenderHint( QPainter::Antialiasing );
195    painter.setFont( font );
196
197    // Draw background
198    painter.drawImage( 0, 0, background );
199
200    // Draw zone image
201    painter.drawImage( 0, 0, currentZoneImage );
202
203#ifdef DEBUG_TIMEZONES
204    QPoint point = getLocationPosition( currentLocation.longitude, currentLocation.latitude );
205    // Draw latitude lines
206    for ( int y_lat = -50; y_lat < 80 ; y_lat+=5 )
207    {
208        QPen p( y_lat ? Qt::black : Qt::red );
209        p.setWidth( 0 );
210        painter.setPen( p );
211        QPoint latLine0( getLocationPosition( 0, y_lat ) );
212        int llx = latLine0.x() + ((y_lat & 1) ? -10 : 0);
213        int lly = latLine0.y();
214
215        for ( int c = 0 ; c < width ; ++c )
216            painter.drawPoint( c, lly );
217    }
218    // Just a dot in the selected location, no label
219    painter.setPen( Qt::red );
220    painter.drawPoint( point );
221#else
222    // Draw pin at current location
223    QPoint point = getLocationPosition( currentLocation.longitude, currentLocation.latitude );
224
225    painter.drawImage( point.x() - pin.width()/2, point.y() - pin.height()/2, pin );
226
227    // Draw text and box
228    const int textWidth = fontMetrics.width( LocaleGlobal::Location::pretty( currentLocation.zone ) );
229    const int textHeight = fontMetrics.height();
230
231    QRect rect = QRect( point.x() - textWidth/2 - 5, point.y() - textHeight - 8, textWidth + 10, textHeight - 2 );
232
233    if ( rect.x() <= 5 )
234        rect.moveLeft( 5 );
235    if ( rect.right() >= width-5 )
236        rect.moveRight( width - 5 );
237    if ( rect.y() <= 5 )
238        rect.moveTop( 5 );
239    if ( rect.y() >= height-5 )
240        rect.moveBottom( height-5 );
241
242    painter.setPen( QPen() ); // no pen
243    painter.setBrush( QColor( 40, 40, 40 ) );
244    painter.drawRoundedRect( rect, 3, 3 );
245    painter.setPen( Qt::white );
246    painter.drawText( rect.x() + 5, rect.bottom() - 4, LocaleGlobal::Location::pretty( currentLocation.zone ) );
247#endif
248
249    painter.end();
250}
251
252
253
254void TimeZoneWidget::mousePressEvent( QMouseEvent* event )
255{
256    if ( event->button() != Qt::LeftButton )
257        return;
258
259    // Set nearest location
260    int nX = 999999, mX = event->pos().x();
261    int nY = 999999, mY = event->pos().y();
262    QHash<QString, QList<LocaleGlobal::Location> > hash = LocaleGlobal::getLocations();
263    QHash<QString, QList<LocaleGlobal::Location> >::iterator iter = hash.begin();
264
265    while ( iter != hash.end() )
266    {
267        QList<LocaleGlobal::Location> locations = iter.value();
268
269        for ( int i = 0; i < locations.size(); ++i )
270        {
271            LocaleGlobal::Location loc = locations[i];
272            QPoint locPos = getLocationPosition( loc.longitude, loc.latitude );
273
274            if ( ( abs( mX - locPos.x() ) + abs( mY - locPos.y() )  <  abs( mX - nX ) + abs( mY - nY ) ) )
275            {
276                currentLocation = loc;
277                nX = locPos.x();
278                nY = locPos.y();
279            }
280        }
281
282        ++iter;
283    }
284
285    // Set zone image and repaint widget
286    setCurrentLocation( currentLocation );
287
288    // Emit signal
289    emit locationChanged( currentLocation );
290}
Note: See TracBrowser for help on using the repository browser.