30#include <wx/filename.h>
36#include "base_platform.h"
38#include "route_point.h"
41#include "waypointman_gui.h"
42#include "ocpn_plugin.h"
45extern float g_MarkScaleFactorExp;
49 return (mi1->icon_name.CmpNoCase(mi2->icon_name));
56 msg.Printf(_T(
"DPMM: %g ScaleFactorExp: %g"), displayDPmm,
57 g_MarkScaleFactorExp);
60 wxString UserIconPath = g_BasePlatform->GetPrivateDataDir();
61 wxChar sep = wxFileName::GetPathSeparator();
62 if (UserIconPath.Last() != sep) UserIconPath.Append(sep);
63 UserIconPath.Append(_T(
"UserIcons/"));
65 wxLogMessage(_T(
"Looking for UserIcons at ") + UserIconPath);
67 if (wxDir::Exists(UserIconPath)) {
68 wxLogMessage(_T(
"Loading UserIcons from ") + UserIconPath);
69 wxArrayString FileList;
72 wxDir::GetAllFiles(UserIconPath, &FileList, _T(
""), wxDIR_FILES);
74 for (
int ifile = 0; ifile < n_files; ifile++) {
75 wxString name = FileList[ifile];
78 wxString iconname = fn.GetName();
81 if (fn.GetExt().Lower() == _T(
"xpm")) {
82 if (icon1.LoadFile(name, wxBITMAP_TYPE_XPM)) {
83 wxLogMessage(_T(
"Adding icon: ") + iconname);
84 ProcessIcon(icon1, iconname, iconname);
87 if (fn.GetExt().Lower() == _T(
"png")) {
88 if (icon1.LoadFile(name, wxBITMAP_TYPE_PNG)) {
89 wxLogMessage(_T(
"Adding icon: ") + iconname);
90 ProcessIcon(icon1, iconname, iconname);
93 if (fn.GetExt().Lower() == _T(
"svg")) {
95 SVGDocumentPixelSize(name, w, h);
96 w = wxMax(wxMax(w, h), 15);
98 const unsigned int bm_size = w;
99 wxBitmap iconSVG = LoadSVG(name, bm_size, bm_size);
100 MarkIcon *pmi = ProcessIcon(iconSVG, iconname, iconname);
101 if (pmi) pmi->preScaled =
true;
107MarkIcon* WayPointmanGui::ProcessIcon(wxBitmap pimage,
const wxString& key,
108 const wxString& description) {
114 for (
unsigned int i = 0; i < m_waypoint_man.m_pIconArray->GetCount(); i++) {
115 pmi = (
MarkIcon *)m_waypoint_man.m_pIconArray->Item(i);
116 if (pmi->icon_name.IsSameAs(key)) {
118 delete pmi->piconBitmap;
125 pmi->icon_name = key;
126 m_waypoint_man.m_pIconArray->Add(pmi);
129 wxBitmap *pbm =
new wxBitmap(pimage);
130 pmi->icon_name = key;
131 pmi->icon_description = description;
132 pmi->piconBitmap = NULL;
133 pmi->icon_texture = 0;
134 pmi->preScaled =
false;
135 pmi->iconImage = pbm->ConvertToImage();
136 pmi->m_blistImageOK =
false;
142void WayPointmanGui::ProcessIcons(
ocpnStyle::Style *style,
double displayDPmm) {
143 m_waypoint_man.m_pIconArray->Clear();
145 ProcessDefaultIcons(displayDPmm);
151 ProcessUserIcons(style, displayDPmm);
153 if (NULL != m_waypoint_man.pmarkicon_image_list) {
154 m_waypoint_man.pmarkicon_image_list->RemoveAll();
155 delete m_waypoint_man.pmarkicon_image_list;
156 m_waypoint_man.pmarkicon_image_list = NULL;
164 for (
unsigned int i = 0; i < m_waypoint_man.m_pIconArray->GetCount(); i++) {
166 w = wxMax(w, pmi->iconImage.GetWidth());
167 h = wxMax(h, pmi->iconImage.GetHeight());
170 m_waypoint_man.m_bitmapSizeForList = wxMax(w, h);
171 m_waypoint_man.m_bitmapSizeForList =
172 wxMin(100, m_waypoint_man.m_bitmapSizeForList);
175void WayPointmanGui::ProcessDefaultIcons(
double displayDPmm) {
176 wxString iconDir = g_BasePlatform->GetSharedDataDir();
177 appendOSDirSlash(&iconDir);
178 iconDir.append(_T(
"uidata"));
179 appendOSDirSlash(&iconDir);
180 iconDir.append(_T(
"markicons"));
181 appendOSDirSlash(&iconDir);
186 if (m_waypoint_man.m_pLegacyIconArray)
187 m_waypoint_man.m_pLegacyIconArray->Clear();
189 m_waypoint_man.m_pLegacyIconArray =
190 new SortedArrayOfMarkIcon(CompareMarkIcons);
192 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-Empty.svg"), _T(
"empty"),
193 _T(
"Empty"), displayDPmm);
194 if (pmi) pmi->preScaled =
true;
195 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-Triangle.svg"), _T(
"triangle"),
196 _T(
"Triangle"), displayDPmm);
197 if (pmi) pmi->preScaled =
true;
198 pmi = ProcessLegacyIcon(iconDir + _T(
"1st-Active-Waypoint.svg"),
199 _T(
"activepoint"), _T(
"Active WP"), displayDPmm);
200 if (pmi) pmi->preScaled =
true;
201 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Boarding-Location.svg"),
202 _T(
"boarding"), _T(
"Boarding Location"), displayDPmm);
203 if (pmi) pmi->preScaled =
true;
204 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Airplane.svg"), _T(
"airplane"),
205 _T(
"Airplane"), displayDPmm);
206 if (pmi) pmi->preScaled =
true;
207 pmi = ProcessLegacyIcon(iconDir + _T(
"1st-Anchorage.svg"), _T(
"anchorage"),
208 _T(
"Anchorage"), displayDPmm);
209 if (pmi) pmi->preScaled =
true;
210 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-Anchor2.svg"), _T(
"anchor"),
211 _T(
"Anchor"), displayDPmm);
212 if (pmi) pmi->preScaled =
true;
213 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Boundary.svg"), _T(
"boundary"),
214 _T(
"Boundary Mark"), displayDPmm);
215 if (pmi) pmi->preScaled =
true;
216 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Buoy-TypeA.svg"), _T(
"bouy1"),
217 _T(
"Bouy Type A"), displayDPmm);
218 if (pmi) pmi->preScaled =
true;
219 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Buoy-TypeB.svg"), _T(
"bouy2"),
220 _T(
"Bouy Type B"), displayDPmm);
221 if (pmi) pmi->preScaled =
true;
222 pmi = ProcessLegacyIcon(iconDir + _T(
"Activity-Campfire.svg"), _T(
"campfire"),
223 _T(
"Campfire"), displayDPmm);
224 if (pmi) pmi->preScaled =
true;
225 pmi = ProcessLegacyIcon(iconDir + _T(
"Activity-Camping.svg"), _T(
"camping"),
226 _T(
"Camping Spot"), displayDPmm);
227 if (pmi) pmi->preScaled =
true;
228 pmi = ProcessLegacyIcon(iconDir + _T(
"Sea-Floor-Coral.svg"), _T(
"coral"),
229 _T(
"Coral"), displayDPmm);
230 if (pmi) pmi->preScaled =
true;
231 pmi = ProcessLegacyIcon(iconDir + _T(
"Activity-Fishing.svg"), _T(
"fishhaven"),
232 _T(
"Fish Haven"), displayDPmm);
233 if (pmi) pmi->preScaled =
true;
234 pmi = ProcessLegacyIcon(iconDir + _T(
"Activity-Fishing.svg"), _T(
"fishing"),
235 _T(
"Fishing Spot"), displayDPmm);
236 if (pmi) pmi->preScaled =
true;
237 pmi = ProcessLegacyIcon(iconDir + _T(
"Activity-Fishing.svg"), _T(
"fish"),
238 _T(
"Fish"), displayDPmm);
239 if (pmi) pmi->preScaled =
true;
240 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Mooring-Buoy.svg"), _T(
"float"),
241 _T(
"Float"), displayDPmm);
242 if (pmi) pmi->preScaled =
true;
243 pmi = ProcessLegacyIcon(iconDir + _T(
"Service-Food.svg"), _T(
"food"),
244 _T(
"Food"), displayDPmm);
245 if (pmi) pmi->preScaled =
true;
246 pmi = ProcessLegacyIcon(iconDir + _T(
"Service-Fuel-Pump-Diesel-Petrol.svg"),
247 _T(
"fuel"), _T(
"Fuel"), displayDPmm);
248 if (pmi) pmi->preScaled =
true;
249 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Light-Green.svg"),
250 _T(
"greenlite"), _T(
"Green Light"), displayDPmm);
251 if (pmi) pmi->preScaled =
true;
252 pmi = ProcessLegacyIcon(iconDir + _T(
"Sea-Floor-Sea-Weed.svg"), _T(
"kelp"),
253 _T(
"Kelp"), displayDPmm);
254 if (pmi) pmi->preScaled =
true;
255 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Light-TypeA.svg"), _T(
"light"),
256 _T(
"Light Type A"), displayDPmm);
257 if (pmi) pmi->preScaled =
true;
258 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Light-TypeB.svg"), _T(
"light1"),
259 _T(
"Light Type B"), displayDPmm);
260 if (pmi) pmi->preScaled =
true;
261 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Light-Vessel.svg"),
262 _T(
"litevessel"), _T(
"litevessel"), displayDPmm);
263 if (pmi) pmi->preScaled =
true;
264 pmi = ProcessLegacyIcon(iconDir + _T(
"1st-Man-Overboard.svg"), _T(
"mob"),
265 _T(
"MOB"), displayDPmm);
266 if (pmi) pmi->preScaled =
true;
267 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Mooring-Buoy.svg"), _T(
"mooring"),
268 _T(
"Mooring Bouy"), displayDPmm);
269 if (pmi) pmi->preScaled =
true;
270 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Mooring-Buoy-Super.svg"),
271 _T(
"oilbouy"), _T(
"Oil Bouy"), displayDPmm);
272 if (pmi) pmi->preScaled =
true;
273 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Oil-Platform.svg"),
274 _T(
"platform"), _T(
"Platform"), displayDPmm);
275 if (pmi) pmi->preScaled =
true;
276 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Light-Red-Green.svg"),
277 _T(
"redgreenlite"), _T(
"Red/Green Light"), displayDPmm);
278 if (pmi) pmi->preScaled =
true;
279 pmi = ProcessLegacyIcon(iconDir + _T(
"Marks-Light-Red.svg"), _T(
"redlite"),
280 _T(
"Red Light"), displayDPmm);
281 if (pmi) pmi->preScaled =
true;
282 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Rock-Exposed.svg"), _T(
"rock1"),
283 _T(
"Rock (exposed)"), displayDPmm);
284 if (pmi) pmi->preScaled =
true;
285 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Rock-Awash.svg"), _T(
"rock2"),
286 _T(
"Rock, (awash)"), displayDPmm);
287 if (pmi) pmi->preScaled =
true;
288 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Sandbar.svg"), _T(
"sand"),
289 _T(
"Sand"), displayDPmm);
290 if (pmi) pmi->preScaled =
true;
291 pmi = ProcessLegacyIcon(iconDir + _T(
"Activity-Diving-Scuba-Flag.svg"),
292 _T(
"scuba"), _T(
"Scuba"), displayDPmm);
293 if (pmi) pmi->preScaled =
true;
294 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Sandbar.svg"), _T(
"shoal"),
295 _T(
"Shoal"), displayDPmm);
296 if (pmi) pmi->preScaled =
true;
297 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Snag.svg"), _T(
"snag"),
298 _T(
"Snag"), displayDPmm);
299 if (pmi) pmi->preScaled =
true;
300 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-Square.svg"), _T(
"square"),
301 _T(
"Square"), displayDPmm);
302 if (pmi) pmi->preScaled =
true;
303 pmi = ProcessLegacyIcon(iconDir + _T(
"1st-Diamond.svg"), _T(
"diamond"),
304 _T(
"Diamond"), displayDPmm);
305 if (pmi) pmi->preScaled =
true;
306 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-Circle.svg"), _T(
"circle"),
307 _T(
"Circle"), displayDPmm);
308 if (pmi) pmi->preScaled =
true;
309 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Wreck1.svg"), _T(
"wreck1"),
310 _T(
"Wreck A"), displayDPmm);
311 if (pmi) pmi->preScaled =
true;
312 pmi = ProcessLegacyIcon(iconDir + _T(
"Hazard-Wreck2.svg"), _T(
"wreck2"),
313 _T(
"Wreck B"), displayDPmm);
314 if (pmi) pmi->preScaled =
true;
315 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-X-Small-Blue.svg"), _T(
"xmblue"),
316 _T(
"Blue X"), displayDPmm);
317 if (pmi) pmi->preScaled =
true;
318 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-X-Small-Green.svg"),
319 _T(
"xmgreen"), _T(
"Green X"), displayDPmm);
320 if (pmi) pmi->preScaled =
true;
321 pmi = ProcessLegacyIcon(iconDir + _T(
"Symbol-X-Small-Red.svg"), _T(
"xmred"),
322 _T(
"Red X"), displayDPmm);
323 if (pmi) pmi->preScaled =
true;
326 if (m_waypoint_man.m_pExtendedIconArray)
327 m_waypoint_man.m_pExtendedIconArray->Clear();
329 m_waypoint_man.m_pExtendedIconArray =
330 new SortedArrayOfMarkIcon(CompareMarkIcons);
333 wxArrayString FileList;
336 int n_files = wxDir::GetAllFiles( iconDir, &FileList );
340 if( fabs(g_ChartScaleFactorExp - 1.0) > 0.1){
342 for(
int ifile = 0; ifile < n_files; ifile++ ) {
343 wxString name = FileList[ifile];
345 wxFileName fn( name );
347 if( fn.GetExt().Lower() == _T(
"svg") ) {
348 wxBitmap bmt = LoadSVG(name, -1, -1 );
349 bm_size = bmt.GetWidth() * g_ChartScaleFactorExp;
355 for(
int ifile = 0; ifile < n_files; ifile++ ) {
356 wxString name = FileList[ifile];
358 wxFileName fn( name );
359 wxString iconname = fn.GetName();
361 if( fn.GetExt().Lower() == _T(
"svg") ) {
362 wxImage iconSVG = LoadSVG( name, (
int)bm_size, (
int)bm_size );
363 MarkIcon * pmi = ProcessExtendedIcon( iconSVG, iconname, iconname );
365 pmi->preScaled =
true;
370 wxArrayString FileList;
372 double bm_size = wxMax(4.0, floor(displayDPmm * 12.0));
373 bm_size /= OCPN_GetWinDIPScaleFactor();
374 bm_size *= g_MarkScaleFactorExp;
376 int n_files = wxDir::GetAllFiles(iconDir, &FileList);
378 g_BasePlatform->ShowBusySpinner();
380 for (
int ifile = 0; ifile < n_files; ifile++) {
381 wxString name = FileList[ifile];
384 wxString iconname = fn.GetName();
387 if (fn.GetExt().Lower() == _T(
"svg")) {
390 SVGDocumentPixelSize(name, w, h);
391 w = wxMax(wxMax(w, h), 15);
394 bm_size = w * g_MarkScaleFactorExp;
395 bm_size /= OCPN_GetWinDIPScaleFactor();
398 wxBitmap bmp = LoadSVG(name, (
int)bm_size, (
int)bm_size);
400 wxImage iconSVG = bmp.ConvertToImage();
402 MarkIcon *pmi = ProcessExtendedIcon(iconSVG, iconname, iconname);
403 if (pmi) pmi->preScaled =
true;
405 wxLogMessage(
"Failed loading mark icon " + name);
409 g_BasePlatform->HideBusySpinner();
414 auto size = m_waypoint_man.m_pLegacyIconArray->GetCount();
415 for (
unsigned int i = 0; i < size; i++) {
416 pmi = (
MarkIcon *)m_waypoint_man.m_pLegacyIconArray->Item(i);
417 m_waypoint_man.m_pIconArray->Add(pmi);
420 size = m_waypoint_man.m_pExtendedIconArray->GetCount();
421 for (
unsigned int i = 0; i < size; i++) {
422 pmi = (
MarkIcon *) m_waypoint_man.m_pExtendedIconArray->Item(i);
427 auto legacy_count = m_waypoint_man.m_pLegacyIconArray->GetCount();
428 for (
unsigned int j = 0; j < legacy_count; j++) {
430 (
MarkIcon *)m_waypoint_man.m_pLegacyIconArray->Item(j);
431 if (pmiLegacy->icon_name.IsSameAs(pmi->icon_name)) {
436 if (!noAdd) m_waypoint_man.m_pIconArray->Add(pmi);
440void WayPointmanGui::ReloadAllIcons(
double displayDPmm) {
441 ProcessIcons(g_StyleManager->GetCurrentStyle(), displayDPmm);
443 for (
unsigned int i = 0; i < m_waypoint_man.m_pIconArray->GetCount(); i++) {
446 if (m_waypoint_man.m_cs == GLOBAL_COLOR_SCHEME_DUSK) {
447 dim_image = m_waypoint_man.CreateDimImage(pmi->iconImage, .50);
448 pmi->iconImage = dim_image;
449 }
else if (m_waypoint_man.m_cs == GLOBAL_COLOR_SCHEME_NIGHT) {
450 dim_image = m_waypoint_man.CreateDimImage(pmi->iconImage, .20);
451 pmi->iconImage = dim_image;
454 ReloadRoutepointIcons();
457void WayPointmanGui::SetColorScheme(ColorScheme cs,
double displayDPmm) {
458 m_waypoint_man.m_cs = cs;
459 ReloadAllIcons(displayDPmm);
462MarkIcon *WayPointmanGui::ProcessLegacyIcon(wxString fileName,
const wxString &key,
463 const wxString &description,
464 double displayDPmm) {
465 double bm_size = -1.0;
467#ifndef ocpnUSE_wxBitmapBundle
469 if (fabs(g_MarkScaleFactorExp - 1.0) > 0.1) {
470 wxBitmap img = LoadSVG(fileName, -1, -1);
471 bm_size = img.GetWidth() * g_MarkScaleFactorExp;
472 bm_size /= OCPN_GetWinDIPScaleFactor();
481 float nominal_legacy_icon_size_pixels = wxMax(4.0,
482 floor(displayDPmm * 12.0));
484 float pix_factor = nominal_legacy_icon_size_pixels / 68.0;
486 wxBitmap img = LoadSVG(fileName, -1, -1);
487 bm_size = img.GetWidth() * pix_factor * g_MarkScaleFactorExp;
491 SVGDocumentPixelSize(fileName, w, h);
492 w = wxMax(wxMax(w, h), 15);
494 bm_size = w * g_MarkScaleFactorExp;
495 bm_size /= OCPN_GetWinDIPScaleFactor();
499 LoadSVG(fileName, (
int)bm_size, (
int)bm_size).ConvertToImage();
501 wxRect rClip = CropImageOnAlpha(image);
502 wxImage imageClip = image.GetSubImage(rClip);
509 for (
unsigned int i = 0; i < m_waypoint_man.m_pLegacyIconArray->GetCount(); i++) {
510 pmi = (
MarkIcon *)m_waypoint_man.m_pLegacyIconArray->Item(i);
511 if (pmi->icon_name.IsSameAs(key)) {
513 delete pmi->piconBitmap;
520 pmi->icon_name = key;
521 m_waypoint_man.m_pLegacyIconArray->Add(pmi);
524 pmi->icon_name = key;
525 pmi->icon_description = description;
526 pmi->piconBitmap = NULL;
527 pmi->icon_texture = 0;
528 pmi->preScaled =
false;
529 pmi->iconImage = imageClip;
530 pmi->m_blistImageOK =
false;
535MarkIcon *WayPointmanGui::ProcessExtendedIcon(wxImage &image,
537 const wxString &description) {
543 auto size = m_waypoint_man.m_pExtendedIconArray->GetCount();
544 for (
unsigned int i = 0; i < size; i++) {
545 pmi = (
MarkIcon *)m_waypoint_man.m_pExtendedIconArray->Item(i);
546 if (pmi->icon_name.IsSameAs(key)) {
548 delete pmi->piconBitmap;
555 pmi->icon_name = key;
556 m_waypoint_man.m_pExtendedIconArray->Add(pmi);
559 wxRect rClip = CropImageOnAlpha(image);
560 wxImage imageClip = image.GetSubImage(rClip);
562 pmi->icon_name = key;
563 pmi->icon_description = description;
564 pmi->piconBitmap = NULL;
565 pmi->icon_texture = 0;
566 pmi->preScaled =
false;
567 pmi->iconImage = imageClip;
568 pmi->m_blistImageOK =
false;
573wxRect WayPointmanGui::CropImageOnAlpha(wxImage &image) {
574 const int w = image.GetWidth();
575 const int h = image.GetHeight();
577 wxRect rv = wxRect(0, 0, w, h);
578 if (!image.HasAlpha())
return rv;
580 unsigned char *pAlpha = image.GetAlpha();
588 for (
int i = 0; i < h; i++) {
589 int lineStartIndex = i * w;
592 while ((j < w) && (pAlpha[lineStartIndex + j] == 0)) j++;
593 leftCrop = wxMin(leftCrop, j);
596 while (k && (pAlpha[lineStartIndex + k] == 0)) k--;
597 rightCrop = wxMin(rightCrop, image.GetWidth() - k - 2);
601 for (
int i = 0; i < w; i++) {
602 int columnStartIndex = i;
605 while ((j < h) && (pAlpha[columnStartIndex + (j * w)] == 0)) j++;
606 topCrop = wxMin(topCrop, j);
609 while (k && (pAlpha[columnStartIndex + (k * w)] == 0)) k--;
610 bottomCrop = wxMin(bottomCrop, h - k - 2);
613 int xcrop = wxMin(rightCrop, leftCrop);
614 int ycrop = wxMin(topCrop, bottomCrop);
615 int crop = wxMin(xcrop, ycrop);
617 rv.x = wxMax(crop, 0);
618 rv.width = wxMax(1, w - (2 * crop));
619 rv.width = wxMin(rv.width, w);
621 rv.height = rv.width;
626void WayPointmanGui::ReloadRoutepointIcons() {
629 wxRoutePointListNode *node = m_waypoint_man.m_pWayPointList->GetFirst();
633 node = node->GetNext();