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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
//! Everything to describe an access a widget use std::marker::PhantomData; use downcast_rs::DowncastSync; use pugl_sys::pugl::*; /// The unique Id of a widget. /// /// The Id is the way, widgets can be accessed by a [`WidgetHandle`](struct.WidgetHandle.html). pub type Id = usize; /// The `Widget` trait. /// /// Widgets need to implement this trait. Most of the methods have /// default implementations, so that simple widgets can be easily /// defined. Eeven layouts are internally treated as widgets. /// /// Data common to all widgets is kept in the struct /// [`WidgetStub`](struct.WidgetStub.html) accessible from the widget by /// the methods [`stub()`](#tymethod.stub) and [`stub_mut()`](#tymethod.stub_mut). pub trait Widget : DowncastSync { /// Called by the UI to pass an event to the widget. /// /// The widget is supposed to process the Event and return `None` /// if the widget has processed the event. If the widget has not /// processed the event it shoud return `Some(ev)` so that the /// event can be passed to its parent widget. /// /// There is [`EventState`](../ui/enum.EventState.html) and the macros /// [`event_processed!()`](../macro.event_processed.html) and /// [`event_not_processed!()`](../macro.event_not_processed.html) to do this. /// /// The default implementation just passes the event without touching it. /// fn event(&mut self, ev: Event) -> Option<Event> { Some (ev) } /// Called when the widget has to draw itself. /// /// # Parameters /// /// * `expose: &ExposeArea` – a pugl_sys::pugl::ExposeArea /// carrying the information which rectangle of the widget /// actually needs to be redrawn. /// /// Default implementation does nothing. fn exposed(&mut self, _expose: &ExposeArea, _cr: &cairo::Context) {} /// Supposed to return the minimum size of the widget. /// /// Default: zero size fn min_size(&self) -> Size { Default::default() } /// Suposed to return true iff the widget is expandable in x-direction /// /// Default: `false` fn width_expandable (&self) -> bool { false } /// Suposed to return true iff the widget is expandable in y-direction /// /// Default: `false` fn height_expandable (&self) -> bool { false } /// Supposed to return true iff the widget can take the focus. /// /// Default: `false` fn takes_focus (&self) -> bool { false } /// Called when the mouse pointer is entering the widget's layout. /// /// Default implementation does nothing. fn pointer_enter(&mut self) {} /// Called when the mouse pointer is leaving the widget's layout. /// /// Default implementation does nothing. fn pointer_leave(&mut self) {} /// Called when the requested reminding time is passed /// /// Supposed to return true, iff the reminder is still needed /// /// Default implementation does nothing and returns false. fn reminder_handler(&mut self) -> bool { false } /// Supposed to return a reference to the `WidgetStub` of the widget /// /// usually implemented by the macro [`widget_stub!()`](../macro.widget_stub.html). fn stub (&self) -> &WidgetStub; /// Supposed to return a mutable reference to the `WidgetStub` of the widget. /// /// Usually implemented by the macro [`widget_stub!()`](../macro.widget_stub.html). fn stub_mut (&mut self) -> &mut WidgetStub; fn ask_for_repaint(&mut self) { self.stub_mut().needs_repaint = true; } /// The widget can request a reminder after `timeout` /// seconds. When the time has passed `reminder_handler() is /// called. /// /// Usually not to be reimplemented. fn request_reminder(&mut self, timeout: f64) { self.stub_mut().reminder_request = Some(timeout); } /// Hands the reminder request over to the UI /// /// Only to be called by the UI as it consumes the reminder request. /// Usually not to be reimplemented. fn reminder_request(&mut self) -> Option<f64> { self.stub_mut().reminder_request.take() } /// Returns true iff the widget is currently focused. /// /// Usually not to be reimplemented. fn has_focus (&self) -> bool { self.stub().has_focus } /// Returns the size of the widget after layouting. /// /// Usually not to be reimplemented. fn size (&self) -> Size { self.stub().layout.size } /// Returns the positon (upper left corner of the widget) /// /// Usually not to be reimplemented. fn pos (&self) -> Coord { self.stub().layout.pos } /// Returns the six scalar values to conveniently describe the widget's geometry /// (left, right, top, bottom, width, height) /// /// Usually not to be reimplemented /// /// Useful in implementations of `::exposed()` when used as /// `let (left, right, top, bottom, width, height) = self.geometry();` /// fn geometry(&self) -> (f64, f64, f64, f64, f64, f64) { let (x, y, w, h) = self.rect(); (x, x+w, y, y+h, w, h) } /// Returns four scalar values to conveniently describe the widget's rectangle /// (x, y, width, height) /// /// Usually not to be reimplemented /// /// Useful in implementations of `::exposed()` when used as /// `let (x, y, w, h) = self.rect();` fn rect(&self) -> (f64, f64, f64, f64) { let x = self.pos().x; let y = self.pos().y; let w = self.size().w; let h = self.size().h; (x, y, w, h) } /// Returns true iff the widget has a defined minimum width /// /// Usually not to be reimplemented. fn sized_width(&self) -> bool { self.min_size().w > 0.0 } /// Returns true iff the widget has a defined minimum height /// /// Usually not to be reimplemented. fn sized_height(&self) -> bool { self.min_size().h > 0.0 } /// Sets the actual width of the widget to `width`. /// /// Usually called by the layouter. /// Usually not to be reimplemented. fn set_width (&mut self, width: f64) { self.stub_mut().layout.size.w = width; } /// Sets the actual height of the widget to `height`. /// /// Usually called by the layouter. /// Usually not to be reimplemented. fn set_height (&mut self, height: f64) { self.stub_mut().layout.size.h = height; } /// Expands the width of the widget by `ammount`. /// /// Usually called by the layouter. /// Usually not to be reimplemented. fn expand_width (&mut self, ammount: f64) { self.stub_mut().layout.size.w += ammount; } /// Expands the width of the widget by `ammount`. /// /// Usually called by the layouter. /// Usually not to be reimplemented. fn expand_height (&mut self, ammount: f64) { self.stub_mut().layout.size.h += ammount; } /// Sets the position of the widget to `pos`. /// /// Usually called by the layouter. /// Usually not to be reimplemented. fn set_pos (&mut self, pos: &Coord) { self.stub_mut().layout.pos = *pos; } /// Sets the position of the widget to `size`. /// /// Usually called by the layouter. /// Usually not to be reimplemented. fn set_size (&mut self, size: &Size) { self.stub_mut().layout.size = *size; } /// Returns the [Layout](struct.Layout.html) (drawing rect) of the widget. /// /// Usually not to be reimplemented. fn layout(&self) -> Layout { self.stub().layout } /// sets the Layout of the widget to `layout` /// /// Probably not needed as only used once in UI fn set_layout(&mut self, layout: &Layout) { self.stub_mut().layout = *layout; } /// Returns true iff the widget is sensitive to user evnets. /// /// Usually not to be reimplemented. fn is_sensitive(&self) -> bool { self.stub().sensitive } /// Returns true iff the widget is currently hovered. /// /// Usually not to be reimplemented. fn is_hovered(&self) -> bool { self.stub().hovered } /// Returns true iff the widget's Layout is containing `pos`. /// /// Usually not to be reimplemented. fn is_hit_by (&self, pos: Coord) -> bool { let layout = self.stub().layout; let x1 = layout.pos.x; let x2 = x1 + layout.size.w; let y1 = layout.pos.y; let y2 = y1 + layout.size.h; (pos.x > x1 && pos.x < x2) && (pos.y > y1 && pos.y < y2) } fn intersects_with(&self, pos: Coord, size: Size) -> bool { let layout = self.layout(); let left = layout.pos.x; let right = left + layout.size.w; let a_left = pos.x; let a_right = pos.x + size.w; if left > a_right || right < a_left { return false; } let top = layout.pos.y; let bottom = top + layout.size.h; let a_top = pos.y; let a_bottom = pos.y + size.h; if top > a_bottom || bottom < a_top { return false; } true } /// Sets the widget's focus state to `yn`. /// /// Usually not to be reimplemented. fn set_focus(&mut self, yn: bool) { let hf = self.stub().has_focus; self.stub_mut().has_focus = yn; if hf != yn { self.stub_mut().needs_repaint = true; } } /// Returns true iff the widget needs to be repainted. /// /// Usually not to be reimplemented. fn needs_repaint(&mut self) -> bool { self.stub_mut().needs_repaint() } /// Wrapper for the `pointer_enter()` event function. /// /// Usually only called by the UI. /// Usually not to be reimplemented. fn pointer_enter_wrap(&mut self) { self.stub_mut().hovered = true; self.ask_for_repaint(); self.pointer_enter(); } /// Wrapper for the `pointer_leave()` event function. /// /// Usually only called by the UI. /// Usually not to be reimplemented. fn pointer_leave_wrap(&mut self) { self.stub_mut().hovered = false; self.ask_for_repaint(); self.pointer_leave(); } } impl_downcast!(sync Widget); /// The rectangle the widget is covering #[derive(Copy, Clone, Default)] pub struct Layout { pub pos: Coord, pub size: Size } /// The stub of a widget. /// /// Contains all the data common to all widgets. pub struct WidgetStub { pub layout: Layout, has_focus: bool, needs_repaint: bool, sensitive: bool, hovered: bool, reminder_request: Option<f64> } impl Default for WidgetStub { fn default() -> WidgetStub { WidgetStub { layout: Layout::default(), has_focus: false, needs_repaint: false, sensitive: true, hovered: false, reminder_request: None } } } impl WidgetStub { fn needs_repaint(&mut self) -> bool { let nrp = self.needs_repaint; self.needs_repaint = false; nrp } } /// A handle of a widget. /// /// Contains the Id of the widget and a `PhantomData` of its actual /// type. When a widget of type `<T: Widget>` is registered in the /// `UI` by [`UI::new_widget()`](../ui/struct.UI.html#method.new_widget) /// an object `WidgetHandle<T>` is returned. As it contains only the /// Id of the widget, it is copyable. /// /// The widget itself can then be borrowed from the `UI` using /// [`UI::widget<T: Widget>()`](../ui/struct.UI.html#method.widget), /// which takes a generic `WidgetHandle` as an argument. So it can /// deduce and downcast the widget to the actual `T`. pub struct WidgetHandle<W: Widget> { id: Id, widget_type: PhantomData<W> } impl<W: Widget> Copy for WidgetHandle<W> { } impl<W: Widget> Clone for WidgetHandle<W> { fn clone(&self) -> WidgetHandle<W> { WidgetHandle::<W> { id: self.id, widget_type: PhantomData::<W> } } } impl<W: Widget> WidgetHandle<W> { pub(crate) fn new(id: Id) -> Self { WidgetHandle::<W> { id, widget_type: PhantomData::<W> } } pub(crate) fn id(&self) -> Id { self.id } } /// Implements [`Widget::stub()`](widget/trait.Widget.html#tymethod.stub) /// and [`Widget::stub_mut()`](widget/trait.Widget.html#tymethod.stub_mut) /// /// Assumes that the trait object implementing /// [`Widget`](widget/trait.Widget.html) has an instance of /// [`WidgetStub`](widget/struct.WidgetStub.html) in a field `stub`. #[macro_export] macro_rules! widget_stub { () => { fn stub (&self) -> &$crate::widget::WidgetStub { &self.stub } fn stub_mut (&mut self) -> &mut $crate::widget::WidgetStub { &mut self.stub } } }