1
0
Fork 0
spacetac/src/ui/common/Tooltip.ts

202 lines
6.5 KiB
TypeScript
Raw Normal View History

2017-10-10 22:32:46 +00:00
/// <reference path="UIBuilder.ts" />
2017-09-24 22:23:22 +00:00
module TK.SpaceTac.UI {
export type TooltipFiller = string | ((filler: TooltipBuilder) => string) | ((filler: TooltipBuilder) => boolean);
2018-05-15 14:57:45 +00:00
export class TooltipContainer extends UIContainer {
view: BaseView
2018-05-15 14:57:45 +00:00
background: UIBackground
content: UIContainer
2018-01-31 18:19:50 +00:00
item?: IBounded
2017-05-15 23:20:35 +00:00
border = 10
margin = 6
viewport: IBounded | null = null
constructor(view: BaseView) {
2018-05-15 14:57:45 +00:00
super(view);
this.view = view;
this.visible = false;
2018-05-15 14:57:45 +00:00
this.background = new UIBackground(view, this);
2018-05-15 14:57:45 +00:00
this.content = new UIContainer(view);
this.add(this.content);
2017-05-14 23:00:36 +00:00
this.view.tooltip_layer.add(this);
}
2017-05-15 23:20:35 +00:00
show(item: IBounded) {
this.item = item;
this.visible = true;
2017-05-15 23:20:35 +00:00
this.update();
}
tryPosition(viewport: IBounded, tooltip: IBounded): [number, number, number] {
let [x, y] = UITools.positionInside(tooltip, viewport);
let distance = Math.max(Math.abs(x - tooltip.x), Math.abs(y - tooltip.y));
if (this.view.isMouseInside({ x: x, y: y, width: tooltip.width, height: tooltip.height })) {
distance += 1000;
}
return [x, y, distance];
}
getBestPosition(item: IBounded, width: number, height: number): [number, number] {
let viewport = this.viewport || {
x: this.view.getX(0),
y: this.view.getY(0),
width: this.view.getX(1) - this.view.getX(0),
height: this.view.getY(1) - this.view.getY(0)
};
2017-05-15 23:20:35 +00:00
let candidates = [
this.tryPosition(viewport, { x: item.x + item.width / 2 - width / 2, y: item.y + item.height + this.margin, width: width, height: height }),
this.tryPosition(viewport, { x: item.x + item.width + this.margin, y: item.y + item.height / 2 - height / 2, width: width, height: height }),
this.tryPosition(viewport, { x: item.x + item.width / 2 - width / 2, y: item.y - height - this.margin, width: width, height: height }),
this.tryPosition(viewport, { x: item.x - width - this.margin, y: item.y + item.height / 2 - height / 2, width: width, height: height }),
]
candidates[0][2] -= 1; // preference to down tooltip on equality
let [x, y, distance] = candidates.sort((a, b) => cmp(a[2], b[2]))[0];
return [x, y];
}
update() {
2018-01-31 18:19:50 +00:00
if (this.visible && this.item) {
2017-05-22 20:41:34 +00:00
let [width, height] = UITools.drawBackground(this.content, this.background, this.border);
2017-05-15 23:20:35 +00:00
let [x, y] = this.getBestPosition(this.item, width, height);
x += this.border;
y += this.border;
if (x != this.x || y != this.y) {
2018-05-15 14:57:45 +00:00
this.setPosition(x, y);
}
}
}
hide() {
this.content.removeAll();
2017-05-15 23:20:35 +00:00
this.background.clear();
this.visible = false;
}
}
2017-05-14 23:00:36 +00:00
/**
* Functions used to fill a tooltip content
*/
export class TooltipBuilder extends UIBuilder {
2018-05-15 14:57:45 +00:00
private content: TooltipContainer;
2017-05-14 23:00:36 +00:00
constructor(container: TooltipContainer) {
2017-10-10 22:32:46 +00:00
let style = new UITextStyle();
style.center = false;
style.vcenter = false;
style.shadow = true;
2017-10-10 22:32:46 +00:00
super(container.view, container.content, style);
2017-05-14 23:00:36 +00:00
2018-05-15 14:57:45 +00:00
this.content = container;
2017-05-28 20:37:07 +00:00
}
2017-05-15 23:20:35 +00:00
/**
* Configure the positioning and base style of the tooltip
*/
configure(border = 10, margin = 6, viewport: IBounded | null = null): void {
2018-05-15 14:57:45 +00:00
this.content.border = border;
this.content.margin = margin;
2017-05-15 23:20:35 +00:00
if (viewport) {
2018-05-15 14:57:45 +00:00
this.content.viewport = viewport;
2017-05-15 23:20:35 +00:00
}
}
2017-05-14 23:00:36 +00:00
}
2017-03-15 21:40:19 +00:00
/**
* Tooltip system, to display information on hover
*/
export class Tooltip {
2018-05-15 14:57:45 +00:00
readonly view: BaseView;
readonly container: TooltipContainer;
2017-03-15 21:40:19 +00:00
constructor(view: BaseView) {
this.view = view;
this.container = new TooltipContainer(view);
2017-03-15 21:40:19 +00:00
}
2017-05-14 23:00:36 +00:00
get ui(): MainUI {
return this.view.gameui;
}
/**
* Get a tooltip builder
2017-05-14 23:00:36 +00:00
*/
getBuilder(): TooltipBuilder {
return new TooltipBuilder(this.container);
2017-05-14 23:00:36 +00:00
}
2017-03-15 21:40:19 +00:00
/**
* Bind to an UI component
*
* When the component is hovered, the function is called to allow filling the tooltip container
*/
2018-05-15 14:57:45 +00:00
bind(obj: UIButton | UIImage, func: (filler: TooltipBuilder) => boolean): void {
this.view.inputs.setHoverClick(obj,
2017-03-15 21:40:19 +00:00
// enter
() => {
2017-04-11 17:01:05 +00:00
this.hide();
if (func(this.getBuilder())) {
2018-05-15 14:57:45 +00:00
this.container.show(UITools.getBounds(obj));
2017-03-15 21:40:19 +00:00
}
},
// leave
2017-04-11 17:01:05 +00:00
() => this.hide(),
2017-03-15 21:40:19 +00:00
// click
2017-04-11 17:01:05 +00:00
() => this.hide()
2017-03-15 21:40:19 +00:00
);
2018-05-15 14:57:45 +00:00
obj.on("pointerdown", () => this.hide());
2017-03-15 21:40:19 +00:00
}
/**
* Bind to an UI component to display a dynamic text
*/
2018-05-15 14:57:45 +00:00
bindDynamicText(obj: UIButton | UIImage, text_getter: () => string): void {
2017-05-14 23:00:36 +00:00
this.bind(obj, filler => {
let content = text_getter();
if (content) {
2017-10-10 22:32:46 +00:00
filler.text(content, 0, 0, { color: "#cccccc", size: 20 });
return true;
} else {
return false;
}
2017-03-15 21:40:19 +00:00
});
}
/**
* Bind to an UI component to display a simple text
*/
2018-05-15 14:57:45 +00:00
bindStaticText(obj: UIButton | UIImage, text: string): void {
2017-03-15 21:40:19 +00:00
this.bindDynamicText(obj, () => text);
}
2017-04-11 17:01:05 +00:00
/**
* Show a tooltip for a component
*/
2018-05-15 14:57:45 +00:00
show(obj: UIButton, content: TooltipFiller): void {
let builder = this.getBuilder();
let scontent = (typeof content == "string") ? content : content(builder);
if (typeof scontent == "string") {
builder.text(scontent, 0, 0, { color: "#cccccc", size: 20 });
}
if (scontent) {
2018-05-15 14:57:45 +00:00
this.container.show(UITools.getBounds(obj));
} else {
this.hide();
}
}
2017-04-11 17:01:05 +00:00
/**
* Hide the current tooltip
*/
hide(): void {
this.container.hide();
2017-04-11 17:01:05 +00:00
}
2017-03-15 21:40:19 +00:00
}
}