MBHaxe/src/gui/GuiMLTextListCtrl.hx

285 lines
7.5 KiB
Haxe

package gui;
import h2d.filter.Filter;
import h2d.HtmlText;
import h2d.Flow;
import h3d.Engine;
import h2d.Tile;
import h2d.Bitmap;
import h3d.mat.Texture;
import shaders.GuiClipFilter;
import h2d.Graphics;
import gui.GuiControl.MouseState;
import h2d.Scene;
import h2d.Text;
import h2d.Font;
import src.MarbleGame;
import src.Settings;
class GuiMLTextListCtrl extends GuiControl {
public var texts:Array<String>;
public var onSelectedFunc:Int->Void;
var font:Font;
var textObjs:Array<Text>;
var g:Graphics;
var _prevSelected:Int = -1;
public var selectedColor:Int = 0x206464;
public var selectedFillColor:Int = 0xC8C8C8;
public var textYOffset:Int = 0;
public var scroll:Float = 0;
public var scrollable:Bool = false;
var filter:Filter = null;
var flow:Flow;
var _imageLoader:String->Tile;
public function new(font:Font, texts:Array<String>, imageLoader:String->Tile, ?filter:Filter = null) {
super();
this.font = font;
this.texts = texts;
this.textObjs = [];
this.filter = filter;
this._imageLoader = imageLoader;
for (text in texts) {
var tobj = new HtmlText(font);
tobj.lineHeightMode = TextOnly;
tobj.loadImage = imageLoader;
tobj.text = text;
tobj.textColor = 0;
if (filter != null)
tobj.filter = filter;
textObjs.push(tobj);
}
this.g = new Graphics();
}
public function setTexts(texts:Array<String>) {
var renderRect = this.getRenderRectangle();
for (textObj in this.textObjs) {
textObj.remove();
}
this.textObjs = [];
for (text in texts) {
var tobj = new HtmlText(font);
tobj.loadImage = this._imageLoader;
tobj.lineHeightMode = TextOnly;
tobj.text = text;
tobj.textColor = 0;
if (filter != null)
tobj.filter = filter;
textObjs.push(tobj);
if (this.scrollable) {
if (this.flow != null) {
if (this.flow.contains(tobj))
this.flow.removeChild(tobj);
this.flow.addChild(tobj);
this.flow.getProperties(tobj).isAbsolute = true;
}
}
}
this.texts = texts;
this._prevSelected = -1;
if (this.onSelectedFunc != null)
this.onSelectedFunc(-1);
redrawSelectionRect(renderRect);
for (i in 0...textObjs.length) {
var text = textObjs[i];
text.setPosition(Math.floor((!scrollable ? renderRect.position.x : 0) + 5),
Math.floor((!scrollable ? renderRect.position.y : 0) + (i * (text.font.size + 4) + 5 + textYOffset * Settings.uiScale - this.scroll)));
if (_prevSelected == i) {
text.textColor = selectedColor;
}
}
}
public override function render(scene2d:Scene) {
var renderRect = this.getRenderRectangle();
var htr = this.getHitTestRect();
if (scene2d.contains(g))
scene2d.removeChild(g);
scene2d.addChild(g);
g.setPosition(renderRect.position.x, renderRect.position.y - this.scroll);
if (scrollable) {
this.flow = new Flow();
this.flow.maxWidth = cast htr.extent.x;
this.flow.maxHeight = cast htr.extent.y;
this.flow.multiline = true;
this.flow.layout = Stack;
this.flow.overflow = FlowOverflow.Hidden;
if (scene2d.contains(this.flow))
scene2d.removeChild(this.flow);
scene2d.addChild(this.flow);
this.flow.setPosition(htr.position.x, htr.position.y);
}
for (i in 0...textObjs.length) {
var text = textObjs[i];
if (!scrollable) {
if (scene2d.contains(text))
scene2d.removeChild(text);
scene2d.addChild(text);
} else {
if (this.flow.contains(text))
this.flow.removeChild(text);
this.flow.addChild(text);
this.flow.getProperties(text).isAbsolute = true;
}
text.setPosition(Math.floor((!scrollable ? renderRect.position.x : 0) + 5),
Math.floor((!scrollable ? renderRect.position.y : 0) + (i * (text.font.size + 4) + 5 + textYOffset * Settings.uiScale - this.scroll)));
if (_prevSelected == i) {
text.textColor = selectedColor;
}
}
redrawSelectionRect(htr);
super.render(scene2d);
}
public function calculateFullHeight() {
return (this.texts.length * (font.size + 4));
}
public override function dispose() {
super.dispose();
for (text in textObjs) {
text.remove();
}
this.g.remove();
if (this.scrollable) {
this.flow.remove();
}
}
public override function onRemove() {
super.onRemove();
for (text in textObjs) {
if (MarbleGame.canvas.scene2d.contains(text)) {
MarbleGame.canvas.scene2d.removeChild(text); // Refresh "layer"
}
}
if (MarbleGame.canvas.scene2d.contains(g))
MarbleGame.canvas.scene2d.removeChild(g);
if (MarbleGame.canvas.scene2d.contains(this.flow))
MarbleGame.canvas.scene2d.removeChild(this.flow);
}
public override function onMouseMove(mouseState:MouseState) {
var mousePos = mouseState.position;
var renderRect = this.getRenderRectangle();
var yStart = renderRect.position.y;
var dy = mousePos.y - yStart;
var hoverIndex = Math.floor((dy + this.scroll) / (font.size + 4));
if (hoverIndex >= this.texts.length) {
hoverIndex = -1;
}
// Update the texts
for (i in 0...textObjs.length) {
var selected = i == hoverIndex || i == this._prevSelected;
var text = textObjs[i];
text.textColor = selected ? selectedColor : 0;
// fill color = 0xC8C8C8
}
// obviously in renderRect
}
public override function onMouseLeave(mouseState:MouseState) {
for (i in 0...textObjs.length) {
if (i == this._prevSelected)
continue;
var text = textObjs[i];
text.textColor = 0;
// fill color = 0xC8C8C8
}
}
public override function onMousePress(mouseState:MouseState) {
super.onMousePress(mouseState);
var mousePos = mouseState.position;
var renderRect = this.getRenderRectangle();
var yStart = renderRect.position.y;
var dy = mousePos.y - yStart;
var selectedIndex = Math.floor((dy + this.scroll) / (font.size + 4));
if (selectedIndex >= this.texts.length) {
selectedIndex = -1;
}
if (_prevSelected != selectedIndex) {
_prevSelected = selectedIndex;
redrawSelectionRect(renderRect);
}
if (onSelectedFunc != null) {
onSelectedFunc(selectedIndex);
}
}
function redrawSelectionRect(renderRect:Rect) {
if (_prevSelected != -1) {
g.clear();
g.beginFill(selectedFillColor);
// Check if we are between the top and bottom, render normally in that case
var topY = 2 + (_prevSelected * (font.size + 4)) + g.y;
var bottomY = 2 + (_prevSelected * (font.size + 4)) + g.y + font.size + 4;
var topRectY = renderRect.position.y;
var bottomRectY = renderRect.position.y + renderRect.extent.y;
if (topY >= topRectY && bottomY <= bottomRectY)
g.drawRect(0, 5 + (_prevSelected * (font.size + 4)) - 3, renderRect.extent.x, font.size + 4);
// We need to do math the draw the partially visible top selected
if (topY <= topRectY && bottomY >= topRectY) {
g.drawRect(0, this.scroll, renderRect.extent.x, topY + font.size + 4 - renderRect.position.y);
}
// Same for the bottom
if (topY <= bottomRectY && bottomY >= bottomRectY) {
g.drawRect(0, this.scroll
+ renderRect.extent.y
- font.size
- 4
+ (topY + font.size + 4 - bottomRectY), renderRect.extent.x,
renderRect.position.y
+ renderRect.extent.y
- (topY));
}
g.endFill();
} else {
g.clear();
}
}
public override function onScroll(scrollX:Float, scrollY:Float) {
super.onScroll(scrollX, scrollY);
var renderRect = this.getRenderRectangle();
this.scroll = scrollY;
var hittestrect = this.getHitTestRect();
for (i in 0...textObjs.length) {
var text = textObjs[i];
text.y = Math.floor((i * (text.font.size + 4) + 5 + textYOffset * Settings.uiScale - scrollY));
g.y = renderRect.position.y - scrollY;
}
redrawSelectionRect(hittestrect);
}
}