Index: binaries/data/mods/mod/gui/common/ResizeBar.js =================================================================== --- /dev/null +++ binaries/data/mods/mod/gui/common/ResizeBar.js @@ -0,0 +1,269 @@ +// See lobby_autociv.js init function for examples +function ResizeBar(object, side, width, objectsHooked, isVisibleCondition, onDragDown) +{ + this.object = this.parseObject(object); + this.side = side; + this.halfWidth = width === undefined ? + ResizeBar.defaults.width / 2.0 : + width / 2.0; + + this.objectsHooked = objectsHooked ? objectsHooked : []; + this.isVisibleCondition = isVisibleCondition ? + isVisibleCondition : + () => !this.object.hidden; + + this.onDragDown = onDragDown ? onDragDown : () => { }; + + this.lastIn = false; + this.dragging = false; + + for (let i = 0; i < this.objectsHooked.length; ++i) + this.objectsHooked[i][0] = this.parseObject(this.objectsHooked[i][0]); +} + +ResizeBar.mouse = { + "x": 0, + "y": 0, + "set": function (mouse) { [this.x, this.y] = [mouse.x, mouse.y]; } +}; + +ResizeBar.mousePress = Object.assign({}, ResizeBar.mouse); + +ResizeBar.mouseRelease = Object.assign({}, ResizeBar.mouse); + +ResizeBar.dragging = false; + +ResizeBar.defaults = { "width": 14 }; + +ResizeBar.prototype.parseObject = function (object) +{ + return typeof object == "string" ? + Engine.GetGUIObjectByName(object) : + object; +}; + +ResizeBar.prototype.mouseInside = function () +{ + if (!this.isVisibleCondition()) + return false; + + let rect = this.object.getComputedSize(); + switch (this.side) + { + case "left": case "right": + return Math.abs(rect[this.side] - ResizeBar.mouse.x) <= this.halfWidth && + rect.top + this.halfWidth < ResizeBar.mouse.y && + rect.bottom - this.halfWidth > ResizeBar.mouse.y; + case "top": case "bottom": + return Math.abs(rect[this.side] - ResizeBar.mouse.y) <= this.halfWidth && + rect.left + this.halfWidth < ResizeBar.mouse.x && + rect.right - this.halfWidth > ResizeBar.mouse.x; + default: + warn(`No side by name: "${this.side}"\n` + Error().stack); + } +}; + +ResizeBar.prototype.sideC = function (side) +{ + switch (side ? side : this.side) + { + case "left": return "right"; + case "right": return "left"; + case "top": return "bottom"; + case "bottom": return "top"; + } +}; + +ResizeBar.prototype.sideO = function (side) +{ + switch (side ? side : this.side) + { + case "left": return "top"; + case "right": return "bottom"; + case "top": return "left"; + case "bottom": return "right"; + } +}; + +ResizeBar.prototype.sideX = function (side) +{ + return this.sideC(this.sideO()); +}; + +ResizeBar.prototype.sideSign = function (side) +{ + switch (side ? side : this.side) + { + case "right": + case "bottom": return +1; + default: return -1; + } +}; + +ResizeBar.prototype.sideMouse = function (side) +{ + switch (side ? side : this.side) + { + case "left": + case "right": return "x"; + default: return "y"; + } +}; + +ResizeBar.prototype.viewResizeBar = function () +{ + let absPos = this.object.getComputedSize(); + + let iSize = GUISize(); + iSize[this.side] = absPos[this.side]; + iSize[this.sideC()] = absPos[this.side]; + iSize[this.sideO()] = absPos[this.sideO()]; + iSize[this.sideX()] = absPos[this.sideX()]; + + let fSize = Object.assign({}, iSize); // Copy + fSize[this.side] = iSize[this.side] + this.sideSign() * this.halfWidth; + fSize[this.sideC()] = iSize[this.side] - this.sideSign() * this.halfWidth; + + animateObject(ResizeBar.bar, { + "onStart": bar => + { + bar.size = iSize; + bar.hidden = false; + }, + "size": fSize + }); +}; + +ResizeBar.prototype.hideResizeBar = function () +{ + let iSize = ResizeBar.bar.size; + let centerPos = (iSize[this.side] + iSize[this.sideC()]) * 0.5; + iSize[this.side] = centerPos; + iSize[this.sideC()] = centerPos; + + animateObject(ResizeBar.bar, { + "size": iSize, + "onComplete": bar => bar.hidden = true + }); +}; + +ResizeBar.prototype.tick = function () +{ + if (!ResizeBar.dragging) + { + let currentIn = this.mouseInside(); + // double check needed for bars intersection case (first added will have priority) + if (this.lastIn == currentIn && !ResizeBar.bar.hidden) return; + if (currentIn) this.viewResizeBar(); + else this.hideResizeBar(); + this.lastIn = currentIn; + return currentIn; + } + else if (this.dragging) + { + let size = ResizeBar.bar.size; + size[this.side] = ResizeBar.mouse[this.sideMouse()] + this.sideSign() * this.halfWidth; + size[this.sideC()] = ResizeBar.mouse[this.sideMouse()] - this.sideSign() * this.halfWidth; + ResizeBar.bar.size = size; + } +}; + +ResizeBar.prototype.dragUp = function () +{ + if (!this.mouseInside()) + return false; + + ResizeBar.mousePress.set(ResizeBar.mouse); + ResizeBar.dragging = true; + this.dragging = true; + return true; +}; + +ResizeBar.prototype.dragDown = function () +{ + if (!this.dragging) + return false; + + ResizeBar.mouseRelease.set(ResizeBar.mouse); + + let displacement = ResizeBar.mouseRelease[this.sideMouse()] - ResizeBar.mousePress[this.sideMouse()]; + if (displacement) + { + animateObject( + this.object, + { + "size": { [this.side]: this.object.size[this.side] + displacement }, + "onComplete": this.onDragDown + } + ); + for (let [object, side] of this.objectsHooked) + animateObject( + object, + { "size": { [side]: object.size[side] + displacement } } + ); + } + + ResizeBar.dragging = false; + this.dragging = false; + return true; +}; + + +var resizeBar = function (object, side, width, objectsHooked, isVisibleCondition, onDragDown) +{ + resizeBar.list.push(new ResizeBar(object, side, width, objectsHooked, isVisibleCondition, onDragDown)); +}; + +resizeBar.list = []; + +resizeBar.onEvent = function (event) +{ + if (resizeBar.firstTick) + return; + + switch (event.type) + { + case "mousebuttondown": + for (let bar of resizeBar.list) + if (bar.dragUp()) break; + break; + case "mousebuttonup": + for (let bar of resizeBar.list) + if (bar.dragDown()) break; + break; + case "mousemotion": + ResizeBar.mouse.set(event) + break; + } +} + +resizeBar.firstTick = true; + +resizeBar.onTick = function () +{ + // Don't process anything at the first tick (error otherwise) + switch (resizeBar.firstTick) + { + case true: + resizeBar.firstTick = false; + ResizeBar.bar = Engine.GetGUIObjectByName("glResizeBar"); + break; + default: + for (let bar of resizeBar.list) + if (bar.tick()) break; + } +} + +/* THIS NEEDS TO BE ADDED ON FILES WHERE YOU WANT TO USE IT + + function handleInputBeforeGui(ev) + { + resizeBar.onEvent(ev); + return false; + } + + function onTick(){ + resizeBar.onTick(); + } + +*/