Skip to content

Commit

Permalink
Use Handled instead of bools. (#1298)
Browse files Browse the repository at this point in the history
Co-authored-by: Leopold Luley <[email protected]>
  • Loading branch information
jneem and luleyleo authored Oct 11, 2020
1 parent 93620d1 commit e6bba98
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 44 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ You can find its changes [documented below](#060---2020-06-01).
- Window construction: WindowDesc decomposed to PendingWindow and WindowConfig to allow for sub-windows and reconfiguration. ([#1235] by [@rjwittams])
- `LocalizedString` and `LabelText` use `ArcStr` instead of String ([#1245] by [@cmyr])
- `LensWrap` widget moved into widget module ([#1251] by [@cmyr])
- `Delegate::command` now returns `Handled`, not `bool` ([#1298] by [@jneem])

### Deprecated

Expand Down Expand Up @@ -492,6 +493,7 @@ Last release without a changelog :(
[#1276]: https://github.com/linebender/druid/pull/1276
[#1278]: https://github.com/linebender/druid/pull/1278
[#1280]: https://github.com/linebender/druid/pull/1280
[#1298]: https://github.com/linebender/druid/pull/1298

[Unreleased]: https://github.com/linebender/druid/compare/v0.6.0...master
[0.6.0]: https://github.com/linebender/druid/compare/v0.5.0...v0.6.0
Expand Down
8 changes: 5 additions & 3 deletions druid/examples/blocking_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use druid::{

use druid::{
widget::{Button, Either, Flex, Label, Spinner},
Target,
Handled, Target,
};

const FINISH_SLOW_FUNCTION: Selector<u32> = Selector::new("finish_slow_function");
Expand Down Expand Up @@ -59,12 +59,14 @@ impl AppDelegate<AppState> for Delegate {
cmd: &Command,
data: &mut AppState,
_env: &Env,
) -> bool {
) -> Handled {
if let Some(number) = cmd.get(FINISH_SLOW_FUNCTION) {
data.processing = false;
data.value = *number;
Handled::Yes
} else {
Handled::No
}
true
}
}

Expand Down
17 changes: 9 additions & 8 deletions druid/examples/multiwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use druid::widget::{
use druid::Target::Global;
use druid::{
commands as sys_cmds, AppDelegate, AppLauncher, Application, Color, Command, ContextMenu, Data,
DelegateCtx, LocalizedString, MenuDesc, MenuItem, Selector, Target, WindowDesc, WindowId,
DelegateCtx, Handled, LocalizedString, MenuDesc, MenuItem, Selector, Target, WindowDesc,
WindowId,
};
use log::info;

Expand Down Expand Up @@ -153,22 +154,22 @@ impl AppDelegate<State> for Delegate {
cmd: &Command,
data: &mut State,
_env: &Env,
) -> bool {
) -> Handled {
match cmd {
_ if cmd.is(sys_cmds::NEW_FILE) => {
let new_win = WindowDesc::new(ui_builder)
.menu(make_menu(data))
.window_size((data.selected as f64 * 100.0 + 300.0, 500.0));
ctx.new_window(new_win);
false
Handled::Yes
}
_ if cmd.is(MENU_COUNT_ACTION) => {
data.selected = *cmd.get_unchecked(MENU_COUNT_ACTION);
let menu = make_menu::<State>(data);
for id in &self.windows {
ctx.set_menu(menu.clone(), *id);
}
false
Handled::Yes
}
// wouldn't it be nice if a menu (like a button) could just mutate state
// directly if desired?
Expand All @@ -178,21 +179,21 @@ impl AppDelegate<State> for Delegate {
for id in &self.windows {
ctx.set_menu(menu.clone(), *id);
}
false
Handled::Yes
}
_ if cmd.is(MENU_DECREMENT_ACTION) => {
data.menu_count = data.menu_count.saturating_sub(1);
let menu = make_menu::<State>(data);
for id in &self.windows {
ctx.set_menu(menu.clone(), *id);
}
false
Handled::Yes
}
_ if cmd.is(MENU_SWITCH_GLOW_ACTION) => {
data.glow_hot = !data.glow_hot;
false
Handled::Yes
}
_ => true,
_ => Handled::No,
}
}

Expand Down
10 changes: 5 additions & 5 deletions druid/examples/open_save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use druid::widget::{Align, Button, Flex, TextBox};
use druid::{
commands, AppDelegate, AppLauncher, Command, DelegateCtx, Env, FileDialogOptions, FileSpec,
LocalizedString, Target, Widget, WindowDesc,
Handled, LocalizedString, Target, Widget, WindowDesc,
};

struct Delegate;
Expand Down Expand Up @@ -84,12 +84,12 @@ impl AppDelegate<String> for Delegate {
cmd: &Command,
data: &mut String,
_env: &Env,
) -> bool {
) -> Handled {
if let Some(Some(file_info)) = cmd.get(commands::SAVE_FILE) {
if let Err(e) = std::fs::write(file_info.path(), &data[..]) {
println!("Error writing file: {}", e);
}
return false;
return Handled::Yes;
}
if let Some(file_info) = cmd.get(commands::OPEN_FILE) {
match std::fs::read_to_string(file_info.path()) {
Expand All @@ -101,8 +101,8 @@ impl AppDelegate<String> for Delegate {
println!("Error opening file: {}", e);
}
}
return false;
return Handled::Yes;
}
true
Handled::No
}
}
8 changes: 4 additions & 4 deletions druid/src/app_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use std::any::{Any, TypeId};

use crate::{
commands, core::CommandQueue, Command, Data, Env, Event, MenuDesc, SingleUse, Target,
commands, core::CommandQueue, Command, Data, Env, Event, Handled, MenuDesc, SingleUse, Target,
WindowDesc, WindowId,
};

Expand Down Expand Up @@ -122,7 +122,7 @@ pub trait AppDelegate<T: Data> {
/// This function is called with each ([`Target`], [`Command`]) pair before
/// they are sent down the tree.
///
/// If your implementation returns `true`, the command will be sent down
/// If your implementation returns `Handled::No`, the command will be sent down
/// the widget tree. Otherwise it will not.
///
/// To do anything fancier than this, you can submit arbitary commands
Expand All @@ -138,8 +138,8 @@ pub trait AppDelegate<T: Data> {
cmd: &Command,
data: &mut T,
env: &Env,
) -> bool {
true
) -> Handled {
Handled::No
}

/// The handler for window creation events.
Expand Down
1 change: 1 addition & 0 deletions druid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ pub use localization::LocalizedString;
pub use menu::{sys as platform_menus, ContextMenu, MenuDesc, MenuItem};
pub use mouse::MouseEvent;
pub use text::{ArcStr, FontDescriptor, TextLayout};
pub use util::Handled;
pub use widget::{Widget, WidgetExt, WidgetId};
pub use win_handler::DruidHandler;
pub use window::{Window, WindowId};
Expand Down
27 changes: 27 additions & 0 deletions druid/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,30 @@ where
}
}
}

/// An enum for specifying whether an event was handled.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Handled {
/// An event was already handled, and shouldn't be propagated to other event handlers.
Yes,
/// An event has not yet been handled.
No,
}

impl Handled {
/// Has the event been handled yet?
pub fn is_handled(self) -> bool {
self == Handled::Yes
}
}

impl From<bool> for Handled {
/// Returns `Handled::Yes` if `handled` is true, and `Handled::No` otherwise.
fn from(handled: bool) -> Handled {
if handled {
Handled::Yes
} else {
Handled::No
}
}
}
45 changes: 25 additions & 20 deletions druid/src/win_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::ext_event::{ExtEventHost, ExtEventSink};
use crate::menu::ContextMenu;
use crate::window::Window;
use crate::{
Command, Data, Env, Event, InternalEvent, KeyEvent, MenuDesc, PlatformError, Target,
Command, Data, Env, Event, Handled, InternalEvent, KeyEvent, MenuDesc, PlatformError, Target,
TimerToken, WindowDesc, WindowId,
};

Expand Down Expand Up @@ -207,9 +207,9 @@ impl<T: Data> Inner<T> {
}
}

fn delegate_cmd(&mut self, cmd: &Command) -> bool {
fn delegate_cmd(&mut self, cmd: &Command) -> Handled {
self.with_delegate(|del, data, env, ctx| del.command(ctx, cmd.target(), cmd, data, env))
.unwrap_or(true)
.unwrap_or(Handled::No)
}

fn connect(&mut self, id: WindowId, handle: WindowHandle) {
Expand Down Expand Up @@ -319,23 +319,23 @@ impl<T: Data> Inner<T> {
}
}

/// Returns `true` if the command was handled.
fn dispatch_cmd(&mut self, cmd: Command) -> bool {
if !self.delegate_cmd(&cmd) {
self.do_update();
return true;
fn dispatch_cmd(&mut self, cmd: Command) -> Handled {
let handled = self.delegate_cmd(&cmd);
self.do_update();
if handled.is_handled() {
return handled;
}

match cmd.target() {
Target::Window(id) => {
// first handle special window-level events
if cmd.is(sys_cmd::SET_MENU) {
self.set_menu(id, &cmd);
return true;
return Handled::Yes;
}
if cmd.is(sys_cmd::SHOW_CONTEXT_MENU) {
self.show_context_menu(id, &cmd);
return true;
return Handled::Yes;
}
if let Some(w) = self.windows.get_mut(id) {
let event = Event::Command(cmd);
Expand All @@ -347,27 +347,31 @@ impl<T: Data> Inner<T> {
Target::Widget(id) => {
for w in self.windows.iter_mut().filter(|w| w.may_contain_widget(id)) {
let event = Event::Internal(InternalEvent::TargetedCommand(cmd.clone()));
if w.event(&mut self.command_queue, event, &mut self.data, &self.env) {
return true;
if w.event(&mut self.command_queue, event, &mut self.data, &self.env)
.is_handled()
{
return Handled::Yes;
}
}
}
Target::Global => {
for w in self.windows.iter_mut() {
let event = Event::Command(cmd.clone());
if w.event(&mut self.command_queue, event, &mut self.data, &self.env) {
return true;
if w.event(&mut self.command_queue, event, &mut self.data, &self.env)
.is_handled()
{
return Handled::Yes;
}
}
}
Target::Auto => {
log::error!("{:?} reached window handler with `Target::Auto`", cmd);
}
}
false
Handled::No
}

fn do_window_event(&mut self, source_id: WindowId, event: Event) -> bool {
fn do_window_event(&mut self, source_id: WindowId, event: Event) -> Handled {
match event {
Event::Command(..) | Event::Internal(InternalEvent::TargetedCommand(..)) => {
panic!("commands should be dispatched via dispatch_cmd");
Expand All @@ -378,13 +382,13 @@ impl<T: Data> Inner<T> {
// if the event was swallowed by the delegate we consider it handled?
let event = match self.delegate_event(source_id, event) {
Some(event) => event,
None => return true,
None => return Handled::Yes,
};

if let Some(win) = self.windows.get_mut(source_id) {
win.event(&mut self.command_queue, event, &mut self.data, &self.env)
} else {
false
Handled::No
}
}

Expand Down Expand Up @@ -490,7 +494,7 @@ impl<T: Data> AppState<T> {
///
/// This is principally because in certain cases (such as keydown on Windows)
/// the OS needs to know if an event was handled.
fn do_window_event(&mut self, event: Event, window_id: WindowId) -> bool {
fn do_window_event(&mut self, event: Event, window_id: WindowId) -> Handled {
let result = self.inner.borrow_mut().do_window_event(window_id, event);
self.process_commands();
self.inner.borrow_mut().do_update();
Expand Down Expand Up @@ -582,7 +586,7 @@ impl<T: Data> AppState<T> {
T::Window(id) if cmd.is(sys_cmd::SHOW_SAVE_PANEL) => self.show_save_panel(cmd, id),
T::Window(id) if cmd.is(sys_cmd::CONFIGURE_WINDOW) => self.configure_window(cmd, id),
T::Window(id) if cmd.is(sys_cmd::CLOSE_WINDOW) => {
if !self.inner.borrow_mut().dispatch_cmd(cmd) {
if !self.inner.borrow_mut().dispatch_cmd(cmd).is_handled() {
self.request_close_window(id);
}
}
Expand Down Expand Up @@ -779,6 +783,7 @@ impl<T: Data> WinHandler for DruidHandler<T> {
fn key_down(&mut self, event: KeyEvent) -> bool {
self.app_state
.do_window_event(Event::KeyDown(event), self.window_id)
.is_handled()
}

fn key_up(&mut self, event: KeyEvent) {
Expand Down
8 changes: 4 additions & 4 deletions druid/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::util::ExtendDrain;
use crate::widget::LabelText;
use crate::win_handler::RUN_COMMANDS_TOKEN;
use crate::{
BoxConstraints, Command, Data, Env, Event, EventCtx, ExtEventSink, InternalEvent,
BoxConstraints, Command, Data, Env, Event, EventCtx, ExtEventSink, Handled, InternalEvent,
InternalLifeCycle, LayoutCtx, LifeCycle, LifeCycleCtx, MenuDesc, PaintCtx, Point, Size,
TimerToken, UpdateCtx, Widget, WidgetId, WidgetPod,
};
Expand Down Expand Up @@ -173,7 +173,7 @@ impl<T: Data> Window<T> {
event: Event,
data: &mut T,
env: &Env,
) -> bool {
) -> Handled {
match &event {
Event::WindowSize(size) => self.size = *size,
Event::MouseDown(e) | Event::MouseUp(e) | Event::MouseMove(e) | Event::Wheel(e) => {
Expand All @@ -194,7 +194,7 @@ impl<T: Data> Window<T> {
Event::Internal(InternalEvent::RouteTimer(token, *widget_id))
} else {
log::error!("No widget found for timer {:?}", token);
return false;
return Handled::No;
}
}
other => other,
Expand Down Expand Up @@ -223,7 +223,7 @@ impl<T: Data> Window<T> {
};

self.root.event(&mut ctx, &event, data, env);
ctx.is_handled
Handled::from(ctx.is_handled)
};

// Clean up the timer token and do it immediately after the event handling
Expand Down

0 comments on commit e6bba98

Please sign in to comment.