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