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 super::{Demo, View};
|
||||||
|
|
||||||
use egui::{
|
use egui::{
|
||||||
vec2, Align, Checkbox, CollapsingHeader, Color32, Context, FontId, Resize, RichText, Sense,
|
vec2, Align, Align2, Checkbox, CollapsingHeader, Color32, ComboBox, Context, FontId, Resize,
|
||||||
Slider, Stroke, TextFormat, TextStyle, Ui, Vec2, Window,
|
RichText, Sense, Slider, Stroke, TextFormat, TextStyle, Ui, Vec2, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Showcase some ui code
|
/// Showcase some ui code
|
||||||
|
|
@ -16,6 +16,7 @@ pub struct MiscDemoWindow {
|
||||||
custom_collapsing_header: CustomCollapsingHeader,
|
custom_collapsing_header: CustomCollapsingHeader,
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
box_painting: BoxPainting,
|
box_painting: BoxPainting,
|
||||||
|
text_rotation: TextRotation,
|
||||||
|
|
||||||
dummy_bool: bool,
|
dummy_bool: bool,
|
||||||
dummy_usize: usize,
|
dummy_usize: usize,
|
||||||
|
|
@ -32,6 +33,7 @@ impl Default for MiscDemoWindow {
|
||||||
custom_collapsing_header: Default::default(),
|
custom_collapsing_header: Default::default(),
|
||||||
tree: Tree::demo(),
|
tree: Tree::demo(),
|
||||||
box_painting: Default::default(),
|
box_painting: Default::default(),
|
||||||
|
text_rotation: Default::default(),
|
||||||
|
|
||||||
dummy_bool: false,
|
dummy_bool: false,
|
||||||
dummy_usize: 0,
|
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")
|
CollapsingHeader::new("Colors")
|
||||||
.default_open(false)
|
.default_open(false)
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
|
|
@ -729,3 +735,95 @@ fn text_layout_demo(ui: &mut Ui) {
|
||||||
|
|
||||||
ui.label(job);
|
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
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:880344367ed65f83898ceca4843b1b6259d1690242ced0d29ac8dc48100a8faa
|
oid sha256:116a53258be27d9c7c56538e5f83202ea731f19887fabadc0449d24fde4d80d9
|
||||||
size 62956
|
size 64494
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use emath::{Align2, Rot2};
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// How to paint some text on screen.
|
/// How to paint some text on screen.
|
||||||
|
|
@ -78,7 +80,7 @@ impl TextShape {
|
||||||
self
|
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).
|
/// The pivot is `pos` (the upper left corner of the text).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_angle(mut self, angle: f32) -> Self {
|
pub fn with_angle(mut self, angle: f32) -> Self {
|
||||||
|
|
@ -86,6 +88,17 @@ impl TextShape {
|
||||||
self
|
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
|
/// Render text with this opacity in gamma space
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_opacity_factor(mut self, opacity_factor: f32) -> Self {
|
pub fn with_opacity_factor(mut self, opacity_factor: f32) -> Self {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue