Add anchored text rotation method, and clarify related docs (#7130)
Add a helper method to perform rotation about a specified anchor. * Closes #7051
This commit is contained in:
parent
f33ff2c83d
commit
df2c16ef0a
|
|
@ -1,8 +1,8 @@
|
|||
use super::{Demo, View};
|
||||
|
||||
use egui::{
|
||||
vec2, Align, Checkbox, CollapsingHeader, Color32, Context, FontId, Resize, RichText, Sense,
|
||||
Slider, Stroke, TextFormat, TextStyle, Ui, Vec2, Window,
|
||||
vec2, Align, Align2, Checkbox, CollapsingHeader, Color32, ComboBox, Context, FontId, Resize,
|
||||
RichText, Sense, Slider, Stroke, TextFormat, TextStyle, Ui, Vec2, Window,
|
||||
};
|
||||
|
||||
/// Showcase some ui code
|
||||
|
|
@ -16,6 +16,7 @@ pub struct MiscDemoWindow {
|
|||
custom_collapsing_header: CustomCollapsingHeader,
|
||||
tree: Tree,
|
||||
box_painting: BoxPainting,
|
||||
text_rotation: TextRotation,
|
||||
|
||||
dummy_bool: bool,
|
||||
dummy_usize: usize,
|
||||
|
|
@ -32,6 +33,7 @@ impl Default for MiscDemoWindow {
|
|||
custom_collapsing_header: Default::default(),
|
||||
tree: Tree::demo(),
|
||||
box_painting: Default::default(),
|
||||
text_rotation: Default::default(),
|
||||
|
||||
dummy_bool: false,
|
||||
dummy_usize: 0,
|
||||
|
|
@ -79,6 +81,10 @@ impl View for MiscDemoWindow {
|
|||
});
|
||||
});
|
||||
|
||||
CollapsingHeader::new("Text rotation")
|
||||
.default_open(false)
|
||||
.show(ui, |ui| self.text_rotation.ui(ui));
|
||||
|
||||
CollapsingHeader::new("Colors")
|
||||
.default_open(false)
|
||||
.show(ui, |ui| {
|
||||
|
|
@ -729,3 +735,95 @@ fn text_layout_demo(ui: &mut Ui) {
|
|||
|
||||
ui.label(job);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
struct TextRotation {
|
||||
size: Vec2,
|
||||
angle: f32,
|
||||
align: egui::Align2,
|
||||
}
|
||||
|
||||
impl Default for TextRotation {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
size: vec2(200.0, 200.0),
|
||||
angle: 0.0,
|
||||
align: egui::Align2::LEFT_TOP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TextRotation {
|
||||
pub fn ui(&mut self, ui: &mut Ui) {
|
||||
ui.add(Slider::new(&mut self.angle, 0.0..=2.0 * std::f32::consts::PI).text("angle"));
|
||||
|
||||
let default_color = if ui.visuals().dark_mode {
|
||||
Color32::LIGHT_GRAY
|
||||
} else {
|
||||
Color32::DARK_GRAY
|
||||
};
|
||||
|
||||
let aligns = [
|
||||
(Align2::LEFT_TOP, "LEFT_TOP"),
|
||||
(Align2::LEFT_CENTER, "LEFT_CENTER"),
|
||||
(Align2::LEFT_BOTTOM, "LEFT_BOTTOM"),
|
||||
(Align2::CENTER_TOP, "CENTER_TOP"),
|
||||
(Align2::CENTER_CENTER, "CENTER_CENTER"),
|
||||
(Align2::CENTER_BOTTOM, "CENTER_BOTTOM"),
|
||||
(Align2::RIGHT_TOP, "RIGHT_TOP"),
|
||||
(Align2::RIGHT_CENTER, "RIGHT_CENTER"),
|
||||
(Align2::RIGHT_BOTTOM, "RIGHT_BOTTOM"),
|
||||
];
|
||||
|
||||
ComboBox::new("anchor", "Anchor")
|
||||
.selected_text(aligns.iter().find(|(a, _)| *a == self.align).unwrap().1)
|
||||
.show_ui(ui, |ui| {
|
||||
for (align2, name) in &aligns {
|
||||
ui.selectable_value(&mut self.align, *align2, *name);
|
||||
}
|
||||
});
|
||||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
let (response, painter) = ui.allocate_painter(self.size, Sense::empty());
|
||||
let rect = response.rect;
|
||||
|
||||
let start_pos = self.size / 2.0;
|
||||
|
||||
let s = ui.ctx().fonts(|f| {
|
||||
let mut t = egui::Shape::text(
|
||||
f,
|
||||
rect.min + start_pos,
|
||||
egui::Align2::LEFT_TOP,
|
||||
"sample_text",
|
||||
egui::FontId::new(12.0, egui::FontFamily::Proportional),
|
||||
default_color,
|
||||
);
|
||||
|
||||
if let egui::epaint::Shape::Text(ts) = &mut t {
|
||||
let new = ts.clone().with_angle_and_anchor(self.angle, self.align);
|
||||
*ts = new;
|
||||
};
|
||||
|
||||
t
|
||||
});
|
||||
|
||||
if let egui::epaint::Shape::Text(ts) = &s {
|
||||
let align_pt =
|
||||
rect.min + start_pos + self.align.pos_in_rect(&ts.galley.rect).to_vec2();
|
||||
painter.circle(align_pt, 2.0, Color32::RED, (0.0, Color32::RED));
|
||||
};
|
||||
|
||||
painter.rect(
|
||||
rect,
|
||||
0.0,
|
||||
default_color.gamma_multiply(0.3),
|
||||
(0.0, Color32::BLACK),
|
||||
egui::StrokeKind::Middle,
|
||||
);
|
||||
painter.add(s);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:880344367ed65f83898ceca4843b1b6259d1690242ced0d29ac8dc48100a8faa
|
||||
size 62956
|
||||
oid sha256:116a53258be27d9c7c56538e5f83202ea731f19887fabadc0449d24fde4d80d9
|
||||
size 64494
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use emath::{Align2, Rot2};
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// How to paint some text on screen.
|
||||
|
|
@ -78,7 +80,7 @@ impl TextShape {
|
|||
self
|
||||
}
|
||||
|
||||
/// Rotate text by this many radians clockwise.
|
||||
/// Set text rotation to `angle` radians clockwise.
|
||||
/// The pivot is `pos` (the upper left corner of the text).
|
||||
#[inline]
|
||||
pub fn with_angle(mut self, angle: f32) -> Self {
|
||||
|
|
@ -86,6 +88,17 @@ impl TextShape {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set the text rotation to the `angle` radians clockwise.
|
||||
/// The pivot is determined by the given `anchor` point on the text bounding box.
|
||||
#[inline]
|
||||
pub fn with_angle_and_anchor(mut self, angle: f32, anchor: Align2) -> Self {
|
||||
self.angle = angle;
|
||||
let a0 = anchor.pos_in_rect(&self.galley.rect).to_vec2();
|
||||
let a1 = Rot2::from_angle(angle) * a0;
|
||||
self.pos += a0 - a1;
|
||||
self
|
||||
}
|
||||
|
||||
/// Render text with this opacity in gamma space
|
||||
#[inline]
|
||||
pub fn with_opacity_factor(mut self, opacity_factor: f32) -> Self {
|
||||
|
|
|
|||
Loading…
Reference in New Issue