//
// Copyright (c) 2016, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 8 Sep 2016 Andy Frank Creation
//
using concurrent
using dom
**
** Tooltip displays a small popup when the mouse hovers over the
** bound node element, and is dismissed when the mouse moves out.
**
** See also: [docDomkit]`docDomkit::Controls#tooltip`
**
@Js class Tooltip : Elem
{
new make() : super()
{
this.style.addClass("domkit-Popup")
this.style->zIndex = 2000
// this.onEvent(EventType.mouseEnter, false) { inTooltip=true; check }
// this.onEvent("mouseleave", false) { inTooltip=false; check }
}
** Time mouse must be over bound node before opening the
** Tooltip. If 'null' the Tooltip is displayed immediatly.
Duration? delay := 750ms
** Bind this tooltip the given node.
Void bind(Elem node)
{
if (this.node != null) throw ArgErr("Tooltip already bound to $this.node")
this.node = node
node.onEvent("mouseenter", false) { inNode=true; check }
node.onEvent("mouseleave", false) { inNode=false; check }
}
** Check if tooltip should be opened or closed.
private Void check()
{
if (inNode) // || inTooltip)
{
// open
if (delay == null)
{
if (isOpen) return
open
}
else
{
if (isOpen) return
if (timerId != null) return
timerId = Win.cur.setTimeout(delay) { this.open }
}
}
else
{
// close
if (isOpen) { close; return }
if (timerId != null) { Win.cur.clearTimeout(timerId); timerId=null }
}
}
** Is Tooltip open.
private Bool isOpen() { parent != null }
** Open tooltip over bound parent node.
private Void open()
{
this.timerId = null
x := node.pagePos.x
y := node.pagePos.y + node.size.h + 1
this.style->left = "${x}px"
this.style->top = "${y}px"
this.style->opacity = "0"
Win.cur.doc.body.add(this)
// adjust if outside viewport
sz := this.size
vp := Win.cur.viewport
if (sz.w + gutter + gutter > vp.w) this.style->width = "${vp.w-gutter-gutter}px"
if (sz.h + gutter + gutter > vp.h) this.style->height = "${vp.h-gutter-gutter}px"
// refresh size
sz = this.size
if ((x + sz.w + gutter) > vp.w) this.style->left = "${vp.w-sz.w-gutter}px"
if ((y + sz.h + gutter) > vp.h) this.style->top = "${vp.h-sz.h-gutter}px"
this.transition(["opacity": "1"], null, 100ms)
}
** Close this tooltip.
@NoDoc Void close()
{
this.transition(["opacity":"0"], null, 100ms) {
this.parent?.remove(this)
}
}
private static const Int gutter := 12
private Elem? node // parent elem
private Int? timerId // open delay timer
private Bool inNode := false // is mouse inside parent node
private Bool inTooltip := false // is mouse inside tooltip
}