Skip to content

Commit

Permalink
Refactor DPI scaling and fix the GTK implementation. (#904)
Browse files Browse the repository at this point in the history
  • Loading branch information
xStrom authored May 20, 2020
1 parent 70d5900 commit e397801
Show file tree
Hide file tree
Showing 27 changed files with 915 additions and 431 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
- `Env` and `Key` gained methods for inspecting an `Env` at runtime ([#880] by [@Zarenor])
- `UpdateCtx::request_timer` and `UpdateCtx::request_anim_frame`. ([#898] by [@finnerale])
- `LifeCycleCtx::request_timer`. ([#954] by [@xStrom])
- `scale` method to `WinHandler`. ([#904] by [@xStrom])
- `WinHandler::scale` method to inform of scale changes. ([#904] by [@xStrom])
- `UpdateCtx::size` and `LifeCycleCtx::size`. ([#917] by [@jneem])
- `WidgetExt::debug_widget_id`, for displaying widget ids on hover. ([#876] by [@cmyr])
- `im` feature, with `Data` support for the [`im` crate](https://docs.rs/im/) collections. ([#924] by [@cmyr])
Expand All @@ -61,6 +63,8 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
- Global `Application` associated functions are instance methods instead, e.g. `Application::global().quit()` instead of the old `Application::quit()`. ([#763] by [@xStrom])
- Timer events will only be delivered to the widgets that requested them. ([#831] by [@sjoshid])
- `Event::Wheel` now contains a `MouseEvent` structure. ([#895] by [@teddemunnik])
- The `WindowHandle::get_dpi` method got replaced by `WindowHandle::get_scale`. ([#904] by [@xStrom])
- The `WinHandler::size` method now gets a `Size` in display points. ([#904] by [@xStrom])
- `AppDelegate::command` now receives a `Target` instead of a `&Target`. ([#909] by [@xStrom])
- `SHOW_WINDOW` and `CLOSE_WINDOW` commands now only use `Target` to determine the affected window. ([#928] by [@finnerale])
- Replaced `NEW_WINDOW`, `SET_MENU` and `SHOW_CONTEXT_MENU` commands with methods on `EventCtx` and `DelegateCtx`. ([#931] by [@finnerale])
Expand Down Expand Up @@ -95,6 +99,7 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
- X11: Support individual window closing. ([#900] by [@xStrom])
- X11: Support `Application::quit`. ([#900] by [@xStrom])
- GTK: Support file filters in open/save dialogs. ([#903] by [@jneem])
- GTK: Support DPI values other than 96. ([#904] by [@xStrom])
- X11: Support key and mouse button state. ([#920] by [@jneem])
- Routing `LifeCycle::FocusChanged` to descendant widgets. ([#925] by [@yrns])
- Built-in open and save menu items now show the correct label and submit the right commands. ([#930] by [@finnerale])
Expand Down Expand Up @@ -128,6 +133,7 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
- GTK: Refactored `Application` to use the new structure. ([#892] by [@xStrom])
- X11: Refactored `Application` to use the new structure. ([#894] by [@xStrom])
- X11: Refactored `Window` to support some reentrancy and invalidation. ([#894] by [@xStrom])
- Refactored DPI scaling. ([#904] by [@xStrom])
- Added docs generation testing for all features. ([#942] by [@xStrom])

### Outside News
Expand Down Expand Up @@ -186,6 +192,7 @@ This means that druid no longer requires cairo on macOS and uses Core Graphics i
[#898]: https://github.com/xi-editor/druid/pull/898
[#900]: https://github.com/xi-editor/druid/pull/900
[#903]: https://github.com/xi-editor/druid/pull/903
[#904]: https://github.com/xi-editor/druid/pull/904
[#905]: https://github.com/xi-editor/druid/pull/905
[#909]: https://github.com/xi-editor/druid/pull/909
[#917]: https://github.com/xi-editor/druid/pull/917
Expand Down
8 changes: 7 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/src/widget.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ widgets].

Widgets are intended to be modular and composable, not monolithic. For instance,
widgets generally do not control their own alignment or padding; if you have
a label, and you would like it to have 8px of horizontal padding and 4px of
a label, and you would like it to have 8dp of horizontal padding and 4dp of
vertical padding, you can just do,

```rust,noplaypen
Expand Down
22 changes: 9 additions & 13 deletions druid-shell/examples/invalidate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ use std::any::Any;

use std::time::{Duration, Instant};

use druid_shell::kurbo::{Point, Rect};
use druid_shell::kurbo::{Point, Rect, Size};
use druid_shell::piet::{Color, Piet, RenderContext};

use druid_shell::{Application, TimerToken, WinHandler, WindowBuilder, WindowHandle};

struct InvalidateTest {
handle: WindowHandle,
size: (f64, f64),
size: Size,
start_time: Instant,
color: Color,
rect: Rect,
Expand All @@ -39,10 +39,10 @@ impl InvalidateTest {
(_, _) => Color::rgb8(r, g, b.wrapping_add(10)),
};

self.rect.x0 = (self.rect.x0 + 5.0) % self.size.0;
self.rect.x1 = (self.rect.x1 + 5.5) % self.size.0;
self.rect.y0 = (self.rect.y0 + 3.0) % self.size.1;
self.rect.y1 = (self.rect.y1 + 3.5) % self.size.1;
self.rect.x0 = (self.rect.x0 + 5.0) % self.size.width;
self.rect.x1 = (self.rect.x1 + 5.5) % self.size.width;
self.rect.y0 = (self.rect.y0 + 3.0) % self.size.height;
self.rect.y1 = (self.rect.y1 + 3.5) % self.size.height;
}
}

Expand All @@ -63,12 +63,8 @@ impl WinHandler for InvalidateTest {
false
}

fn size(&mut self, width: u32, height: u32) {
let dpi = self.handle.get_dpi();
let dpi_scale = dpi as f64 / 96.0;
let width_f = (width as f64) / dpi_scale;
let height_f = (height as f64) / dpi_scale;
self.size = (width_f, height_f);
fn size(&mut self, size: Size) {
self.size = size;
}

fn command(&mut self, id: u32) {
Expand All @@ -91,7 +87,7 @@ fn main() {
let app = Application::new().unwrap();
let mut builder = WindowBuilder::new(app.clone());
let inv_test = InvalidateTest {
size: Default::default(),
size: Size::ZERO,
handle: Default::default(),
start_time: Instant::now(),
rect: Rect::from_origin_size(Point::ZERO, (10.0, 20.0)),
Expand Down
23 changes: 11 additions & 12 deletions druid-shell/examples/perftest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::any::Any;

use time::Instant;

use piet_common::kurbo::{Line, Rect};
use piet_common::kurbo::{Line, Rect, Size};
use piet_common::{Color, FontBuilder, Piet, RenderContext, Text, TextLayoutBuilder};

use druid_shell::{Application, KeyEvent, WinHandler, WindowBuilder, WindowHandle};
Expand All @@ -26,7 +26,7 @@ const FG_COLOR: Color = Color::rgb8(0xf0, 0xf0, 0xea);

struct PerfTest {
handle: WindowHandle,
size: (f64, f64),
size: Size,
start_time: Instant,
last_time: Instant,
}
Expand All @@ -37,11 +37,14 @@ impl WinHandler for PerfTest {
}

fn paint(&mut self, piet: &mut Piet, _: Rect) -> bool {
let (width, height) = self.size;
let rect = Rect::new(0.0, 0.0, width, height);
let rect = self.size.to_rect();
piet.fill(rect, &BG_COLOR);

piet.stroke(Line::new((0.0, height), (width, 0.0)), &FG_COLOR, 1.0);
piet.stroke(
Line::new((0.0, self.size.height), (self.size.width, 0.0)),
&FG_COLOR,
1.0,
);

let current_ns = (Instant::now() - self.start_time).whole_nanoseconds();
let th = ::std::f64::consts::PI * (current_ns as f64) * 2e-9;
Expand Down Expand Up @@ -98,12 +101,8 @@ impl WinHandler for PerfTest {
false
}

fn size(&mut self, width: u32, height: u32) {
let dpi = self.handle.get_dpi();
let dpi_scale = dpi as f64 / 96.0;
let width_f = (width as f64) / dpi_scale;
let height_f = (height as f64) / dpi_scale;
self.size = (width_f, height_f);
fn size(&mut self, size: Size) {
self.size = size;
}

fn destroy(&mut self) {
Expand All @@ -119,7 +118,7 @@ fn main() {
let app = Application::new().unwrap();
let mut builder = WindowBuilder::new(app.clone());
let perf_test = PerfTest {
size: Default::default(),
size: Size::ZERO,
handle: Default::default(),
start_time: time::Instant::now(),
last_time: time::Instant::now(),
Expand Down
15 changes: 5 additions & 10 deletions druid-shell/examples/shello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use std::any::Any;

use druid_shell::kurbo::{Line, Rect};
use druid_shell::kurbo::{Line, Rect, Size};
use druid_shell::piet::{Color, RenderContext};

use druid_shell::{
Expand All @@ -27,7 +27,7 @@ const FG_COLOR: Color = Color::rgb8(0xf0, 0xf0, 0xea);

#[derive(Default)]
struct HelloState {
size: (f64, f64),
size: Size,
handle: WindowHandle,
}

Expand All @@ -37,8 +37,7 @@ impl WinHandler for HelloState {
}

fn paint(&mut self, piet: &mut piet_common::Piet, _: Rect) -> bool {
let (width, height) = self.size;
let rect = Rect::new(0.0, 0.0, width, height);
let rect = self.size.to_rect();
piet.fill(rect, &BG_COLOR);
piet.stroke(Line::new((10.0, 50.0), (90.0, 90.0)), &FG_COLOR, 1.0);
false
Expand Down Expand Up @@ -92,12 +91,8 @@ impl WinHandler for HelloState {
println!("timer fired: {:?}", id);
}

fn size(&mut self, width: u32, height: u32) {
let dpi = self.handle.get_dpi();
let dpi_scale = dpi as f64 / 96.0;
let width_f = (width as f64) / dpi_scale;
let height_f = (height as f64) / dpi_scale;
self.size = (width_f, height_f);
fn size(&mut self, size: Size) {
self.size = size;
}

fn destroy(&mut self) {
Expand Down
62 changes: 58 additions & 4 deletions druid-shell/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ use std::fmt;

use crate::platform::error as platform;

/// Error codes. At the moment, this is little more than HRESULT, but that
/// might change.
/// Shell errors.
#[derive(Debug, Clone)]
pub enum Error {
/// The Application instance has already been created.
ApplicationAlreadyExists,
Other(&'static str),
/// The window has already been destroyed.
WindowDropped,
/// Runtime borrow failure.
BorrowError(BorrowError),
/// Platform specific error.
Platform(platform::Error),
/// Other miscellaneous error.
Other(&'static str),
}

impl fmt::Display for Error {
Expand All @@ -33,8 +39,10 @@ impl fmt::Display for Error {
Error::ApplicationAlreadyExists => {
write!(f, "An application instance has already been created.")
}
Error::WindowDropped => write!(f, "The window has already been destroyed."),
Error::BorrowError(err) => fmt::Display::fmt(err, f),
Error::Platform(err) => fmt::Display::fmt(err, f),
Error::Other(s) => write!(f, "{}", s),
Error::Platform(p) => fmt::Display::fmt(&p, f),
}
}
}
Expand All @@ -46,3 +54,49 @@ impl From<platform::Error> for Error {
Error::Platform(src)
}
}

/// Runtime borrow failure.
#[derive(Debug, Clone)]
pub struct BorrowError {
location: &'static str,
target: &'static str,
mutable: bool,
}

impl BorrowError {
pub fn new(location: &'static str, target: &'static str, mutable: bool) -> BorrowError {
BorrowError {
location,
target,
mutable,
}
}
}

impl fmt::Display for BorrowError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
if self.mutable {
// Mutable borrow fails when any borrow exists
write!(
f,
"{} was already borrowed in {}",
self.target, self.location
)
} else {
// Regular borrow fails when a mutable borrow exists
write!(
f,
"{} was already mutably borrowed in {}",
self.target, self.location
)
}
}
}

impl std::error::Error for BorrowError {}

impl From<BorrowError> for Error {
fn from(src: BorrowError) -> Error {
Error::BorrowError(src)
}
}
2 changes: 2 additions & 0 deletions druid-shell/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ mod keycodes;
mod menu;
mod mouse;
mod platform;
mod scale;
mod util;
mod window;

Expand All @@ -48,6 +49,7 @@ pub use keyboard::{KeyEvent, KeyModifiers};
pub use keycodes::KeyCode;
pub use menu::Menu;
pub use mouse::{Cursor, MouseButton, MouseButtons, MouseEvent};
pub use scale::{Scalable, Scale, ScaledArea};
pub use window::{
IdleHandle, IdleToken, Text, TimerToken, WinHandler, WindowBuilder, WindowHandle,
};
4 changes: 2 additions & 2 deletions druid-shell/src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ use crate::keyboard::KeyModifiers;
/// receiving a move event before another mouse event.
#[derive(Debug, Clone, PartialEq)]
pub struct MouseEvent {
/// The location of the mouse in the current window.
/// The location of the mouse in [display points] in relation to the current window.
///
/// This is in px units not device pixels, that is, adjusted for hi-dpi.
/// [display points]: struct.Scale.html
pub pos: Point,
/// Mouse buttons being held down during a move or after a click event.
/// Thus it will contain the `button` that triggered a mouse-down event,
Expand Down
Loading

0 comments on commit e397801

Please sign in to comment.