Merge pull request #321 from AdenKoperczak/location_markers_part2
Location Markers Part 2
|
|
@ -10,4 +10,6 @@ Checks:
|
||||||
- '-misc-include-cleaner'
|
- '-misc-include-cleaner'
|
||||||
- '-misc-non-private-member-variables-in-classes'
|
- '-misc-non-private-member-variables-in-classes'
|
||||||
- '-modernize-use-trailing-return-type'
|
- '-modernize-use-trailing-return-type'
|
||||||
|
- '-bugprone-easily-swappable-parameters'
|
||||||
|
- '-modernize-return-braced-init-list'
|
||||||
FormatStyle: 'file'
|
FormatStyle: 'file'
|
||||||
|
|
|
||||||
1
scwx-qt/res/icons/font-awesome-6/briefcase-solid.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M184 48l144 0c4.4 0 8 3.6 8 8l0 40L176 96l0-40c0-4.4 3.6-8 8-8zm-56 8l0 40L64 96C28.7 96 0 124.7 0 160l0 96 192 0 128 0 192 0 0-96c0-35.3-28.7-64-64-64l-64 0 0-40c0-30.9-25.1-56-56-56L184 0c-30.9 0-56 25.1-56 56zM512 288l-192 0 0 32c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32l0-32L0 288 0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-128z"/></svg>
|
||||||
|
After Width: | Height: | Size: 623 B |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M243.4 2.6l-224 96c-14 6-21.8 21-18.7 35.8S16.8 160 32 160l0 8c0 13.3 10.7 24 24 24l400 0c13.3 0 24-10.7 24-24l0-8c15.2 0 28.3-10.7 31.3-25.6s-4.8-29.9-18.7-35.8l-224-96c-8-3.4-17.2-3.4-25.2 0zM128 224l-64 0 0 196.3c-.6 .3-1.2 .7-1.8 1.1l-48 32c-11.7 7.8-17 22.4-12.9 35.9S17.9 512 32 512l448 0c14.1 0 26.5-9.2 30.6-22.7s-1.1-28.1-12.9-35.9l-48-32c-.6-.4-1.2-.7-1.8-1.1L448 224l-64 0 0 192-40 0 0-192-64 0 0 192-48 0 0-192-64 0 0 192-40 0 0-192zM256 64a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>
|
||||||
|
After Width: | Height: | Size: 757 B |
1
scwx-qt/res/icons/font-awesome-6/building-solid.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 384 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M48 0C21.5 0 0 21.5 0 48L0 464c0 26.5 21.5 48 48 48l96 0 0-80c0-26.5 21.5-48 48-48s48 21.5 48 48l0 80 96 0c26.5 0 48-21.5 48-48l0-416c0-26.5-21.5-48-48-48L48 0zM64 240c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32zm112-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32c0-8.8 7.2-16 16-16zm80 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32zM80 96l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32c0-8.8 7.2-16 16-16zm80 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32zM272 96l32 0c8.8 0 16 7.2 16 16l0 32c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-32c0-8.8 7.2-16 16-16z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1 KiB |
1
scwx-qt/res/icons/font-awesome-6/caravan-solid.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 640 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M0 112C0 67.8 35.8 32 80 32l336 0c88.4 0 160 71.6 160 160l0 160 32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-32 0-288 0c0 53-43 96-96 96s-96-43-96-96l-16 0c-44.2 0-80-35.8-80-80L0 112zM320 352l128 0 0-96-32 0c-8.8 0-16-7.2-16-16s7.2-16 16-16l32 0 0-64c0-17.7-14.3-32-32-32l-64 0c-17.7 0-32 14.3-32 32l0 192zM96 128c-17.7 0-32 14.3-32 32l0 64c0 17.7 14.3 32 32 32l128 0c17.7 0 32-14.3 32-32l0-64c0-17.7-14.3-32-32-32L96 128zm96 336a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>
|
||||||
|
After Width: | Height: | Size: 732 B |
1
scwx-qt/res/icons/font-awesome-6/house-solid-white.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path opacity="1" fill="#ffffff" d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z"/></svg>
|
||||||
|
After Width: | Height: | Size: 735 B |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M256 0c17.7 0 32 14.3 32 32l0 34.7C368.4 80.1 431.9 143.6 445.3 224l34.7 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-34.7 0C431.9 368.4 368.4 431.9 288 445.3l0 34.7c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-34.7C143.6 431.9 80.1 368.4 66.7 288L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l34.7 0C80.1 143.6 143.6 80.1 224 66.7L224 32c0-17.7 14.3-32 32-32zM128 256a128 128 0 1 0 256 0 128 128 0 1 0 -256 0zm128-80a80 80 0 1 1 0 160 80 80 0 1 1 0-160z"/></svg>
|
||||||
|
After Width: | Height: | Size: 708 B |
4
scwx-qt/res/icons/font-awesome-6/location-pin.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 384 512">
|
||||||
|
<!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
|
||||||
|
<path fill="#ffffff" d="M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 463 B |
1
scwx-qt/res/icons/font-awesome-6/star-solid-white.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path opacity="1" fill="#ffffff" d="M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"/></svg>
|
||||||
|
After Width: | Height: | Size: 616 B |
1
scwx-qt/res/icons/font-awesome-6/tent-solid.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="16" viewBox="0 0 576 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffffff" d="M269.4 6C280.5-2 295.5-2 306.6 6l224 160c7.4 5.3 12.2 13.5 13.2 22.5l32 288c1 9-1.9 18.1-8 24.9s-14.7 10.7-23.8 10.7l-80 0-28.2 0c-12.1 0-23.2-6.8-28.6-17.7L306.7 293.5c-1.7-3.4-5.1-5.5-8.8-5.5c-5.5 0-9.9 4.4-9.9 9.9L288 480c0 17.7-14.3 32-32 32l-16 0L32 512c-9.1 0-17.8-3.9-23.8-10.7s-9-15.8-8-24.9l32-288c1-9 5.8-17.2 13.2-22.5L269.4 6z"/></svg>
|
||||||
|
After Width: | Height: | Size: 608 B |
|
|
@ -6,6 +6,6 @@
|
||||||
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
|
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
|
||||||
stroke="black" stroke-width="40" fill="none"/>
|
stroke="black" stroke-width="40" fill="none"/>
|
||||||
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
|
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
|
||||||
stroke="red" stroke-width="20" fill="none"/>
|
stroke="#ffffff" stroke-width="20" fill="none"/>
|
||||||
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 357 B |
|
|
@ -222,8 +222,8 @@ set(HDR_TYPES source/scwx/qt/types/alert_types.hpp
|
||||||
source/scwx/qt/types/layer_types.hpp
|
source/scwx/qt/types/layer_types.hpp
|
||||||
source/scwx/qt/types/location_types.hpp
|
source/scwx/qt/types/location_types.hpp
|
||||||
source/scwx/qt/types/map_types.hpp
|
source/scwx/qt/types/map_types.hpp
|
||||||
source/scwx/qt/types/media_types.hpp
|
|
||||||
source/scwx/qt/types/marker_types.hpp
|
source/scwx/qt/types/marker_types.hpp
|
||||||
|
source/scwx/qt/types/media_types.hpp
|
||||||
source/scwx/qt/types/qt_types.hpp
|
source/scwx/qt/types/qt_types.hpp
|
||||||
source/scwx/qt/types/radar_product_record.hpp
|
source/scwx/qt/types/radar_product_record.hpp
|
||||||
source/scwx/qt/types/text_event_key.hpp
|
source/scwx/qt/types/text_event_key.hpp
|
||||||
|
|
@ -255,6 +255,7 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
|
||||||
source/scwx/qt/ui/county_dialog.hpp
|
source/scwx/qt/ui/county_dialog.hpp
|
||||||
source/scwx/qt/ui/download_dialog.hpp
|
source/scwx/qt/ui/download_dialog.hpp
|
||||||
source/scwx/qt/ui/edit_line_dialog.hpp
|
source/scwx/qt/ui/edit_line_dialog.hpp
|
||||||
|
source/scwx/qt/ui/edit_marker_dialog.hpp
|
||||||
source/scwx/qt/ui/flow_layout.hpp
|
source/scwx/qt/ui/flow_layout.hpp
|
||||||
source/scwx/qt/ui/gps_info_dialog.hpp
|
source/scwx/qt/ui/gps_info_dialog.hpp
|
||||||
source/scwx/qt/ui/hotkey_edit.hpp
|
source/scwx/qt/ui/hotkey_edit.hpp
|
||||||
|
|
@ -285,6 +286,7 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
|
||||||
source/scwx/qt/ui/county_dialog.cpp
|
source/scwx/qt/ui/county_dialog.cpp
|
||||||
source/scwx/qt/ui/download_dialog.cpp
|
source/scwx/qt/ui/download_dialog.cpp
|
||||||
source/scwx/qt/ui/edit_line_dialog.cpp
|
source/scwx/qt/ui/edit_line_dialog.cpp
|
||||||
|
source/scwx/qt/ui/edit_marker_dialog.cpp
|
||||||
source/scwx/qt/ui/flow_layout.cpp
|
source/scwx/qt/ui/flow_layout.cpp
|
||||||
source/scwx/qt/ui/gps_info_dialog.cpp
|
source/scwx/qt/ui/gps_info_dialog.cpp
|
||||||
source/scwx/qt/ui/hotkey_edit.cpp
|
source/scwx/qt/ui/hotkey_edit.cpp
|
||||||
|
|
@ -314,6 +316,7 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui
|
||||||
source/scwx/qt/ui/collapsible_group.ui
|
source/scwx/qt/ui/collapsible_group.ui
|
||||||
source/scwx/qt/ui/county_dialog.ui
|
source/scwx/qt/ui/county_dialog.ui
|
||||||
source/scwx/qt/ui/edit_line_dialog.ui
|
source/scwx/qt/ui/edit_line_dialog.ui
|
||||||
|
source/scwx/qt/ui/edit_marker_dialog.ui
|
||||||
source/scwx/qt/ui/gps_info_dialog.ui
|
source/scwx/qt/ui/gps_info_dialog.ui
|
||||||
source/scwx/qt/ui/imgui_debug_dialog.ui
|
source/scwx/qt/ui/imgui_debug_dialog.ui
|
||||||
source/scwx/qt/ui/layer_dialog.ui
|
source/scwx/qt/ui/layer_dialog.ui
|
||||||
|
|
@ -357,6 +360,7 @@ set(HDR_UTIL source/scwx/qt/util/color.hpp
|
||||||
source/scwx/qt/util/network.hpp
|
source/scwx/qt/util/network.hpp
|
||||||
source/scwx/qt/util/streams.hpp
|
source/scwx/qt/util/streams.hpp
|
||||||
source/scwx/qt/util/texture_atlas.hpp
|
source/scwx/qt/util/texture_atlas.hpp
|
||||||
|
source/scwx/qt/util/q_color_modulate.hpp
|
||||||
source/scwx/qt/util/q_file_buffer.hpp
|
source/scwx/qt/util/q_file_buffer.hpp
|
||||||
source/scwx/qt/util/q_file_input_stream.hpp
|
source/scwx/qt/util/q_file_input_stream.hpp
|
||||||
source/scwx/qt/util/time.hpp
|
source/scwx/qt/util/time.hpp
|
||||||
|
|
@ -369,6 +373,7 @@ set(SRC_UTIL source/scwx/qt/util/color.cpp
|
||||||
source/scwx/qt/util/maplibre.cpp
|
source/scwx/qt/util/maplibre.cpp
|
||||||
source/scwx/qt/util/network.cpp
|
source/scwx/qt/util/network.cpp
|
||||||
source/scwx/qt/util/texture_atlas.cpp
|
source/scwx/qt/util/texture_atlas.cpp
|
||||||
|
source/scwx/qt/util/q_color_modulate.cpp
|
||||||
source/scwx/qt/util/q_file_buffer.cpp
|
source/scwx/qt/util/q_file_buffer.cpp
|
||||||
source/scwx/qt/util/q_file_input_stream.cpp
|
source/scwx/qt/util/q_file_input_stream.cpp
|
||||||
source/scwx/qt/util/time.cpp
|
source/scwx/qt/util/time.cpp
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,10 @@
|
||||||
<file>res/icons/font-awesome-6/angles-up-solid.svg</file>
|
<file>res/icons/font-awesome-6/angles-up-solid.svg</file>
|
||||||
<file>res/icons/font-awesome-6/backward-step-solid.svg</file>
|
<file>res/icons/font-awesome-6/backward-step-solid.svg</file>
|
||||||
<file>res/icons/font-awesome-6/book-solid.svg</file>
|
<file>res/icons/font-awesome-6/book-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/briefcase-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/building-columns-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/building-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/caravan-solid.svg</file>
|
||||||
<file>res/icons/font-awesome-6/copy-regular.svg</file>
|
<file>res/icons/font-awesome-6/copy-regular.svg</file>
|
||||||
<file>res/icons/font-awesome-6/discord.svg</file>
|
<file>res/icons/font-awesome-6/discord.svg</file>
|
||||||
<file>res/icons/font-awesome-6/earth-americas-solid.svg</file>
|
<file>res/icons/font-awesome-6/earth-americas-solid.svg</file>
|
||||||
|
|
@ -40,8 +44,11 @@
|
||||||
<file>res/icons/font-awesome-6/gears-solid.svg</file>
|
<file>res/icons/font-awesome-6/gears-solid.svg</file>
|
||||||
<file>res/icons/font-awesome-6/github.svg</file>
|
<file>res/icons/font-awesome-6/github.svg</file>
|
||||||
<file>res/icons/font-awesome-6/house-solid.svg</file>
|
<file>res/icons/font-awesome-6/house-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/house-solid-white.svg</file>
|
||||||
<file>res/icons/font-awesome-6/keyboard-regular.svg</file>
|
<file>res/icons/font-awesome-6/keyboard-regular.svg</file>
|
||||||
<file>res/icons/font-awesome-6/layer-group-solid.svg</file>
|
<file>res/icons/font-awesome-6/layer-group-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/location-crosshairs-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/location-pin.svg</file>
|
||||||
<file>res/icons/font-awesome-6/palette-solid.svg</file>
|
<file>res/icons/font-awesome-6/palette-solid.svg</file>
|
||||||
<file>res/icons/font-awesome-6/pause-solid.svg</file>
|
<file>res/icons/font-awesome-6/pause-solid.svg</file>
|
||||||
<file>res/icons/font-awesome-6/play-solid.svg</file>
|
<file>res/icons/font-awesome-6/play-solid.svg</file>
|
||||||
|
|
@ -53,7 +60,9 @@
|
||||||
<file>res/icons/font-awesome-6/square-minus-regular.svg</file>
|
<file>res/icons/font-awesome-6/square-minus-regular.svg</file>
|
||||||
<file>res/icons/font-awesome-6/square-plus-regular.svg</file>
|
<file>res/icons/font-awesome-6/square-plus-regular.svg</file>
|
||||||
<file>res/icons/font-awesome-6/star-solid.svg</file>
|
<file>res/icons/font-awesome-6/star-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/star-solid-white.svg</file>
|
||||||
<file>res/icons/font-awesome-6/stop-solid.svg</file>
|
<file>res/icons/font-awesome-6/stop-solid.svg</file>
|
||||||
|
<file>res/icons/font-awesome-6/tent-solid.svg</file>
|
||||||
<file>res/icons/font-awesome-6/volume-high-solid.svg</file>
|
<file>res/icons/font-awesome-6/volume-high-solid.svg</file>
|
||||||
<file>res/palettes/wct/CC.pal</file>
|
<file>res/palettes/wct/CC.pal</file>
|
||||||
<file>res/palettes/wct/Default16.pal</file>
|
<file>res/palettes/wct/Default16.pal</file>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ static constexpr std::size_t kIntegersPerVertex_ = 4;
|
||||||
static constexpr std::size_t kIntegerBufferLength_ =
|
static constexpr std::size_t kIntegerBufferLength_ =
|
||||||
kNumTriangles * kVerticesPerTriangle * kIntegersPerVertex_;
|
kNumTriangles * kVerticesPerTriangle * kIntegersPerVertex_;
|
||||||
|
|
||||||
struct GeoIconDrawItem
|
struct GeoIconDrawItem : types::EventHandler
|
||||||
{
|
{
|
||||||
units::length::nautical_miles<double> threshold_ {};
|
units::length::nautical_miles<double> threshold_ {};
|
||||||
std::chrono::sys_time<std::chrono::seconds> startTime_ {};
|
std::chrono::sys_time<std::chrono::seconds> startTime_ {};
|
||||||
|
|
@ -691,7 +691,7 @@ void GeoIcons::Impl::UpdateSingleBuffer(
|
||||||
hoverIcons.end(),
|
hoverIcons.end(),
|
||||||
[&di](auto& entry) { return entry.di_ == di; });
|
[&di](auto& entry) { return entry.di_ == di; });
|
||||||
|
|
||||||
if (di->visible_ && !di->hoverText_.empty())
|
if (di->visible_ && (!di->hoverText_.empty() || di->event_ != nullptr))
|
||||||
{
|
{
|
||||||
const units::angle::radians<double> radians = angle;
|
const units::angle::radians<double> radians = angle;
|
||||||
|
|
||||||
|
|
@ -903,7 +903,7 @@ bool GeoIcons::RunMousePicking(
|
||||||
const QPointF& mouseGlobalPos,
|
const QPointF& mouseGlobalPos,
|
||||||
const glm::vec2& mouseCoords,
|
const glm::vec2& mouseCoords,
|
||||||
const common::Coordinate& /* mouseGeoCoords */,
|
const common::Coordinate& /* mouseGeoCoords */,
|
||||||
std::shared_ptr<types::EventHandler>& /* eventHandler */)
|
std::shared_ptr<types::EventHandler>& eventHandler)
|
||||||
{
|
{
|
||||||
std::unique_lock lock {p->iconMutex_};
|
std::unique_lock lock {p->iconMutex_};
|
||||||
|
|
||||||
|
|
@ -993,12 +993,27 @@ bool GeoIcons::RunMousePicking(
|
||||||
if (it != p->currentHoverIcons_.crend())
|
if (it != p->currentHoverIcons_.crend())
|
||||||
{
|
{
|
||||||
itemPicked = true;
|
itemPicked = true;
|
||||||
util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos);
|
if (!it->di_->hoverText_.empty())
|
||||||
|
{
|
||||||
|
// Show tooltip
|
||||||
|
util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos);
|
||||||
|
}
|
||||||
|
if (it->di_->event_ != nullptr)
|
||||||
|
{
|
||||||
|
eventHandler = it->di_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return itemPicked;
|
return itemPicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeoIcons::RegisterEventHandler(
|
||||||
|
const std::shared_ptr<GeoIconDrawItem>& di,
|
||||||
|
const std::function<void(QEvent*)>& eventHandler)
|
||||||
|
{
|
||||||
|
di->event_ = eventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace draw
|
} // namespace draw
|
||||||
} // namespace gl
|
} // namespace gl
|
||||||
} // namespace qt
|
} // namespace qt
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void FinishIcons();
|
void FinishIcons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event handler for an icon.
|
||||||
|
*
|
||||||
|
* @param [in] di Icon draw item
|
||||||
|
* @param [in] eventHandler Event handler function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
RegisterEventHandler(const std::shared_ptr<GeoIconDrawItem>& di,
|
||||||
|
const std::function<void(QEvent*)>& eventHandler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Impl;
|
class Impl;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
#include <scwx/qt/manager/marker_manager.hpp>
|
#include <scwx/qt/manager/marker_manager.hpp>
|
||||||
#include <scwx/qt/types/marker_types.hpp>
|
#include <scwx/qt/types/marker_types.hpp>
|
||||||
|
#include <scwx/qt/util/color.hpp>
|
||||||
#include <scwx/qt/util/json.hpp>
|
#include <scwx/qt/util/json.hpp>
|
||||||
|
#include <scwx/qt/util/texture_atlas.hpp>
|
||||||
#include <scwx/qt/main/application.hpp>
|
#include <scwx/qt/main/application.hpp>
|
||||||
|
#include <scwx/qt/manager/resource_manager.hpp>
|
||||||
#include <scwx/util/logger.hpp>
|
#include <scwx/util/logger.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <boost/json.hpp>
|
#include <boost/json.hpp>
|
||||||
|
|
@ -27,6 +31,10 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
static const std::string kNameName_ = "name";
|
static const std::string kNameName_ = "name";
|
||||||
static const std::string kLatitudeName_ = "latitude";
|
static const std::string kLatitudeName_ = "latitude";
|
||||||
static const std::string kLongitudeName_ = "longitude";
|
static const std::string kLongitudeName_ = "longitude";
|
||||||
|
static const std::string kIconName_ = "icon";
|
||||||
|
static const std::string kIconColorName_ = "icon-color";
|
||||||
|
|
||||||
|
static const std::string defaultIconName = "images/location-marker";
|
||||||
|
|
||||||
class MarkerManager::Impl
|
class MarkerManager::Impl
|
||||||
{
|
{
|
||||||
|
|
@ -36,15 +44,16 @@ public:
|
||||||
explicit Impl(MarkerManager* self) : self_ {self} {}
|
explicit Impl(MarkerManager* self) : self_ {self} {}
|
||||||
~Impl() { threadPool_.join(); }
|
~Impl() { threadPool_.join(); }
|
||||||
|
|
||||||
std::string markerSettingsPath_ {""};
|
std::string markerSettingsPath_ {""};
|
||||||
std::vector<std::shared_ptr<MarkerRecord>> markerRecords_ {};
|
std::vector<std::shared_ptr<MarkerRecord>> markerRecords_ {};
|
||||||
std::unordered_map<types::MarkerId, size_t> idToIndex_ {};
|
std::unordered_map<types::MarkerId, size_t> idToIndex_ {};
|
||||||
|
std::unordered_map<std::string, types::MarkerIconInfo> markerIcons_ {};
|
||||||
|
|
||||||
MarkerManager* self_;
|
MarkerManager* self_;
|
||||||
|
|
||||||
boost::asio::thread_pool threadPool_ {1u};
|
boost::asio::thread_pool threadPool_ {1u};
|
||||||
std::shared_mutex markerRecordLock_ {};
|
std::shared_mutex markerRecordLock_ {};
|
||||||
|
std::shared_mutex markerIconsLock_ {};
|
||||||
|
|
||||||
void InitializeMarkerSettings();
|
void InitializeMarkerSettings();
|
||||||
void ReadMarkerSettings();
|
void ReadMarkerSettings();
|
||||||
|
|
@ -53,16 +62,12 @@ public:
|
||||||
|
|
||||||
void InitalizeIds();
|
void InitalizeIds();
|
||||||
types::MarkerId NewId();
|
types::MarkerId NewId();
|
||||||
types::MarkerId lastId_;
|
types::MarkerId lastId_ {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
class MarkerManager::Impl::MarkerRecord
|
class MarkerManager::Impl::MarkerRecord
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MarkerRecord(const std::string& name, double latitude, double longitude) :
|
|
||||||
markerInfo_ {types::MarkerInfo(name, latitude, longitude)}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
MarkerRecord(const types::MarkerInfo& info) :
|
MarkerRecord(const types::MarkerInfo& info) :
|
||||||
markerInfo_ {info}
|
markerInfo_ {info}
|
||||||
{
|
{
|
||||||
|
|
@ -81,16 +86,50 @@ public:
|
||||||
{
|
{
|
||||||
jv = {{kNameName_, record->markerInfo_.name},
|
jv = {{kNameName_, record->markerInfo_.name},
|
||||||
{kLatitudeName_, record->markerInfo_.latitude},
|
{kLatitudeName_, record->markerInfo_.latitude},
|
||||||
{kLongitudeName_, record->markerInfo_.longitude}};
|
{kLongitudeName_, record->markerInfo_.longitude},
|
||||||
|
{kIconName_, record->markerInfo_.iconName},
|
||||||
|
{kIconColorName_,
|
||||||
|
util::color::ToArgbString(record->markerInfo_.iconColor)}};
|
||||||
}
|
}
|
||||||
|
|
||||||
friend MarkerRecord tag_invoke(boost::json::value_to_tag<MarkerRecord>,
|
friend MarkerRecord tag_invoke(boost::json::value_to_tag<MarkerRecord>,
|
||||||
const boost::json::value& jv)
|
const boost::json::value& jv)
|
||||||
{
|
{
|
||||||
return MarkerRecord(
|
static const boost::gil::rgba8_pixel_t defaultIconColor =
|
||||||
|
util::color::ToRgba8PixelT("#ffff0000");
|
||||||
|
|
||||||
|
const boost::json::object& jo = jv.as_object();
|
||||||
|
|
||||||
|
std::string iconName = defaultIconName;
|
||||||
|
boost::gil::rgba8_pixel_t iconColor = defaultIconColor;
|
||||||
|
|
||||||
|
if (jo.contains(kIconName_) && jo.at(kIconName_).is_string())
|
||||||
|
{
|
||||||
|
iconName = boost::json::value_to<std::string>(jv.at(kIconName_));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jo.contains(kIconColorName_) && jo.at(kIconName_).is_string())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
iconColor = util::color::ToRgba8PixelT(
|
||||||
|
boost::json::value_to<std::string>(jv.at(kIconColorName_)));
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
logger_->warn(
|
||||||
|
"Could not parse color value in location-markers.json with the "
|
||||||
|
"following exception: {}",
|
||||||
|
ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {types::MarkerInfo(
|
||||||
boost::json::value_to<std::string>(jv.at(kNameName_)),
|
boost::json::value_to<std::string>(jv.at(kNameName_)),
|
||||||
boost::json::value_to<double>(jv.at(kLatitudeName_)),
|
boost::json::value_to<double>(jv.at(kLatitudeName_)),
|
||||||
boost::json::value_to<double>(jv.at(kLongitudeName_)));
|
boost::json::value_to<double>(jv.at(kLongitudeName_)),
|
||||||
|
iconName,
|
||||||
|
iconColor)};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -129,7 +168,7 @@ void MarkerManager::Impl::ReadMarkerSettings()
|
||||||
|
|
||||||
boost::json::value markerJson = nullptr;
|
boost::json::value markerJson = nullptr;
|
||||||
{
|
{
|
||||||
std::unique_lock lock(markerRecordLock_);
|
const std::unique_lock lock(markerRecordLock_);
|
||||||
|
|
||||||
// Determine if marker settings exists
|
// Determine if marker settings exists
|
||||||
if (std::filesystem::exists(markerSettingsPath_))
|
if (std::filesystem::exists(markerSettingsPath_))
|
||||||
|
|
@ -147,18 +186,16 @@ void MarkerManager::Impl::ReadMarkerSettings()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MarkerRecord record =
|
auto record = boost::json::value_to<MarkerRecord>(markerEntry);
|
||||||
boost::json::value_to<MarkerRecord>(markerEntry);
|
|
||||||
|
|
||||||
if (!record.markerInfo_.name.empty())
|
const types::MarkerId id = NewId();
|
||||||
{
|
const size_t index = markerRecords_.size();
|
||||||
types::MarkerId id = NewId();
|
record.markerInfo_.id = id;
|
||||||
size_t index = markerRecords_.size();
|
markerRecords_.emplace_back(
|
||||||
record.markerInfo_.id = id;
|
std::make_shared<MarkerRecord>(record.markerInfo_));
|
||||||
markerRecords_.emplace_back(
|
idToIndex_.emplace(id, index);
|
||||||
std::make_shared<MarkerRecord>(record.markerInfo_));
|
|
||||||
idToIndex_.emplace(id, index);
|
self_->add_icon(record.markerInfo_.iconName, true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
|
|
@ -166,6 +203,8 @@ void MarkerManager::Impl::ReadMarkerSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResourceManager::BuildAtlas();
|
||||||
|
|
||||||
logger_->debug("{} location marker entries", markerRecords_.size());
|
logger_->debug("{} location marker entries", markerRecords_.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +216,7 @@ void MarkerManager::Impl::WriteMarkerSettings()
|
||||||
{
|
{
|
||||||
logger_->info("Saving location marker settings");
|
logger_->info("Saving location marker settings");
|
||||||
|
|
||||||
std::shared_lock lock(markerRecordLock_);
|
const std::shared_lock lock(markerRecordLock_);
|
||||||
auto markerJson = boost::json::value_from(markerRecords_);
|
auto markerJson = boost::json::value_from(markerRecords_);
|
||||||
util::json::WriteJsonFile(markerSettingsPath_, markerJson);
|
util::json::WriteJsonFile(markerSettingsPath_, markerJson);
|
||||||
}
|
}
|
||||||
|
|
@ -198,6 +237,20 @@ MarkerManager::Impl::GetMarkerByName(const std::string& name)
|
||||||
|
|
||||||
MarkerManager::MarkerManager() : p(std::make_unique<Impl>(this))
|
MarkerManager::MarkerManager() : p(std::make_unique<Impl>(this))
|
||||||
{
|
{
|
||||||
|
static const std::vector<types::MarkerIconInfo> defaultMarkerIcons_ {
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationMarker, -1, -1),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationPin, 6, 16),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationCrosshair, -1, -1),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationStar, -1, -1),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationBriefcase, -1, -1),
|
||||||
|
types::MarkerIconInfo(
|
||||||
|
types::ImageTexture::LocationBuildingColumns, -1, -1),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationBuilding, -1, -1),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationCaravan, -1, -1),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationHouse, -1, -1),
|
||||||
|
types::MarkerIconInfo(types::ImageTexture::LocationTent, -1, -1),
|
||||||
|
};
|
||||||
|
|
||||||
p->InitializeMarkerSettings();
|
p->InitializeMarkerSettings();
|
||||||
|
|
||||||
boost::asio::post(p->threadPool_,
|
boost::asio::post(p->threadPool_,
|
||||||
|
|
@ -207,8 +260,18 @@ MarkerManager::MarkerManager() : p(std::make_unique<Impl>(this))
|
||||||
{
|
{
|
||||||
// Read Marker settings on startup
|
// Read Marker settings on startup
|
||||||
main::Application::WaitForInitialization();
|
main::Application::WaitForInitialization();
|
||||||
|
{
|
||||||
|
const std::unique_lock lock(p->markerIconsLock_);
|
||||||
|
p->markerIcons_.reserve(
|
||||||
|
defaultMarkerIcons_.size());
|
||||||
|
for (auto& icon : defaultMarkerIcons_)
|
||||||
|
{
|
||||||
|
p->markerIcons_.emplace(icon.name, icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
p->ReadMarkerSettings();
|
p->ReadMarkerSettings();
|
||||||
|
|
||||||
|
Q_EMIT IconsReady();
|
||||||
Q_EMIT MarkersInitialized(p->markerRecords_.size());
|
Q_EMIT MarkersInitialized(p->markerRecords_.size());
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
|
|
@ -230,7 +293,7 @@ size_t MarkerManager::marker_count()
|
||||||
|
|
||||||
std::optional<types::MarkerInfo> MarkerManager::get_marker(types::MarkerId id)
|
std::optional<types::MarkerInfo> MarkerManager::get_marker(types::MarkerId id)
|
||||||
{
|
{
|
||||||
std::shared_lock lock(p->markerRecordLock_);
|
const std::shared_lock lock(p->markerRecordLock_);
|
||||||
if (!p->idToIndex_.contains(id))
|
if (!p->idToIndex_.contains(id))
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -248,7 +311,7 @@ std::optional<types::MarkerInfo> MarkerManager::get_marker(types::MarkerId id)
|
||||||
|
|
||||||
std::optional<size_t> MarkerManager::get_index(types::MarkerId id)
|
std::optional<size_t> MarkerManager::get_index(types::MarkerId id)
|
||||||
{
|
{
|
||||||
std::shared_lock lock(p->markerRecordLock_);
|
const std::shared_lock lock(p->markerRecordLock_);
|
||||||
if (!p->idToIndex_.contains(id))
|
if (!p->idToIndex_.contains(id))
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -256,10 +319,11 @@ std::optional<size_t> MarkerManager::get_index(types::MarkerId id)
|
||||||
return p->idToIndex_[id];
|
return p->idToIndex_[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkerManager::set_marker(types::MarkerId id, const types::MarkerInfo& marker)
|
void MarkerManager::set_marker(types::MarkerId id,
|
||||||
|
const types::MarkerInfo& marker)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::unique_lock lock(p->markerRecordLock_);
|
const std::unique_lock lock(p->markerRecordLock_);
|
||||||
if (!p->idToIndex_.contains(id))
|
if (!p->idToIndex_.contains(id))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -270,33 +334,39 @@ void MarkerManager::set_marker(types::MarkerId id, const types::MarkerInfo& mark
|
||||||
logger_->warn("id in idToIndex_ but out of range!");
|
logger_->warn("id in idToIndex_ but out of range!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::shared_ptr<MarkerManager::Impl::MarkerRecord>& markerRecord =
|
const std::shared_ptr<MarkerManager::Impl::MarkerRecord>& markerRecord =
|
||||||
p->markerRecords_[index];
|
p->markerRecords_[index];
|
||||||
markerRecord->markerInfo_ = marker;
|
markerRecord->markerInfo_ = marker;
|
||||||
|
markerRecord->markerInfo_.id = id;
|
||||||
|
|
||||||
|
add_icon(marker.iconName);
|
||||||
}
|
}
|
||||||
Q_EMIT MarkerChanged(id);
|
Q_EMIT MarkerChanged(id);
|
||||||
Q_EMIT MarkersUpdated();
|
Q_EMIT MarkersUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkerManager::add_marker(const types::MarkerInfo& marker)
|
types::MarkerId MarkerManager::add_marker(const types::MarkerInfo& marker)
|
||||||
{
|
{
|
||||||
types::MarkerId id;
|
types::MarkerId id;
|
||||||
{
|
{
|
||||||
std::unique_lock lock(p->markerRecordLock_);
|
const std::unique_lock lock(p->markerRecordLock_);
|
||||||
id = p->NewId();
|
id = p->NewId();
|
||||||
size_t index = p->markerRecords_.size();
|
size_t index = p->markerRecords_.size();
|
||||||
p->idToIndex_.emplace(id, index);
|
p->idToIndex_.emplace(id, index);
|
||||||
p->markerRecords_.emplace_back(std::make_shared<Impl::MarkerRecord>(marker));
|
p->markerRecords_.emplace_back(std::make_shared<Impl::MarkerRecord>(marker));
|
||||||
p->markerRecords_[index]->markerInfo_.id = id;
|
p->markerRecords_[index]->markerInfo_.id = id;
|
||||||
|
|
||||||
|
add_icon(marker.iconName);
|
||||||
}
|
}
|
||||||
Q_EMIT MarkerAdded(id);
|
Q_EMIT MarkerAdded(id);
|
||||||
Q_EMIT MarkersUpdated();
|
Q_EMIT MarkersUpdated();
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkerManager::remove_marker(types::MarkerId id)
|
void MarkerManager::remove_marker(types::MarkerId id)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::unique_lock lock(p->markerRecordLock_);
|
const std::unique_lock lock(p->markerRecordLock_);
|
||||||
if (!p->idToIndex_.contains(id))
|
if (!p->idToIndex_.contains(id))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -327,7 +397,7 @@ void MarkerManager::remove_marker(types::MarkerId id)
|
||||||
void MarkerManager::move_marker(size_t from, size_t to)
|
void MarkerManager::move_marker(size_t from, size_t to)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::unique_lock lock(p->markerRecordLock_);
|
const std::unique_lock lock(p->markerRecordLock_);
|
||||||
if (from >= p->markerRecords_.size() || to >= p->markerRecords_.size())
|
if (from >= p->markerRecords_.size() || to >= p->markerRecords_.size())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -358,13 +428,64 @@ void MarkerManager::move_marker(size_t from, size_t to)
|
||||||
|
|
||||||
void MarkerManager::for_each(std::function<MarkerForEachFunc> func)
|
void MarkerManager::for_each(std::function<MarkerForEachFunc> func)
|
||||||
{
|
{
|
||||||
std::shared_lock lock(p->markerRecordLock_);
|
const std::shared_lock lock(p->markerRecordLock_);
|
||||||
for (auto marker : p->markerRecords_)
|
for (auto marker : p->markerRecords_)
|
||||||
{
|
{
|
||||||
func(marker->markerInfo_);
|
func(marker->markerInfo_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkerManager::add_icon(const std::string& name, bool startup)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const std::unique_lock lock(p->markerIconsLock_);
|
||||||
|
if (p->markerIcons_.contains(name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const std::shared_ptr<boost::gil::rgba8_image_t> image =
|
||||||
|
ResourceManager::LoadImageResource(name);
|
||||||
|
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
auto icon = types::MarkerIconInfo(name, -1, -1, image);
|
||||||
|
p->markerIcons_.emplace(name, icon);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// defaultIconName should always be in markerIcons, so at is fine
|
||||||
|
auto icon = p->markerIcons_.at(defaultIconName);
|
||||||
|
p->markerIcons_.emplace(name, icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!startup)
|
||||||
|
{
|
||||||
|
ResourceManager::BuildAtlas();
|
||||||
|
Q_EMIT IconAdded(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<types::MarkerIconInfo>
|
||||||
|
MarkerManager::get_icon(const std::string& name)
|
||||||
|
{
|
||||||
|
const std::shared_lock lock(p->markerIconsLock_);
|
||||||
|
auto it = p->markerIcons_.find(name);
|
||||||
|
if (it != p->markerIcons_.end())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, types::MarkerIconInfo>
|
||||||
|
MarkerManager::get_icons()
|
||||||
|
{
|
||||||
|
const std::shared_lock lock(p->markerIconsLock_);
|
||||||
|
return p->markerIcons_;
|
||||||
|
}
|
||||||
|
|
||||||
// Only use for testing
|
// Only use for testing
|
||||||
void MarkerManager::set_marker_settings_path(const std::string& path)
|
void MarkerManager::set_marker_settings_path(const std::string& path)
|
||||||
{
|
{
|
||||||
|
|
@ -377,7 +498,7 @@ std::shared_ptr<MarkerManager> MarkerManager::Instance()
|
||||||
static std::weak_ptr<MarkerManager> markerManagerReference_ {};
|
static std::weak_ptr<MarkerManager> markerManagerReference_ {};
|
||||||
static std::mutex instanceMutex_ {};
|
static std::mutex instanceMutex_ {};
|
||||||
|
|
||||||
std::unique_lock lock(instanceMutex_);
|
const std::unique_lock lock(instanceMutex_);
|
||||||
|
|
||||||
std::shared_ptr<MarkerManager> markerManager =
|
std::shared_ptr<MarkerManager> markerManager =
|
||||||
markerManagerReference_.lock();
|
markerManagerReference_.lock();
|
||||||
|
|
@ -391,6 +512,11 @@ std::shared_ptr<MarkerManager> MarkerManager::Instance()
|
||||||
return markerManager;
|
return markerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& MarkerManager::getDefaultIconName()
|
||||||
|
{
|
||||||
|
return defaultIconName;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace manager
|
} // namespace manager
|
||||||
} // namespace qt
|
} // namespace qt
|
||||||
} // namespace scwx
|
} // namespace scwx
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,15 @@ public:
|
||||||
|
|
||||||
size_t marker_count();
|
size_t marker_count();
|
||||||
std::optional<types::MarkerInfo> get_marker(types::MarkerId id);
|
std::optional<types::MarkerInfo> get_marker(types::MarkerId id);
|
||||||
std::optional<size_t> get_index(types::MarkerId id);
|
std::optional<size_t> get_index(types::MarkerId id);
|
||||||
void set_marker(types::MarkerId id, const types::MarkerInfo& marker);
|
void set_marker(types::MarkerId id, const types::MarkerInfo& marker);
|
||||||
void add_marker(const types::MarkerInfo& marker);
|
types::MarkerId add_marker(const types::MarkerInfo& marker);
|
||||||
void remove_marker(types::MarkerId id);
|
void remove_marker(types::MarkerId id);
|
||||||
void move_marker(size_t from, size_t to);
|
void move_marker(size_t from, size_t to);
|
||||||
|
|
||||||
|
void add_icon(const std::string& name, bool startup = false);
|
||||||
|
std::optional<types::MarkerIconInfo> get_icon(const std::string& name);
|
||||||
|
const std::unordered_map<std::string, types::MarkerIconInfo> get_icons();
|
||||||
|
|
||||||
void for_each(std::function<MarkerForEachFunc> func);
|
void for_each(std::function<MarkerForEachFunc> func);
|
||||||
|
|
||||||
|
|
@ -35,6 +39,7 @@ public:
|
||||||
void set_marker_settings_path(const std::string& path);
|
void set_marker_settings_path(const std::string& path);
|
||||||
|
|
||||||
static std::shared_ptr<MarkerManager> Instance();
|
static std::shared_ptr<MarkerManager> Instance();
|
||||||
|
static const std::string& getDefaultIconName();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void MarkersInitialized(size_t count);
|
void MarkersInitialized(size_t count);
|
||||||
|
|
@ -43,6 +48,9 @@ signals:
|
||||||
void MarkerAdded(types::MarkerId id);
|
void MarkerAdded(types::MarkerId id);
|
||||||
void MarkerRemoved(types::MarkerId id);
|
void MarkerRemoved(types::MarkerId id);
|
||||||
|
|
||||||
|
void IconsReady();
|
||||||
|
void IconAdded(std::string name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Impl;
|
class Impl;
|
||||||
std::unique_ptr<Impl> p;
|
std::unique_ptr<Impl> p;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ namespace ResourceManager
|
||||||
static const std::string logPrefix_ = "scwx::qt::manager::resource_manager";
|
static const std::string logPrefix_ = "scwx::qt::manager::resource_manager";
|
||||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
|
|
||||||
|
static const size_t atlasWidth = 2048;
|
||||||
|
static const size_t atlasHeight = 2048;
|
||||||
|
|
||||||
static void LoadFonts();
|
static void LoadFonts();
|
||||||
static void LoadTextures();
|
static void LoadTextures();
|
||||||
|
|
||||||
|
|
@ -68,8 +71,7 @@ LoadImageResources(const std::vector<std::string>& urlStrings)
|
||||||
|
|
||||||
if (!images.empty())
|
if (!images.empty())
|
||||||
{
|
{
|
||||||
util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance();
|
BuildAtlas();
|
||||||
textureAtlas.BuildAtlas(2048, 2048);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return images;
|
return images;
|
||||||
|
|
@ -103,7 +105,13 @@ static void LoadTextures()
|
||||||
GetTexturePath(lineTexture));
|
GetTexturePath(lineTexture));
|
||||||
}
|
}
|
||||||
|
|
||||||
textureAtlas.BuildAtlas(2048, 2048);
|
BuildAtlas();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildAtlas()
|
||||||
|
{
|
||||||
|
util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance();
|
||||||
|
textureAtlas.BuildAtlas(atlasWidth, atlasHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ResourceManager
|
} // namespace ResourceManager
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ std::shared_ptr<boost::gil::rgba8_image_t>
|
||||||
LoadImageResource(const std::string& urlString);
|
LoadImageResource(const std::string& urlString);
|
||||||
std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
|
std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
|
||||||
LoadImageResources(const std::vector<std::string>& urlStrings);
|
LoadImageResources(const std::vector<std::string>& urlStrings);
|
||||||
|
void BuildAtlas();
|
||||||
|
|
||||||
} // namespace ResourceManager
|
} // namespace ResourceManager
|
||||||
} // namespace manager
|
} // namespace manager
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@
|
||||||
#include <scwx/qt/map/layer_wrapper.hpp>
|
#include <scwx/qt/map/layer_wrapper.hpp>
|
||||||
#include <scwx/qt/map/map_provider.hpp>
|
#include <scwx/qt/map/map_provider.hpp>
|
||||||
#include <scwx/qt/map/map_settings.hpp>
|
#include <scwx/qt/map/map_settings.hpp>
|
||||||
|
#include <scwx/qt/map/marker_layer.hpp>
|
||||||
#include <scwx/qt/map/overlay_layer.hpp>
|
#include <scwx/qt/map/overlay_layer.hpp>
|
||||||
#include <scwx/qt/map/overlay_product_layer.hpp>
|
#include <scwx/qt/map/overlay_product_layer.hpp>
|
||||||
#include <scwx/qt/map/placefile_layer.hpp>
|
#include <scwx/qt/map/placefile_layer.hpp>
|
||||||
#include <scwx/qt/map/marker_layer.hpp>
|
|
||||||
#include <scwx/qt/map/radar_product_layer.hpp>
|
#include <scwx/qt/map/radar_product_layer.hpp>
|
||||||
#include <scwx/qt/map/radar_range_layer.hpp>
|
#include <scwx/qt/map/radar_range_layer.hpp>
|
||||||
#include <scwx/qt/map/radar_site_layer.hpp>
|
#include <scwx/qt/map/radar_site_layer.hpp>
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <scwx/qt/settings/general_settings.hpp>
|
#include <scwx/qt/settings/general_settings.hpp>
|
||||||
#include <scwx/qt/settings/map_settings.hpp>
|
#include <scwx/qt/settings/map_settings.hpp>
|
||||||
#include <scwx/qt/settings/palette_settings.hpp>
|
#include <scwx/qt/settings/palette_settings.hpp>
|
||||||
|
#include <scwx/qt/ui/edit_marker_dialog.hpp>
|
||||||
#include <scwx/qt/util/file.hpp>
|
#include <scwx/qt/util/file.hpp>
|
||||||
#include <scwx/qt/util/maplibre.hpp>
|
#include <scwx/qt/util/maplibre.hpp>
|
||||||
#include <scwx/qt/util/tooltip.hpp>
|
#include <scwx/qt/util/tooltip.hpp>
|
||||||
|
|
@ -127,8 +128,6 @@ public:
|
||||||
ImGui_ImplQt_Init();
|
ImGui_ImplQt_Init();
|
||||||
|
|
||||||
InitializeCustomStyles();
|
InitializeCustomStyles();
|
||||||
|
|
||||||
ConnectSignals();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~MapWidgetImpl()
|
~MapWidgetImpl()
|
||||||
|
|
@ -219,6 +218,8 @@ public:
|
||||||
std::shared_ptr<model::LayerModel> layerModel_ {
|
std::shared_ptr<model::LayerModel> layerModel_ {
|
||||||
model::LayerModel::Instance()};
|
model::LayerModel::Instance()};
|
||||||
|
|
||||||
|
ui::EditMarkerDialog* editMarkerDialog_ {nullptr};
|
||||||
|
|
||||||
std::shared_ptr<manager::HotkeyManager> hotkeyManager_ {
|
std::shared_ptr<manager::HotkeyManager> hotkeyManager_ {
|
||||||
manager::HotkeyManager::Instance()};
|
manager::HotkeyManager::Instance()};
|
||||||
std::shared_ptr<manager::PlacefileManager> placefileManager_ {
|
std::shared_ptr<manager::PlacefileManager> placefileManager_ {
|
||||||
|
|
@ -283,6 +284,12 @@ MapWidget::MapWidget(std::size_t id, const QMapLibre::Settings& settings) :
|
||||||
setFocusPolicy(Qt::StrongFocus);
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
|
||||||
ImGui_ImplQt_RegisterWidget(this);
|
ImGui_ImplQt_RegisterWidget(this);
|
||||||
|
|
||||||
|
// Qt parent deals with memory management
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
|
||||||
|
p->editMarkerDialog_ = new ui::EditMarkerDialog(this);
|
||||||
|
|
||||||
|
p->ConnectSignals();
|
||||||
}
|
}
|
||||||
|
|
||||||
MapWidget::~MapWidget()
|
MapWidget::~MapWidget()
|
||||||
|
|
@ -429,6 +436,16 @@ void MapWidgetImpl::HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat)
|
||||||
|
|
||||||
switch (hotkey)
|
switch (hotkey)
|
||||||
{
|
{
|
||||||
|
case types::Hotkey::AddLocationMarker:
|
||||||
|
if (hasMouse_)
|
||||||
|
{
|
||||||
|
auto coordinate = map_->coordinateForPixel(lastPos_);
|
||||||
|
|
||||||
|
editMarkerDialog_->setup(coordinate.first, coordinate.second);
|
||||||
|
editMarkerDialog_->show();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case types::Hotkey::ChangeMapStyle:
|
case types::Hotkey::ChangeMapStyle:
|
||||||
if (context_->settings().isActive_)
|
if (context_->settings().isActive_)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
#include <scwx/qt/map/marker_layer.hpp>
|
#include <scwx/qt/map/marker_layer.hpp>
|
||||||
#include <scwx/qt/manager/marker_manager.hpp>
|
#include <scwx/qt/manager/marker_manager.hpp>
|
||||||
#include <scwx/util/logger.hpp>
|
#include <scwx/util/logger.hpp>
|
||||||
#include <scwx/qt/types/marker_types.hpp>
|
|
||||||
#include <scwx/qt/types/texture_types.hpp>
|
|
||||||
#include <scwx/qt/gl/draw/geo_icons.hpp>
|
#include <scwx/qt/gl/draw/geo_icons.hpp>
|
||||||
|
#include <scwx/qt/types/marker_types.hpp>
|
||||||
|
#include <scwx/qt/ui/edit_marker_dialog.hpp>
|
||||||
|
|
||||||
|
#include <QGeoPositionInfo>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace scwx
|
namespace scwx
|
||||||
{
|
{
|
||||||
|
|
@ -19,48 +24,104 @@ class MarkerLayer::Impl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Impl(MarkerLayer* self, std::shared_ptr<MapContext> context) :
|
explicit Impl(MarkerLayer* self, std::shared_ptr<MapContext> context) :
|
||||||
self_ {self}, geoIcons_ {std::make_shared<gl::draw::GeoIcons>(context)}
|
self_ {self},
|
||||||
|
geoIcons_ {std::make_shared<gl::draw::GeoIcons>(context)},
|
||||||
|
editMarkerDialog_ {std::make_shared<ui::EditMarkerDialog>()}
|
||||||
{
|
{
|
||||||
ConnectSignals();
|
ConnectSignals();
|
||||||
}
|
}
|
||||||
~Impl() {}
|
~Impl() = default;
|
||||||
|
|
||||||
void ReloadMarkers();
|
void ReloadMarkers();
|
||||||
void ConnectSignals();
|
void ConnectSignals();
|
||||||
|
|
||||||
|
std::shared_ptr<manager::MarkerManager> markerManager_ {
|
||||||
|
manager::MarkerManager::Instance()};
|
||||||
|
|
||||||
|
void set_icon_sheets();
|
||||||
|
|
||||||
MarkerLayer* self_;
|
MarkerLayer* self_;
|
||||||
const std::string& markerIconName_ {
|
|
||||||
types::GetTextureName(types::ImageTexture::LocationMarker)};
|
|
||||||
|
|
||||||
std::shared_ptr<gl::draw::GeoIcons> geoIcons_;
|
std::shared_ptr<gl::draw::GeoIcons> geoIcons_;
|
||||||
|
std::shared_ptr<ui::EditMarkerDialog> editMarkerDialog_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void MarkerLayer::Impl::ConnectSignals()
|
void MarkerLayer::Impl::ConnectSignals()
|
||||||
{
|
{
|
||||||
auto markerManager = manager::MarkerManager::Instance();
|
QObject::connect(markerManager_.get(),
|
||||||
|
&manager::MarkerManager::MarkersUpdated,
|
||||||
QObject::connect(markerManager.get(),
|
self_,
|
||||||
&manager::MarkerManager::MarkersUpdated,
|
[this]() { ReloadMarkers(); });
|
||||||
self_,
|
QObject::connect(markerManager_.get(),
|
||||||
[this]()
|
&manager::MarkerManager::IconsReady,
|
||||||
{
|
self_,
|
||||||
this->ReloadMarkers();
|
[this]() { set_icon_sheets(); });
|
||||||
});
|
QObject::connect(markerManager_.get(),
|
||||||
|
&manager::MarkerManager::IconAdded,
|
||||||
|
self_,
|
||||||
|
[this]() { set_icon_sheets(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkerLayer::Impl::ReloadMarkers()
|
void MarkerLayer::Impl::ReloadMarkers()
|
||||||
{
|
{
|
||||||
logger_->debug("ReloadMarkers()");
|
logger_->debug("ReloadMarkers()");
|
||||||
auto markerManager = manager::MarkerManager::Instance();
|
|
||||||
|
|
||||||
geoIcons_->StartIcons();
|
geoIcons_->StartIcons();
|
||||||
|
markerManager_->for_each(
|
||||||
markerManager->for_each(
|
|
||||||
[this](const types::MarkerInfo& marker)
|
[this](const types::MarkerInfo& marker)
|
||||||
{
|
{
|
||||||
std::shared_ptr<gl::draw::GeoIconDrawItem> icon = geoIcons_->AddIcon();
|
// must use local ID, instead of reference to marker in event handler
|
||||||
geoIcons_->SetIconTexture(icon, markerIconName_, 0);
|
// callback.
|
||||||
|
const types::MarkerId id = marker.id;
|
||||||
|
|
||||||
|
const std::shared_ptr<gl::draw::GeoIconDrawItem> icon =
|
||||||
|
geoIcons_->AddIcon();
|
||||||
|
|
||||||
|
const std::string latitudeString =
|
||||||
|
common::GetLatitudeString(marker.latitude);
|
||||||
|
const std::string longitudeString =
|
||||||
|
common::GetLongitudeString(marker.longitude);
|
||||||
|
|
||||||
|
const std::string hoverText =
|
||||||
|
marker.name != "" ?
|
||||||
|
fmt::format(
|
||||||
|
"{}\n{}, {}", marker.name, latitudeString, longitudeString) :
|
||||||
|
fmt::format("{}, {}", latitudeString, longitudeString);
|
||||||
|
|
||||||
|
auto iconInfo = markerManager_->get_icon(marker.iconName);
|
||||||
|
if (iconInfo)
|
||||||
|
{
|
||||||
|
geoIcons_->SetIconTexture(icon, iconInfo->name, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
geoIcons_->SetIconTexture(icon, marker.iconName, 0);
|
||||||
|
}
|
||||||
|
|
||||||
geoIcons_->SetIconLocation(icon, marker.latitude, marker.longitude);
|
geoIcons_->SetIconLocation(icon, marker.latitude, marker.longitude);
|
||||||
|
geoIcons_->SetIconHoverText(icon, hoverText);
|
||||||
|
geoIcons_->SetIconModulate(icon, marker.iconColor);
|
||||||
|
geoIcons_->RegisterEventHandler(
|
||||||
|
icon,
|
||||||
|
[this, id](QEvent* ev)
|
||||||
|
{
|
||||||
|
switch (ev->type())
|
||||||
|
{
|
||||||
|
case QEvent::Type::MouseButtonPress:
|
||||||
|
{
|
||||||
|
auto* mouseEvent = reinterpret_cast<QMouseEvent*>(ev);
|
||||||
|
if (mouseEvent->buttons() == Qt::MouseButton::RightButton)
|
||||||
|
{
|
||||||
|
editMarkerDialog_->setup(id);
|
||||||
|
editMarkerDialog_->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
geoIcons_->FinishIcons();
|
geoIcons_->FinishIcons();
|
||||||
|
|
@ -80,17 +141,28 @@ void MarkerLayer::Initialize()
|
||||||
logger_->debug("Initialize()");
|
logger_->debug("Initialize()");
|
||||||
DrawLayer::Initialize();
|
DrawLayer::Initialize();
|
||||||
|
|
||||||
p->geoIcons_->StartIconSheets();
|
p->set_icon_sheets();
|
||||||
p->geoIcons_->AddIconSheet(p->markerIconName_);
|
|
||||||
p->geoIcons_->FinishIconSheets();
|
|
||||||
|
|
||||||
p->ReloadMarkers();
|
p->ReloadMarkers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkerLayer::Impl::set_icon_sheets()
|
||||||
|
{
|
||||||
|
geoIcons_->StartIconSheets();
|
||||||
|
for (auto& markerIcon : markerManager_->get_icons())
|
||||||
|
{
|
||||||
|
geoIcons_->AddIconSheet(markerIcon.second.name,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
markerIcon.second.hotX,
|
||||||
|
markerIcon.second.hotY);
|
||||||
|
}
|
||||||
|
geoIcons_->FinishIconSheets();
|
||||||
|
}
|
||||||
|
|
||||||
void MarkerLayer::Render(const QMapLibre::CustomLayerRenderParameters& params)
|
void MarkerLayer::Render(const QMapLibre::CustomLayerRenderParameters& params)
|
||||||
{
|
{
|
||||||
// auto markerManager = manager::MarkerManager::Instance();
|
|
||||||
gl::OpenGLFunctions& gl = context()->gl();
|
gl::OpenGLFunctions& gl = context()->gl();
|
||||||
|
context()->set_render_parameters(params);
|
||||||
|
|
||||||
DrawLayer::Render(params);
|
DrawLayer::Render(params);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <scwx/qt/manager/marker_manager.hpp>
|
#include <scwx/qt/manager/marker_manager.hpp>
|
||||||
#include <scwx/qt/types/marker_types.hpp>
|
#include <scwx/qt/types/marker_types.hpp>
|
||||||
#include <scwx/qt/types/qt_types.hpp>
|
#include <scwx/qt/types/qt_types.hpp>
|
||||||
|
#include <scwx/qt/util/q_color_modulate.hpp>
|
||||||
#include <scwx/util/logger.hpp>
|
#include <scwx/util/logger.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -18,6 +19,7 @@ namespace model
|
||||||
|
|
||||||
static const std::string logPrefix_ = "scwx::qt::model::marker_model";
|
static const std::string logPrefix_ = "scwx::qt::model::marker_model";
|
||||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
|
static const int iconSize_ = 30;
|
||||||
|
|
||||||
static constexpr int kFirstColumn =
|
static constexpr int kFirstColumn =
|
||||||
static_cast<int>(MarkerModel::Column::Latitude);
|
static_cast<int>(MarkerModel::Column::Latitude);
|
||||||
|
|
@ -38,7 +40,6 @@ public:
|
||||||
MarkerModel::MarkerModel(QObject* parent) :
|
MarkerModel::MarkerModel(QObject* parent) :
|
||||||
QAbstractTableModel(parent), p(std::make_unique<Impl>())
|
QAbstractTableModel(parent), p(std::make_unique<Impl>())
|
||||||
{
|
{
|
||||||
|
|
||||||
connect(p->markerManager_.get(),
|
connect(p->markerManager_.get(),
|
||||||
&manager::MarkerManager::MarkersInitialized,
|
&manager::MarkerManager::MarkersInitialized,
|
||||||
this,
|
this,
|
||||||
|
|
@ -78,26 +79,11 @@ Qt::ItemFlags MarkerModel::flags(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
||||||
|
|
||||||
switch (index.column())
|
|
||||||
{
|
|
||||||
case static_cast<int>(Column::Name):
|
|
||||||
case static_cast<int>(Column::Latitude):
|
|
||||||
case static_cast<int>(Column::Longitude):
|
|
||||||
flags |= Qt::ItemFlag::ItemIsEditable;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant MarkerModel::data(const QModelIndex& index, int role) const
|
QVariant MarkerModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
|
|
||||||
static const char COORDINATE_FORMAT = 'g';
|
|
||||||
static const int COORDINATE_PRECISION = 10;
|
|
||||||
|
|
||||||
if (!index.isValid() || index.row() < 0 ||
|
if (!index.isValid() || index.row() < 0 ||
|
||||||
static_cast<size_t>(index.row()) >= p->markerIds_.size())
|
static_cast<size_t>(index.row()) >= p->markerIds_.size())
|
||||||
{
|
{
|
||||||
|
|
@ -118,8 +104,7 @@ QVariant MarkerModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
case static_cast<int>(Column::Name):
|
case static_cast<int>(Column::Name):
|
||||||
if (role == Qt::ItemDataRole::DisplayRole ||
|
if (role == Qt::ItemDataRole::DisplayRole ||
|
||||||
role == Qt::ItemDataRole::ToolTipRole ||
|
role == Qt::ItemDataRole::ToolTipRole)
|
||||||
role == Qt::ItemDataRole::EditRole)
|
|
||||||
{
|
{
|
||||||
return QString::fromStdString(markerInfo->name);
|
return QString::fromStdString(markerInfo->name);
|
||||||
}
|
}
|
||||||
|
|
@ -132,11 +117,6 @@ QVariant MarkerModel::data(const QModelIndex& index, int role) const
|
||||||
return QString::fromStdString(
|
return QString::fromStdString(
|
||||||
common::GetLatitudeString(markerInfo->latitude));
|
common::GetLatitudeString(markerInfo->latitude));
|
||||||
}
|
}
|
||||||
else if (role == Qt::ItemDataRole::EditRole)
|
|
||||||
{
|
|
||||||
return QString::number(
|
|
||||||
markerInfo->latitude, COORDINATE_FORMAT, COORDINATE_PRECISION);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case static_cast<int>(Column::Longitude):
|
case static_cast<int>(Column::Longitude):
|
||||||
|
|
@ -146,13 +126,41 @@ QVariant MarkerModel::data(const QModelIndex& index, int role) const
|
||||||
return QString::fromStdString(
|
return QString::fromStdString(
|
||||||
common::GetLongitudeString(markerInfo->longitude));
|
common::GetLongitudeString(markerInfo->longitude));
|
||||||
}
|
}
|
||||||
else if (role == Qt::ItemDataRole::EditRole)
|
|
||||||
{
|
|
||||||
return QString::number(
|
|
||||||
markerInfo->longitude, COORDINATE_FORMAT, COORDINATE_PRECISION);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
break;
|
break;
|
||||||
|
case static_cast<int>(Column::Icon):
|
||||||
|
if (role == Qt::ItemDataRole::DisplayRole)
|
||||||
|
{
|
||||||
|
std::optional<types::MarkerIconInfo> icon =
|
||||||
|
p->markerManager_->get_icon(markerInfo->iconName);
|
||||||
|
if (icon)
|
||||||
|
{
|
||||||
|
return QString::fromStdString(icon->shortName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (role == Qt::ItemDataRole::DecorationRole)
|
||||||
|
{
|
||||||
|
std::optional<types::MarkerIconInfo> icon =
|
||||||
|
p->markerManager_->get_icon(markerInfo->iconName);
|
||||||
|
if (icon)
|
||||||
|
{
|
||||||
|
return util::modulateColors(icon->qIcon,
|
||||||
|
QSize(iconSize_, iconSize_),
|
||||||
|
QColor(markerInfo->iconColor[0],
|
||||||
|
markerInfo->iconColor[1],
|
||||||
|
markerInfo->iconColor[2],
|
||||||
|
markerInfo->iconColor[3]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -190,6 +198,9 @@ QVariant MarkerModel::headerData(int section,
|
||||||
case static_cast<int>(Column::Longitude):
|
case static_cast<int>(Column::Longitude):
|
||||||
return tr("Longitude");
|
return tr("Longitude");
|
||||||
|
|
||||||
|
case static_cast<int>(Column::Icon):
|
||||||
|
return tr("Icon");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -199,78 +210,9 @@ QVariant MarkerModel::headerData(int section,
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MarkerModel::setData(const QModelIndex& index,
|
bool MarkerModel::setData(const QModelIndex&, const QVariant&, int)
|
||||||
const QVariant& value,
|
|
||||||
int role)
|
|
||||||
{
|
{
|
||||||
|
return false;
|
||||||
if (!index.isValid() || index.row() < 0 ||
|
|
||||||
static_cast<size_t>(index.row()) >= p->markerIds_.size())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::MarkerId id = p->markerIds_[index.row()];
|
|
||||||
std::optional<types::MarkerInfo> markerInfo =
|
|
||||||
p->markerManager_->get_marker(id);
|
|
||||||
if (!markerInfo)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
switch(index.column())
|
|
||||||
{
|
|
||||||
case static_cast<int>(Column::Name):
|
|
||||||
if (role == Qt::ItemDataRole::EditRole)
|
|
||||||
{
|
|
||||||
QString str = value.toString();
|
|
||||||
markerInfo->name = str.toStdString();
|
|
||||||
p->markerManager_->set_marker(id, *markerInfo);
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case static_cast<int>(Column::Latitude):
|
|
||||||
if (role == Qt::ItemDataRole::EditRole)
|
|
||||||
{
|
|
||||||
QString str = value.toString();
|
|
||||||
bool ok;
|
|
||||||
double latitude = str.toDouble(&ok);
|
|
||||||
if (!str.isEmpty() && ok && -90 <= latitude && latitude <= 90)
|
|
||||||
{
|
|
||||||
markerInfo->latitude = latitude;
|
|
||||||
p->markerManager_->set_marker(id, *markerInfo);
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case static_cast<int>(Column::Longitude):
|
|
||||||
if (role == Qt::ItemDataRole::EditRole)
|
|
||||||
{
|
|
||||||
QString str = value.toString();
|
|
||||||
bool ok;
|
|
||||||
double longitude = str.toDouble(&ok);
|
|
||||||
if (!str.isEmpty() && ok && -180 <= longitude && longitude <= 180)
|
|
||||||
{
|
|
||||||
markerInfo->longitude = longitude;
|
|
||||||
p->markerManager_->set_marker(id, *markerInfo);
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
Q_EMIT dataChanged(index, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkerModel::HandleMarkersInitialized(size_t count)
|
void MarkerModel::HandleMarkersInitialized(size_t count)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ public:
|
||||||
{
|
{
|
||||||
Latitude = 0,
|
Latitude = 0,
|
||||||
Longitude = 1,
|
Longitude = 1,
|
||||||
Name = 2,
|
Icon = 2,
|
||||||
|
Name = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit MarkerModel(QObject* parent = nullptr);
|
explicit MarkerModel(QObject* parent = nullptr);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ namespace settings
|
||||||
static const std::string logPrefix_ = "scwx::qt::settings::hotkey_settings";
|
static const std::string logPrefix_ = "scwx::qt::settings::hotkey_settings";
|
||||||
|
|
||||||
static const std::unordered_map<types::Hotkey, QKeySequence> kDefaultHotkeys_ {
|
static const std::unordered_map<types::Hotkey, QKeySequence> kDefaultHotkeys_ {
|
||||||
|
{types::Hotkey::AddLocationMarker, QKeySequence {Qt::Key::Key_M}},
|
||||||
{types::Hotkey::ChangeMapStyle, QKeySequence {Qt::Key::Key_Z}},
|
{types::Hotkey::ChangeMapStyle, QKeySequence {Qt::Key::Key_Z}},
|
||||||
{types::Hotkey::CopyCursorCoordinates,
|
{types::Hotkey::CopyCursorCoordinates,
|
||||||
QKeySequence {QKeyCombination {Qt::KeyboardModifier::ControlModifier,
|
QKeySequence {QKeyCombination {Qt::KeyboardModifier::ControlModifier,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace types
|
||||||
{
|
{
|
||||||
|
|
||||||
static const std::unordered_map<Hotkey, std::string> hotkeyShortName_ {
|
static const std::unordered_map<Hotkey, std::string> hotkeyShortName_ {
|
||||||
|
{Hotkey::AddLocationMarker, "add_location_marker"},
|
||||||
{Hotkey::ChangeMapStyle, "change_map_style"},
|
{Hotkey::ChangeMapStyle, "change_map_style"},
|
||||||
{Hotkey::CopyCursorCoordinates, "copy_cursor_coordinates"},
|
{Hotkey::CopyCursorCoordinates, "copy_cursor_coordinates"},
|
||||||
{Hotkey::CopyMapCoordinates, "copy_map_coordinates"},
|
{Hotkey::CopyMapCoordinates, "copy_map_coordinates"},
|
||||||
|
|
@ -52,6 +53,7 @@ static const std::unordered_map<Hotkey, std::string> hotkeyShortName_ {
|
||||||
{Hotkey::Unknown, "?"}};
|
{Hotkey::Unknown, "?"}};
|
||||||
|
|
||||||
static const std::unordered_map<Hotkey, std::string> hotkeyLongName_ {
|
static const std::unordered_map<Hotkey, std::string> hotkeyLongName_ {
|
||||||
|
{Hotkey::AddLocationMarker, "Add Location Marker"},
|
||||||
{Hotkey::ChangeMapStyle, "Change Map Style"},
|
{Hotkey::ChangeMapStyle, "Change Map Style"},
|
||||||
{Hotkey::CopyCursorCoordinates, "Copy Cursor Coordinates"},
|
{Hotkey::CopyCursorCoordinates, "Copy Cursor Coordinates"},
|
||||||
{Hotkey::CopyMapCoordinates, "Copy Map Coordinates"},
|
{Hotkey::CopyMapCoordinates, "Copy Map Coordinates"},
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace types
|
||||||
|
|
||||||
enum class Hotkey
|
enum class Hotkey
|
||||||
{
|
{
|
||||||
|
AddLocationMarker,
|
||||||
ChangeMapStyle,
|
ChangeMapStyle,
|
||||||
CopyCursorCoordinates,
|
CopyCursorCoordinates,
|
||||||
CopyMapCoordinates,
|
CopyMapCoordinates,
|
||||||
|
|
@ -52,7 +53,7 @@ enum class Hotkey
|
||||||
Unknown
|
Unknown
|
||||||
};
|
};
|
||||||
typedef scwx::util::
|
typedef scwx::util::
|
||||||
Iterator<Hotkey, Hotkey::ChangeMapStyle, Hotkey::TimelineStepEnd>
|
Iterator<Hotkey, Hotkey::AddLocationMarker, Hotkey::TimelineStepEnd>
|
||||||
HotkeyIterator;
|
HotkeyIterator;
|
||||||
|
|
||||||
Hotkey GetHotkeyFromShortName(const std::string& name);
|
Hotkey GetHotkeyFromShortName(const std::string& name);
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,82 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <scwx/qt/types/texture_types.hpp>
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace scwx
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <boost/gil.hpp>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
namespace scwx::qt::types
|
||||||
{
|
{
|
||||||
namespace qt
|
using MarkerId = std::uint64_t;
|
||||||
{
|
|
||||||
namespace types
|
|
||||||
{
|
|
||||||
typedef std::uint64_t MarkerId;
|
|
||||||
|
|
||||||
struct MarkerInfo
|
struct MarkerInfo
|
||||||
{
|
{
|
||||||
MarkerInfo(const std::string& name, double latitude, double longitude) :
|
MarkerInfo(std::string name,
|
||||||
name {name}, latitude {latitude}, longitude {longitude}
|
double latitude,
|
||||||
|
double longitude,
|
||||||
|
std::string iconName,
|
||||||
|
const boost::gil::rgba8_pixel_t& iconColor) :
|
||||||
|
name {std::move(name)},
|
||||||
|
latitude {latitude},
|
||||||
|
longitude {longitude},
|
||||||
|
iconName {std::move(iconName)},
|
||||||
|
iconColor {iconColor}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkerId id;
|
MarkerId id {0};
|
||||||
std::string name;
|
std::string name;
|
||||||
double latitude;
|
double latitude;
|
||||||
double longitude;
|
double longitude;
|
||||||
|
std::string iconName;
|
||||||
|
boost::gil::rgba8_pixel_t iconColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace types
|
struct MarkerIconInfo
|
||||||
} // namespace qt
|
{
|
||||||
} // namespace scwx
|
// Initializer for default icons (which use a texture)
|
||||||
|
explicit MarkerIconInfo(types::ImageTexture texture,
|
||||||
|
std::int32_t hotX,
|
||||||
|
std::int32_t hotY) :
|
||||||
|
name {types::GetTextureName(texture)},
|
||||||
|
path {types::GetTexturePath(texture)},
|
||||||
|
hotX {hotX},
|
||||||
|
hotY {hotY},
|
||||||
|
qIcon {QIcon(QString::fromStdString(path))},
|
||||||
|
image {}
|
||||||
|
{
|
||||||
|
auto qName = QString::fromStdString(name);
|
||||||
|
QStringList parts = qName.split("location-");
|
||||||
|
shortName = parts.last().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializer for custom icons (which use a file path)
|
||||||
|
explicit MarkerIconInfo(const std::string& path,
|
||||||
|
std::int32_t hotX,
|
||||||
|
std::int32_t hotY,
|
||||||
|
std::shared_ptr<boost::gil::rgba8_image_t> image) :
|
||||||
|
name {path},
|
||||||
|
path {path},
|
||||||
|
shortName {QFileInfo(path.c_str()).fileName().toStdString()},
|
||||||
|
hotX {hotX},
|
||||||
|
hotY {hotY},
|
||||||
|
qIcon {QIcon(QString::fromStdString(path))},
|
||||||
|
image {image}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string path;
|
||||||
|
std::string shortName;
|
||||||
|
std::int32_t hotX;
|
||||||
|
std::int32_t hotY;
|
||||||
|
QIcon qIcon;
|
||||||
|
std::optional<std::shared_ptr<boost::gil::rgba8_image_t>> image;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace scwx::qt::types
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,33 @@ static const std::unordered_map<ImageTexture, TextureInfo> imageTextureInfo_ {
|
||||||
{ImageTexture::Cursor17,
|
{ImageTexture::Cursor17,
|
||||||
{"images/cursor-17", ":/res/textures/images/cursor-17.png"}},
|
{"images/cursor-17", ":/res/textures/images/cursor-17.png"}},
|
||||||
{ImageTexture::Dot3, {"images/dot-3", ":/res/textures/images/dot-3.png"}},
|
{ImageTexture::Dot3, {"images/dot-3", ":/res/textures/images/dot-3.png"}},
|
||||||
|
{ImageTexture::LocationBriefcase,
|
||||||
|
{"images/location-briefcase",
|
||||||
|
":/res/icons/font-awesome-6/briefcase-solid.svg"}},
|
||||||
|
{ImageTexture::LocationBuildingColumns,
|
||||||
|
{"images/location-building-columns",
|
||||||
|
":/res/icons/font-awesome-6/building-columns-solid.svg"}},
|
||||||
|
{ImageTexture::LocationBuilding,
|
||||||
|
{"images/location-building",
|
||||||
|
":/res/icons/font-awesome-6/building-solid.svg"}},
|
||||||
|
{ImageTexture::LocationCaravan,
|
||||||
|
{"images/location-caravan",
|
||||||
|
":/res/icons/font-awesome-6/caravan-solid.svg"}},
|
||||||
|
{ImageTexture::LocationCrosshair,
|
||||||
|
{"images/location-crosshair",
|
||||||
|
":/res/icons/font-awesome-6/location-crosshairs-solid.svg"}},
|
||||||
|
{ImageTexture::LocationHouse,
|
||||||
|
{"images/location-house",
|
||||||
|
":/res/icons/font-awesome-6/house-solid-white.svg"}},
|
||||||
{ImageTexture::LocationMarker,
|
{ImageTexture::LocationMarker,
|
||||||
{"images/location-marker", ":/res/textures/images/location-marker.svg"}},
|
{"images/location-marker", ":/res/textures/images/location-marker.svg"}},
|
||||||
|
{ImageTexture::LocationPin,
|
||||||
|
{"images/location-pin", ":/res/icons/font-awesome-6/location-pin.svg"}},
|
||||||
|
{ImageTexture::LocationStar,
|
||||||
|
{"images/location-star",
|
||||||
|
":/res/icons/font-awesome-6/star-solid-white.svg"}},
|
||||||
|
{ImageTexture::LocationTent,
|
||||||
|
{"images/location-tent", ":/res/icons/font-awesome-6/tent-solid.svg"}},
|
||||||
{ImageTexture::MapboxLogo,
|
{ImageTexture::MapboxLogo,
|
||||||
{"images/mapbox-logo", ":/res/textures/images/mapbox-logo.svg"}},
|
{"images/mapbox-logo", ":/res/textures/images/mapbox-logo.svg"}},
|
||||||
{ImageTexture::MapTilerLogo,
|
{ImageTexture::MapTilerLogo,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,16 @@ enum class ImageTexture
|
||||||
Crosshairs24,
|
Crosshairs24,
|
||||||
Cursor17,
|
Cursor17,
|
||||||
Dot3,
|
Dot3,
|
||||||
|
LocationBriefcase,
|
||||||
|
LocationBuildingColumns,
|
||||||
|
LocationBuilding,
|
||||||
|
LocationCaravan,
|
||||||
|
LocationCrosshair,
|
||||||
|
LocationHouse,
|
||||||
LocationMarker,
|
LocationMarker,
|
||||||
|
LocationPin,
|
||||||
|
LocationStar,
|
||||||
|
LocationTent,
|
||||||
MapboxLogo,
|
MapboxLogo,
|
||||||
MapTilerLogo
|
MapTilerLogo
|
||||||
};
|
};
|
||||||
|
|
|
||||||
314
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.cpp
Normal file
|
|
@ -0,0 +1,314 @@
|
||||||
|
#include "edit_marker_dialog.hpp"
|
||||||
|
#include "ui_edit_marker_dialog.h"
|
||||||
|
|
||||||
|
#include <scwx/qt/manager/marker_manager.hpp>
|
||||||
|
#include <scwx/qt/types/marker_types.hpp>
|
||||||
|
#include <scwx/qt/util/color.hpp>
|
||||||
|
#include <scwx/qt/util/q_color_modulate.hpp>
|
||||||
|
#include <scwx/util/logger.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QColorDialog>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
namespace scwx::qt::ui
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string logPrefix_ = "scwx::qt::ui::edit_marker_dialog";
|
||||||
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
|
|
||||||
|
class EditMarkerDialog::Impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Impl(EditMarkerDialog* self) : self_ {self} {}
|
||||||
|
|
||||||
|
void show_color_dialog();
|
||||||
|
void show_icon_file_dialog();
|
||||||
|
|
||||||
|
void set_icon_color(const std::string& color);
|
||||||
|
|
||||||
|
void connect_signals();
|
||||||
|
|
||||||
|
void handle_accepted();
|
||||||
|
void handle_rejected();
|
||||||
|
|
||||||
|
EditMarkerDialog* self_;
|
||||||
|
QPushButton* deleteButton_ {nullptr};
|
||||||
|
QIcon get_colored_icon(const types::MarkerIconInfo& marker,
|
||||||
|
const std::string& color);
|
||||||
|
|
||||||
|
std::shared_ptr<manager::MarkerManager> markerManager_ =
|
||||||
|
manager::MarkerManager::Instance();
|
||||||
|
types::MarkerId editId_ {0};
|
||||||
|
bool adding_ {false};
|
||||||
|
std::string setIconOnAdded_ {""};
|
||||||
|
};
|
||||||
|
|
||||||
|
QIcon EditMarkerDialog::Impl::get_colored_icon(
|
||||||
|
const types::MarkerIconInfo& marker, const std::string& color)
|
||||||
|
{
|
||||||
|
return util::modulateColors(marker.qIcon,
|
||||||
|
self_->ui->iconComboBox->iconSize(),
|
||||||
|
QColor(QString::fromStdString(color)));
|
||||||
|
}
|
||||||
|
|
||||||
|
EditMarkerDialog::EditMarkerDialog(QWidget* parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
p {std::make_unique<Impl>(this)},
|
||||||
|
ui(new Ui::EditMarkerDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
for (auto& markerIcon : p->markerManager_->get_icons())
|
||||||
|
{
|
||||||
|
ui->iconComboBox->addItem(
|
||||||
|
markerIcon.second.qIcon,
|
||||||
|
QString::fromStdString(markerIcon.second.shortName),
|
||||||
|
QString::fromStdString(markerIcon.second.name));
|
||||||
|
}
|
||||||
|
p->deleteButton_ =
|
||||||
|
ui->buttonBox->addButton("Delete", QDialogButtonBox::DestructiveRole);
|
||||||
|
p->connect_signals();
|
||||||
|
}
|
||||||
|
|
||||||
|
EditMarkerDialog::~EditMarkerDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::setup()
|
||||||
|
{
|
||||||
|
setup(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::setup(double latitude, double longitude)
|
||||||
|
{
|
||||||
|
// By default use foreground color as marker color, mainly so the icons
|
||||||
|
// are vissable in the dropdown menu.
|
||||||
|
const QColor color = QWidget::palette().color(QWidget::foregroundRole());
|
||||||
|
p->editId_ = p->markerManager_->add_marker(types::MarkerInfo(
|
||||||
|
"",
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
manager::MarkerManager::getDefaultIconName(),
|
||||||
|
boost::gil::rgba8_pixel_t {static_cast<uint8_t>(color.red()),
|
||||||
|
static_cast<uint8_t>(color.green()),
|
||||||
|
static_cast<uint8_t>(color.blue()),
|
||||||
|
static_cast<uint8_t>(color.alpha())}));
|
||||||
|
|
||||||
|
setup(p->editId_);
|
||||||
|
p->adding_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::setup(types::MarkerId id)
|
||||||
|
{
|
||||||
|
std::optional<types::MarkerInfo> marker = p->markerManager_->get_marker(id);
|
||||||
|
if (!marker)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->editId_ = id;
|
||||||
|
p->adding_ = false;
|
||||||
|
|
||||||
|
const std::string iconColorStr =
|
||||||
|
util::color::ToArgbString(marker->iconColor);
|
||||||
|
p->set_icon_color(iconColorStr);
|
||||||
|
|
||||||
|
int iconIndex =
|
||||||
|
ui->iconComboBox->findData(QString::fromStdString(marker->iconName));
|
||||||
|
if (iconIndex < 0 || marker->iconName == "")
|
||||||
|
{
|
||||||
|
iconIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->nameLineEdit->setText(QString::fromStdString(marker->name));
|
||||||
|
ui->iconComboBox->setCurrentIndex(iconIndex);
|
||||||
|
ui->latitudeDoubleSpinBox->setValue(marker->latitude);
|
||||||
|
ui->longitudeDoubleSpinBox->setValue(marker->longitude);
|
||||||
|
ui->iconColorLineEdit->setText(QString::fromStdString(iconColorStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
types::MarkerInfo EditMarkerDialog::get_marker_info() const
|
||||||
|
{
|
||||||
|
const QString colorName = ui->iconColorLineEdit->text();
|
||||||
|
const boost::gil::rgba8_pixel_t color =
|
||||||
|
util::color::ToRgba8PixelT(colorName.toStdString());
|
||||||
|
|
||||||
|
return types::MarkerInfo(
|
||||||
|
ui->nameLineEdit->text().toStdString(),
|
||||||
|
ui->latitudeDoubleSpinBox->value(),
|
||||||
|
ui->longitudeDoubleSpinBox->value(),
|
||||||
|
ui->iconComboBox->currentData().toString().toStdString(),
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::Impl::show_color_dialog()
|
||||||
|
{
|
||||||
|
// WA_DeleteOnClose manages memory
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
|
||||||
|
auto* dialog = new QColorDialog(self_);
|
||||||
|
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
dialog->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel);
|
||||||
|
|
||||||
|
const QColor initialColor(self_->ui->iconColorLineEdit->text());
|
||||||
|
if (initialColor.isValid())
|
||||||
|
{
|
||||||
|
dialog->setCurrentColor(initialColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(dialog,
|
||||||
|
&QColorDialog::colorSelected,
|
||||||
|
self_,
|
||||||
|
[this](const QColor& qColor)
|
||||||
|
{
|
||||||
|
const QString colorName =
|
||||||
|
qColor.name(QColor::NameFormat::HexArgb);
|
||||||
|
self_->ui->iconColorLineEdit->setText(colorName);
|
||||||
|
set_icon_color(colorName.toStdString());
|
||||||
|
});
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::Impl::show_icon_file_dialog()
|
||||||
|
{
|
||||||
|
auto* dialog = new QFileDialog(self_);
|
||||||
|
|
||||||
|
dialog->setFileMode(QFileDialog::ExistingFile);
|
||||||
|
dialog->setNameFilters({"Icon (*.png *.svg)", "All Files (*)"});
|
||||||
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
QObject::connect(dialog,
|
||||||
|
&QFileDialog::fileSelected,
|
||||||
|
self_,
|
||||||
|
[this](const QString& file)
|
||||||
|
{
|
||||||
|
const std::string path =
|
||||||
|
QDir::toNativeSeparators(file).toStdString();
|
||||||
|
setIconOnAdded_ = path;
|
||||||
|
markerManager_->add_icon(path);
|
||||||
|
});
|
||||||
|
dialog->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::Impl::connect_signals()
|
||||||
|
{
|
||||||
|
connect(self_,
|
||||||
|
&EditMarkerDialog::accepted,
|
||||||
|
self_,
|
||||||
|
[this]() { handle_accepted(); });
|
||||||
|
|
||||||
|
connect(self_,
|
||||||
|
&EditMarkerDialog::rejected,
|
||||||
|
self_,
|
||||||
|
[this]() { handle_rejected(); });
|
||||||
|
|
||||||
|
connect(deleteButton_,
|
||||||
|
&QPushButton::clicked,
|
||||||
|
self_,
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
markerManager_->remove_marker(editId_);
|
||||||
|
self_->done(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(self_->ui->iconColorLineEdit,
|
||||||
|
&QLineEdit::textEdited,
|
||||||
|
self_,
|
||||||
|
[this](const QString& text) { set_icon_color(text.toStdString()); });
|
||||||
|
|
||||||
|
connect(self_->ui->iconColorButton,
|
||||||
|
&QAbstractButton::clicked,
|
||||||
|
self_,
|
||||||
|
[this]() { show_color_dialog(); });
|
||||||
|
|
||||||
|
connect(self_->ui->iconFileOpenButton,
|
||||||
|
&QPushButton::clicked,
|
||||||
|
self_,
|
||||||
|
[this]() { show_icon_file_dialog(); });
|
||||||
|
|
||||||
|
connect(markerManager_.get(),
|
||||||
|
&manager::MarkerManager::IconAdded,
|
||||||
|
self_,
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
const std::string color =
|
||||||
|
self_->ui->iconColorLineEdit->text().toStdString();
|
||||||
|
set_icon_color(color);
|
||||||
|
|
||||||
|
if (setIconOnAdded_ != "")
|
||||||
|
{
|
||||||
|
const int i = self_->ui->iconComboBox->findData(
|
||||||
|
QString::fromStdString(setIconOnAdded_));
|
||||||
|
if (i >= 0)
|
||||||
|
{
|
||||||
|
self_->ui->iconComboBox->setCurrentIndex(i);
|
||||||
|
setIconOnAdded_ = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(self_->ui->buttonBox->button(QDialogButtonBox::Apply),
|
||||||
|
&QAbstractButton::clicked,
|
||||||
|
self_,
|
||||||
|
[this]() { handle_accepted(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::Impl::set_icon_color(const std::string& color)
|
||||||
|
{
|
||||||
|
self_->ui->iconColorFrame->setStyleSheet(
|
||||||
|
QString::fromStdString(fmt::format("background-color: {}", color)));
|
||||||
|
|
||||||
|
auto* iconComboBox = self_->ui->iconComboBox;
|
||||||
|
|
||||||
|
const QVariant currentIcon = iconComboBox->currentData();
|
||||||
|
|
||||||
|
self_->ui->iconComboBox->clear();
|
||||||
|
for (auto& markerIcon : markerManager_->get_icons())
|
||||||
|
{
|
||||||
|
const int i =
|
||||||
|
iconComboBox->findData(QString::fromStdString(markerIcon.second.name));
|
||||||
|
const QIcon icon = get_colored_icon(markerIcon.second, color);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
iconComboBox->addItem(
|
||||||
|
icon,
|
||||||
|
QString::fromStdString(markerIcon.second.shortName),
|
||||||
|
QString::fromStdString(markerIcon.second.name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self_->ui->iconComboBox->setItemIcon(i, icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int i = iconComboBox->findData(currentIcon);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iconComboBox->setCurrentIndex(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::Impl::handle_accepted()
|
||||||
|
{
|
||||||
|
markerManager_->set_marker(editId_, self_->get_marker_info());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditMarkerDialog::Impl::handle_rejected()
|
||||||
|
{
|
||||||
|
if (adding_)
|
||||||
|
{
|
||||||
|
markerManager_->remove_marker(editId_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace scwx::qt::ui
|
||||||
34
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
#include <scwx/qt/types/marker_types.hpp>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class EditMarkerDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace scwx::qt::ui
|
||||||
|
{
|
||||||
|
class EditMarkerDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY_MOVE(EditMarkerDialog)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit EditMarkerDialog(QWidget* parent = nullptr);
|
||||||
|
~EditMarkerDialog() override;
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
void setup(double latitude, double longitude);
|
||||||
|
void setup(types::MarkerId id);
|
||||||
|
|
||||||
|
[[nodiscard]] types::MarkerInfo get_marker_info() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> p;
|
||||||
|
Ui::EditMarkerDialog* ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace scwx::qt::ui
|
||||||
210
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.ui
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>EditMarkerDialog</class>
|
||||||
|
<widget class="QDialog" name="EditMarkerDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>249</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Edit Location Marker</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="9" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="2">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="iconColorFrame">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Shape::Box</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Shadow::Plain</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="iconColorLineEdit">
|
||||||
|
<property name="text">
|
||||||
|
<string>#ffffffff</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="iconColorButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../../scwx-qt.qrc">
|
||||||
|
<normaloff>:/res/icons/font-awesome-6/palette-solid.svg</normaloff>:/res/icons/font-awesome-6/palette-solid.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="latitudeDoubleSpinBox">
|
||||||
|
<property name="correctionMode">
|
||||||
|
<enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-90.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>90.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Icon</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0" colspan="3">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Longitude</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Icon Color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Latitude</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="3">
|
||||||
|
<widget class="QToolButton" name="iconFileOpenButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add Custom Icon</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="longitudeDoubleSpinBox">
|
||||||
|
<property name="correctionMode">
|
||||||
|
<enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-180.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>180.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="2">
|
||||||
|
<widget class="QLineEdit" name="nameLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QComboBox" name="iconComboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../scwx-qt.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>EditMarkerDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>EditMarkerDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include <scwx/qt/manager/marker_manager.hpp>
|
#include <scwx/qt/manager/marker_manager.hpp>
|
||||||
#include <scwx/qt/model/marker_model.hpp>
|
#include <scwx/qt/model/marker_model.hpp>
|
||||||
#include <scwx/qt/types/qt_types.hpp>
|
#include <scwx/qt/types/qt_types.hpp>
|
||||||
#include <scwx/qt/ui/open_url_dialog.hpp>
|
#include <scwx/qt/ui/edit_marker_dialog.hpp>
|
||||||
#include <scwx/util/logger.hpp>
|
#include <scwx/util/logger.hpp>
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
@ -23,17 +23,24 @@ class MarkerSettingsWidgetImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MarkerSettingsWidgetImpl(MarkerSettingsWidget* self) :
|
explicit MarkerSettingsWidgetImpl(MarkerSettingsWidget* self) :
|
||||||
self_ {self},
|
self_ {self},
|
||||||
markerModel_ {new model::MarkerModel(self_)}
|
markerModel_ {new model::MarkerModel(self_)},
|
||||||
|
proxyModel_ {new QSortFilterProxyModel(self_)}
|
||||||
{
|
{
|
||||||
|
proxyModel_->setSourceModel(markerModel_);
|
||||||
|
proxyModel_->setSortRole(Qt::DisplayRole); // TODO types::SortRole
|
||||||
|
proxyModel_->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
proxyModel_->setFilterKeyColumn(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectSignals();
|
void ConnectSignals();
|
||||||
|
|
||||||
MarkerSettingsWidget* self_;
|
MarkerSettingsWidget* self_;
|
||||||
model::MarkerModel* markerModel_;
|
model::MarkerModel* markerModel_;
|
||||||
|
QSortFilterProxyModel* proxyModel_;
|
||||||
std::shared_ptr<manager::MarkerManager> markerManager_ {
|
std::shared_ptr<manager::MarkerManager> markerManager_ {
|
||||||
manager::MarkerManager::Instance()};
|
manager::MarkerManager::Instance()};
|
||||||
|
std::shared_ptr<ui::EditMarkerDialog> editMarkerDialog_ {nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -45,8 +52,9 @@ MarkerSettingsWidget::MarkerSettingsWidget(QWidget* parent) :
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
ui->removeButton->setEnabled(false);
|
ui->removeButton->setEnabled(false);
|
||||||
|
ui->markerView->setModel(p->proxyModel_);
|
||||||
|
|
||||||
ui->markerView->setModel(p->markerModel_);
|
p->editMarkerDialog_ = std::make_shared<ui::EditMarkerDialog>(this);
|
||||||
|
|
||||||
p->ConnectSignals();
|
p->ConnectSignals();
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +71,8 @@ void MarkerSettingsWidgetImpl::ConnectSignals()
|
||||||
self_,
|
self_,
|
||||||
[this]()
|
[this]()
|
||||||
{
|
{
|
||||||
markerManager_->add_marker(types::MarkerInfo("", 0, 0));
|
editMarkerDialog_->setup();
|
||||||
|
editMarkerDialog_->show();
|
||||||
});
|
});
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
self_->ui->removeButton,
|
self_->ui->removeButton,
|
||||||
|
|
@ -99,9 +108,30 @@ void MarkerSettingsWidgetImpl::ConnectSignals()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool itemSelected = selected.size() > 0;
|
const bool itemSelected = selected.size() > 0;
|
||||||
self_->ui->removeButton->setEnabled(itemSelected);
|
self_->ui->removeButton->setEnabled(itemSelected);
|
||||||
});
|
});
|
||||||
|
QObject::connect(self_->ui->markerView,
|
||||||
|
&QAbstractItemView::doubleClicked,
|
||||||
|
self_,
|
||||||
|
[this](const QModelIndex& index)
|
||||||
|
{
|
||||||
|
const int row = index.row();
|
||||||
|
if (row < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<types::MarkerId> id =
|
||||||
|
markerModel_->getId(row);
|
||||||
|
if (!id)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
editMarkerDialog_->setup(*id);
|
||||||
|
editMarkerDialog_->show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
|
||||||
64
scwx-qt/source/scwx/qt/util/q_color_modulate.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include <scwx/qt/util/q_color_modulate.hpp>
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
namespace scwx::qt::util
|
||||||
|
{
|
||||||
|
|
||||||
|
void modulateColors_(QImage& image, const QColor& color)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < image.height(); ++y)
|
||||||
|
{
|
||||||
|
QRgb* line = reinterpret_cast<QRgb*>(image.scanLine(y));
|
||||||
|
for (int x = 0; x < image.width(); ++x)
|
||||||
|
{
|
||||||
|
// This is pulled from Qt Documentation
|
||||||
|
// https://doc.qt.io/qt-6/qimage.html#scanLine
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||||
|
QRgb& rgb = line[x];
|
||||||
|
/* clang-format off
|
||||||
|
* NOLINTBEGIN(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
|
||||||
|
* qRed/qGreen/qBlue/qAlpha return values 0-255, handlable by float
|
||||||
|
* redF/greenF/blueF/alphaF are all 0-1, so output is 0-255
|
||||||
|
* Rounding is fine for this.
|
||||||
|
* clang-format on
|
||||||
|
*/
|
||||||
|
const int red = qRed(rgb) * color.redF();
|
||||||
|
const int green = qGreen(rgb) * color.greenF();
|
||||||
|
const int blue = qBlue(rgb) * color.blueF();
|
||||||
|
const int alpha = qAlpha(rgb) * color.alphaF();
|
||||||
|
/* clang-format off
|
||||||
|
* NOLINTEND(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
|
||||||
|
* clang-format on
|
||||||
|
*/
|
||||||
|
|
||||||
|
rgb = qRgba(red, green, blue, alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage modulateColors(const QImage& image, const QColor& color)
|
||||||
|
{
|
||||||
|
QImage copy = image.copy();
|
||||||
|
modulateColors_(copy, color);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap modulateColors(const QPixmap& pixmap, const QColor& color)
|
||||||
|
{
|
||||||
|
QImage image = pixmap.toImage();
|
||||||
|
modulateColors_(image, color);
|
||||||
|
return QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon modulateColors(const QIcon& icon, const QSize& size, const QColor& color)
|
||||||
|
{
|
||||||
|
const QPixmap pixmap = modulateColors(icon.pixmap(size), color);
|
||||||
|
return QIcon(pixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace scwx::qt::util
|
||||||
16
scwx-qt/source/scwx/qt/util/q_color_modulate.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
namespace scwx::qt::util
|
||||||
|
{
|
||||||
|
|
||||||
|
QImage modulateColors(const QImage& image, const QColor& color);
|
||||||
|
QPixmap modulateColors(const QPixmap& pixmap, const QColor& color);
|
||||||
|
QIcon modulateColors(const QIcon& icon, const QSize& size, const QColor& color);
|
||||||
|
|
||||||
|
} // namespace scwx::qt::util
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4b4d9c54b8218aa2297dbd457e3747091570f0d2
|
Subproject commit 0d085b1df59045e14ca996982b4907b1a0da4fdb
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <scwx/qt/model/marker_model.hpp>
|
#include <scwx/qt/model/marker_model.hpp>
|
||||||
#include <scwx/qt/manager/marker_manager.hpp>
|
#include <scwx/qt/manager/marker_manager.hpp>
|
||||||
#include <scwx/qt/main/application.hpp>
|
#include <scwx/qt/main/application.hpp>
|
||||||
|
#include <scwx/qt/util/color.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -9,7 +10,6 @@
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
|
||||||
namespace scwx
|
namespace scwx
|
||||||
{
|
{
|
||||||
namespace qt
|
namespace qt
|
||||||
|
|
@ -25,11 +25,17 @@ static const std::string ONE_MARKERS_FILE =
|
||||||
std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-one.json";
|
std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-one.json";
|
||||||
static const std::string FIVE_MARKERS_FILE =
|
static const std::string FIVE_MARKERS_FILE =
|
||||||
std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-five.json";
|
std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-five.json";
|
||||||
|
static const std::string PART1_MARKER_FILE =
|
||||||
|
std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-part1.json";
|
||||||
|
|
||||||
static std::mutex initializedMutex {};
|
static std::mutex initializedMutex {};
|
||||||
static std::condition_variable initializedCond {};
|
static std::condition_variable initializedCond {};
|
||||||
static bool initialized;
|
static bool initialized;
|
||||||
|
|
||||||
|
static const boost::gil::rgba8_pixel_t defaultIconColor =
|
||||||
|
util::color::ToRgba8PixelT("#ffff0000");
|
||||||
|
static const std::string defaultIconName = "images/location-marker";
|
||||||
|
|
||||||
void CompareFiles(const std::string& file1, const std::string& file2)
|
void CompareFiles(const std::string& file1, const std::string& file2)
|
||||||
{
|
{
|
||||||
std::ifstream ifs1 {file1};
|
std::ifstream ifs1 {file1};
|
||||||
|
|
@ -49,8 +55,8 @@ void CopyFile(const std::string& from, const std::string& to)
|
||||||
CompareFiles(from, to);
|
CompareFiles(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void TestFunction(std::shared_ptr<manager::MarkerManager> manager,
|
using TestFunction = void(std::shared_ptr<manager::MarkerManager>,
|
||||||
MarkerModel& model);
|
MarkerModel&);
|
||||||
|
|
||||||
void RunTest(const std::string& filename, TestFunction testFunction)
|
void RunTest(const std::string& filename, TestFunction testFunction)
|
||||||
{
|
{
|
||||||
|
|
@ -65,7 +71,7 @@ void RunTest(const std::string& filename, TestFunction testFunction)
|
||||||
initialized = false;
|
initialized = false;
|
||||||
QObject::connect(manager.get(),
|
QObject::connect(manager.get(),
|
||||||
&manager::MarkerManager::MarkersInitialized,
|
&manager::MarkerManager::MarkersInitialized,
|
||||||
[](size_t count)
|
[]()
|
||||||
{
|
{
|
||||||
std::unique_lock lock(initializedMutex);
|
std::unique_lock lock(initializedMutex);
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
@ -119,7 +125,10 @@ TEST(MarkerModelTest, AddRemove)
|
||||||
|
|
||||||
RunTest(ONE_MARKERS_FILE,
|
RunTest(ONE_MARKERS_FILE,
|
||||||
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel&)
|
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel&)
|
||||||
{ manager->add_marker(types::MarkerInfo("Null", 0, 0)); });
|
{
|
||||||
|
manager->add_marker(types::MarkerInfo(
|
||||||
|
"Null", 0, 0, defaultIconName, defaultIconColor));
|
||||||
|
});
|
||||||
RunTest(
|
RunTest(
|
||||||
EMPTY_MARKERS_FILE,
|
EMPTY_MARKERS_FILE,
|
||||||
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel& model)
|
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel& model)
|
||||||
|
|
@ -143,11 +152,16 @@ TEST(MarkerModelTest, AddFive)
|
||||||
RunTest(FIVE_MARKERS_FILE,
|
RunTest(FIVE_MARKERS_FILE,
|
||||||
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel&)
|
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel&)
|
||||||
{
|
{
|
||||||
manager->add_marker(types::MarkerInfo("Null", 0, 0));
|
manager->add_marker(types::MarkerInfo(
|
||||||
manager->add_marker(types::MarkerInfo("North", 90, 0));
|
"Null", 0, 0, defaultIconName, defaultIconColor));
|
||||||
manager->add_marker(types::MarkerInfo("South", -90, 0));
|
manager->add_marker(types::MarkerInfo(
|
||||||
manager->add_marker(types::MarkerInfo("East", 0, 90));
|
"North", 90, 0, defaultIconName, defaultIconColor));
|
||||||
manager->add_marker(types::MarkerInfo("West", 0, -90));
|
manager->add_marker(types::MarkerInfo(
|
||||||
|
"South", -90, 0, defaultIconName, defaultIconColor));
|
||||||
|
manager->add_marker(types::MarkerInfo(
|
||||||
|
"East", 0, 90, defaultIconName, defaultIconColor));
|
||||||
|
manager->add_marker(types::MarkerInfo(
|
||||||
|
"West", 0, -90, defaultIconName, defaultIconColor));
|
||||||
});
|
});
|
||||||
|
|
||||||
std::filesystem::remove(TEMP_MARKERS_FILE);
|
std::filesystem::remove(TEMP_MARKERS_FILE);
|
||||||
|
|
@ -161,10 +175,14 @@ TEST(MarkerModelTest, AddFour)
|
||||||
RunTest(FIVE_MARKERS_FILE,
|
RunTest(FIVE_MARKERS_FILE,
|
||||||
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel&)
|
[](std::shared_ptr<manager::MarkerManager> manager, MarkerModel&)
|
||||||
{
|
{
|
||||||
manager->add_marker(types::MarkerInfo("North", 90, 0));
|
manager->add_marker(types::MarkerInfo(
|
||||||
manager->add_marker(types::MarkerInfo("South", -90, 0));
|
"North", 90, 0, defaultIconName, defaultIconColor));
|
||||||
manager->add_marker(types::MarkerInfo("East", 0, 90));
|
manager->add_marker(types::MarkerInfo(
|
||||||
manager->add_marker(types::MarkerInfo("West", 0, -90));
|
"South", -90, 0, defaultIconName, defaultIconColor));
|
||||||
|
manager->add_marker(types::MarkerInfo(
|
||||||
|
"East", 0, 90, defaultIconName, defaultIconColor));
|
||||||
|
manager->add_marker(types::MarkerInfo(
|
||||||
|
"West", 0, -90, defaultIconName, defaultIconColor));
|
||||||
});
|
});
|
||||||
|
|
||||||
std::filesystem::remove(TEMP_MARKERS_FILE);
|
std::filesystem::remove(TEMP_MARKERS_FILE);
|
||||||
|
|
@ -235,6 +253,17 @@ TEST(MarkerModelTest, RemoveFour)
|
||||||
EXPECT_EQ(std::filesystem::exists(TEMP_MARKERS_FILE), false);
|
EXPECT_EQ(std::filesystem::exists(TEMP_MARKERS_FILE), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MarkerModelTest, UpdateFromPart1)
|
||||||
|
{
|
||||||
|
CopyFile(PART1_MARKER_FILE, TEMP_MARKERS_FILE);
|
||||||
|
|
||||||
|
RunTest(ONE_MARKERS_FILE,
|
||||||
|
[](std::shared_ptr<manager::MarkerManager>, MarkerModel&) {});
|
||||||
|
|
||||||
|
std::filesystem::remove(TEMP_MARKERS_FILE);
|
||||||
|
EXPECT_EQ(std::filesystem::exists(TEMP_MARKERS_FILE), false);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace model
|
} // namespace model
|
||||||
} // namespace qt
|
} // namespace qt
|
||||||
} // namespace scwx
|
} // namespace scwx
|
||||||
|
|
|
||||||