1 /**********************************************************************************************
2     Copyright (C) 2018 Oliver Eichler <oliver.eichler@gmx.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 3 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, see <http://www.gnu.org/licenses/>.
16 
17 **********************************************************************************************/
18 
19 #include "helpers/CDraw.h"
20 #include "helpers/CSettings.h"
21 #include "helpers/CWptIconManager.h"
22 #include "misc.h"
23 #include "setup/IAppSetup.h"
24 
25 #include <QtWidgets>
26 
27 CWptIconManager* CWptIconManager::pSelf = nullptr;
28 const char* CWptIconManager::wptDefault = "://icons/waypoints/32x32/Default.png";
29 
CWptIconManager(QObject * parent)30 CWptIconManager::CWptIconManager(QObject* parent)
31 {
32     pSelf = this;
33 
34     init();
35 }
36 
~CWptIconManager()37 CWptIconManager::~CWptIconManager()
38 {
39     qDebug() << "CWptIconManager::~CWptIconManager()";
40     removeNumberedBullets();
41 }
42 
removeNumberedBullets()43 void CWptIconManager::removeNumberedBullets()
44 {
45     for(const QString& filename : qAsConst(mapNumberedBullets))
46     {
47         QFile::remove(filename);
48     }
49     mapNumberedBullets.clear();
50 }
51 
createGrayscale(QString path)52 QPixmap CWptIconManager::createGrayscale(QString path)
53 {
54     QPixmap pixmap(path);
55     QBitmap alpha = pixmap.createHeuristicMask();
56     QImage image = pixmap.toImage().convertToFormat(QImage::Format_Grayscale8);
57     QPixmap pixmap_gray = QPixmap::fromImage(image.convertToFormat(QImage::Format_ARGB32));
58     pixmap_gray.setMask(alpha);
59     return pixmap_gray;
60 }
61 
init()62 void CWptIconManager::init()
63 {
64     wptIcons.clear();
65 
66     wptIcons["Default"] = icon_t(wptDefault, 16, 16);
67     wptIcons["City (Capitol)"] = icon_t("://icons/waypoints/32x32/CityCapitol.png", 16, 16);
68     wptIcons["City (Large)"] = icon_t("://icons/waypoints/32x32/CityLarge.png", 16, 16);
69     wptIcons["City (Medium)"] = icon_t("://icons/waypoints/32x32/CityMedium.png", 16, 16);
70     wptIcons["City (Small)"] = icon_t("://icons/waypoints/32x32/CitySmall.png", 16, 16);
71     wptIcons["Residence"] = icon_t("://icons/waypoints/32x32/Residence.png", 16, 16);
72     wptIcons["Flag, Red"] = icon_t("://icons/waypoints/32x32/FlagRed.png", 0, 32);
73     wptIcons["Flag, Blue"] = icon_t("://icons/waypoints/32x32/FlagBlue.png", 0, 32);
74     wptIcons["Flag, Green"] = icon_t("://icons/waypoints/32x32/FlagGreen.png", 0, 32);
75     wptIcons["Pin, Red"] = icon_t("://icons/waypoints/32x32/PinRed.png", 0, 32);
76     wptIcons["Pin, Blue"] = icon_t("://icons/waypoints/32x32/PinBlue.png", 0, 32);
77     wptIcons["Pin, Green"] = icon_t("://icons/waypoints/32x32/PinGreen.png", 0, 32);
78     wptIcons["Block, Red"] = icon_t("://icons/waypoints/32x32/BoxRed.png", 16, 16);
79     wptIcons["Block, Blue"] = icon_t("://icons/waypoints/32x32/BoxBlue.png", 16, 16);
80     wptIcons["Block, Green"] = icon_t("://icons/waypoints/32x32/BoxGreen.png", 16, 16);
81     wptIcons["Blue Diamond"] = icon_t("://icons/waypoints/32x32/DiamondBlue.png", 16, 16);
82     wptIcons["Green Diamond"] = icon_t("://icons/waypoints/32x32/DiamondGreen.png", 16, 16);
83     wptIcons["Red Diamond"] = icon_t("://icons/waypoints/32x32/DiamondRed.png", 16, 16);
84     wptIcons["Parking Area"] = icon_t("://icons/cache/32x32/parking.png", 16, 16);
85     wptIcons["Trailhead"] = icon_t("://icons/cache/32x32/trailhead.png", 16, 16);
86     wptIcons["Waypoint"] = icon_t("://icons/waypoints/32x32/Waypoint.png", 16, 16);
87     wptIcons["1st Category"] = icon_t("://icons/waypoints/32x32/1stCategory.png", 16, 16);
88     wptIcons["2nd Category"] = icon_t("://icons/waypoints/32x32/2ndCategory.png", 16, 16);
89     wptIcons["3rd Category"] = icon_t("://icons/waypoints/32x32/3rdCategory.png", 16, 16);
90     wptIcons["4th Category"] = icon_t("://icons/waypoints/32x32/4thCategory.png", 16, 16);
91     wptIcons["Danger"] = icon_t("://icons/waypoints/32x32/Danger.png", 16, 16);
92     wptIcons["First Aid"] = icon_t("://icons/waypoints/32x32/FirstAid.png", 16, 16);
93     wptIcons["Food"] = icon_t("://icons/waypoints/32x32/Food.png", 16, 16);
94     wptIcons["Generic"] = icon_t("://icons/waypoints/32x32/Generic.png", 16, 16);
95     wptIcons["Hors Category"] = icon_t("://icons/waypoints/32x32/HorsCategory.png", 16, 16);
96     wptIcons["Left"] = icon_t("://icons/waypoints/32x32/Left.png", 16, 16);
97     wptIcons["Right"] = icon_t("://icons/waypoints/32x32/Right.png", 16, 16);
98     wptIcons["Sprint"] = icon_t("://icons/waypoints/32x32/Sprint.png", 16, 16);
99     wptIcons["Straight"] = icon_t("://icons/waypoints/32x32/Straight.png", 16, 16);
100     wptIcons["Summit"] = icon_t("://icons/waypoints/32x32/Summit.png", 16, 16);
101     wptIcons["Valley"] = icon_t("://icons/waypoints/32x32/Valley.png", 16, 16);
102     wptIcons["Water"] = icon_t("://icons/waypoints/32x32/Water.png", 16, 16);
103     wptIcons["LeftFork"] = icon_t("://icons/waypoints/32x32/LeftFork.png", 16, 16);
104     wptIcons["RightFork"] = icon_t("://icons/waypoints/32x32/RightFork.png", 16, 16);
105     wptIcons["MiddleFork"] = icon_t("://icons/waypoints/32x32/MiddleFork.png", 16, 16);
106     wptIcons["SlightLeft"] = icon_t("://icons/waypoints/32x32/SlightLeft.png", 16, 16);
107     wptIcons["SharpLeft"] = icon_t("://icons/waypoints/32x32/SharpLeft.png", 16, 16);
108     wptIcons["SlightRight"] = icon_t("://icons/waypoints/32x32/SlightRight.png", 16, 16);
109     wptIcons["SharpRight"] = icon_t("://icons/waypoints/32x32/SharpRight.png", 16, 16);
110     wptIcons["UTurn"] = icon_t("://icons/waypoints/32x32/UTurn.png", 16, 16);
111     wptIcons["Start"] = icon_t("://icons/waypoints/32x32/Start.png", 16, 16);
112     wptIcons["End"] = icon_t("://icons/waypoints/32x32/End.png", 16, 16);
113 
114     wptIcons["Bank"] = icon_t("://icons/poi/SJJB/png/money_bank.n.32.png", 16, 16);
115     wptIcons["Gas Station"] = icon_t("://icons/poi/SJJB/png/transport_fuel.n.32.png", 16, 16);
116     wptIcons["Restaurant"] = icon_t("://icons/poi/SJJB/png/food_restaurant.n.32.png", 16, 16);
117     wptIcons["Bar"] = icon_t("://icons/poi/SJJB/png/food_bar.n.32.png", 16, 16);
118     wptIcons["Shipwreck"] = icon_t("://icons/poi/SJJB/png/tourist_wreck.n.32.png", 16, 16);
119     wptIcons["Boat Ramp"] = icon_t("://icons/poi/SJJB/png/transport_slipway.n.32.png", 16, 16);
120     wptIcons["Campground"] = icon_t("://icons/poi/SJJB/png/accommodation_camping.n.32.png", 16, 16);
121     wptIcons["Restroom"] = icon_t("://icons/poi/SJJB/png/amenity_toilets.n.32.png", 16, 16);
122     wptIcons["Drinking Water"] = icon_t("://icons/poi/SJJB/png/food_drinkingtap.n.32.png", 16, 16);
123     wptIcons["Telephone"] = icon_t("://icons/poi/SJJB/png/amenity_telephone.n.32.png", 16, 16);
124     wptIcons["Medical Facility"] = icon_t("://icons/poi/SJJB/png/health_hospital.n.32.png", 16, 16);
125     wptIcons["Information"] = icon_t("://icons/poi/SJJB/png/tourist_information.n.32.png", 16, 16);
126     wptIcons["Parking Area"] = icon_t("://icons/poi/SJJB/png/transport_parking.n.32.png", 16, 16);
127     wptIcons["Picnic Area"] = icon_t("://icons/poi/SJJB/png/tourist_picnic.n.32.png", 16, 16);
128     wptIcons["Scenic Area"] = icon_t("://icons/poi/SJJB/png/tourist_view_point.n.32.png", 16, 16);
129     wptIcons["Swimming Area"] = icon_t("://icons/poi/SJJB/png/sport_swimming_outdoor.n.32.png", 16, 16);
130     wptIcons["Dam"] = icon_t("://icons/poi/SJJB/png/water_dam.n.32.png", 16, 16);
131     wptIcons["Shopping Center"] = icon_t("://icons/poi/SJJB/png/shopping_supermarket.n.32.png", 16, 16);
132     wptIcons["Lodging"] = icon_t("://icons/poi/SJJB/png/accommodation_hotel.n.32.png", 16, 16);
133     wptIcons["Mine"] = icon_t("://icons/poi/SJJB/png/poi_mine.n.32.png", 16, 16);
134     wptIcons["Car Rental"] = icon_t("://icons/poi/SJJB/png/transport_rental_car.n.32.png", 16, 16);
135     wptIcons["Car Repair"] = icon_t("://icons/poi/SJJB/png/shopping_car_repair.n.32.png", 16, 16);
136     wptIcons["Fast Food"] = icon_t("://icons/poi/SJJB/png/food_fastfood.n.32.png", 16, 16);
137     wptIcons["Fitness Center"] = icon_t("://icons/poi/SJJB/png/sport_gym.n.32.png", 16, 16);
138     wptIcons["Museum"] = icon_t("://icons/poi/SJJB/png/tourist_museum.n.32.png", 16, 16);
139     wptIcons["Pharmacy"] = icon_t("://icons/poi/SJJB/png/health_pharmacy.n.32.png", 16, 16);
140     wptIcons["Pizza"] = icon_t("://icons/poi/SJJB/png/food_pizza.n.32.png", 16, 16);
141     wptIcons["Post Office"] = icon_t("://icons/poi/SJJB/png/amenity_post_office.n.32.png", 16, 16);
142     wptIcons["RV Park"] = icon_t("://icons/poi/SJJB/png/accommodation_caravan_park.n.32.png", 16, 16);
143     wptIcons["School"] = icon_t("://icons/poi/SJJB/png/education_school.n.32.png", 16, 16);
144     wptIcons["Stadium"] = icon_t("://icons/poi/SJJB/png/sport_stadium.n.32.png", 16, 16);
145     wptIcons["Department Store"] = icon_t("://icons/poi/SJJB/png/shopping_department_store.n.32.png", 16, 16);
146     wptIcons["Zoo"] = icon_t("://icons/poi/SJJB/png/tourist_zoo.n.32.png", 16, 16);
147     wptIcons["Convenience Store"] = icon_t("://icons/poi/SJJB/png/shopping_convenience.n.32.png", 16, 16);
148     wptIcons["Live Theater"] = icon_t("://icons/poi/SJJB/png/tourist_theatre.n.32.png", 16, 16);
149     wptIcons["Scales"] = icon_t("://icons/poi/SJJB/png/amenity_court.n.32.png", 16, 16);
150     wptIcons["Church"] = icon_t("://icons/poi/SJJB/png/place_of_worship_unknown.n.32.png", 16, 16);
151     wptIcons["Ghost Town"] = icon_t("://icons/poi/SJJB/png/tourist_ruin.n.32.png", 16, 16);
152     wptIcons["Beach"] = icon_t("://icons/poi/SJJB/png/tourist_beach.n.32.png", 16, 16);
153     wptIcons["Forest"] = icon_t("://icons/poi/SJJB/png/landuse_coniferous_and_deciduous.n.32.png", 16, 16);
154     wptIcons["Airport"] = icon_t("://icons/poi/SJJB/png/transport_airport.n.32.png", 16, 16);
155     wptIcons["Heliport"] = icon_t("://icons/poi/SJJB/png/transport_helicopter_pad.n.32.png", 16, 16);
156     wptIcons["Tall Tower"] = icon_t("://icons/poi/SJJB/png/poi_tower_communications.n.32.png", 16, 16);
157     wptIcons["Short Tower"] = icon_t("://icons/poi/SJJB/png/poi_tower_lookout.n.32.png", 16, 16);
158     wptIcons["Library"] = icon_t("://icons/poi/SJJB/png/amenity_library.n.32.png", 16, 16);
159     wptIcons["Ground Transportation"] = icon_t("://icons/poi/SJJB/png/transport_bus_stop.n.32.png", 16, 16);
160     wptIcons["City Hall"] = icon_t("://icons/poi/SJJB/png/amenity_town_hall.n.32.png", 16, 16);
161     wptIcons["Winery"] = icon_t("://icons/poi/SJJB/png/shopping_alcohol.n.32.png", 16, 16);
162     wptIcons["Lodge"] = icon_t("://icons/poi/SJJB/png/accommodation_shelter.n.32.png", 16, 16);
163     wptIcons["Railway"] = icon_t("://icons/poi/SJJB/png/transport_train_station.n.32.png", 16, 16);
164     wptIcons["Parking, Pay"] = icon_t("://icons/poi/SJJB/png/transport_parking_car_paid.n.32.png", 16, 16);
165 
166     setWptIconByName("Traditional Cache", "://icons/geocaching/icons/traditional.png");
167     setWptIconByName("Multi-cache", "://icons/geocaching/icons/multi.png");
168     setWptIconByName("Unknown Cache", "://icons/geocaching/icons/unknown.png");
169     setWptIconByName("Wherigo Cache", "://icons/geocaching/icons/wherigo.png");
170     setWptIconByName("Event Cache", "://icons/geocaching/icons/event.png");
171     setWptIconByName("Mega-Event Cache", "://icons/geocaching/icons/mega.png");
172     setWptIconByName("Giga-Event Cache", "://icons/geocaching/icons/giga.png");
173     setWptIconByName("Cache In Trash Out Event", "://icons/geocaching/icons/cito.png");
174     setWptIconByName("Earthcache", "://icons/geocaching/icons/earth.png");
175     setWptIconByName("Letterbox Hybrid", "://icons/geocaching/icons/letterbox.png");
176     setWptIconByName("Virtual Cache", "://icons/geocaching/icons/virtual.png");
177     setWptIconByName("Webcam Cache", "://icons/geocaching/icons/webcam.png");
178 
179     setWptIconByName("gray_Traditional Cache", createGrayscale("://icons/geocaching/icons/traditional.png"));
180     setWptIconByName("gray_Multi-cache", createGrayscale("://icons/geocaching/icons/multi.png"));
181     setWptIconByName("gray_Unknown Cache", createGrayscale("://icons/geocaching/icons/unknown.png"));
182     setWptIconByName("gray_Wherigo Cache", createGrayscale("://icons/geocaching/icons/wherigo.png"));
183     setWptIconByName("gray_Event Cache", createGrayscale("://icons/geocaching/icons/event.png"));
184     setWptIconByName("gray_Mega-Event Cache", createGrayscale("://icons/geocaching/icons/mega.png"));
185     setWptIconByName("gray_Giga-Event Cache", createGrayscale("://icons/geocaching/icons/giga.png"));
186     setWptIconByName("gray_Cache In Trash Out Event", createGrayscale("://icons/geocaching/icons/cito.png"));
187     setWptIconByName("gray_Earthcache", createGrayscale("://icons/geocaching/icons/earth.png"));
188     setWptIconByName("gray_Letterbox Hybrid", createGrayscale("://icons/geocaching/icons/letterbox.png"));
189     setWptIconByName("gray_Virtual Cache", createGrayscale("://icons/geocaching/icons/virtual.png"));
190     setWptIconByName("gray_Webcam Cache", createGrayscale("://icons/geocaching/icons/webcam.png"));
191 
192     SETTINGS;
193     QDir dirIcon(cfg.value("Paths/externalWptIcons", IAppSetup::getPlatformInstance()->userDataPath("WaypointIcons")).toString());
194 
195 
196     const QStringList& filenames = dirIcon.entryList(QString("*.bmp *.png").split(" "), QDir::Files);
197 
198     for(const QString& filename : filenames)
199     {
200         QFileInfo fi(filename);
201         QString name = fi.completeBaseName();
202         setWptIconByName(name, dirIcon.filePath(filename));
203     }
204 }
205 
setWptIconByName(const QString & name,const QString & filename)206 void CWptIconManager::setWptIconByName(const QString& name, const QString& filename)
207 {
208     QPixmap icon(filename);
209     wptIcons[name] = icon_t(filename, icon.width() >> 1, icon.height() >> 1);
210 }
211 
212 
setWptIconByName(const QString & name,const QPixmap & icon)213 void CWptIconManager::setWptIconByName(const QString& name, const QPixmap& icon)
214 {
215     SETTINGS;
216     QDir dirIcon(cfg.value("Paths/externalWptIcons", IAppSetup::getPlatformInstance()->userDataPath("WaypointIcons")).toString());
217     QString filename = dirIcon.filePath(name + ".png");
218 
219     icon.save(filename);
220     wptIcons[name] = icon_t(filename, icon.width() >> 1, icon.height() >> 1);
221 }
222 
loadIcon(const QString & path)223 QPixmap CWptIconManager::loadIcon(const QString& path)
224 {
225     QFileInfo finfo(path);
226     if(finfo.completeSuffix() != "bmp")
227     {
228         return QPixmap(path);
229     }
230     else
231     {
232         QImage img = QPixmap(path).toImage().convertToFormat(QImage::Format_Indexed8);
233         img.setColor(0, qRgba(0, 0, 0, 0));
234         return QPixmap::fromImage(img);
235     }
236 }
237 
238 
getWptIconByName(const QString & name,QPointF & focus,QString * src)239 QPixmap CWptIconManager::getWptIconByName(const QString& name, QPointF& focus, QString* src)
240 {
241     QPixmap icon;
242     QString path;
243 
244     if(wptIcons.contains(name))
245     {
246         focus = wptIcons[name].focus;
247         path = wptIcons[name].path;
248     }
249     else
250     {
251         focus = wptIcons["Default"].focus;
252         path = wptIcons["Default"].path;
253     }
254 
255     if(path.isEmpty())
256     {
257         path = wptDefault;
258     }
259 
260     if(src)
261     {
262         *src = path;
263     }
264 
265     icon = loadIcon(path);
266 
267     // Limit icon size to 22 pixel max.
268     if(icon.width() > 22 || icon.height() > 22)
269     {
270         qreal s;
271         if(icon.width() > icon.height())
272         {
273             s = 22.0 / icon.width();
274         }
275         else
276         {
277             s = 22.0 / icon.height();
278         }
279 
280         focus = focus * s;
281         icon = icon.scaled(icon.size() * s, Qt::KeepAspectRatio, Qt::SmoothTransformation);
282     }
283 
284     return icon;
285 }
286 
selectWptIcon(QWidget * parent)287 QString CWptIconManager::selectWptIcon(QWidget* parent)
288 {
289     QString icon;
290 
291     QMenu* menu = getWptIconMenu("", nullptr, "", parent);
292     QAction* action = menu->exec(QCursor::pos());
293 
294     if(action != nullptr)
295     {
296         icon = action->property("iconName").toString();
297     }
298 
299     return icon;
300 }
301 
302 
303 
getNumberedBullet(qint32 n)304 QString CWptIconManager::getNumberedBullet(qint32 n)
305 {
306     const QFont& font = CMainWindow::self().getMapFont();
307     if(mapNumberedBullets.contains(n) && (lastFont == font))
308     {
309         return mapNumberedBullets[n];
310     }
311 
312     if(lastFont != font)
313     {
314         removeNumberedBullets();
315         lastFont = font;
316     }
317 
318     const QString& filename = QDir::temp().absoluteFilePath(QString("Bullet%1.png").arg(n));
319     mapNumberedBullets[n] = filename;
320 
321     const QPixmap& pixmap = CDraw::number(n, Qt::black);
322     pixmap.save(filename);
323 
324     return filename;
325 }
326 
getWptIconMenu(const QString & title,QObject * obj,const char * slot,QWidget * parent)327 QMenu* CWptIconManager::getWptIconMenu(const QString& title, QObject* obj, const char* slot, QWidget* parent)
328 {
329     QMenu* menu = new QMenu(title, parent);
330     menu->setIcon(QIcon("://icons/waypoints/32x32/PinBlue.png"));
331 
332     const QMap<QString, icon_t>& wptIcons = getWptIcons();
333     QStringList keys = wptIcons.keys();
334 
335     qSort(keys.begin(), keys.end(), sortByString);
336 
337     for(const QString& key : qAsConst(keys))
338     {
339         const QString& icon = wptIcons[key].path;
340         QPixmap pixmap = loadIcon(icon);
341 
342         QAction* action = menu->addAction(pixmap, key);
343         action->setProperty("iconName", key);
344         if(obj != nullptr)
345         {
346             QAction::connect(action, SIGNAL(triggered(bool)), obj, slot);
347         }
348     }
349 
350     return menu;
351 }
352 
353