#[cfg(feature = "click")]
use crate::event;
use crate::holder;
use egui::{
epaint::{Color32, CornerRadius, Rect, RectShape},
Pos2, Response, Sense, Ui, Widget, WidgetInfo, WidgetType
};
#[cfg(feature = "click")]
use egui::PointerButton;
use std::{ops::Deref, sync::{Arc, Mutex}};
#[cfg(feature = "click")]
use std::ops::DerefMut;
#[cfg(not(feature = "click"))]
use std::marker::PhantomData;
pub struct CanvasWidget<'a> {
shapes: Arc<Mutex<holder::ShapeMap>>,
background_color: Option<Color32>,
pos: Option<holder::PositionInfo>,
needless_click_sense: bool,
#[cfg(feature = "click")]
click_handler: Arc<Mutex<Option<holder::ClickHandler<'a>>>>,
#[cfg(feature = "click")]
has_click_handler: bool,
#[cfg(not(feature = "click"))]
_marker: PhantomData<&'a ()>
}
#[cfg(not(feature = "click"))]
impl CanvasWidget<'_> {
pub fn new(
shapes: Arc<Mutex<holder::ShapeMap>>,
background_color: Option<Color32>,
pos: Option<holder::PositionInfo>,
needless_click_sense: bool
) -> Self {
Self {
shapes, background_color, pos,
needless_click_sense, _marker: PhantomData
}
}
}
#[cfg(feature = "click")]
impl<'a> CanvasWidget<'a> {
pub fn new(
shapes: Arc<Mutex<holder::ShapeMap>>,
background_color: Option<Color32>,
pos: Option<holder::PositionInfo>,
needless_click_sense: bool,
click_handler: Arc<Mutex<Option<holder::ClickHandler<'a>>>>,
has_click_handler: bool
) -> Self {
Self {
shapes, background_color, pos, needless_click_sense,
click_handler, has_click_handler
}
}
}
impl CanvasWidget<'_> {
fn get_self_pos(&self, ui: &Ui) -> holder::PositionInfo {
match self.pos {
Some(pos) => pos,
None => holder::PositionInfo::new(Pos2::ZERO, ui.available_size())
}
}
#[cfg(feature = "click")]
fn handle_click(&mut self, response: &Response, ui: &Ui) {
if !self.has_click_handler { return; }
let pos = response.interact_pointer_pos();
if pos.is_none() { return; }
let button = if response.clicked_by(PointerButton::Primary) {
PointerButton::Primary
} else if response.clicked_by(PointerButton::Secondary) {
PointerButton::Secondary
} else if response.clicked_by(PointerButton::Middle) {
PointerButton::Middle
} else if response.clicked_by(PointerButton::Extra1) {
PointerButton::Extra1
} else if response.clicked_by(PointerButton::Extra2) {
PointerButton::Extra2
} else { return; };
let pos = pos.unwrap();
let holder::PositionInfo{ pos: self_pos, size: self_size } = self.get_self_pos(ui);
let self_other_corner = self_pos + self_size;
if pos.x <= self_pos.x || pos.x >= self_other_corner.x ||
pos.y <= self_pos.y || pos.y >= self_other_corner.y
{ return; }
let mut lock = self.click_handler.lock().unwrap();
let click_handler = lock.deref_mut().as_mut().unwrap();
click_handler(event::ClickEvent::new(button, pos));
}
}
impl Widget for CanvasWidget<'_> {
#[cfg(not(feature = "click"))]
fn ui(self, ui: &mut Ui) -> Response {
let sense = if self.needless_click_sense {
Sense::click()
} else {
Sense::hover()
};
let holder::PositionInfo { pos, size } = self.get_self_pos(ui);
let rect = Rect { min: pos, max: pos + size };
let response = ui.allocate_rect(rect, sense);
response.widget_info(
|| WidgetInfo::new(WidgetType::Other)
);
if ui.is_visible() {
if let Some(bg) = self.background_color {
ui.painter().add(RectShape::filled(
rect, CornerRadius::ZERO, bg
));
}
for pred_arc in self.shapes.lock().expect(crate::LOCK_ERR_MSG).values() {
let pred_lock = pred_arc.lock().unwrap();
if let Some(shape) = pred_lock.deref().finalise(ui) {
ui.painter().add(shape);
}
}
}
response
}
#[cfg(feature = "click")]
fn ui(mut self, ui: &mut Ui) -> Response {
let sense = if self.has_click_handler || self.needless_click_sense {
Sense::click()
} else {
Sense::hover()
};
let holder::PositionInfo { pos, size } = self.get_self_pos(ui);
let rect = Rect { min: pos, max: pos + size };
let response = ui.allocate_rect(rect, sense);
response.widget_info(
|| WidgetInfo::new(WidgetType::Other)
);
if ui.is_visible() {
self.handle_click(&response, ui);
if let Some(bg) = self.background_color {
ui.painter().add(RectShape::filled(
rect, CornerRadius::ZERO, bg
));
}
for pred_arc in self.shapes.lock().expect(crate::LOCK_ERR_MSG).values() {
let pred_lock = pred_arc.lock().unwrap();
if let Some(shape) = pred_lock.deref().finalise(ui) {
ui.painter().add(shape);
}
}
}
response
}
}