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
// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License in the LICENSE-APACHE file or at: // https://www.apache.org/licenses/LICENSE-2.0 //! Event handling: Response type use super::VoidResponse; use kas::geom::Rect; /// Response type from [`Handler::handle`]. /// /// This type wraps [`Handler::Msg`] allowing both custom messages and toolkit /// messages. /// /// [`Handler::handle`]: super::Handler::handle /// [`Handler::Msg`]: super::Handler::Msg #[derive(Clone, Debug)] #[must_use] pub enum Response<M> { /// Nothing of external interest /// /// This implies that the event was consumed, but does not affect parents. /// Note that we consider "view changes" (i.e. scrolling) to not be of /// external interest. None, /// Unhandled event /// /// Indicates that the event was not consumed. An ancestor or the event /// manager is thus able to make use of this event. Unhandled, /// (Keyboard) focus has changed. This region should be made visible. Focus(Rect), /// Widget wishes to be selected (or have selection status toggled) Select, /// Notify of update to widget's data /// /// Widgets which hold editable data should return either this or /// [`Response::Msg`] on handling events which update that data. /// Note: scrolling/adjusting a view is not considered a data update. Update, /// Custom message type /// /// This signals a (possible) update to the widget's data, while passing a /// data payload to the parent widget. Msg(M), } // Unfortunately we cannot write generic `From` / `TryFrom` impls // due to trait coherence rules, so we impl `from` etc. directly. impl<M> Response<M> { /// Construct `None` or `Msg(msg)` #[inline] pub fn none_or_msg(opt_msg: Option<M>) -> Self { match opt_msg { None => Response::None, Some(msg) => Response::Msg(msg), } } /// Construct `Update` or `Msg(msg)` #[inline] pub fn update_or_msg(opt_msg: Option<M>) -> Self { match opt_msg { None => Response::Update, Some(msg) => Response::Msg(msg), } } /// True if variant is `None` #[inline] pub fn is_none(&self) -> bool { match self { &Response::None => true, _ => false, } } /// True if variant is `Unhandled` #[inline] pub fn is_unhandled(&self) -> bool { match self { &Response::Unhandled => true, _ => false, } } /// True if variant is `Msg` #[inline] pub fn is_msg(&self) -> bool { match self { &Response::Msg(_) => true, _ => false, } } /// Map from one `Response` type to another /// /// Once Rust supports specialisation, this will likely be replaced with a /// `From` implementation. #[inline] pub fn from<N>(r: Response<N>) -> Self where N: Into<M>, { r.try_into().unwrap_or_else(|msg| Response::Msg(msg.into())) } /// Map one `Response` type into another /// /// Once Rust supports specialisation, this will likely be redundant. #[inline] pub fn into<N>(self) -> Response<N> where M: Into<N>, { Response::from(self) } /// Try mapping from one `Response` type to another, failing on `Msg` /// variant and returning the payload. #[inline] pub fn try_from<N>(r: Response<N>) -> Result<Self, N> { use Response::*; match r { None => Ok(None), Unhandled => Ok(Unhandled), Focus(rect) => Ok(Focus(rect)), Select => Ok(Select), Update => Ok(Update), Msg(m) => Err(m), } } /// Try mapping one `Response` type into another, failing on `Msg` /// variant and returning the payload. #[inline] pub fn try_into<N>(self) -> Result<Response<N>, M> { Response::try_from(self) } } impl VoidResponse { /// Convert a `Response<VoidMsg>` to another `Response` pub fn void_into<M>(self) -> Response<M> { self.try_into().unwrap_or(Response::None) } } impl<M> From<M> for Response<M> { fn from(msg: M) -> Self { Response::Msg(msg) } }