-
Notifications
You must be signed in to change notification settings - Fork 323
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Scrollbar and ScrollArea (enso-org/ide#1614)
Original commit: enso-org/ide@9bf3843
- Loading branch information
1 parent
dd94908
commit a1cd8b8
Showing
14 changed files
with
671 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
//! A debug scene which shows the scroll area. | ||
use crate::prelude::*; | ||
use wasm_bindgen::prelude::*; | ||
|
||
use ensogl_core::application::Application; | ||
use ensogl_core::data::color; | ||
use ensogl_core::display::object::ObjectOps; | ||
use ensogl_core::system::web; | ||
use ensogl_text_msdf_sys::run_once_initialized; | ||
use ensogl_theme as theme; | ||
use ensogl_gui_components::scroll_area::ScrollArea; | ||
use ensogl_core::display::shape::{Circle, Rect, ShapeSystem}; | ||
use ensogl_core::display::shape::PixelDistance; | ||
use ensogl_core::display::shape::ShapeOps; | ||
use ensogl_core::display::Sprite; | ||
|
||
|
||
|
||
// =================== | ||
// === Entry Point === | ||
// =================== | ||
|
||
/// An entry point. | ||
#[wasm_bindgen] | ||
pub fn entry_point_scroll_area() { | ||
web::forward_panic_hook_to_console(); | ||
web::set_stack_trace_limit(); | ||
run_once_initialized(|| { | ||
let app = Application::new(&web::get_html_element_by_id("root").unwrap()); | ||
init(&app); | ||
mem::forget(app); | ||
}); | ||
} | ||
|
||
|
||
|
||
// ======================== | ||
// === Init Application === | ||
// ======================== | ||
|
||
fn init(app:&Application) { | ||
theme::builtin::dark::register(&app); | ||
theme::builtin::light::register(&app); | ||
theme::builtin::light::enable(&app); | ||
|
||
let scene = app.display.scene(); | ||
scene.camera().set_position_xy(Vector2(100.0,-100.0)); | ||
|
||
|
||
// === Background === | ||
|
||
let background_color = color::Rgba::new(0.9,0.9,0.9,1.0); | ||
let background_size = (200.px(), 200.px()); | ||
let background_shape = Rect(background_size).corners_radius(5.5.px()).fill(background_color); | ||
let background_system = ShapeSystem::new(scene,background_shape); | ||
let background: Sprite = background_system.new_instance(); | ||
scene.add_child(&background); | ||
background.size.set(Vector2::new(200.0,200.0)); | ||
background.set_position_x(100.0); | ||
background.set_position_y(-100.0); | ||
std::mem::forget(background); | ||
|
||
|
||
// === Scroll Area === | ||
|
||
let scroll_area = ScrollArea::new(&app); | ||
app.display.add_child(&scroll_area); | ||
scroll_area.resize(Vector2(200.0,200.0)); | ||
scroll_area.set_content_width(300.0); | ||
scroll_area.set_content_height(1000.0); | ||
|
||
|
||
// === Content === | ||
|
||
let sprite_system = ShapeSystem::new(scene,&Circle(50.px())); | ||
let sprite: Sprite = sprite_system.new_instance(); | ||
scroll_area.content.add_child(&sprite); | ||
sprite.size.set(Vector2::new(100.0,100.0)); | ||
sprite.set_position_x(100.0); | ||
sprite.set_position_y(-100.0); | ||
std::mem::forget(sprite); | ||
|
||
|
||
std::mem::forget(scroll_area); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
//! This module provides the [`ScrollArea`] component. | ||
use crate::prelude::*; | ||
|
||
use crate::scrollbar; | ||
use crate::scrollbar::Scrollbar; | ||
|
||
use enso_frp as frp; | ||
use ensogl_core::display; | ||
use ensogl_core::display::object::ObjectOps; | ||
use ensogl_core::application::Application; | ||
use ensogl_core::control::io::mouse; | ||
use ensogl_core::control::callback; | ||
|
||
|
||
|
||
// =========== | ||
// === Frp === | ||
// =========== | ||
|
||
ensogl_core::define_endpoints! { | ||
Input { | ||
/// Set the width and height in px. | ||
resize (Vector2), | ||
/// Set the content width in px. Affects how far one can scroll horizontally. | ||
set_content_width (f32), | ||
/// Set the content height in px. Affects how far one can scroll vertically. | ||
set_content_height (f32), | ||
/// Scrolls smoothly to the given x coordinate. | ||
scroll_to_x (f32), | ||
/// Scrolls smoothly to the given y coordinate. | ||
scroll_to_y (f32), | ||
/// Jumps instantly to the given x coordinate, without animation. | ||
jump_to_x (f32), | ||
/// Jumps instantly to the given y coordinate, without animation. | ||
jump_to_y (f32), | ||
} | ||
Output { | ||
/// The content's x coordinate at the left edge of the area. | ||
scroll_position_x (f32), | ||
/// The content's y coordinate at the top edge of the area. | ||
scroll_position_y (f32), | ||
} | ||
} | ||
|
||
|
||
|
||
// =================== | ||
// === Scroll Area === | ||
// =================== | ||
|
||
/// This struct provides a scroll area component. It displays two scrollbars, for horizontal and | ||
/// vertical scrolling. Content can be added to the `content` attribute. The content size has to be | ||
/// set through `set_content_height` and `set_content_width`. The component is anchored at the top | ||
/// left corner. All scroll coordinates describe the point of the `content` object at that corner. | ||
/// The scrollbars are only active when the content is actually larger than the viewport on the | ||
/// respective axis. | ||
#[derive(Debug,Clone,CloneRef)] | ||
pub struct ScrollArea { | ||
/// All objects that should be inside the scroll area and affected by the scrolling, have to be | ||
/// added as children to `content`. | ||
pub content : display::object::Instance, | ||
display_object : display::object::Instance, | ||
h_scrollbar : Scrollbar, | ||
v_scrollbar : Scrollbar, | ||
scroll_handler_handle : callback::Handle, | ||
frp : Frp, | ||
} | ||
|
||
impl Deref for ScrollArea { | ||
type Target = Frp; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.frp | ||
} | ||
} | ||
|
||
impl display::Object for ScrollArea { | ||
fn display_object(&self) -> &display::object::Instance { | ||
&self.display_object | ||
} | ||
} | ||
|
||
impl ScrollArea { | ||
/// Create a new scroll area for use in the given application. | ||
pub fn new(app:&Application) -> ScrollArea { | ||
let scene = app.display.scene(); | ||
let logger = Logger::new("ScrollArea"); | ||
let display_object = display::object::Instance::new(&logger); | ||
|
||
let content = display::object::Instance::new(&logger); | ||
display_object.add_child(&content); | ||
|
||
let h_scrollbar = Scrollbar::new(&app); | ||
display_object.add_child(&h_scrollbar); | ||
|
||
let v_scrollbar = Scrollbar::new(&app); | ||
display_object.add_child(&v_scrollbar); | ||
v_scrollbar.set_rotation_z(-90.0_f32.to_radians()); | ||
|
||
let frp = Frp::new(); | ||
let network = &frp.network; | ||
|
||
frp::extend! { network | ||
|
||
// === Size and Position === | ||
|
||
h_scrollbar.set_max <+ frp.set_content_width; | ||
v_scrollbar.set_max <+ frp.set_content_height; | ||
h_scrollbar.set_thumb_size <+ frp.resize.map(|size| size.x); | ||
v_scrollbar.set_thumb_size <+ frp.resize.map(|size| size.y); | ||
h_scrollbar.set_length <+ frp.resize.map(|size| size.x); | ||
v_scrollbar.set_length <+ frp.resize.map(|size| size.y); | ||
|
||
eval frp.resize([h_scrollbar,v_scrollbar](size) { | ||
h_scrollbar.set_position_y(-size.y+scrollbar::WIDTH/2.0); | ||
v_scrollbar.set_position_x(size.x-scrollbar::WIDTH/2.0); | ||
h_scrollbar.set_position_x(size.x/2.0); | ||
v_scrollbar.set_position_y(-size.y/2.0); | ||
}); | ||
|
||
|
||
// === Scrolling === | ||
|
||
h_scrollbar.scroll_to <+ frp.scroll_to_x; | ||
v_scrollbar.scroll_to <+ frp.scroll_to_y; | ||
h_scrollbar.jump_to <+ frp.jump_to_x; | ||
v_scrollbar.jump_to <+ frp.jump_to_y; | ||
|
||
frp.source.scroll_position_x <+ h_scrollbar.thumb_position.map(|x| -x); | ||
frp.source.scroll_position_y <+ v_scrollbar.thumb_position; | ||
|
||
eval frp.scroll_position_x((&pos) content.set_position_x(pos)); | ||
eval frp.scroll_position_y((&pos) content.set_position_y(pos)); | ||
} | ||
|
||
|
||
// === Mouse Wheel === | ||
|
||
let mouse = &scene.mouse; | ||
frp::extend! { network | ||
hovering <- all_with(&mouse.frp.position,&frp.resize, | ||
f!([scene,display_object](&pos,&size) { | ||
let local_pos = scene.screen_to_object_space(&display_object,pos); | ||
(0.0..=size.x).contains(&local_pos.x) && (-size.y..=0.0).contains(&local_pos.y) | ||
})); | ||
hovering <- hovering.sampler(); | ||
} | ||
|
||
let mouse_manager = &mouse.mouse_manager; | ||
let scroll_handler = f!([v_scrollbar,h_scrollbar](event:&mouse::OnWheel) | ||
if hovering.value() { | ||
h_scrollbar.scroll_by(event.delta_x() as f32); | ||
v_scrollbar.scroll_by(event.delta_y() as f32); | ||
} | ||
); | ||
let scroll_handler_handle = mouse_manager.on_wheel.add(scroll_handler); | ||
|
||
|
||
ScrollArea {content,display_object,h_scrollbar,v_scrollbar,scroll_handler_handle,frp} | ||
} | ||
} |
Oops, something went wrong.