#[derive(Clone, Default, PartialEq)]
pub struct Output {
pub cursor_icon: CursorIcon,
pub open_url: Option<OpenUrl>,
pub copied_text: String,
pub needs_repaint: bool,
pub events: Vec<OutputEvent>,
pub text_cursor: Option<crate::Pos2>,
}
impl Output {
pub fn open_url(&mut self, url: impl Into<String>) {
self.open_url = Some(OpenUrl::same_tab(url))
}
pub fn events_description(&self) -> String {
if let Some(event) = self.events.iter().rev().next() {
match event {
OutputEvent::WidgetEvent(WidgetEvent::Focus, widget_info) => {
return widget_info.description();
}
}
}
Default::default()
}
}
#[derive(Clone, PartialEq)]
pub struct OpenUrl {
pub url: String,
pub new_tab: bool,
}
impl OpenUrl {
pub fn same_tab(url: impl Into<String>) -> Self {
Self {
url: url.into(),
new_tab: false,
}
}
pub fn new_tab(url: impl Into<String>) -> Self {
Self {
url: url.into(),
new_tab: true,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CursorIcon {
Default,
None,
ContextMenu,
Help,
PointingHand,
Progress,
Wait,
Cell,
Crosshair,
Text,
VerticalText,
Alias,
Copy,
Move,
NoDrop,
NotAllowed,
Grab,
Grabbing,
AllScroll,
ResizeHorizontal,
ResizeNeSw,
ResizeNwSe,
ResizeVertical,
ZoomIn,
ZoomOut,
}
impl CursorIcon {
pub const ALL: [CursorIcon; 25] = [
CursorIcon::Default,
CursorIcon::None,
CursorIcon::ContextMenu,
CursorIcon::Help,
CursorIcon::PointingHand,
CursorIcon::Progress,
CursorIcon::Wait,
CursorIcon::Cell,
CursorIcon::Crosshair,
CursorIcon::Text,
CursorIcon::VerticalText,
CursorIcon::Alias,
CursorIcon::Copy,
CursorIcon::Move,
CursorIcon::NoDrop,
CursorIcon::NotAllowed,
CursorIcon::Grab,
CursorIcon::Grabbing,
CursorIcon::AllScroll,
CursorIcon::ResizeHorizontal,
CursorIcon::ResizeNeSw,
CursorIcon::ResizeNwSe,
CursorIcon::ResizeVertical,
CursorIcon::ZoomIn,
CursorIcon::ZoomOut,
];
}
impl Default for CursorIcon {
fn default() -> Self {
Self::Default
}
}
#[derive(Clone, PartialEq)]
pub enum OutputEvent {
WidgetEvent(WidgetEvent, WidgetInfo),
}
impl std::fmt::Debug for OutputEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::WidgetEvent(we, wi) => write!(f, "{:?}: {:?}", we, wi),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum WidgetEvent {
Focus,
}
#[derive(Clone, PartialEq)]
pub struct WidgetInfo {
pub typ: WidgetType,
pub label: Option<String>,
pub edit_text: Option<String>,
pub selected: Option<bool>,
pub value: Option<f64>,
}
impl std::fmt::Debug for WidgetInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self {
typ,
label,
edit_text,
selected,
value,
} = self;
let mut s = f.debug_struct("WidgetInfo");
s.field("typ", typ);
if let Some(label) = label {
s.field("label", label);
}
if let Some(edit_text) = edit_text {
s.field("edit_text", edit_text);
}
if let Some(selected) = selected {
s.field("selected", selected);
}
if let Some(value) = value {
s.field("value", value);
}
s.finish()
}
}
impl WidgetInfo {
pub fn new(typ: WidgetType) -> Self {
Self {
typ,
label: None,
edit_text: None,
selected: None,
value: None,
}
}
pub fn labeled(typ: WidgetType, label: impl Into<String>) -> Self {
Self {
label: Some(label.into()),
..Self::new(typ)
}
}
pub fn selected(typ: WidgetType, selected: bool, label: impl Into<String>) -> Self {
Self {
label: Some(label.into()),
selected: Some(selected),
..Self::new(typ)
}
}
pub fn drag_value(value: f64) -> Self {
Self {
value: Some(value),
..Self::new(WidgetType::DragValue)
}
}
pub fn slider(value: f64, label: impl Into<String>) -> Self {
let label = label.into();
Self {
label: if label.is_empty() { None } else { Some(label) },
value: Some(value),
..Self::new(WidgetType::Slider)
}
}
pub fn text_edit(edit_text: impl Into<String>) -> Self {
Self {
edit_text: Some(edit_text.into()),
..Self::new(WidgetType::TextEdit)
}
}
pub fn description(&self) -> String {
let Self {
typ,
label,
edit_text,
selected,
value,
} = self;
let widget_name = match typ {
WidgetType::Hyperlink => "link",
WidgetType::TextEdit => "text edit",
WidgetType::Button => "button",
WidgetType::Checkbox => "checkbox",
WidgetType::RadioButton => "radio",
WidgetType::SelectableLabel => "selectable",
WidgetType::ComboBox => "combo",
WidgetType::Slider => "slider",
WidgetType::DragValue => "drag value",
WidgetType::ColorButton => "color button",
WidgetType::ImageButton => "image button",
WidgetType::CollapsingHeader => "collapsing header",
WidgetType::Label | WidgetType::Other => "",
};
let mut description = widget_name.to_owned();
if let Some(selected) = selected {
if *typ == WidgetType::Checkbox {
description += " ";
description += if *selected { "checked" } else { "unchecked" };
} else {
description += if *selected { "selected" } else { "" };
};
}
if let Some(label) = label {
description += " ";
description += label;
}
if let Some(edit_text) = edit_text {
description += " ";
description += edit_text;
}
if let Some(value) = value {
description += " ";
description += &value.to_string();
}
description.trim().to_owned()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum WidgetType {
Label,
Hyperlink,
TextEdit,
Button,
Checkbox,
RadioButton,
SelectableLabel,
ComboBox,
Slider,
DragValue,
ColorButton,
ImageButton,
CollapsingHeader,
Other,
}