Skip to content

Commit ec93adb

Browse files
0HyperCubeTrueDoctor
authored andcommitted
Improve scrollbar behavior (#351)
* Change scrollbar behavior * Leave space at the end of the scrollbar * Change mid to center * Use shorter array initialization * Add space around scrollbar * Fix scrollbar spacing * Smooth end of scrollbars * Add page up and down * Page up and down on click in scrollbar track * Add shift pageup to translate horizontally
1 parent ae390f5 commit ec93adb

File tree

10 files changed

+64
-17
lines changed

10 files changed

+64
-17
lines changed

editor/src/consts.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ pub const LINE_ROTATE_SNAP_ANGLE: f64 = 15.;
1919
// SELECT TOOL
2020
pub const SELECTION_TOLERANCE: f64 = 1.0;
2121

22+
// SCROLLBARS
23+
pub const SCROLLBAR_SPACING: f64 = 0.1;
24+
pub const ASYMPTOTIC_EFFECT: f64 = 0.5;
25+
pub const SCALE_EFFECT: f64 = 0.5;
26+
2227
pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document";
2328
pub const FILE_SAVE_SUFFIX: &str = ".graphite";
2429
pub const FILE_EXPORT_SUFFIX: &str = ".svg";

editor/src/document/document_file.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pub use super::layer_panel::*;
22
use crate::{
3-
consts::{FILE_EXPORT_SUFFIX, FILE_SAVE_SUFFIX},
3+
consts::{ASYMPTOTIC_EFFECT, FILE_EXPORT_SUFFIX, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING},
44
EditorError,
55
};
66
use glam::{DAffine2, DVec2};
@@ -313,13 +313,13 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
313313
)
314314
}
315315
CreateFolder(mut path) => {
316-
let id = generate_hash(responses.iter(), ipp, self.document.hash());
316+
let id = generate_uuid();
317317
path.push(id);
318318
self.layerdata_mut(&path).expanded = true;
319319
responses.push_back(DocumentOperation::CreateFolder { path }.into())
320320
}
321321
GroupSelectedLayers => {
322-
let id = generate_hash(responses.iter(), ipp, self.document.hash());
322+
let id = generate_uuid();
323323
responses.push_back(DocumentsMessage::CopySelectedLayers.into());
324324
responses.push_back(DocumentMessage::DeleteSelectedLayers.into());
325325
responses.push_back(DocumentOperation::CreateFolder { path: vec![id] }.into());
@@ -413,15 +413,16 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
413413
}
414414
.into(),
415415
);
416-
let root = self.layerdata(&[]);
417-
let viewport = ipp.viewport_bounds.size();
418-
let [bounds1, bounds2] = self.document.visible_layers_bounding_box().unwrap_or_default();
419-
let bounds1 = bounds1.min(DVec2::ZERO) - viewport * (f64::powf(2., root.scale / 3.) * 0.5);
420-
let bounds2 = bounds2.max(viewport) + viewport * (f64::powf(2., root.scale / 3.) * 0.5);
421-
let bounds_length = bounds2 - bounds1;
422-
let scrollbar_multiplier = bounds_length - viewport;
423-
let scrollbar_position = bounds1.abs() / scrollbar_multiplier;
424-
let scrollbar_size = viewport / bounds_length;
416+
let scale = 0.5 + ASYMPTOTIC_EFFECT + self.layerdata(&[]).scale * SCALE_EFFECT;
417+
let viewport_size = ipp.viewport_bounds.size();
418+
let viewport_mid = ipp.viewport_bounds.center();
419+
let [bounds1, bounds2] = self.document.visible_layers_bounding_box().unwrap_or([viewport_mid; 2]);
420+
let bounds1 = bounds1.min(viewport_mid) - viewport_size * scale;
421+
let bounds2 = bounds2.max(viewport_mid) + viewport_size * scale;
422+
let bounds_length = (bounds2 - bounds1) * (1. + SCROLLBAR_SPACING);
423+
let scrollbar_position = DVec2::splat(0.5) - (bounds1.lerp(bounds2, 0.5) - viewport_mid) / (bounds_length - viewport_size);
424+
let scrollbar_multiplier = bounds_length - viewport_size;
425+
let scrollbar_size = viewport_size / bounds_length;
425426
responses.push_back(
426427
FrontendMessage::UpdateScrollbars {
427428
position: scrollbar_position.into(),

editor/src/document/movement_handler.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ pub enum MovementMessage {
3030
DecreaseCanvasZoom,
3131
WheelCanvasZoom,
3232
ZoomCanvasToFitAll,
33-
TranslateCanvas(glam::DVec2),
33+
TranslateCanvas(DVec2),
34+
TranslateCanvasByViewportFraction(DVec2),
3435
}
3536

3637
#[derive(Debug, Clone, Default, PartialEq)]
@@ -193,6 +194,12 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
193194
TranslateCanvas(delta) => {
194195
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
195196

197+
layerdata.translation += transformed_delta;
198+
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
199+
}
200+
TranslateCanvasByViewportFraction(delta) => {
201+
let transformed_delta = document.root.transform.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
202+
196203
layerdata.translation += transformed_delta;
197204
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
198205
}
@@ -212,6 +219,8 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
212219
DecreaseCanvasZoom,
213220
WheelCanvasTranslate,
214221
ZoomCanvasToFitAll,
222+
TranslateCanvas,
223+
TranslateCanvasByViewportFraction,
215224
);
216225

217226
if self.rotating {

editor/src/input/input_mapper.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use glam::DAffine2;
1+
use glam::{DAffine2, DVec2};
22
use graphene::{layers::style, Operation};
33

44
use super::{
@@ -204,6 +204,7 @@ impl Default for Mapping {
204204
entry! {action=DocumentMessage::ExportDocument, key_down=KeyE, modifiers=[KeyControl]},
205205
entry! {action=DocumentMessage::SaveDocument, key_down=KeyS, modifiers=[KeyControl]},
206206
entry! {action=DocumentMessage::SaveDocument, key_down=KeyS, modifiers=[KeyControl, KeyShift]},
207+
// Document movement
207208
entry! {action=MovementMessage::MouseMove, message=InputMapperMessage::PointerMove},
208209
entry! {action=MovementMessage::RotateCanvasBegin{snap:false}, key_down=Mmb, modifiers=[KeyControl]},
209210
entry! {action=MovementMessage::RotateCanvasBegin{snap:true}, key_down=Mmb, modifiers=[KeyControl, KeyShift]},
@@ -219,6 +220,11 @@ impl Default for Mapping {
219220
entry! {action=MovementMessage::WheelCanvasZoom, message=InputMapperMessage::MouseScroll, modifiers=[KeyControl]},
220221
entry! {action=MovementMessage::WheelCanvasTranslate{use_y_as_x: true}, message=InputMapperMessage::MouseScroll, modifiers=[KeyShift]},
221222
entry! {action=MovementMessage::WheelCanvasTranslate{use_y_as_x: false}, message=InputMapperMessage::MouseScroll},
223+
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(1., 0.)), key_down=KeyPageUp, modifiers=[KeyShift]},
224+
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(-1., 0.)), key_down=KeyPageDown, modifiers=[KeyShift]},
225+
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(0., 1.)), key_down=KeyPageUp},
226+
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(0., -1.)), key_down=KeyPageDown},
227+
// Document actions
222228
entry! {action=DocumentsMessage::NewDocument, key_down=KeyN, modifiers=[KeyControl]},
223229
entry! {action=DocumentsMessage::NextDocument, key_down=KeyTab, modifiers=[KeyControl]},
224230
entry! {action=DocumentsMessage::PrevDocument, key_down=KeyTab, modifiers=[KeyControl, KeyShift]},
@@ -227,6 +233,7 @@ impl Default for Mapping {
227233
entry! {action=DocumentMessage::DuplicateSelectedLayers, key_down=KeyD, modifiers=[KeyControl]},
228234
entry! {action=DocumentsMessage::CopySelectedLayers, key_down=KeyC, modifiers=[KeyControl]},
229235
entry! {action=DocumentMessage::GroupSelectedLayers, key_down=KeyG},
236+
// Nudging
230237
entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowLeft]},
231238
entry! {action=DocumentMessage::NudgeSelectedLayers(SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowRight]},
232239
entry! {action=DocumentMessage::NudgeSelectedLayers(0., -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift]},

editor/src/input/keyboard.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ pub enum Key {
7676
KeyRightBracket,
7777
KeyLeftCurlyBracket,
7878
KeyRightCurlyBracket,
79+
KeyPageUp,
80+
KeyPageDown,
7981

8082
// This has to be the last element in the enum.
8183
NumKeys,

editor/src/input/mouse.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ impl ViewportBounds {
2222
pub fn size(&self) -> DVec2 {
2323
self.bottom_right - self.top_left
2424
}
25+
26+
pub fn center(&self) -> DVec2 {
27+
self.bottom_right.lerp(self.top_left, 0.5)
28+
}
2529
}
2630

2731
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]

frontend/src/components/panels/Document.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
:handlePosition="scrollbarPos.y"
129129
@update:handlePosition="translateCanvasY"
130130
v-model:handleLength="scrollbarSize.y"
131+
@pressTrack="pageY"
131132
:class="'right-scrollbar'"
132133
/>
133134
</LayoutCol>
@@ -138,6 +139,7 @@
138139
:handlePosition="scrollbarPos.x"
139140
@update:handlePosition="translateCanvasX"
140141
v-model:handleLength="scrollbarSize.x"
142+
@pressTrack="pageX"
141143
:class="'bottom-scrollbar'"
142144
/>
143145
</LayoutRow>
@@ -293,6 +295,14 @@ export default defineComponent({
293295
this.scrollbarPos.y = newValue;
294296
(await wasm).translate_canvas(0, -delta * this.scrollbarMultiplier.y);
295297
},
298+
async pageX(delta: number) {
299+
const move = delta < 0 ? 1 : -1;
300+
(await wasm).translate_canvas_by_fraction(move, 0);
301+
},
302+
async pageY(delta: number) {
303+
const move = delta < 0 ? 1 : -1;
304+
(await wasm).translate_canvas_by_fraction(0, move);
305+
},
296306
async selectTool(toolName: string) {
297307
(await wasm).select_tool(toolName);
298308
},

frontend/src/components/widgets/scrollbars/PersistentScrollbar.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,9 @@ export default defineComponent({
186186
},
187187
grabArea(e: MouseEvent) {
188188
if (!this.dragging) {
189-
this.dragging = true;
190-
this.mousePos = mousePosition(this.direction, e);
191-
this.clampHandlePosition(((this.mousePos - this.trackOffset()) / this.trackLength() - this.handleLength / 2) / (1 - this.handleLength));
189+
const mousePos = mousePosition(this.direction, e);
190+
const oldMouse = handleToTrack(this.handleLength, this.handlePosition) * this.trackLength() + this.trackOffset();
191+
this.$emit("pressTrack", mousePos - oldMouse);
192192
}
193193
},
194194
mouseUp() {

frontend/wasm/src/document.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,13 @@ pub fn translate_canvas(delta_x: f64, delta_y: f64) -> Result<(), JsValue> {
312312
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error)
313313
}
314314

315+
/// Translates document (in viewport coords)
316+
#[wasm_bindgen]
317+
pub fn translate_canvas_by_fraction(delta_x: f64, delta_y: f64) -> Result<(), JsValue> {
318+
let ev = MovementMessage::TranslateCanvasByViewportFraction((delta_x, delta_y).into());
319+
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(ev)).map_err(convert_error)
320+
}
321+
315322
/// Update the list of selected layers. The layer paths have to be stored in one array and are separated by LayerId::MAX
316323
#[wasm_bindgen]
317324
pub fn select_layers(paths: Vec<LayerId>) -> Result<(), JsValue> {

frontend/wasm/src/wrappers.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ pub fn translate_key(name: &str) -> Key {
151151
"]" => KeyRightBracket,
152152
"{" => KeyLeftCurlyBracket,
153153
"}" => KeyRightCurlyBracket,
154+
"pageup" => KeyPageUp,
155+
"pagedown" => KeyPageDown,
154156
_ => UnknownKey,
155157
}
156158
}

0 commit comments

Comments
 (0)