use super::*;
use crate::geometry::Point;
use crate::widgets::scroll_view::{
current_scroll_style, current_scroll_visibility, ScrollBarStyle, ScrollBarVisibility,
};
use crate::widgets::scrollbar::{
paint_prepared_scrollbar, ScrollbarGeometry, ScrollbarOrientation, DEFAULT_GRAB_MARGIN,
};
pub(crate) enum ScrollMove {
Dragging(bool),
Hover(bool),
}
impl TextArea {
pub(crate) fn inner_height(&self) -> f64 {
(self.bounds.height - self.padding * 2.0).max(0.0)
}
pub(crate) fn content_height(&self) -> f64 {
self.cached_lines.len() as f64 * self.cached_line_h
}
pub(crate) fn max_scroll_y(&self) -> f64 {
(self.content_height() - self.inner_height()).max(0.0)
}
pub fn scroll_offset(&self) -> f64 {
self.vbar.offset
}
pub(crate) fn page_lines(&self) -> usize {
if self.cached_line_h <= 0.0 {
return 1;
}
((self.inner_height() / self.cached_line_h).floor() as usize).max(1)
}
fn scroll_style(&self) -> ScrollBarStyle {
current_scroll_style()
}
fn scroll_visibility(&self) -> ScrollBarVisibility {
current_scroll_visibility()
}
pub(crate) fn sync_scroll(&mut self) {
self.vbar.enabled = true;
self.vbar.content = self.content_height();
self.vbar.clamp_offset(self.inner_height());
}
fn v_scrollbar_geometry(&self) -> ScrollbarGeometry {
ScrollbarGeometry {
orientation: ScrollbarOrientation::Vertical,
track_start: self.padding,
track_end: (self.bounds.height - self.padding).max(self.padding),
cross_end: (self.bounds.width - 2.0).max(0.0),
hit_margin: DEFAULT_GRAB_MARGIN,
}
}
pub(crate) fn ensure_cursor_visible(&mut self) {
let inner_w = self.inner_width();
self.refresh_wrap(inner_w);
let line_h = self.cached_line_h;
if line_h <= 0.0 {
return;
}
let inner_h = self.inner_height();
let cursor = self.edit.borrow().cursor;
let line = self.line_for_cursor(cursor);
let top = line as f64 * line_h;
let bottom = top + line_h;
let mut off = self.vbar.offset;
if top < off {
off = top; } else if bottom > off + inner_h {
off = bottom - inner_h; }
self.vbar.offset = off.clamp(0.0, self.max_scroll_y());
}
pub(crate) fn scroll_by_wheel(&mut self, delta_y: f64) -> bool {
if self.max_scroll_y() <= 0.0 {
return false;
}
let line_h = if self.cached_line_h > 0.0 {
self.cached_line_h
} else {
self.font_size * 1.35
};
self.vbar
.scroll_by(-delta_y * 3.0 * line_h, self.inner_height())
}
pub(crate) fn scrollbar_begin_drag(&mut self, pos: Point) -> bool {
if self.max_scroll_y() <= 0.0 {
return false;
}
let geom = self.v_scrollbar_geometry();
self.vbar
.begin_drag(pos, self.inner_height(), self.scroll_style(), geom)
}
pub(crate) fn scrollbar_on_mouse_move(&mut self, pos: Point) -> ScrollMove {
let geom = self.v_scrollbar_geometry();
let vp = self.inner_height();
let style = self.scroll_style();
if self.vbar.dragging {
ScrollMove::Dragging(self.vbar.drag_to(pos, vp, style, geom))
} else {
ScrollMove::Hover(self.vbar.update_hover(pos, vp, style, geom))
}
}
pub(crate) fn scrollbar_end_drag(&mut self) -> bool {
let was = self.vbar.dragging;
self.vbar.dragging = false;
was
}
pub(crate) fn paint_scrollbar(&mut self, ctx: &mut dyn DrawCtx) {
let vp = self.inner_height();
let style = self.scroll_style();
let vis = self.scroll_visibility();
let geom = self.v_scrollbar_geometry();
if let Some(bar) = self.vbar.prepare_paint(vp, style, vis, geom) {
paint_prepared_scrollbar(ctx, bar);
}
}
pub(crate) fn scrollbar_animating(&self) -> bool {
self.vbar.animation_active()
}
}