-- OT-MMO: las ventanas propias recuerdan posición (y tamaño si se pide) entre sesiones (guía A.9, auditoría §6). -- Uso, una vez creada la ventana: OtmmoVentanas.recordar(ventana, 'libro') (o { tamano = true } si es redimensionable). -- Solo se guarda lo que el jugador movió a mano: si nunca la arrastró, sigue saliendo donde la pone su módulo. -- Al abrirse se recoloca y se encaja en su padre (bindRectToParent): si la resolución bajó, no queda fuera de pantalla. -- Al cambiar el tamaño de la pantalla, las abiertas se vuelven a encajar. OtmmoVentanas = {} local NODO = 'otmmo-ventanas' local registradas = {} -- [clave] = ventana local function datos() local t = g_settings.getNode(NODO) return type(t) == 'table' and t or {} end function OtmmoVentanas.guardar(w) local clave = w and w.otmmoClave if not clave or w:isDestroyed() then return end local t = datos() t[clave] = { x = w:getX(), y = w:getY(), w = w:getWidth(), h = w:getHeight() } g_settings.setNode(NODO, t) g_settings.save() end function OtmmoVentanas.aplicar(w) local d = w and w.otmmoClave and datos()[w.otmmoClave] if type(d) ~= 'table' or not tonumber(d.x) or not tonumber(d.y) then return false end w:breakAnchors() if w.otmmoTamano and tonumber(d.w) and tonumber(d.h) then w:resize(tonumber(d.w), tonumber(d.h)) w.otmmoResized = true end w:setPosition({ x = tonumber(d.x), y = tonumber(d.y) }) w:bindRectToParent() w.movida = true -- game_hud: la bolsa deja de pegarse al micromenú return true end function OtmmoVentanas.olvidar(clave) local t = datos() t[clave] = nil g_settings.setNode(NODO, t) end function OtmmoVentanas.recordar(w, clave, opciones) if not w or w.otmmoClave then return w end if not opciones or opciones.controles ~= false then OtmmoVentanas.controles(w) end w.otmmoClave = clave w.otmmoTamano = opciones and opciones.tamano or false registradas[clave] = w connect(w, { onVisibilityChange = function(self, visible) if visible then OtmmoVentanas.aplicar(self) end end, onDragLeave = function(self) OtmmoVentanas.guardar(self) end, onDestroy = function(self) if registradas[clave] == self then registradas[clave] = nil end end, }) if w:isVisible() then OtmmoVentanas.aplicar(w) end return w end -- Cambio de resolución: las ventanas abiertas vuelven dentro de su padre. 31-oct: desde su posición GUARDADA, no desde -- la ya encajada: al achicar la ventana y volver a agrandarla, cada una vuelve donde la dejó el jugador (antes se -- quedaba en el borde al que la empujó el tamaño pequeño, y dos barras podían acabar una encima de otra). Con una -- espera corta: arrastrar el borde del navegador da muchos cambios de tamaño seguidos. local recolocar = nil connect(rootWidget, { onGeometryChange = function() removeEvent(recolocar) recolocar = scheduleEvent(function() recolocar = nil for _, w in pairs(registradas) do if not w:isDestroyed() and w:isVisible() then if not OtmmoVentanas.aplicar(w) then w:bindRectToParent() end end end end, 160) end, }) function OtmmoVentanas.bloqueada() return g_settings.getBoolean('otmmo-ui-locked', false) end function OtmmoVentanas.alternarBloqueo() local locked = not OtmmoVentanas.bloqueada() g_settings.set('otmmo-ui-locked', locked) for _, name in ipairs({ 'actionBarBottomLocked', 'actionBarLeftLocked', 'actionBarRightLocked' }) do if modules.client_options then modules.client_options.setOption(name, locked) end end return locked end function OtmmoVentanas.cerrar(w) if w.onEscape then signalcall(w.onEscape, w) else w:hide() end end function OtmmoVentanas.plegar(w) if w.otmmoPlegados then local saved = w.otmmoPlegados w.otmmoPlegados = nil w:setHeight(saved.alto) for child, visible in pairs(saved.hijos) do if not child:isDestroyed() then child:setVisible(visible) end end if w.onUnfold then w:onUnfold() end else local saved = { alto = w:getHeight(), hijos = {} } for _, child in ipairs(w:getChildren()) do if child:getId() ~= 'otmmoClose' and child:getId() ~= 'otmmoCollapse' and child:getId() ~= 'cerrar' then saved.hijos[child] = child:isExplicitlyVisible() child:hide() end end w.otmmoPlegados = saved w:setHeight(36 + w:getPaddingBottom()) end end function OtmmoVentanas.moverCon(w, handle, clave) OtmmoVentanas.recordar(w, clave, { controles = false }) handle:setDraggable(true) handle.onMousePress = function() return true end handle.onDragEnter = function(h, pos) if OtmmoVentanas.bloqueada() then return false end local x, y = w:getX(), w:getY() w:breakAnchors() w:setPosition({ x = x, y = y }) h.ref = { x = pos.x - x, y = pos.y - y } return true end handle.onDragMove = function(h, pos) if not h.ref or OtmmoVentanas.bloqueada() then return false end w:setPosition({ x = pos.x - h.ref.x, y = pos.y - h.ref.y }) w:bindRectToParent() w.movida = true return true end handle.onDragLeave = function(h) h.ref = nil OtmmoVentanas.guardar(w) return true end end function OtmmoVentanas.redimensionar(w, minW, minH, changed) if w.otmmoResize then return end w.otmmoTamano = true local h = g_ui.createWidget('UIButton', w) w.otmmoResize = h h:setId('otmmoResize') h:setText('/') h:setSize({ width = 18, height = 18 }) h:addAnchor(AnchorRight, 'parent', AnchorRight) h:addAnchor(AnchorBottom, 'parent', AnchorBottom) h:setMarginRight(-w:getPaddingRight() + 2) h:setMarginBottom(-w:getPaddingBottom() + 2) h:setTooltip('Arrastra para cambiar el tamano') h:setDraggable(true) h.onMousePress = function() return true end h.onDragEnter = function(self, pos) if OtmmoVentanas.bloqueada() or w.otmmoPlegados then return false end self.ref = { x = pos.x, y = pos.y, w = w:getWidth(), h = w:getHeight() } return true end h.onDragMove = function(self, pos) if not self.ref or OtmmoVentanas.bloqueada() then return false end local parent = w:getParent() w:resize(math.min(parent:getWidth(), math.max(minW, self.ref.w + pos.x - self.ref.x)), math.min(parent:getHeight(), math.max(minH, self.ref.h + pos.y - self.ref.y))) w.otmmoResized = true w:bindRectToParent() if changed then changed() end return true end h.onDragLeave = function(self) self.ref = nil OtmmoVentanas.guardar(w) return true end end function OtmmoVentanas.controles(w) if not w or w:isDestroyed() or w.otmmoClose then return end local layout = w:getLayout() if layout and not layout:isUIAnchorLayout() then return end g_ui.createWidget('OtmmoWindowClose', w) g_ui.createWidget('OtmmoWindowCollapse', w) end