1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use image::DynamicImage;
use crate::bridge::ffi;
use crate::{
AnyLayer, ImageId, ImageRenderer, Layer, LayerId, Source, SourceId, SourceRefMut, StyleError,
};
/// A mutable reference to the renderer's current map style.
#[derive(Debug)]
pub struct StyleRef<'a, S> {
image_renderer: &'a mut ImageRenderer<S>,
}
impl<'a, S> StyleRef<'a, S> {
pub(crate) fn new(image_renderer: &'a mut ImageRenderer<S>) -> Self {
Self { image_renderer }
}
/// Adds an image to the style with the given ID, pixel ratio, and options.
///
/// Pass `true` for `signed_distance_field` to register the image as an SDF (signed
/// distance field) icon; pass `false` for a regular bitmap icon.
///
/// # Errors
///
/// Returns an error if MapLibre Native rejects the image.
pub fn add_image(
&mut self,
id: impl AsRef<str>,
image: &DynamicImage,
pixel_ratio: f32,
signed_distance_field: bool,
) -> Result<ImageId, StyleError> {
use image::EncodableLayout;
let id = id.as_ref();
let image = image.to_rgba8();
self.image_renderer.instance.pin_mut().style_add_image(
id,
image.as_bytes(),
ffi::Size { width: image.width(), height: image.height() },
pixel_ratio,
signed_distance_field,
)?;
Ok(ImageId::new(id.to_owned()))
}
/// Removes an image from the style by ID.
///
/// No-op if `id` does not match an existing image.
pub fn remove_image(&mut self, id: impl AsRef<str>) {
self.image_renderer.instance.pin_mut().style_remove_image(id.as_ref());
}
/// Adds a source to the current map style and returns its stable source ID.
///
/// # Errors
///
/// Returns an error if MapLibre Native rejects the source.
pub fn add_source<T: Source>(&mut self, source: T) -> Result<SourceId, StyleError> {
let source_id = SourceId::new(source.source_id().to_owned());
self.image_renderer.instance.pin_mut().style_add_source(source.into_source())?;
Ok(source_id)
}
/// Returns a mutable reference to a source in the current map style.
///
/// Returns `None` if `source_id` does not match an existing source.
pub fn source_mut(&mut self, source_id: impl AsRef<str>) -> Option<SourceRefMut<'_>> {
SourceRefMut::from_ffi(
self.image_renderer.instance.pin_mut().style_get_source_mut(source_id.as_ref()),
)
}
/// Adds a new layer and returns its stable layer ID.
///
/// # Errors
///
/// Returns an error if MapLibre Native rejects the layer.
pub fn add_layer<T: Layer>(&mut self, layer: T) -> Result<LayerId, StyleError> {
let layer_id = LayerId::new(layer.layer_id().to_owned());
self.add_layer_inner(layer.into_layer(), None)?;
Ok(layer_id)
}
/// Adds a new layer before an existing layer.
///
/// `before_layer` is the ID of an existing layer; the new layer is inserted
/// directly below it. If `before_layer` does not match any existing layer,
/// the new layer is appended to the end of the style.
///
/// # Errors
///
/// Returns an error if MapLibre Native rejects the layer.
pub fn add_layer_before<T: Layer>(
&mut self,
layer: T,
before_layer: impl AsRef<str>,
) -> Result<LayerId, StyleError> {
let layer_id = LayerId::new(layer.layer_id().to_owned());
self.add_layer_inner(layer.into_layer(), Some(before_layer.as_ref()))?;
Ok(layer_id)
}
fn add_layer_inner(
&mut self,
layer: cxx::UniquePtr<ffi::CxxLayer>,
before_id: Option<&str>,
) -> Result<(), StyleError> {
// The C++ bridge encodes "append" as an empty string; that detail is
// contained here so the public API can use separate append/before methods.
let before_id = before_id.unwrap_or_default();
self.image_renderer.instance.pin_mut().style_add_layer(layer, before_id)?;
Ok(())
}
/// Removes a layer from the current map style by ID and returns it.
///
/// Returns `None` if `layer_id` does not match an existing layer.
pub fn remove_layer(&mut self, layer_id: impl AsRef<str>) -> Option<AnyLayer> {
AnyLayer::from_layer_ptr(
self.image_renderer.instance.pin_mut().style_remove_layer(layer_id.as_ref()),
)
}
/// Removes a source from the current map style by ID.
///
/// No-op if `source_id` does not match an existing source.
pub fn remove_source(&mut self, source_id: impl AsRef<str>) {
self.image_renderer.instance.pin_mut().style_remove_source(source_id.as_ref());
}
}