forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 2
/
scrolling.rs
150 lines (135 loc) · 6.41 KB
/
scrolling.rs
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
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate webrender_traits;
#[macro_use]
extern crate lazy_static;
#[path="common/boilerplate.rs"]
mod boilerplate;
use boilerplate::HandyDandyRectBuilder;
use std::sync::Mutex;
use webrender_traits::*;
fn body(_api: &RenderApi,
builder: &mut DisplayListBuilder,
pipeline_id: &PipelineId,
layout_size: &LayoutSize)
{
let bounds = LayoutRect::new(LayoutPoint::zero(), *layout_size);
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
bounds,
None,
TransformStyle::Flat,
None,
webrender_traits::MixBlendMode::Normal,
Vec::new());
if true { // scrolling and clips stuff
// let's make a scrollbox
let scrollbox = (0, 0).to(300, 400);
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
LayoutRect::new(LayoutPoint::new(10.0, 10.0),
LayoutSize::zero()),
None,
TransformStyle::Flat,
None,
webrender_traits::MixBlendMode::Normal,
Vec::new());
// set the scrolling clip
let clip = builder.push_clip_region(&scrollbox, vec![], None);
let clip_id = builder.define_clip((0, 0).to(1000, 1000),
clip,
Some(ClipId::new(42, *pipeline_id)));
builder.push_clip_id(clip_id);
// now put some content into it.
// start with a white background
let clip = builder.push_clip_region(&(0, 0).to(1000, 1000), vec![], None);
builder.push_rect((0, 0).to(500, 500),
clip,
ColorF::new(1.0, 1.0, 1.0, 1.0));
// let's make a 50x50 blue square as a visual reference
let clip = builder.push_clip_region(&(0, 0).to(50, 50), vec![], None);
builder.push_rect((0, 0).to(50, 50),
clip,
ColorF::new(0.0, 0.0, 1.0, 1.0));
// and a 50x50 green square next to it with an offset clip
// to see what that looks like
let clip = builder.push_clip_region(&(60, 10).to(110, 60), vec![], None);
builder.push_rect((50, 0).to(100, 50),
clip,
ColorF::new(0.0, 1.0, 0.0, 1.0));
// Below the above rectangles, set up a nested scrollbox. It's still in
// the same stacking context, so note that the rects passed in need to
// be relative to the stacking context.
let clip = builder.push_clip_region(&(0, 100).to(200, 300), vec![], None);
let nested_clip_id = builder.define_clip((0, 100).to(300, 400),
clip,
Some(ClipId::new(43, *pipeline_id)));
builder.push_clip_id(nested_clip_id);
// give it a giant gray background just to distinguish it and to easily
// visually identify the nested scrollbox
let clip = builder.push_clip_region(&(-1000, -1000).to(5000, 5000), vec![], None);
builder.push_rect((-1000, -1000).to(5000, 5000),
clip,
ColorF::new(0.5, 0.5, 0.5, 1.0));
// add a teal square to visualize the scrolling/clipping behaviour
// as you scroll the nested scrollbox with WASD keys
let clip = builder.push_clip_region(&(0, 100).to(50, 150), vec![], None);
builder.push_rect((0, 100).to(50, 150),
clip,
ColorF::new(0.0, 1.0, 1.0, 1.0));
// just for good measure add another teal square in the bottom-right
// corner of the nested scrollframe content, which can be scrolled into
// view by the user
let clip = builder.push_clip_region(&(250, 350).to(300, 400), vec![], None);
builder.push_rect((250, 350).to(300, 400),
clip,
ColorF::new(0.0, 1.0, 1.0, 1.0));
builder.pop_clip_id(); // nested_clip_id
builder.pop_clip_id(); // clip_id
builder.pop_stacking_context();
}
builder.pop_stacking_context();
}
lazy_static! {
static ref CURSOR_POSITION: Mutex<WorldPoint> = Mutex::new(WorldPoint::zero());
}
fn event_handler(event: &glutin::Event,
api: &RenderApi)
{
match *event {
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
let offset = match key {
glutin::VirtualKeyCode::Down => (0.0, -10.0),
glutin::VirtualKeyCode::Up => (0.0, 10.0),
glutin::VirtualKeyCode::Right => (-10.0, 0.0),
glutin::VirtualKeyCode::Left => (10.0, 0.0),
_ => return,
};
api.scroll(ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
*CURSOR_POSITION.lock().unwrap(),
ScrollEventPhase::Start);
}
glutin::Event::MouseMoved(x, y) => {
*CURSOR_POSITION.lock().unwrap() = WorldPoint::new(x as f32, y as f32);
}
glutin::Event::MouseWheel(delta, _, event_cursor_position) => {
if let Some((x, y)) = event_cursor_position {
*CURSOR_POSITION.lock().unwrap() = WorldPoint::new(x as f32, y as f32);
}
const LINE_HEIGHT: f32 = 38.0;
let (dx, dy) = match delta {
glutin::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
glutin::MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
};
api.scroll(ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
*CURSOR_POSITION.lock().unwrap(),
ScrollEventPhase::Start);
}
_ => ()
}
}
fn main() {
boilerplate::main_wrapper(body, event_handler, None);
}