diff --git a/data/images/ui/icon_add.png b/data/images/ui/icon_add.png new file mode 100644 index 00000000..9c2a0f75 Binary files /dev/null and b/data/images/ui/icon_add.png differ diff --git a/data/styles/10-buttons.otui b/data/styles/10-buttons.otui index 8e1607e1..0eebf67b 100644 --- a/data/styles/10-buttons.otui +++ b/data/styles/10-buttons.otui @@ -66,4 +66,18 @@ PreviousButton < UIButton image-clip: 0 21 12 21 $disabled: - image-color: #ffffff55 \ No newline at end of file + image-color: #ffffff55 + +AddButton < UIButton + size: 20 20 + image-source: /images/ui/icon_add + image-color: #ffffffff + + $hover !disabled: + image-color: #ffffff99 + + $pressed: + image-color: #ffffff44 + + $disabled: + image-color: #ffffff55 diff --git a/modules/client/client.otmod b/modules/client/client.otmod index 28cec272..31ffa32b 100644 --- a/modules/client/client.otmod +++ b/modules/client/client.otmod @@ -18,4 +18,5 @@ Module - client_options - client_terminal - client_modulemanager + - client_serverlist //- client_stats diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 5a4fd4a2..faef1290 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -34,9 +34,19 @@ local function onMotd(protocol, motd) end local function onCharacterList(protocol, characters, account, otui) + -- Try add server to the server list + ServerList.add(G.host, G.port, g_game.getProtocolVersion()) + if enterGame:getChildById('rememberPasswordBox'):isChecked() then - g_settings.set('account', g_crypt.encrypt(G.account)) - g_settings.set('password', g_crypt.encrypt(G.password)) + local account = g_crypt.encrypt(G.account) + local password = g_crypt.encrypt(G.password) + + g_settings.set('account', account) + g_settings.set('password', password) + + ServerList.setServerAccount(G.host, account) + ServerList.setServerPassword(G.host, password) + g_settings.set('autologin', enterGame:getChildById('autoLoginBox'):isChecked()) else EnterGame.clearAccountFields() @@ -90,8 +100,8 @@ function EnterGame.init() motdButton:show() end - local account = g_crypt.decrypt(g_settings.get('account')) - local password = g_crypt.decrypt(g_settings.get('password')) + local account = g_settings.get('account') + local password = g_settings.get('password') local host = g_settings.get('host') local port = g_settings.get('port') local autologin = g_settings.getBoolean('autologin') @@ -99,16 +109,15 @@ function EnterGame.init() if port == nil or port == 0 then port = 7171 end - enterGame:getChildById('accountNameTextEdit'):setText(account) - enterGame:getChildById('accountNameTextEdit'):setCursorPos(-1) - enterGame:getChildById('accountPasswordTextEdit'):setText(password) + EnterGame.setAccountName(account) + EnterGame.setPassword(password) + enterGame:getChildById('serverHostTextEdit'):setText(host) enterGame:getChildById('serverPortTextEdit'):setText(port) enterGame:getChildById('autoLoginBox'):setChecked(autologin) - enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0) protocolBox = enterGame:getChildById('protocolComboBox') - protocolBox.onOptionChange = onChangeProtocol + protocolBox.onOptionChange = onChangeProtocol for _i, proto in pairs(g_game.getSupportedProtocols()) do protocolBox:addOption(proto) end @@ -184,6 +193,18 @@ function EnterGame.openWindow() end end +function EnterGame.setAccountName(account) + local account = g_crypt.decrypt(account) + enterGame:getChildById('accountNameTextEdit'):setText(account) + enterGame:getChildById('accountNameTextEdit'):setCursorPos(-1) + enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0) +end + +function EnterGame.setPassword(password) + local password = g_crypt.decrypt(password) + enterGame:getChildById('accountPasswordTextEdit'):setText(password) +end + function EnterGame.clearAccountFields() enterGame:getChildById('accountNameTextEdit'):clearText() enterGame:getChildById('accountPasswordTextEdit'):clearText() @@ -285,6 +306,11 @@ function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeig protocolLabel:setVisible(false) protocolLabel:setHeight(0) + local serverListButton = enterGame:getChildById('serverListButton') + serverListButton:setVisible(false) + serverListButton:setHeight(0) + serverListButton:setWidth(0) + local rememberPasswordBox = enterGame:getChildById('rememberPasswordBox') rememberPasswordBox:setMarginTop(-5) diff --git a/modules/client_entergame/entergame.otui b/modules/client_entergame/entergame.otui index a0065268..b026c430 100644 --- a/modules/client_entergame/entergame.otui +++ b/modules/client_entergame/entergame.otui @@ -1,5 +1,19 @@ EnterGameWindow < MainWindow +ServerListButton < UIButton + size: 17 17 + image-source: /images/topbuttons/minimap + image-color: #ffffffff + + $hover !disabled: + image-color: #ffffff99 + + $pressed: + image-color: #ffffff44 + + $disabled: + image-color: #ffffff55 + EnterGameWindow id: enterGame !text: tr('Enter Game') @@ -41,13 +55,21 @@ EnterGameWindow margin-top: 8 text-auto-resize: true + ServerListButton + id: serverListButton + anchors.right: parent.right + anchors.top: serverLabel.bottom + margin-top: 3 + @onClick: ServerList.show() + TextEdit id: serverHostTextEdit !tooltip: tr('Make sure that your client uses\nthe correct game protocol version') anchors.left: parent.left - anchors.right: parent.right + anchors.right: serverListButton.left anchors.top: serverLabel.bottom margin-top: 2 + margin-right: 4 MenuLabel id: protocolLabel diff --git a/modules/client_serverlist/addserver.lua b/modules/client_serverlist/addserver.lua new file mode 100644 index 00000000..3a4f65d3 --- /dev/null +++ b/modules/client_serverlist/addserver.lua @@ -0,0 +1,38 @@ +AddServer = {} + +-- private variables +local addServerWindow = nil + +-- public functions +function AddServer.init() + addServerWindow = g_ui.displayUI('addserver') +end + +function AddServer.terminate() + addServerWindow:destroy() +end + +function AddServer.add() + local host = addServerWindow:getChildById('host'):getText() + local port = addServerWindow:getChildById('port'):getText() + local protocol = addServerWindow:getChildById('protocol'):getCurrentOption().text + + local added, error = ServerList.add(host, port, protocol) + if not added then + displayErrorBox(tr('Add Error'), tr(error)) + else + AddServer.hide() + end +end + +function AddServer.show() + addServerWindow:show() + addServerWindow:raise() + addServerWindow:focus() + addServerWindow:lock() +end + +function AddServer.hide() + addServerWindow:hide() + addServerWindow:unlock() +end \ No newline at end of file diff --git a/modules/client_serverlist/addserver.otui b/modules/client_serverlist/addserver.otui new file mode 100644 index 00000000..df43e97c --- /dev/null +++ b/modules/client_serverlist/addserver.otui @@ -0,0 +1,73 @@ +MainWindow + id: addServerWindow + !text: tr('New Server') + size: 180 180 + visible: false + @onEscape: AddServer.hide() + @onEnter: | + AddServer.add() + + Label + id: hostLabel + !text: tr('Host:') + anchors.top: parent.top + anchors.left: parent.left + margin-bottom: 2 + + TextEdit + id: host + anchors.top: hostLabel.bottom + anchors.left: hostLabel.left + anchors.right: parent.right + auto-focus: first + + Label + id: portLabel + !text: tr('Port:') + anchors.top: host.bottom + anchors.left: host.left + margin-top: 3 + margin-bottom: 2 + + TextEdit + id: port + text: 7171 + anchors.top: portLabel.bottom + anchors.left: portLabel.left + anchors.right: host.right + + Label + id: protocolLabel + !text: tr('Protocol:') + anchors.top: port.bottom + anchors.left: port.left + margin-top: 3 + margin-bottom: 2 + + ComboBox + id: protocol + anchors.top: protocolLabel.bottom + anchors.left: protocolLabel.left + anchors.right: port.right + @onSetup: | + for _, proto in pairs(g_game.getSupportedProtocols()) do + self:addOption(proto) + end + + Button + id: buttonAdd + !text: tr('Add') + width: 64 + anchors.right: parent.horizontalCenter + anchors.bottom: parent.bottom + margin-right: 5 + @onClick: | + AddServer.add() + + Button + id: buttonCancel + !text: tr('Cancel') + width: 64 + anchors.left: parent.horizontalCenter + anchors.bottom: parent.bottom + @onClick: AddServer.hide() diff --git a/modules/client_serverlist/serverlist.lua b/modules/client_serverlist/serverlist.lua new file mode 100644 index 00000000..48e88395 --- /dev/null +++ b/modules/client_serverlist/serverlist.lua @@ -0,0 +1,127 @@ +ServerList = {} + +-- private variables +local serverListWindow = nil +local serverTextList = nil +local servers = {} + +-- private functions +function getServer(host) + for k,server in pairs(servers) do + if server.host == host then + return server + end + end +end + +function getServerKey(host) + for k,server in pairs(servers) do + if server.host == host then + return k + end + end +end + +-- public functions +function ServerList.init() + serverListWindow = g_ui.displayUI('serverlist') + serverTextList = serverListWindow:getChildById('serverList') + + servers = g_settings.getNode('ServerList') or {} + ServerList.load() +end + +function ServerList.terminate() + ServerList.destroy() + + g_settings.setNode('ServerList', servers) + + ServerList = nil +end + +function ServerList.load() + for k,server in pairs(servers) do + ServerList.add(server.host, server.port, server.protocol, true) + end +end + +function ServerList.select() + local selected = serverTextList:getFocusedChild() + if selected then + local server = servers[getServerKey(selected:getId())] + if server then + EnterGame.setDefaultServer(server.host, server.port, server.protocol) + EnterGame.setAccountName(server.account) + EnterGame.setPassword(server.password) + ServerList.hide() + end + end +end + +function ServerList.add(host, port, protocol, load) + if not load and getServerKey(host) then + return false, 'Server already exists' + elseif host == '' or port == '' then + return false, 'Required fields are missing' + end + local widget = g_ui.createWidget('ServerWidget', serverTextList) + widget:setId(host) + + if not load then + servers[table.size(servers)+1] = { + host = host, + port = port, + protocol = protocol, + account = '', + password = '' + } + end + + local details = widget:getChildById('details') + details:setText(host..':'..port) + + local proto = widget:getChildById('protocol') + proto:setText(protocol) + + connect(widget, { onDoubleClick = function () ServerList.select() return true end } ) + return true +end + +function ServerList.remove(host) + servers[getServerKey(host)] = nil +end + +function ServerList.destroy() + if serverListWindow then + serverTextList = nil + serverListWindow:destroy() + serverListWindow = nil + end +end + +function ServerList.show() + if g_game.isOnline() then + return + end + serverListWindow:show() + serverListWindow:raise() + serverListWindow:focus() +end + +function ServerList.hide() + serverListWindow:hide() +end + +function ServerList.setServerAccount(host, account) + local key = getServerKey(host) + if servers[key] then + servers[key].account = account + end +end + +function ServerList.setServerPassword(host, password) + local key = getServerKey(host) + if servers[key] then + servers[key].password = password + end +end \ No newline at end of file diff --git a/modules/client_serverlist/serverlist.otmod b/modules/client_serverlist/serverlist.otmod new file mode 100644 index 00000000..75427090 --- /dev/null +++ b/modules/client_serverlist/serverlist.otmod @@ -0,0 +1,18 @@ +Module + name: client_serverlist + description: Manages a server list of previously entered servers + author: BeniS + website: www.otclient.info + + dependencies: + - client_entergame + + @onLoad: | + dofile 'serverlist' + dofile 'addserver' + ServerList.init() + AddServer.init() + + @onUnload: | + ServerList.terminate() + AddServer.terminate() diff --git a/modules/client_serverlist/serverlist.otui b/modules/client_serverlist/serverlist.otui new file mode 100644 index 00000000..8da715de --- /dev/null +++ b/modules/client_serverlist/serverlist.otui @@ -0,0 +1,113 @@ +ServerWidget < UIWidget + height: 14 + background-color: alpha + &updateOnStates: | + function(self) + local children = self:getChildren() + for i=1,#children do + children[i]:setOn(self:isFocused()) + end + end + @onFocusChange: self:updateOnStates() + @onSetup: self:updateOnStates() + + $focus: + background-color: #ffffff22 + + Label + id: details + color: #aaaaaa + anchors.top: parent.top + anchors.left: parent.left + font: verdana-11px-monochrome + text-auto-resize: true + background-color: alpha + text-offset: 2 0 + + $on: + color: #ffffff + + Label + id: protocol + color: #ffffff + color: #aaaaaa + anchors.top: parent.top + anchors.right: next.left + margin-right: 5 + font: verdana-11px-monochrome + text-auto-resize: true + background-color: alpha + &baseText: '(%s)' + + $on: + color: #ffffff + + Button + id: remove + !text: tr('x') + width: 12 + height: 12 + anchors.top: parent.top + anchors.right: parent.right + margin-right: 4 + margin-top: 1 + @onClick: | + local parent = self:getParent() + ServerList.remove(parent:getId()) + parent:destroy() + +MainWindow + id: serverListWindow + !text: tr('Server List') + size: 340 290 + visible: false + @onEnter: ServerList.select() + @onEscape: ServerList.hide() + @onSetup: | + g_keyboard.bindKeyPress('Up', function() self:getChildById('serverList'):focusPreviousChild(KeyboardFocusReason) end, self) + g_keyboard.bindKeyPress('Down', function() self:getChildById('serverList'):focusNextChild(KeyboardFocusReason) end, self) + + TextList + id: serverList + anchors.top: parent.top + anchors.left: parent.left + anchors.right: serverListScrollBar.left + anchors.bottom: buttonOk.top + margin-bottom: 5 + padding: 1 + focusable: false + vertical-scrollbar: serverListScrollBar + auto-focus: first + + VerticalScrollBar + id: serverListScrollBar + anchors.top: parent.top + anchors.bottom: buttonOk.top + anchors.right: parent.right + margin-bottom: 5 + step: 14 + pixels-scroll: true + + AddButton + id: buttonAdd + !tooltip: tr('Add new server') + anchors.left: parent.left + anchors.bottom: parent.bottom + @onClick: AddServer.show() + + Button + id: buttonOk + !text: tr('Select') + width: 64 + anchors.right: next.left + anchors.bottom: parent.bottom + margin-right: 10 + @onClick: ServerList.select() + + Button + id: buttonCancel + !text: tr('Cancel') + width: 64 + anchors.right: parent.right + anchors.bottom: parent.bottom + @onClick: ServerList.hide() \ No newline at end of file diff --git a/modules/corelib/table.lua b/modules/corelib/table.lua index c90c8545..8a7b0d59 100644 --- a/modules/corelib/table.lua +++ b/modules/corelib/table.lua @@ -146,7 +146,7 @@ end function table.size(t) local size = 0 - for i, n in pairs(table) do + for i, n in pairs(t) do size = size + 1 end