mirror of
https://github.com/RGBCube/serenity
synced 2025-05-25 22:35:07 +00:00
Maps: Add FavoritesModel and remove hacky misusage of JSONArrayModel
This commit is contained in:
parent
29026ce965
commit
bd86beb7e4
7 changed files with 224 additions and 74 deletions
|
@ -11,6 +11,7 @@ compile_gml(SearchPanel.gml SearchPanelGML.cpp)
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
main.cpp
|
main.cpp
|
||||||
FavoritesEditDialogGML.cpp
|
FavoritesEditDialogGML.cpp
|
||||||
|
FavoritesModel.cpp
|
||||||
FavoritesPanelGML.cpp
|
FavoritesPanelGML.cpp
|
||||||
FavoritesPanel.cpp
|
FavoritesPanel.cpp
|
||||||
MapWidget.cpp
|
MapWidget.cpp
|
||||||
|
|
121
Userland/Applications/Maps/FavoritesModel.cpp
Normal file
121
Userland/Applications/Maps/FavoritesModel.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FavoritesModel.h"
|
||||||
|
#include <AK/JsonArray.h>
|
||||||
|
#include <AK/JsonObject.h>
|
||||||
|
|
||||||
|
namespace Maps {
|
||||||
|
|
||||||
|
GUI::Variant FavoritesModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const
|
||||||
|
{
|
||||||
|
if (index.row() < 0 || index.row() >= row_count())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (role == GUI::ModelRole::TextAlignment)
|
||||||
|
return Gfx::TextAlignment::CenterLeft;
|
||||||
|
|
||||||
|
auto const& favorite = m_favorites.at(index.row());
|
||||||
|
if (role == GUI::ModelRole::Display)
|
||||||
|
return ByteString::formatted("{}\n{:.5}, {:.5}", favorite.name, favorite.latlng.latitude, favorite.latlng.longitude);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Favorite&> FavoritesModel::get_favorite(GUI::ModelIndex const& index)
|
||||||
|
{
|
||||||
|
if (index.row() < 0 || index.row() >= row_count())
|
||||||
|
return {};
|
||||||
|
return m_favorites.at(index.row());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FavoritesModel::add_favorite(Favorite favorite)
|
||||||
|
{
|
||||||
|
m_favorites.append(move(favorite));
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FavoritesModel::update_favorite(GUI::ModelIndex const& index, Favorite favorite)
|
||||||
|
{
|
||||||
|
if (index.row() < 0 || index.row() >= row_count())
|
||||||
|
return;
|
||||||
|
m_favorites[index.row()] = move(favorite);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FavoritesModel::delete_favorite(Favorite const& favorite)
|
||||||
|
{
|
||||||
|
m_favorites.remove_first_matching([&](auto& other) {
|
||||||
|
return other == favorite;
|
||||||
|
});
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> FavoritesModel::save_to_file(Core::File& file) const
|
||||||
|
{
|
||||||
|
JsonArray array {};
|
||||||
|
array.ensure_capacity(m_favorites.size());
|
||||||
|
|
||||||
|
for (auto const& favorite : m_favorites) {
|
||||||
|
JsonObject object;
|
||||||
|
object.set("name", favorite.name.to_byte_string());
|
||||||
|
object.set("latitude", favorite.latlng.latitude);
|
||||||
|
object.set("longitude", favorite.latlng.longitude);
|
||||||
|
object.set("zoom", favorite.zoom);
|
||||||
|
TRY(array.append(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto json_string = array.to_byte_string();
|
||||||
|
TRY(file.write_until_depleted(json_string.bytes()));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> FavoritesModel::load_from_file(Core::File& file)
|
||||||
|
{
|
||||||
|
auto json_bytes = TRY(file.read_until_eof());
|
||||||
|
StringView json_string { json_bytes };
|
||||||
|
auto json = TRY(JsonValue::from_string(json_string));
|
||||||
|
if (!json.is_array())
|
||||||
|
return Error::from_string_literal("Failed to read favorites from file: Not a JSON array.");
|
||||||
|
auto& json_array = json.as_array();
|
||||||
|
|
||||||
|
Vector<Favorite> new_favorites;
|
||||||
|
TRY(new_favorites.try_ensure_capacity(json_array.size()));
|
||||||
|
TRY(json_array.try_for_each([&](JsonValue const& json_value) -> ErrorOr<void> {
|
||||||
|
if (!json_value.is_object())
|
||||||
|
return {};
|
||||||
|
auto& json_object = json_value.as_object();
|
||||||
|
|
||||||
|
Favorite favorite;
|
||||||
|
|
||||||
|
auto name = json_object.get_byte_string("name"sv);
|
||||||
|
if (!name.has_value())
|
||||||
|
return {};
|
||||||
|
favorite.name = MUST(String::from_byte_string(*name));
|
||||||
|
|
||||||
|
auto latitude = json_object.get_double_with_precision_loss("latitude"sv);
|
||||||
|
if (!latitude.has_value())
|
||||||
|
return {};
|
||||||
|
auto longitude = json_object.get_double_with_precision_loss("longitude"sv);
|
||||||
|
if (!longitude.has_value())
|
||||||
|
return {};
|
||||||
|
favorite.latlng = { *latitude, *longitude };
|
||||||
|
|
||||||
|
auto zoom = json_object.get_i32("zoom"sv);
|
||||||
|
if (!zoom.has_value())
|
||||||
|
return {};
|
||||||
|
favorite.zoom = *zoom;
|
||||||
|
|
||||||
|
new_favorites.append(favorite);
|
||||||
|
return {};
|
||||||
|
}));
|
||||||
|
|
||||||
|
m_favorites = move(new_favorites);
|
||||||
|
invalidate();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
Userland/Applications/Maps/FavoritesModel.h
Normal file
53
Userland/Applications/Maps/FavoritesModel.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MapWidget.h"
|
||||||
|
#include <LibGUI/Model.h>
|
||||||
|
|
||||||
|
namespace Maps {
|
||||||
|
|
||||||
|
struct Favorite {
|
||||||
|
String name;
|
||||||
|
MapWidget::LatLng latlng;
|
||||||
|
int zoom;
|
||||||
|
|
||||||
|
bool operator==(Favorite const& other) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FavoritesModel final : public GUI::Model {
|
||||||
|
public:
|
||||||
|
static NonnullRefPtr<FavoritesModel> create()
|
||||||
|
{
|
||||||
|
return adopt_ref(*new FavoritesModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int row_count(GUI::ModelIndex const& index = GUI::ModelIndex()) const override
|
||||||
|
{
|
||||||
|
if (!index.is_valid())
|
||||||
|
return m_favorites.size();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int column_count(GUI::ModelIndex const&) const override { return 1; }
|
||||||
|
|
||||||
|
virtual GUI::Variant data(GUI::ModelIndex const& index, GUI::ModelRole role = GUI::ModelRole::Display) const override;
|
||||||
|
|
||||||
|
Vector<Favorite> const& favorites() const { return m_favorites; }
|
||||||
|
Optional<Favorite&> get_favorite(GUI::ModelIndex const&);
|
||||||
|
void add_favorite(Favorite);
|
||||||
|
void update_favorite(GUI::ModelIndex const&, Favorite);
|
||||||
|
void delete_favorite(Favorite const&);
|
||||||
|
|
||||||
|
ErrorOr<void> save_to_file(Core::File&) const;
|
||||||
|
ErrorOr<void> load_from_file(Core::File&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector<Favorite> m_favorites;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
#include "FavoritesEditDialog.h"
|
#include "FavoritesEditDialog.h"
|
||||||
#include <LibCore/StandardPaths.h>
|
#include <LibCore/StandardPaths.h>
|
||||||
#include <LibGUI/Button.h>
|
#include <LibGUI/Button.h>
|
||||||
|
#include <LibGUI/Dialog.h>
|
||||||
#include <LibGUI/JsonArrayModel.h>
|
#include <LibGUI/JsonArrayModel.h>
|
||||||
#include <LibGUI/Menu.h>
|
#include <LibGUI/Menu.h>
|
||||||
#include <LibGUI/TextBox.h>
|
#include <LibGUI/TextBox.h>
|
||||||
|
@ -20,31 +21,27 @@ ErrorOr<void> FavoritesPanel::initialize()
|
||||||
m_empty_container = *find_descendant_of_type_named<GUI::Frame>("empty_container");
|
m_empty_container = *find_descendant_of_type_named<GUI::Frame>("empty_container");
|
||||||
m_favorites_list = *find_descendant_of_type_named<GUI::ListView>("favorites_list");
|
m_favorites_list = *find_descendant_of_type_named<GUI::ListView>("favorites_list");
|
||||||
|
|
||||||
|
m_model = FavoritesModel::create();
|
||||||
|
m_favorites_list->set_model(m_model);
|
||||||
m_favorites_list->set_item_height(m_favorites_list->font().preferred_line_height() * 2 + m_favorites_list->vertical_padding());
|
m_favorites_list->set_item_height(m_favorites_list->font().preferred_line_height() * 2 + m_favorites_list->vertical_padding());
|
||||||
m_favorites_list->on_selection_change = [this]() {
|
m_favorites_list->on_selection_change = [this]() {
|
||||||
auto const& index = m_favorites_list->selection().first();
|
if (auto favorite = m_model->get_favorite(m_favorites_list->selection().first()); favorite.has_value())
|
||||||
if (!index.is_valid())
|
on_selected_favorite_change(*favorite);
|
||||||
return;
|
|
||||||
auto& model = *m_favorites_list->model();
|
|
||||||
on_selected_favorite_change({ MUST(String::from_byte_string(model.index(index.row(), 0).data().to_byte_string())),
|
|
||||||
{ model.index(index.row(), 1).data().as_double(),
|
|
||||||
model.index(index.row(), 2).data().as_double() },
|
|
||||||
model.index(index.row(), 3).data().to_i32() });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
m_favorites_list->on_context_menu_request = [this](auto const& index, auto const& event) {
|
m_favorites_list->on_context_menu_request = [this](auto const& index, auto const& event) {
|
||||||
m_context_menu = GUI::Menu::construct();
|
m_context_menu = GUI::Menu::construct();
|
||||||
m_context_menu->add_action(GUI::Action::create(
|
m_context_menu->add_action(GUI::Action::create(
|
||||||
"&Edit...", MUST(Gfx::Bitmap::load_from_file("/res/icons/16x16/rename.png"sv)), [this, index](auto&) {
|
"&Edit...", MUST(Gfx::Bitmap::load_from_file("/res/icons/16x16/rename.png"sv)), [this, index](auto&) {
|
||||||
MUST(edit_favorite(index.row()));
|
MUST(edit_favorite(index));
|
||||||
},
|
},
|
||||||
this));
|
this));
|
||||||
m_context_menu->add_action(GUI::CommonActions::make_delete_action(
|
m_context_menu->add_action(GUI::CommonActions::make_delete_action(
|
||||||
[this, index](auto&) {
|
[this, index](auto&) {
|
||||||
auto& model = *static_cast<GUI::JsonArrayModel*>(m_favorites_list->model());
|
if (auto favorite = m_model->get_favorite(index); favorite.has_value()) {
|
||||||
MUST(model.remove(index.row()));
|
m_model->delete_favorite(*favorite);
|
||||||
MUST(model.store());
|
favorites_changed();
|
||||||
favorites_changed();
|
}
|
||||||
},
|
},
|
||||||
this));
|
this));
|
||||||
m_context_menu->popup(event.screen_position());
|
m_context_menu->popup(event.screen_position());
|
||||||
|
@ -54,48 +51,36 @@ ErrorOr<void> FavoritesPanel::initialize()
|
||||||
|
|
||||||
void FavoritesPanel::load_favorites()
|
void FavoritesPanel::load_favorites()
|
||||||
{
|
{
|
||||||
Vector<GUI::JsonArrayModel::FieldSpec> favorites_fields;
|
if (auto maybe_file = Core::File::open(MUST(String::formatted("{}/MapsFavorites.json", Core::StandardPaths::config_directory())), Core::File::OpenMode::Read); !maybe_file.is_error()) {
|
||||||
favorites_fields.empend("name", "Name"_string, Gfx::TextAlignment::CenterLeft, [](JsonObject const& object) -> GUI::Variant {
|
auto file = maybe_file.release_value();
|
||||||
ByteString name = object.get_byte_string("name"sv).release_value();
|
(void)m_model->load_from_file(*file);
|
||||||
double latitude = object.get_double_with_precision_loss("latitude"sv).release_value();
|
}
|
||||||
double longitude = object.get_double_with_precision_loss("longitude"sv).release_value();
|
|
||||||
return ByteString::formatted("{}\n{:.5}, {:.5}", name, latitude, longitude);
|
|
||||||
});
|
|
||||||
favorites_fields.empend("latitude", "Latitude"_string, Gfx::TextAlignment::CenterLeft, [](JsonObject const& object) -> GUI::Variant {
|
|
||||||
return object.get_double_with_precision_loss("latitude"sv).release_value();
|
|
||||||
});
|
|
||||||
favorites_fields.empend("longitude", "Longitude"_string, Gfx::TextAlignment::CenterLeft, [](JsonObject const& object) -> GUI::Variant {
|
|
||||||
return object.get_double_with_precision_loss("longitude"sv).release_value();
|
|
||||||
});
|
|
||||||
favorites_fields.empend("zoom", "Zoom"_string, Gfx::TextAlignment::CenterLeft);
|
|
||||||
m_favorites_list->set_model(*GUI::JsonArrayModel::create(ByteString::formatted("{}/MapsFavorites.json", Core::StandardPaths::config_directory()), move(favorites_fields)));
|
|
||||||
m_favorites_list->model()->invalidate();
|
|
||||||
favorites_changed();
|
favorites_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> FavoritesPanel::add_favorite(Favorite const& favorite)
|
|
||||||
{
|
|
||||||
auto& model = *static_cast<GUI::JsonArrayModel*>(m_favorites_list->model());
|
|
||||||
Vector<JsonValue> favorite_json;
|
|
||||||
favorite_json.append(favorite.name.to_byte_string());
|
|
||||||
favorite_json.append(favorite.latlng.latitude);
|
|
||||||
favorite_json.append(favorite.latlng.longitude);
|
|
||||||
favorite_json.append(favorite.zoom);
|
|
||||||
TRY(model.add(move(favorite_json)));
|
|
||||||
TRY(model.store());
|
|
||||||
favorites_changed();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void FavoritesPanel::reset()
|
void FavoritesPanel::reset()
|
||||||
{
|
{
|
||||||
m_favorites_list->selection().clear();
|
m_favorites_list->selection().clear();
|
||||||
m_favorites_list->scroll_to_top();
|
m_favorites_list->scroll_to_top();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> FavoritesPanel::edit_favorite(int row)
|
void FavoritesPanel::add_favorite(Favorite favorite)
|
||||||
{
|
{
|
||||||
auto& model = *static_cast<GUI::JsonArrayModel*>(m_favorites_list->model());
|
m_model->add_favorite(move(favorite));
|
||||||
|
favorites_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FavoritesPanel::delete_favorite(Favorite const& favorite)
|
||||||
|
{
|
||||||
|
m_model->delete_favorite(favorite);
|
||||||
|
favorites_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> FavoritesPanel::edit_favorite(GUI::ModelIndex const& index)
|
||||||
|
{
|
||||||
|
auto favorite = m_model->get_favorite(index);
|
||||||
|
if (!favorite.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
auto edit_dialog = TRY(GUI::Dialog::try_create(window()));
|
auto edit_dialog = TRY(GUI::Dialog::try_create(window()));
|
||||||
edit_dialog->set_title("Edit Favorite");
|
edit_dialog->set_title("Edit Favorite");
|
||||||
|
@ -106,19 +91,14 @@ ErrorOr<void> FavoritesPanel::edit_favorite(int row)
|
||||||
edit_dialog->set_main_widget(widget);
|
edit_dialog->set_main_widget(widget);
|
||||||
|
|
||||||
auto& name_textbox = *widget->find_descendant_of_type_named<GUI::TextBox>("name_textbox");
|
auto& name_textbox = *widget->find_descendant_of_type_named<GUI::TextBox>("name_textbox");
|
||||||
name_textbox.set_text(model.index(row, 0).data().to_byte_string().split('\n').at(0));
|
name_textbox.set_text(favorite->name);
|
||||||
name_textbox.set_focus(true);
|
name_textbox.set_focus(true);
|
||||||
name_textbox.select_all();
|
name_textbox.select_all();
|
||||||
|
|
||||||
auto& ok_button = *widget->find_descendant_of_type_named<GUI::Button>("ok_button");
|
auto& ok_button = *widget->find_descendant_of_type_named<GUI::Button>("ok_button");
|
||||||
ok_button.on_click = [&](auto) {
|
ok_button.on_click = [&](auto) {
|
||||||
Vector<JsonValue> favorite_json;
|
favorite->name = MUST(String::from_byte_string(name_textbox.text()));
|
||||||
favorite_json.append(name_textbox.text());
|
m_model->update_favorite(index, *favorite);
|
||||||
favorite_json.append(model.index(row, 1).data().as_double());
|
|
||||||
favorite_json.append(model.index(row, 2).data().as_double());
|
|
||||||
favorite_json.append(model.index(row, 3).data().to_i32());
|
|
||||||
MUST(model.set(row, move(favorite_json)));
|
|
||||||
MUST(model.store());
|
|
||||||
favorites_changed();
|
favorites_changed();
|
||||||
edit_dialog->done(GUI::Dialog::ExecResult::OK);
|
edit_dialog->done(GUI::Dialog::ExecResult::OK);
|
||||||
};
|
};
|
||||||
|
@ -135,18 +115,16 @@ ErrorOr<void> FavoritesPanel::edit_favorite(int row)
|
||||||
|
|
||||||
void FavoritesPanel::favorites_changed()
|
void FavoritesPanel::favorites_changed()
|
||||||
{
|
{
|
||||||
auto& model = *static_cast<GUI::JsonArrayModel*>(m_favorites_list->model());
|
// Update UI
|
||||||
m_empty_container->set_visible(model.row_count() == 0);
|
m_empty_container->set_visible(m_model->row_count() == 0);
|
||||||
m_favorites_list->set_visible(model.row_count() > 0);
|
m_favorites_list->set_visible(m_model->row_count() > 0);
|
||||||
|
on_favorites_change(m_model->favorites());
|
||||||
|
|
||||||
Vector<Favorite> favorites;
|
// Save favorites
|
||||||
for (int index = 0; index < model.row_count(); index++) {
|
if (auto maybe_file = Core::File::open(MUST(String::formatted("{}/MapsFavorites.json", Core::StandardPaths::config_directory())), Core::File::OpenMode::Write); !maybe_file.is_error()) {
|
||||||
favorites.append({ MUST(String::from_byte_string(model.index(index, 0).data().to_byte_string())),
|
auto file = maybe_file.release_value();
|
||||||
{ model.index(index, 1).data().as_double(),
|
MUST(m_model->save_to_file(*file));
|
||||||
model.index(index, 2).data().as_double() },
|
|
||||||
model.index(index, 3).data().to_i32() });
|
|
||||||
}
|
}
|
||||||
on_favorites_change(favorites);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "MapWidget.h"
|
#include "FavoritesModel.h"
|
||||||
#include <LibGUI/Dialog.h>
|
|
||||||
#include <LibGUI/ItemListModel.h>
|
|
||||||
#include <LibGUI/ListView.h>
|
#include <LibGUI/ListView.h>
|
||||||
|
|
||||||
namespace Maps {
|
namespace Maps {
|
||||||
|
@ -17,17 +15,13 @@ class FavoritesPanel final : public GUI::Widget {
|
||||||
C_OBJECT(FavoritesPanel)
|
C_OBJECT(FavoritesPanel)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Favorite {
|
|
||||||
String name;
|
|
||||||
MapWidget::LatLng latlng;
|
|
||||||
int zoom;
|
|
||||||
};
|
|
||||||
static ErrorOr<NonnullRefPtr<FavoritesPanel>> try_create();
|
static ErrorOr<NonnullRefPtr<FavoritesPanel>> try_create();
|
||||||
ErrorOr<void> initialize();
|
ErrorOr<void> initialize();
|
||||||
|
|
||||||
void load_favorites();
|
void load_favorites();
|
||||||
void reset();
|
void reset();
|
||||||
ErrorOr<void> add_favorite(Favorite const& favorite);
|
void add_favorite(Favorite favorite);
|
||||||
|
void delete_favorite(Favorite const& favorite);
|
||||||
|
|
||||||
Function<void(Vector<Favorite> const&)> on_favorites_change;
|
Function<void(Vector<Favorite> const&)> on_favorites_change;
|
||||||
Function<void(Favorite const&)> on_selected_favorite_change;
|
Function<void(Favorite const&)> on_selected_favorite_change;
|
||||||
|
@ -36,11 +30,12 @@ protected:
|
||||||
FavoritesPanel() = default;
|
FavoritesPanel() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorOr<void> edit_favorite(int row);
|
ErrorOr<void> edit_favorite(GUI::ModelIndex const& index);
|
||||||
void favorites_changed();
|
void favorites_changed();
|
||||||
|
|
||||||
RefPtr<GUI::Frame> m_empty_container;
|
RefPtr<GUI::Frame> m_empty_container;
|
||||||
RefPtr<GUI::ListView> m_favorites_list;
|
RefPtr<GUI::ListView> m_favorites_list;
|
||||||
|
RefPtr<FavoritesModel> m_model;
|
||||||
RefPtr<GUI::Menu> m_context_menu;
|
RefPtr<GUI::Menu> m_context_menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ public:
|
||||||
double latitude;
|
double latitude;
|
||||||
double longitude;
|
double longitude;
|
||||||
|
|
||||||
|
bool operator==(LatLng const& other) const = default;
|
||||||
|
|
||||||
double distance_to(LatLng const& other) const;
|
double distance_to(LatLng const& other) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
auto favorites_icon = TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-hearts.png"sv));
|
auto favorites_icon = TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-hearts.png"sv));
|
||||||
map_widget.add_context_menu_action(GUI::Action::create(
|
map_widget.add_context_menu_action(GUI::Action::create(
|
||||||
"Add to &Favorites", favorites_icon, [favorites_panel, &map_widget](auto&) {
|
"Add to &Favorites", favorites_icon, [favorites_panel, &map_widget](auto&) {
|
||||||
MUST(favorites_panel->add_favorite({ "Unnamed place"_string, map_widget.context_menu_latlng(), map_widget.zoom() }));
|
favorites_panel->add_favorite({ "Unnamed place"_string, map_widget.context_menu_latlng(), map_widget.zoom() });
|
||||||
},
|
},
|
||||||
window));
|
window));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue