implement more functionality

* update TODO
* rework UISpinBox
* restore move of stackable items and with horizontal scrollbar
* implement classic control look
This commit is contained in:
Eduardo Bart 2012-03-29 10:45:40 -03:00
parent 15fce6d4cf
commit 47e7eef716
16 changed files with 142 additions and 152 deletions

51
TODO
View File

@ -1,35 +1,16 @@
====================================================
High priority TODO in order (before first public disclose)
multiline text edit
move windows, navigate in containers
complete miniwindow (close, minimize, resize, move)
create and bind all game events
player status icons (poison, etc)
load modules from zip files
display exit box when exiting from game
scrollbar and scrollable widgets
====================================================
Low priority TODO
== Core
review directories loading search
load modules from zip packages
create a class for reading binary files
rework lua/c++ logger
replace autoload-antencedence with load-before/load-after
== Graphics
use CoordsBuffer in font
cache renders into framebuffers
use hardware buffer
use indices
fix opacity and cached framebuffers conflict
map zoom rendering could be optimized using framebuffer caches
make low/medium/high settings for economizing graphics memory thus allowing to run the client smoothily in smartphones
implement graphics options menu
== Lua
== Modules
fix modules recursivity, it makes client crash
load modules from zip packages
== Lua engine
make possible to bind non LuaObject derived classes on lua engine (for usage with Point,Rect,Color,Size)
review usage of x,y/width,height in lua instead of point/size
@ -37,40 +18,34 @@ review usage of x,y/width,height in lua instead of point/size
port to MacOs and iphone
== UI
review anchors API, add possibility to get/remove anchors
multiline rich text widget
move layout proprieties to widget style
multiline text editor widget
fix style inheretance using a style translator
fix style inheritance using a style translator
find a way to add new widgets without focusing them
review UI/style loader and make more error prone with more warnings
reapply anchor styles when adding new childs
ui text selection
find styles by scope
make set of background/icon/image width alone work
check for recursive anchors and print a error instead of crashing
make api to enable/disable capture of events to avoid massive event processing
make api to enable/disable capture of events like mouseMove to avoid massive event processing
review style apply system
rework widgets rendering order
cache or preload otui files to avoid freezes because of hd reading
review widgets rendering order, consider adding z-index
change Align/Anchors lua API from enum to text
== Client
fix modules recursivity, it makes client crash
implement left panel with dragging windows
== Game
clean sprites cache periodically
create a shader manager
find a way to load map rendering styles
move redering of creatures names, skulls, etc to UI
make protocol class compatible with old tibia protocols
handle corrupt errors in dat/spr
remake spr/dat using OTML and image files
game/graphics window with options
do lua game event calls from Game instead from GameProtocol
== Game modules
minimap window
login queue
questlog
edit texts
trade window
shop window
battle window

View File

@ -26,8 +26,9 @@ function Mouse.isCursorChanged()
return cursorChanged
end
function Mouse.isPressed()
return g_ui.getPressedWidget() ~= nil
function Mouse.isPressed(button)
if not button then button = MouseLeftButton end
return g_window.isMouseButtonPressed(button)
end
function Mouse.bindAutoPress(widget, callback)

View File

@ -180,10 +180,18 @@ end
function UIScrollBar:onMouseWheel(mousePos, mouseWheel)
if mouseWheel == MouseWheelUp then
if self.orientation == 'vertical' then
self:decrement()
else
self:increment()
end
else
if self.orientation == 'vertical' then
self:increment()
else
self:decrement()
end
end
return true
end

View File

@ -5,60 +5,23 @@ function UISpinBox.create()
spinbox:setValidCharacters('0123456789')
spinbox.minimum = 0
spinbox.maximum = 0
spinbox:setCurrentIndex(0)
spinbox.value = 0
spinbox:setText("0")
return spinbox
end
function UISpinBox:setCurrentIndex(index)
if index >= self.minimum and index <= self.maximum then
if self:getText():len() > 0 then
self:setText(index)
end
self.currentIndex = index
self:onIndexChange(index)
end
end
function UISpinBox:setMinimum(minimum)
if minimum > self.maximum then
print("[UISpinBox:setMinimum]: minimum value cant be greater than maximum")
return false
end
if self.currentIndex < minimum then
self:setCurrentIndex(minimum)
end
self.minimum = minimum
end
function UISpinBox:setMaximum(maximum)
if maximum < self.minimum then
print("[UISpinBox:setMaximum]: maximum value cant be lower than minimum")
return false
end
if self.currentIndex > maximum then
self:setCurrentIndex(maximum)
end
self.maximum = maximum
end
function UISpinBox:getCurrentIndex()
return self.currentIndex
end
function UISpinBox:onMouseWheel(mousePos, direction)
if direction == MouseWheelUp then
self:setCurrentIndex(self.currentIndex + 1)
self:setValue(self.value + 1)
elseif direction == MouseWheelDown then
self:setCurrentIndex(self.currentIndex - 1)
self:setValue(self.value - 1)
end
return true
end
function UISpinBox:onTextChange(text, oldText)
if text:len() == 0 then
self:setCurrentIndex(self.minimum)
self:setValue(self.minimum)
return
end
@ -68,21 +31,45 @@ function UISpinBox:onTextChange(text, oldText)
return
end
self:setCurrentIndex(number)
self:setValue(number)
end
function UISpinBox:onIndexChange(index)
function UISpinBox:onValueChange(value)
-- nothing todo
end
function UISpinBox:onStyleApply(styleName, styleNode)
-- tonumber converts to 0 if not valid
if styleNode.maximum and tonumber(styleNode.maximum) then
self:setMaximum(tonumber(styleNode.maximum))
for name, value in pairs(styleNode) do
if name == 'maximum' then
self:setMaximum(value)
elseif name == 'minimum' then
self:setMinimum(value)
end
if styleNode.minimum and tonumber(styleNode.minimum) then
self:setMinimum(tonumber(styleNode.minimum))
end
end
function UISpinBox:setValue(value)
value = math.max(math.min(self.maximum, value), self.minimum)
if value == self.value then return end
if self:getText():len() > 0 then
self:setText(value)
end
self.value = value
signalcall(self.onValueChange, self, value)
end
function UISpinBox:setMinimum(minimum)
self.minimum = minimum
if self.value < minimum then
self:setValue(minimum)
end
end
function UISpinBox:setMaximum(maximum)
self.maximum = maximum
if self.value > maximum then
self:setValue(maximum)
end
end
function UISpinBox:getValue() return self.value end

View File

@ -202,8 +202,9 @@ function GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatu
if creatureThing:asPlayer() then
menu:addSeparator()
menu:addOption('Message to ' .. creatureThing:getName(), function() print('message') end)
menu:addOption('Add to VIP list', function() g_game.addVip(creatureThing:getName()) end)
local creatureName = creatureThing:getName()
menu:addOption('Message to ' .. creatureName, function() g_game.openPrivateChannel(creatureName) end)
menu:addOption('Add to VIP list', function() g_game.addVip(creatureName) end)
local localPlayerShield = localPlayer:asCreature():getShield()
local creatureShield = creatureThing:getShield()
@ -310,6 +311,31 @@ function GameInterface.processMouseAction(menuPosition, mouseButton, autoWalk, l
return false
end
function GameInterface.moveStackableItem(item, toPos)
local count = item:getCount()
local countWindow = createWidget('CountWindow', rootWidget)
local spinbox = countWindow:getChildById('countSpinBox')
local scrollbar = countWindow:getChildById('countScrollBar')
spinbox:setMaximum(count)
spinbox:setMinimum(1)
spinbox:setValue(count)
scrollbar:setMaximum(count)
scrollbar:setMinimum(1)
scrollbar:setValue(count)
scrollbar.onValueChange = function(self, value) spinbox:setValue(value) end
spinbox.onValueChange = function(self, value) scrollbar:setValue(value) end
local okButton = countWindow:getChildById('buttonOk')
local moveFunc = function()
g_game.move(item, toPos, spinbox:getValue())
okButton:getParent():destroy()
end
countWindow.onEnter = moveFunc
okButton.onClick = moveFunc
end
function GameInterface.getRootPanel()
return gameRootPanel
end

View File

@ -12,17 +12,17 @@ CountWindow < MainWindow
margin-top: 2
SpinBox
id: spinbox
id: countSpinBox
anchors.left: prev.right
anchors.right: parent.right
anchors.top: parent.top
HorizontalSeparator
id: separator
HorizontalScrollBar
id: countScrollBar
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: next.top
margin-bottom: 10
anchors.top: prev.bottom
margin-top: 8
Button
id: buttonOk
@ -30,7 +30,7 @@ CountWindow < MainWindow
width: 64
anchors.right: next.left
anchors.bottom: parent.bottom
margin-right: 10
margin-right: 5
Button
id: buttonCancel

View File

@ -1,2 +0,0 @@
UICountWindow = {}

View File

@ -13,17 +13,13 @@ function UIGameMap:onDragEnter(mousePos)
local thing = tile:getTopMoveThing()
if not thing then return false end
self.parsed = false
self.currentDragThing = thing
Mouse.setTargetCursor()
return true
end
function UIGameMap:onDragLeave(droppedWidget, mousePos)
if not self.parsed then
self.currentDragThing = nil
end
Mouse.restoreCursor()
return true
end
@ -34,33 +30,34 @@ function UIGameMap:onDrop(widget, mousePos)
local tile = self:getTile(mousePos)
if not tile then return false end
local count = widget.currentDragThing:getCount()
if widget.currentDragThing:isStackable() and count > 1 then
widget.parsed = true
local moveWindow = createWidget('CountWindow', rootWidget)
local spinbox = moveWindow:getChildById('spinbox')
spinbox:setMaximum(count)
spinbox:setMinimum(1)
spinbox:setCurrentIndex(count)
local okButton = moveWindow:getChildById('buttonOk')
okButton.onClick = function()
g_game.move(widget.currentDragThing, tile:getPosition(), spinbox:getCurrentIndex())
okButton:getParent():destroy()
widget.currentDragThing = nil
end
moveWindow.onEnter = okButton.onClick
local item = widget.currentDragThing
local toPos = tile:getPosition()
if item:isStackable() and item:getCount() > 1 then
GameInterface.moveStackableItem(item, toPos)
else
g_game.move(widget.currentDragThing, tile:getPosition(), 1)
g_game.move(item, toPos, 1)
end
return true
end
function UIGameMap:onMouseRelease(mousePosition, mouseButton)
if self.cancelNextRelease then
self.cancelNextRelease = false
return true
end
local tile = self:getTile(mousePosition)
if tile == nil then return false end
if GameInterface.processMouseAction(mousePosition, mouseButton, nil, tile:getTopLookThing(), tile:getTopUseThing(), tile:getTopCreature(), tile:getTopMultiUseThing()) then
if Options.getOption('classicControl') and
((Mouse.isPressed(MouseLeftButton) and mouseButton == MouseRightButton) or
(Mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then
local tile = self:getTile(mousePosition)
g_game.look(tile:getTopLookThing())
self.cancelNextRelease = true
return true
elseif GameInterface.processMouseAction(mousePosition, mouseButton, nil, tile:getTopLookThing(), tile:getTopUseThing(), tile:getTopCreature(), tile:getTopMultiUseThing()) then
return true
elseif mouseButton == MouseLeftButton and self:isPressed() then
local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), tile:getPosition(), 255)

View File

@ -5,8 +5,6 @@ function UIItem:onDragEnter(mousePos)
if not item then return false end
self:setBorderWidth(1)
self.parsed = false
self.currentDragThing = item
Mouse.setTargetCursor()
return true
@ -14,11 +12,7 @@ end
function UIItem:onDragLeave(droppedWidget, mousePos)
if self:isVirtual() then return false end
if not self.parsed then
self.currentDragThing = nil
end
Mouse.restoreCursor()
self:setBorderWidth(0)
return true
@ -29,24 +23,12 @@ function UIItem:onDrop(widget, mousePos)
if not widget or not widget.currentDragThing then return false end
local pos = self.position
local count = widget.currentDragThing:getCount()
if widget.currentDragThing:isStackable() and count > 1 then
widget.parsed = true
local countWindow = createWidget('CountWindow', rootWidget)
local spinbox = moveWindow:getChildById('spinbox')
spinbox:setMaximum(count)
spinbox:setMinimum(1)
spinbox:setCurrentIndex(count)
local okButton = moveWindow:getChildById('buttonOk')
okButton.onClick = function()
g_game.move(widget.currentDragThing, pos, spinbox:getCurrentIndex()) okButton:getParent():destroy()
widget.currentDragThing = nil
end
moveWindow.onEnter = okButton.onClick
local item = widget.currentDragThing
local toPos = self.position
if item:isStackable() and item:getCount() > 1 then
GameInterface.moveStackableItem(item, toPos)
else
g_game.move(widget.currentDragThing, pos, 1)
g_game.move(item, toPos, 1)
end
self:setBorderWidth(0)

View File

@ -39,7 +39,7 @@ BattleParty < BattleIcon
MiniWindow
id: battleWindow
text: Battle
height: 100
height: 166
icon: battle.png
@onClose: Battle.toggle()

View File

@ -37,7 +37,7 @@ function HotkeysManager.init()
hotkeysWindow = displayUI('hotkeys_manager.otui')
hotkeysWindow:setVisible(false)
hotkeysButton = TopMenu.addLeftButton('hotkeysButton', 'Hotkeys (Ctrl+K)', '/game_hotkeys/icon.png', HotkeysManager.toggle)
hotkeysButton = TopMenu.addGameButton('hotkeysButton', 'Hotkeys (Ctrl+K)', '/game_hotkeys/icon.png', HotkeysManager.toggle)
Keyboard.bindKeyDown('Ctrl+K', HotkeysManager.toggle)
currentHotkeysList = hotkeysWindow:getChildById('currentHotkeys')

View File

@ -484,6 +484,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassStaticFunction("g_window", "getMousePosition", std::bind(&PlatformWindow::getMousePosition, &g_window));
g_lua.bindClassStaticFunction("g_window", "getKeyboardModifiers", std::bind(&PlatformWindow::getKeyboardModifiers, &g_window));
g_lua.bindClassStaticFunction("g_window", "isKeyPressed", std::bind(&PlatformWindow::isKeyPressed, &g_window, _1));
g_lua.bindClassStaticFunction("g_window", "isMouseButtonPressed", std::bind(&PlatformWindow::isMouseButtonPressed, &g_window, _1));
g_lua.bindClassStaticFunction("g_window", "isVisible", std::bind(&PlatformWindow::isVisible, &g_window));
g_lua.bindClassStaticFunction("g_window", "isFullscreen", std::bind(&PlatformWindow::isFullscreen, &g_window));
g_lua.bindClassStaticFunction("g_window", "isMaximized", std::bind(&PlatformWindow::isMaximized, &g_window));

View File

@ -104,6 +104,9 @@ void PlatformWindow::releaseAllKeys()
processKeyUp(keyCode);
}
for(int i=0;i<4;++i)
m_mouseButtonStates[i] = false;
}
void PlatformWindow::fireKeysPress()
@ -133,3 +136,4 @@ void PlatformWindow::fireKeysPress()
}
}
}

View File

@ -77,8 +77,9 @@ public:
int getY() { return m_position.y; }
Point getMousePosition() { return m_inputEvent.mousePos; }
int getKeyboardModifiers() { return m_inputEvent.keyboardModifiers; }
bool isKeyPressed(Fw::Key keyCode) { return m_keysState[keyCode]; }
bool isKeyPressed(Fw::Key keyCode) { return m_keysState[keyCode]; }
bool isMouseButtonPressed(Fw::MouseButton mouseButton) { return m_mouseButtonStates[mouseButton]; }
bool isVisible() { return m_visible; }
bool isMaximized() { return m_maximized; }
bool isFullscreen() { return m_fullscreen; }
@ -107,6 +108,7 @@ protected:
Size m_unmaximizedSize;
Point m_unmaximizedPos;
InputEvent m_inputEvent;
Boolean<false> m_mouseButtonStates[4];
Boolean<false> m_created;
Boolean<false> m_visible;

View File

@ -490,6 +490,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
SetCapture(m_window);
m_inputEvent.reset(Fw::MousePressInputEvent);
m_inputEvent.mouseButton = Fw::MouseLeftButton;
m_mouseButtonStates[Fw::MouseLeftButton] = true;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
@ -498,6 +499,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
SetCapture(NULL);
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
m_inputEvent.mouseButton = Fw::MouseLeftButton;
m_mouseButtonStates[Fw::MouseLeftButton] = false;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
@ -506,6 +508,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
SetCapture(m_window);
m_inputEvent.reset(Fw::MousePressInputEvent);
m_inputEvent.mouseButton = Fw::MouseMidButton;
m_mouseButtonStates[Fw::MouseMidButton] = true;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
@ -514,6 +517,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
SetCapture(NULL);
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
m_inputEvent.mouseButton = Fw::MouseMidButton;
m_mouseButtonStates[Fw::MouseMidButton] = false;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
@ -522,6 +526,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
SetCapture(m_window);
m_inputEvent.reset(Fw::MousePressInputEvent);
m_inputEvent.mouseButton = Fw::MouseRightButton;
m_mouseButtonStates[Fw::MouseRightButton] = true;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;
@ -530,6 +535,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
SetCapture(NULL);
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
m_inputEvent.mouseButton = Fw::MouseRightButton;
m_mouseButtonStates[Fw::MouseRightButton] = false;
if(m_onInputEvent)
m_onInputEvent(m_inputEvent);
break;

View File

@ -719,12 +719,15 @@ void X11Window::poll()
switch(event.xbutton.button) {
case Button1:
m_inputEvent.mouseButton = Fw::MouseLeftButton;
m_mouseButtonStates[Fw::MouseLeftButton] = (event.type == ButtonPress);
break;
case Button3:
m_inputEvent.mouseButton = Fw::MouseRightButton;
m_mouseButtonStates[Fw::MouseRightButton] = (event.type == ButtonPress);
break;
case Button2:
m_inputEvent.mouseButton = Fw::MouseMidButton;
m_mouseButtonStates[Fw::MouseMidButton] = (event.type == ButtonPress);
break;
case Button4:
if(event.type == ButtonPress) {