a lot of changes in modules

This commit is contained in:
Eduardo Bart 2012-02-06 17:19:47 -02:00
parent add8505a5b
commit 88301c329a
50 changed files with 488 additions and 322 deletions

3
addons/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!/README.txt
!.gitignore

1
addons/README.txt Normal file
View File

@ -0,0 +1 @@
You can plance any personal addons here.

View File

@ -1,24 +0,0 @@
Module
name: client
description: Load all other otclient dependecies
author: OTClient team
website: https://github.com/edubart/otclient
canUnload: false
// NOTE: order does matter
dependencies:
- client_background
- client_topmenu
- client_tibiafiles
- client_about
- client_options
- client_entergame
- client_modulemanager
- game
onLoad: |
dofile 'client'
Client.init()
onUnload: |
Client.terminate()

View File

@ -3,6 +3,12 @@ Module
description: Create the about window description: Create the about window
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 160
unloadable: true
dependencies:
- client_topmenu
onLoad: | onLoad: |
dofile 'about' dofile 'about'

View File

@ -3,6 +3,8 @@ Module
description: Handles the background of the login screen description: Handles the background of the login screen
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 110
onLoad: | onLoad: |
dofile 'background' dofile 'background'

View File

@ -42,11 +42,11 @@ local function tryLogin(charInfo, tries)
Game.loginWorld(EnterGame.account, EnterGame.password, charInfo.worldHost, charInfo.worldPort, charInfo.characterName) Game.loginWorld(EnterGame.account, EnterGame.password, charInfo.worldHost, charInfo.worldPort, charInfo.characterName)
loadBox = displayCancelBox('Please wait', 'Connecting to game server...') loadBox = displayCancelBox('Please wait', 'Connecting to game server...')
function loadBox.onCancel() connect(loadBox, { onCancel = function()
loadBox = nil loadBox = nil
Game.cancelLogin() Game.cancelLogin()
CharacterList.show() CharacterList.show()
end end })
-- save last used character -- save last used character
Settings.set('lastUsedCharacter', charInfo.characterName) Settings.set('lastUsedCharacter', charInfo.characterName)

View File

@ -8,7 +8,6 @@ local motdMessage
local motdButton local motdButton
local enterGameButton local enterGameButton
-- private functions -- private functions
local function clearAccountFields() local function clearAccountFields()
enterGame:getChildById('accountNameLineEdit'):clearText() enterGame:getChildById('accountNameLineEdit'):clearText()
@ -20,11 +19,13 @@ end
local function onError(protocol, message, connectionError) local function onError(protocol, message, connectionError)
loadBox:destroy() loadBox:destroy()
loadBox = nil
if not connectionError then if not connectionError then
clearAccountFields() clearAccountFields()
end end
local errorBox = displayErrorBox('Login Error', message) local errorBox = displayErrorBox('Login Error', message)
errorBox.onOk = EnterGame.show connect(errorBox, { onOk = EnterGame.show })
end end
local function onMotd(protocol, motd) local function onMotd(protocol, motd)
@ -43,13 +44,15 @@ local function onCharacterList(protocol, characters, premDays)
end end
loadBox:destroy() loadBox:destroy()
loadBox = nil
CharacterList.create(characters, premDays) CharacterList.create(characters, premDays)
local lastMotdNumber = Settings.getNumber("motd") local lastMotdNumber = Settings.getNumber("motd")
if motdNumber and motdNumber ~= lastMotdNumber then if motdNumber and motdNumber ~= lastMotdNumber then
Settings.set("motd", motdNumber) Settings.set("motd", motdNumber)
local motdBox = displayInfoBox("Message of the day", motdMessage) local motdBox = displayInfoBox("Message of the day", motdMessage)
motdBox.onOk = CharacterList.show connect(motdBox, { onOk = CharacterList.show })
CharacterList.hide() CharacterList.hide()
end end
end end
@ -76,9 +79,14 @@ function EnterGame.init()
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0) enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
enterGame:getChildById('accountNameLineEdit'):focus() enterGame:getChildById('accountNameLineEdit'):focus()
-- only open entergame when app starts
if not g_app.isRunning() then
if #account > 0 and autologin then if #account > 0 and autologin then
addEvent(EnterGame.doLogin) addEvent(EnterGame.doLogin)
end end
else
enterGame:hide()
end
end end
function EnterGame.terminate() function EnterGame.terminate()
@ -124,10 +132,11 @@ function EnterGame.doLogin()
protocolLogin.onCharacterList = onCharacterList protocolLogin.onCharacterList = onCharacterList
loadBox = displayCancelBox('Please wait', 'Connecting to login server...') loadBox = displayCancelBox('Please wait', 'Connecting to login server...')
loadBox.onCancel = function(msgbox) connect(loadBox, { onCancel = function(msgbox)
loadBox = nil
protocolLogin:cancelLogin() protocolLogin:cancelLogin()
EnterGame.show() EnterGame.show()
end end })
protocolLogin:login(EnterGame.host, EnterGame.port, EnterGame.account, EnterGame.password) protocolLogin:login(EnterGame.host, EnterGame.port, EnterGame.account, EnterGame.password)
end end

View File

@ -3,6 +3,8 @@ Module
description: Manages enter game and character list windows description: Manages enter game and character list windows
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 150
onLoad: | onLoad: |
dofile 'entergame' dofile 'entergame'

View File

@ -34,5 +34,4 @@ function Client.terminate()
Settings.set('window-size', g_window.getUnmaximizedSize()) Settings.set('window-size', g_window.getUnmaximizedSize())
Settings.set('window-pos', g_window.getUnmaximizedPos()) Settings.set('window-pos', g_window.getUnmaximizedPos())
Settings.set('window-maximized', g_window.isMaximized()) Settings.set('window-maximized', g_window.isMaximized())
g_window.hide()
end end

View File

@ -0,0 +1,14 @@
Module
name: client_main
description: Initialize the client and setups its main window
author: OTClient team
website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 100
onLoad: |
dofile 'client'
Client.init()
onUnload: |
Client.terminate()

View File

Before

Width:  |  Height:  |  Size: 518 B

After

Width:  |  Height:  |  Size: 518 B

View File

@ -54,25 +54,40 @@ function ModuleManager.refreshModules()
end end
function ModuleManager.listModules() function ModuleManager.listModules()
if not moduleManagerWindow then return end
moduleList:destroyChildren() moduleList:destroyChildren()
local modules = g_modules.getModules() local modules = g_modules.getModules()
for i,module in ipairs(modules) do for i,module in ipairs(modules) do
local label = createWidget('ModuleListLabel', moduleList) local label = createWidget('ModuleListLabel', moduleList)
label:setText(module:getName()) label:setText(module:getName())
label:setOn(module:isLoaded())
end end
moduleList:focusChild(moduleList:getFirstChild(), ActiveFocusReason) moduleList:focusChild(moduleList:getFirstChild(), ActiveFocusReason)
end end
function ModuleManager.refreshLoadedModules()
if not moduleManagerWindow then return end
for i,child in ipairs(moduleList:getChildren()) do
local module = g_modules.getModule(child:getText())
child:setOn(module:isLoaded())
end
end
function ModuleManager.updateModuleInfo(moduleName) function ModuleManager.updateModuleInfo(moduleName)
if not moduleManagerWindow then return end
local name = '' local name = ''
local description = '' local description = ''
local autoLoad = '' local autoLoad = ''
local author = '' local author = ''
local website = '' local website = ''
local version = '' local version = ''
local canLoad = false local loaded = false
local canReload = false
local canUnload = false local canUnload = false
local module = g_modules.getModule(moduleName) local module = g_modules.getModule(moduleName)
@ -82,8 +97,9 @@ function ModuleManager.updateModuleInfo(moduleName)
author = module:getAuthor() author = module:getAuthor()
website = module:getWebsite() website = module:getWebsite()
version = module:getVersion() version = module:getVersion()
canUnload = module:isLoaded() loaded = module:isLoaded()
canLoad = not canUnload canUnload = module:canUnload()
canReload = not loaded or canUnload
end end
moduleManagerWindow:recursiveGetChildById('moduleName'):setText(name) moduleManagerWindow:recursiveGetChildById('moduleName'):setText(name)
@ -93,17 +109,26 @@ function ModuleManager.updateModuleInfo(moduleName)
moduleManagerWindow:recursiveGetChildById('moduleWebsite'):setText(website) moduleManagerWindow:recursiveGetChildById('moduleWebsite'):setText(website)
moduleManagerWindow:recursiveGetChildById('moduleVersion'):setText(version) moduleManagerWindow:recursiveGetChildById('moduleVersion'):setText(version)
moduleManagerWindow:recursiveGetChildById('moduleLoadButton'):setEnabled(canLoad) local reloadButton = moduleManagerWindow:recursiveGetChildById('moduleReloadButton')
moduleManagerWindow:recursiveGetChildById('moduleUnloadButton'):setEnabled(canUnload) reloadButton:setEnabled(canReload)
reloadButton:setVisible(true)
if loaded then reloadButton:setText('Reload')
else reloadButton:setText('Load') end
local unloadButton = moduleManagerWindow:recursiveGetChildById('moduleUnloadButton')
unloadButton:setVisible(true)
unloadButton:setEnabled(canUnload)
end end
function ModuleManager.loadCurrentModule() function ModuleManager.reloadCurrentModule()
local focusedChild = moduleList:getFocusedChild() local focusedChild = moduleList:getFocusedChild()
if focusedChild then if focusedChild then
local module = g_modules.getModule(focusedChild:getText()) local module = g_modules.getModule(focusedChild:getText())
if module then if module then
module:load() module:reload()
ModuleManager.updateModuleInfo(module:getName()) ModuleManager.updateModuleInfo(module:getName())
ModuleManager.refreshLoadedModules()
ModuleManager.show()
end end
end end
end end
@ -115,7 +140,14 @@ function ModuleManager.unloadCurrentModule()
if module then if module then
module:unload() module:unload()
ModuleManager.updateModuleInfo(module:getName()) ModuleManager.updateModuleInfo(module:getName())
ModuleManager.refreshLoadedModules()
end end
end end
end end
function ModuleManager.reloadAllModules()
g_modules.reloadModules()
ModuleManager.refreshLoadedModules()
ModuleManager.show()
end

View File

@ -3,6 +3,12 @@ Module
description: Manage other modules description: Manage other modules
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 140
dependencies:
- client_topmenu
onLoad: | onLoad: |
dofile 'modulemanager' dofile 'modulemanager'
ModuleManager.init() ModuleManager.init()

View File

@ -3,11 +3,21 @@ ModuleListLabel < Label
background-color: alpha background-color: alpha
text-offset: 2 0 text-offset: 2 0
focusable: true focusable: true
color: #cccccc
$focus: $focus:
background-color: #ffffff22
color: #ffffff color: #ffffff
$on:
background-color: #006600
$!on:
background-color: #660000
$on focus:
background-color: #004400
$!on focus:
background-color: #440000
ModuleInfoLabel < Label ModuleInfoLabel < Label
$!first: $!first:
margin-top: 5 margin-top: 5
@ -19,10 +29,11 @@ ModuleValueLabel < UILabel
text-offset: 3 0 text-offset: 3 0
image-source: /core_styles/images/panel_flat.png image-source: /core_styles/images/panel_flat.png
image-border: 1 image-border: 1
height: 16
MainWindow MainWindow
id: moduleManagerWindow id: moduleManagerWindow
size: 450 450 size: 480 450
text: Module Manager text: Module Manager
@onEscape: ModuleManager.hide() @onEscape: ModuleManager.hide()
@ -38,21 +49,31 @@ MainWindow
margin-bottom: 30 margin-bottom: 30
Button Button
id: refreshModulesButton
anchors.top: moduleList.bottom anchors.top: moduleList.bottom
anchors.horizontalCenter: moduleList.horizontalCenter anchors.left: moduleList.left
margin-top: 8 margin-top: 8
width: 80
text: Refresh text: Refresh
@onClick: ModuleManager.refreshModules() @onClick: ModuleManager.refreshModules()
Button
id: reloadAllModulesButton
anchors.top: moduleList.bottom
anchors.right: moduleList.right
margin-top: 8
width: 80
text: Reload All
@onClick: ModuleManager.reloadAllModules()
Panel Panel
id: moduleInfo id: moduleInfo
anchors.left: moduleList.right anchors.left: moduleList.right
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
margin: 0 5 5 15 margin: 0 5 5 15
layout: layout: verticalBox
type: verticalBox height: 265
fit-children: true
ModuleInfoLabel ModuleInfoLabel
text: Module name text: Module name
@ -65,11 +86,6 @@ MainWindow
id: moduleDescription id: moduleDescription
height: 100 height: 100
ModuleInfoLabel
text: Loaded
ModuleValueLabel
id: moduleLoaded
//ModuleInfoLabel //ModuleInfoLabel
// text: Autoload // text: Autoload
//ModuleValueLabel //ModuleValueLabel
@ -97,13 +113,13 @@ MainWindow
id: moduleVersion id: moduleVersion
Button Button
id: moduleLoadButton id: moduleReloadButton
anchors.top: moduleInfo.bottom anchors.top: moduleInfo.bottom
anchors.left: moduleInfo.left anchors.left: moduleInfo.left
margin-top: 8 margin-top: 8
text: Load text: Load
enabled: false visible: false
@onClick: ModuleManager.loadCurrentModule() @onClick: ModuleManager.reloadCurrentModule()
Button Button
id: moduleUnloadButton id: moduleUnloadButton
@ -112,6 +128,6 @@ MainWindow
margin-left: 10 margin-left: 10
margin-top: 8 margin-top: 8
text: Unload text: Unload
enabled: false visible: false
@onClick: ModuleManager.unloadCurrentModule() @onClick: ModuleManager.unloadCurrentModule()

View File

@ -3,6 +3,11 @@ Module
description: Create the options window description: Create the options window
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 130
dependencies:
- client_topmenu
onLoad: | onLoad: |
dofile 'options' dofile 'options'

View File

@ -45,14 +45,6 @@ function quit()
exit() exit()
end end
function reloadModule(name)
local module = g_modules.getModule(name)
if module then
module:unload()
module:load()
end
end
function autoReloadModule(name) function autoReloadModule(name)
local function reloadEvent() local function reloadEvent()
reloadModule(name) reloadModule(name)

View File

@ -86,7 +86,10 @@ end
local function doCommand() local function doCommand()
local currentCommand = commandLineEdit:getText() local currentCommand = commandLineEdit:getText()
Terminal.executeCommand(currentCommand) Terminal.executeCommand(currentCommand)
if commandLineEdit then
commandLineEdit:clearText() commandLineEdit:clearText()
end
return true return true
end end

View File

@ -1,11 +1,10 @@
Module Module
name: terminal name: client_terminal
description: Terminal for executing lua functions description: Terminal for executing lua functions
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoLoad: true autoload-antecedence: 160
autoLoadAntecedence: 200
onLoad: | onLoad: |
dofile 'terminal' dofile 'terminal'

View File

Before

Width:  |  Height:  |  Size: 459 B

After

Width:  |  Height:  |  Size: 459 B

View File

@ -24,6 +24,9 @@ function TopMenu.init()
TopMenu.addRightButton('logoutButton', 'Logout (Ctrl+Q)', '/core_styles/icons/logout.png', onLogout) TopMenu.addRightButton('logoutButton', 'Logout (Ctrl+Q)', '/core_styles/icons/logout.png', onLogout)
Keyboard.bindKeyDown('Ctrl+Q', onLogout) Keyboard.bindKeyDown('Ctrl+Q', onLogout)
connect(Game, { onLogin = TopMenu.showGameButtons,
onLogout = TopMenu.hideGameButtons })
end end
function TopMenu.terminate() function TopMenu.terminate()
@ -33,6 +36,9 @@ function TopMenu.terminate()
gameButtonsPanel = nil gameButtonsPanel = nil
topMenu:destroy() topMenu:destroy()
topMenu = nil topMenu = nil
disconnect(Game, { onLogin = TopMenu.showGameButtons,
onLogout = TopMenu.hideGameButtons })
end end
function TopMenu.addButton(id, description, icon, callback, right) function TopMenu.addButton(id, description, icon, callback, right)
@ -82,6 +88,3 @@ end
function TopMenu.getButton(id) function TopMenu.getButton(id)
return topMenu:recursiveGetChildById(id) return topMenu:recursiveGetChildById(id)
end end
connect(Game, { onLogin = TopMenu.showGameButtons,
onLogout = TopMenu.hideGameButtons })

View File

@ -3,6 +3,8 @@ Module
description: Create the top menu description: Create the top menu
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 120
onLoad: | onLoad: |
dofile 'topmenu' dofile 'topmenu'

View File

@ -1,17 +0,0 @@
Module
name: core
description: Contains lua classes, functions and constants used by other modules
author: OTClient team
website: https://github.com/edubart/otclient
// core must be loaded before other modules
autoLoad: true
autoLoadAntecedence: 10
// NOTE: order does matter
dependencies:
- core_lib
- core_fonts
- core_styles
- core_widgets

View File

@ -3,7 +3,8 @@ Module
description: Contains fonts used by core description: Contains fonts used by core
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
canUnload: false autoload: true
autoload-antecedence: 30
onLoad: | onLoad: |
importFont 'verdana-11px-antialised' importFont 'verdana-11px-antialised'

View File

@ -3,6 +3,8 @@ Module
description: Contains core lua classes, functions and constants used by other modules description: Contains core lua classes, functions and constants used by other modules
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoload: true
autoload-antecedence: 10
onLoad: | onLoad: |
dofile 'ext/table' dofile 'ext/table'
@ -21,5 +23,3 @@ Module
dofile 'keyboard' dofile 'keyboard'
dofile 'mouse' dofile 'mouse'
onUnload: |
rootWidget = nil

View File

@ -1,34 +1,20 @@
local eventId = 0
local eventList = {}
function scheduleEvent(func, delay) function scheduleEvent(func, delay)
if not func then return end local event = g_dispatcher.scheduleEvent(callback, delay)
eventId = eventId + 1
local id = eventId -- must hold a reference to the callback, otherwise it would be collected
local function proxyFunc() event._callback = callback
if eventList[id] then return event
if eventList[id].active then
func()
end
eventList[id] = nil
end
end
eventList[id] = { func = proxyFunc, active = true }
if delay and delay > 0 then
g_dispatcher.scheduleEvent(proxyFunc, delay)
else
g_dispatcher.addEvent(proxyFunc, false)
end
return id
end end
function addEvent(func) function addEvent(callback, front)
return scheduleEvent(func, 0) local event = g_dispatcher.addEvent(callback, front)
-- must hold a reference to the callback, otherwise it would be collected
event._callback = callback
return event
end end
function removeEvent(id) function removeEvent(event)
if id and eventList[id] then if event then
eventList[id].active = false event:cancel()
return true
end end
end end

View File

@ -74,3 +74,16 @@ function createWidget(style, parent)
widget:setStyle(style) widget:setStyle(style)
return widget return widget
end end
function reloadModule(name)
local module = g_modules.getModule(name)
if module then
module:reload()
end
end
function reloadModules()
g_modules.reloadModules()
end

View File

@ -35,6 +35,28 @@ function connect(object, signalsAndSlots, pushFront)
end end
end end
function disconnect(object, signalsAndSlots)
for signal,slot in pairs(signalsAndSlots) do
if not object[signal] then
elseif type(object[signal]) == 'function' then
if object[signal] == slot then
object[signal] = nil
end
elseif type(object[signal]) == 'table' then
for k,func in pairs(object[signal]) do
if func == slot then
table.remove(object[signal], k)
if #object[signal] == 1 then
object[signal] = object[signal][1]
end
break
end
end
end
end
end
function extends(base) function extends(base)
local derived = {} local derived = {}
function derived.internalCreate() function derived.internalCreate()

View File

@ -3,6 +3,9 @@ Module
description: Contains ui styles used by other modules description: Contains ui styles used by other modules
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
reloadable: true
autoload: true
autoload-antecedence: 20
onLoad: | onLoad: |
importStyle 'styles/buttons.otui' importStyle 'styles/buttons.otui'
@ -20,3 +23,4 @@ Module
importStyle 'styles/popupmenus.otui' importStyle 'styles/popupmenus.otui'
importStyle 'styles/comboboxes.otui' importStyle 'styles/comboboxes.otui'
importStyle 'styles/spinboxes.otui' importStyle 'styles/spinboxes.otui'
importStyle 'styles/messagebox.otui'

View File

@ -0,0 +1,19 @@
MessageBoxWindow < MainWindow
id: messageBoxWindow
anchors.centerIn: parent
height: 60
width: 80
padding-bottom: 10
padding-right: 10
MessageBoxLabel < Label
id: messageBoxLabel
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
MessageBoxRightButton < Button
id: messageBoxRightButton
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 64
visible: true

View File

@ -1,20 +1,4 @@
Window < UIWindow Window < UIWindow
font: verdana-11px-antialised
size: 200 200
opacity: 1
color: white
text-offset: 0 2
text-align: top
move-policy: free
stackable: true
image-source: /core_styles/images/window.png
image-border: 4
image-border-top: 20
$disabled:
color: #aaaaaa88
Window2 < UIWindow
font: verdana-11px-antialised font: verdana-11px-antialised
size: 200 200 size: 200 200
opacity: 1 opacity: 1
@ -31,7 +15,7 @@ Window2 < UIWindow
$disabled: $disabled:
color: #aaaaaa88 color: #aaaaaa88
MainWindow < Window2 MainWindow < Window
anchors.centerIn: parent anchors.centerIn: parent
MiniWindow < UIWindow MiniWindow < UIWindow

View File

@ -3,6 +3,10 @@ Module
description: Contains widgets used by other modules description: Contains widgets used by other modules
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
reloadable: true
unloadble: false
autoload: true
autoload-antecedence: 40
onLoad: | onLoad: |
dofile 'uiwidget' dofile 'uiwidget'
@ -16,6 +20,12 @@ Module
dofile 'uipopupmenu' dofile 'uipopupmenu'
dofile 'uiwindow' dofile 'uiwindow'
dofile 'uiitem' dofile 'uiitem'
dofile 'tooltip/tooltip' dofile 'uimessagebox'
dofile 'messagebox/messagebox'
dofile 'tooltip'
--dofile 'messagebox/messagebox'
ToolTip.init()
onUnload: |
ToolTip.terminate()

View File

@ -1,81 +0,0 @@
MessageBox = {}
MessageBox.__index = MessageBox
-- messagebox flags
MessageBoxOk = 1
MessageBoxCancel = 2
function MessageBox.create(title, text, flags)
local box = {}
setmetatable(box, MessageBox)
-- create messagebox window
local window = displayUI('messagebox.otui')
window:lock()
window:setText(title)
local label = window:getChildById('messageBoxLabel')
label:setText(text)
label:resizeToText()
-- set window size based on label size
window:setWidth(math.max(label:getWidth() + 48, 120))
window:setHeight(label:getHeight() + 64)
-- setup messagebox first button
local buttonRight = window:getChildById('messageBoxRightButton')
if flags == MessageBoxOk then
buttonRight:setText("Ok")
box.onOk = function() end
buttonRight.onClick = function()
box.onOk()
box:destroy()
end
window.onEnter = buttonRight.onClick
window.onEscape = buttonRight.onClick
elseif flags == MessageBoxCancel then
buttonRight:setText("Cancel")
box.onCancel = function() end
buttonRight.onClick = function()
box.onCancel()
box:destroy()
end
window.onEnter = buttonRight.onClick
window.onEscape = buttonRight.onClick
end
box.window = window
return box
end
function MessageBox:destroy()
if self.onDestroy then
self.onDestroy()
self.onDestroy = nil
end
if self.window then
self.window:destroy()
self.window = nil
end
self.onOk = nil
self.onCancel = nil
end
-- shortcuts for creating message boxes
function displayMessageBox(title, text, flags)
return MessageBox.create(title, text, flags)
end
function displayErrorBox(title, text)
return MessageBox.create(title, text, MessageBoxOk)
end
function displayInfoBox(title, text)
return MessageBox.create(title, text, MessageBoxOk)
end
function displayCancelBox(title, text)
return MessageBox.create(title, text, MessageBoxCancel)
end

View File

@ -1,21 +0,0 @@
Window
id: messageBoxWindow
anchors.centerIn: parent
height: 80
width: 120
Label
id: messageBoxLabel
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
margin-top: 27
margin-bottom : 27
Button
id: messageBoxRightButton
anchors.bottom: parent.bottom
anchors.right: parent.right
margin-right: 10
margin-bottom: 10
width: 64
visible: true

View File

@ -6,6 +6,8 @@ local currentHoveredWidget
-- private functions -- private functions
local function moveToolTip(tooltip) local function moveToolTip(tooltip)
if not tooltip:isVisible() then return end
local pos = g_window.getMousePosition() local pos = g_window.getMousePosition()
pos.y = pos.y + 1 pos.y = pos.y + 1
local xdif = g_window.getSize().width - (pos.x + tooltip:getWidth()) local xdif = g_window.getSize().width - (pos.x + tooltip:getWidth())
@ -17,28 +19,6 @@ local function moveToolTip(tooltip)
tooltip:setPosition(pos) tooltip:setPosition(pos)
end end
-- public functions
function ToolTip.display(text)
if text == nil then return end
ToolTip.hide()
toolTipLabel = createWidget('Label', rootWidget)
toolTipLabel:setId('toolTip')
toolTipLabel:setBackgroundColor('#111111bb')
toolTipLabel:setText(text)
toolTipLabel:resizeToText()
toolTipLabel:resize(toolTipLabel:getWidth() + 4, toolTipLabel:getHeight() + 4)
toolTipLabel.onMouseMove = moveToolTip
moveToolTip(toolTipLabel)
end
function ToolTip.hide()
if toolTipLabel then
toolTipLabel:destroy()
toolTipLabel = nil
end
end
-- UIWidget hooks
local function onWidgetHoverChange(widget, hovered) local function onWidgetHoverChange(widget, hovered)
if hovered then if hovered then
if widget.tooltip then if widget.tooltip then
@ -59,8 +39,39 @@ local function onWidgetStyleApply(widget, styleName, styleNode)
end end
end end
-- public functions
function ToolTip.init()
toolTipLabel = createWidget('Label', rootWidget)
toolTipLabel:setId('toolTip')
toolTipLabel:setBackgroundColor('#111111bb')
connect(toolTipLabel, { onMouseMove = moveToolTip })
connect(UIWidget, { onStyleApply = onWidgetStyleApply, connect(UIWidget, { onStyleApply = onWidgetStyleApply,
onHoverChange = onWidgetHoverChange}) onHoverChange = onWidgetHoverChange})
end
function ToolTip.terminate()
disconnect(UIWidget, { onStyleApply = onWidgetStyleApply,
onHoverChange = onWidgetHoverChange })
currentHoveredWidget = nil
toolTipLabel:destroy()
toolTipLabel = nil
end
function ToolTip.display(text)
if text == nil then return end
toolTipLabel:setText(text)
toolTipLabel:resizeToText()
toolTipLabel:resize(toolTipLabel:getWidth() + 4, toolTipLabel:getHeight() + 4)
toolTipLabel:show()
toolTipLabel:raise()
moveToolTip(toolTipLabel)
end
function ToolTip.hide()
toolTipLabel:hide()
end
-- UIWidget extensions -- UIWidget extensions
function UIWidget:setTooltip(text) function UIWidget:setTooltip(text)

View File

@ -1,7 +0,0 @@
Label
id: toolTipText
background-color: #111111bb
size: 200 200
id: toolTip
focusable: false
anchors.centerIn: parent

View File

@ -1,23 +1,64 @@
--[[
UIMessageBox = extends(UIWindow) UIMessageBox = extends(UIWindow)
function UIMessageBox.create(title, message) MessageBoxOk = 1
MessageBoxCancel = 2
-- messagebox cannot be created from otui files
UIMessageBox.create = nil
function UIMessageBox.display(title, message, flags)
local messagebox = UIMessageBox.internalCreate() local messagebox = UIMessageBox.internalCreate()
rootWidget:addChild(messagebox)
messagebox:setStyle('MessageBoxWindow')
messagebox:setText(title) messagebox:setText(title)
local messageLabel = self:getChildById('messageLabel')
label:setText(message)
label:resizeToText()
window:setWidth(math.max(label:getWidth() + self:getPaddingLeft() + self:getPaddingRight(), self:getWidth())) local messageLabel = createWidget('MessageBoxLabel', messagebox)
window:setHeight(label:getHeight() + self:getPaddingTop() + self:getPaddingBottom()) messageLabel:setText(message)
messageLabel:resizeToText()
messagebox:setWidth(math.max(messageLabel:getWidth() + 48, messagebox:getWidth()))
messagebox:setHeight(math.max(messageLabel:getHeight() + 64, messagebox:getHeight()))
-- setup messagebox first button
local buttonRight = createWidget('MessageBoxRightButton', messagebox)
if flags == MessageBoxOk then
buttonRight:setText('Ok')
connect(buttonRight, { onClick = function(self) self:getParent():ok() end })
elseif flags == MessageBoxCancel then
buttonRight:setText('Cancel')
connect(buttonRight, { onClick = function(self) self:getParent():cancel() end })
end
connect(messagebox, { onEnter = function(self) self:destroy() end })
connect(messagebox, { onEscape = function(self) self:destroy() end })
messagebox:lock()
return messagebox return messagebox
end end
function UIMessageBox:setTitle(title) function displayInfoBox(title, message)
return UIMessageBox.display(title, message, MessageBoxOk)
end end
function UIMessageBox:setMessage(message) function displayErrorBox(title, message)
return UIMessageBox.display(title, message, MessageBoxOk)
end
function displayCancelBox(title, message)
return UIMessageBox.display(title, message, MessageBoxCancel)
end
function UIMessageBox:ok()
signalcall(self.onOk, self)
self.onOk = nil
self:destroy()
end
function UIMessageBox:cancel()
signalcall(self.onCancel, self)
self.onCancel = nil
self:destroy()
end end
]]--

View File

@ -90,13 +90,13 @@ end
function Game.onLoginError(message) function Game.onLoginError(message)
CharacterList.destroyLoadBox() CharacterList.destroyLoadBox()
local errorBox = displayErrorBox("Login Error", "Login error: " .. message) local errorBox = displayErrorBox("Login Error", "Login error: " .. message)
errorBox.onOk = CharacterList.show connect(errorBox, { onOk = CharacterList.show })
end end
function Game.onConnectionError(message) function Game.onConnectionError(message)
CharacterList.destroyLoadBox() CharacterList.destroyLoadBox()
local errorBox = displayErrorBox("Login Error", "Connection error: " .. message) local errorBox = displayErrorBox("Login Error", "Connection error: " .. message)
errorBox.onOk = CharacterList.show connect(errorBox, { onOk = CharacterList.show })
end end
local function onApplicationClose() local function onApplicationClose()

View File

@ -30,5 +30,4 @@ UIGame
id: mouseGrabber id: mouseGrabber
focusable: false focusable: false
visible: false visible: false
phantom: true

View File

@ -33,7 +33,7 @@ public:
Event(const SimpleCallback& callback) : m_callback(callback), m_canceled(false), m_executed(false) { } Event(const SimpleCallback& callback) : m_callback(callback), m_canceled(false), m_executed(false) { }
void execute() { void execute() {
if(!m_canceled && !m_executed) { if(!m_canceled && !m_executed && m_callback) {
m_callback(); m_callback();
m_executed = true; m_executed = true;
} }

View File

@ -52,8 +52,10 @@ bool Module::load()
if(m_loadCallback) if(m_loadCallback)
m_loadCallback(); m_loadCallback();
logInfo("Loaded module '", m_name, "'");
m_loaded = true; m_loaded = true;
logInfo("Loaded module '", m_name, "'");
g_modules.updateModuleLoadOrder(asModule());
return true; return true;
} }
@ -63,9 +65,33 @@ void Module::unload()
if(m_unloadCallback) if(m_unloadCallback)
m_unloadCallback(); m_unloadCallback();
m_loaded = false; m_loaded = false;
logInfo("Unloaded module '", m_name, "'");
g_modules.updateModuleLoadOrder(asModule());
} }
} }
bool Module::reload()
{
unload();
return load();
}
bool Module::isDependent()
{
for(const ModulePtr& module : g_modules.getModules()) {
if(module->isLoaded() && module->hasDependency(m_name))
return true;
}
return false;
}
bool Module::hasDependency(const std::string& name)
{
if(std::find(m_dependencies.begin(), m_dependencies.end(), name) != m_dependencies.end())
return true;
return false;
}
void Module::discover(const OTMLNodePtr& moduleNode) void Module::discover(const OTMLNodePtr& moduleNode)
{ {
const static std::string none = "none"; const static std::string none = "none";
@ -73,8 +99,9 @@ void Module::discover(const OTMLNodePtr& moduleNode)
m_author = moduleNode->valueAt("author", none); m_author = moduleNode->valueAt("author", none);
m_website = moduleNode->valueAt("website", none); m_website = moduleNode->valueAt("website", none);
m_version = moduleNode->valueAt("version", none); m_version = moduleNode->valueAt("version", none);
m_autoLoad = moduleNode->valueAt<bool>("autoLoad", false); m_autoLoad = moduleNode->valueAt<bool>("autoload", false);
m_autoLoadAntecedence = moduleNode->valueAt<int>("autoLoadAntecedence", 100); m_unloadable = moduleNode->valueAt<bool>("unloadable", true);
m_autoLoadAntecedence = moduleNode->valueAt<int>("autoload-antecedence", 9999);
if(OTMLNodePtr node = moduleNode->get("dependencies")) { if(OTMLNodePtr node = moduleNode->get("dependencies")) {
for(const OTMLNodePtr& tmp : node->children()) for(const OTMLNodePtr& tmp : node->children())
@ -95,4 +122,3 @@ void Module::discover(const OTMLNodePtr& moduleNode)
m_unloadCallback = g_lua.polymorphicPop<SimpleCallback>(); m_unloadCallback = g_lua.polymorphicPop<SimpleCallback>();
} }
} }

View File

@ -35,8 +35,12 @@ public:
bool load(); bool load();
void unload(); void unload();
bool reload();
bool canUnload() { return m_loaded && m_unloadable && !isDependent(); }
bool isLoaded() { return m_loaded; } bool isLoaded() { return m_loaded; }
bool isDependent();
bool hasDependency(const std::string& name);
std::string getDescription() { return m_description; } std::string getDescription() { return m_description; }
std::string getName() { return m_name; } std::string getName() { return m_name; }
@ -46,6 +50,8 @@ public:
bool isAutoLoad() { return m_autoLoad; } bool isAutoLoad() { return m_autoLoad; }
int getAutoLoadAntecedence() { return m_autoLoadAntecedence; } int getAutoLoadAntecedence() { return m_autoLoadAntecedence; }
ModulePtr asModule() { return std::static_pointer_cast<Module>(shared_from_this()); }
protected: protected:
void discover(const OTMLNodePtr& moduleNode); void discover(const OTMLNodePtr& moduleNode);
friend class ModuleManager; friend class ModuleManager;
@ -53,6 +59,7 @@ protected:
private: private:
Boolean<false> m_loaded; Boolean<false> m_loaded;
Boolean<false> m_autoLoad; Boolean<false> m_autoLoad;
Boolean<true> m_unloadable;
int m_autoLoadAntecedence; int m_autoLoadAntecedence;
std::string m_name; std::string m_name;
std::string m_description; std::string m_description;

View File

@ -61,13 +61,13 @@ void ModuleManager::autoLoadModules(int maxAntecedence)
void ModuleManager::discoverModulesPath() void ModuleManager::discoverModulesPath()
{ {
// search for modules directory // search for modules directory
std::string possibleDirs[] = { "modules", std::string possibleModulesDirs[] = { "modules",
g_resources.getBaseDir() + "modules", g_resources.getBaseDir() + "modules",
g_resources.getBaseDir() + "../modules", g_resources.getBaseDir() + "../modules",
g_resources.getBaseDir() + "../share/" + g_app->getAppName() + "/modules", g_resources.getBaseDir() + "../share/" + g_app->getAppName() + "/modules",
"" }; "" };
bool found = false; bool found = false;
for(const std::string& dir : possibleDirs) { for(const std::string& dir : possibleModulesDirs) {
// try to add module directory // try to add module directory
if(g_resources.addToSearchPath(dir, false)) { if(g_resources.addToSearchPath(dir, false)) {
logInfo("Using modules directory '", dir.c_str(), "'"); logInfo("Using modules directory '", dir.c_str(), "'");
@ -78,6 +78,21 @@ void ModuleManager::discoverModulesPath()
if(!found) if(!found)
logFatal("Could not find modules directory"); logFatal("Could not find modules directory");
// search for addons directory
std::string possibleAddonsDirs[] = { "addons",
g_resources.getBaseDir() + "addons",
g_resources.getBaseDir() + "../addons",
g_resources.getBaseDir() + "../addons/" + g_app->getAppName() + "/modules",
"" };
for(const std::string& dir : possibleAddonsDirs) {
// try to add module directory
if(g_resources.addToSearchPath(dir, false)) {
logInfo("Using addons directory '", dir.c_str(), "'");
found = true;
break;
}
}
} }
ModulePtr ModuleManager::discoverModule(const std::string& moduleFile) ModulePtr ModuleManager::discoverModule(const std::string& moduleFile)
@ -99,6 +114,7 @@ ModulePtr ModuleManager::discoverModule(const std::string& moduleFile)
} }
module->discover(moduleNode); module->discover(moduleNode);
// not loaded modules are always in back
if(push) if(push)
m_modules.push_back(module); m_modules.push_back(module);
} catch(Exception& e) { } catch(Exception& e) {
@ -116,10 +132,30 @@ void ModuleManager::ensureModuleLoaded(const std::string& moduleName)
void ModuleManager::unloadModules() void ModuleManager::unloadModules()
{ {
for(const ModulePtr& module : m_modules) auto modulesBackup = m_modules;
for(const ModulePtr& module : modulesBackup)
module->unload(); module->unload();
} }
void ModuleManager::reloadModules()
{
std::deque<ModulePtr> toLoadList;
// unload in the reverse direction, try to unload upto 10 times (because of dependencies)
for(int i=0;i<10;++i) {
auto modulesBackup = m_modules;
for(const ModulePtr& module : modulesBackup) {
if(module->isLoaded() && module->canUnload()) {
module->unload();
toLoadList.push_front(module);
}
}
}
for(const ModulePtr& module : toLoadList)
module->load();
}
ModulePtr ModuleManager::getModule(const std::string& moduleName) ModulePtr ModuleManager::getModule(const std::string& moduleName)
{ {
for(const ModulePtr& module : m_modules) for(const ModulePtr& module : m_modules)
@ -127,3 +163,14 @@ ModulePtr ModuleManager::getModule(const std::string& moduleName)
return module; return module;
return nullptr; return nullptr;
} }
void ModuleManager::updateModuleLoadOrder(ModulePtr module)
{
auto it = std::find(m_modules.begin(), m_modules.end(), module);
if(it != m_modules.end())
m_modules.erase(it);
if(module->isLoaded())
m_modules.push_front(module);
else
m_modules.push_back(module);
}

View File

@ -34,12 +34,18 @@ public:
ModulePtr discoverModule(const std::string& moduleFile); ModulePtr discoverModule(const std::string& moduleFile);
void ensureModuleLoaded(const std::string& moduleName); void ensureModuleLoaded(const std::string& moduleName);
void unloadModules(); void unloadModules();
void reloadModules();
ModulePtr getModule(const std::string& moduleName); ModulePtr getModule(const std::string& moduleName);
std::vector<ModulePtr> getModules() { return m_modules; } std::deque<ModulePtr> getModules() { return m_modules; }
protected:
void updateModuleLoadOrder(ModulePtr module);
friend class Module;
private: private:
std::vector<ModulePtr> m_modules; std::deque<ModulePtr> m_modules;
std::multimap<int, ModulePtr> m_autoLoadModules; std::multimap<int, ModulePtr> m_autoLoadModules;
}; };

View File

@ -48,8 +48,16 @@ bool FontManager::importFont(std::string fontFile)
OTMLNodePtr fontNode = doc->at("Font"); OTMLNodePtr fontNode = doc->at("Font");
std::string name = fontNode->valueAt("name"); std::string name = fontNode->valueAt("name");
if(fontExists(name)) //if(fontExists(name))
Fw::throwException("font '", name, "' already exists, cannot have duplicate font names"); // Fw::throwException("font '", name, "' already exists, cannot have duplicate font names");
// remove any font with the same name
for(auto it = m_fonts.begin(); it != m_fonts.end(); ++it) {
if((*it)->getName() == name) {
m_fonts.erase(it);
break;
}
}
FontPtr font(new Font(name)); FontPtr font(new Font(name));
font->load(fontNode); font->load(fontNode);

View File

@ -47,11 +47,15 @@ void Application::registerLuaFunctions()
// Event // Event
g_lua.registerClass<Event>(); g_lua.registerClass<Event>();
g_lua.bindClassMemberFunction<Event>("cancel", &Event::cancel);
g_lua.bindClassMemberFunction<Event>("execute", &Event::execute);
g_lua.bindClassMemberFunction<Event>("isCanceled", &Event::isCanceled); g_lua.bindClassMemberFunction<Event>("isCanceled", &Event::isCanceled);
g_lua.bindClassMemberFunction<Event>("isExecuted", &Event::isExecuted); g_lua.bindClassMemberFunction<Event>("isExecuted", &Event::isExecuted);
// ScheduledEvent // ScheduledEvent
g_lua.registerClass<ScheduledEvent, Event>(); g_lua.registerClass<ScheduledEvent, Event>();
g_lua.bindClassMemberFunction<ScheduledEvent>("reamaningTicks", &ScheduledEvent::reamaningTicks);
g_lua.bindClassMemberFunction<ScheduledEvent>("ticks", &ScheduledEvent::ticks);
// UIWidget // UIWidget
g_lua.registerClass<UIWidget>(); g_lua.registerClass<UIWidget>();
@ -370,6 +374,8 @@ void Application::registerLuaFunctions()
g_lua.registerClass<Module>(); g_lua.registerClass<Module>();
g_lua.bindClassMemberFunction<Module>("load", &Module::load); g_lua.bindClassMemberFunction<Module>("load", &Module::load);
g_lua.bindClassMemberFunction<Module>("unload", &Module::unload); g_lua.bindClassMemberFunction<Module>("unload", &Module::unload);
g_lua.bindClassMemberFunction<Module>("reload", &Module::reload);
g_lua.bindClassMemberFunction<Module>("canUnload", &Module::canUnload);
g_lua.bindClassMemberFunction<Module>("isLoaded", &Module::isLoaded); g_lua.bindClassMemberFunction<Module>("isLoaded", &Module::isLoaded);
g_lua.bindClassMemberFunction<Module>("getDescription", &Module::getDescription); g_lua.bindClassMemberFunction<Module>("getDescription", &Module::getDescription);
g_lua.bindClassMemberFunction<Module>("getName", &Module::getName); g_lua.bindClassMemberFunction<Module>("getName", &Module::getName);
@ -397,6 +403,8 @@ void Application::registerLuaFunctions()
// Application // Application
g_lua.registerStaticClass("g_app"); g_lua.registerStaticClass("g_app");
g_lua.bindClassStaticFunction("g_app", "exit", std::bind(&Application::exit, g_app)); g_lua.bindClassStaticFunction("g_app", "exit", std::bind(&Application::exit, g_app));
g_lua.bindClassStaticFunction("g_app", "isRunning", std::bind(&Application::isRunning, g_app));
g_lua.bindClassStaticFunction("g_app", "isStopping", std::bind(&Application::isStopping, g_app));
// ConfigManager // ConfigManager
g_lua.registerStaticClass("g_configs"); g_lua.registerStaticClass("g_configs");
@ -477,6 +485,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassStaticFunction("g_modules", "discoverModule", std::bind(&ModuleManager::discoverModule, &g_modules, _1)); g_lua.bindClassStaticFunction("g_modules", "discoverModule", std::bind(&ModuleManager::discoverModule, &g_modules, _1));
g_lua.bindClassStaticFunction("g_modules", "ensureModuleLoaded", std::bind(&ModuleManager::ensureModuleLoaded, &g_modules, _1)); g_lua.bindClassStaticFunction("g_modules", "ensureModuleLoaded", std::bind(&ModuleManager::ensureModuleLoaded, &g_modules, _1));
g_lua.bindClassStaticFunction("g_modules", "unloadModules", std::bind(&ModuleManager::unloadModules, &g_modules)); g_lua.bindClassStaticFunction("g_modules", "unloadModules", std::bind(&ModuleManager::unloadModules, &g_modules));
g_lua.bindClassStaticFunction("g_modules", "reloadModules", std::bind(&ModuleManager::reloadModules, &g_modules));
g_lua.bindClassStaticFunction("g_modules", "getModule", std::bind(&ModuleManager::getModule, &g_modules, _1)); g_lua.bindClassStaticFunction("g_modules", "getModule", std::bind(&ModuleManager::getModule, &g_modules, _1));
g_lua.bindClassStaticFunction("g_modules", "getModules", std::bind(&ModuleManager::getModules, &g_modules)); g_lua.bindClassStaticFunction("g_modules", "getModules", std::bind(&ModuleManager::getModules, &g_modules));

View File

@ -132,6 +132,9 @@ bool luavalue_cast(int index, std::vector<T>& vec);
template<class T> template<class T>
void push_luavalue(const std::deque<T>& vec); void push_luavalue(const std::deque<T>& vec);
template<typename T>
bool luavalue_cast(int index, std::deque<T>& vec);
// tuple // tuple
template<typename... Args> template<typename... Args>
void push_luavalue(const std::tuple<Args...>& tuple); void push_luavalue(const std::tuple<Args...>& tuple);
@ -279,6 +282,22 @@ void push_luavalue(const std::deque<T>& vec) {
} }
} }
template<typename T>
bool luavalue_cast(int index, std::deque<T>& vec)
{
if(g_lua.isTable(index)) {
g_lua.pushNil();
while(g_lua.next(index < 0 ? index-1 : index)) {
T value;
if(luavalue_cast(-1, value))
vec.push_back(value);
g_lua.pop();
}
return true;
}
return false;
}
template<int N> template<int N>
struct push_tuple_luavalue { struct push_tuple_luavalue {
template<typename Tuple> template<typename Tuple>

View File

@ -554,6 +554,7 @@ void UIWidget::destroy()
#ifdef DEBUG #ifdef DEBUG
auto self = asUIWidget(); auto self = asUIWidget();
if(self != g_ui.getRootWidget()) {
g_lua.collectGarbage(); g_lua.collectGarbage();
g_dispatcher.addEvent([self] { g_dispatcher.addEvent([self] {
g_lua.collectGarbage(); g_lua.collectGarbage();
@ -563,6 +564,7 @@ void UIWidget::destroy()
logWarning("widget '", self->getId(), "' destroyed but still have ", self->getUseCount()-1, " reference(s) left"); logWarning("widget '", self->getId(), "' destroyed but still have ", self->getUseCount()-1, " reference(s) left");
}); });
}); });
}
#endif #endif
m_destroyed = true; m_destroyed = true;
@ -853,9 +855,9 @@ UIWidgetPtr UIWidget::getChildById(const std::string& childId)
UIWidgetPtr UIWidget::getChildByPos(const Point& childPos) UIWidgetPtr UIWidget::getChildByPos(const Point& childPos)
{ {
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) { for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
const UIWidgetPtr& widget = (*it); const UIWidgetPtr& child = (*it);
if(widget->isExplicitlyVisible() && widget->containsPoint(childPos)) if(child->isExplicitlyVisible() && child->containsPoint(childPos))
return widget; return child;
} }
return nullptr; return nullptr;
@ -884,7 +886,8 @@ UIWidgetPtr UIWidget::recursiveGetChildById(const std::string& id)
UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos) UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos)
{ {
for(const UIWidgetPtr& child : m_children) { for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
const UIWidgetPtr& child = (*it);
if(child->isExplicitlyVisible() && child->containsPoint(childPos)) { if(child->isExplicitlyVisible() && child->containsPoint(childPos)) {
if(UIWidgetPtr subChild = child->recursiveGetChildByPos(childPos)) if(UIWidgetPtr subChild = child->recursiveGetChildByPos(childPos))
return subChild; return subChild;
@ -1280,9 +1283,9 @@ bool UIWidget::propagateOnKeyPress(uchar keyCode, int keyboardModifiers, int aut
return true; return true;
} }
if(autoRepeatTicks == 0 || autoRepeatTicks >= m_autoRepeatDelay) { if(autoRepeatTicks == 0 || autoRepeatTicks >= m_autoRepeatDelay)
return onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks); return onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks);
} else else
return false; return false;
} }

View File

@ -86,7 +86,7 @@ void UIWidget::onFontChange(const std::string& font)
void UIWidget::wrapText() void UIWidget::wrapText()
{ {
setText(m_font->wrapText(m_text, getWidth())); setText(m_font->wrapText(m_text, getWidth() - m_textOffset.x));
} }
void UIWidget::setText(const std::string& text) void UIWidget::setText(const std::string& text)

View File

@ -37,11 +37,18 @@ void OTClient::init(const std::vector<std::string>& args)
Application::init(args, Fw::AppEnableAll); Application::init(args, Fw::AppEnableAll);
g_modules.discoverModules(); g_modules.discoverModules();
g_modules.autoLoadModules(100);
g_modules.ensureModuleLoaded("client");
g_modules.autoLoadModules(1000);
//g_map.load(); // core modules 0-99
g_modules.autoLoadModules(99);
g_modules.ensureModuleLoaded("core_lib");
// client modules 100-499
g_modules.autoLoadModules(499);
g_modules.ensureModuleLoaded("client_main");
// game modules 500-999
g_modules.autoLoadModules(999);
g_modules.ensureModuleLoaded("game");
// addons 1000-9999
g_modules.autoLoadModules(9999);
// load otclientrc.lua // load otclientrc.lua
if(g_resources.fileExists("/otclientrc.lua")) { if(g_resources.fileExists("/otclientrc.lua")) {