Browse Source

Maps: Add markers to map widget

Bastiaan van der Plaat 1 year ago
parent
commit
dfb54083ee

BIN
Base/res/graphics/maps/marker-blue.png


+ 38 - 2
Userland/Applications/Maps/MapWidget.cpp

@@ -59,6 +59,7 @@ MapWidget::MapWidget(Options const& options)
     m_request_client = Protocol::RequestClient::try_create().release_value_but_fixme_should_propagate_errors();
     m_request_client = Protocol::RequestClient::try_create().release_value_but_fixme_should_propagate_errors();
     if (options.attribution_enabled)
     if (options.attribution_enabled)
         add_panel({ options.attribution_text, Panel::Position::BottomRight, options.attribution_url, true });
         add_panel({ options.attribution_text, Panel::Position::BottomRight, options.attribution_url, true });
+    m_marker_image = Gfx::Bitmap::load_from_file("/res/graphics/maps/marker-blue.png"sv).release_value_but_fixme_should_propagate_errors();
 }
 }
 
 
 void MapWidget::set_zoom(int zoom)
 void MapWidget::set_zoom(int zoom)
@@ -114,6 +115,28 @@ void MapWidget::mousemove_event(GUI::MouseEvent& event)
         if (panel.url.has_value() && panel.rect.contains(event.x(), event.y()))
         if (panel.url.has_value() && panel.rect.contains(event.x(), event.y()))
             return set_override_cursor(Gfx::StandardCursor::Hand);
             return set_override_cursor(Gfx::StandardCursor::Hand);
     set_override_cursor(Gfx::StandardCursor::Arrow);
     set_override_cursor(Gfx::StandardCursor::Arrow);
+
+    // Handle marker tooltip hover
+    double center_tile_x = floor(longitude_to_tile_x(m_center.longitude, m_zoom));
+    double center_tile_y = floor(latitude_to_tile_y(m_center.latitude, m_zoom));
+    double offset_x = (longitude_to_tile_x(m_center.longitude, m_zoom) - center_tile_x) * TILE_SIZE;
+    double offset_y = (latitude_to_tile_y(m_center.latitude, m_zoom) - center_tile_y) * TILE_SIZE;
+    for (auto const& marker : m_markers) {
+        if (!marker.tooltip.has_value())
+            continue;
+        RefPtr<Gfx::Bitmap> marker_image = marker.image ? marker.image : m_marker_image;
+        Gfx::IntRect marker_rect = {
+            static_cast<int>(width() / 2 + (longitude_to_tile_x(marker.latlng.longitude, m_zoom) - center_tile_x) * TILE_SIZE - offset_x) - marker_image->width() / 2,
+            static_cast<int>(height() / 2 + (latitude_to_tile_y(marker.latlng.latitude, m_zoom) - center_tile_y) * TILE_SIZE - offset_y) - marker_image->height(),
+            marker_image->width(),
+            marker_image->height()
+        };
+        if (marker_rect.contains(event.x(), event.y())) {
+            GUI::Application::the()->show_tooltip(marker.tooltip.value().to_deprecated_string(), this);
+            return;
+        }
+    }
+    GUI::Application::the()->hide_tooltip();
 }
 }
 
 
 void MapWidget::mouseup_event(GUI::MouseEvent& event)
 void MapWidget::mouseup_event(GUI::MouseEvent& event)
@@ -246,7 +269,7 @@ void MapWidget::clear_tile_queue()
     m_tiles.remove_all_matching([](auto, auto const& value) -> bool { return !value; });
     m_tiles.remove_all_matching([](auto, auto const& value) -> bool { return !value; });
 }
 }
 
 
-void MapWidget::paint_tiles(GUI::Painter& painter)
+void MapWidget::paint_map(GUI::Painter& painter)
 {
 {
     int center_tile_x = floor(longitude_to_tile_x(m_center.longitude, m_zoom));
     int center_tile_x = floor(longitude_to_tile_x(m_center.longitude, m_zoom));
     int center_tile_y = floor(latitude_to_tile_y(m_center.latitude, m_zoom));
     int center_tile_y = floor(latitude_to_tile_y(m_center.latitude, m_zoom));
@@ -323,6 +346,19 @@ void MapWidget::paint_tiles(GUI::Painter& painter)
             }
             }
         }
         }
     }
     }
+
+    // Draw markers
+    for (auto const& marker : m_markers) {
+        RefPtr<Gfx::Bitmap> marker_image = marker.image ? marker.image : m_marker_image;
+        Gfx::IntRect marker_rect = {
+            static_cast<int>(width() / 2 + (longitude_to_tile_x(marker.latlng.longitude, m_zoom) - center_tile_x) * TILE_SIZE - offset_x) - marker_image->width() / 2,
+            static_cast<int>(height() / 2 + (latitude_to_tile_y(marker.latlng.latitude, m_zoom) - center_tile_y) * TILE_SIZE - offset_y) - marker_image->height(),
+            marker_image->width(),
+            marker_image->height()
+        };
+        if (marker_rect.intersects(frame_inner_rect()))
+            painter.blit(marker_rect.location(), *marker_image, { 0, 0, marker_image->width(), marker_image->height() }, 1);
+    }
 }
 }
 
 
 void MapWidget::paint_scale_line(GUI::Painter& painter, String label, Gfx::IntRect rect)
 void MapWidget::paint_scale_line(GUI::Painter& painter, String label, Gfx::IntRect rect)
@@ -400,7 +436,7 @@ void MapWidget::paint_event(GUI::PaintEvent& event)
     if (m_connection_failed)
     if (m_connection_failed)
         return painter.draw_text(frame_inner_rect(), "Failed to fetch map tiles :^("sv, Gfx::TextAlignment::Center, panel_foreground_color);
         return painter.draw_text(frame_inner_rect(), "Failed to fetch map tiles :^("sv, Gfx::TextAlignment::Center, panel_foreground_color);
 
 
-    paint_tiles(painter);
+    paint_map(painter);
     if (m_scale_enabled)
     if (m_scale_enabled)
         paint_scale(painter);
         paint_scale(painter);
     paint_panels(painter);
     paint_panels(painter);

+ 23 - 2
Userland/Applications/Maps/MapWidget.h

@@ -48,6 +48,22 @@ public:
     int zoom() const { return m_zoom; }
     int zoom() const { return m_zoom; }
     void set_zoom(int zoom);
     void set_zoom(int zoom);
 
 
+    struct Marker {
+        LatLng latlng;
+        Optional<String> tooltip {};
+        RefPtr<Gfx::Bitmap> image { nullptr };
+    };
+    void add_marker(Marker const& marker)
+    {
+        m_markers.append(marker);
+        update();
+    }
+    void clear_markers()
+    {
+        m_markers.clear();
+        update();
+    }
+
     struct Panel {
     struct Panel {
         enum class Position {
         enum class Position {
             TopLeft,
             TopLeft,
@@ -93,9 +109,12 @@ public:
         Download,
         Download,
     };
     };
 
 
-private:
+protected:
     MapWidget(Options const&);
     MapWidget(Options const&);
 
 
+    RefPtr<Protocol::RequestClient> request_client() const { return m_request_client; }
+
+private:
     virtual void doubleclick_event(GUI::MouseEvent&) override;
     virtual void doubleclick_event(GUI::MouseEvent&) override;
     virtual void mousemove_event(GUI::MouseEvent&) override;
     virtual void mousemove_event(GUI::MouseEvent&) override;
     virtual void mousedown_event(GUI::MouseEvent&) override;
     virtual void mousedown_event(GUI::MouseEvent&) override;
@@ -109,7 +128,7 @@ private:
     void process_tile_queue();
     void process_tile_queue();
     void clear_tile_queue();
     void clear_tile_queue();
 
 
-    void paint_tiles(GUI::Painter&);
+    void paint_map(GUI::Painter&);
     void paint_scale_line(GUI::Painter&, String label, Gfx::IntRect rect);
     void paint_scale_line(GUI::Painter&, String label, Gfx::IntRect rect);
     void paint_scale(GUI::Painter&);
     void paint_scale(GUI::Painter&);
     void paint_panels(GUI::Painter&);
     void paint_panels(GUI::Painter&);
@@ -131,6 +150,7 @@ private:
     RefPtr<Protocol::RequestClient> m_request_client;
     RefPtr<Protocol::RequestClient> m_request_client;
     Vector<RefPtr<Protocol::Request>, TILES_DOWNLOAD_PARALLEL_MAX> m_active_requests;
     Vector<RefPtr<Protocol::Request>, TILES_DOWNLOAD_PARALLEL_MAX> m_active_requests;
     Queue<TileKey, 32> m_tile_queue;
     Queue<TileKey, 32> m_tile_queue;
+    RefPtr<Gfx::Bitmap> m_marker_image;
     String m_tile_layer_url;
     String m_tile_layer_url;
     LatLng m_center;
     LatLng m_center;
     int m_zoom {};
     int m_zoom {};
@@ -144,6 +164,7 @@ private:
     bool m_first_image_loaded { false };
     bool m_first_image_loaded { false };
     bool m_connection_failed { false };
     bool m_connection_failed { false };
     OrderedHashMap<TileKey, RefPtr<Gfx::Bitmap>> m_tiles;
     OrderedHashMap<TileKey, RefPtr<Gfx::Bitmap>> m_tiles;
+    Vector<Marker> m_markers;
     Vector<Panel> m_panels;
     Vector<Panel> m_panels;
 };
 };