///|
fn cell_to_client_x(col : Int) -> Int {
col * 8 + 4
}
///|
fn cell_to_client_y(row : Int) -> Int {
let viewport_row = if row > 0 { row } else { 0 }
viewport_row * 16 + 8
}
///|
fn Browser::get_client_coords_for_source_id(
self : Browser,
source_id : String,
) -> (Int, Int)? {
if self.hit_regions.is_empty() {
return None
}
let mut i = self.hit_regions.length() - 1
while i >= 0 {
let region = self.hit_regions[i]
if region.source_id == source_id {
let center_col = region.col + region.width / 2
let center_row = region.row + region.height / 2
return Some((cell_to_client_x(center_col), cell_to_client_y(center_row)))
}
i = i - 1
}
None
}
///|
fn Browser::get_hit_region_for_source_id(
self : Browser,
source_id : String,
) -> @tui.HitRegion? {
if self.hit_regions.is_empty() {
return None
}
let mut i = self.hit_regions.length() - 1
while i >= 0 {
let region = self.hit_regions[i]
if region.source_id == source_id {
return Some(region)
}
i = i - 1
}
None
}
///|
pub async fn Browser::handle_focused_key(
self : Browser,
key : String,
) -> Bool raise @http.HttpError {
let source_id = self.get_focused_source_id()
match source_id {
Some(id) => {
self.focus_source_id(id)
match self.dispatch_focused_key_to_source_id(id, key) {
Handled => true
Activate => self.activate_focused_link()
Submit =>
match self.dispatch_submit_to_source_id(id) {
Prevented => true
Handled => true
Navigate(request) => {
let resolved_request = {
..request,
url: resolve_url(self.current_url, request.url),
}
let _ = self.navigate_request(resolved_request)
true
}
NotSubmittable => true
}
NotHandled => false
}
}
None => false
}
}
///|
pub async fn Browser::activate_focused_link(
self : Browser,
) -> Bool raise @http.HttpError {
let source_id = self.get_focused_source_id()
let href = self.get_focused_link_url()
match source_id {
Some(id) => {
self.focus_source_id(id)
let (client_x, client_y) = match
self.get_client_coords_for_source_id(id) {
Some(coords) => coords
None => (0, 0)
}
let dispatch = self.dispatch_click_to_source_id(id, client_x~, client_y~)
if !dispatch.allow_default {
return true
}
if self.dispatch_activation_default_to_source_id(id) {
return true
}
match self.dispatch_submit_to_source_id(id, client_x~, client_y~) {
Prevented => return true
Handled => return true
Navigate(request) => {
let resolved_request = {
..request,
url: resolve_url(self.current_url, request.url),
}
let _ = self.navigate_request(resolved_request)
return true
}
NotSubmittable => ()
}
if href is None && dispatch.handled {
return true
}
}
None => ()
}
match href {
Some(url) if url.length() > 0 => {
let _ = self.navigate(url)
true
}
_ => false
}
}
///|
pub fn Browser::hover_at(self : Browser, col : Int, row : Int) -> Bool {
let next_source_id = self.get_hover_source_id_at(col, row)
let changed = self.dispatch_hover_transition(
self.hovered_source_id,
next_source_id,
cell_to_client_x(col),
cell_to_client_y(row),
)
self.hovered_source_id = next_source_id
changed
}
///|
pub fn Browser::pointer_down_at(self : Browser, col : Int, row : Int) -> Bool {
let source_id = self.get_hover_source_id_at(col, row)
self.hovered_source_id = source_id
self.dragging_source_id = None
self.drag_over_source_id = None
self.drop_allowed_source_id = None
match source_id {
Some(id) => {
self.focus_source_id(id)
if self.set_text_control_caret_from_cell(id, col, row) {
self.text_selection_anchor_source_id = Some(id)
self.text_selection_anchor_col = col
self.text_selection_anchor_row = row
} else {
self.text_selection_anchor_source_id = None
}
self.pressed_source_id = Some(id)
self.dispatch_pointer_mouse_event_to_source_id(
id,
"pointerdown",
"mousedown",
cell_to_client_x(col),
cell_to_client_y(row),
)
}
None => {
self.pressed_source_id = None
self.text_selection_anchor_source_id = None
false
}
}
}
///|
pub fn Browser::pointer_move_at(self : Browser, col : Int, row : Int) -> Bool {
let client_x = cell_to_client_x(col)
let client_y = cell_to_client_y(row)
let mut changed = self.hover_at(col, row)
match self.pressed_source_id {
Some(pressed_id) => {
match self.text_selection_anchor_source_id {
Some(anchor_source_id) if anchor_source_id == pressed_id &&
self.dragging_source_id is None =>
if self.set_text_control_selection_from_cells(
pressed_id,
self.text_selection_anchor_col,
self.text_selection_anchor_row,
col,
row,
) {
changed = true
}
_ => ()
}
if self.dragging_source_id is None &&
self.is_draggable_source_id(pressed_id) {
if self.dispatch_drag_event_to_source_id(
pressed_id,
"dragstart",
client_x,
client_y,
related_source_id=None,
) {
self.dragging_source_id = Some(pressed_id)
changed = true
}
}
match self.dragging_source_id {
Some(drag_id) => {
let plan = @interaction_policy.drag_move_target_plan(
drag_id,
self.drag_over_source_id.unwrap_or(""),
self.get_hover_source_id_at(col, row).unwrap_or(""),
)
let next_target = if plan.over_target != "" {
Some(plan.over_target)
} else {
None
}
if self.dispatch_drag_event_to_source_id(
drag_id,
"drag",
client_x,
client_y,
related_source_id=next_target,
) {
changed = true
}
if self.drag_over_source_id != next_target {
self.drop_allowed_source_id = None
match self.drag_over_source_id {
Some(previous_target) if plan.emit_dragleave =>
if self.dispatch_drag_event_to_source_id(
previous_target,
"dragleave",
client_x,
client_y,
related_source_id=next_target,
) {
changed = true
}
_ => ()
}
match next_target {
Some(next_id) if plan.emit_dragenter =>
if self.dispatch_drag_event_to_source_id(
next_id,
"dragenter",
client_x,
client_y,
related_source_id=self.drag_over_source_id,
) {
changed = true
}
_ => ()
}
self.drag_over_source_id = next_target
}
match self.drag_over_source_id {
Some(target_id) if plan.emit_dragover => {
let (handled_drag_over, canceled_drag_over) = self.dispatch_drag_event_status_to_source_id(
target_id,
"dragover",
client_x,
client_y,
related_source_id=Some(drag_id),
)
if handled_drag_over {
changed = true
}
let accepted_target = @interaction_policy.drag_accept_target(
drag_id, target_id, canceled_drag_over,
)
self.drop_allowed_source_id = if accepted_target != "" {
Some(accepted_target)
} else {
None
}
}
_ => ()
}
}
None => ()
}
changed
}
None => changed
}
}
///|
pub async fn Browser::pointer_up_at(
self : Browser,
col : Int,
row : Int,
) -> Bool raise @http.HttpError {
let client_x = cell_to_client_x(col)
let client_y = cell_to_client_y(row)
let up_source_id = self.get_hover_source_id_at(col, row)
let pressed_source_id = self.pressed_source_id
let dragging_source_id = self.dragging_source_id
let drag_over_source_id = self.drag_over_source_id
let drop_allowed_source_id = self.drop_allowed_source_id
let mut handled = false
match up_source_id {
Some(id) =>
if self.dispatch_pointer_mouse_event_to_source_id(
id, "pointerup", "mouseup", client_x, client_y,
) {
handled = true
}
None => ()
}
self.pressed_source_id = None
self.text_selection_anchor_source_id = None
self.dragging_source_id = None
self.drag_over_source_id = None
self.drop_allowed_source_id = None
match dragging_source_id {
Some(drag_id) => {
let drop_target = @interaction_policy.drag_drop_target(
drag_id,
drag_over_source_id.unwrap_or(""),
drop_allowed_source_id.unwrap_or(""),
)
match drag_over_source_id {
Some(target_id) if drop_target == target_id &&
self.is_current_drop_allowed() =>
if self.dispatch_drag_event_to_source_id(
target_id,
"drop",
client_x,
client_y,
related_source_id=Some(drag_id),
) {
handled = true
}
_ => ()
}
if self.dispatch_drag_event_to_source_id(
drag_id,
"dragend",
client_x,
client_y,
related_source_id=drag_over_source_id,
) {
handled = true
}
return handled
}
None => ()
}
match (pressed_source_id, up_source_id) {
(Some(down_id), Some(up_id)) if down_id == up_id => {
let dispatch = self.dispatch_click_only_to_source_id(
down_id, client_x, client_y,
)
if !dispatch.allow_default {
return true
}
if self.dispatch_activation_default_to_source_id(down_id) {
return true
}
match self.dispatch_submit_to_source_id(down_id, client_x~, client_y~) {
Prevented => return true
Handled => return true
Navigate(request) => {
let resolved_request = {
..request,
url: resolve_url(self.current_url, request.url),
}
let _ = self.navigate_request(resolved_request)
return true
}
NotSubmittable => ()
}
match self.get_href_for_source_id(down_id) {
Some(url) if url.length() > 0 => {
let _ = self.navigate(resolve_url(self.current_url, url))
true
}
_ => handled || dispatch.handled
}
}
_ => handled
}
}
///|
pub async fn Browser::activate_at(
self : Browser,
col : Int,
row : Int,
) -> Bool raise @http.HttpError {
let source_id = self.get_source_id_at(col, row)
let href = match self.get_link_at(col, row) {
Some(url) => Some(resolve_url(self.current_url, url))
None =>
match source_id {
Some(id) => self.get_href_for_source_id(id)
None => None
}
}
match source_id {
Some(id) => {
self.focus_source_id(id)
let _ = self.set_text_control_caret_from_cell(id, col, row)
let dispatch = self.dispatch_click_to_source_id(
id,
client_x=cell_to_client_x(col),
client_y=cell_to_client_y(row),
)
if !dispatch.allow_default {
return true
}
if self.dispatch_activation_default_to_source_id(id) {
return true
}
match
self.dispatch_submit_to_source_id(
id,
client_x=cell_to_client_x(col),
client_y=cell_to_client_y(row),
) {
Prevented => return true
Handled => return true
Navigate(request) => {
let resolved_request = {
..request,
url: resolve_url(self.current_url, request.url),
}
let _ = self.navigate_request(resolved_request)
return true
}
NotSubmittable => ()
}
match href {
Some(url) if url.length() > 0 => {
let _ = self.navigate(url)
true
}
_ => dispatch.handled
}
}
None =>
match href {
Some(url) if url.length() > 0 => {
let _ = self.navigate(url)
true
}
_ => false
}
}
}
///|
pub async fn Browser::activate_link_at(
self : Browser,
col : Int,
row : Int,
) -> Bool raise @http.HttpError {
self.activate_at(col, row)
}